From dd1d7ff161e22d697eec3c40893d380b0c0ef0bb Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 5 Oct 2010 14:57:51 +0200 Subject: [PATCH 001/238] Bug#55091: Server crashes on ADD PARTITION after a failed attempt In case of failure in ALTER ... PARTITION under LOCK TABLE the server could crash, due to it had modified the locked table object, which was not reverted in case of failure, resulting in a bad table definition used after the failed command. Solved by always closing the LOCKED TABLE, even in case of error. Note: this is a 5.1-only fix, bug#56172 fixed it in 5.5+ mysql-test/r/partition_innodb_plugin.result: updated result mysql-test/t/disabled.def: Only disabled valgrind instead. mysql-test/t/partition_innodb_plugin.test: Added test sql/sql_partition.cc: close_thread_tables do not close LOCKED TABLEs and destroys the table object (including part_info), so to avoid it to be reused, always close the table regardless of any previous failure. --- mysql-test/r/partition_innodb_plugin.result | 73 +++++++++++++++++++++ mysql-test/t/disabled.def | 1 - mysql-test/t/partition_innodb_plugin.test | 66 +++++++++++++++++++ sql/sql_partition.cc | 21 +++++- 4 files changed, 159 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/partition_innodb_plugin.result b/mysql-test/r/partition_innodb_plugin.result index dd91eee316a..f6b5ce84338 100644 --- a/mysql-test/r/partition_innodb_plugin.result +++ b/mysql-test/r/partition_innodb_plugin.result @@ -1,3 +1,76 @@ +call mtr.add_suppression("nnoDB: Error: table `test`.`t1` .* Partition.* InnoDB internal"); +# +# Bug#55091: Server crashes on ADD PARTITION after a failed attempt +# +SET @old_innodb_file_format_check = @@global.innodb_file_format_check; +SET @old_innodb_file_format = @@global.innodb_file_format; +SET @old_innodb_file_per_table = @@global.innodb_file_per_table; +SET @old_innodb_strict_mode = @@global.innodb_strict_mode; +SET @@global.innodb_file_format = Barracuda, +@@global.innodb_file_per_table = ON, +@@global.innodb_strict_mode = ON; +# Connection con1 +CREATE TABLE t1 (id INT NOT NULL +PRIMARY KEY, +user_num CHAR(10) +) ENGINE = InnoDB +KEY_BLOCK_SIZE=4 +PARTITION BY HASH(id) PARTITIONS 1; +t1#P#p0.ibd +t1.frm +t1.par +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + `user_num` char(10) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=4 +/*!50100 PARTITION BY HASH (id) +PARTITIONS 1 */ +SET GLOBAL innodb_file_per_table = OFF; +# Connection con2 +LOCK TABLE t1 WRITE; +# ALTER fails because COMPRESSED/KEY_BLOCK_SIZE +# are incompatible with innodb_file_per_table = OFF; +ALTER TABLE t1 ADD PARTITION PARTITIONS 1; +ERROR HY000: Got error 1478 from storage engine +t1#P#p0.ibd +t1.frm +t1.par +# This SET is not needed to reproduce the bug, +# it is here just to make the test case more realistic +SET innodb_strict_mode = OFF; +ALTER TABLE t1 ADD PARTITION PARTITIONS 2; +Warnings: +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=4. +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=4. +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=4. +t1.frm +t1.par +ALTER TABLE t1 REBUILD PARTITION p0; +Warnings: +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=4. +UNLOCK TABLES; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + `user_num` char(10) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=4 +/*!50100 PARTITION BY HASH (id) +PARTITIONS 3 */ +DROP TABLE t1; +# Connection default +SET @@global.innodb_strict_mode = @old_innodb_strict_mode; +SET @@global.innodb_file_format = @old_innodb_file_format; +SET @@global.innodb_file_per_table = @old_innodb_file_per_table; +SET @@global.innodb_file_format_check = @old_innodb_file_format_check; SET NAMES utf8; CREATE TABLE `t``\""e` (a INT, PRIMARY KEY (a)) ENGINE=InnoDB diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index cede26f555a..bb931fb7b14 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -11,6 +11,5 @@ ############################################################################## kill : Bug#37780 2008-12-03 HHunger need some changes to be robust enough for pushbuild. query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails sporadically -partition_innodb_plugin : Bug#53307 2010-04-30 VasilDimov valgrind warnings main.mysqlhotcopy_myisam : bug#54129 2010-06-04 Horst main.mysqlhotcopy_archive: bug#54129 2010-06-04 Horst diff --git a/mysql-test/t/partition_innodb_plugin.test b/mysql-test/t/partition_innodb_plugin.test index eeb990c0d81..114adf67180 100644 --- a/mysql-test/t/partition_innodb_plugin.test +++ b/mysql-test/t/partition_innodb_plugin.test @@ -1,5 +1,71 @@ --source include/have_partition.inc --source include/have_innodb_plugin.inc +# Remove the line below when bug#53307 is solved. +--source include/not_valgrind.inc + +let $MYSQLD_DATADIR= `SELECT @@datadir`; + +call mtr.add_suppression("nnoDB: Error: table `test`.`t1` .* Partition.* InnoDB internal"); +--echo # +--echo # Bug#55091: Server crashes on ADD PARTITION after a failed attempt +--echo # +SET @old_innodb_file_format_check = @@global.innodb_file_format_check; +SET @old_innodb_file_format = @@global.innodb_file_format; +SET @old_innodb_file_per_table = @@global.innodb_file_per_table; +SET @old_innodb_strict_mode = @@global.innodb_strict_mode; +SET @@global.innodb_file_format = Barracuda, +@@global.innodb_file_per_table = ON, +@@global.innodb_strict_mode = ON; + +--echo # Connection con1 +--connect(con1,localhost,root,,) + +CREATE TABLE t1 (id INT NOT NULL +PRIMARY KEY, +user_num CHAR(10) +) ENGINE = InnoDB +KEY_BLOCK_SIZE=4 +PARTITION BY HASH(id) PARTITIONS 1; + +--list_files $MYSQLD_DATADIR/test +SHOW CREATE TABLE t1; + +SET GLOBAL innodb_file_per_table = OFF; + +--disconnect con1 +--connect(con2,localhost,root,,) +--echo # Connection con2 + +LOCK TABLE t1 WRITE; + +--echo # ALTER fails because COMPRESSED/KEY_BLOCK_SIZE +--echo # are incompatible with innodb_file_per_table = OFF; + +--error ER_GET_ERRNO +ALTER TABLE t1 ADD PARTITION PARTITIONS 1; + +--list_files $MYSQLD_DATADIR/test +--echo # This SET is not needed to reproduce the bug, +--echo # it is here just to make the test case more realistic +SET innodb_strict_mode = OFF; + +ALTER TABLE t1 ADD PARTITION PARTITIONS 2; +--list_files $MYSQLD_DATADIR/test + +# really bug#56172 +ALTER TABLE t1 REBUILD PARTITION p0; + +UNLOCK TABLES; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +--disconnect con2 +--connection default +--echo # Connection default +SET @@global.innodb_strict_mode = @old_innodb_strict_mode; +SET @@global.innodb_file_format = @old_innodb_file_format; +SET @@global.innodb_file_per_table = @old_innodb_file_per_table; +SET @@global.innodb_file_format_check = @old_innodb_file_format_check; # # Bug#32430 - show engine innodb status causes errors diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 76caa2b0c8d..7b0c47865d8 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5934,6 +5934,12 @@ static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt) int err; if (lpt->thd->locked_tables) { + /* + Close the table if open, to remove/destroy the already altered + table->part_info object, so that it is not reused. + */ + if (lpt->table->db_stat) + abort_and_upgrade_lock_and_close_table(lpt); /* When we have the table locked, it is necessary to reopen the table since all table objects were closed and removed as part of the @@ -6436,7 +6442,20 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, table, table_list, FALSE, NULL, written_bin_log)); err: - close_thread_tables(thd); + if (thd->locked_tables) + { + /* + table->part_info was altered in prep_alter_part_table and must be + destroyed and recreated, since otherwise it will be reused, since + we are under LOCK TABLE. + */ + alter_partition_lock_handling(lpt); + } + else + { + /* Force the table to be closed to avoid reuse of the table->part_info */ + close_thread_tables(thd); + } DBUG_RETURN(TRUE); } #endif From 20d704978ddb14dee414f40f28bd58f82b21711c Mon Sep 17 00:00:00 2001 From: Gleb Shchepa Date: Sun, 31 Oct 2010 19:04:38 +0300 Subject: [PATCH 002/238] Bug #52160: crash and inconsistent results when grouping by a function and column The bugreport reveals two different bugs about grouping on a function: 1) grouping by the TIME_TO_SEC function result caused a server crash or wrong results and 2) grouping by the function returning a blob caused an unexpected "Duplicate entry" error and wrong result. Details for the 1st bug: TIME_TO_SEC() returns NULL if its argument is invalid (empty string for example). Thus its nullability depends not only on the nullability of its arguments but also on their values. Fixed by (overoptimistically) setting TIME_TO_SEC() to be nullable despite the nullability of its arguments. Details for the 2nd bug: The server is unable to create indices on blobs without explicit blob key part length. However, this fact was ignored for blob function result fields of GROUP BY intermediate tables. Fixed by disabling GROUP BY index creation for blob function result fields like regular blob fields. mysql-test/r/func_time.result: Test case for bug #52160. mysql-test/r/type_blob.result: Test case for bug #52160. mysql-test/t/func_time.test: Test case for bug #52160. mysql-test/t/type_blob.test: Test case for bug #52160. sql/item_timefunc.h: Bug #52160: crash and inconsistent results when grouping by a function and column TIME_TO_SEC() returns NULL if its argument is invalid (empty string for example). Thus its nullability depends not only Fixed by (overoptimistically) setting TIME_TO_SEC() to be nullable despite the nullability of its arguments. sql/sql_select.cc: Bug #52160: crash and inconsistent results when grouping by a function and column The server is unable to create indices on blobs without explicit blob key part length. However, this fact was ignored for blob function result fields of GROUP BY intermediate tables. Fixed by disabling GROUP BY index creation for blob function result fields like regular blob fields. --- mysql-test/r/func_time.result | 14 ++++++++++++++ mysql-test/r/type_blob.result | 11 +++++++++++ mysql-test/t/func_time.test | 10 ++++++++++ mysql-test/t/type_blob.test | 16 ++++++++++++++++ sql/item_timefunc.h | 1 + sql/sql_select.cc | 2 ++ 6 files changed, 54 insertions(+) diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 4ff4cfa586b..48e837f180f 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -1343,4 +1343,18 @@ SELECT 1 FROM t1 ORDER BY @x:=makedate(a,a); 1 1 DROP TABLE t1; +# +# Bug #52160: crash and inconsistent results when grouping +# by a function and column +# +CREATE TABLE t1(a CHAR(10) NOT NULL); +INSERT INTO t1 VALUES (''),(''); +SELECT COUNT(*) FROM t1 GROUP BY TIME_TO_SEC(a); +COUNT(*) +2 +Warnings: +Warning 1292 Truncated incorrect time value: '' +Warning 1292 Truncated incorrect time value: '' +Warning 1292 Truncated incorrect time value: '' +DROP TABLE t1; End of 5.1 tests diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result index 08c30d884fd..e6fd49b4247 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -974,3 +974,14 @@ ERROR 42000: Display width out of range for column 'cast as char' (max = 4294967 explain select convert(1, binary(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999)); ERROR 42000: Display width out of range for column 'cast as char' (max = 4294967295) End of 5.0 tests +# Bug #52160: crash and inconsistent results when grouping +# by a function and column +CREATE FUNCTION f1() RETURNS TINYBLOB RETURN 1; +CREATE TABLE t1(a CHAR(1)); +INSERT INTO t1 VALUES ('0'), ('0'); +SELECT COUNT(*) FROM t1 GROUP BY f1(), a; +COUNT(*) +2 +DROP FUNCTION f1; +DROP TABLE t1; +End of 5.1 tests diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index e764906c374..8fce7072319 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -849,4 +849,14 @@ INSERT INTO t1 VALUES (0),(9.216e-096); SELECT 1 FROM t1 ORDER BY @x:=makedate(a,a); DROP TABLE t1; +--echo # +--echo # Bug #52160: crash and inconsistent results when grouping +--echo # by a function and column +--echo # + +CREATE TABLE t1(a CHAR(10) NOT NULL); +INSERT INTO t1 VALUES (''),(''); +SELECT COUNT(*) FROM t1 GROUP BY TIME_TO_SEC(a); +DROP TABLE t1; + --echo End of 5.1 tests diff --git a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test index 460da1c1614..4e097edf73d 100644 --- a/mysql-test/t/type_blob.test +++ b/mysql-test/t/type_blob.test @@ -612,3 +612,19 @@ explain select convert(1, binary(4294967296)); explain select convert(1, binary(999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999)); --echo End of 5.0 tests + +--echo # Bug #52160: crash and inconsistent results when grouping +--echo # by a function and column + +CREATE FUNCTION f1() RETURNS TINYBLOB RETURN 1; + +CREATE TABLE t1(a CHAR(1)); +INSERT INTO t1 VALUES ('0'), ('0'); + +SELECT COUNT(*) FROM t1 GROUP BY f1(), a; + +DROP FUNCTION f1; +DROP TABLE t1; + +--echo End of 5.1 tests + diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index ef86406e1be..47bb9509582 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -331,6 +331,7 @@ public: const char *func_name() const { return "time_to_sec"; } void fix_length_and_dec() { + maybe_null= TRUE; decimals=0; max_length=10*MY_CHARSET_BIN_MB_MAXLEN; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 08bd0c28738..77d4447fd0f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15198,6 +15198,8 @@ calc_group_buffer(JOIN *join,ORDER *group) { key_length+= 8; } + else if (type == MYSQL_TYPE_BLOB) + key_length+= MAX_BLOB_WIDTH; // Can't be used as a key else { /* From 6c802b3c4307580a3387a5a8fcd29a0656fa4177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 2 Nov 2010 09:28:05 +0200 Subject: [PATCH 003/238] White-space corrections in the InnoDB Plugin ChangeLog --- storage/innodb_plugin/ChangeLog | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 9033e5557f3..1be14034be4 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,13 +1,13 @@ 2010-10-24 The InnoDB Team * row/row0mysql.c - Fix Bug #57700 Latching order violation in + Fix Bug#57700 Latching order violation in row_truncate_table_for_mysql() 2010-10-20 The InnoDB Team * dict/dict0load.c - Fix Bug #57616 Sig 11 in dict_load_table() when failed to load + Fix Bug#57616 Sig 11 in dict_load_table() when failed to load index or foreign key 2010-10-19 The InnoDB Team @@ -17,7 +17,7 @@ include/ibuf0ibuf.h, include/row0mysql.h, row/row0mysql.c, row/row0sel.c, innodb_bug56680.test, innodb_bug56680.result: - Fix Bug #56680 InnoDB may return wrong results from a + Fix Bug#56680 InnoDB may return wrong results from a case-insensitive covering index 2010-10-18 The InnoDB Team @@ -61,7 +61,7 @@ 2010-08-03 The InnoDB Team * include/dict0dict.h, include/dict0dict.ic, row/row0mysql.c: - Fix bug #54678, InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock + Fix Bug#54678 InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock 2010-08-03 The InnoDB Team @@ -135,7 +135,7 @@ * dict/dict0load.c, fil/fil0fil.c: Fix Bug#54658: InnoDB: Warning: allocated tablespace %lu, - old maximum was 0 (introduced in Bug #53578 fix) + old maximum was 0 (introduced in Bug#53578 fix) 2010-06-16 The InnoDB Team From 004bb1b15ebbf4efe996d04c4bb95a235a718c62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 2 Nov 2010 09:28:48 +0200 Subject: [PATCH 004/238] Bug#57799 READ UNCOMMITTED access failure of off-page DYNAMIC or COMPRESSED columns again This is follow-up to Bug #54358. Not all occurrences of the bug were fixed. We need to check all calls to btr_copy_externally_stored_field_prefix_low() and do the right thing when the pointer to the off-page column is null (full of zero bytes). It turns out that only the call to btr_copy_externally_stored_field_prefix() in row_sel_sec_rec_is_for_blob() needs to be changed. For fetching complete off-page columns rather than prefixes, the function btr_rec_copy_externally_stored_field() already checks if the pointer is null (all-zero). Two of its callers (row_merge_copy_blobs() and row_sel_fetch_columns()) are never executed as READ COMMITTED and can rightfully assert that the fetch succeeded. The third caller, row_sel_store_mysql_rec(), already does the right thing. The calls in row_upd_ext_fetch() and trx_undo_page_fetch_ext() must expect that the off-page column exists. Update and rollback are locking operations, never READ UNCOMMITTED. --- storage/innodb_plugin/ChangeLog | 6 ++++++ storage/innodb_plugin/row/row0sel.c | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 1be14034be4..3792d48e5f2 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,9 @@ +2010-11-02 The InnoDB Team + + * row/row0sel.c: + Fix Bug#57799 READ UNCOMMITTED access failure of off-page + DYNAMIC or COMPRESSED columns again + 2010-10-24 The InnoDB Team * row/row0mysql.c diff --git a/storage/innodb_plugin/row/row0sel.c b/storage/innodb_plugin/row/row0sel.c index ac78a95839c..423ddfade22 100644 --- a/storage/innodb_plugin/row/row0sel.c +++ b/storage/innodb_plugin/row/row0sel.c @@ -106,6 +106,18 @@ row_sel_sec_rec_is_for_blob( ulint len; byte buf[DICT_MAX_INDEX_COL_LEN]; + ut_a(clust_len >= BTR_EXTERN_FIELD_REF_SIZE); + + if (UNIV_UNLIKELY + (!memcmp(clust_field + clust_len - BTR_EXTERN_FIELD_REF_SIZE, + field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE))) { + /* The externally stored field was not written yet. + This record should only be seen by + recv_recovery_rollback_active() or any + TRX_ISO_READ_UNCOMMITTED transactions. */ + return(FALSE); + } + len = btr_copy_externally_stored_field_prefix(buf, sizeof buf, zip_size, clust_field, clust_len); From addb14753368e09fb3cb10e6d5cda69e3e96a4e0 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Tue, 2 Nov 2010 10:00:04 +0200 Subject: [PATCH 005/238] Increment InnoDB Plugin version to 1.0.14. InnoDB Plugin 1.0.13 has been released with MySQL 5.1.52. --- storage/innodb_plugin/include/univ.i | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innodb_plugin/include/univ.i b/storage/innodb_plugin/include/univ.i index ee77582d7f1..c1ed56684c9 100644 --- a/storage/innodb_plugin/include/univ.i +++ b/storage/innodb_plugin/include/univ.i @@ -46,7 +46,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 1 #define INNODB_VERSION_MINOR 0 -#define INNODB_VERSION_BUGFIX 13 +#define INNODB_VERSION_BUGFIX 14 /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; From 1a5a109524cbd3445544888170686b023c6331b8 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Tue, 2 Nov 2010 15:20:02 +0200 Subject: [PATCH 006/238] Bug #51208: Extra string allocation from thd->mem_root in sql_show.cc, find_files() Removed the extra allocation. --- sql/sql_show.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index e074461b452..9b344204d64 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -534,12 +534,6 @@ find_files(THD *thd, List *files, const char *db, else if (wild_compare(uname, wild, 0)) continue; } - if (!(file_name= - thd->make_lex_string(file_name, uname, file_name_len, TRUE))) - { - my_dirend(dirp); - DBUG_RETURN(FIND_FILES_OOM); - } } else { From 49cbbf6ea4d9dbcd75292967a67173d21e61fc25 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Tue, 2 Nov 2010 18:57:20 +0200 Subject: [PATCH 007/238] Fix Bug#53046 dict_update_statistics_low can still be run concurrently on same table Replace the array of mutexes that used to protect dict_index_t::stat_n_diff_key_vals[] with an array of rw locks that protects all the stats related members in dict_table_t and all of its indexes. Approved by: Jimmy (rb://503) --- .../innodb_plugin/r/innodb_bug53046.result | 27 ++++ .../innodb_plugin/t/innodb_bug53046.test | 48 ++++++ storage/innodb_plugin/btr/btr0cur.c | 4 - storage/innodb_plugin/dict/dict0dict.c | 140 ++++++++++++------ storage/innodb_plugin/dict/dict0load.c | 5 +- storage/innodb_plugin/handler/ha_innodb.cc | 24 ++- storage/innodb_plugin/include/dict0dict.h | 34 +++-- storage/innodb_plugin/row/row0mysql.c | 6 +- 8 files changed, 215 insertions(+), 73 deletions(-) create mode 100644 mysql-test/suite/innodb_plugin/r/innodb_bug53046.result create mode 100644 mysql-test/suite/innodb_plugin/t/innodb_bug53046.test diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug53046.result b/mysql-test/suite/innodb_plugin/r/innodb_bug53046.result new file mode 100644 index 00000000000..69be6c4e0a7 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/r/innodb_bug53046.result @@ -0,0 +1,27 @@ +CREATE TABLE bug53046_1 (c1 INT PRIMARY KEY) ENGINE=INNODB; +CREATE TABLE bug53046_2 (c2 INT PRIMARY KEY, +FOREIGN KEY (c2) REFERENCES bug53046_1(c1) +ON UPDATE CASCADE ON DELETE CASCADE) ENGINE=INNODB; +INSERT INTO bug53046_1 VALUES (1); +INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1) +FROM bug53046_1; +INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1) +FROM bug53046_1; +INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1) +FROM bug53046_1; +INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1) +FROM bug53046_1; +INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1) +FROM bug53046_1; +INSERT INTO bug53046_2 VALUES (1), (2); +ANALYZE TABLE bug53046_1; +Table Op Msg_type Msg_text +test.bug53046_1 analyze status OK +SHOW TABLE STATUS LIKE 'bug53046_1'; +UPDATE bug53046_1 SET c1 = c1 - 1; +DELETE FROM bug53046_1; +INSERT INTO bug53046_1 VALUES (1); +INSERT INTO bug53046_2 VALUES (1); +TRUNCATE TABLE bug53046_2; +DROP TABLE bug53046_2; +DROP TABLE bug53046_1; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug53046.test b/mysql-test/suite/innodb_plugin/t/innodb_bug53046.test new file mode 100644 index 00000000000..7d9422fe487 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb_bug53046.test @@ -0,0 +1,48 @@ +# +# http://bugs.mysql.com/53046 +# dict_update_statistics_low can still be run concurrently on same table +# +# This is a symbolic test, it would not fail if the bug is present. +# Rather those SQL commands have been used during manual testing under +# UNIV_DEBUG & UNIV_SYNC_DEBUG to test all changed codepaths for locking +# correctness. +# + +-- source include/have_innodb_plugin.inc + +CREATE TABLE bug53046_1 (c1 INT PRIMARY KEY) ENGINE=INNODB; +CREATE TABLE bug53046_2 (c2 INT PRIMARY KEY, + FOREIGN KEY (c2) REFERENCES bug53046_1(c1) + ON UPDATE CASCADE ON DELETE CASCADE) ENGINE=INNODB; + +INSERT INTO bug53046_1 VALUES (1); +let $i = 5; +while ($i) { + eval INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1) + FROM bug53046_1; + dec $i; +} + +INSERT INTO bug53046_2 VALUES (1), (2); + +# CREATE TABLE innodb_table_monitor (a int) ENGINE=INNODB; +# wait more than 1 minute and observe the mysqld output +# DROP TABLE innodb_table_monitor; + +ANALYZE TABLE bug53046_1; + +# this prints create time and other nondeterministic data +-- disable_result_log +SHOW TABLE STATUS LIKE 'bug53046_1'; +-- enable_result_log + +UPDATE bug53046_1 SET c1 = c1 - 1; + +DELETE FROM bug53046_1; + +INSERT INTO bug53046_1 VALUES (1); +INSERT INTO bug53046_2 VALUES (1); +TRUNCATE TABLE bug53046_2; + +DROP TABLE bug53046_2; +DROP TABLE bug53046_1; diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c index 79fe328a631..cbad05345e6 100644 --- a/storage/innodb_plugin/btr/btr0cur.c +++ b/storage/innodb_plugin/btr/btr0cur.c @@ -3355,8 +3355,6 @@ btr_estimate_number_of_different_key_vals( also the pages used for external storage of fields (those pages are included in index->stat_n_leaf_pages) */ - dict_index_stat_mutex_enter(index); - for (j = 0; j <= n_cols; j++) { index->stat_n_diff_key_vals[j] = ((n_diff[j] @@ -3386,8 +3384,6 @@ btr_estimate_number_of_different_key_vals( index->stat_n_diff_key_vals[j] += add_on; } - dict_index_stat_mutex_exit(index); - mem_free(n_diff); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); diff --git a/storage/innodb_plugin/dict/dict0dict.c b/storage/innodb_plugin/dict/dict0dict.c index a3575c283cd..2adae4afffb 100644 --- a/storage/innodb_plugin/dict/dict0dict.c +++ b/storage/innodb_plugin/dict/dict0dict.c @@ -80,9 +80,18 @@ UNIV_INTERN rw_lock_t dict_operation_lock; /** Identifies generated InnoDB foreign key names */ static char dict_ibfk[] = "_ibfk_"; -/** array of mutexes protecting dict_index_t::stat_n_diff_key_vals[] */ -#define DICT_INDEX_STAT_MUTEX_SIZE 32 -static mutex_t dict_index_stat_mutex[DICT_INDEX_STAT_MUTEX_SIZE]; +/** array of rw locks protecting +dict_table_t::stat_initialized +dict_table_t::stat_n_rows (*) +dict_table_t::stat_clustered_index_size +dict_table_t::stat_sum_of_other_index_sizes +dict_table_t::stat_modified_counter (*) +dict_table_t::indexes*::stat_n_diff_key_vals[] +dict_table_t::indexes*::stat_index_size +dict_table_t::indexes*::stat_n_leaf_pages +(*) those are not always protected for performance reasons */ +#define DICT_TABLE_STATS_LATCHES_SIZE 64 +static rw_lock_t dict_table_stats_latches[DICT_TABLE_STATS_LATCHES_SIZE]; /*******************************************************************//** Tries to find column names for the index and sets the col field of the @@ -243,43 +252,65 @@ dict_mutex_exit_for_mysql(void) mutex_exit(&(dict_sys->mutex)); } -/** Get the mutex that protects index->stat_n_diff_key_vals[] */ -#define GET_INDEX_STAT_MUTEX(index) \ - (&dict_index_stat_mutex[ut_fold_dulint(index->id) \ - % DICT_INDEX_STAT_MUTEX_SIZE]) +/** Get the latch that protects the stats of a given table */ +#define GET_TABLE_STATS_LATCH(table) \ + (&dict_table_stats_latches[ut_fold_dulint(table->id) \ + % DICT_TABLE_STATS_LATCHES_SIZE]) /**********************************************************************//** -Lock the appropriate mutex to protect index->stat_n_diff_key_vals[]. -index->id is used to pick the right mutex and it should not change -before dict_index_stat_mutex_exit() is called on this index. */ +Lock the appropriate latch to protect a given table's statistics. +table->id is used to pick the corresponding latch from a global array of +latches. */ UNIV_INTERN void -dict_index_stat_mutex_enter( -/*========================*/ - const dict_index_t* index) /*!< in: index */ +dict_table_stats_lock( +/*==================*/ + const dict_table_t* table, /*!< in: table */ + ulint latch_mode) /*!< in: RW_S_LATCH or + RW_X_LATCH */ { - ut_ad(index != NULL); - ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); - ut_ad(index->cached); - ut_ad(!index->to_be_dropped); + ut_ad(table != NULL); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - mutex_enter(GET_INDEX_STAT_MUTEX(index)); + switch (latch_mode) { + case RW_S_LATCH: + rw_lock_s_lock(GET_TABLE_STATS_LATCH(table)); + break; + case RW_X_LATCH: + rw_lock_x_lock(GET_TABLE_STATS_LATCH(table)); + break; + case RW_NO_LATCH: + /* fall through */ + default: + ut_error; + } } /**********************************************************************//** -Unlock the appropriate mutex that protects index->stat_n_diff_key_vals[]. */ +Unlock the latch that has been locked by dict_table_stats_lock() */ UNIV_INTERN void -dict_index_stat_mutex_exit( -/*=======================*/ - const dict_index_t* index) /*!< in: index */ +dict_table_stats_unlock( +/*====================*/ + const dict_table_t* table, /*!< in: table */ + ulint latch_mode) /*!< in: RW_S_LATCH or + RW_X_LATCH */ { - ut_ad(index != NULL); - ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); - ut_ad(index->cached); - ut_ad(!index->to_be_dropped); + ut_ad(table != NULL); + ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); - mutex_exit(GET_INDEX_STAT_MUTEX(index)); + switch (latch_mode) { + case RW_S_LATCH: + rw_lock_s_unlock(GET_TABLE_STATS_LATCH(table)); + break; + case RW_X_LATCH: + rw_lock_x_unlock(GET_TABLE_STATS_LATCH(table)); + break; + case RW_NO_LATCH: + /* fall through */ + default: + ut_error; + } } /********************************************************************//** @@ -668,8 +699,8 @@ dict_init(void) mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH); - for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) { - mutex_create(&dict_index_stat_mutex[i], SYNC_INDEX_TREE); + for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) { + rw_lock_create(&dict_table_stats_latches[i], SYNC_INDEX_TREE); } } @@ -700,12 +731,11 @@ dict_table_get( mutex_exit(&(dict_sys->mutex)); if (table != NULL) { - if (!table->stat_initialized) { - /* If table->ibd_file_missing == TRUE, this will - print an error message and return without doing - anything. */ - dict_update_statistics(table); - } + /* If table->ibd_file_missing == TRUE, this will + print an error message and return without doing + anything. */ + dict_update_statistics(table, TRUE /* only update stats + if they have not been initialized */); } return(table); @@ -4186,6 +4216,10 @@ void dict_update_statistics_low( /*=======================*/ dict_table_t* table, /*!< in/out: table */ + ibool only_calc_if_missing_stats,/*!< in: only + update/recalc the stats if they have + not been initialized yet, otherwise + do nothing */ ibool has_dict_mutex __attribute__((unused))) /*!< in: TRUE if the caller has the dictionary mutex */ @@ -4216,6 +4250,12 @@ dict_update_statistics_low( return; } + dict_table_stats_lock(table, RW_X_LATCH); + + if (only_calc_if_missing_stats && table->stat_initialized) { + dict_table_stats_unlock(table, RW_X_LATCH); + return; + } do { if (UNIV_LIKELY @@ -4261,13 +4301,9 @@ dict_update_statistics_low( index = dict_table_get_first_index(table); - dict_index_stat_mutex_enter(index); - table->stat_n_rows = index->stat_n_diff_key_vals[ dict_index_get_n_unique(index)]; - dict_index_stat_mutex_exit(index); - table->stat_clustered_index_size = index->stat_index_size; table->stat_sum_of_other_index_sizes = sum_of_index_sizes @@ -4276,6 +4312,8 @@ dict_update_statistics_low( table->stat_initialized = TRUE; table->stat_modified_counter = 0; + + dict_table_stats_unlock(table, RW_X_LATCH); } /*********************************************************************//** @@ -4285,9 +4323,13 @@ UNIV_INTERN void dict_update_statistics( /*===================*/ - dict_table_t* table) /*!< in/out: table */ + dict_table_t* table, /*!< in/out: table */ + ibool only_calc_if_missing_stats)/*!< in: only + update/recalc the stats if they have + not been initialized yet, otherwise + do nothing */ { - dict_update_statistics_low(table, FALSE); + dict_update_statistics_low(table, only_calc_if_missing_stats, FALSE); } /**********************************************************************//** @@ -4367,7 +4409,11 @@ dict_table_print_low( ut_ad(mutex_own(&(dict_sys->mutex))); - dict_update_statistics_low(table, TRUE); + dict_update_statistics_low(table, + FALSE /* update even if initialized */, + TRUE /* we have the dict mutex */); + + dict_table_stats_lock(table, RW_S_LATCH); fprintf(stderr, "--------------------------------------\n" @@ -4396,6 +4442,8 @@ dict_table_print_low( index = UT_LIST_GET_NEXT(indexes, index); } + dict_table_stats_unlock(table, RW_S_LATCH); + foreign = UT_LIST_GET_FIRST(table->foreign_list); while (foreign != NULL) { @@ -4444,8 +4492,6 @@ dict_index_print_low( ut_ad(mutex_own(&(dict_sys->mutex))); - dict_index_stat_mutex_enter(index); - if (index->n_user_defined_cols > 0) { n_vals = index->stat_n_diff_key_vals[ index->n_user_defined_cols]; @@ -4453,8 +4499,6 @@ dict_index_print_low( n_vals = index->stat_n_diff_key_vals[1]; } - dict_index_stat_mutex_exit(index); - fprintf(stderr, " INDEX: name %s, id %lu %lu, fields %lu/%lu," " uniq %lu, type %lu\n" @@ -4943,8 +4987,8 @@ dict_close(void) mem_free(dict_sys); dict_sys = NULL; - for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) { - mutex_free(&dict_index_stat_mutex[i]); + for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) { + rw_lock_free(&dict_table_stats_latches[i]); } } #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innodb_plugin/dict/dict0load.c b/storage/innodb_plugin/dict/dict0load.c index 3dcee46b92c..3baa12b4235 100644 --- a/storage/innodb_plugin/dict/dict0load.c +++ b/storage/innodb_plugin/dict/dict0load.c @@ -222,7 +222,10 @@ loop: is no index */ if (dict_table_get_first_index(table)) { - dict_update_statistics_low(table, TRUE); + dict_update_statistics_low( + table, + FALSE /* update even if initialized */, + TRUE /* we have the dict mutex */); } dict_table_print_low(table); diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 99d4f294f81..60ca1c0bb03 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -7343,6 +7343,7 @@ ha_innobase::estimate_rows_upper_bound(void) dict_index_t* index; ulonglong estimate; ulonglong local_data_file_length; + ulint stat_n_leaf_pages; DBUG_ENTER("estimate_rows_upper_bound"); @@ -7362,10 +7363,12 @@ ha_innobase::estimate_rows_upper_bound(void) index = dict_table_get_first_index(prebuilt->table); - ut_a(index->stat_n_leaf_pages > 0); + stat_n_leaf_pages = index->stat_n_leaf_pages; + + ut_a(stat_n_leaf_pages > 0); local_data_file_length = - ((ulonglong) index->stat_n_leaf_pages) * UNIV_PAGE_SIZE; + ((ulonglong) stat_n_leaf_pages) * UNIV_PAGE_SIZE; /* Calculate a minimum length for a clustered index record and from @@ -7564,7 +7567,9 @@ ha_innobase::info_low( prebuilt->trx->op_info = "updating table statistics"; - dict_update_statistics(ib_table); + dict_update_statistics(ib_table, + FALSE /* update even if stats + are initialized */); prebuilt->trx->op_info = "returning various info to MySQL"; } @@ -7583,6 +7588,9 @@ ha_innobase::info_low( } if (flag & HA_STATUS_VARIABLE) { + + dict_table_stats_lock(ib_table, RW_S_LATCH); + n_rows = ib_table->stat_n_rows; /* Because we do not protect stat_n_rows by any mutex in a @@ -7632,6 +7640,8 @@ ha_innobase::info_low( ib_table->stat_sum_of_other_index_sizes) * UNIV_PAGE_SIZE; + dict_table_stats_unlock(ib_table, RW_S_LATCH); + /* Since fsp_get_available_space_in_free_extents() is acquiring latches inside InnoDB, we do not call it if we are asked by MySQL to avoid locking. Another reason to @@ -7708,6 +7718,8 @@ ha_innobase::info_low( table->s->keys); } + dict_table_stats_lock(ib_table, RW_S_LATCH); + for (i = 0; i < table->s->keys; i++) { ulong j; /* We could get index quickly through internal @@ -7745,8 +7757,6 @@ ha_innobase::info_low( break; } - dict_index_stat_mutex_enter(index); - if (index->stat_n_diff_key_vals[j + 1] == 0) { rec_per_key = stats.records; @@ -7755,8 +7765,6 @@ ha_innobase::info_low( index->stat_n_diff_key_vals[j + 1]); } - dict_index_stat_mutex_exit(index); - /* Since MySQL seems to favor table scans too much over index searches, we pretend index selectivity is 2 times better than @@ -7773,6 +7781,8 @@ ha_innobase::info_low( (ulong) rec_per_key; } } + + dict_table_stats_unlock(ib_table, RW_S_LATCH); } if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { diff --git a/storage/innodb_plugin/include/dict0dict.h b/storage/innodb_plugin/include/dict0dict.h index 5ffa59538c8..44db7b3df1d 100644 --- a/storage/innodb_plugin/include/dict0dict.h +++ b/storage/innodb_plugin/include/dict0dict.h @@ -1056,6 +1056,10 @@ void dict_update_statistics_low( /*=======================*/ dict_table_t* table, /*!< in/out: table */ + ibool only_calc_if_missing_stats,/*!< in: only + update/recalc the stats if they have + not been initialized yet, otherwise + do nothing */ ibool has_dict_mutex);/*!< in: TRUE if the caller has the dictionary mutex */ /*********************************************************************//** @@ -1065,7 +1069,11 @@ UNIV_INTERN void dict_update_statistics( /*===================*/ - dict_table_t* table); /*!< in/out: table */ + dict_table_t* table, /*!< in/out: table */ + ibool only_calc_if_missing_stats);/*!< in: only + update/recalc the stats if they have + not been initialized yet, otherwise + do nothing */ /********************************************************************//** Reserves the dictionary system mutex for MySQL. */ UNIV_INTERN @@ -1079,21 +1087,25 @@ void dict_mutex_exit_for_mysql(void); /*===========================*/ /**********************************************************************//** -Lock the appropriate mutex to protect index->stat_n_diff_key_vals[]. -index->id is used to pick the right mutex and it should not change -before dict_index_stat_mutex_exit() is called on this index. */ +Lock the appropriate latch to protect a given table's statistics. +table->id is used to pick the corresponding latch from a global array of +latches. */ UNIV_INTERN void -dict_index_stat_mutex_enter( -/*========================*/ - const dict_index_t* index); /*!< in: index */ +dict_table_stats_lock( +/*==================*/ + const dict_table_t* table, /*!< in: table */ + ulint latch_mode); /*!< in: RW_S_LATCH or + RW_X_LATCH */ /**********************************************************************//** -Unlock the appropriate mutex that protects index->stat_n_diff_key_vals[]. */ +Unlock the latch that has been locked by dict_table_stats_lock() */ UNIV_INTERN void -dict_index_stat_mutex_exit( -/*=======================*/ - const dict_index_t* index); /*!< in: index */ +dict_table_stats_unlock( +/*====================*/ + const dict_table_t* table, /*!< in: table */ + ulint latch_mode); /*!< in: RW_S_LATCH or + RW_X_LATCH */ /********************************************************************//** Checks if the database name in two table names is the same. @return TRUE if same db name */ diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index 827be32bdf7..b121edd0f3a 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -871,7 +871,8 @@ row_update_statistics_if_needed( if (counter > 2000000000 || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) { - dict_update_statistics(table); + dict_update_statistics(table, FALSE /* update even if stats + are initialized */); } } @@ -2953,7 +2954,8 @@ next_rec: dict_table_autoinc_lock(table); dict_table_autoinc_initialize(table, 1); dict_table_autoinc_unlock(table); - dict_update_statistics(table); + dict_update_statistics(table, FALSE /* update even if stats are + initialized */); trx_commit_for_mysql(trx); From 64e476e070b473cd55b1f3338d84c24e4017e1a3 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 2 Nov 2010 17:28:34 -0500 Subject: [PATCH 008/238] In this patch, existing tests innodb_bug54679.test and innodb_bug56632.test are removed and replaced by the comprehensive innodb-create-options.test. It uses the rules listed in the comments at the top of that test. This patch introduces these differences from previous behavior; 1) KEY_BLOCK_SIZE=0 is allowed by Innodb in both strict and non-strict mode with no errors or warnings. It was previously used by the server to set KEY_BLOCK_SIZE to undefined. (Bug#56628) 2) An explicit valid non-DEFAULT ROW_FORMAT always takes priority over a valid KEY_BLOCK_SIZE. (bug#56632) 3) Automatic use of COMPRESSED row format is only done if the ROW_FORMAT is DEFAULT or unspecified. 4) ROW_FORMAT=FIXED is prevented in strict mode. This patch also includes various formatting changes for consistency with InnoDB coding standards. Related Bugs Bug#54679: ALTER TABLE causes compressed row_format to revert to compact Bug#56628: ALTER TABLE .. KEY_BLOCK_SIZE=0 produces untrue warning or unnecessary error Bug#56632: ALTER TABLE implicitly changes ROW_FORMAT to COMPRESSED --- .../r/innodb-create-options.result | 854 ++++++++++++++++++ .../suite/innodb_plugin/r/innodb-zip.result | 20 +- .../innodb_plugin/r/innodb_bug54679.result | 91 -- .../innodb_plugin/r/innodb_bug56632.result | 294 ------ .../t/innodb-create-options.test | 575 ++++++++++++ .../suite/innodb_plugin/t/innodb-zip.test | 8 +- .../innodb_plugin/t/innodb_bug54679.test | 97 -- .../innodb_plugin/t/innodb_bug56632.test | 216 ----- storage/innodb_plugin/handler/ha_innodb.cc | 291 +++--- 9 files changed, 1575 insertions(+), 871 deletions(-) create mode 100755 mysql-test/suite/innodb_plugin/r/innodb-create-options.result delete mode 100644 mysql-test/suite/innodb_plugin/r/innodb_bug54679.result delete mode 100755 mysql-test/suite/innodb_plugin/r/innodb_bug56632.result create mode 100755 mysql-test/suite/innodb_plugin/t/innodb-create-options.test delete mode 100644 mysql-test/suite/innodb_plugin/t/innodb_bug54679.test delete mode 100755 mysql-test/suite/innodb_plugin/t/innodb_bug56632.test diff --git a/mysql-test/suite/innodb_plugin/r/innodb-create-options.result b/mysql-test/suite/innodb_plugin/r/innodb-create-options.result new file mode 100755 index 00000000000..aec9d731ce6 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/r/innodb-create-options.result @@ -0,0 +1,854 @@ +SET storage_engine=InnoDB; +SET GLOBAL innodb_file_format=`Barracuda`; +SET GLOBAL innodb_file_per_table=ON; +SET SESSION innodb_strict_mode = ON; +# Test 1) StrictMode=ON, CREATE and ALTER with each ROW_FORMAT & KEY_BLOCK_SIZE=0 +# KEY_BLOCK_SIZE=0 means 'no KEY_BLOCK_SIZE is specified' +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +# 'FIXED' is sent to InnoDB since it is used by MyISAM. +# But it is an invalid mode in InnoDB +CREATE TABLE t1 ( i INT ) ROW_FORMAT=FIXED; +ERROR HY000: Can't create table 'test.t1' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: invalid ROW_FORMAT specifier. +Error 1005 Can't create table 'test.t1' (errno: 1478) +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED +ALTER TABLE t1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=COMPACT +ALTER TABLE t1 ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Dynamic row_format=DYNAMIC +ALTER TABLE t1 ROW_FORMAT=REDUNDANT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Redundant row_format=REDUNDANT +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact +ALTER TABLE t1 ROW_FORMAT=FIXED KEY_BLOCK_SIZE=0; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: invalid ROW_FORMAT specifier. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact +# Test 2) StrictMode=ON, CREATE with each ROW_FORMAT & a valid non-zero KEY_BLOCK_SIZE +# KEY_BLOCK_SIZE is incompatible with COMPACT, REDUNDANT, & DYNAMIC +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1; +ERROR HY000: Can't create table 'test.t1' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. +Error 1005 Can't create table 'test.t1' (errno: 1478) +CREATE TABLE t1 ( i INT ) ROW_FORMAT=REDUNDANT KEY_BLOCK_SIZE=2; +ERROR HY000: Can't create table 'test.t1' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE. +Error 1005 Can't create table 'test.t1' (errno: 1478) +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=4; +ERROR HY000: Can't create table 'test.t1' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. +Error 1005 Can't create table 'test.t1' (errno: 1478) +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=8 +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=8 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=16; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed KEY_BLOCK_SIZE=16 +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed KEY_BLOCK_SIZE=16 +# Test 3) StrictMode=ON, ALTER with each ROW_FORMAT & a valid non-zero KEY_BLOCK_SIZE +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ); +ALTER TABLE t1 ROW_FORMAT=FIXED KEY_BLOCK_SIZE=1; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: invalid ROW_FORMAT specifier. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=2; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=4; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=REDUNDANT KEY_BLOCK_SIZE=8; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=16; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed KEY_BLOCK_SIZE=16 +ALTER TABLE t1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=1 +# Test 4) StrictMode=ON, CREATE with ROW_FORMAT=COMPACT, ALTER with a valid non-zero KEY_BLOCK_SIZE +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=COMPACT +ALTER TABLE t1 KEY_BLOCK_SIZE=2; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=REDUNDANT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Redundant row_format=REDUNDANT +ALTER TABLE t1 KEY_BLOCK_SIZE=4; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=DYNAMIC; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Dynamic row_format=DYNAMIC +ALTER TABLE t1 KEY_BLOCK_SIZE=8; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=COMPRESSED; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED +ALTER TABLE t1 KEY_BLOCK_SIZE=16; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=16 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT; +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=1; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed KEY_BLOCK_SIZE=1 +# Test 5) StrictMode=ON, CREATE with a valid KEY_BLOCK_SIZE +# ALTER with each ROW_FORMAT +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) KEY_BLOCK_SIZE=2; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=2 +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` int(11) DEFAULT NULL, + `f1` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=2 +ALTER TABLE t1 ROW_FORMAT=COMPACT; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=REDUNDANT; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=DYNAMIC; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=COMPRESSED; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=2 +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact +ALTER TABLE t1 ROW_FORMAT=COMPACT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=COMPACT +# Test 6) StrictMode=ON, CREATE with an invalid KEY_BLOCK_SIZE. +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) KEY_BLOCK_SIZE=9; +ERROR HY000: Can't create table 'test.t1' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] +Error 1005 Can't create table 'test.t1' (errno: 1478) +# Test 7) StrictMode=ON, Make sure ROW_FORMAT= COMPRESSED & DYNAMIC and +# and a valid non-zero KEY_BLOCK_SIZE are rejected with Antelope +# and that they can be set to default values during strict mode. +SET GLOBAL innodb_file_format=Antelope; +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1 ( i INT ) KEY_BLOCK_SIZE=4; +ERROR HY000: Can't create table 'test.t1' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. +Error 1005 Can't create table 'test.t1' (errno: 1478) +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED; +ERROR HY000: Can't create table 'test.t1' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_format > Antelope. +Error 1005 Can't create table 'test.t1' (errno: 1478) +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DYNAMIC; +ERROR HY000: Can't create table 'test.t1' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope. +Error 1005 Can't create table 'test.t1' (errno: 1478) +CREATE TABLE t1 ( i INT ) ROW_FORMAT=REDUNDANT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Redundant row_format=REDUNDANT +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=COMPACT +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DEFAULT; +SHOW WARNINGS; +Level Code Message +ALTER TABLE t1 KEY_BLOCK_SIZE=8; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=COMPRESSED; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_format > Antelope. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=DYNAMIC; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +SET GLOBAL innodb_file_format=Barracuda; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4; +SET GLOBAL innodb_file_format=Antelope; +ALTER TABLE t1 ADD COLUMN f1 INT; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. +Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_format > Antelope. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +Level Code Message +ALTER TABLE t1 ADD COLUMN f2 INT; +SHOW WARNINGS; +Level Code Message +SET GLOBAL innodb_file_format=Barracuda; +# Test 8) StrictMode=ON, Make sure ROW_FORMAT= COMPRESSED & DYNAMIC and +# and a valid non-zero KEY_BLOCK_SIZE are rejected with +# innodb_file_per_table=OFF and that they can be set to default +# values during strict mode. +SET GLOBAL innodb_file_per_table=OFF; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) KEY_BLOCK_SIZE=16; +ERROR HY000: Can't create table 'test.t1' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. +Error 1005 Can't create table 'test.t1' (errno: 1478) +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED; +ERROR HY000: Can't create table 'test.t1' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table. +Error 1005 Can't create table 'test.t1' (errno: 1478) +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DYNAMIC; +ERROR HY000: Can't create table 'test.t1' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table. +Error 1005 Can't create table 'test.t1' (errno: 1478) +CREATE TABLE t1 ( i INT ) ROW_FORMAT=REDUNDANT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Redundant row_format=REDUNDANT +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=COMPACT +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DEFAULT; +SHOW WARNINGS; +Level Code Message +ALTER TABLE t1 KEY_BLOCK_SIZE=1; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=COMPRESSED; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=DYNAMIC; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=COMPACT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=COMPACT +ALTER TABLE t1 ROW_FORMAT=REDUNDANT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Redundant row_format=REDUNDANT +ALTER TABLE t1 ROW_FORMAT=DEFAULT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact +SET GLOBAL innodb_file_per_table=ON; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4; +SET GLOBAL innodb_file_per_table=OFF; +ALTER TABLE t1 ADD COLUMN f1 INT; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. +Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +Level Code Message +ALTER TABLE t1 ADD COLUMN f2 INT; +SHOW WARNINGS; +Level Code Message +SET GLOBAL innodb_file_per_table=ON; +################################################## +SET SESSION innodb_strict_mode = OFF; +# Test 9) StrictMode=OFF, CREATE and ALTER with each ROW_FORMAT & KEY_BLOCK_SIZE=0 +# KEY_BLOCK_SIZE=0 means 'no KEY_BLOCK_SIZE is specified' +# 'FIXED' is sent to InnoDB since it is used by MyISAM. +# It is an invalid mode in InnoDB, use COMPACT +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=FIXED; +Warnings: +Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=FIXED +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED +ALTER TABLE t1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=COMPACT +ALTER TABLE t1 ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Dynamic row_format=DYNAMIC +ALTER TABLE t1 ROW_FORMAT=REDUNDANT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Redundant row_format=REDUNDANT +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact +ALTER TABLE t1 ROW_FORMAT=FIXED KEY_BLOCK_SIZE=0; +Warnings: +Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=FIXED +# Test 10) StrictMode=OFF, CREATE with each ROW_FORMAT & a valid KEY_BLOCK_SIZE +# KEY_BLOCK_SIZE is ignored with COMPACT, REDUNDANT, & DYNAMIC +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1; +Warnings: +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=COMPACT KEY_BLOCK_SIZE=1 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=REDUNDANT KEY_BLOCK_SIZE=2; +Warnings: +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=2 unless ROW_FORMAT=COMPRESSED. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=2 unless ROW_FORMAT=COMPRESSED. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Redundant row_format=REDUNDANT KEY_BLOCK_SIZE=2 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=4; +Warnings: +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=4 unless ROW_FORMAT=COMPRESSED. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=4 unless ROW_FORMAT=COMPRESSED. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Dynamic row_format=DYNAMIC KEY_BLOCK_SIZE=4 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=8 +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=8 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=16; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed KEY_BLOCK_SIZE=16 +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed KEY_BLOCK_SIZE=16 +# Test 11) StrictMode=OFF, ALTER with each ROW_FORMAT & a valid KEY_BLOCK_SIZE +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ); +ALTER TABLE t1 ROW_FORMAT=FIXED KEY_BLOCK_SIZE=1; +Warnings: +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. +Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. +Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=FIXED KEY_BLOCK_SIZE=1 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ); +ALTER TABLE t1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=2; +Warnings: +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=2 unless ROW_FORMAT=COMPRESSED. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=2 unless ROW_FORMAT=COMPRESSED. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=COMPACT KEY_BLOCK_SIZE=2 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ); +ALTER TABLE t1 ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=4; +Warnings: +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=4 unless ROW_FORMAT=COMPRESSED. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=4 unless ROW_FORMAT=COMPRESSED. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Dynamic row_format=DYNAMIC KEY_BLOCK_SIZE=4 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ); +ALTER TABLE t1 ROW_FORMAT=REDUNDANT KEY_BLOCK_SIZE=8; +Warnings: +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=8 unless ROW_FORMAT=COMPRESSED. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=8 unless ROW_FORMAT=COMPRESSED. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Redundant row_format=REDUNDANT KEY_BLOCK_SIZE=8 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ); +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=16; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed KEY_BLOCK_SIZE=16 +ALTER TABLE t1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=1 +# Test 12) StrictMode=OFF, CREATE with ROW_FORMAT=COMPACT, ALTER with a valid KEY_BLOCK_SIZE +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=COMPACT +ALTER TABLE t1 KEY_BLOCK_SIZE=2; +Warnings: +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=2 unless ROW_FORMAT=COMPRESSED. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=2 unless ROW_FORMAT=COMPRESSED. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=COMPACT KEY_BLOCK_SIZE=2 +ALTER TABLE t1 ROW_FORMAT=REDUNDANT; +Warnings: +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=2 unless ROW_FORMAT=COMPRESSED. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=2 unless ROW_FORMAT=COMPRESSED. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Redundant row_format=REDUNDANT KEY_BLOCK_SIZE=2 +ALTER TABLE t1 ROW_FORMAT=DYNAMIC; +Warnings: +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=2 unless ROW_FORMAT=COMPRESSED. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=2 unless ROW_FORMAT=COMPRESSED. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Dynamic row_format=DYNAMIC KEY_BLOCK_SIZE=2 +ALTER TABLE t1 ROW_FORMAT=COMPRESSED; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=2 +ALTER TABLE t1 KEY_BLOCK_SIZE=4; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=4 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT; +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=8; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed KEY_BLOCK_SIZE=8 +# Test 13) StrictMode=OFF, CREATE with a valid KEY_BLOCK_SIZE +# ALTER with each ROW_FORMAT +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) KEY_BLOCK_SIZE=16; +SHOW WARNINGS; +Level Code Message +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=16 +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW WARNINGS; +Level Code Message +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` int(11) DEFAULT NULL, + `f1` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=16 +ALTER TABLE t1 ROW_FORMAT=COMPACT; +Warnings: +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=16 unless ROW_FORMAT=COMPRESSED. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=16 unless ROW_FORMAT=COMPRESSED. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=COMPACT KEY_BLOCK_SIZE=16 +ALTER TABLE t1 ROW_FORMAT=REDUNDANT; +Warnings: +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=16 unless ROW_FORMAT=COMPRESSED. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=16 unless ROW_FORMAT=COMPRESSED. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Redundant row_format=REDUNDANT KEY_BLOCK_SIZE=16 +ALTER TABLE t1 ROW_FORMAT=DYNAMIC; +Warnings: +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=16 unless ROW_FORMAT=COMPRESSED. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=16 unless ROW_FORMAT=COMPRESSED. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Dynamic row_format=DYNAMIC KEY_BLOCK_SIZE=16 +ALTER TABLE t1 ROW_FORMAT=COMPRESSED; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=16 +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact +ALTER TABLE t1 ROW_FORMAT=COMPACT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=COMPACT +# Test 14) StrictMode=OFF, CREATE with an invalid KEY_BLOCK_SIZE, it defaults to 8 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) KEY_BLOCK_SIZE=15; +Warnings: +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=15. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=15. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact KEY_BLOCK_SIZE=15 +# Test 15) StrictMode=OFF, Make sure ROW_FORMAT= COMPRESSED & DYNAMIC and a +valid KEY_BLOCK_SIZE are remembered but not used when ROW_FORMAT +is reverted to Antelope and then used again when ROW_FORMAT=Barracuda. +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=1 +SET GLOBAL innodb_file_format=Antelope; +ALTER TABLE t1 ADD COLUMN f1 INT; +Warnings: +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1. +Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_format > Antelope. +Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1. +Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_format > Antelope. +Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=COMPRESSED KEY_BLOCK_SIZE=1 +SET GLOBAL innodb_file_format=Barracuda; +ALTER TABLE t1 ADD COLUMN f2 INT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=1 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DYNAMIC; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Dynamic row_format=DYNAMIC +SET GLOBAL innodb_file_format=Antelope; +ALTER TABLE t1 ADD COLUMN f1 INT; +Warnings: +Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope. +Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope. +Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=DYNAMIC +SET GLOBAL innodb_file_format=Barracuda; +ALTER TABLE t1 ADD COLUMN f2 INT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Dynamic row_format=DYNAMIC +# Test 16) StrictMode=OFF, Make sure ROW_FORMAT= COMPRESSED & DYNAMIC and a +valid KEY_BLOCK_SIZE are remembered but not used when innodb_file_per_table=OFF +and then used again when innodb_file_per_table=ON. +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=2; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=2 +SET GLOBAL innodb_file_per_table=OFF; +ALTER TABLE t1 ADD COLUMN f1 INT; +Warnings: +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=2. +Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table. +Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. +Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=2. +Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table. +Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=COMPRESSED KEY_BLOCK_SIZE=2 +SET GLOBAL innodb_file_per_table=ON; +ALTER TABLE t1 ADD COLUMN f2 INT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=2 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DYNAMIC; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Dynamic row_format=DYNAMIC +SET GLOBAL innodb_file_per_table=OFF; +ALTER TABLE t1 ADD COLUMN f1 INT; +Warnings: +Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table. +Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table. +Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Compact row_format=DYNAMIC +SET GLOBAL innodb_file_per_table=ON; +ALTER TABLE t1 ADD COLUMN f2 INT; +SHOW WARNINGS; +Level Code Message +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +t1 Dynamic row_format=DYNAMIC +# Cleanup +DROP TABLE IF EXISTS t1; diff --git a/mysql-test/suite/innodb_plugin/r/innodb-zip.result b/mysql-test/suite/innodb_plugin/r/innodb-zip.result index 21396d81ba8..fc35143b305 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb-zip.result +++ b/mysql-test/suite/innodb_plugin/r/innodb-zip.result @@ -83,8 +83,6 @@ test t8 Compact test t9 Compact drop table t0,t00,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14; alter table t1 key_block_size=0; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=0. alter table t1 row_format=dynamic; SELECT table_schema, table_name, row_format FROM information_schema.tables WHERE engine='innodb'; @@ -190,16 +188,9 @@ set global innodb_file_per_table = on; set global innodb_file_format = `1`; set innodb_strict_mode = off; create table t1 (id int primary key) engine = innodb key_block_size = 0; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=0. drop table t1; set innodb_strict_mode = on; create table t1 (id int primary key) engine = innodb key_block_size = 0; -ERROR HY000: Can't create table 'test.t1' (errno: 1478) -show warnings; -Level Code Message -Warning 1478 InnoDB: invalid KEY_BLOCK_SIZE = 0. Valid values are [1, 2, 4, 8, 16] -Error 1005 Can't create table 'test.t1' (errno: 1478) create table t2 (id int primary key) engine = innodb key_block_size = 9; ERROR HY000: Can't create table 'test.t2' (errno: 1478) show warnings; @@ -218,6 +209,7 @@ create table t11(id int primary key) engine = innodb row_format = redundant; SELECT table_schema, table_name, row_format FROM information_schema.tables WHERE engine='innodb'; table_schema table_name row_format +test t1 Compact test t10 Compact test t11 Redundant test t3 Compressed @@ -227,7 +219,7 @@ test t6 Compressed test t7 Compressed test t8 Compressed test t9 Dynamic -drop table t3, t4, t5, t6, t7, t8, t9, t10, t11; +drop table t1, t3, t4, t5, t6, t7, t8, t9, t10, t11; create table t1 (id int primary key) engine = innodb key_block_size = 8 row_format = compressed; create table t2 (id int primary key) engine = innodb @@ -253,16 +245,12 @@ Warning 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. Error 1005 Can't create table 'test.t4' (errno: 1478) create table t5 (id int primary key) engine = innodb key_block_size = 8 row_format = default; -ERROR HY000: Can't create table 'test.t5' (errno: 1478) -show warnings; -Level Code Message -Warning 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. -Error 1005 Can't create table 'test.t5' (errno: 1478) SELECT table_schema, table_name, row_format FROM information_schema.tables WHERE engine='innodb'; table_schema table_name row_format test t1 Compressed -drop table t1; +test t5 Compressed +drop table t1, t5; create table t1 (id int primary key) engine = innodb key_block_size = 9 row_format = redundant; ERROR HY000: Can't create table 'test.t1' (errno: 1478) diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug54679.result b/mysql-test/suite/innodb_plugin/r/innodb_bug54679.result deleted file mode 100644 index 14fd32ca469..00000000000 --- a/mysql-test/suite/innodb_plugin/r/innodb_bug54679.result +++ /dev/null @@ -1,91 +0,0 @@ -SET GLOBAL innodb_file_format='Barracuda'; -SET GLOBAL innodb_file_per_table=ON; -SET innodb_strict_mode=ON; -CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables -WHERE TABLE_NAME='bug54679'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug54679 Compressed row_format=COMPRESSED -ALTER TABLE bug54679 ADD COLUMN b INT; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables -WHERE TABLE_NAME='bug54679'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug54679 Compressed row_format=COMPRESSED -DROP TABLE bug54679; -CREATE TABLE bug54679 (a INT) ENGINE=InnoDB; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables -WHERE TABLE_NAME='bug54679'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug54679 Compact -ALTER TABLE bug54679 KEY_BLOCK_SIZE=1; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables -WHERE TABLE_NAME='bug54679'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug54679 Compressed KEY_BLOCK_SIZE=1 -ALTER TABLE bug54679 ROW_FORMAT=REDUNDANT; -ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE. -Error 1005 Can't create table '#sql-temporary' (errno: 1478) -DROP TABLE bug54679; -CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=REDUNDANT; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables -WHERE TABLE_NAME='bug54679'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug54679 Redundant row_format=REDUNDANT -ALTER TABLE bug54679 KEY_BLOCK_SIZE=2; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables -WHERE TABLE_NAME='bug54679'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug54679 Compressed row_format=REDUNDANT KEY_BLOCK_SIZE=2 -SET GLOBAL innodb_file_format=Antelope; -ALTER TABLE bug54679 KEY_BLOCK_SIZE=4; -ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. -Error 1005 Can't create table '#sql-temporary' (errno: 1478) -ALTER TABLE bug54679 ROW_FORMAT=DYNAMIC; -ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. -Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope. -Warning 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. -Error 1005 Can't create table '#sql-temporary' (errno: 1478) -DROP TABLE bug54679; -CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; -ERROR HY000: Can't create table 'test.bug54679' (errno: 1478) -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope. -Error 1005 Can't create table 'test.bug54679' (errno: 1478) -CREATE TABLE bug54679 (a INT) ENGINE=InnoDB; -SET GLOBAL innodb_file_format=Barracuda; -SET GLOBAL innodb_file_per_table=OFF; -ALTER TABLE bug54679 KEY_BLOCK_SIZE=4; -ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. -Error 1005 Can't create table '#sql-temporary' (errno: 1478) -ALTER TABLE bug54679 ROW_FORMAT=DYNAMIC; -ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table. -Error 1005 Can't create table '#sql-temporary' (errno: 1478) -DROP TABLE bug54679; -CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; -ERROR HY000: Can't create table 'test.bug54679' (errno: 1478) -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table. -Error 1005 Can't create table 'test.bug54679' (errno: 1478) -SET GLOBAL innodb_file_per_table=ON; -CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; -DROP TABLE bug54679; -SET GLOBAL innodb_file_format=Antelope; -SET GLOBAL innodb_file_format_check=Antelope; -SET GLOBAL innodb_file_per_table=0; diff --git a/mysql-test/suite/innodb_plugin/r/innodb_bug56632.result b/mysql-test/suite/innodb_plugin/r/innodb_bug56632.result deleted file mode 100755 index 8236b37676b..00000000000 --- a/mysql-test/suite/innodb_plugin/r/innodb_bug56632.result +++ /dev/null @@ -1,294 +0,0 @@ -SET storage_engine=InnoDB; -SET GLOBAL innodb_file_format=`Barracuda`; -SET GLOBAL innodb_file_per_table=ON; -SET SESSION innodb_strict_mode = ON; -# Test 1) CREATE with ROW_FORMAT & KEY_BLOCK_SIZE, ALTER with neither -DROP TABLE IF EXISTS bug56632; -Warnings: -Note 1051 Unknown table 'bug56632' -CREATE TABLE bug56632 ( i INT ) ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1; -ERROR HY000: Can't create table 'test.bug56632' (errno: 1478) -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. -Error 1005 Can't create table 'test.bug56632' (errno: 1478) -# Test 2) CREATE with ROW_FORMAT, ALTER with KEY_BLOCK_SIZE -DROP TABLE IF EXISTS bug56632; -Warnings: -Note 1051 Unknown table 'bug56632' -CREATE TABLE bug56632 ( i INT ) ROW_FORMAT=COMPACT; -SHOW WARNINGS; -Level Code Message -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compact row_format=COMPACT -ALTER TABLE bug56632 KEY_BLOCK_SIZE=1; -SHOW WARNINGS; -Level Code Message -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compressed row_format=COMPACT KEY_BLOCK_SIZE=1 -# Test 3) CREATE with KEY_BLOCK_SIZE, ALTER with ROW_FORMAT -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=1; -SHOW WARNINGS; -Level Code Message -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=1 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compressed KEY_BLOCK_SIZE=1 -ALTER TABLE bug56632 ROW_FORMAT=COMPACT; -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=1 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compressed KEY_BLOCK_SIZE=1 -# Test 4) CREATE with neither, ALTER with ROW_FORMAT & KEY_BLOCK_SIZE -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ); -SHOW WARNINGS; -Level Code Message -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compact -ALTER TABLE bug56632 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1; -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compact -# Test 5) CREATE with KEY_BLOCK_SIZE=3 (invalid). -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=3; -ERROR HY000: Can't create table 'test.bug56632' (errno: 1478) -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: invalid KEY_BLOCK_SIZE = 3. Valid values are [1, 2, 4, 8, 16] -Error 1005 Can't create table 'test.bug56632' (errno: 1478) -SET SESSION innodb_strict_mode = OFF; -# Test 6) CREATE with ROW_FORMAT & KEY_BLOCK_SIZE, ALTER with neither -DROP TABLE IF EXISTS bug56632; -Warnings: -Note 1051 Unknown table 'bug56632' -CREATE TABLE bug56632 ( i INT ) ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compact row_format=COMPACT KEY_BLOCK_SIZE=1 -ALTER TABLE bug56632 ADD COLUMN f1 INT; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL, - `f1` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compact row_format=COMPACT KEY_BLOCK_SIZE=1 -# Test 7) CREATE with ROW_FORMAT, ALTER with KEY_BLOCK_SIZE -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ) ROW_FORMAT=COMPACT; -SHOW WARNINGS; -Level Code Message -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compact row_format=COMPACT -ALTER TABLE bug56632 KEY_BLOCK_SIZE=1; -SHOW WARNINGS; -Level Code Message -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compressed row_format=COMPACT KEY_BLOCK_SIZE=1 -# Test 8) CREATE with KEY_BLOCK_SIZE, ALTER with ROW_FORMAT -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=1; -SHOW WARNINGS; -Level Code Message -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=1 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compressed KEY_BLOCK_SIZE=1 -ALTER TABLE bug56632 ROW_FORMAT=COMPACT; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compact row_format=COMPACT KEY_BLOCK_SIZE=1 -# Test 9) CREATE with neither, ALTER with ROW_FORMAT & KEY_BLOCK_SIZE -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ); -SHOW WARNINGS; -Level Code Message -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compact -ALTER TABLE bug56632 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compact row_format=COMPACT KEY_BLOCK_SIZE=1 -# Test 10) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with neither. -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=3; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=3. -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=3. -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=3 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compact KEY_BLOCK_SIZE=3 -ALTER TABLE bug56632 ADD COLUMN f1 INT; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=3. -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=3. -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL, - `f1` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=3 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compact KEY_BLOCK_SIZE=3 -# Test 11) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with ROW_FORMAT=COMPACT. -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=3; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=3. -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=3. -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=3 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compact KEY_BLOCK_SIZE=3 -ALTER TABLE bug56632 ROW_FORMAT=COMPACT; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=3. -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=3. -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=3 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compact row_format=COMPACT KEY_BLOCK_SIZE=3 -# Test 12) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with KEY_BLOCK_SIZE=1. -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=3; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=3. -SHOW WARNINGS; -Level Code Message -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=3. -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=3 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compact KEY_BLOCK_SIZE=3 -ALTER TABLE bug56632 KEY_BLOCK_SIZE=1; -SHOW WARNINGS; -Level Code Message -SHOW CREATE TABLE bug56632; -Table Create Table -bug56632 CREATE TABLE `bug56632` ( - `i` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=1 -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -TABLE_NAME ROW_FORMAT CREATE_OPTIONS -bug56632 Compressed KEY_BLOCK_SIZE=1 -# Cleanup -DROP TABLE IF EXISTS bug56632; diff --git a/mysql-test/suite/innodb_plugin/t/innodb-create-options.test b/mysql-test/suite/innodb_plugin/t/innodb-create-options.test new file mode 100755 index 00000000000..2f95ccc45cb --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/innodb-create-options.test @@ -0,0 +1,575 @@ +# Tests for various combinations of ROW_FORMAT and KEY_BLOCK_SIZE +# Related bugs; +# Bug#54679: ALTER TABLE causes compressed row_format to revert to compact +# Bug#56628: ALTER TABLE .. KEY_BLOCK_SIZE=0 produces untrue warning or unnecessary error +# Bug#56632: ALTER TABLE implicitly changes ROW_FORMAT to COMPRESSED +# Rules for interpreting CREATE_OPTIONS +# 1) Create options on an ALTER are added to the options on the +# previous CREATE or ALTER statements. +# 2) KEY_BLOCK_SIZE=0 is considered a unspecified value. +# If the current ROW_FORMAT has explicitly been set to COMPRESSED, +# InnoDB will use a default value of 8. Otherwise KEY_BLOCK_SIZE +# will not be used. +# 3) ROW_FORMAT=DEFAULT allows InnoDB to choose its own default, COMPACT. +# 4) ROW_FORMAT=DEFAULT and KEY_BLOCK_SIZE=0 can be used at any time to +# unset or erase the values persisted in the MySQL dictionary and +# by SHOW CTREATE TABLE. +# 5) When incompatible values for ROW_FORMAT and KEY_BLOCK_SIZE are +# both explicitly given, the ROW_FORMAT is always used in non-strict +# mode. +# 6) InnoDB will automatically convert a table to COMPRESSED only if a +# valid non-zero KEY_BLOCK_SIZE has been given and ROW_FORMAT=DEFAULT +# or has not been used on a previous CREATE TABLE or ALTER TABLE. +# 7) InnoDB strict mode is designed to prevent incompatible create +# options from being used together. +# 8) The non-strict behavior is intended to permit you to import a +# mysqldump file into a database that does not support compressed +# tables, even if the source database contained compressed tables. +# All invalid values and/or incompatible combinations of ROW_FORMAT +# and KEY_BLOCK_SIZE are automatically corrected +# +# *** innodb_strict_mode=ON *** +# 1) Valid ROW_FORMATs are COMPRESSED, COMPACT, DEFAULT, DYNAMIC +# & REDUNDANT. All others are rejected. +# 2) Valid KEY_BLOCK_SIZEs are 0,1,2,4,8,16. All others are rejected. +# 3) KEY_BLOCK_SIZE=0 can be used to set it to 'unspecified'. +# 4) KEY_BLOCK_SIZE=1,2,4,8 & 16 are incompatible with COMPACT, DYNAMIC & +# REDUNDANT. +# 5) KEY_BLOCK_SIZE=1,2,4,8 & 16 as well as ROW_FORMAT=COMPRESSED and +# ROW_FORMAT=DYNAMIC are incompatible with innodb_file_format=Antelope +# and innodb_file_per_table=OFF +# 6) KEY_BLOCK_SIZE on an ALTER must occur with ROW_FORMAT=COMPRESSED +# or ROW_FORMAT=DEFAULT if the ROW_FORMAT was previously specified +# as COMPACT, DYNAMIC or REDUNDANT. +# 7) KEY_BLOCK_SIZE on an ALTER can occur without a ROW_FORMAT if the +# previous ROW_FORMAT was DEFAULT, COMPRESSED, or unspecified. +# +# *** innodb_strict_mode=OFF *** +# 1. Ignore a bad KEY_BLOCK_SIZE, defaulting it to 8. +# 2. Ignore a bad ROW_FORMAT, defaulting to COMPACT. +# 3. Ignore a valid KEY_BLOCK_SIZE when an incompatible but valid +# ROW_FORMAT is specified. +# 4. If innodb_file_format=Antelope or innodb_file_per_table=OFF +# it will ignore ROW_FORMAT=COMPRESSED or DYNAMIC and it will +# ignore all non-zero KEY_BLOCK_SIZEs. +# +# See InnoDB documentation page "SQL Compression Syntax Warnings and Errors" + +-- source include/have_innodb_plugin.inc +SET storage_engine=InnoDB; + +--disable_query_log +# These values can change during the test +LET $innodb_file_format_orig=`select @@innodb_file_format`; +LET $innodb_file_format_check_orig=`select @@innodb_file_format_check`; +LET $innodb_file_per_table_orig=`select @@innodb_file_per_table`; +LET $innodb_strict_mode_orig=`select @@session.innodb_strict_mode`; +--enable_query_log + +SET GLOBAL innodb_file_format=`Barracuda`; +SET GLOBAL innodb_file_per_table=ON; + +# The first half of these tests are with strict mode ON. +SET SESSION innodb_strict_mode = ON; + +--echo # Test 1) StrictMode=ON, CREATE and ALTER with each ROW_FORMAT & KEY_BLOCK_SIZE=0 +--echo # KEY_BLOCK_SIZE=0 means 'no KEY_BLOCK_SIZE is specified' +DROP TABLE IF EXISTS t1; +--echo # 'FIXED' is sent to InnoDB since it is used by MyISAM. +--echo # But it is an invalid mode in InnoDB +--error ER_CANT_CREATE_TABLE +CREATE TABLE t1 ( i INT ) ROW_FORMAT=FIXED; +SHOW WARNINGS; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=REDUNDANT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 ROW_FORMAT=FIXED KEY_BLOCK_SIZE=0; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; + + + +--echo # Test 2) StrictMode=ON, CREATE with each ROW_FORMAT & a valid non-zero KEY_BLOCK_SIZE +--echo # KEY_BLOCK_SIZE is incompatible with COMPACT, REDUNDANT, & DYNAMIC +DROP TABLE IF EXISTS t1; +--error ER_CANT_CREATE_TABLE +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1; +SHOW WARNINGS; +--error ER_CANT_CREATE_TABLE +CREATE TABLE t1 ( i INT ) ROW_FORMAT=REDUNDANT KEY_BLOCK_SIZE=2; +SHOW WARNINGS; +--error ER_CANT_CREATE_TABLE +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=4; +SHOW WARNINGS; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=16; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; + + +--echo # Test 3) StrictMode=ON, ALTER with each ROW_FORMAT & a valid non-zero KEY_BLOCK_SIZE +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ); +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 ROW_FORMAT=FIXED KEY_BLOCK_SIZE=1; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=2; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=4; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 ROW_FORMAT=REDUNDANT KEY_BLOCK_SIZE=8; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=16; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; + + +--echo # Test 4) StrictMode=ON, CREATE with ROW_FORMAT=COMPACT, ALTER with a valid non-zero KEY_BLOCK_SIZE +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 KEY_BLOCK_SIZE=2; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +ALTER TABLE t1 ROW_FORMAT=REDUNDANT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 KEY_BLOCK_SIZE=4; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +ALTER TABLE t1 ROW_FORMAT=DYNAMIC; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 KEY_BLOCK_SIZE=8; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +ALTER TABLE t1 ROW_FORMAT=COMPRESSED; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 KEY_BLOCK_SIZE=16; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT; +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=1; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; + +--echo # Test 5) StrictMode=ON, CREATE with a valid KEY_BLOCK_SIZE +--echo # ALTER with each ROW_FORMAT +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) KEY_BLOCK_SIZE=2; +SHOW CREATE TABLE t1; +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW CREATE TABLE t1; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 ROW_FORMAT=COMPACT; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 ROW_FORMAT=REDUNDANT; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 ROW_FORMAT=DYNAMIC; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +ALTER TABLE t1 ROW_FORMAT=COMPRESSED; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=COMPACT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; + +--echo # Test 6) StrictMode=ON, CREATE with an invalid KEY_BLOCK_SIZE. +DROP TABLE IF EXISTS t1; +--error ER_CANT_CREATE_TABLE +CREATE TABLE t1 ( i INT ) KEY_BLOCK_SIZE=9; +SHOW WARNINGS; + +--echo # Test 7) StrictMode=ON, Make sure ROW_FORMAT= COMPRESSED & DYNAMIC and +--echo # and a valid non-zero KEY_BLOCK_SIZE are rejected with Antelope +--echo # and that they can be set to default values during strict mode. +SET GLOBAL innodb_file_format=Antelope; +DROP TABLE IF EXISTS t1; +--error ER_CANT_CREATE_TABLE +CREATE TABLE t1 ( i INT ) KEY_BLOCK_SIZE=4; +SHOW WARNINGS; +--error ER_CANT_CREATE_TABLE +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED; +SHOW WARNINGS; +--error ER_CANT_CREATE_TABLE +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DYNAMIC; +SHOW WARNINGS; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=REDUNDANT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DEFAULT; +SHOW WARNINGS; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 KEY_BLOCK_SIZE=8; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 ROW_FORMAT=COMPRESSED; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 ROW_FORMAT=DYNAMIC; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +SET GLOBAL innodb_file_format=Barracuda; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4; +SET GLOBAL innodb_file_format=Antelope; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 ADD COLUMN f1 INT; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +ALTER TABLE t1 ADD COLUMN f2 INT; +SHOW WARNINGS; +SET GLOBAL innodb_file_format=Barracuda; + +--echo # Test 8) StrictMode=ON, Make sure ROW_FORMAT= COMPRESSED & DYNAMIC and +--echo # and a valid non-zero KEY_BLOCK_SIZE are rejected with +--echo # innodb_file_per_table=OFF and that they can be set to default +--echo # values during strict mode. +SET GLOBAL innodb_file_per_table=OFF; +DROP TABLE IF EXISTS t1; +--error ER_CANT_CREATE_TABLE +CREATE TABLE t1 ( i INT ) KEY_BLOCK_SIZE=16; +SHOW WARNINGS; +--error ER_CANT_CREATE_TABLE +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED; +SHOW WARNINGS; +--error ER_CANT_CREATE_TABLE +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DYNAMIC; +SHOW WARNINGS; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=REDUNDANT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DEFAULT; +SHOW WARNINGS; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 KEY_BLOCK_SIZE=1; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 ROW_FORMAT=COMPRESSED; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 ROW_FORMAT=DYNAMIC; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +ALTER TABLE t1 ROW_FORMAT=COMPACT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=REDUNDANT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=DEFAULT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +SET GLOBAL innodb_file_per_table=ON; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4; +SET GLOBAL innodb_file_per_table=OFF; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 ADD COLUMN f1 INT; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +ALTER TABLE t1 ADD COLUMN f2 INT; +SHOW WARNINGS; +SET GLOBAL innodb_file_per_table=ON; + +--echo ################################################## +SET SESSION innodb_strict_mode = OFF; + +--echo # Test 9) StrictMode=OFF, CREATE and ALTER with each ROW_FORMAT & KEY_BLOCK_SIZE=0 +--echo # KEY_BLOCK_SIZE=0 means 'no KEY_BLOCK_SIZE is specified' +--echo # 'FIXED' is sent to InnoDB since it is used by MyISAM. +--echo # It is an invalid mode in InnoDB, use COMPACT +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=FIXED; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=REDUNDANT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=FIXED KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; + +--echo # Test 10) StrictMode=OFF, CREATE with each ROW_FORMAT & a valid KEY_BLOCK_SIZE +--echo # KEY_BLOCK_SIZE is ignored with COMPACT, REDUNDANT, & DYNAMIC +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=REDUNDANT KEY_BLOCK_SIZE=2; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=4; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=16; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; + + +--echo # Test 11) StrictMode=OFF, ALTER with each ROW_FORMAT & a valid KEY_BLOCK_SIZE +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ); +ALTER TABLE t1 ROW_FORMAT=FIXED KEY_BLOCK_SIZE=1; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ); +ALTER TABLE t1 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=2; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ); +ALTER TABLE t1 ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=4; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ); +ALTER TABLE t1 ROW_FORMAT=REDUNDANT KEY_BLOCK_SIZE=8; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ); +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=16; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; + + +--echo # Test 12) StrictMode=OFF, CREATE with ROW_FORMAT=COMPACT, ALTER with a valid KEY_BLOCK_SIZE +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 KEY_BLOCK_SIZE=2; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=REDUNDANT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=DYNAMIC; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=COMPRESSED; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 KEY_BLOCK_SIZE=4; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPACT; +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=8; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; + +--echo # Test 13) StrictMode=OFF, CREATE with a valid KEY_BLOCK_SIZE +--echo # ALTER with each ROW_FORMAT +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) KEY_BLOCK_SIZE=16; +SHOW WARNINGS; +SHOW CREATE TABLE t1; +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW WARNINGS; +SHOW CREATE TABLE t1; +ALTER TABLE t1 ROW_FORMAT=COMPACT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=REDUNDANT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=DYNAMIC; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=COMPRESSED; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=DEFAULT KEY_BLOCK_SIZE=0; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +ALTER TABLE t1 ROW_FORMAT=COMPACT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; + +--echo # Test 14) StrictMode=OFF, CREATE with an invalid KEY_BLOCK_SIZE, it defaults to 8 +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) KEY_BLOCK_SIZE=15; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; + +--echo # Test 15) StrictMode=OFF, Make sure ROW_FORMAT= COMPRESSED & DYNAMIC and a +--echo valid KEY_BLOCK_SIZE are remembered but not used when ROW_FORMAT +--echo is reverted to Antelope and then used again when ROW_FORMAT=Barracuda. +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +SET GLOBAL innodb_file_format=Antelope; +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +SET GLOBAL innodb_file_format=Barracuda; +ALTER TABLE t1 ADD COLUMN f2 INT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DYNAMIC; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +SET GLOBAL innodb_file_format=Antelope; +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +SET GLOBAL innodb_file_format=Barracuda; +ALTER TABLE t1 ADD COLUMN f2 INT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; + +--echo # Test 16) StrictMode=OFF, Make sure ROW_FORMAT= COMPRESSED & DYNAMIC and a +--echo valid KEY_BLOCK_SIZE are remembered but not used when innodb_file_per_table=OFF +--echo and then used again when innodb_file_per_table=ON. +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=2; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +SET GLOBAL innodb_file_per_table=OFF; +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +SET GLOBAL innodb_file_per_table=ON; +ALTER TABLE t1 ADD COLUMN f2 INT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( i INT ) ROW_FORMAT=DYNAMIC; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +SET GLOBAL innodb_file_per_table=OFF; +ALTER TABLE t1 ADD COLUMN f1 INT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; +SET GLOBAL innodb_file_per_table=ON; +ALTER TABLE t1 ADD COLUMN f2 INT; +SHOW WARNINGS; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 't1'; + + +--echo # Cleanup +DROP TABLE IF EXISTS t1; + +--disable_query_log +EVAL SET GLOBAL innodb_file_format=$innodb_file_format_orig; +EVAL SET GLOBAL innodb_file_format_check=$innodb_file_format_check_orig; +EVAL SET GLOBAL innodb_file_per_table=$innodb_file_per_table_orig; +EVAL SET SESSION innodb_strict_mode=$innodb_strict_mode_orig; +--enable_query_log + diff --git a/mysql-test/suite/innodb_plugin/t/innodb-zip.test b/mysql-test/suite/innodb_plugin/t/innodb-zip.test index 4980af437e6..8c1ef1f5467 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb-zip.test +++ b/mysql-test/suite/innodb_plugin/t/innodb-zip.test @@ -173,9 +173,7 @@ set innodb_strict_mode = on; #Test different values of KEY_BLOCK_SIZE ---error ER_CANT_CREATE_TABLE create table t1 (id int primary key) engine = innodb key_block_size = 0; -show warnings; --error ER_CANT_CREATE_TABLE create table t2 (id int primary key) engine = innodb key_block_size = 9; @@ -196,7 +194,7 @@ create table t11(id int primary key) engine = innodb row_format = redundant; SELECT table_schema, table_name, row_format FROM information_schema.tables WHERE engine='innodb'; -drop table t3, t4, t5, t6, t7, t8, t9, t10, t11; +drop table t1, t3, t4, t5, t6, t7, t8, t9, t10, t11; #test different values of ROW_FORMAT with KEY_BLOCK_SIZE create table t1 (id int primary key) engine = innodb @@ -217,14 +215,12 @@ create table t4 (id int primary key) engine = innodb key_block_size = 8 row_format = dynamic; show warnings; ---error ER_CANT_CREATE_TABLE create table t5 (id int primary key) engine = innodb key_block_size = 8 row_format = default; -show warnings; SELECT table_schema, table_name, row_format FROM information_schema.tables WHERE engine='innodb'; -drop table t1; +drop table t1, t5; #test multiple errors --error ER_CANT_CREATE_TABLE diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug54679.test b/mysql-test/suite/innodb_plugin/t/innodb_bug54679.test deleted file mode 100644 index 863d9847ac1..00000000000 --- a/mysql-test/suite/innodb_plugin/t/innodb_bug54679.test +++ /dev/null @@ -1,97 +0,0 @@ -# Test Bug #54679 alter table causes compressed row_format to revert to compact - ---source include/have_innodb_plugin.inc - -let $file_format=`select @@innodb_file_format`; -let $file_format_check=`select @@innodb_file_format_check`; -let $file_per_table=`select @@innodb_file_per_table`; -SET GLOBAL innodb_file_format='Barracuda'; -SET GLOBAL innodb_file_per_table=ON; -SET innodb_strict_mode=ON; - -CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables -WHERE TABLE_NAME='bug54679'; - -# The ROW_FORMAT of the table should be preserved when it is not specified -# in ALTER TABLE. -ALTER TABLE bug54679 ADD COLUMN b INT; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables -WHERE TABLE_NAME='bug54679'; - -DROP TABLE bug54679; - -# Check that the ROW_FORMAT conversion to/from COMPRESSED works. - -CREATE TABLE bug54679 (a INT) ENGINE=InnoDB; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables -WHERE TABLE_NAME='bug54679'; - -# KEY_BLOCK_SIZE implies COMPRESSED. -ALTER TABLE bug54679 KEY_BLOCK_SIZE=1; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables -WHERE TABLE_NAME='bug54679'; - ---replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ ---error ER_CANT_CREATE_TABLE -ALTER TABLE bug54679 ROW_FORMAT=REDUNDANT; ---replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ -SHOW WARNINGS; -DROP TABLE bug54679; -CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=REDUNDANT; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables -WHERE TABLE_NAME='bug54679'; - -ALTER TABLE bug54679 KEY_BLOCK_SIZE=2; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables -WHERE TABLE_NAME='bug54679'; - -# This prevents other than REDUNDANT or COMPACT ROW_FORMAT for new tables. -SET GLOBAL innodb_file_format=Antelope; - ---replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ ---error ER_CANT_CREATE_TABLE -ALTER TABLE bug54679 KEY_BLOCK_SIZE=4; ---replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ -SHOW WARNINGS; ---replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ ---error ER_CANT_CREATE_TABLE -ALTER TABLE bug54679 ROW_FORMAT=DYNAMIC; ---replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ -SHOW WARNINGS; -DROP TABLE bug54679; ---replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ ---error ER_CANT_CREATE_TABLE -CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; ---replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ -SHOW WARNINGS; -CREATE TABLE bug54679 (a INT) ENGINE=InnoDB; - -SET GLOBAL innodb_file_format=Barracuda; -# This will prevent ROW_FORMAT=COMPRESSED, because the system tablespace -# cannot be compressed. -SET GLOBAL innodb_file_per_table=OFF; - ---replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ ---error ER_CANT_CREATE_TABLE -ALTER TABLE bug54679 KEY_BLOCK_SIZE=4; ---replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ -SHOW WARNINGS; ---replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ ---error ER_CANT_CREATE_TABLE -ALTER TABLE bug54679 ROW_FORMAT=DYNAMIC; ---replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ -SHOW WARNINGS; -DROP TABLE bug54679; ---replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ ---error ER_CANT_CREATE_TABLE -CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; ---replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ -SHOW WARNINGS; -SET GLOBAL innodb_file_per_table=ON; -CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; -DROP TABLE bug54679; - -EVAL SET GLOBAL innodb_file_format=$file_format; -EVAL SET GLOBAL innodb_file_format_check=$file_format_check; -EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/mysql-test/suite/innodb_plugin/t/innodb_bug56632.test b/mysql-test/suite/innodb_plugin/t/innodb_bug56632.test deleted file mode 100755 index 7f1c41cddfa..00000000000 --- a/mysql-test/suite/innodb_plugin/t/innodb_bug56632.test +++ /dev/null @@ -1,216 +0,0 @@ -# -# Bug#56632: ALTER TABLE implicitly changes ROW_FORMAT to COMPRESSED -# http://bugs.mysql.com/56632 -# -# Innodb automatically uses compressed mode when the KEY_BLOCK_SIZE -# parameter is used, except if the ROW_FORMAT is also specified, in -# which case the KEY_BLOCK_SIZE is ignored and a warning is shown. -# But Innodb was getting confused when neither of those parameters -# was used on the ALTER statement after they were both used on the -# CREATE. -# -# This will test the results of all 4 combinations of these two -# parameters of the CREATE and ALTER. -# -# Tests 1-5 use INNODB_STRICT_MODE=1 which returns an error -# if there is anything wrong with the statement. -# -# 1) CREATE with ROW_FORMAT=COMPACT & KEY_BLOCK_SIZE=1, ALTER with neither. -# Result; CREATE; fails with error ER_CANT_CREATE_TABLE -# 2) CREATE with ROW_FORMAT=COMPACT, ALTER with KEY_BLOCK_SIZE=1 -# Result; CREATE succeeds, -# ALTER quietly converts ROW_FORMAT to compressed. -# 3) CREATE with KEY_BLOCK_SIZE=1, ALTER with ROW_FORMAT=COMPACT -# Result; CREATE quietly converts ROW_FORMAT to compressed, -# ALTER fails with error ER_CANT_CREATE_TABLE. -# 4) CREATE with neither, ALTER with ROW_FORMAT=COMPACT & KEY_BLOCK_SIZE=1 -# Result; CREATE succeeds, -# ALTER; fails with error ER_CANT_CREATE_TABLE -# 5) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with neither. -# Result; CREATE; fails with error ER_CANT_CREATE_TABLE -# -# Tests 6-11 use INNODB_STRICT_MODE=0 which automatically makes -# adjustments if the prameters are incompatible. -# -# 6) CREATE with ROW_FORMAT=COMPACT & KEY_BLOCK_SIZE=1, ALTER with neither. -# Result; CREATE succeeds, warns that KEY_BLOCK_SIZE is ignored. -# ALTER succeeds, no warnings. -# 7) CREATE with ROW_FORMAT=COMPACT, ALTER with KEY_BLOCK_SIZE=1 -# Result; CREATE succeeds, -# ALTER quietly converts ROW_FORMAT to compressed. -# 8) CREATE with KEY_BLOCK_SIZE=1, ALTER with ROW_FORMAT=COMPACT -# Result; CREATE quietly converts ROW_FORMAT to compressed, -# ALTER succeeds, warns that KEY_BLOCK_SIZE is ignored. -# 9) CREATE with neither, ALTER with ROW_FORMAT=COMPACT & KEY_BLOCK_SIZE=1 -# Result; CREATE succeeds, -# ALTER succeeds, warns that KEY_BLOCK_SIZE is ignored. -# 10) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with neither. -# Result; CREATE succeeds, warns that KEY_BLOCK_SIZE=3 is ignored. -# ALTER succeeds, warns that KEY_BLOCK_SIZE=3 is ignored. -# 11) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with ROW_FORMAT=COMPACT. -# Result; CREATE succeeds, warns that KEY_BLOCK_SIZE=3 is ignored. -# ALTER succeeds, warns that KEY_BLOCK_SIZE=3 is ignored. -# 12) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with KEY_BLOCK_SIZE=1. -# Result; CREATE succeeds, warns that KEY_BLOCK_SIZE=3 is ignored. -# ALTER succeeds, quietly converts ROW_FORMAT to compressed. - --- source include/have_innodb_plugin.inc - -SET storage_engine=InnoDB; - ---disable_query_log -# These values can change during the test -LET $innodb_file_format_orig=`select @@innodb_file_format`; -LET $innodb_file_format_check_orig=`select @@innodb_file_format_check`; -LET $innodb_file_per_table_orig=`select @@innodb_file_per_table`; -LET $innodb_strict_mode_orig=`select @@session.innodb_strict_mode`; ---enable_query_log - -SET GLOBAL innodb_file_format=`Barracuda`; -SET GLOBAL innodb_file_per_table=ON; - -# Innodb strict mode will cause an error on the CREATE or ALTER when; -# 1. both ROW_FORMAT=COMPACT and KEY_BLOCK_SIZE=1, -# 2. KEY_BLOCK_SIZE is not a valid number (0,1,2,4,8,16). -# With innodb_strict_mode = OFF, These errors are corrected -# and just a warning is returned. -SET SESSION innodb_strict_mode = ON; - ---echo # Test 1) CREATE with ROW_FORMAT & KEY_BLOCK_SIZE, ALTER with neither -DROP TABLE IF EXISTS bug56632; ---error ER_CANT_CREATE_TABLE -CREATE TABLE bug56632 ( i INT ) ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1; -SHOW WARNINGS; - ---echo # Test 2) CREATE with ROW_FORMAT, ALTER with KEY_BLOCK_SIZE -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ) ROW_FORMAT=COMPACT; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -ALTER TABLE bug56632 KEY_BLOCK_SIZE=1; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; - ---echo # Test 3) CREATE with KEY_BLOCK_SIZE, ALTER with ROW_FORMAT -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=1; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; ---disable_result_log ---error ER_CANT_CREATE_TABLE -ALTER TABLE bug56632 ROW_FORMAT=COMPACT; ---enable_result_log -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; - ---echo # Test 4) CREATE with neither, ALTER with ROW_FORMAT & KEY_BLOCK_SIZE -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ); -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; ---disable_result_log ---error ER_CANT_CREATE_TABLE -ALTER TABLE bug56632 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1; ---enable_result_log -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; - ---echo # Test 5) CREATE with KEY_BLOCK_SIZE=3 (invalid). -DROP TABLE IF EXISTS bug56632; ---error ER_CANT_CREATE_TABLE -CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=3; -SHOW WARNINGS; - -SET SESSION innodb_strict_mode = OFF; - ---echo # Test 6) CREATE with ROW_FORMAT & KEY_BLOCK_SIZE, ALTER with neither -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ) ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -ALTER TABLE bug56632 ADD COLUMN f1 INT; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; - ---echo # Test 7) CREATE with ROW_FORMAT, ALTER with KEY_BLOCK_SIZE -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ) ROW_FORMAT=COMPACT; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -ALTER TABLE bug56632 KEY_BLOCK_SIZE=1; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; - ---echo # Test 8) CREATE with KEY_BLOCK_SIZE, ALTER with ROW_FORMAT -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=1; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -ALTER TABLE bug56632 ROW_FORMAT=COMPACT; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; - ---echo # Test 9) CREATE with neither, ALTER with ROW_FORMAT & KEY_BLOCK_SIZE -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ); -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -ALTER TABLE bug56632 ROW_FORMAT=COMPACT KEY_BLOCK_SIZE=1; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; - ---echo # Test 10) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with neither. -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=3; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -ALTER TABLE bug56632 ADD COLUMN f1 INT; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; - ---echo # Test 11) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with ROW_FORMAT=COMPACT. -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=3; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -ALTER TABLE bug56632 ROW_FORMAT=COMPACT; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; - ---echo # Test 12) CREATE with KEY_BLOCK_SIZE=3 (invalid), ALTER with KEY_BLOCK_SIZE=1. -DROP TABLE IF EXISTS bug56632; -CREATE TABLE bug56632 ( i INT ) KEY_BLOCK_SIZE=3; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; -ALTER TABLE bug56632 KEY_BLOCK_SIZE=1; -SHOW WARNINGS; -SHOW CREATE TABLE bug56632; -SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables WHERE TABLE_NAME = 'bug56632'; - ---echo # Cleanup -DROP TABLE IF EXISTS bug56632; - ---disable_query_log -EVAL SET GLOBAL innodb_file_per_table=$innodb_file_per_table_orig; -EVAL SET GLOBAL innodb_file_format=$innodb_file_format_orig; -EVAL SET GLOBAL innodb_file_format_check=$innodb_file_format_check_orig; -EVAL SET SESSION innodb_strict_mode=$innodb_strict_mode_orig; ---enable_query_log - diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 99d4f294f81..ff2f46256e6 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -6290,6 +6290,33 @@ create_clustered_index_when_no_primary( return(error); } +/*****************************************************************//** +Return a display name for the row format +@return row format name */ + +const char *get_row_format_name( +/*============================*/ +enum row_type row_format) /*!< in: Row Format */ +{ + switch (row_format) { + case ROW_TYPE_COMPACT: + return("COMPACT"); + case ROW_TYPE_COMPRESSED: + return("COMPRESSED"); + case ROW_TYPE_DYNAMIC: + return("DYNAMIC"); + case ROW_TYPE_REDUNDANT: + return("REDUNDANT"); + case ROW_TYPE_DEFAULT: + return("DEFAULT"); + case ROW_TYPE_FIXED: + return("FIXED"); + default: + break; + } + return("NOT USED"); +} + /*****************************************************************//** Validates the create options. We may build on this function in future. For now, it checks two specifiers: @@ -6305,9 +6332,9 @@ create_options_are_valid( columns and indexes */ HA_CREATE_INFO* create_info) /*!< in: create info. */ { - ibool kbs_specified = FALSE; + ibool kbs_specified = FALSE; ibool ret = TRUE; - + enum row_type row_type = form->s->row_type; ut_ad(thd != NULL); @@ -6316,13 +6343,28 @@ create_options_are_valid( return(TRUE); } + /* Check for a valid Innodb ROW_FORMAT specifier. For example, + ROW_TYPE_FIXED can be sent to Innodb */ + switch (row_type) { + case ROW_TYPE_COMPACT: + case ROW_TYPE_COMPRESSED: + case ROW_TYPE_DYNAMIC: + case ROW_TYPE_REDUNDANT: + case ROW_TYPE_DEFAULT: + break; + default: + push_warning( + thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: invalid ROW_FORMAT specifier."); + ret = FALSE; + } + ut_ad(form != NULL); ut_ad(create_info != NULL); - /* First check if KEY_BLOCK_SIZE was specified. */ - if (create_info->key_block_size - || (create_info->used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE)) { - + /* First check if a non-zero KEY_BLOCK_SIZE was specified. */ + if (create_info->key_block_size) { kbs_specified = TRUE; switch (create_info->key_block_size) { case 1: @@ -6333,13 +6375,12 @@ create_options_are_valid( /* Valid value. */ break; default: - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: invalid" - " KEY_BLOCK_SIZE = %lu." - " Valid values are" - " [1, 2, 4, 8, 16]", - create_info->key_block_size); + push_warning_printf( + thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: invalid KEY_BLOCK_SIZE = %lu." + " Valid values are [1, 2, 4, 8, 16]", + create_info->key_block_size); ret = FALSE; } } @@ -6347,109 +6388,67 @@ create_options_are_valid( /* If KEY_BLOCK_SIZE was specified, check for its dependencies. */ if (kbs_specified && !srv_file_per_table) { - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: KEY_BLOCK_SIZE" - " requires innodb_file_per_table."); + push_warning( + thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: KEY_BLOCK_SIZE" + " requires innodb_file_per_table."); ret = FALSE; } if (kbs_specified && srv_file_format < DICT_TF_FORMAT_ZIP) { - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: KEY_BLOCK_SIZE" - " requires innodb_file_format >" - " Antelope."); + push_warning( + thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: KEY_BLOCK_SIZE requires" + " innodb_file_format > Antelope."); ret = FALSE; } - /* Now check for ROW_FORMAT specifier. */ - if (create_info->used_fields & HA_CREATE_USED_ROW_FORMAT) { - switch (form->s->row_type) { - const char* row_format_name; - case ROW_TYPE_COMPRESSED: - case ROW_TYPE_DYNAMIC: - row_format_name - = form->s->row_type == ROW_TYPE_COMPRESSED - ? "COMPRESSED" - : "DYNAMIC"; - - /* These two ROW_FORMATs require srv_file_per_table - and srv_file_format > Antelope */ - if (!srv_file_per_table) { - push_warning_printf( - thd, - MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: ROW_FORMAT=%s" - " requires innodb_file_per_table.", - row_format_name); - ret = FALSE; - } - - if (srv_file_format < DICT_TF_FORMAT_ZIP) { - push_warning_printf( - thd, - MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: ROW_FORMAT=%s" - " requires innodb_file_format >" - " Antelope.", - row_format_name); - ret = FALSE; - } - - /* Cannot specify KEY_BLOCK_SIZE with - ROW_FORMAT = DYNAMIC. - However, we do allow COMPRESSED to be - specified with KEY_BLOCK_SIZE. */ - if (kbs_specified - && form->s->row_type == ROW_TYPE_DYNAMIC) { - push_warning_printf( - thd, - MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: cannot specify" - " ROW_FORMAT = DYNAMIC with" - " KEY_BLOCK_SIZE."); - ret = FALSE; - } - - break; - - case ROW_TYPE_REDUNDANT: - case ROW_TYPE_COMPACT: - case ROW_TYPE_DEFAULT: - /* Default is COMPACT. */ - row_format_name - = form->s->row_type == ROW_TYPE_REDUNDANT - ? "REDUNDANT" - : "COMPACT"; - - /* Cannot specify KEY_BLOCK_SIZE with these - format specifiers. */ - if (kbs_specified) { - push_warning_printf( - thd, - MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: cannot specify" - " ROW_FORMAT = %s with" - " KEY_BLOCK_SIZE.", - row_format_name); - ret = FALSE; - } - - break; - - default: - push_warning(thd, - MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: invalid ROW_FORMAT specifier."); - ret = FALSE; - + switch (row_type) { + case ROW_TYPE_COMPRESSED: + case ROW_TYPE_DYNAMIC: + /* These two ROW_FORMATs require srv_file_per_table + and srv_file_format > Antelope */ + if (!srv_file_per_table) { + push_warning_printf( + thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: ROW_FORMAT=%s" + " requires innodb_file_per_table.", + get_row_format_name(row_type)); + ret = FALSE; } + + if (srv_file_format < DICT_TF_FORMAT_ZIP) { + push_warning_printf( + thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: ROW_FORMAT=%s requires" + " innodb_file_format > Antelope.", + get_row_format_name(row_type)); + ret = FALSE; + } + default: + break; + } + + switch (row_type) { + case ROW_TYPE_REDUNDANT: + case ROW_TYPE_COMPACT: + case ROW_TYPE_DYNAMIC: + /* KEY_BLOCK_SIZE is only allowed with Compressed or Default */ + if (kbs_specified) { + push_warning_printf( + thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: cannot specify ROW_FORMAT = %s" + " with KEY_BLOCK_SIZE.", + get_row_format_name(row_type)); + ret = FALSE; + } + default: + break; } return(ret); @@ -6575,8 +6574,7 @@ ha_innobase::create( goto cleanup; } - if (create_info->key_block_size - || (create_info->used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE)) { + if (create_info->key_block_size) { /* Determine the page_zip.ssize corresponding to the requested page size (key_block_size) in kilobytes. */ @@ -6597,38 +6595,39 @@ ha_innobase::create( } if (!srv_file_per_table) { - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: KEY_BLOCK_SIZE" - " requires innodb_file_per_table."); + push_warning( + thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: KEY_BLOCK_SIZE" + " requires innodb_file_per_table."); flags = 0; } if (file_format < DICT_TF_FORMAT_ZIP) { - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: KEY_BLOCK_SIZE" - " requires innodb_file_format >" - " Antelope."); + push_warning( + thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: KEY_BLOCK_SIZE requires" + " innodb_file_format > Antelope."); flags = 0; } if (!flags) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: ignoring" - " KEY_BLOCK_SIZE=%lu.", - create_info->key_block_size); + push_warning_printf( + thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: ignoring" + " KEY_BLOCK_SIZE=%lu.", + create_info->key_block_size); } } row_type = form->s->row_type; if (flags) { - /* if KEY_BLOCK_SIZE was specified on this statement and - ROW_FORMAT was not, automatically change ROW_FORMAT to COMPRESSED.*/ - if ( (create_info->used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE) - && !(create_info->used_fields & HA_CREATE_USED_ROW_FORMAT)) { + /* if ROW_FORMAT is set to default, + automatically change it to COMPRESSED.*/ + if (row_type == ROW_TYPE_DEFAULT) { row_type = ROW_TYPE_COMPRESSED; } else if (row_type != ROW_TYPE_COMPRESSED) { /* ROW_FORMAT other than COMPRESSED @@ -6638,8 +6637,7 @@ ha_innobase::create( such combinations can be obtained with ALTER TABLE anyway. */ push_warning_printf( - thd, - MYSQL_ERROR::WARN_LEVEL_WARN, + thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, "InnoDB: ignoring KEY_BLOCK_SIZE=%lu" " unless ROW_FORMAT=COMPRESSED.", @@ -6664,33 +6662,24 @@ ha_innobase::create( } switch (row_type) { - const char* row_format_name; case ROW_TYPE_REDUNDANT: break; case ROW_TYPE_COMPRESSED: case ROW_TYPE_DYNAMIC: - row_format_name - = row_type == ROW_TYPE_COMPRESSED - ? "COMPRESSED" - : "DYNAMIC"; - if (!srv_file_per_table) { push_warning_printf( - thd, - MYSQL_ERROR::WARN_LEVEL_WARN, + thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: ROW_FORMAT=%s" - " requires innodb_file_per_table.", - row_format_name); + "InnoDB: ROW_FORMAT=%s requires" + " innodb_file_per_table.", + get_row_format_name(row_type)); } else if (file_format < DICT_TF_FORMAT_ZIP) { push_warning_printf( - thd, - MYSQL_ERROR::WARN_LEVEL_WARN, + thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: ROW_FORMAT=%s" - " requires innodb_file_format >" - " Antelope.", - row_format_name); + "InnoDB: ROW_FORMAT=%s requires" + " innodb_file_format > Antelope.", + get_row_format_name(row_type)); } else { flags |= DICT_TF_COMPACT | (DICT_TF_FORMAT_ZIP @@ -6702,10 +6691,10 @@ ha_innobase::create( case ROW_TYPE_NOT_USED: case ROW_TYPE_FIXED: default: - push_warning(thd, - MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: assuming ROW_FORMAT=COMPACT."); + push_warning( + thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: assuming ROW_FORMAT=COMPACT."); case ROW_TYPE_DEFAULT: case ROW_TYPE_COMPACT: flags = DICT_TF_COMPACT; From c64f9526996a6a7014eb4cb286a3d15c9c026d08 Mon Sep 17 00:00:00 2001 From: Sunny Bains Date: Wed, 3 Nov 2010 12:40:53 +1100 Subject: [PATCH 009/238] Fix Bug #54538 - use of exclusive innodb dictionary lock limits performance. This patch doesn't get rid of the need to acquire the dict_sys->mutex but reduces the need to keep the mutex locked for the duration of the query to fsp_get_available_space_in_free_extents() from ha_innobase::info(). This is a port of revno:3548 from the builtin to the plugin. rb://501 Approved by Jimmy Yang and Marko Makela. --- storage/innodb_plugin/fil/fil0fil.c | 88 ++++++++++++++++------ storage/innodb_plugin/fsp/fsp0fsp.c | 50 ++++++++++++ storage/innodb_plugin/handler/ha_innodb.cc | 19 ++--- storage/innodb_plugin/include/fil0fil.h | 8 ++ storage/innodb_plugin/include/univ.i | 3 + 5 files changed, 134 insertions(+), 34 deletions(-) diff --git a/storage/innodb_plugin/fil/fil0fil.c b/storage/innodb_plugin/fil/fil0fil.c index 796fe921a7e..0f774dcaaa1 100644 --- a/storage/innodb_plugin/fil/fil0fil.c +++ b/storage/innodb_plugin/fil/fil0fil.c @@ -329,14 +329,15 @@ fil_get_space_id_for_table( /*******************************************************************//** Frees a space object from the tablespace memory cache. Closes the files in the chain but does not delete them. There must not be any pending i/o's or -flushes on the files. */ +flushes on the files. +@return TRUE on success */ static ibool fil_space_free( /*===========*/ - /* out: TRUE if success */ - ulint id, /* in: space id */ - ibool own_mutex);/* in: TRUE if own system->mutex */ + ulint id, /* in: space id */ + ibool x_latched); /* in: TRUE if caller has space->latch + in X mode */ /********************************************************************//** Reads data from a space to a buffer. Remember that the possible incomplete blocks at the end of file are ignored: they are not taken into account when @@ -1123,6 +1124,7 @@ try_again: space = fil_space_get_by_name(name); if (UNIV_LIKELY_NULL(space)) { + ibool success; ulint namesake_id; ut_print_timestamp(stderr); @@ -1161,9 +1163,10 @@ try_again: namesake_id = space->id; - mutex_exit(&fil_system->mutex); + success = fil_space_free(namesake_id, FALSE); + ut_a(success); - fil_space_free(namesake_id, FALSE); + mutex_exit(&fil_system->mutex); goto try_again; } @@ -1314,15 +1317,14 @@ fil_space_free( /*===========*/ /* out: TRUE if success */ ulint id, /* in: space id */ - ibool own_mutex) /* in: TRUE if own system->mutex */ + ibool x_latched) /* in: TRUE if caller has space->latch + in X mode */ { fil_space_t* space; fil_space_t* namespace; fil_node_t* fil_node; - if (!own_mutex) { - mutex_enter(&fil_system->mutex); - } + ut_ad(mutex_own(&fil_system->mutex)); space = fil_space_get_by_id(id); @@ -1333,8 +1335,6 @@ fil_space_free( " from the cache but\n" "InnoDB: it is not there.\n", (ulong) id); - mutex_exit(&fil_system->mutex); - return(FALSE); } @@ -1369,8 +1369,8 @@ fil_space_free( ut_a(0 == UT_LIST_GET_LEN(space->chain)); - if (!own_mutex) { - mutex_exit(&fil_system->mutex); + if (x_latched) { + rw_lock_x_unlock(&space->latch); } rw_lock_free(&(space->latch)); @@ -1615,25 +1615,27 @@ fil_close_all_files(void) /*=====================*/ { fil_space_t* space; - fil_node_t* node; mutex_enter(&fil_system->mutex); space = UT_LIST_GET_FIRST(fil_system->space_list); while (space != NULL) { + fil_node_t* node; fil_space_t* prev_space = space; - node = UT_LIST_GET_FIRST(space->chain); + for (node = UT_LIST_GET_FIRST(space->chain); + node != NULL; + node = UT_LIST_GET_NEXT(chain, node)) { - while (node != NULL) { if (node->open) { fil_node_close_file(node, fil_system); } - node = UT_LIST_GET_NEXT(chain, node); } + space = UT_LIST_GET_NEXT(space_list, space); - fil_space_free(prev_space->id, TRUE); + + fil_space_free(prev_space->id, FALSE); } mutex_exit(&fil_system->mutex); @@ -2253,6 +2255,19 @@ try_again: path = mem_strdup(space->name); mutex_exit(&fil_system->mutex); + + /* Important: We rely on the data dictionary mutex to ensure + that a race is not possible here. It should serialize the tablespace + drop/free. We acquire an X latch only to avoid a race condition + when accessing the tablespace instance via: + + fsp_get_available_space_in_free_extents(). + + There our main motivation is to reduce the contention on the + dictionary mutex. */ + + rw_lock_x_lock(&space->latch); + #ifndef UNIV_HOTBACKUP /* Invalidate in the buffer pool all pages belonging to the tablespace. Since we have set space->is_being_deleted = TRUE, readahead @@ -2265,7 +2280,11 @@ try_again: #endif /* printf("Deleting tablespace %s id %lu\n", space->name, id); */ - success = fil_space_free(id, FALSE); + mutex_enter(&fil_system->mutex); + + success = fil_space_free(id, TRUE); + + mutex_exit(&fil_system->mutex); if (success) { success = os_file_delete(path); @@ -2273,6 +2292,8 @@ try_again: if (!success) { success = os_file_delete_if_exists(path); } + } else { + rw_lock_x_unlock(&space->latch); } if (success) { @@ -2300,6 +2321,31 @@ try_again: return(FALSE); } +/*******************************************************************//** +Returns TRUE if a single-table tablespace is being deleted. +@return TRUE if being deleted */ +UNIV_INTERN +ibool +fil_tablespace_is_being_deleted( +/*============================*/ + ulint id) /*!< in: space id */ +{ + fil_space_t* space; + ibool is_being_deleted; + + mutex_enter(&fil_system->mutex); + + space = fil_space_get_by_id(id); + + ut_a(space != NULL); + + is_being_deleted = space->is_being_deleted; + + mutex_exit(&fil_system->mutex); + + return(is_being_deleted); +} + #ifndef UNIV_HOTBACKUP /*******************************************************************//** Discards a single-table tablespace. The tablespace must be cached in the @@ -4763,7 +4809,7 @@ fil_page_get_type( return(mach_read_from_2(page + FIL_PAGE_TYPE)); } -/******************************************************************** +/****************************************************************//** Initializes the tablespace memory cache. */ UNIV_INTERN void diff --git a/storage/innodb_plugin/fsp/fsp0fsp.c b/storage/innodb_plugin/fsp/fsp0fsp.c index 2bae8481d20..f600e96bf88 100644 --- a/storage/innodb_plugin/fsp/fsp0fsp.c +++ b/storage/innodb_plugin/fsp/fsp0fsp.c @@ -3102,13 +3102,63 @@ fsp_get_available_space_in_free_extents( ut_ad(!mutex_own(&kernel_mutex)); + /* The convoluted mutex acquire is to overcome latching order + issues: The problem is that the fil_mutex is at a lower level + than the tablespace latch and the buffer pool mutex. We have to + first prevent any operations on the file system by acquiring the + dictionary mutex. Then acquire the tablespace latch to obey the + latching order and then release the dictionary mutex. That way we + ensure that the tablespace instance can't be freed while we are + examining its contents (see fil_space_free()). + + However, there is one further complication, we release the fil_mutex + when we need to invalidate the the pages in the buffer pool and we + reacquire the fil_mutex when deleting and freeing the tablespace + instance in fil0fil.c. Here we need to account for that situation + too. */ + + mutex_enter(&dict_sys->mutex); + + /* At this stage there is no guarantee that the tablespace even + exists in the cache. */ + + if (fil_tablespace_deleted_or_being_deleted_in_mem(space, -1)) { + + mutex_exit(&dict_sys->mutex); + + return(ULLINT_UNDEFINED); + } + mtr_start(&mtr); latch = fil_space_get_latch(space, &flags); + + /* This should ensure that the tablespace instance can't be freed + by another thread. However, the tablespace pages can still be freed + from the buffer pool. We need to check for that again. */ + zip_size = dict_table_flags_to_zip_size(flags); mtr_x_lock(latch, &mtr); + mutex_exit(&dict_sys->mutex); + + /* At this point it is possible for the tablespace to be deleted and + its pages removed from the buffer pool. We need to check for that + situation. However, the tablespace instance can't be deleted because + our latching above should ensure that. */ + + if (fil_tablespace_is_being_deleted(space)) { + + mtr_commit(&mtr); + + return(ULLINT_UNDEFINED); + } + + /* From here on even if the user has dropped the tablespace, the + pages _must_ still exist in the buffer pool and the tablespace + instance _must_ be in the file system hash table. */ + space_header = fsp_get_space_header(space, zip_size, &mtr); size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr); diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index ff2f46256e6..ef323f7b87c 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -7637,19 +7637,12 @@ ha_innobase::info_low( innodb_crash_recovery is set to a high value. */ stats.delete_length = 0; } else { - /* lock the data dictionary to avoid races with - ibd_file_missing and tablespace_discarded */ - row_mysql_lock_data_dictionary(prebuilt->trx); + ullint avail_space; - /* ib_table->space must be an existent tablespace */ - if (!ib_table->ibd_file_missing - && !ib_table->tablespace_discarded) { - - stats.delete_length = - fsp_get_available_space_in_free_extents( - ib_table->space) * 1024; - } else { + avail_space = fsp_get_available_space_in_free_extents( + ib_table->space); + if (avail_space == ULLINT_UNDEFINED) { THD* thd; thd = ha_thd(); @@ -7666,9 +7659,9 @@ ha_innobase::info_low( ib_table->name); stats.delete_length = 0; + } else { + stats.delete_length = avail_space * 1024; } - - row_mysql_unlock_data_dictionary(prebuilt->trx); } stats.check_time = 0; diff --git a/storage/innodb_plugin/include/fil0fil.h b/storage/innodb_plugin/include/fil0fil.h index c894875b352..f6a19646292 100644 --- a/storage/innodb_plugin/include/fil0fil.h +++ b/storage/innodb_plugin/include/fil0fil.h @@ -716,6 +716,14 @@ fil_page_get_type( /*==============*/ const byte* page); /*!< in: file page */ +/*******************************************************************//** +Returns TRUE if a single-table tablespace is being deleted. +@return TRUE if being deleted */ +UNIV_INTERN +ibool +fil_tablespace_is_being_deleted( +/*============================*/ + ulint id); /*!< in: space id */ typedef struct fil_space_struct fil_space_t; diff --git a/storage/innodb_plugin/include/univ.i b/storage/innodb_plugin/include/univ.i index c1ed56684c9..cab3af5297e 100644 --- a/storage/innodb_plugin/include/univ.i +++ b/storage/innodb_plugin/include/univ.i @@ -360,6 +360,9 @@ typedef unsigned long long int ullint; /* Maximum value for ib_uint64_t */ #define IB_ULONGLONG_MAX ((ib_uint64_t) (~0ULL)) +/* THe 'undefined' value for ullint */ +#define ULLINT_UNDEFINED ((ullint)(-1)) + /* This 'ibool' type is used within Innobase. Remember that different included headers may define 'bool' differently. Do not assume that 'bool' is a ulint! */ #define ibool ulint From eab53d4e8058c05d3ac7f347700c01df93817fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 3 Nov 2010 11:16:11 +0200 Subject: [PATCH 010/238] Non-functional change: Remove bogus const qualifiers and make some function comments more accurate. --- storage/innodb_plugin/btr/btr0cur.c | 4 ++-- storage/innodb_plugin/include/btr0cur.h | 2 +- storage/innodb_plugin/include/row0ins.h | 2 +- storage/innodb_plugin/include/row0upd.h | 4 ++-- storage/innodb_plugin/row/row0ins.c | 6 +++--- storage/innodb_plugin/row/row0upd.c | 8 ++++---- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c index 79fe328a631..cb0a61ee497 100644 --- a/storage/innodb_plugin/btr/btr0cur.c +++ b/storage/innodb_plugin/btr/btr0cur.c @@ -953,7 +953,7 @@ btr_cur_ins_lock_and_undo( not zero, the parameters index and thr should be specified */ btr_cur_t* cursor, /*!< in: cursor on page after which to insert */ - const dtuple_t* entry, /*!< in: entry to insert */ + dtuple_t* entry, /*!< in/out: entry to insert */ que_thr_t* thr, /*!< in: query thread or NULL */ mtr_t* mtr, /*!< in/out: mini-transaction */ ibool* inherit)/*!< out: TRUE if the inserted new record maybe @@ -3794,7 +3794,7 @@ Stores the fields in big_rec_vec to the tablespace and puts pointers to them in rec. The extern flags in rec will have to be set beforehand. The fields are stored on pages allocated from leaf node file segment of the index tree. -@return DB_SUCCESS or error */ +@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ UNIV_INTERN ulint btr_store_big_rec_extern_fields( diff --git a/storage/innodb_plugin/include/btr0cur.h b/storage/innodb_plugin/include/btr0cur.h index 7f6bff11f84..1e1dc0f580a 100644 --- a/storage/innodb_plugin/include/btr0cur.h +++ b/storage/innodb_plugin/include/btr0cur.h @@ -520,7 +520,7 @@ Stores the fields in big_rec_vec to the tablespace and puts pointers to them in rec. The extern flags in rec will have to be set beforehand. The fields are stored on pages allocated from leaf node file segment of the index tree. -@return DB_SUCCESS or error */ +@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ UNIV_INTERN ulint btr_store_big_rec_extern_fields( diff --git a/storage/innodb_plugin/include/row0ins.h b/storage/innodb_plugin/include/row0ins.h index 9f93565ddb7..c780d228a45 100644 --- a/storage/innodb_plugin/include/row0ins.h +++ b/storage/innodb_plugin/include/row0ins.h @@ -84,7 +84,7 @@ ulint row_ins_index_entry( /*================*/ dict_index_t* index, /*!< in: index */ - dtuple_t* entry, /*!< in: index entry to insert */ + dtuple_t* entry, /*!< in/out: index entry to insert */ ulint n_ext, /*!< in: number of externally stored columns */ ibool foreign,/*!< in: TRUE=check foreign key constraints */ que_thr_t* thr); /*!< in: query thread */ diff --git a/storage/innodb_plugin/include/row0upd.h b/storage/innodb_plugin/include/row0upd.h index 4e2de9bd2ec..ea14cd64213 100644 --- a/storage/innodb_plugin/include/row0upd.h +++ b/storage/innodb_plugin/include/row0upd.h @@ -126,8 +126,8 @@ UNIV_INTERN void row_upd_index_entry_sys_field( /*==========================*/ - const dtuple_t* entry, /*!< in: index entry, where the memory buffers - for sys fields are already allocated: + dtuple_t* entry, /*!< in/out: index entry, where the memory + buffers for sys fields are already allocated: the function just copies the new values to them */ dict_index_t* index, /*!< in: clustered index */ diff --git a/storage/innodb_plugin/row/row0ins.c b/storage/innodb_plugin/row/row0ins.c index a193bf21f7c..81b58465e11 100644 --- a/storage/innodb_plugin/row/row0ins.c +++ b/storage/innodb_plugin/row/row0ins.c @@ -1781,7 +1781,7 @@ ulint row_ins_duplicate_error_in_clust( /*=============================*/ btr_cur_t* cursor, /*!< in: B-tree cursor */ - dtuple_t* entry, /*!< in: entry to insert */ + const dtuple_t* entry, /*!< in: entry to insert */ que_thr_t* thr, /*!< in: query thread */ mtr_t* mtr) /*!< in: mtr */ { @@ -1977,7 +1977,7 @@ row_ins_index_entry_low( depending on whether we wish optimistic or pessimistic descent down the index tree */ dict_index_t* index, /*!< in: index */ - dtuple_t* entry, /*!< in: index entry to insert */ + dtuple_t* entry, /*!< in/out: index entry to insert */ ulint n_ext, /*!< in: number of externally stored columns */ que_thr_t* thr) /*!< in: query thread */ { @@ -2158,7 +2158,7 @@ ulint row_ins_index_entry( /*================*/ dict_index_t* index, /*!< in: index */ - dtuple_t* entry, /*!< in: index entry to insert */ + dtuple_t* entry, /*!< in/out: index entry to insert */ ulint n_ext, /*!< in: number of externally stored columns */ ibool foreign,/*!< in: TRUE=check foreign key constraints */ que_thr_t* thr) /*!< in: query thread */ diff --git a/storage/innodb_plugin/row/row0upd.c b/storage/innodb_plugin/row/row0upd.c index 444003ba3f0..0dc550b93f5 100644 --- a/storage/innodb_plugin/row/row0upd.c +++ b/storage/innodb_plugin/row/row0upd.c @@ -371,8 +371,8 @@ UNIV_INTERN void row_upd_index_entry_sys_field( /*==========================*/ - const dtuple_t* entry, /*!< in: index entry, where the memory buffers - for sys fields are already allocated: + dtuple_t* entry, /*!< in/out: index entry, where the memory + buffers for sys fields are already allocated: the function just copies the new values to them */ dict_index_t* index, /*!< in: clustered index */ @@ -1587,12 +1587,12 @@ static ulint row_upd_clust_rec_by_insert( /*========================*/ - upd_node_t* node, /*!< in: row update node */ + upd_node_t* node, /*!< in/out: row update node */ dict_index_t* index, /*!< in: clustered index of the record */ que_thr_t* thr, /*!< in: query thread */ ibool check_ref,/*!< in: TRUE if index may be referenced in a foreign key constraint */ - mtr_t* mtr) /*!< in: mtr; gets committed here */ + mtr_t* mtr) /*!< in/out: mtr; gets committed here */ { mem_heap_t* heap = NULL; btr_pcur_t* pcur; From bfc704035514564e39e0c01ba6f1dbf40086c3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 3 Nov 2010 11:19:12 +0200 Subject: [PATCH 011/238] Bug#57947 InnoDB diagnostics shows btr_block_get calls instead of real callers Improve the diagnostics of buffer pool accesses for B-trees, so that the file names and line numbers of the real calls are shown instead of the line of the buf_page_get() call in btr_block_get(). btr_page_get(): Replaced with a macro. btr_block_get_func(): Renamed from btr_block_get(). Add file, line. btr_block_get(): A macro that passes the __FILE__, __LINE__ to btr_block_get_func(). dict_truncate_index_tree(): Replace a btr_page_get() call with btr_block_get(), since we are only latching the page, not accessing it. --- storage/innodb_plugin/ChangeLog | 6 +++ storage/innodb_plugin/dict/dict0crea.c | 2 +- storage/innodb_plugin/include/btr0btr.h | 49 ++++++++++++++---------- storage/innodb_plugin/include/btr0btr.ic | 38 ++++++------------ 4 files changed, 48 insertions(+), 47 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 3792d48e5f2..57a4b588703 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,9 @@ +2010-11-03 The InnoDB Team + + * include/btr0btr.h, include/btr0btr.ic, dict/dict0crea.c: + Fix Bug#57947 InnoDB diagnostics shows btr_block_get calls + instead of real callers + 2010-11-02 The InnoDB Team * row/row0sel.c: diff --git a/storage/innodb_plugin/dict/dict0crea.c b/storage/innodb_plugin/dict/dict0crea.c index e63f8bc3e6a..7d6cbc8c1c8 100644 --- a/storage/innodb_plugin/dict/dict0crea.c +++ b/storage/innodb_plugin/dict/dict0crea.c @@ -828,7 +828,7 @@ dict_truncate_index_tree( appropriate field in the SYS_INDEXES record: this mini-transaction marks the B-tree totally truncated */ - btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, mtr); + btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr); btr_free_root(space, zip_size, root_page_no, mtr); create: diff --git a/storage/innodb_plugin/include/btr0btr.h b/storage/innodb_plugin/include/btr0btr.h index 5e6a76c7d21..dde3a0bab69 100644 --- a/storage/innodb_plugin/include/btr0btr.h +++ b/storage/innodb_plugin/include/btr0btr.h @@ -94,26 +94,35 @@ btr_root_get( Gets a buffer page and declares its latching order level. */ UNIV_INLINE buf_block_t* -btr_block_get( -/*==========*/ - ulint space, /*!< in: space id */ - ulint zip_size, /*!< in: compressed page size in bytes - or 0 for uncompressed pages */ - ulint page_no, /*!< in: page number */ - ulint mode, /*!< in: latch mode */ - mtr_t* mtr); /*!< in: mtr */ -/**************************************************************//** -Gets a buffer page and declares its latching order level. */ -UNIV_INLINE -page_t* -btr_page_get( -/*=========*/ - ulint space, /*!< in: space id */ - ulint zip_size, /*!< in: compressed page size in bytes - or 0 for uncompressed pages */ - ulint page_no, /*!< in: page number */ - ulint mode, /*!< in: latch mode */ - mtr_t* mtr); /*!< in: mtr */ +btr_block_get_func( +/*===============*/ + ulint space, /*!< in: space id */ + ulint zip_size, /*!< in: compressed page size in bytes + or 0 for uncompressed pages */ + ulint page_no, /*!< in: page number */ + ulint mode, /*!< in: latch mode */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ + mtr_t* mtr) /*!< in/out: mtr */ + __attribute__((nonnull)); +/** Gets a buffer page and declares its latching order level. +@param space tablespace identifier +@param zip_size compressed page size in bytes or 0 for uncompressed pages +@param page_no page number +@param mode latch mode +@param mtr mini-transaction handle +@return the block descriptor */ +# define btr_block_get(space,zip_size,page_no,mode,mtr) \ + btr_block_get_func(space,zip_size,page_no,mode,__FILE__,__LINE__,mtr) +/** Gets a buffer page and declares its latching order level. +@param space tablespace identifier +@param zip_size compressed page size in bytes or 0 for uncompressed pages +@param page_no page number +@param mode latch mode +@param mtr mini-transaction handle +@return the uncompressed page frame */ +# define btr_page_get(space,zip_size,page_no,mode,mtr) \ + buf_block_get_frame(btr_block_get(space,zip_size,page_no,mode,mtr)) #endif /* !UNIV_HOTBACKUP */ /**************************************************************//** Gets the index id field of a page. diff --git a/storage/innodb_plugin/include/btr0btr.ic b/storage/innodb_plugin/include/btr0btr.ic index 97944cc2e26..83eb3627abb 100644 --- a/storage/innodb_plugin/include/btr0btr.ic +++ b/storage/innodb_plugin/include/btr0btr.ic @@ -39,18 +39,21 @@ Created 6/2/1994 Heikki Tuuri Gets a buffer page and declares its latching order level. */ UNIV_INLINE buf_block_t* -btr_block_get( -/*==========*/ - ulint space, /*!< in: space id */ - ulint zip_size, /*!< in: compressed page size in bytes - or 0 for uncompressed pages */ - ulint page_no, /*!< in: page number */ - ulint mode, /*!< in: latch mode */ - mtr_t* mtr) /*!< in: mtr */ +btr_block_get_func( +/*===============*/ + ulint space, /*!< in: space id */ + ulint zip_size, /*!< in: compressed page size in bytes + or 0 for uncompressed pages */ + ulint page_no, /*!< in: page number */ + ulint mode, /*!< in: latch mode */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ + mtr_t* mtr) /*!< in/out: mtr */ { buf_block_t* block; - block = buf_page_get(space, zip_size, page_no, mode, mtr); + block = buf_page_get_gen(space, zip_size, page_no, mode, + NULL, BUF_GET, file, line, mtr); if (mode != RW_NO_LATCH) { @@ -60,23 +63,6 @@ btr_block_get( return(block); } -/**************************************************************//** -Gets a buffer page and declares its latching order level. */ -UNIV_INLINE -page_t* -btr_page_get( -/*=========*/ - ulint space, /*!< in: space id */ - ulint zip_size, /*!< in: compressed page size in bytes - or 0 for uncompressed pages */ - ulint page_no, /*!< in: page number */ - ulint mode, /*!< in: latch mode */ - mtr_t* mtr) /*!< in: mtr */ -{ - return(buf_block_get_frame(btr_block_get(space, zip_size, page_no, - mode, mtr))); -} - /**************************************************************//** Sets the index id field of a page. */ UNIV_INLINE From a491492f15ef8a06d426719cae0c20b370956790 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Wed, 3 Nov 2010 11:30:08 +0200 Subject: [PATCH 012/238] Add ChangeLog entry for Bug#53046 --- storage/innodb_plugin/ChangeLog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 3792d48e5f2..de1530fd92c 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,11 @@ +2010-11-02 The InnoDB Team + + * btr/btr0cur.c, dict/dict0dict.c, dict/dict0load.c, + handler/ha_innodb.cc, include/dict0dict.h, row/row0mysql.c, + innodb_bug53046.result, innodb_bug53046.test: + Fix Bug#53046 dict_update_statistics_low can still be run + concurrently on same table + 2010-11-02 The InnoDB Team * row/row0sel.c: From dfe39f68a97d08f5037b6bdd82bfb63bb0657a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 3 Nov 2010 14:38:36 +0200 Subject: [PATCH 013/238] rw_lock_debug_print(): Output the thread ID in unsigned format. --- storage/innobase/sync/sync0rw.c | 2 +- storage/innodb_plugin/sync/sync0rw.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index 367f019ce55..0b05fb826ac 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -888,7 +888,7 @@ rw_lock_debug_print( rwt = info->lock_type; - fprintf(stderr, "Locked: thread %ld file %s line %ld ", + fprintf(stderr, "Locked: thread %lu file %s line %lu ", (ulong) os_thread_pf(info->thread_id), info->file_name, (ulong) info->line); if (rwt == RW_LOCK_SHARED) { diff --git a/storage/innodb_plugin/sync/sync0rw.c b/storage/innodb_plugin/sync/sync0rw.c index 52eaa5d0f43..365a53dcac1 100644 --- a/storage/innodb_plugin/sync/sync0rw.c +++ b/storage/innodb_plugin/sync/sync0rw.c @@ -988,7 +988,7 @@ rw_lock_debug_print( rwt = info->lock_type; - fprintf(stderr, "Locked: thread %ld file %s line %ld ", + fprintf(stderr, "Locked: thread %lu file %s line %lu ", (ulong) os_thread_pf(info->thread_id), info->file_name, (ulong) info->line); if (rwt == RW_LOCK_SHARED) { From b01a4ceb565a1077ee93682f166e6a0420099486 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 Nov 2010 14:02:15 +0100 Subject: [PATCH 014/238] Raise version number after cloning 5.1.53 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index b7cd3585789..7fd581af009 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ dnl dnl When changing the major version number please also check the switch dnl statement in mysqlbinlog::check_master_version(). You may also need dnl to update version.c in ndb. -AC_INIT([MySQL Server], [5.1.53], [], [mysql]) +AC_INIT([MySQL Server], [5.1.54], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 39bceaac0295e556a8db5d354315b39dfb0f3ef6 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 3 Nov 2010 15:31:42 +0200 Subject: [PATCH 015/238] added windows cmake binaries --- .bzrignore | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.bzrignore b/.bzrignore index e1e2083e2d2..3d27c001e2b 100644 --- a/.bzrignore +++ b/.bzrignore @@ -9,15 +9,19 @@ *.core *.d *.da +*.dll *.exe +*.exp *.gcda *.gcno *.gcov *.idb +*.ilk *.la *.lai *.lib *.lo +*.manifest *.map *.o *.obj @@ -87,6 +91,7 @@ BitKeeper/tmp/* BitKeeper/tmp/bkr3sAHD BitKeeper/tmp/gone CMakeFiles/* +CMakeFiles COPYING COPYING.LIB Docs/#manual.texi# @@ -146,6 +151,7 @@ Makefile Makefile.in Makefile.in' PENDING/* +scripts/scripts TAGS VC++Files/client/mysql_amd64.dsp ac_available_languages_fragment @@ -1968,6 +1974,7 @@ sql-bench/test-transactions sql-bench/test-wisconsin sql/*.cpp sql/*.ds? +sql/*.def sql/*.vcproj sql/.deps/client.Po sql/.deps/derror.Po @@ -2100,6 +2107,7 @@ sql/.libs/udf_example.lai sql/.libs/udf_example.so.0 sql/.libs/udf_example.so.0.0.0 sql/client.c +sql/cmake_dummy.cc sql/Doxyfile sql/f.c sql/gen_lex_hash @@ -3030,6 +3038,7 @@ vio/viotest.cpp win/configure.data win/vs71cache.txt win/vs8cache.txt +win/nmake_cache.txt ylwrap zlib/*.ds? zlib/*.vcproj From 4cfa91f42c4cde9c35979cd2b9837cb60213d876 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 3 Nov 2010 16:03:40 +0200 Subject: [PATCH 016/238] bumped up the version --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 7680a60226a..7c781c35cc2 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ dnl dnl When changing the major version number please also check the switch dnl statement in mysqlbinlog::check_master_version(). You may also need dnl to update version.c in ndb. -AC_INIT([MySQL Server], [5.1.53], [], [mysql]) +AC_INIT([MySQL Server], [5.1.54], [], [mysql]) AC_CONFIG_SRCDIR([sql/mysqld.cc]) AC_CANONICAL_SYSTEM From 1f0f542a4264e2896fc8b2be8190d3e8fa813b80 Mon Sep 17 00:00:00 2001 From: Sunny Bains Date: Thu, 4 Nov 2010 09:41:36 +1100 Subject: [PATCH 017/238] Add change log entry for bug#54538 fix. --- storage/innodb_plugin/ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 57a4b588703..62371d05bd0 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -4,6 +4,13 @@ Fix Bug#57947 InnoDB diagnostics shows btr_block_get calls instead of real callers +2010-11-03 The InnoDB Team + + * fil/fil0fil.c, fsp/fsp0fsp.c, handler/ha_innodb.cc, + include/fil0fil.h, include/univ.i: + Fix Bug #54538 - use of exclusive innodb dictionary lock limits + performance. + 2010-11-02 The InnoDB Team * row/row0sel.c: From 57cb45514dd00b2afd48e9a0b8b36730ac350e72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 4 Nov 2010 15:12:15 +0200 Subject: [PATCH 018/238] row_ins_index_entry(): Note that only CREATE INDEX sets foreign=FALSE. --- storage/innodb_plugin/include/row0ins.h | 3 ++- storage/innodb_plugin/row/row0ins.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/storage/innodb_plugin/include/row0ins.h b/storage/innodb_plugin/include/row0ins.h index c780d228a45..810973e61a7 100644 --- a/storage/innodb_plugin/include/row0ins.h +++ b/storage/innodb_plugin/include/row0ins.h @@ -86,7 +86,8 @@ row_ins_index_entry( dict_index_t* index, /*!< in: index */ dtuple_t* entry, /*!< in/out: index entry to insert */ ulint n_ext, /*!< in: number of externally stored columns */ - ibool foreign,/*!< in: TRUE=check foreign key constraints */ + ibool foreign,/*!< in: TRUE=check foreign key constraints + (foreign=FALSE only during CREATE INDEX) */ que_thr_t* thr); /*!< in: query thread */ /***********************************************************//** Inserts a row to a table. This is a high-level function used in diff --git a/storage/innodb_plugin/row/row0ins.c b/storage/innodb_plugin/row/row0ins.c index 81b58465e11..298c601c7e3 100644 --- a/storage/innodb_plugin/row/row0ins.c +++ b/storage/innodb_plugin/row/row0ins.c @@ -2160,7 +2160,8 @@ row_ins_index_entry( dict_index_t* index, /*!< in: index */ dtuple_t* entry, /*!< in/out: index entry to insert */ ulint n_ext, /*!< in: number of externally stored columns */ - ibool foreign,/*!< in: TRUE=check foreign key constraints */ + ibool foreign,/*!< in: TRUE=check foreign key constraints + (foreign=FALSE only during CREATE INDEX) */ que_thr_t* thr) /*!< in: query thread */ { ulint err; From f6ae96d40dc3e24c7ea0d88fa8cbfc3554449d04 Mon Sep 17 00:00:00 2001 From: Guilhem Bichot Date: Fri, 5 Nov 2010 14:17:47 +0100 Subject: [PATCH 019/238] BUG#57933 "add -Wdeclaration-after-statement to gcc builds"; first part, for autotools build. config/ac-macros/maintainer.m4: Add the flag. With it, and as we use -Werror, we nicely get "error: ISO C90 forbids mixed declarations and code" if a declaration follows a statement in C code. Note that g++ refuses this flag. --- config/ac-macros/maintainer.m4 | 1 + 1 file changed, 1 insertion(+) diff --git a/config/ac-macros/maintainer.m4 b/config/ac-macros/maintainer.m4 index 5960853d7f1..b4d2f08e558 100644 --- a/config/ac-macros/maintainer.m4 +++ b/config/ac-macros/maintainer.m4 @@ -19,6 +19,7 @@ AC_DEFUN([MY_MAINTAINER_MODE_WARNINGS], [ AS_IF([test "$GCC" = "yes"], [ C_WARNINGS="-Wall -Wextra -Wunused -Wwrite-strings -Wno-strict-aliasing -Werror" CXX_WARNINGS="${C_WARNINGS} -Wno-unused-parameter" + C_WARNINGS="${C_WARNINGS} -Wdeclaration-after-statement" ]) # Test whether the warning options work. From 866cec611a369be344bafed0d4691ad6b83e4086 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Fri, 5 Nov 2010 15:26:38 +0100 Subject: [PATCH 020/238] Bug #57840 MTR: parallel execution breaks with smart ordering of test cases There were actually more problems in this area: Slaves (if any) were unconditionally restarted, this appears unnecessary. Sort criteria were suboptimal, included the test name. Added logic to "reserve" a sequence of tests with same config for one thread Got rid of sort_criteria hash, put it into the test case itself Adds little sanity check that expected worker picks up test Fixed some tests that may fail if starting on running server Some of these fail only if *same* test is repeated. Finally, special sorting of tests that do --force-restart --- mysql-test/lib/mtr_cases.pm | 21 ++++--- mysql-test/mysql-test-run.pl | 58 ++++++++++++------- .../suite/binlog/t/binlog_index-master.opt | 1 + .../binlog/t/binlog_stm_binlog-master.opt | 1 + .../binlog/t/binlog_stm_do_db-master.opt | 1 + .../suite/rpl/r/rpl_ignore_table.result | 1 + .../suite/rpl/t/rpl_cross_version-master.opt | 1 + .../suite/rpl/t/rpl_current_user-master.opt | 1 + mysql-test/suite/rpl/t/rpl_ignore_table.test | 2 + .../rpl/t/rpl_loaddata_symlink-master.sh | 1 + .../suite/rpl/t/rpl_loaddata_symlink-slave.sh | 1 + ...rpl_slave_load_tmpdir_not_exist-master.opt | 1 + mysql-test/t/key_cache-master.opt | 1 + mysql-test/t/mysqlbinlog-master.opt | 1 + 14 files changed, 62 insertions(+), 30 deletions(-) create mode 100644 mysql-test/suite/binlog/t/binlog_index-master.opt create mode 100644 mysql-test/suite/rpl/t/rpl_current_user-master.opt create mode 100644 mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist-master.opt diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index 7d25a72212a..7961fa6fa7d 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -170,8 +170,6 @@ sub collect_test_cases ($$$) { if ( $opt_reorder && !$quick_collect) { # Reorder the test cases in an order that will make them faster to run - my %sort_criteria; - # Make a mapping of test name to a string that represents how that test # should be sorted among the other tests. Put the most important criterion # first, then a sub-criterion, then sub-sub-criterion, etc. @@ -183,24 +181,31 @@ sub collect_test_cases ($$$) { # Append the criteria for sorting, in order of importance. # push(@criteria, "ndb=" . ($tinfo->{'ndb_test'} ? "A" : "B")); + push(@criteria, $tinfo->{template_path}); # Group test with equal options together. # Ending with "~" makes empty sort later than filled my $opts= $tinfo->{'master_opt'} ? $tinfo->{'master_opt'} : []; push(@criteria, join("!", sort @{$opts}) . "~"); + # Add slave opts if any + if ($tinfo->{'slave_opt'}) + { + push(@criteria, join("!", sort @{$tinfo->{'slave_opt'}})); + } + # This sorts tests with force-restart *before* identical tests + push(@criteria, $tinfo->{force_restart} ? "force-restart" : "no-restart"); - $sort_criteria{$tinfo->{name}} = join(" ", @criteria); + $tinfo->{criteria}= join(" ", @criteria); } - @$cases = sort { - $sort_criteria{$a->{'name'}} . $a->{'name'} cmp - $sort_criteria{$b->{'name'}} . $b->{'name'}; } @$cases; + @$cases = sort {$a->{criteria} cmp $b->{criteria}; } @$cases; # For debugging the sort-order # foreach my $tinfo (@$cases) # { - # print("$sort_criteria{$tinfo->{'name'}} -> \t$tinfo->{'name'}\n"); + # my $tname= $tinfo->{name} . ' ' . $tinfo->{combination}; + # my $crit= $tinfo->{criteria}; + # print("$tname\n\t$crit\n"); # } - } if (defined $print_testcases){ diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 651dabcd408..b4cd53cff09 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -662,22 +662,40 @@ sub run_test_server ($$$) { next; } - # Prefer same configuration, or just use next if --noreorder - if (!$opt_reorder or (defined $result and - $result->{template_path} eq $t->{template_path})) - { - #mtr_report("Test uses same config => good match"); - # Test uses same config => good match - $next= splice(@$tests, $i, 1); - last; - } - # Second best choice is the first that does not fulfill # any of the above conditions if (!defined $second_best){ #mtr_report("Setting second_best to $i"); $second_best= $i; } + + # Smart allocation of next test within this thread. + + if ($opt_reorder and $opt_parallel > 1 and defined $result) + { + my $wid= $result->{worker}; + # Reserved for other thread, try next + next if (defined $t->{reserved} and $t->{reserved} != $wid); + if (! defined $t->{reserved}) + { + # Force-restart not relevant when comparing *next* test + $t->{criteria} =~ s/force-restart$/no-restart/; + my $criteria= $t->{criteria}; + # Reserve similar tests for this worker, but not too many + my $maxres= (@$tests - $i) / $opt_parallel + 1; + for (my $j= $i+1; $j <= $i + $maxres; $j++) + { + my $tt= $tests->[$j]; + last unless defined $tt; + last if $tt->{criteria} ne $criteria; + $tt->{reserved}= $wid; + } + } + } + + # At this point we have found next suitable test + $next= splice(@$tests, $i, 1); + last; } # Use second best choice if no other test has been found @@ -686,10 +704,12 @@ sub run_test_server ($$$) { mtr_error("Internal error, second best too large($second_best)") if $second_best > $#$tests; $next= splice(@$tests, $second_best, 1); + delete $next->{reserved}; } if ($next) { - #$next->print_test(); + # We don't need this any more + delete $next->{criteria}; $next->write_test($sock, 'TESTCASE'); $running{$next->key()}= $next; $num_ndb_tests++ if ($next->{ndb_test}); @@ -772,6 +792,11 @@ sub run_worker ($) { delete($test->{'comment'}); delete($test->{'logfile'}); + # A sanity check. Should this happen often we need to look at it. + if (defined $test->{reserved} && $test->{reserved} != $thread_num) { + my $tres= $test->{reserved}; + mtr_warning("Test reserved for w$tres picked up by w$thread_num"); + } $test->{worker} = $thread_num if $opt_parallel > 1; run_testcase($test); @@ -4575,17 +4600,6 @@ sub server_need_restart { } } - # Temporary re-enable the "always restart slave" hack - # this should be removed asap, but will require that each rpl - # testcase cleanup better after itself - ie. stop and reset - # replication - # Use the "#!use-slave-opt" marker to detect that this is a "slave" - # server - if ( $server->option("#!use-slave-opt") ){ - mtr_verbose_restart($server, "Always restart slave(s)"); - return 1; - } - my $is_mysqld= grep ($server eq $_, mysqlds()); if ($is_mysqld) { diff --git a/mysql-test/suite/binlog/t/binlog_index-master.opt b/mysql-test/suite/binlog/t/binlog_index-master.opt new file mode 100644 index 00000000000..cef79bc8585 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_index-master.opt @@ -0,0 +1 @@ +--force-restart diff --git a/mysql-test/suite/binlog/t/binlog_stm_binlog-master.opt b/mysql-test/suite/binlog/t/binlog_stm_binlog-master.opt index ad2c6a647b5..377e2114039 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_binlog-master.opt +++ b/mysql-test/suite/binlog/t/binlog_stm_binlog-master.opt @@ -1 +1,2 @@ -O max_binlog_size=4096 +--force-restart diff --git a/mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt b/mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt index e2cfcb299cf..2a1187d3fe4 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt +++ b/mysql-test/suite/binlog/t/binlog_stm_do_db-master.opt @@ -1 +1,2 @@ --binlog-do-db=b42829 +--force-restart diff --git a/mysql-test/suite/rpl/r/rpl_ignore_table.result b/mysql-test/suite/rpl/r/rpl_ignore_table.result index e77be425270..6b845ddcac9 100644 --- a/mysql-test/suite/rpl/r/rpl_ignore_table.result +++ b/mysql-test/suite/rpl/r/rpl_ignore_table.result @@ -141,3 +141,4 @@ HEX(word) SELECT * FROM tmptbl504451f4258$1; ERROR 42S02: Table 'test.tmptbl504451f4258$1' doesn't exist DROP TABLE t5; +call mtr.force_restart(); diff --git a/mysql-test/suite/rpl/t/rpl_cross_version-master.opt b/mysql-test/suite/rpl/t/rpl_cross_version-master.opt index 0ea05290c11..2b2d357b124 100644 --- a/mysql-test/suite/rpl/t/rpl_cross_version-master.opt +++ b/mysql-test/suite/rpl/t/rpl_cross_version-master.opt @@ -1 +1,2 @@ --replicate-same-server-id --relay-log=slave-relay-bin --secure-file-priv=$MYSQL_TMP_DIR +--force-restart diff --git a/mysql-test/suite/rpl/t/rpl_current_user-master.opt b/mysql-test/suite/rpl/t/rpl_current_user-master.opt new file mode 100644 index 00000000000..cef79bc8585 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_current_user-master.opt @@ -0,0 +1 @@ +--force-restart diff --git a/mysql-test/suite/rpl/t/rpl_ignore_table.test b/mysql-test/suite/rpl/t/rpl_ignore_table.test index 66f96e8f4e8..b5666ad6e91 100644 --- a/mysql-test/suite/rpl/t/rpl_ignore_table.test +++ b/mysql-test/suite/rpl/t/rpl_ignore_table.test @@ -174,3 +174,5 @@ SELECT * FROM tmptbl504451f4258$1; connection master; DROP TABLE t5; sync_slave_with_master; + +call mtr.force_restart(); diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.sh b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.sh index 066f72926af..e5bb3e61d11 100644 --- a/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.sh +++ b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-master.sh @@ -1 +1,2 @@ +rm -f $MYSQLTEST_VARDIR/std_data_master_link ln -s $MYSQLTEST_VARDIR/std_data $MYSQLTEST_VARDIR/std_data_master_link diff --git a/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.sh b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.sh index 218209a2542..7a0c0bb382a 100644 --- a/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.sh +++ b/mysql-test/suite/rpl/t/rpl_loaddata_symlink-slave.sh @@ -1 +1,2 @@ +rm -f $MYSQLTEST_VARDIR/std_data_slave_link ln -s $MYSQLTEST_VARDIR/std_data $MYSQLTEST_VARDIR/std_data_slave_link diff --git a/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist-master.opt b/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist-master.opt new file mode 100644 index 00000000000..cef79bc8585 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist-master.opt @@ -0,0 +1 @@ +--force-restart diff --git a/mysql-test/t/key_cache-master.opt b/mysql-test/t/key_cache-master.opt index 66e19c18a8a..6398e3e0a26 100644 --- a/mysql-test/t/key_cache-master.opt +++ b/mysql-test/t/key_cache-master.opt @@ -1 +1,2 @@ --key_buffer_size=2M --small.key_buffer_size=256K --small.key_buffer_size=128K +--force-restart diff --git a/mysql-test/t/mysqlbinlog-master.opt b/mysql-test/t/mysqlbinlog-master.opt index ac1a87c73b3..a9f4a6010d8 100644 --- a/mysql-test/t/mysqlbinlog-master.opt +++ b/mysql-test/t/mysqlbinlog-master.opt @@ -1 +1,2 @@ --max-binlog-size=4096 +--force-restart From 8f237f5874a814daaa7431748849997d1a2aa8ea Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Sun, 7 Nov 2010 23:42:54 +0600 Subject: [PATCH 021/238] A fix and a test case for Bug#47924 -main.log_tables times out sporadically. The cause of the sporadic time out was a leaking protection against the global read lock, taken by the RENAME statement, and not released in case of an error occurred during RENAME. The leaking protection counter would lead to the value of protect_against_global_read never dropping to 0. Consequently FLUSH TABLES in all connections, including the one that leaked the protection, could not proceed. The fix is to ensure that all branchesin RENAME code properly release GRL protection. mysql-test/r/log_tables.result: Added results for test for bug#47924. mysql-test/t/log_tables.test: Added test for bug#47924. sql/sql_rename.cc: mysql_rename_tables() modified: replaced return from function to goto to clean up code block in case of error. --- mysql-test/r/log_tables.result | 10 ++++++++++ mysql-test/t/log_tables.test | 19 +++++++++++++++++++ sql/sql_rename.cc | 6 +++--- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result index f8321520880..fcde09db7c5 100644 --- a/mysql-test/r/log_tables.result +++ b/mysql-test/r/log_tables.result @@ -899,6 +899,16 @@ TIMESTAMP 1 1 SELECT SQL_NO_CACHE 'Bug#31700 - KEY', f1,f2,f3,SLEEP(1.1) FROM t1 TIMESTAMP 1 1 SELECT SQL_NO_CACHE 'Bug#31700 - PK', f1,f2,f3,SLEEP(1.1) FROM t1 WHERE f1=2 DROP TABLE t1; TRUNCATE TABLE mysql.slow_log; +use mysql; +drop table if exists renamed_general_log; +drop table if exists renamed_slow_log; +RENAME TABLE general_log TO renamed_general_log; +ERROR HY000: Cannot rename 'general_log'. When logging enabled, rename to/from log table must rename two tables: the log table to an archive table and another table back to 'general_log' +RENAME TABLE slow_log TO renamed_slow_log; +ERROR HY000: Cannot rename 'slow_log'. When logging enabled, rename to/from log table must rename two tables: the log table to an archive table and another table back to 'slow_log' +use test; +flush tables with read lock; +unlock tables; SET @@session.long_query_time= @old_long_query_time; SET @@global.log_output= @old_log_output; SET @@global.slow_query_log= @old_slow_query_log; diff --git a/mysql-test/t/log_tables.test b/mysql-test/t/log_tables.test index 076f2e8bc3b..af6c34dec37 100644 --- a/mysql-test/t/log_tables.test +++ b/mysql-test/t/log_tables.test @@ -1027,6 +1027,25 @@ DROP TABLE t1; TRUNCATE TABLE mysql.slow_log; +# +# Bug #47924 main.log_tables times out sporadically +# + +use mysql; +# Should result in error +--disable_warnings +drop table if exists renamed_general_log; +drop table if exists renamed_slow_log; +--enable_warnings +--error ER_CANT_RENAME_LOG_TABLE +RENAME TABLE general_log TO renamed_general_log; +--error ER_CANT_RENAME_LOG_TABLE +RENAME TABLE slow_log TO renamed_slow_log; + +use test; +flush tables with read lock; +unlock tables; + SET @@session.long_query_time= @old_long_query_time; SET @@global.log_output= @old_log_output; diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index e85e730db5b..df7054c94d0 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -99,7 +99,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) */ my_error(ER_CANT_RENAME_LOG_TABLE, MYF(0), ren_table->table_name, ren_table->table_name); - DBUG_RETURN(1); + goto err; } } else @@ -112,7 +112,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) */ my_error(ER_CANT_RENAME_LOG_TABLE, MYF(0), ren_table->table_name, ren_table->table_name); - DBUG_RETURN(1); + goto err; } else { @@ -130,7 +130,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) else my_error(ER_CANT_RENAME_LOG_TABLE, MYF(0), rename_log_table[1], rename_log_table[1]); - DBUG_RETURN(1); + goto err; } } From d7202ef7f8785d47788072d71f59270a862299b6 Mon Sep 17 00:00:00 2001 From: Anitha Gopi Date: Mon, 8 Nov 2010 14:57:05 +0530 Subject: [PATCH 022/238] Bug#58041 : Moved rpl_binlog_row to daily. Run just main suite for ps_row and embedded per push. Other suites run daily --- mysql-test/collections/mysql-5.1-bugteam.daily | 5 +++++ mysql-test/collections/mysql-5.1-bugteam.push | 4 ++++ 2 files changed, 9 insertions(+) create mode 100644 mysql-test/collections/mysql-5.1-bugteam.daily create mode 100644 mysql-test/collections/mysql-5.1-bugteam.push diff --git a/mysql-test/collections/mysql-5.1-bugteam.daily b/mysql-test/collections/mysql-5.1-bugteam.daily new file mode 100644 index 00000000000..0503bd49f73 --- /dev/null +++ b/mysql-test/collections/mysql-5.1-bugteam.daily @@ -0,0 +1,5 @@ +perl mysql-test-run.pl --timer --force --parallel=auto --comment=n_mix --vardir=var-n_mix --mysqld=--binlog-format=mixed --experimental=collections/default.experimental +perl mysql-test-run.pl --timer --force --parallel=auto --comment=ps_row --vardir=var-ps_row --ps-protocol --mysqld=--binlog-format=row --experimental=collections/default.experimental +perl mysql-test-run.pl --timer --force --parallel=auto --comment=embedded --vardir=var-emebbed --embedded --experimental=collections/default.experimental +perl mysql-test-run.pl --timer --force --parallel=auto --comment=rpl_binlog_row --vardir=var-rpl_binlog_row --suite=rpl,binlog --mysqld=--binlog-format=row --experimental=collections/default.experimental +perl mysql-test-run.pl --timer --force --parallel=auto --comment=funcs_1 --vardir=var-funcs_1 --suite=funcs_1 --experimental=collections/default.experimental diff --git a/mysql-test/collections/mysql-5.1-bugteam.push b/mysql-test/collections/mysql-5.1-bugteam.push new file mode 100644 index 00000000000..d01b98eb87f --- /dev/null +++ b/mysql-test/collections/mysql-5.1-bugteam.push @@ -0,0 +1,4 @@ +perl mysql-test-run.pl --timer --force --parallel=auto --comment=n_mix --vardir=var-n_mix --mysqld=--binlog-format=mixed --experimental=collections/default.experimental --skip-ndb +perl mysql-test-run.pl --timer --force --parallel=auto --comment=ps_row --vardir=var-ps_row --suite=main --ps-protocol --mysqld=--binlog-format=row --experimental=collections/default.experimental --skip-ndb +perl mysql-test-run.pl --timer --force --parallel=auto --comment=embedded --vardir=var-emebbed --suite=main --embedded --experimental=collections/default.experimental --skip-ndb +perl mysql-test-run.pl --timer --force --parallel=auto --comment=funcs_1 --vardir=var-funcs_1 --suite=funcs_1 --experimental=collections/default.experimental --skip-ndb From 0a29baba4bae36b947aba9001956f3c800f4205f Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Mon, 8 Nov 2010 13:34:27 +0300 Subject: [PATCH 023/238] Fix for bug #54575: crash when joining tables with unique set column(backport from 5.1) Problem: a flaw (derefencing a NULL pointer) in the LIKE optimization code may lead to a server crash in some rare cases. Fix: check the pointer before its dereferencing. mysql-test/r/func_like.result: Fix for bug #54575: crash when joining tables with unique set column - test result. mysql-test/t/func_like.test: Fix for bug #54575: crash when joining tables with unique set column - test case. sql/item_cmpfunc.cc: Fix for bug #54575: crash when joining tables with unique set column - check res2 buffer pointer before its dereferencing as it may be NULL in some cases. --- mysql-test/r/func_like.result | 14 ++++++++++++++ mysql-test/t/func_like.test | 18 ++++++++++++++++-- sql/item_cmpfunc.cc | 7 ++++--- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/func_like.result b/mysql-test/r/func_like.result index 7e6fedb9403..f8743d6305f 100644 --- a/mysql-test/r/func_like.result +++ b/mysql-test/r/func_like.result @@ -165,3 +165,17 @@ select 'andre%' like 'andre select _cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê'; _cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê' 1 +End of 4.1 tests +# +# Bug #54575: crash when joining tables with unique set column +# +CREATE TABLE t1(a SET('a') NOT NULL, UNIQUE KEY(a)); +CREATE TABLE t2(b INT PRIMARY KEY); +INSERT INTO t1 VALUES (); +Warnings: +Warning 1364 Field 'a' doesn't have a default value +INSERT INTO t2 VALUES (1), (2), (3); +SELECT 1 FROM t2 JOIN t1 ON 1 LIKE a GROUP BY a; +1 +DROP TABLE t1, t2; +End of 5.1 tests diff --git a/mysql-test/t/func_like.test b/mysql-test/t/func_like.test index 4e1183afeff..50ebb2b2782 100644 --- a/mysql-test/t/func_like.test +++ b/mysql-test/t/func_like.test @@ -112,5 +112,19 @@ select 'andre%' like 'andre # select _cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê'; -# -# End of 4.1 tests + +--echo End of 4.1 tests + + +--echo # +--echo # Bug #54575: crash when joining tables with unique set column +--echo # +CREATE TABLE t1(a SET('a') NOT NULL, UNIQUE KEY(a)); +CREATE TABLE t2(b INT PRIMARY KEY); +INSERT INTO t1 VALUES (); +INSERT INTO t2 VALUES (1), (2), (3); +SELECT 1 FROM t2 JOIN t1 ON 1 LIKE a GROUP BY a; +DROP TABLE t1, t2; + + +--echo End of 5.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 5c2fb9857d5..4ae381af683 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4220,13 +4220,14 @@ Item_func::optimize_type Item_func_like::select_optimize() const if (args[1]->const_item()) { String* res2= args[1]->val_str((String *)&tmp_value2); + const char *ptr2; - if (!res2) + if (!res2 || !(ptr2= res2->ptr())) return OPTIMIZE_NONE; - if (*res2->ptr() != wild_many) + if (*ptr2 != wild_many) { - if (args[0]->result_type() != STRING_RESULT || *res2->ptr() != wild_one) + if (args[0]->result_type() != STRING_RESULT || *ptr2 != wild_one) return OPTIMIZE_OP; } } From 50a3c55ee7e378b36bca5940e382fb18674dbd9b Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Mon, 8 Nov 2010 13:51:39 +0300 Subject: [PATCH 024/238] Bug#52711 Segfault when doing EXPLAIN SELECT with union...order by (select... where...) backport from 5.1 mysql-test/r/subselect.result: backport from 5.1 mysql-test/t/subselect.test: backport from 5.1 sql/sql_select.cc: backport from 5.1 --- mysql-test/r/subselect.result | 16 ++++++++++++++++ mysql-test/t/subselect.test | 21 +++++++++++++++++++++ sql/sql_select.cc | 5 +++-- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 09a650c722b..7fbe4c08b08 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -4527,4 +4527,20 @@ pk int_key 3 3 7 3 DROP TABLE t1,t2; +# +# Bug #52711: Segfault when doing EXPLAIN SELECT with +# union...order by (select... where...) +# +CREATE TABLE t1 (a VARCHAR(10), FULLTEXT KEY a (a)); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (1),(2); +# Should not crash +EXPLAIN +SELECT * FROM t2 UNION SELECT * FROM t2 +ORDER BY (SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE)); +# Should not crash +SELECT * FROM t2 UNION SELECT * FROM t2 +ORDER BY (SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE)); +DROP TABLE t1,t2; End of 5.0 tests. diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index bd12742f0f1..0956f91619d 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -3506,5 +3506,26 @@ ORDER BY outr.pk; DROP TABLE t1,t2; +--echo # +--echo # Bug #52711: Segfault when doing EXPLAIN SELECT with +--echo # union...order by (select... where...) +--echo # + +CREATE TABLE t1 (a VARCHAR(10), FULLTEXT KEY a (a)); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (b INT); +INSERT INTO t2 VALUES (1),(2); + +--echo # Should not crash +--disable_result_log +EXPLAIN +SELECT * FROM t2 UNION SELECT * FROM t2 + ORDER BY (SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE)); + +--echo # Should not crash +SELECT * FROM t2 UNION SELECT * FROM t2 + ORDER BY (SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE)); +DROP TABLE t1,t2; +--enable_result_log --echo End of 5.0 tests. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 53a6b699022..929ef3c8949 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -501,7 +501,7 @@ JOIN::prepare(Item ***rref_pointer_array, thd->lex->allow_sum_func= save_allow_sum_func; } - if (!thd->lex->view_prepare_mode) + if (!thd->lex->view_prepare_mode && !(select_options & SELECT_DESCRIBE)) { Item_subselect *subselect; /* Is it subselect? */ @@ -6861,7 +6861,8 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, *simple_order=0; // Must do a temp table to sort else if (!(order_tables & not_const_tables)) { - if (order->item[0]->with_subselect) + if (order->item[0]->with_subselect && + !(join->select_lex->options & SELECT_DESCRIBE)) order->item[0]->val_str(&order->item[0]->str_value); DBUG_PRINT("info",("removing: %s", order->item[0]->full_name())); continue; // skip const item From 7b047a31a09a7999353232cb6407b4e6338d5b70 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Mon, 8 Nov 2010 13:43:54 +0200 Subject: [PATCH 025/238] Make SQLString reallocation addaptive Avoid doing reallocs Prealloc some strings / provide extension allocation size to some strings This gave a 25 % speedup in some mysql-test-run tests. mysys/safemalloc.c: More DBUG_PRINT sql/net_serv.cc: Make all mallocs() look the similar. (just-for-safety fix) sql/protocol.cc: Ensure that communication packet buffer is allocated. (It's freed by stored precedures and some DLL statements) sql/sp.cc: Fixed valgrind warning sql/sql_select.cc: Set extent allocation for buffer that has a lot of append() calls. sql/sql_show.cc: Fixed wrong usage of string buffer. Old code worked in test suite 'just-by-chance' sql/sql_string.cc: Call realloc_with_extra_if_needed() in append() functions. sql/sql_string.h: Added 'extra_alloc' member, to specify chunck size for realloc(). extra_alloc is addaptive to catch cases where preallocation of buffers is not done properly. Simplified free() to allow compiler to optimize things better (and to keep things consistent). Fixed shrink() to take into account the extra memory added to the Alloced_length in realloc(). This saves us a realloc() per query. sql/sql_test.cc: Set extent allocation for buffer that has a lot of append() calls. sql/table.cc: Set extent allocation for buffer that has a lot of append() calls. --- mysys/safemalloc.c | 4 ++++ sql/net_serv.cc | 4 ++-- sql/protocol.cc | 3 +++ sql/sp.cc | 2 +- sql/sql_select.cc | 1 + sql/sql_show.cc | 2 +- sql/sql_string.cc | 18 ++++++++--------- sql/sql_string.h | 48 +++++++++++++++++++++++++++++----------------- sql/sql_test.cc | 3 ++- sql/table.cc | 4 +++- 10 files changed, 56 insertions(+), 33 deletions(-) diff --git a/mysys/safemalloc.c b/mysys/safemalloc.c index 0d0ae2dabe5..0e489263c69 100644 --- a/mysys/safemalloc.c +++ b/mysys/safemalloc.c @@ -224,6 +224,8 @@ void *_myrealloc(register void *ptr, register size_t size, struct st_irem *irem; char *data; DBUG_ENTER("_myrealloc"); + DBUG_PRINT("my",("ptr: 0x%lx size: %lu my_flags: %d", (long) ptr, + (ulong) size, MyFlags)); if (!ptr && (MyFlags & MY_ALLOW_ZERO_PTR)) DBUG_RETURN(_mymalloc(size, filename, lineno, MyFlags)); @@ -245,6 +247,8 @@ void *_myrealloc(register void *ptr, register size_t size, (void) fflush(stderr); DBUG_RETURN((uchar*) NULL); } + DBUG_PRINT("my", ("old_size: %lu -> new_size: %lu", + (ulong) irem->datasize, (ulong) size)); if ((data= _mymalloc(size,filename,lineno,MyFlags))) /* Allocate new area */ { diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 4796a5601bf..6a4079b1fef 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -116,7 +116,7 @@ my_bool my_net_init(NET *net, Vio* vio) net->vio = vio; my_net_local_init(net); /* Set some limits */ if (!(net->buff=(uchar*) my_malloc((size_t) net->max_packet+ - NET_HEADER_SIZE + COMP_HEADER_SIZE, + NET_HEADER_SIZE + COMP_HEADER_SIZE +1, MYF(MY_WME)))) DBUG_RETURN(1); net->buff_end=net->buff+net->max_packet; @@ -580,7 +580,7 @@ net_real_write(NET *net,const uchar *packet, size_t len) uchar *b; uint header_length=NET_HEADER_SIZE+COMP_HEADER_SIZE; if (!(b= (uchar*) my_malloc(len + NET_HEADER_SIZE + - COMP_HEADER_SIZE, MYF(MY_WME)))) + COMP_HEADER_SIZE + 1, MYF(MY_WME)))) { net->error= 2; net->last_errno= ER_OUT_OF_RESOURCES; diff --git a/sql/protocol.cc b/sql/protocol.cc index 8a9d712077d..70b171fa652 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -632,6 +632,9 @@ bool Protocol::send_fields(List *list, uint flags) uint count= 0; #endif + /* We have to reallocate it here as a stored procedure may have reset it */ + (void) local_packet->alloc(thd->variables.net_buffer_length); + while ((item=it++)) { char *pos; diff --git a/sql/sp.cc b/sql/sp.cc index ebf2b3c360d..68e2f19fd47 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -785,7 +785,7 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, { Parser_state parser_state; - if (parser_state.init(thd, defstr.c_ptr(), defstr.length())) + if (parser_state.init(thd, defstr.c_ptr_safe(), defstr.length())) { ret= SP_INTERNAL_ERROR; goto end; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e185996126d..e6be979becb 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15997,6 +15997,7 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, char buff[256]; String str(buff,sizeof(buff),&my_charset_bin); str.length(0); + str.extra_allocation(1024); item->print(&str, QT_ORDINARY); item_field->name= sql_strmake(str.ptr(),str.length()); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 8f1f938d36e..265c86f55e7 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4329,7 +4329,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, base_type [(dimension)] [unsigned] [zerofill]. For DATA_TYPE column we extract only base type. */ - tmp_buff= strchr(type.ptr(), '('); + tmp_buff= strchr(type.c_ptr_safe(), '('); if (!tmp_buff) /* if there is no dimention part then check the presence of diff --git a/sql/sql_string.cc b/sql/sql_string.cc index eafd8502706..b359b2a7168 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -411,7 +411,7 @@ bool String::append(const String &s) { if (s.length()) { - if (realloc(str_length+s.length())) + if (realloc_with_extra_if_needed(str_length+s.length())) return TRUE; memcpy(Ptr+str_length,s.ptr(),s.length()); str_length+=s.length(); @@ -436,7 +436,7 @@ bool String::append(const char *s,uint32 arg_length) { uint32 add_length=arg_length * str_charset->mbmaxlen; uint dummy_errors; - if (realloc(str_length+ add_length)) + if (realloc_with_extra_if_needed(str_length+ add_length)) return TRUE; str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset, s, arg_length, &my_charset_latin1, @@ -447,7 +447,7 @@ bool String::append(const char *s,uint32 arg_length) /* For an ASCII compatinble string we can just append. */ - if (realloc(str_length+arg_length)) + if (realloc_with_extra_if_needed(str_length+arg_length)) return TRUE; memcpy(Ptr+str_length,s,arg_length); str_length+=arg_length; @@ -478,14 +478,14 @@ bool String::append(const char *s,uint32 arg_length, CHARSET_INFO *cs) { uint32 add_length= arg_length / cs->mbminlen * str_charset->mbmaxlen; uint dummy_errors; - if (realloc(str_length + add_length)) + if (realloc_with_extra_if_needed(str_length + add_length)) return TRUE; str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset, s, arg_length, cs, &dummy_errors); } else { - if (realloc(str_length + arg_length)) + if (realloc_with_extra_if_needed(str_length + arg_length)) return TRUE; memcpy(Ptr + str_length, s, arg_length); str_length+= arg_length; @@ -497,7 +497,7 @@ bool String::append(const char *s,uint32 arg_length, CHARSET_INFO *cs) #ifdef TO_BE_REMOVED bool String::append(FILE* file, uint32 arg_length, myf my_flags) { - if (realloc(str_length+arg_length)) + if (realloc_with_extra_if_needed(str_length+arg_length)) return TRUE; if (my_fread(file, (uchar*) Ptr + str_length, arg_length, my_flags)) { @@ -511,7 +511,7 @@ bool String::append(FILE* file, uint32 arg_length, myf my_flags) bool String::append(IO_CACHE* file, uint32 arg_length) { - if (realloc(str_length+arg_length)) + if (realloc_with_extra_if_needed(str_length+arg_length)) return TRUE; if (my_b_read(file, (uchar*) Ptr + str_length, arg_length)) { @@ -527,7 +527,7 @@ bool String::append_with_prefill(const char *s,uint32 arg_length, { int t_length= arg_length > full_length ? arg_length : full_length; - if (realloc(str_length + t_length)) + if (realloc_with_extra_if_needed(str_length + t_length)) return TRUE; t_length= full_length - arg_length; if (t_length > 0) @@ -636,7 +636,7 @@ bool String::replace(uint32 offset,uint32 arg_length, { if (diff) { - if (realloc(str_length+(uint32) diff)) + if (realloc_with_extra_if_needed(str_length+(uint32) diff)) return TRUE; bmove_upp((uchar*) Ptr+str_length+diff, (uchar*) Ptr+str_length, str_length-offset-arg_length); diff --git a/sql/sql_string.h b/sql/sql_string.h index e595de47f99..dc9122a4fcb 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -53,23 +53,24 @@ uint convert_to_printable(char *to, size_t to_len, class String { char *Ptr; - uint32 str_length,Alloced_length; + uint32 str_length,Alloced_length, extra_alloc; bool alloced; CHARSET_INFO *str_charset; public: String() { - Ptr=0; str_length=Alloced_length=0; alloced=0; + Ptr=0; str_length=Alloced_length=extra_alloc=0; alloced=0; str_charset= &my_charset_bin; } String(uint32 length_arg) { - alloced=0; Alloced_length=0; (void) real_alloc(length_arg); + alloced=0; Alloced_length= extra_alloc= 0; (void) real_alloc(length_arg); str_charset= &my_charset_bin; } String(const char *str, CHARSET_INFO *cs) { - Ptr=(char*) str; str_length=(uint) strlen(str); Alloced_length=0; alloced=0; + Ptr=(char*) str; str_length= (uint32) strlen(str); + Alloced_length= extra_alloc= 0; alloced=0; str_charset=cs; } /* @@ -79,18 +80,18 @@ public: */ String(const char *str,uint32 len, CHARSET_INFO *cs) { - Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0; + Ptr=(char*) str; str_length=len; Alloced_length= extra_alloc=0; alloced=0; str_charset=cs; } String(char *str,uint32 len, CHARSET_INFO *cs) { - Ptr=(char*) str; Alloced_length=str_length=len; alloced=0; + Ptr=(char*) str; Alloced_length=str_length=len; extra_alloc= 0; alloced=0; str_charset=cs; } String(const String &str) { Ptr=str.Ptr ; str_length=str.str_length ; - Alloced_length=str.Alloced_length; alloced=0; + Alloced_length=str.Alloced_length; extra_alloc= 0; alloced=0; str_charset=str.str_charset; } static void *operator new(size_t size, MEM_ROOT *mem_root) throw () @@ -106,8 +107,10 @@ public: inline CHARSET_INFO *charset() const { return str_charset; } inline uint32 length() const { return str_length;} inline uint32 alloced_length() const { return Alloced_length;} + inline uint32 extra_allocation() const { return extra_alloc;} inline char& operator [] (uint32 i) const { return Ptr[i]; } inline void length(uint32 len) { str_length=len ; } + inline void extra_allocation(uint32 len) { extra_alloc= len; } inline bool is_empty() const { return (str_length == 0); } inline void mark_as_const() { Alloced_length= 0;} inline const char *ptr() const { return Ptr; } @@ -136,23 +139,21 @@ public: { DBUG_ASSERT(&str != this); free(); - Ptr=(char*) str.ptr()+offset; str_length=arg_length; alloced=0; + Ptr=(char*) str.ptr()+offset; str_length=arg_length; if (str.Alloced_length) Alloced_length=str.Alloced_length-offset; - else - Alloced_length=0; str_charset=str.str_charset; } inline void set(char *str,uint32 arg_length, CHARSET_INFO *cs) { free(); - Ptr=(char*) str; str_length=Alloced_length=arg_length ; alloced=0; + Ptr=(char*) str; str_length=Alloced_length=arg_length; str_charset=cs; } inline void set(const char *str,uint32 arg_length, CHARSET_INFO *cs) { free(); - Ptr=(char*) str; str_length=arg_length; Alloced_length=0 ; alloced=0; + Ptr=(char*) str; str_length=arg_length; str_charset=cs; } bool set_ascii(const char *str, uint32 arg_length); @@ -203,11 +204,11 @@ public: if (alloced) { alloced=0; - Alloced_length=0; my_free(Ptr,MYF(0)); - Ptr=0; - str_length=0; /* Safety */ } + Alloced_length= extra_alloc= 0; + Ptr=0; + str_length=0; /* Safety */ } inline bool alloc(uint32 arg_length) { @@ -217,9 +218,21 @@ public: } bool real_alloc(uint32 arg_length); // Empties old string bool realloc(uint32 arg_length); - inline void shrink(uint32 arg_length) // Shrink buffer + bool realloc_with_extra(uint32 arg_length) + { + if (extra_alloc < 4096) + extra_alloc= extra_alloc*2+128; + return realloc(arg_length + extra_alloc); + } + bool realloc_with_extra_if_needed(uint32 arg_length) { if (arg_length < Alloced_length) + return 0; + return realloc_with_extra(arg_length); + } + inline void shrink(uint32 arg_length) // Shrink buffer + { + if (ALIGN_SIZE(arg_length+1) < Alloced_length) { char *new_ptr; if (!(new_ptr=(char*) my_realloc(Ptr,arg_length,MYF(0)))) @@ -246,7 +259,6 @@ public: DBUG_ASSERT(!s.uses_buffer_owned_by(this)); free(); Ptr=s.Ptr ; str_length=s.str_length ; Alloced_length=s.Alloced_length; - alloced=0; } return *this; } @@ -281,7 +293,7 @@ public: } else { - if (realloc(str_length+1)) + if (realloc_with_extra(str_length + 1)) return 1; Ptr[str_length++]=chr; } diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 541fcc155af..185c0a02799 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -57,9 +57,10 @@ print_where(COND *cond,const char *info, enum_query_type query_type) { if (cond) { - char buff[256]; + char buff[1024]; String str(buff,(uint32) sizeof(buff), system_charset_info); str.length(0); + str.extra_allocation(1024); cond->print(&str, query_type); str.append('\0'); DBUG_LOCK_FILE; diff --git a/sql/table.cc b/sql/table.cc index 7a2581d5ab8..45c1f5ab378 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3328,11 +3328,13 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) is backward compatible. */ } - char buffer[STRING_BUFFER_USUAL_SIZE]; + char buffer[1024]; for (i=0 ; i < table_def->count; i++, field_def++) { String sql_type(buffer, sizeof(buffer), system_charset_info); sql_type.length(0); + /* Allocate min 256 characters at once */ + sql_type.extra_allocation(256); if (i < table->s->fields) { Field *field= table->field[i]; From 83e40f9634f860d8fbb1c4877b370003ca693618 Mon Sep 17 00:00:00 2001 From: Jon Olav Hauglid Date: Mon, 8 Nov 2010 12:51:48 +0100 Subject: [PATCH 026/238] Bug #45288 pb2 returns a lot of compilation warnings GCOV builds were broken after the patch for Bug#57933 which added add -Wdeclaration-after-statement to gcc builds. This patch fixes: stacktrace.c:328: warning: ISO C90 forbids mixed declarations and code No test case added. --- mysys/stacktrace.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mysys/stacktrace.c b/mysys/stacktrace.c index 7bac8017324..ebd84548a9b 100644 --- a/mysys/stacktrace.c +++ b/mysys/stacktrace.c @@ -318,6 +318,9 @@ end: /* Produce a core for the thread */ void my_write_core(int sig) { +#ifdef HAVE_gcov + extern void __gcov_flush(void); +#endif signal(sig, SIG_DFL); #ifdef HAVE_gcov /* @@ -325,7 +328,6 @@ void my_write_core(int sig) information from this process, causing gcov output to be incomplete. So we force the writing of coverage information here before terminating. */ - extern void __gcov_flush(void); __gcov_flush(); #endif pthread_kill(pthread_self(), sig); From bf10c4a583a93997988b0e7fb01d9dda14bbe325 Mon Sep 17 00:00:00 2001 From: "Horst.Hunger" Date: Mon, 8 Nov 2010 16:30:26 +0100 Subject: [PATCH 027/238] Fix for bug#52501 consisting of changes of some sys_vars tests including review results. --- mysql-test/suite/sys_vars/README | 3 -- .../suite/sys_vars/inc/timestamp_basic.inc | 4 -- .../sys_vars/r/general_log_file_basic.result | 5 +- .../suite/sys_vars/r/general_log_func.result | 2 + .../r/innodb_commit_concurrency_basic.result | 46 ++++++------------- .../suite/sys_vars/r/log_output_basic.result | 4 +- .../suite/sys_vars/r/log_output_func.result | 3 +- .../r/slow_query_log_file_basic.result | 4 +- .../sys_vars/r/timestamp_basic_32.result | 12 ++--- .../sys_vars/r/timestamp_basic_64.result | 16 +++---- .../sys_vars/r/tmp_table_size_basic.result | 2 - .../sys_vars/t/completion_type_func.test | 2 +- mysql-test/suite/sys_vars/t/disabled.def | 13 ++++++ .../sys_vars/t/general_log_file_basic.test | 6 ++- .../suite/sys_vars/t/general_log_func.test | 2 + ...innodb_commit_concurrency_basic-master.opt | 1 + .../t/innodb_commit_concurrency_basic.test | 18 +++----- .../suite/sys_vars/t/log_output_func.test | 6 ++- .../myisam_data_pointer_size_func-master.opt | 1 + .../t/myisam_data_pointer_size_func.test | 3 ++ .../suite/sys_vars/t/rpl_init_slave_func.test | 2 +- .../sys_vars/t/slow_query_log_file_basic.test | 8 +++- .../sys_vars/t/sql_log_off_func-master.opt | 1 + .../suite/sys_vars/t/timestamp_basic_32.test | 4 ++ .../suite/sys_vars/t/timestamp_basic_64.test | 5 ++ .../sys_vars/t/tmp_table_size_basic.test | 3 +- 26 files changed, 91 insertions(+), 85 deletions(-) delete mode 100644 mysql-test/suite/sys_vars/README create mode 100644 mysql-test/suite/sys_vars/t/disabled.def create mode 100644 mysql-test/suite/sys_vars/t/innodb_commit_concurrency_basic-master.opt create mode 100644 mysql-test/suite/sys_vars/t/myisam_data_pointer_size_func-master.opt create mode 100644 mysql-test/suite/sys_vars/t/sql_log_off_func-master.opt diff --git a/mysql-test/suite/sys_vars/README b/mysql-test/suite/sys_vars/README deleted file mode 100644 index a84f00f1f62..00000000000 --- a/mysql-test/suite/sys_vars/README +++ /dev/null @@ -1,3 +0,0 @@ -Some of these tests allocate more than 4GB RAM. -So, assure that the machine on which the suite will be executed has more than 4GB RAM. - diff --git a/mysql-test/suite/sys_vars/inc/timestamp_basic.inc b/mysql-test/suite/sys_vars/inc/timestamp_basic.inc index 9ef57c97043..68ded3e5a97 100644 --- a/mysql-test/suite/sys_vars/inc/timestamp_basic.inc +++ b/mysql-test/suite/sys_vars/inc/timestamp_basic.inc @@ -66,10 +66,6 @@ SET @@timestamp = 0; --echo 'Setting 0 resets timestamp to session default timestamp' -SET @@timestamp = 123456789123456; -SELECT @@timestamp; -SET @@timestamp = 60*60*60*60*365; -SELECT @@timestamp; SET @@timestamp = -1000000000; SELECT @@timestamp; diff --git a/mysql-test/suite/sys_vars/r/general_log_file_basic.result b/mysql-test/suite/sys_vars/r/general_log_file_basic.result index 48a8d90b55e..5c0b93cf4ab 100644 --- a/mysql-test/suite/sys_vars/r/general_log_file_basic.result +++ b/mysql-test/suite/sys_vars/r/general_log_file_basic.result @@ -1,7 +1,6 @@ -SET @start_value = @@global.general_log_file; SELECT @start_value; @start_value -test.log +NULL '#---------------------FN_DYNVARS_004_01-------------------------#' SET @@global.general_log_file = DEFAULT; SELECT RIGHT(@@global.general_log_file,10) AS log_file; @@ -17,4 +16,4 @@ FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='general_log_file'; @@global.general_log_file = VARIABLE_VALUE 1 -SET @@global.general_log_file= @start_value; +SET @@global.general_log_file= 'test.log'; diff --git a/mysql-test/suite/sys_vars/r/general_log_func.result b/mysql-test/suite/sys_vars/r/general_log_func.result index 39ba90265d5..119991396e0 100644 --- a/mysql-test/suite/sys_vars/r/general_log_func.result +++ b/mysql-test/suite/sys_vars/r/general_log_func.result @@ -26,6 +26,7 @@ SELECT @@general_log; INSERT into t1(name) values('Record_3'); INSERT into t1(name) values('Record_4'); ## There should be a difference ## +SET @start_value= @@global.max_allowed_packet; SET @@global.max_allowed_packet= 1024*1024*1024; SET @orig_file= load_file('MYSQLD_LOGFILE.orig'); SET @copy_file= load_file('MYSQLD_LOGFILE.copy'); @@ -34,3 +35,4 @@ STRCMP(@orig_file, @copy_file) 1 ## Dropping tables ## DROP TABLE t1; +SET @@global.max_allowed_packet= @start_value; diff --git a/mysql-test/suite/sys_vars/r/innodb_commit_concurrency_basic.result b/mysql-test/suite/sys_vars/r/innodb_commit_concurrency_basic.result index 301016d4362..201f183ad0e 100644 --- a/mysql-test/suite/sys_vars/r/innodb_commit_concurrency_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_commit_concurrency_basic.result @@ -1,30 +1,23 @@ SET @global_start_value = @@global.innodb_commit_concurrency; SELECT @global_start_value; @global_start_value -0 +10 '#--------------------FN_DYNVARS_046_01------------------------#' -SET @@global.innodb_commit_concurrency = 0; SET @@global.innodb_commit_concurrency = DEFAULT; SELECT @@global.innodb_commit_concurrency; @@global.innodb_commit_concurrency -0 +10 '#---------------------FN_DYNVARS_046_02-------------------------#' SET innodb_commit_concurrency = 1; ERROR HY000: Variable 'innodb_commit_concurrency' is a GLOBAL variable and should be set with SET GLOBAL SELECT @@innodb_commit_concurrency; @@innodb_commit_concurrency -0 +10 SELECT local.innodb_commit_concurrency; ERROR 42S02: Unknown table 'local' in field list SET global innodb_commit_concurrency = 0; -SELECT @@global.innodb_commit_concurrency; -@@global.innodb_commit_concurrency -0 +ERROR HY000: Incorrect arguments to SET '#--------------------FN_DYNVARS_046_03------------------------#' -SET @@global.innodb_commit_concurrency = 0; -SELECT @@global.innodb_commit_concurrency; -@@global.innodb_commit_concurrency -0 SET @@global.innodb_commit_concurrency = 1; SELECT @@global.innodb_commit_concurrency; @@global.innodb_commit_concurrency @@ -35,27 +28,17 @@ SELECT @@global.innodb_commit_concurrency; 1000 '#--------------------FN_DYNVARS_046_04-------------------------#' SET @@global.innodb_commit_concurrency = -1; -Warnings: -Warning 1292 Truncated incorrect commit_concurrency value: '18446744073709551615' -SELECT @@global.innodb_commit_concurrency; -@@global.innodb_commit_concurrency -1000 +SELECT @@global.innodb_commit_concurrency IN (4294967295,18446744073709551615); +@@global.innodb_commit_concurrency IN (4294967295,18446744073709551615) +1 SET @@global.innodb_commit_concurrency = "T"; ERROR 42000: Incorrect argument type to variable 'innodb_commit_concurrency' -SELECT @@global.innodb_commit_concurrency; -@@global.innodb_commit_concurrency -1000 SET @@global.innodb_commit_concurrency = "Y"; ERROR 42000: Incorrect argument type to variable 'innodb_commit_concurrency' -SELECT @@global.innodb_commit_concurrency; -@@global.innodb_commit_concurrency -1000 SET @@global.innodb_commit_concurrency = 1001; -Warnings: -Warning 1292 Truncated incorrect commit_concurrency value: '1001' SELECT @@global.innodb_commit_concurrency; @@global.innodb_commit_concurrency -1000 +1001 '#----------------------FN_DYNVARS_046_05------------------------#' SELECT @@global.innodb_commit_concurrency = VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES @@ -65,32 +48,33 @@ VARIABLE_VALUE 1 SELECT @@global.innodb_commit_concurrency; @@global.innodb_commit_concurrency -1000 +1001 SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='innodb_commit_concurrency'; VARIABLE_VALUE -1000 +1001 '#---------------------FN_DYNVARS_046_06-------------------------#' SET @@global.innodb_commit_concurrency = OFF; ERROR 42000: Incorrect argument type to variable 'innodb_commit_concurrency' SELECT @@global.innodb_commit_concurrency; @@global.innodb_commit_concurrency -1000 +1001 SET @@global.innodb_commit_concurrency = ON; ERROR 42000: Incorrect argument type to variable 'innodb_commit_concurrency' SELECT @@global.innodb_commit_concurrency; @@global.innodb_commit_concurrency -1000 +1001 '#---------------------FN_DYNVARS_046_07----------------------#' SET @@global.innodb_commit_concurrency = TRUE; SELECT @@global.innodb_commit_concurrency; @@global.innodb_commit_concurrency 1 SET @@global.innodb_commit_concurrency = FALSE; +ERROR HY000: Incorrect arguments to SET SELECT @@global.innodb_commit_concurrency; @@global.innodb_commit_concurrency -0 +1 SET @@global.innodb_commit_concurrency = @global_start_value; SELECT @@global.innodb_commit_concurrency; @@global.innodb_commit_concurrency -0 +10 diff --git a/mysql-test/suite/sys_vars/r/log_output_basic.result b/mysql-test/suite/sys_vars/r/log_output_basic.result index 481d5862074..6f350556ff9 100644 --- a/mysql-test/suite/sys_vars/r/log_output_basic.result +++ b/mysql-test/suite/sys_vars/r/log_output_basic.result @@ -1,7 +1,7 @@ SET @start_value = @@global.log_output; SELECT @start_value; @start_value -FILE,TABLE +FILE '#--------------------FN_DYNVARS_065_01------------------------#' SET @@global.log_output = FILE; SET @@global.log_output = DEFAULT; @@ -172,4 +172,4 @@ TABLE SET @@global.log_output = @start_value; SELECT @@global.log_output; @@global.log_output -FILE,TABLE +FILE diff --git a/mysql-test/suite/sys_vars/r/log_output_func.result b/mysql-test/suite/sys_vars/r/log_output_func.result index 060f930a161..00a8e824f78 100644 --- a/mysql-test/suite/sys_vars/r/log_output_func.result +++ b/mysql-test/suite/sys_vars/r/log_output_func.result @@ -1,6 +1,5 @@ SET @start_value= @@global.log_output; SET @start_general_log= @@global.general_log; -SET @start_general_log_file= @@global.general_log_file; '#--------------------FN_DYNVARS_065_01-------------------------#' SET @@global.log_output = 'NONE'; 'connect (con1,localhost,root,,,,)' @@ -53,7 +52,7 @@ count(*) DROP TABLE t1; connection default; SET @@global.general_log= 'OFF'; -SET @@global.general_log_file= @start_general_log_file; +SET @@global.general_log_file= '/home/horst/bzr/5.1-52501/mysql-test/var/mysqld.1/mysqld.log'; SET @@global.log_output= @start_value; SET @@global.general_log= @start_general_log; SET @@global.general_log= 'ON'; diff --git a/mysql-test/suite/sys_vars/r/slow_query_log_file_basic.result b/mysql-test/suite/sys_vars/r/slow_query_log_file_basic.result index 925f940a5c4..3cd62187d0b 100644 --- a/mysql-test/suite/sys_vars/r/slow_query_log_file_basic.result +++ b/mysql-test/suite/sys_vars/r/slow_query_log_file_basic.result @@ -1,4 +1,4 @@ -SET @start_value = @@global.slow_query_log_file; +slowtest.log '#---------------------FN_DYNVARS_004_01-------------------------#' SET @@global.slow_query_log_file = DEFAULT; SELECT RIGHT(@@global.slow_query_log_file,15); @@ -14,4 +14,4 @@ FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='slow_query_log_file'; @@global.slow_query_log_file = VARIABLE_VALUE 1 -SET @@global.slow_query_log_file= @start_value; +SET @@global.slow_query_log_file= 'slowtest.log'; diff --git a/mysql-test/suite/sys_vars/r/timestamp_basic_32.result b/mysql-test/suite/sys_vars/r/timestamp_basic_32.result index a8be2201e68..87c9edc668e 100644 --- a/mysql-test/suite/sys_vars/r/timestamp_basic_32.result +++ b/mysql-test/suite/sys_vars/r/timestamp_basic_32.result @@ -8,14 +8,6 @@ ERROR HY000: Variable 'timestamp' is a SESSION variable and can't be used with S '#--------------------FN_DYNVARS_001_03------------------------#' SET @@timestamp = 0; 'Setting 0 resets timestamp to session default timestamp' -SET @@timestamp = 123456789123456; -SELECT @@timestamp; -@@timestamp -2249167232 -SET @@timestamp = 60*60*60*60*365; -SELECT @@timestamp; -@@timestamp -435432704 SET @@timestamp = -1000000000; SELECT @@timestamp; @@timestamp @@ -66,3 +58,7 @@ ERROR 42S02: Unknown table 'session' in field list SELECT timestamp = @@session.timestamp; ERROR 42S22: Unknown column 'timestamp' in 'field list' SET @@timestamp = @session_start_value; +SET @@timestamp = 123456789123456; +ERROR HY000: This version of MySQL doesn't support dates later than 2038 +SET @@timestamp = 60*60*60*60*365; +ERROR HY000: This version of MySQL doesn't support dates later than 2038 diff --git a/mysql-test/suite/sys_vars/r/timestamp_basic_64.result b/mysql-test/suite/sys_vars/r/timestamp_basic_64.result index 824a3ea5529..b5d3979610f 100644 --- a/mysql-test/suite/sys_vars/r/timestamp_basic_64.result +++ b/mysql-test/suite/sys_vars/r/timestamp_basic_64.result @@ -8,14 +8,6 @@ ERROR HY000: Variable 'timestamp' is a SESSION variable and can't be used with S '#--------------------FN_DYNVARS_001_03------------------------#' SET @@timestamp = 0; 'Setting 0 resets timestamp to session default timestamp' -SET @@timestamp = 123456789123456; -SELECT @@timestamp; -@@timestamp -123456789123456 -SET @@timestamp = 60*60*60*60*365; -SELECT @@timestamp; -@@timestamp -4730400000 SET @@timestamp = -1000000000; SELECT @@timestamp; @@timestamp @@ -66,3 +58,11 @@ ERROR 42S02: Unknown table 'session' in field list SELECT timestamp = @@session.timestamp; ERROR 42S22: Unknown column 'timestamp' in 'field list' SET @@timestamp = @session_start_value; +SET @@timestamp = 123456789123456; +SELECT @@timestamp; +@@timestamp +123456789123456 +SET @@timestamp = 60*60*60*60*365; +SELECT @@timestamp; +@@timestamp +4730400000 diff --git a/mysql-test/suite/sys_vars/r/tmp_table_size_basic.result b/mysql-test/suite/sys_vars/r/tmp_table_size_basic.result index 2ebeb8d61d8..06b624ad5c8 100644 --- a/mysql-test/suite/sys_vars/r/tmp_table_size_basic.result +++ b/mysql-test/suite/sys_vars/r/tmp_table_size_basic.result @@ -100,8 +100,6 @@ SELECT @@session.tmp_table_size; SET @@session.tmp_table_size = "Test"; ERROR 42000: Incorrect argument type to variable 'tmp_table_size' SET @@session.tmp_table_size = 12345678901; -Warnings: -Warning 1292 Truncated incorrect tmp_table_size value: '12345678901' SELECT @@session.tmp_table_size IN (12345678901,4294967295); @@session.tmp_table_size IN (12345678901,4294967295) 1 diff --git a/mysql-test/suite/sys_vars/t/completion_type_func.test b/mysql-test/suite/sys_vars/t/completion_type_func.test index 8e363ed2a7d..82e2dc47e54 100644 --- a/mysql-test/suite/sys_vars/t/completion_type_func.test +++ b/mysql-test/suite/sys_vars/t/completion_type_func.test @@ -18,7 +18,7 @@ # server-system-variables.html#option_mysqld_completion_type # # # ################################################################################ - +--source include/not_embedded.inc --source include/have_innodb.inc --disable_warnings diff --git a/mysql-test/suite/sys_vars/t/disabled.def b/mysql-test/suite/sys_vars/t/disabled.def new file mode 100644 index 00000000000..915ea7a6f5c --- /dev/null +++ b/mysql-test/suite/sys_vars/t/disabled.def @@ -0,0 +1,13 @@ +############################################################################## +# +# List the test cases that are to be disabled temporarily. +# +# Separate the test case name and the comment with ':'. +# +# : BUG# +# +# Do not use any TAB characters for whitespace. +# +############################################################################## +sys_vars.max_binlog_cache_size_basic_64 : bug#56408 2010-08-31 Horst +sys_vars.max_binlog_cache_size_basic_32 : bug#56408 2010-08-31 Horst diff --git a/mysql-test/suite/sys_vars/t/general_log_file_basic.test b/mysql-test/suite/sys_vars/t/general_log_file_basic.test index 014108f88d2..35905bad987 100644 --- a/mysql-test/suite/sys_vars/t/general_log_file_basic.test +++ b/mysql-test/suite/sys_vars/t/general_log_file_basic.test @@ -35,7 +35,8 @@ # Saving initial value of general_log_file in a temporary variable # ######################################################################## -SET @start_value = @@global.general_log_file; +#SET @start_value = @@global.general_log_file; +LET $start_value = `SELECT @@global.general_log_file`; SELECT @start_value; @@ -68,7 +69,8 @@ SELECT @@global.general_log_file = VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='general_log_file'; -SET @@global.general_log_file= @start_value; +#SET @@global.general_log_file= @start_value; +eval SET @@global.general_log_file= '$start_value'; ##################################################### # END OF general_log_file TESTS # diff --git a/mysql-test/suite/sys_vars/t/general_log_func.test b/mysql-test/suite/sys_vars/t/general_log_func.test index 24d535e88e5..d355d0d619c 100644 --- a/mysql-test/suite/sys_vars/t/general_log_func.test +++ b/mysql-test/suite/sys_vars/t/general_log_func.test @@ -79,6 +79,7 @@ INSERT into t1(name) values('Record_4'); --chmod 0777 $MYSQLD_LOGFILE.orig --echo ## There should be a difference ## +SET @start_value= @@global.max_allowed_packet; SET @@global.max_allowed_packet= 1024*1024*1024; --replace_result $MYSQLD_LOGFILE MYSQLD_LOGFILE eval SET @orig_file= load_file('$MYSQLD_LOGFILE.orig'); @@ -91,3 +92,4 @@ eval SELECT STRCMP(@orig_file, @copy_file); --echo ## Dropping tables ## DROP TABLE t1; +SET @@global.max_allowed_packet= @start_value; diff --git a/mysql-test/suite/sys_vars/t/innodb_commit_concurrency_basic-master.opt b/mysql-test/suite/sys_vars/t/innodb_commit_concurrency_basic-master.opt new file mode 100644 index 00000000000..727bbc4b11b --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_commit_concurrency_basic-master.opt @@ -0,0 +1 @@ +--innodb-commit-concurrency=10 diff --git a/mysql-test/suite/sys_vars/t/innodb_commit_concurrency_basic.test b/mysql-test/suite/sys_vars/t/innodb_commit_concurrency_basic.test index 1ef69e34999..2c7645f3b25 100644 --- a/mysql-test/suite/sys_vars/t/innodb_commit_concurrency_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_commit_concurrency_basic.test @@ -11,6 +11,10 @@ # Creation Date: 2008-02-07 # # Author: Rizwan # # # +# Modified 2010-09-01 Horst # +# Added amaster.opt with innodb-commit-concurrency > 0 to be able to assign # +# different values <> 0 # +# # #Description:Test Cases of Dynamic System Variable innodb_commit_concurrency # # that checks the behavior of this variable in the following ways # # * Default Value # @@ -43,7 +47,6 @@ SELECT @global_start_value; # Display the DEFAULT value of innodb_commit_concurrency # ######################################################################## -SET @@global.innodb_commit_concurrency = 0; SET @@global.innodb_commit_concurrency = DEFAULT; SELECT @@global.innodb_commit_concurrency; @@ -60,20 +63,14 @@ SELECT @@innodb_commit_concurrency; --Error ER_UNKNOWN_TABLE SELECT local.innodb_commit_concurrency; +--error ER_WRONG_ARGUMENTS SET global innodb_commit_concurrency = 0; -SELECT @@global.innodb_commit_concurrency; - - --echo '#--------------------FN_DYNVARS_046_03------------------------#' ########################################################################## # change the value of innodb_commit_concurrency to a valid value # ########################################################################## - -SET @@global.innodb_commit_concurrency = 0; -SELECT @@global.innodb_commit_concurrency; - SET @@global.innodb_commit_concurrency = 1; SELECT @@global.innodb_commit_concurrency; SET @@global.innodb_commit_concurrency = 1000; @@ -85,15 +82,13 @@ SELECT @@global.innodb_commit_concurrency; ########################################################################### SET @@global.innodb_commit_concurrency = -1; -SELECT @@global.innodb_commit_concurrency; +SELECT @@global.innodb_commit_concurrency IN (4294967295,18446744073709551615); --Error ER_WRONG_TYPE_FOR_VAR SET @@global.innodb_commit_concurrency = "T"; -SELECT @@global.innodb_commit_concurrency; --Error ER_WRONG_TYPE_FOR_VAR SET @@global.innodb_commit_concurrency = "Y"; -SELECT @@global.innodb_commit_concurrency; SET @@global.innodb_commit_concurrency = 1001; SELECT @@global.innodb_commit_concurrency; @@ -131,6 +126,7 @@ SELECT @@global.innodb_commit_concurrency; SET @@global.innodb_commit_concurrency = TRUE; SELECT @@global.innodb_commit_concurrency; +--error ER_WRONG_ARGUMENTS SET @@global.innodb_commit_concurrency = FALSE; SELECT @@global.innodb_commit_concurrency; diff --git a/mysql-test/suite/sys_vars/t/log_output_func.test b/mysql-test/suite/sys_vars/t/log_output_func.test index 007c4f38659..8a2fbe0728b 100644 --- a/mysql-test/suite/sys_vars/t/log_output_func.test +++ b/mysql-test/suite/sys_vars/t/log_output_func.test @@ -26,7 +26,8 @@ SET @start_value= @@global.log_output; SET @start_general_log= @@global.general_log; -SET @start_general_log_file= @@global.general_log_file; +#SET @start_general_log_file= @@global.general_log_file; +LET $start_general_log_file= `SELECT @@global.general_log_file`; --echo '#--------------------FN_DYNVARS_065_01-------------------------#' ################################################################## @@ -113,7 +114,8 @@ file_exists $MYSQLTEST_VARDIR/run/mytest.log ; --echo connection default; connection default; SET @@global.general_log= 'OFF'; -SET @@global.general_log_file= @start_general_log_file; +#SET @@global.general_log_file= @start_general_log_file; +eval SET @@global.general_log_file= '$start_general_log_file'; SET @@global.log_output= @start_value; SET @@global.general_log= @start_general_log; SET @@global.general_log= 'ON'; diff --git a/mysql-test/suite/sys_vars/t/myisam_data_pointer_size_func-master.opt b/mysql-test/suite/sys_vars/t/myisam_data_pointer_size_func-master.opt new file mode 100644 index 00000000000..d392e2e4262 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/myisam_data_pointer_size_func-master.opt @@ -0,0 +1 @@ +--log-error='dummy.log' diff --git a/mysql-test/suite/sys_vars/t/myisam_data_pointer_size_func.test b/mysql-test/suite/sys_vars/t/myisam_data_pointer_size_func.test index 37dd3a5a297..441e9c72982 100644 --- a/mysql-test/suite/sys_vars/t/myisam_data_pointer_size_func.test +++ b/mysql-test/suite/sys_vars/t/myisam_data_pointer_size_func.test @@ -19,6 +19,9 @@ # # ################################################################################ +# due to bug#56486 +--source include/not_windows.inc + --echo '#--------------------FN_DYNVARS_093_01-------------------------#' ############################################################################### # Check if setting myisam_data_pointer_size is changed in every new connection# diff --git a/mysql-test/suite/sys_vars/t/rpl_init_slave_func.test b/mysql-test/suite/sys_vars/t/rpl_init_slave_func.test index f2c66eb3a0a..2cc31c91388 100644 --- a/mysql-test/suite/sys_vars/t/rpl_init_slave_func.test +++ b/mysql-test/suite/sys_vars/t/rpl_init_slave_func.test @@ -55,7 +55,7 @@ DROP TABLE t1; eval SELECT @@global.init_slave = $my_init_slave; --echo Expect 1 # wait for the slave threads have set the global variable. -let $wait_timeout= 90; +let $wait_timeout= 240; let $wait_condition= SELECT @@global.max_connections = @start_max_connections; --source include/wait_condition_sp.inc # check that the action in init_slave does not happen immediately diff --git a/mysql-test/suite/sys_vars/t/slow_query_log_file_basic.test b/mysql-test/suite/sys_vars/t/slow_query_log_file_basic.test index 9125b686cad..810588b8f4e 100644 --- a/mysql-test/suite/sys_vars/t/slow_query_log_file_basic.test +++ b/mysql-test/suite/sys_vars/t/slow_query_log_file_basic.test @@ -35,7 +35,9 @@ # Saving initial value of slow_query_log_file in a temporary variable # ########################################################################### -SET @start_value = @@global.slow_query_log_file; +#SET @start_value = @@global.slow_query_log_file; +LET $start_value = `SELECT @@global.slow_query_log_file`; +--echo $start_value --echo '#---------------------FN_DYNVARS_004_01-------------------------#' ############################################### @@ -65,7 +67,9 @@ SELECT @@global.slow_query_log_file = VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME='slow_query_log_file'; -SET @@global.slow_query_log_file= @start_value; +#SET @@global.slow_query_log_file= @start_value; +eval SET @@global.slow_query_log_file= '$start_value'; +#SELECT @start_value; ##################################################### # END OF slow_query_log_file TESTS # ##################################################### diff --git a/mysql-test/suite/sys_vars/t/sql_log_off_func-master.opt b/mysql-test/suite/sys_vars/t/sql_log_off_func-master.opt new file mode 100644 index 00000000000..875ecc54b55 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/sql_log_off_func-master.opt @@ -0,0 +1 @@ +--general-log --log-output=TABLE,FILE diff --git a/mysql-test/suite/sys_vars/t/timestamp_basic_32.test b/mysql-test/suite/sys_vars/t/timestamp_basic_32.test index a2b6139aef9..11b7535d9ef 100644 --- a/mysql-test/suite/sys_vars/t/timestamp_basic_32.test +++ b/mysql-test/suite/sys_vars/t/timestamp_basic_32.test @@ -7,3 +7,7 @@ --source include/have_32bit.inc --source suite/sys_vars/inc/timestamp_basic.inc +--error ER_UNKNOWN_ERROR +SET @@timestamp = 123456789123456; +--error ER_UNKNOWN_ERROR +SET @@timestamp = 60*60*60*60*365; diff --git a/mysql-test/suite/sys_vars/t/timestamp_basic_64.test b/mysql-test/suite/sys_vars/t/timestamp_basic_64.test index fbc86316ed9..5180c86392a 100644 --- a/mysql-test/suite/sys_vars/t/timestamp_basic_64.test +++ b/mysql-test/suite/sys_vars/t/timestamp_basic_64.test @@ -7,3 +7,8 @@ --source include/have_64bit.inc --source suite/sys_vars/inc/timestamp_basic.inc +SET @@timestamp = 123456789123456; +SELECT @@timestamp; +SET @@timestamp = 60*60*60*60*365; +SELECT @@timestamp; + diff --git a/mysql-test/suite/sys_vars/t/tmp_table_size_basic.test b/mysql-test/suite/sys_vars/t/tmp_table_size_basic.test index c2ff51d50ca..116196ddb07 100644 --- a/mysql-test/suite/sys_vars/t/tmp_table_size_basic.test +++ b/mysql-test/suite/sys_vars/t/tmp_table_size_basic.test @@ -133,8 +133,9 @@ SELECT @@session.tmp_table_size; --Error ER_WRONG_TYPE_FOR_VAR SET @@session.tmp_table_size = "Test"; +--disable_warnings SET @@session.tmp_table_size = 12345678901; - +--enable_warnings # With a 64 bit mysqld:12345678901,with a 32 bit mysqld: 4294967295 SELECT @@session.tmp_table_size IN (12345678901,4294967295); From 1b88853ab80315746dc38057bbd25ec6da7e9bf6 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Tue, 9 Nov 2010 12:45:13 -0200 Subject: [PATCH 028/238] Bug#57210: remove pstack Quoting from the bug report: The pstack library has been included in MySQL since version 4.0.0. It's useless and should be removed. Details: According to its own documentation, pstack only works on Linux on x86 in 32 bit mode and requires LinuxThreads and a statically linked binary. It doesn't really support any Linux from 2003 or later and doesn't work on any other OS. The --enable-pstack option is thus deprecated and has no effect. --- BUILD/compile-pentium-mysqlfs-debug | 2 +- Makefile.am | 2 - README | 94 - configure.in | 45 +- include/mysql_embed.h | 1 - pstack/Makefile.am | 32 - pstack/aout/Makefile.am | 4 - pstack/aout/aout64.h | 475 -- pstack/aout/stab.def | 264 - pstack/aout/stab_gnu.h | 37 - pstack/bucomm.c | 238 - pstack/bucomm.h | 91 - pstack/budbg.h | 64 - pstack/debug.c | 3509 ------------- pstack/debug.h | 798 --- pstack/demangle.h | 90 - pstack/filemode.c | 266 - pstack/ieee.c | 7602 --------------------------- pstack/ieee.h | 138 - pstack/libiberty.h | 180 - pstack/linuxthreads.c | 90 - pstack/linuxthreads.h | 28 - pstack/pstack.c | 2746 ---------- pstack/pstack.h | 22 - pstack/pstacktrace.h | 24 - pstack/rddbg.c | 462 -- pstack/stabs.c | 5082 ------------------ sql/Makefile.am | 1 - sql/mysqld.cc | 26 +- 29 files changed, 14 insertions(+), 22399 deletions(-) delete mode 100644 pstack/Makefile.am delete mode 100644 pstack/aout/Makefile.am delete mode 100644 pstack/aout/aout64.h delete mode 100644 pstack/aout/stab.def delete mode 100644 pstack/aout/stab_gnu.h delete mode 100644 pstack/bucomm.c delete mode 100644 pstack/bucomm.h delete mode 100644 pstack/budbg.h delete mode 100644 pstack/debug.c delete mode 100644 pstack/debug.h delete mode 100644 pstack/demangle.h delete mode 100644 pstack/filemode.c delete mode 100644 pstack/ieee.c delete mode 100644 pstack/ieee.h delete mode 100644 pstack/libiberty.h delete mode 100644 pstack/linuxthreads.c delete mode 100644 pstack/linuxthreads.h delete mode 100644 pstack/pstack.c delete mode 100644 pstack/pstack.h delete mode 100644 pstack/pstacktrace.h delete mode 100644 pstack/rddbg.c delete mode 100644 pstack/stabs.c diff --git a/BUILD/compile-pentium-mysqlfs-debug b/BUILD/compile-pentium-mysqlfs-debug index c871200604e..0f457eec0bb 100755 --- a/BUILD/compile-pentium-mysqlfs-debug +++ b/BUILD/compile-pentium-mysqlfs-debug @@ -6,6 +6,6 @@ path=`dirname $0` extra_flags="$pentium_cflags $debug_cflags" extra_configs="$pentium_configs $debug_configs $static_link" -extra_configs="$extra_configs --with-debug=full --with-mysqlfs --without-server --without-pstack" +extra_configs="$extra_configs --with-debug=full --with-mysqlfs --without-server" . "$path/FINISH.sh" diff --git a/Makefile.am b/Makefile.am index 4ce753ad8aa..9996d187cd4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,7 +23,6 @@ EXTRA_DIST = INSTALL-SOURCE INSTALL-WIN-SOURCE \ SUBDIRS = . include @docs_dirs@ @zlib_dir@ \ @readline_topdir@ sql-common scripts \ - @pstack_dir@ \ @sql_union_dirs@ unittest \ @sql_server@ @man_dirs@ tests \ netware @libmysqld_dirs@ \ @@ -32,7 +31,6 @@ SUBDIRS = . include @docs_dirs@ @zlib_dir@ \ DIST_SUBDIRS = . include Docs zlib \ cmd-line-utils sql-common scripts \ - pstack \ strings mysys dbug extra regex libmysql libmysql_r client unittest storage plugin \ vio sql man tests \ netware libmysqld \ diff --git a/README b/README index ac92d77f8bd..71491e31a8c 100644 --- a/README +++ b/README @@ -1192,97 +1192,3 @@ library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. *************************************************************************** - -%%The following software may be included in this product: -pstack (part of GNU Binutils) - -Use of any of this software is governed by the terms of the license below: - -pstack is comprised of various .c and .h files; all begin like this: - -/* bucomm.h -- binutils common include file. - Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. - -This file is part of GNU Binutils. - -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; either version 2 of the License, or -(at your option) any later version. - -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., 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. */ - -*************************************************************************** - -%%The following software may be included in this product: -libiberty.h (part of pstack GNU Binutils) - -Use of any of this software is governed by the terms of the license below: - -See -http://www.koders.com/c/fid99F596804BBE22C076522B848D5575F142079064.aspx - -/* Function declarations for libiberty. - Written by Cygnus Support, 1994. - - The libiberty library provides a number of functions which are - missing on some operating systems. We do not declare those here, - to avoid conflicts with the system header files on operating - systems that do support those functions. In this file we only - declare those functions which are specific to libiberty. */ - -*************************************************************************** - -%%The following software may be included in this product: -ieee.h (part of pstack GNU Binutils) - -Use of any of this software is governed by the terms of the license below: - -See -http://src.opensolaris.org/source/xref//sfw/usr/src/cmd/gdb/gdb-6.3/include/ieee.h - - -/* IEEE Standard 695-1980 "Universal Format for Object Modules" -header file - Contributed by Cygnus Support. */ - -*************************************************************************** - -%%The following software may be included in this product: -pstack.c (part of pstack GNU Binutils) - -Use of any of this software is governed by the terms of the license below: - -/* - pstack.c -- asynchronous stack trace of a running process - Copyright (c) 1999 Ross Thompson - Author: Ross Thompson - Critical bug fix: Tim Waugh -*/ - -/* - This file 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; either version 2 of the License, or - (at your option) any later version. - - 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., 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. -*/ - -*************************************************************************** diff --git a/configure.in b/configure.in index 7fd581af009..6c9c64d9c86 100644 --- a/configure.in +++ b/configure.in @@ -910,46 +910,6 @@ struct request_info *req; ]) AC_SUBST(WRAPLIBS) -if test "$TARGET_LINUX" = "true"; then - AC_ARG_WITH(pstack, - [ --with-pstack Use the pstack backtrace library], - [ USE_PSTACK=$withval ], - [ USE_PSTACK=no ]) - pstack_libs= - pstack_dir= - if test "$USE_PSTACK" = yes -a "$TARGET_LINUX" = "true" -a "$BASE_MACHINE_TYPE" = "i386" - then - have_libiberty= have_libbfd= - my_save_LIBS="$LIBS" -dnl I have no idea if this is a good test - can not find docs for libiberty - AC_CHECK_LIB([iberty], [fdmatch], - [have_libiberty=yes - AC_CHECK_LIB([bfd], [bfd_openr], [have_libbfd=yes], , [-liberty])]) - LIBS="$my_save_LIBS" - - if test x"$have_libiberty" = xyes -a x"$have_libbfd" = xyes - then - pstack_dir="pstack" - pstack_libs="../pstack/libpstack.a -lbfd -liberty" - # We must link staticly when using pstack - with_mysqld_ldflags="-all-static" - AC_SUBST([pstack_dir]) - AC_SUBST([pstack_libs]) - AC_DEFINE([USE_PSTACK], [1], [the pstack backtrace library]) -dnl This check isn't needed, but might be nice to give some feedback.... -dnl AC_CHECK_HEADER(libiberty.h, -dnl have_libiberty_h=yes, -dnl have_libiberty_h=no) - else - USE_PSTACK="no" - fi - else - USE_PSTACK="no" - fi -fi -AC_MSG_CHECKING([if we should use pstack]) -AC_MSG_RESULT([$USE_PSTACK]) - # Check for gtty if termio.h doesn't exists if test "$ac_cv_header_termio_h" = "no" -a "$ac_cv_header_termios_h" = "no" then @@ -1178,7 +1138,7 @@ dnl Is this the right match for DEC OSF on alpha? sql/Makefile.in) # Use gen_lex_hash.linux instead of gen_lex_hash # Add library dependencies to mysqld_DEPENDENCIES - lib_DEPENDENCIES="\$(pstack_libs) \$(openssl_libs) \$(yassl_libs)" + lib_DEPENDENCIES="\$(openssl_libs) \$(yassl_libs)" cat > $filesed << EOF s,\(\./gen_lex_hash\)\$(EXEEXT),\1.linux, s%\(mysqld_DEPENDENCIES = \)%\1$lib_DEPENDENCIES % @@ -2880,9 +2840,6 @@ esac AC_SUBST(MAKE_BINARY_DISTRIBUTION_OPTIONS) # Output results -if test -d "$srcdir/pstack" ; then - AC_CONFIG_FILES(pstack/Makefile pstack/aout/Makefile) -fi if test -d "$srcdir/cmd-line-utils/readline" ; then AC_CONFIG_FILES(cmd-line-utils/readline/Makefile) fi diff --git a/include/mysql_embed.h b/include/mysql_embed.h index 4a7fd3ef63c..a7d6e610918 100644 --- a/include/mysql_embed.h +++ b/include/mysql_embed.h @@ -20,7 +20,6 @@ /* Things we don't need in the embedded version of MySQL */ /* TODO HF add #undef HAVE_VIO if we don't want client in embedded library */ -#undef HAVE_PSTACK /* No stacktrace */ #undef HAVE_OPENSSL #undef HAVE_SMEM /* No shared memory */ #undef HAVE_NDBCLUSTER_DB /* No NDB cluster */ diff --git a/pstack/Makefile.am b/pstack/Makefile.am deleted file mode 100644 index 870fed6ceeb..00000000000 --- a/pstack/Makefile.am +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (C) 2000-2003, 2005 MySQL AB -# -# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -# -# As pstack doesn't work on all configurations, we have to use -# the USE_PSTACK hack to get all files into distribution -# - -SUBDIRS = aout - -INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include - -pkglib_LIBRARIES = libpstack.a -libpstack_a_SOURCES = bucomm.c filemode.c linuxthreads.c rddbg.c \ - debug.c ieee.c pstack.c stabs.c -noinst_HEADERS = bucomm.h debug.h ieee.h budbg.h demangle.h \ - linuxthreads.h pstack.h pstacktrace.h - -# Don't update the files from bitkeeper -%::SCCS/s.% diff --git a/pstack/aout/Makefile.am b/pstack/aout/Makefile.am deleted file mode 100644 index 2e61555db87..00000000000 --- a/pstack/aout/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -noinst_HEADERS = aout64.h stab.def stab_gnu.h - -# Don't update the files from bitkeeper -%::SCCS/s.% diff --git a/pstack/aout/aout64.h b/pstack/aout/aout64.h deleted file mode 100644 index 76f1140b682..00000000000 --- a/pstack/aout/aout64.h +++ /dev/null @@ -1,475 +0,0 @@ -/* `a.out' object-file definitions, including extensions to 64-bit fields */ - -#ifndef __A_OUT_64_H__ -#define __A_OUT_64_H__ - -/* This is the layout on disk of the 32-bit or 64-bit exec header. */ - -#ifndef external_exec -struct external_exec -{ - bfd_byte e_info[4]; /* magic number and stuff */ - bfd_byte e_text[BYTES_IN_WORD]; /* length of text section in bytes */ - bfd_byte e_data[BYTES_IN_WORD]; /* length of data section in bytes */ - bfd_byte e_bss[BYTES_IN_WORD]; /* length of bss area in bytes */ - bfd_byte e_syms[BYTES_IN_WORD]; /* length of symbol table in bytes */ - bfd_byte e_entry[BYTES_IN_WORD]; /* start address */ - bfd_byte e_trsize[BYTES_IN_WORD]; /* length of text relocation info */ - bfd_byte e_drsize[BYTES_IN_WORD]; /* length of data relocation info */ -}; - -#define EXEC_BYTES_SIZE (4 + BYTES_IN_WORD * 7) - -/* Magic numbers for a.out files */ - -#if ARCH_SIZE==64 -#define OMAGIC 0x1001 /* Code indicating object file */ -#define ZMAGIC 0x1002 /* Code indicating demand-paged executable. */ -#define NMAGIC 0x1003 /* Code indicating pure executable. */ - -/* There is no 64-bit QMAGIC as far as I know. */ - -#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \ - && N_MAGIC(x) != NMAGIC \ - && N_MAGIC(x) != ZMAGIC) -#else -#define OMAGIC 0407 /* ...object file or impure executable. */ -#define NMAGIC 0410 /* Code indicating pure executable. */ -#define ZMAGIC 0413 /* Code indicating demand-paged executable. */ -#define BMAGIC 0415 /* Used by a b.out object. */ - -/* This indicates a demand-paged executable with the header in the text. - It is used by 386BSD (and variants) and Linux, at least. */ -#ifndef QMAGIC -#define QMAGIC 0314 -#endif -# ifndef N_BADMAG -# define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \ - && N_MAGIC(x) != NMAGIC \ - && N_MAGIC(x) != ZMAGIC \ - && N_MAGIC(x) != QMAGIC) -# endif /* N_BADMAG */ -#endif - -#endif - -#ifdef QMAGIC -#define N_IS_QMAGIC(x) (N_MAGIC (x) == QMAGIC) -#else -#define N_IS_QMAGIC(x) (0) -#endif - -/* The difference between TARGET_PAGE_SIZE and N_SEGSIZE is that TARGET_PAGE_SIZE is - the finest granularity at which you can page something, thus it - controls the padding (if any) before the text segment of a ZMAGIC - file. N_SEGSIZE is the resolution at which things can be marked as - read-only versus read/write, so it controls the padding between the - text segment and the data segment (in memory; on disk the padding - between them is TARGET_PAGE_SIZE). TARGET_PAGE_SIZE and N_SEGSIZE are the same - for most machines, but different for sun3. */ - -/* By default, segment size is constant. But some machines override this - to be a function of the a.out header (e.g. machine type). */ - -#ifndef N_SEGSIZE -#define N_SEGSIZE(x) SEGMENT_SIZE -#endif - -/* Virtual memory address of the text section. - This is getting very complicated. A good reason to discard a.out format - for something that specifies these fields explicitly. But til then... - - * OMAGIC and NMAGIC files: - (object files: text for "relocatable addr 0" right after the header) - start at 0, offset is EXEC_BYTES_SIZE, size as stated. - * The text address, offset, and size of ZMAGIC files depend - on the entry point of the file: - * entry point below TEXT_START_ADDR: - (hack for SunOS shared libraries) - start at 0, offset is 0, size as stated. - * If N_HEADER_IN_TEXT(x) is true (which defaults to being the - case when the entry point is EXEC_BYTES_SIZE or further into a page): - no padding is needed; text can start after exec header. Sun - considers the text segment of such files to include the exec header; - for BFD's purposes, we don't, which makes more work for us. - start at TEXT_START_ADDR + EXEC_BYTES_SIZE, offset is EXEC_BYTES_SIZE, - size as stated minus EXEC_BYTES_SIZE. - * If N_HEADER_IN_TEXT(x) is false (which defaults to being the case when - the entry point is less than EXEC_BYTES_SIZE into a page (e.g. page - aligned)): (padding is needed so that text can start at a page boundary) - start at TEXT_START_ADDR, offset TARGET_PAGE_SIZE, size as stated. - - Specific configurations may want to hardwire N_HEADER_IN_TEXT, - for efficiency or to allow people to play games with the entry point. - In that case, you would #define N_HEADER_IN_TEXT(x) as 1 for sunos, - and as 0 for most other hosts (Sony News, Vax Ultrix, etc). - (Do this in the appropriate bfd target file.) - (The default is a heuristic that will break if people try changing - the entry point, perhaps with the ld -e flag.) - - * QMAGIC is always like a ZMAGIC for which N_HEADER_IN_TEXT is true, - and for which the starting address is TARGET_PAGE_SIZE (or should this be - SEGMENT_SIZE?) (TEXT_START_ADDR only applies to ZMAGIC, not to QMAGIC). - */ - -/* This macro is only relevant for ZMAGIC files; QMAGIC always has the header - in the text. */ -#ifndef N_HEADER_IN_TEXT -#define N_HEADER_IN_TEXT(x) (((x).a_entry & (TARGET_PAGE_SIZE-1)) >= EXEC_BYTES_SIZE) -#endif - -/* Sun shared libraries, not linux. This macro is only relevant for ZMAGIC - files. */ -#ifndef N_SHARED_LIB -#define N_SHARED_LIB(x) ((x).a_entry < TEXT_START_ADDR) -#endif - -/* Returning 0 not TEXT_START_ADDR for OMAGIC and NMAGIC is based on - the assumption that we are dealing with a .o file, not an - executable. This is necessary for OMAGIC (but means we don't work - right on the output from ld -N); more questionable for NMAGIC. */ - -#ifndef N_TXTADDR -#define N_TXTADDR(x) \ - (/* The address of a QMAGIC file is always one page in, */ \ - /* with the header in the text. */ \ - N_IS_QMAGIC (x) ? TARGET_PAGE_SIZE + EXEC_BYTES_SIZE : \ - N_MAGIC(x) != ZMAGIC ? 0 : /* object file or NMAGIC */\ - N_SHARED_LIB(x) ? 0 : \ - N_HEADER_IN_TEXT(x) ? \ - TEXT_START_ADDR + EXEC_BYTES_SIZE : /* no padding */\ - TEXT_START_ADDR /* a page of padding */\ - ) -#endif - -/* If N_HEADER_IN_TEXT is not true for ZMAGIC, there is some padding - to make the text segment start at a certain boundary. For most - systems, this boundary is TARGET_PAGE_SIZE. But for Linux, in the - time-honored tradition of crazy ZMAGIC hacks, it is 1024 which is - not what TARGET_PAGE_SIZE needs to be for QMAGIC. */ - -#ifndef ZMAGIC_DISK_BLOCK_SIZE -#define ZMAGIC_DISK_BLOCK_SIZE TARGET_PAGE_SIZE -#endif - -#define N_DISK_BLOCK_SIZE(x) \ - (N_MAGIC(x) == ZMAGIC ? ZMAGIC_DISK_BLOCK_SIZE : TARGET_PAGE_SIZE) - -/* Offset in an a.out of the start of the text section. */ -#ifndef N_TXTOFF -#define N_TXTOFF(x) \ - (/* For {O,N,Q}MAGIC, no padding. */ \ - N_MAGIC(x) != ZMAGIC ? EXEC_BYTES_SIZE : \ - N_SHARED_LIB(x) ? 0 : \ - N_HEADER_IN_TEXT(x) ? \ - EXEC_BYTES_SIZE : /* no padding */\ - ZMAGIC_DISK_BLOCK_SIZE /* a page of padding */\ - ) -#endif -/* Size of the text section. It's always as stated, except that we - offset it to `undo' the adjustment to N_TXTADDR and N_TXTOFF - for ZMAGIC files that nominally include the exec header - as part of the first page of text. (BFD doesn't consider the - exec header to be part of the text segment.) */ -#ifndef N_TXTSIZE -#define N_TXTSIZE(x) \ - (/* For QMAGIC, we don't consider the header part of the text section. */\ - N_IS_QMAGIC (x) ? (x).a_text - EXEC_BYTES_SIZE : \ - (N_MAGIC(x) != ZMAGIC || N_SHARED_LIB(x)) ? (x).a_text : \ - N_HEADER_IN_TEXT(x) ? \ - (x).a_text - EXEC_BYTES_SIZE: /* no padding */\ - (x).a_text /* a page of padding */\ - ) -#endif -/* The address of the data segment in virtual memory. - It is the text segment address, plus text segment size, rounded - up to a N_SEGSIZE boundary for pure or pageable files. */ -#ifndef N_DATADDR -#define N_DATADDR(x) \ - (N_MAGIC(x)==OMAGIC? (N_TXTADDR(x)+N_TXTSIZE(x)) \ - : (N_SEGSIZE(x) + ((N_TXTADDR(x)+N_TXTSIZE(x)-1) & ~(N_SEGSIZE(x)-1)))) -#endif -/* The address of the BSS segment -- immediately after the data segment. */ - -#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data) - -/* Offsets of the various portions of the file after the text segment. */ - -/* For {Q,Z}MAGIC, there is padding to make the data segment start on - a page boundary. Most of the time the a_text field (and thus - N_TXTSIZE) already contains this padding. It is possible that for - BSDI and/or 386BSD it sometimes doesn't contain the padding, and - perhaps we should be adding it here. But this seems kind of - questionable and probably should be BSDI/386BSD-specific if we do - do it. - - For NMAGIC (at least for hp300 BSD, probably others), there is - padding in memory only, not on disk, so we must *not* ever pad here - for NMAGIC. */ - -#ifndef N_DATOFF -#define N_DATOFF(x) \ - (N_TXTOFF(x) + N_TXTSIZE(x)) -#endif - -#ifndef N_TRELOFF -#define N_TRELOFF(x) ( N_DATOFF(x) + (x).a_data ) -#endif -#ifndef N_DRELOFF -#define N_DRELOFF(x) ( N_TRELOFF(x) + (x).a_trsize ) -#endif -#ifndef N_SYMOFF -#define N_SYMOFF(x) ( N_DRELOFF(x) + (x).a_drsize ) -#endif -#ifndef N_STROFF -#define N_STROFF(x) ( N_SYMOFF(x) + (x).a_syms ) -#endif - -/* Symbols */ -#ifndef external_nlist -struct external_nlist { - bfd_byte e_strx[BYTES_IN_WORD]; /* index into string table of name */ - bfd_byte e_type[1]; /* type of symbol */ - bfd_byte e_other[1]; /* misc info (usually empty) */ - bfd_byte e_desc[2]; /* description field */ - bfd_byte e_value[BYTES_IN_WORD]; /* value of symbol */ -}; -#define EXTERNAL_NLIST_SIZE (BYTES_IN_WORD+4+BYTES_IN_WORD) -#endif - -struct internal_nlist { - unsigned long n_strx; /* index into string table of name */ - unsigned char n_type; /* type of symbol */ - unsigned char n_other; /* misc info (usually empty) */ - unsigned short n_desc; /* description field */ - bfd_vma n_value; /* value of symbol */ -}; - -/* The n_type field is the symbol type, containing: */ - -#define N_UNDF 0 /* Undefined symbol */ -#define N_ABS 2 /* Absolute symbol -- defined at particular addr */ -#define N_TEXT 4 /* Text sym -- defined at offset in text seg */ -#define N_DATA 6 /* Data sym -- defined at offset in data seg */ -#define N_BSS 8 /* BSS sym -- defined at offset in zero'd seg */ -#define N_COMM 0x12 /* Common symbol (visible after shared lib dynlink) */ -#define N_FN 0x1f /* File name of .o file */ -#define N_FN_SEQ 0x0C /* N_FN from Sequent compilers (sigh) */ -/* Note: N_EXT can only be usefully OR-ed with N_UNDF, N_ABS, N_TEXT, - N_DATA, or N_BSS. When the low-order bit of other types is set, - (e.g. N_WARNING versus N_FN), they are two different types. */ -#define N_EXT 1 /* External symbol (as opposed to local-to-this-file) */ -#define N_TYPE 0x1e -#define N_STAB 0xe0 /* If any of these bits are on, it's a debug symbol */ - -#define N_INDR 0x0a - -/* The following symbols refer to set elements. - All the N_SET[ATDB] symbols with the same name form one set. - Space is allocated for the set in the text section, and each set - elements value is stored into one word of the space. - The first word of the space is the length of the set (number of elements). - - The address of the set is made into an N_SETV symbol - whose name is the same as the name of the set. - This symbol acts like a N_DATA global symbol - in that it can satisfy undefined external references. */ - -/* These appear as input to LD, in a .o file. */ -#define N_SETA 0x14 /* Absolute set element symbol */ -#define N_SETT 0x16 /* Text set element symbol */ -#define N_SETD 0x18 /* Data set element symbol */ -#define N_SETB 0x1A /* Bss set element symbol */ - -/* This is output from LD. */ -#define N_SETV 0x1C /* Pointer to set vector in data area. */ - -/* Warning symbol. The text gives a warning message, the next symbol - in the table will be undefined. When the symbol is referenced, the - message is printed. */ - -#define N_WARNING 0x1e - -/* Weak symbols. These are a GNU extension to the a.out format. The - semantics are those of ELF weak symbols. Weak symbols are always - externally visible. The N_WEAK? values are squeezed into the - available slots. The value of a N_WEAKU symbol is 0. The values - of the other types are the definitions. */ -#define N_WEAKU 0x0d /* Weak undefined symbol. */ -#define N_WEAKA 0x0e /* Weak absolute symbol. */ -#define N_WEAKT 0x0f /* Weak text symbol. */ -#define N_WEAKD 0x10 /* Weak data symbol. */ -#define N_WEAKB 0x11 /* Weak bss symbol. */ - -/* Relocations - - There are two types of relocation flavours for a.out systems, - standard and extended. The standard form is used on systems where the - instruction has room for all the bits of an offset to the operand, whilst - the extended form is used when an address operand has to be split over n - instructions. Eg, on the 68k, each move instruction can reference - the target with a displacement of 16 or 32 bits. On the sparc, move - instructions use an offset of 14 bits, so the offset is stored in - the reloc field, and the data in the section is ignored. -*/ - -/* This structure describes a single relocation to be performed. - The text-relocation section of the file is a vector of these structures, - all of which apply to the text section. - Likewise, the data-relocation section applies to the data section. */ - -struct reloc_std_external { - bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */ - bfd_byte r_index[3]; /* symbol table index of symbol */ - bfd_byte r_type[1]; /* relocation type */ -}; - -#define RELOC_STD_BITS_PCREL_BIG ((unsigned int) 0x80) -#define RELOC_STD_BITS_PCREL_LITTLE ((unsigned int) 0x01) - -#define RELOC_STD_BITS_LENGTH_BIG ((unsigned int) 0x60) -#define RELOC_STD_BITS_LENGTH_SH_BIG 5 -#define RELOC_STD_BITS_LENGTH_LITTLE ((unsigned int) 0x06) -#define RELOC_STD_BITS_LENGTH_SH_LITTLE 1 - -#define RELOC_STD_BITS_EXTERN_BIG ((unsigned int) 0x10) -#define RELOC_STD_BITS_EXTERN_LITTLE ((unsigned int) 0x08) - -#define RELOC_STD_BITS_BASEREL_BIG ((unsigned int) 0x08) -#define RELOC_STD_BITS_BASEREL_LITTLE ((unsigned int) 0x10) - -#define RELOC_STD_BITS_JMPTABLE_BIG ((unsigned int) 0x04) -#define RELOC_STD_BITS_JMPTABLE_LITTLE ((unsigned int) 0x20) - -#define RELOC_STD_BITS_RELATIVE_BIG ((unsigned int) 0x02) -#define RELOC_STD_BITS_RELATIVE_LITTLE ((unsigned int) 0x40) - -#define RELOC_STD_SIZE (BYTES_IN_WORD + 3 + 1) /* Bytes per relocation entry */ - -struct reloc_std_internal -{ - bfd_vma r_address; /* Address (within segment) to be relocated. */ - /* The meaning of r_symbolnum depends on r_extern. */ - unsigned int r_symbolnum:24; - /* Nonzero means value is a pc-relative offset - and it should be relocated for changes in its own address - as well as for changes in the symbol or section specified. */ - unsigned int r_pcrel:1; - /* Length (as exponent of 2) of the field to be relocated. - Thus, a value of 2 indicates 1<<2 bytes. */ - unsigned int r_length:2; - /* 1 => relocate with value of symbol. - r_symbolnum is the index of the symbol - in files the symbol table. - 0 => relocate with the address of a segment. - r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS - (the N_EXT bit may be set also, but signifies nothing). */ - unsigned int r_extern:1; - /* The next three bits are for SunOS shared libraries, and seem to - be undocumented. */ - unsigned int r_baserel:1; /* Linkage table relative */ - unsigned int r_jmptable:1; /* pc-relative to jump table */ - unsigned int r_relative:1; /* "relative relocation" */ - /* unused */ - unsigned int r_pad:1; /* Padding -- set to zero */ -}; - - -/* EXTENDED RELOCS */ - -struct reloc_ext_external { - bfd_byte r_address[BYTES_IN_WORD]; /* offset of of data to relocate */ - bfd_byte r_index[3]; /* symbol table index of symbol */ - bfd_byte r_type[1]; /* relocation type */ - bfd_byte r_addend[BYTES_IN_WORD]; /* datum addend */ -}; - -#define RELOC_EXT_BITS_EXTERN_BIG ((unsigned int) 0x80) -#define RELOC_EXT_BITS_EXTERN_LITTLE ((unsigned int) 0x01) - -#define RELOC_EXT_BITS_TYPE_BIG ((unsigned int) 0x1F) -#define RELOC_EXT_BITS_TYPE_SH_BIG 0 -#define RELOC_EXT_BITS_TYPE_LITTLE ((unsigned int) 0xF8) -#define RELOC_EXT_BITS_TYPE_SH_LITTLE 3 - -/* Bytes per relocation entry */ -#define RELOC_EXT_SIZE (BYTES_IN_WORD + 3 + 1 + BYTES_IN_WORD) - -enum reloc_type -{ - /* simple relocations */ - RELOC_8, /* data[0:7] = addend + sv */ - RELOC_16, /* data[0:15] = addend + sv */ - RELOC_32, /* data[0:31] = addend + sv */ - /* pc-rel displacement */ - RELOC_DISP8, /* data[0:7] = addend - pc + sv */ - RELOC_DISP16, /* data[0:15] = addend - pc + sv */ - RELOC_DISP32, /* data[0:31] = addend - pc + sv */ - /* Special */ - RELOC_WDISP30, /* data[0:29] = (addend + sv - pc)>>2 */ - RELOC_WDISP22, /* data[0:21] = (addend + sv - pc)>>2 */ - RELOC_HI22, /* data[0:21] = (addend + sv)>>10 */ - RELOC_22, /* data[0:21] = (addend + sv) */ - RELOC_13, /* data[0:12] = (addend + sv) */ - RELOC_LO10, /* data[0:9] = (addend + sv) */ - RELOC_SFA_BASE, - RELOC_SFA_OFF13, - /* P.I.C. (base-relative) */ - RELOC_BASE10, /* Not sure - maybe we can do this the */ - RELOC_BASE13, /* right way now */ - RELOC_BASE22, - /* for some sort of pc-rel P.I.C. (?) */ - RELOC_PC10, - RELOC_PC22, - /* P.I.C. jump table */ - RELOC_JMP_TBL, - /* reputedly for shared libraries somehow */ - RELOC_SEGOFF16, - RELOC_GLOB_DAT, - RELOC_JMP_SLOT, - RELOC_RELATIVE, - - RELOC_11, - RELOC_WDISP2_14, - RELOC_WDISP19, - RELOC_HHI22, /* data[0:21] = (addend + sv) >> 42 */ - RELOC_HLO10, /* data[0:9] = (addend + sv) >> 32 */ - - /* 29K relocation types */ - RELOC_JUMPTARG, - RELOC_CONST, - RELOC_CONSTH, - - /* All the new ones I can think of, for sparc v9 */ - - RELOC_64, /* data[0:63] = addend + sv */ - RELOC_DISP64, /* data[0:63] = addend - pc + sv */ - RELOC_WDISP21, /* data[0:20] = (addend + sv - pc)>>2 */ - RELOC_DISP21, /* data[0:20] = addend - pc + sv */ - RELOC_DISP14, /* data[0:13] = addend - pc + sv */ - /* Q . - What are the other ones, - Since this is a clean slate, can we throw away the ones we dont - understand ? Should we sort the values ? What about using a - microcode format like the 68k ? - */ - NO_RELOC - }; - - -struct reloc_internal { - bfd_vma r_address; /* offset of of data to relocate */ - long r_index; /* symbol table index of symbol */ - enum reloc_type r_type; /* relocation type */ - bfd_vma r_addend; /* datum addend */ -}; - -/* Q. - Should the length of the string table be 4 bytes or 8 bytes ? - - Q. - What about archive indexes ? - - */ - -#endif /* __A_OUT_64_H__ */ diff --git a/pstack/aout/stab.def b/pstack/aout/stab.def deleted file mode 100644 index 3c6b456d3a9..00000000000 --- a/pstack/aout/stab.def +++ /dev/null @@ -1,264 +0,0 @@ -/* Table of DBX symbol codes for the GNU system. - Copyright (C) 1988, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. - -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; either version 2 of the License, or -(at your option) any later version. - -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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* New stab from Solaris 2. This uses an n_type of 0, which in a.out files - overlaps the N_UNDF used for ordinary symbols. In ELF files, the - debug information is in a different file section, so there is no conflict. - This symbol's n_value gives the size of the string section associated - with this file. The symbol's n_strx (relative to the just-updated - string section start address) gives the name of the source file, - e.g. "foo.c", without any path information. The symbol's n_desc gives - the count of upcoming symbols associated with this file (not including - this one). */ -/* __define_stab (N_UNDF, 0x00, "UNDF") */ - -/* Global variable. Only the name is significant. - To find the address, look in the corresponding external symbol. */ -__define_stab (N_GSYM, 0x20, "GSYM") - -/* Function name for BSD Fortran. Only the name is significant. - To find the address, look in the corresponding external symbol. */ -__define_stab (N_FNAME, 0x22, "FNAME") - -/* Function name or text-segment variable for C. Value is its address. - Desc is supposedly starting line number, but GCC doesn't set it - and DBX seems not to miss it. */ -__define_stab (N_FUN, 0x24, "FUN") - -/* Data-segment variable with internal linkage. Value is its address. - "Static Sym". */ -__define_stab (N_STSYM, 0x26, "STSYM") - -/* BSS-segment variable with internal linkage. Value is its address. */ -__define_stab (N_LCSYM, 0x28, "LCSYM") - -/* Name of main routine. Only the name is significant. */ -__define_stab (N_MAIN, 0x2a, "MAIN") - -/* Solaris2: Read-only data symbols. */ -__define_stab (N_ROSYM, 0x2c, "ROSYM") - -/* Global symbol in Pascal. - Supposedly the value is its line number; I'm skeptical. */ -__define_stab (N_PC, 0x30, "PC") - -/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */ -__define_stab (N_NSYMS, 0x32, "NSYMS") - -/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */ -__define_stab (N_NOMAP, 0x34, "NOMAP") - -/* New stab from Solaris 2. Like N_SO, but for the object file. Two in - a row provide the build directory and the relative path of the .o from it. - Solaris2 uses this to avoid putting the stabs info into the linked - executable; this stab goes into the ".stab.index" section, and the debugger - reads the real stabs directly from the .o files instead. */ -__define_stab (N_OBJ, 0x38, "OBJ") - -/* New stab from Solaris 2. Options for the debugger, related to the - source language for this module. E.g. whether to use ANSI - integral promotions or traditional integral promotions. */ -__define_stab (N_OPT, 0x3c, "OPT") - -/* Register variable. Value is number of register. */ -__define_stab (N_RSYM, 0x40, "RSYM") - -/* Modula-2 compilation unit. Can someone say what info it contains? */ -__define_stab (N_M2C, 0x42, "M2C") - -/* Line number in text segment. Desc is the line number; - value is corresponding address. On Solaris2, the line number is - relative to the start of the current function. */ -__define_stab (N_SLINE, 0x44, "SLINE") - -/* Similar, for data segment. */ -__define_stab (N_DSLINE, 0x46, "DSLINE") - -/* Similar, for bss segment. */ -__define_stab (N_BSLINE, 0x48, "BSLINE") - -/* Sun's source-code browser stabs. ?? Don't know what the fields are. - Supposedly the field is "path to associated .cb file". THIS VALUE - OVERLAPS WITH N_BSLINE! */ -__define_stab_duplicate (N_BROWS, 0x48, "BROWS") - -/* GNU Modula-2 definition module dependency. Value is the modification time - of the definition file. Other is non-zero if it is imported with the - GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there - are enough empty fields? */ -__define_stab(N_DEFD, 0x4a, "DEFD") - -/* New in Solaris2. Function start/body/end line numbers. */ -__define_stab(N_FLINE, 0x4C, "FLINE") - -/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2 - and one is for C++. Still,... */ -/* GNU C++ exception variable. Name is variable name. */ -__define_stab (N_EHDECL, 0x50, "EHDECL") -/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */ -__define_stab_duplicate (N_MOD2, 0x50, "MOD2") - -/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if - this entry is immediately followed by a CAUGHT stab saying what exception - was caught. Multiple CAUGHT stabs means that multiple exceptions - can be caught here. If Desc is 0, it means all exceptions are caught - here. */ -__define_stab (N_CATCH, 0x54, "CATCH") - -/* Structure or union element. Value is offset in the structure. */ -__define_stab (N_SSYM, 0x60, "SSYM") - -/* Solaris2: Last stab emitted for module. */ -__define_stab (N_ENDM, 0x62, "ENDM") - -/* Name of main source file. - Value is starting text address of the compilation. - If multiple N_SO's appear, the first to contain a trailing / is the - compilation directory. The first to not contain a trailing / is the - source file name, relative to the compilation directory. Others (perhaps - resulting from cfront) are ignored. - On Solaris2, value is undefined, but desc is a source-language code. */ - -__define_stab (N_SO, 0x64, "SO") - -/* Automatic variable in the stack. Value is offset from frame pointer. - Also used for type descriptions. */ -__define_stab (N_LSYM, 0x80, "LSYM") - -/* Beginning of an include file. Only Sun uses this. - In an object file, only the name is significant. - The Sun linker puts data into some of the other fields. */ -__define_stab (N_BINCL, 0x82, "BINCL") - -/* Name of sub-source file (#include file). - Value is starting text address of the compilation. */ -__define_stab (N_SOL, 0x84, "SOL") - -/* Parameter variable. Value is offset from argument pointer. - (On most machines the argument pointer is the same as the frame pointer. */ -__define_stab (N_PSYM, 0xa0, "PSYM") - -/* End of an include file. No name. - This and N_BINCL act as brackets around the file's output. - In an object file, there is no significant data in this entry. - The Sun linker puts data into some of the fields. */ -__define_stab (N_EINCL, 0xa2, "EINCL") - -/* Alternate entry point. Value is its address. */ -__define_stab (N_ENTRY, 0xa4, "ENTRY") - -/* Beginning of lexical block. - The desc is the nesting level in lexical blocks. - The value is the address of the start of the text for the block. - The variables declared inside the block *precede* the N_LBRAC symbol. - On Solaris2, the value is relative to the start of the current function. */ -__define_stab (N_LBRAC, 0xc0, "LBRAC") - -/* Place holder for deleted include file. Replaces a N_BINCL and everything - up to the corresponding N_EINCL. The Sun linker generates these when - it finds multiple identical copies of the symbols from an include file. - This appears only in output from the Sun linker. */ -__define_stab (N_EXCL, 0xc2, "EXCL") - -/* Modula-2 scope information. Can someone say what info it contains? */ -__define_stab (N_SCOPE, 0xc4, "SCOPE") - -/* End of a lexical block. Desc matches the N_LBRAC's desc. - The value is the address of the end of the text for the block. - On Solaris2, the value is relative to the start of the current function. */ -__define_stab (N_RBRAC, 0xe0, "RBRAC") - -/* Begin named common block. Only the name is significant. */ -__define_stab (N_BCOMM, 0xe2, "BCOMM") - -/* End named common block. Only the name is significant - (and it should match the N_BCOMM). */ -__define_stab (N_ECOMM, 0xe4, "ECOMM") - -/* Member of a common block; value is offset within the common block. - This should occur within a BCOMM/ECOMM pair. */ -__define_stab (N_ECOML, 0xe8, "ECOML") - -/* Solaris2: Pascal "with" statement: type,,0,0,offset */ -__define_stab (N_WITH, 0xea, "WITH") - -/* These STAB's are used on Gould systems for Non-Base register symbols - or something like that. FIXME. I have assigned the values at random - since I don't have a Gould here. Fixups from Gould folk welcome... */ -__define_stab (N_NBTEXT, 0xF0, "NBTEXT") -__define_stab (N_NBDATA, 0xF2, "NBDATA") -__define_stab (N_NBBSS, 0xF4, "NBBSS") -__define_stab (N_NBSTS, 0xF6, "NBSTS") -__define_stab (N_NBLCS, 0xF8, "NBLCS") - -/* Second symbol entry containing a length-value for the preceding entry. - The value is the length. */ -__define_stab (N_LENG, 0xfe, "LENG") - -/* The above information, in matrix format. - - STAB MATRIX - _________________________________________________ - | 00 - 1F are not dbx stab symbols | - | In most cases, the low bit is the EXTernal bit| - - | 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA | - | 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT | - - | 08 BSS | 0A INDR | 0C FN_SEQ | 0E WEAKA | - | 09 |EXT | 0B | 0D WEAKU | 0F WEAKT | - - | 10 WEAKD | 12 COMM | 14 SETA | 16 SETT | - | 11 WEAKB | 13 | 15 | 17 | - - | 18 SETD | 1A SETB | 1C SETV | 1E WARNING| - | 19 | 1B | 1D | 1F FN | - - |_______________________________________________| - | Debug entries with bit 01 set are unused. | - | 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM | - | 28 LCSYM | 2A MAIN | 2C ROSYM | 2E | - | 30 PC | 32 NSYMS | 34 NOMAP | 36 | - | 38 OBJ | 3A | 3C OPT | 3E | - | 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE | - | 48 BSLINE*| 4A DEFD | 4C FLINE | 4E | - | 50 EHDECL*| 52 | 54 CATCH | 56 | - | 58 | 5A | 5C | 5E | - | 60 SSYM | 62 ENDM | 64 SO | 66 | - | 68 | 6A | 6C | 6E | - | 70 | 72 | 74 | 76 | - | 78 | 7A | 7C | 7E | - | 80 LSYM | 82 BINCL | 84 SOL | 86 | - | 88 | 8A | 8C | 8E | - | 90 | 92 | 94 | 96 | - | 98 | 9A | 9C | 9E | - | A0 PSYM | A2 EINCL | A4 ENTRY | A6 | - | A8 | AA | AC | AE | - | B0 | B2 | B4 | B6 | - | B8 | BA | BC | BE | - | C0 LBRAC | C2 EXCL | C4 SCOPE | C6 | - | C8 | CA | CC | CE | - | D0 | D2 | D4 | D6 | - | D8 | DA | DC | DE | - | E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 | - | E8 ECOML | EA WITH | EC | EE | - | F0 | F2 | F4 | F6 | - | F8 | FA | FC | FE LENG | - +-----------------------------------------------+ - * 50 EHDECL is also MOD2. - * 48 BSLINE is also BROWS. - */ diff --git a/pstack/aout/stab_gnu.h b/pstack/aout/stab_gnu.h deleted file mode 100644 index 7d18e14a263..00000000000 --- a/pstack/aout/stab_gnu.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __GNU_STAB__ - -/* Indicate the GNU stab.h is in use. */ - -#define __GNU_STAB__ - -#define __define_stab(NAME, CODE, STRING) NAME=CODE, -#define __define_stab_duplicate(NAME, CODE, STRING) NAME=CODE, - -enum __stab_debug_code -{ -#include "aout/stab.def" -LAST_UNUSED_STAB_CODE -}; - -#undef __define_stab - -/* Definitions of "desc" field for N_SO stabs in Solaris2. */ - -#define N_SO_AS 1 -#define N_SO_C 2 -#define N_SO_ANSI_C 3 -#define N_SO_CC 4 /* C++ */ -#define N_SO_FORTRAN 5 -#define N_SO_PASCAL 6 - -/* Solaris2: Floating point type values in basic types. */ - -#define NF_NONE 0 -#define NF_SINGLE 1 /* IEEE 32-bit */ -#define NF_DOUBLE 2 /* IEEE 64-bit */ -#define NF_COMPLEX 3 /* Fortran complex */ -#define NF_COMPLEX16 4 /* Fortran double complex */ -#define NF_COMPLEX32 5 /* Fortran complex*16 */ -#define NF_LDOUBLE 6 /* Long double (whatever that is) */ - -#endif /* __GNU_STAB_ */ diff --git a/pstack/bucomm.c b/pstack/bucomm.c deleted file mode 100644 index d3231e71747..00000000000 --- a/pstack/bucomm.c +++ /dev/null @@ -1,238 +0,0 @@ -/* bucomm.c -- Bin Utils COMmon code. - Copyright (C) 1991, 92, 93, 94, 95, 1997 Free Software Foundation, Inc. - - This file is part of GNU Binutils. - - 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; either version 2 of the License, or - (at your option) any later version. - - 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., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ - -/* We might put this in a library someday so it could be dynamically - loaded, but for now it's not necessary. */ - -#include -#include -#include "bucomm.h" - -#include -#include /* ctime, maybe time_t */ - -#ifdef ANSI_PROTOTYPES -#include -#else -#include -#endif - -/* Error reporting */ - -char *program_name; - -void -bfd_nonfatal (string) - CONST char *string; -{ - CONST char *errmsg = bfd_errmsg (bfd_get_error ()); - - if (string) - fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg); - else - fprintf (stderr, "%s: %s\n", program_name, errmsg); -} - -void -bfd_fatal (string) - CONST char *string; -{ - bfd_nonfatal (string); - xexit (1); -} - -#ifdef ANSI_PROTOTYPES -void -fatal (const char *format, ...) -{ - va_list args; - - fprintf (stderr, "%s: ", program_name); - va_start (args, format); - vfprintf (stderr, format, args); - va_end (args); - putc ('\n', stderr); - xexit (1); -} -#else -void -fatal (va_alist) - va_dcl -{ - char *Format; - va_list args; - - fprintf (stderr, "%s: ", program_name); - va_start (args); - Format = va_arg (args, char *); - vfprintf (stderr, Format, args); - va_end (args); - putc ('\n', stderr); - xexit (1); -} -#endif - -/* Set the default BFD target based on the configured target. Doing - this permits the binutils to be configured for a particular target, - and linked against a shared BFD library which was configured for a - different target. */ - -#define TARGET "elf32-i386" /* FIXME: hard-coded! */ -void -set_default_bfd_target () -{ - /* The macro TARGET is defined by Makefile. */ - const char *target = TARGET; - - if (! bfd_set_default_target (target)) - { - char *errmsg; - - errmsg = (char *) xmalloc (100 + strlen (target)); - sprintf (errmsg, "can't set BFD default target to `%s'", target); - bfd_fatal (errmsg); - } -} - -/* After a false return from bfd_check_format_matches with - bfd_get_error () == bfd_error_file_ambiguously_recognized, print - the possible matching targets. */ - -void -list_matching_formats (p) - char **p; -{ - fprintf(stderr, "%s: Matching formats:", program_name); - while (*p) - fprintf(stderr, " %s", *p++); - fprintf(stderr, "\n"); -} - -/* List the supported targets. */ - -void -list_supported_targets (name, f) - const char *name; - FILE *f; -{ - extern bfd_target *bfd_target_vector[]; - int t; - - if (name == NULL) - fprintf (f, "Supported targets:"); - else - fprintf (f, "%s: supported targets:", name); - for (t = 0; bfd_target_vector[t] != NULL; t++) - fprintf (f, " %s", bfd_target_vector[t]->name); - fprintf (f, "\n"); -} - -/* Display the archive header for an element as if it were an ls -l listing: - - Mode User\tGroup\tSize\tDate Name */ - -void -print_arelt_descr (file, abfd, verbose) - FILE *file; - bfd *abfd; - boolean verbose; -{ - struct stat buf; - - if (verbose) - { - if (bfd_stat_arch_elt (abfd, &buf) == 0) - { - char modebuf[11]; - char timebuf[40]; - time_t when = buf.st_mtime; - CONST char *ctime_result = (CONST char *) ctime (&when); - - /* POSIX format: skip weekday and seconds from ctime output. */ - sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20); - - mode_string (buf.st_mode, modebuf); - modebuf[10] = '\0'; - /* POSIX 1003.2/D11 says to skip first character (entry type). */ - fprintf (file, "%s %ld/%ld %6ld %s ", modebuf + 1, - (long) buf.st_uid, (long) buf.st_gid, - (long) buf.st_size, timebuf); - } - } - - fprintf (file, "%s\n", bfd_get_filename (abfd)); -} - -/* Return the name of a temporary file in the same directory as FILENAME. */ - -char * -make_tempname (filename) - char *filename; -{ - static char template[] = "stXXXXXX"; - char *tmpname; - char *slash = strrchr (filename, '/'); - -#if defined (__DJGPP__) || defined (__GO32__) || defined (_WIN32) - if (slash == NULL) - slash = strrchr (filename, '\\'); -#endif - - if (slash != (char *) NULL) - { - char c; - - c = *slash; - *slash = 0; - tmpname = xmalloc (strlen (filename) + sizeof (template) + 1); - strcpy (tmpname, filename); - strcat (tmpname, "/"); - strcat (tmpname, template); - mkstemp (tmpname); - *slash = c; - } - else - { - tmpname = xmalloc (sizeof (template)); - strcpy (tmpname, template); - mkstemp (tmpname); - } - return tmpname; -} - -/* Parse a string into a VMA, with a fatal error if it can't be - parsed. */ - -bfd_vma -parse_vma (s, arg) - const char *s; - const char *arg; -{ - bfd_vma ret; - const char *end; - - ret = bfd_scan_vma (s, &end, 0); - if (*end != '\0') - { - fprintf (stderr, "%s: %s: bad number: %s\n", program_name, arg, s); - exit (1); - } - return ret; -} diff --git a/pstack/bucomm.h b/pstack/bucomm.h deleted file mode 100644 index 6b3633d8d63..00000000000 --- a/pstack/bucomm.h +++ /dev/null @@ -1,91 +0,0 @@ -/* bucomm.h -- binutils common include file. - Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. - -This file is part of GNU Binutils. - -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; either version 2 of the License, or -(at your option) any later version. - -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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifndef _BUCOMM_H -#define _BUCOMM_H - -#include "ansidecl.h" -#include -#include - -#include -#include - -#include - -#include - -#include - -#ifdef __GNUC__ -# undef alloca -# define alloca __builtin_alloca -#else -# if HAVE_ALLOCA_H -# include -# else -# ifndef alloca /* predefined by HP cc +Olibcalls */ -# if !defined (__STDC__) && !defined (__hpux) -char *alloca (); -# else -void *alloca (); -# endif /* __STDC__, __hpux */ -# endif /* alloca */ -# endif /* HAVE_ALLOCA_H */ -#endif - -#ifndef BFD_TRUE_FALSE -#define boolean bfd_boolean -#define true TRUE -#define false FALSE -#endif - -/* bucomm.c */ -void bfd_nonfatal PARAMS ((CONST char *)); - -void bfd_fatal PARAMS ((CONST char *)); - -void fatal PARAMS ((CONST char *, ...)); - -void set_default_bfd_target PARAMS ((void)); - -void list_matching_formats PARAMS ((char **p)); - -void list_supported_targets PARAMS ((const char *, FILE *)); - -void print_arelt_descr PARAMS ((FILE *file, bfd *abfd, boolean verbose)); - -char *make_tempname PARAMS ((char *)); - -bfd_vma parse_vma PARAMS ((const char *, const char *)); - -extern char *program_name; - -/* filemode.c */ -void mode_string PARAMS ((unsigned long mode, char *buf)); - -/* version.c */ -extern void print_version PARAMS ((const char *)); - -/* libiberty */ -PTR xmalloc PARAMS ((size_t)); - -PTR xrealloc PARAMS ((PTR, size_t)); - -#endif /* _BUCOMM_H */ diff --git a/pstack/budbg.h b/pstack/budbg.h deleted file mode 100644 index 9f0203ad5e7..00000000000 --- a/pstack/budbg.h +++ /dev/null @@ -1,64 +0,0 @@ -/* budbg.c -- Interfaces to the generic debugging information routines. - Copyright (C) 1995, 1996 Free Software Foundation, Inc. - Written by Ian Lance Taylor . - - This file is part of GNU Binutils. - - 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; either version 2 of the License, or - (at your option) any later version. - - 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., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ - -#ifndef BUDBG_H -#define BUDBG_H - -#include - -#ifndef BFD_TRUE_FALSE -#define boolean bfd_boolean -#define true TRUE -#define false FALSE -#endif - -/* Routine used to read generic debugging information. */ - -extern PTR read_debugging_info PARAMS ((bfd *, asymbol **, long)); - -/* Routine used to print generic debugging information. */ - -extern boolean print_debugging_info PARAMS ((FILE *, PTR)); - -/* Routines used to read and write stabs information. */ - -extern PTR start_stab PARAMS ((PTR, bfd *, boolean, asymbol **, long)); - -extern boolean finish_stab PARAMS ((PTR, PTR)); - -extern boolean parse_stab PARAMS ((PTR, PTR, int, int, bfd_vma, const char *)); - -extern boolean write_stabs_in_sections_debugging_info - PARAMS ((bfd *, PTR, bfd_byte **, bfd_size_type *, bfd_byte **, - bfd_size_type *)); - -/* Routines used to read and write IEEE debugging information. */ - -extern boolean parse_ieee - PARAMS ((PTR, bfd *, const bfd_byte *, bfd_size_type)); - -extern boolean write_ieee_debugging_info PARAMS ((bfd *, PTR)); - -/* Routine used to read COFF debugging information. */ - -extern boolean parse_coff PARAMS ((bfd *, asymbol **, long, PTR)); - -#endif diff --git a/pstack/debug.c b/pstack/debug.c deleted file mode 100644 index 73412ae3f03..00000000000 --- a/pstack/debug.c +++ /dev/null @@ -1,3509 +0,0 @@ -/* debug.c -- Handle generic debugging information. - Copyright (C) 1995, 1996 Free Software Foundation, Inc. - Written by Ian Lance Taylor . - - This file is part of GNU Binutils. - - 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; either version 2 of the License, or - (at your option) any later version. - - 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., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ - -/* This file implements a generic debugging format. We may eventually - have readers which convert different formats into this generic - format, and writers which write it out. The initial impetus for - this was writing a convertor from stabs to HP IEEE-695 debugging - format. */ - -#include -#include - -#include -#include "bucomm.h" -#include -#include "debug.h" - -/* Global information we keep for debugging. A pointer to this - structure is the debugging handle passed to all the routines. */ - -struct debug_handle -{ - /* A linked list of compilation units. */ - struct debug_unit *units; - /* The current compilation unit. */ - struct debug_unit *current_unit; - /* The current source file. */ - struct debug_file *current_file; - /* The current function. */ - struct debug_function *current_function; - /* The current block. */ - struct debug_block *current_block; - /* The current line number information for the current unit. */ - struct debug_lineno *current_lineno; - /* Mark. This is used by debug_write. */ - unsigned int mark; - /* A struct/class ID used by debug_write. */ - unsigned int class_id; - /* The base for class_id for this call to debug_write. */ - unsigned int base_id; - /* The current line number in debug_write. */ - struct debug_lineno *current_write_lineno; - unsigned int current_write_lineno_index; - /* A list of classes which have assigned ID's during debug_write. - This is linked through the next_id field of debug_class_type. */ - struct debug_class_id *id_list; - /* A list used to avoid recursion during debug_type_samep. */ - struct debug_type_compare_list *compare_list; -}; - -/* Information we keep for a single compilation unit. */ - -struct debug_unit -{ - /* The next compilation unit. */ - struct debug_unit *next; - /* A list of files included in this compilation unit. The first - file is always the main one, and that is where the main file name - is stored. */ - struct debug_file *files; - /* Line number information for this compilation unit. This is not - stored by function, because assembler code may have line number - information without function information. */ - struct debug_lineno *linenos; -}; - -/* Information kept for a single source file. */ - -struct debug_file -{ - /* The next source file in this compilation unit. */ - struct debug_file *next; - /* The name of the source file. */ - const char *filename; - /* Global functions, variables, types, etc. */ - struct debug_namespace *globals; -}; - -/* A type. */ - -struct debug_type -{ - /* Kind of type. */ - enum debug_type_kind kind; - /* Size of type (0 if not known). */ - unsigned int size; - /* Type which is a pointer to this type. */ - debug_type pointer; - /* Tagged union with additional information about the type. */ - union - { - /* DEBUG_KIND_INDIRECT. */ - struct debug_indirect_type *kindirect; - /* DEBUG_KIND_INT. */ - /* Whether the integer is unsigned. */ - boolean kint; - /* DEBUG_KIND_STRUCT, DEBUG_KIND_UNION, DEBUG_KIND_CLASS, - DEBUG_KIND_UNION_CLASS. */ - struct debug_class_type *kclass; - /* DEBUG_KIND_ENUM. */ - struct debug_enum_type *kenum; - /* DEBUG_KIND_POINTER. */ - struct debug_type *kpointer; - /* DEBUG_KIND_FUNCTION. */ - struct debug_function_type *kfunction; - /* DEBUG_KIND_REFERENCE. */ - struct debug_type *kreference; - /* DEBUG_KIND_RANGE. */ - struct debug_range_type *krange; - /* DEBUG_KIND_ARRAY. */ - struct debug_array_type *karray; - /* DEBUG_KIND_SET. */ - struct debug_set_type *kset; - /* DEBUG_KIND_OFFSET. */ - struct debug_offset_type *koffset; - /* DEBUG_KIND_METHOD. */ - struct debug_method_type *kmethod; - /* DEBUG_KIND_CONST. */ - struct debug_type *kconst; - /* DEBUG_KIND_VOLATILE. */ - struct debug_type *kvolatile; - /* DEBUG_KIND_NAMED, DEBUG_KIND_TAGGED. */ - struct debug_named_type *knamed; - } u; -}; - -/* Information kept for an indirect type. */ - -struct debug_indirect_type -{ - /* Slot where the final type will appear. */ - debug_type *slot; - /* Tag. */ - const char *tag; -}; - -/* Information kept for a struct, union, or class. */ - -struct debug_class_type -{ - /* NULL terminated array of fields. */ - debug_field *fields; - /* A mark field which indicates whether the struct has already been - printed. */ - unsigned int mark; - /* This is used to uniquely identify unnamed structs when printing. */ - unsigned int id; - /* The remaining fields are only used for DEBUG_KIND_CLASS and - DEBUG_KIND_UNION_CLASS. */ - /* NULL terminated array of base classes. */ - debug_baseclass *baseclasses; - /* NULL terminated array of methods. */ - debug_method *methods; - /* The type of the class providing the virtual function table for - this class. This may point to the type itself. */ - debug_type vptrbase; -}; - -/* Information kept for an enum. */ - -struct debug_enum_type -{ - /* NULL terminated array of names. */ - const char **names; - /* Array of corresponding values. */ - bfd_signed_vma *values; -}; - -/* Information kept for a function. FIXME: We should be able to - record the parameter types. */ - -struct debug_function_type -{ - /* Return type. */ - debug_type return_type; - /* NULL terminated array of argument types. */ - debug_type *arg_types; - /* Whether the function takes a variable number of arguments. */ - boolean varargs; -}; - -/* Information kept for a range. */ - -struct debug_range_type -{ - /* Range base type. */ - debug_type type; - /* Lower bound. */ - bfd_signed_vma lower; - /* Upper bound. */ - bfd_signed_vma upper; -}; - -/* Information kept for an array. */ - -struct debug_array_type -{ - /* Element type. */ - debug_type element_type; - /* Range type. */ - debug_type range_type; - /* Lower bound. */ - bfd_signed_vma lower; - /* Upper bound. */ - bfd_signed_vma upper; - /* Whether this array is really a string. */ - boolean stringp; -}; - -/* Information kept for a set. */ - -struct debug_set_type -{ - /* Base type. */ - debug_type type; - /* Whether this set is really a bitstring. */ - boolean bitstringp; -}; - -/* Information kept for an offset type (a based pointer). */ - -struct debug_offset_type -{ - /* The type the pointer is an offset from. */ - debug_type base_type; - /* The type the pointer points to. */ - debug_type target_type; -}; - -/* Information kept for a method type. */ - -struct debug_method_type -{ - /* The return type. */ - debug_type return_type; - /* The object type which this method is for. */ - debug_type domain_type; - /* A NULL terminated array of argument types. */ - debug_type *arg_types; - /* Whether the method takes a variable number of arguments. */ - boolean varargs; -}; - -/* Information kept for a named type. */ - -struct debug_named_type -{ - /* Name. */ - struct debug_name *name; - /* Real type. */ - debug_type type; -}; - -/* A field in a struct or union. */ - -struct debug_field -{ - /* Name of the field. */ - const char *name; - /* Type of the field. */ - struct debug_type *type; - /* Visibility of the field. */ - enum debug_visibility visibility; - /* Whether this is a static member. */ - boolean static_member; - union - { - /* If static_member is false. */ - struct - { - /* Bit position of the field in the struct. */ - unsigned int bitpos; - /* Size of the field in bits. */ - unsigned int bitsize; - } f; - /* If static_member is true. */ - struct - { - const char *physname; - } s; - } u; -}; - -/* A base class for an object. */ - -struct debug_baseclass -{ - /* Type of the base class. */ - struct debug_type *type; - /* Bit position of the base class in the object. */ - unsigned int bitpos; - /* Whether the base class is virtual. */ - boolean virtual; - /* Visibility of the base class. */ - enum debug_visibility visibility; -}; - -/* A method of an object. */ - -struct debug_method -{ - /* The name of the method. */ - const char *name; - /* A NULL terminated array of different types of variants. */ - struct debug_method_variant **variants; -}; - -/* The variants of a method function of an object. These indicate - which method to run. */ - -struct debug_method_variant -{ - /* The physical name of the function. */ - const char *physname; - /* The type of the function. */ - struct debug_type *type; - /* The visibility of the function. */ - enum debug_visibility visibility; - /* Whether the function is const. */ - boolean constp; - /* Whether the function is volatile. */ - boolean volatilep; - /* The offset to the function in the virtual function table. */ - bfd_vma voffset; - /* If voffset is VOFFSET_STATIC_METHOD, this is a static method. */ -#define VOFFSET_STATIC_METHOD ((bfd_vma) -1) - /* Context of a virtual method function. */ - struct debug_type *context; -}; - -/* A variable. This is the information we keep for a variable object. - This has no name; a name is associated with a variable in a - debug_name structure. */ - -struct debug_variable -{ - /* Kind of variable. */ - enum debug_var_kind kind; - /* Type. */ - debug_type type; - /* Value. The interpretation of the value depends upon kind. */ - bfd_vma val; -}; - -/* A function. This has no name; a name is associated with a function - in a debug_name structure. */ - -struct debug_function -{ - /* Return type. */ - debug_type return_type; - /* Parameter information. */ - struct debug_parameter *parameters; - /* Block information. The first structure on the list is the main - block of the function, and describes function local variables. */ - struct debug_block *blocks; -}; - -/* A function parameter. */ - -struct debug_parameter -{ - /* Next parameter. */ - struct debug_parameter *next; - /* Name. */ - const char *name; - /* Type. */ - debug_type type; - /* Kind. */ - enum debug_parm_kind kind; - /* Value (meaning depends upon kind). */ - bfd_vma val; -}; - -/* A typed constant. */ - -struct debug_typed_constant -{ - /* Type. */ - debug_type type; - /* Value. FIXME: We may eventually need to support non-integral - values. */ - bfd_vma val; -}; - -/* Information about a block within a function. */ - -struct debug_block -{ - /* Next block with the same parent. */ - struct debug_block *next; - /* Parent block. */ - struct debug_block *parent; - /* List of child blocks. */ - struct debug_block *children; - /* Start address of the block. */ - bfd_vma start; - /* End address of the block. */ - bfd_vma end; - /* Local variables. */ - struct debug_namespace *locals; -}; - -/* Line number information we keep for a compilation unit. FIXME: - This structure is easy to create, but can be very space - inefficient. */ - -struct debug_lineno -{ - /* More line number information for this block. */ - struct debug_lineno *next; - /* Source file. */ - struct debug_file *file; - /* Line numbers, terminated by a -1 or the end of the array. */ -#define DEBUG_LINENO_COUNT 10 - unsigned long linenos[DEBUG_LINENO_COUNT]; - /* Addresses for the line numbers. */ - bfd_vma addrs[DEBUG_LINENO_COUNT]; -}; - -/* A namespace. This is a mapping from names to objects. FIXME: This - should be implemented as a hash table. */ - -struct debug_namespace -{ - /* List of items in this namespace. */ - struct debug_name *list; - /* Pointer to where the next item in this namespace should go. */ - struct debug_name **tail; -}; - -/* Kinds of objects that appear in a namespace. */ - -enum debug_object_kind -{ - /* A type. */ - DEBUG_OBJECT_TYPE, - /* A tagged type (really a different sort of namespace). */ - DEBUG_OBJECT_TAG, - /* A variable. */ - DEBUG_OBJECT_VARIABLE, - /* A function. */ - DEBUG_OBJECT_FUNCTION, - /* An integer constant. */ - DEBUG_OBJECT_INT_CONSTANT, - /* A floating point constant. */ - DEBUG_OBJECT_FLOAT_CONSTANT, - /* A typed constant. */ - DEBUG_OBJECT_TYPED_CONSTANT -}; - -/* Linkage of an object that appears in a namespace. */ - -enum debug_object_linkage -{ - /* Local variable. */ - DEBUG_LINKAGE_AUTOMATIC, - /* Static--either file static or function static, depending upon the - namespace is. */ - DEBUG_LINKAGE_STATIC, - /* Global. */ - DEBUG_LINKAGE_GLOBAL, - /* No linkage. */ - DEBUG_LINKAGE_NONE -}; - -/* A name in a namespace. */ - -struct debug_name -{ - /* Next name in this namespace. */ - struct debug_name *next; - /* Name. */ - const char *name; - /* Mark. This is used by debug_write. */ - unsigned int mark; - /* Kind of object. */ - enum debug_object_kind kind; - /* Linkage of object. */ - enum debug_object_linkage linkage; - /* Tagged union with additional information about the object. */ - union - { - /* DEBUG_OBJECT_TYPE. */ - struct debug_type *type; - /* DEBUG_OBJECT_TAG. */ - struct debug_type *tag; - /* DEBUG_OBJECT_VARIABLE. */ - struct debug_variable *variable; - /* DEBUG_OBJECT_FUNCTION. */ - struct debug_function *function; - /* DEBUG_OBJECT_INT_CONSTANT. */ - bfd_vma int_constant; - /* DEBUG_OBJECT_FLOAT_CONSTANT. */ - double float_constant; - /* DEBUG_OBJECT_TYPED_CONSTANT. */ - struct debug_typed_constant *typed_constant; - } u; -}; - -/* During debug_write, a linked list of these structures is used to - keep track of ID numbers that have been assigned to classes. */ - -struct debug_class_id -{ - /* Next ID number. */ - struct debug_class_id *next; - /* The type with the ID. */ - struct debug_type *type; - /* The tag; NULL if no tag. */ - const char *tag; -}; - -/* During debug_type_samep, a linked list of these structures is kept - on the stack to avoid infinite recursion. */ - -struct debug_type_compare_list -{ - /* Next type on list. */ - struct debug_type_compare_list *next; - /* The types we are comparing. */ - struct debug_type *t1; - struct debug_type *t2; -}; - -/* Local functions. */ - -static void debug_error PARAMS ((const char *)); -static struct debug_name *debug_add_to_namespace - PARAMS ((struct debug_handle *, struct debug_namespace **, const char *, - enum debug_object_kind, enum debug_object_linkage)); -static struct debug_name *debug_add_to_current_namespace - PARAMS ((struct debug_handle *, const char *, enum debug_object_kind, - enum debug_object_linkage)); -static struct debug_type *debug_make_type - PARAMS ((struct debug_handle *, enum debug_type_kind, unsigned int)); -static struct debug_type *debug_get_real_type PARAMS ((PTR, debug_type)); -static boolean debug_write_name - PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, - struct debug_name *)); -static boolean debug_write_type - PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, - struct debug_type *, struct debug_name *)); -static boolean debug_write_class_type - PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, - struct debug_type *, const char *)); -static boolean debug_write_function - PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, - const char *, enum debug_object_linkage, struct debug_function *)); -static boolean debug_write_block - PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, - struct debug_block *)); -static boolean debug_write_linenos - PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, - bfd_vma)); -static boolean debug_set_class_id - PARAMS ((struct debug_handle *, const char *, struct debug_type *)); -static boolean debug_type_samep - PARAMS ((struct debug_handle *, struct debug_type *, struct debug_type *)); -static boolean debug_class_type_samep - PARAMS ((struct debug_handle *, struct debug_type *, struct debug_type *)); - -/* Issue an error message. */ - -static void -debug_error (message) - const char *message; -{ - fprintf (stderr, "%s\n", message); -} - -/* Add an object to a namespace. */ - -static struct debug_name * -debug_add_to_namespace (info, nsp, name, kind, linkage) - struct debug_handle *info; - struct debug_namespace **nsp; - const char *name; - enum debug_object_kind kind; - enum debug_object_linkage linkage; -{ - struct debug_name *n; - struct debug_namespace *ns; - - n = (struct debug_name *) xmalloc (sizeof *n); - memset (n, 0, sizeof *n); - - n->name = name; - n->kind = kind; - n->linkage = linkage; - - ns = *nsp; - if (ns == NULL) - { - ns = (struct debug_namespace *) xmalloc (sizeof *ns); - memset (ns, 0, sizeof *ns); - - ns->tail = &ns->list; - - *nsp = ns; - } - - *ns->tail = n; - ns->tail = &n->next; - - return n; -} - -/* Add an object to the current namespace. */ - -static struct debug_name * -debug_add_to_current_namespace (info, name, kind, linkage) - struct debug_handle *info; - const char *name; - enum debug_object_kind kind; - enum debug_object_linkage linkage; -{ - struct debug_namespace **nsp; - - if (info->current_unit == NULL - || info->current_file == NULL) - { - debug_error ("debug_add_to_current_namespace: no current file"); - return NULL; - } - - if (info->current_block != NULL) - nsp = &info->current_block->locals; - else - nsp = &info->current_file->globals; - - return debug_add_to_namespace (info, nsp, name, kind, linkage); -} - -/* Return a handle for debugging information. */ - -PTR -debug_init () -{ - struct debug_handle *ret; - - ret = (struct debug_handle *) xmalloc (sizeof *ret); - memset (ret, 0, sizeof *ret); - return (PTR) ret; -} - -/* Set the source filename. This implicitly starts a new compilation - unit. */ - -boolean -debug_set_filename (handle, name) - PTR handle; - const char *name; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_file *nfile; - struct debug_unit *nunit; - - if (name == NULL) - name = ""; - - nfile = (struct debug_file *) xmalloc (sizeof *nfile); - memset (nfile, 0, sizeof *nfile); - - nfile->filename = name; - - nunit = (struct debug_unit *) xmalloc (sizeof *nunit); - memset (nunit, 0, sizeof *nunit); - - nunit->files = nfile; - info->current_file = nfile; - - if (info->current_unit != NULL) - info->current_unit->next = nunit; - else - { - assert (info->units == NULL); - info->units = nunit; - } - - info->current_unit = nunit; - - info->current_function = NULL; - info->current_block = NULL; - info->current_lineno = NULL; - - return true; -} - -/* Change source files to the given file name. This is used for - include files in a single compilation unit. */ - -boolean -debug_start_source (handle, name) - PTR handle; - const char *name; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_file *f, **pf; - - if (name == NULL) - name = ""; - - if (info->current_unit == NULL) - { - debug_error ("debug_start_source: no debug_set_filename call"); - return false; - } - - for (f = info->current_unit->files; f != NULL; f = f->next) - { - if (f->filename[0] == name[0] - && f->filename[1] == name[1] - && strcmp (f->filename, name) == 0) - { - info->current_file = f; - return true; - } - } - - f = (struct debug_file *) xmalloc (sizeof *f); - memset (f, 0, sizeof *f); - - f->filename = name; - - for (pf = &info->current_file->next; - *pf != NULL; - pf = &(*pf)->next) - ; - *pf = f; - - info->current_file = f; - - return true; -} - -/* Record a function definition. This implicitly starts a function - block. The debug_type argument is the type of the return value. - The boolean indicates whether the function is globally visible. - The bfd_vma is the address of the start of the function. Currently - the parameter types are specified by calls to - debug_record_parameter. FIXME: There is no way to specify nested - functions. */ - -boolean -debug_record_function (handle, name, return_type, global, addr) - PTR handle; - const char *name; - debug_type return_type; - boolean global; - bfd_vma addr; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_function *f; - struct debug_block *b; - struct debug_name *n; - - if (name == NULL) - name = ""; - if (return_type == NULL) - return false; - - if (info->current_unit == NULL) - { - debug_error ("debug_record_function: no debug_set_filename call"); - return false; - } - - f = (struct debug_function *) xmalloc (sizeof *f); - memset (f, 0, sizeof *f); - - f->return_type = return_type; - - b = (struct debug_block *) xmalloc (sizeof *b); - memset (b, 0, sizeof *b); - - b->start = addr; - b->end = (bfd_vma) -1; - - f->blocks = b; - - info->current_function = f; - info->current_block = b; - - /* FIXME: If we could handle nested functions, this would be the - place: we would want to use a different namespace. */ - n = debug_add_to_namespace (info, - &info->current_file->globals, - name, - DEBUG_OBJECT_FUNCTION, - (global - ? DEBUG_LINKAGE_GLOBAL - : DEBUG_LINKAGE_STATIC)); - if (n == NULL) - return false; - - n->u.function = f; - - return true; -} - -/* Record a parameter for the current function. */ - -boolean -debug_record_parameter (handle, name, type, kind, val) - PTR handle; - const char *name; - debug_type type; - enum debug_parm_kind kind; - bfd_vma val; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_parameter *p, **pp; - - if (name == NULL || type == NULL) - return false; - - if (info->current_unit == NULL - || info->current_function == NULL) - { - debug_error ("debug_record_parameter: no current function"); - return false; - } - - p = (struct debug_parameter *) xmalloc (sizeof *p); - memset (p, 0, sizeof *p); - - p->name = name; - p->type = type; - p->kind = kind; - p->val = val; - - for (pp = &info->current_function->parameters; - *pp != NULL; - pp = &(*pp)->next) - ; - *pp = p; - - return true; -} - -/* End a function. FIXME: This should handle function nesting. */ - -boolean -debug_end_function (handle, addr) - PTR handle; - bfd_vma addr; -{ - struct debug_handle *info = (struct debug_handle *) handle; - - if (info->current_unit == NULL - || info->current_block == NULL - || info->current_function == NULL) - { - debug_error ("debug_end_function: no current function"); - return false; - } - - if (info->current_block->parent != NULL) - { - debug_error ("debug_end_function: some blocks were not closed"); - return false; - } - - info->current_block->end = addr; - - info->current_function = NULL; - info->current_block = NULL; - - return true; -} - -/* Start a block in a function. All local information will be - recorded in this block, until the matching call to debug_end_block. - debug_start_block and debug_end_block may be nested. The bfd_vma - argument is the address at which this block starts. */ - -boolean -debug_start_block (handle, addr) - PTR handle; - bfd_vma addr; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_block *b, **pb; - - /* We must always have a current block: debug_record_function sets - one up. */ - if (info->current_unit == NULL - || info->current_block == NULL) - { - debug_error ("debug_start_block: no current block"); - return false; - } - - b = (struct debug_block *) xmalloc (sizeof *b); - memset (b, 0, sizeof *b); - - b->parent = info->current_block; - b->start = addr; - b->end = (bfd_vma) -1; - - /* This new block is a child of the current block. */ - for (pb = &info->current_block->children; - *pb != NULL; - pb = &(*pb)->next) - ; - *pb = b; - - info->current_block = b; - - return true; -} - -/* Finish a block in a function. This matches the call to - debug_start_block. The argument is the address at which this block - ends. */ - -boolean -debug_end_block (handle, addr) - PTR handle; - bfd_vma addr; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_block *parent; - - if (info->current_unit == NULL - || info->current_block == NULL) - { - debug_error ("debug_end_block: no current block"); - return false; - } - - parent = info->current_block->parent; - if (parent == NULL) - { - debug_error ("debug_end_block: attempt to close top level block"); - return false; - } - - info->current_block->end = addr; - - info->current_block = parent; - - return true; -} - -/* Associate a line number in the current source file and function - with a given address. */ - -boolean -debug_record_line (handle, lineno, addr) - PTR handle; - unsigned long lineno; - bfd_vma addr; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_lineno *l; - unsigned int i; - - if (info->current_unit == NULL) - { - debug_error ("debug_record_line: no current unit"); - return false; - } - - l = info->current_lineno; - if (l != NULL && l->file == info->current_file) - { - for (i = 0; i < DEBUG_LINENO_COUNT; i++) - { - if (l->linenos[i] == (unsigned long) -1) - { - l->linenos[i] = lineno; - l->addrs[i] = addr; - return true; - } - } - } - - /* If we get here, then either 1) there is no current_lineno - structure, which means this is the first line number in this - compilation unit, 2) the current_lineno structure is for a - different file, or 3) the current_lineno structure is full. - Regardless, we want to allocate a new debug_lineno structure, put - it in the right place, and make it the new current_lineno - structure. */ - - l = (struct debug_lineno *) xmalloc (sizeof *l); - memset (l, 0, sizeof *l); - - l->file = info->current_file; - l->linenos[0] = lineno; - l->addrs[0] = addr; - for (i = 1; i < DEBUG_LINENO_COUNT; i++) - l->linenos[i] = (unsigned long) -1; - - if (info->current_lineno != NULL) - info->current_lineno->next = l; - else - info->current_unit->linenos = l; - - info->current_lineno = l; - - return true; -} - -/* Start a named common block. This is a block of variables that may - move in memory. */ - -boolean -debug_start_common_block (handle, name) - PTR handle; - const char *name; -{ - /* FIXME */ - debug_error ("debug_start_common_block: not implemented"); - return false; -} - -/* End a named common block. */ - -boolean -debug_end_common_block (handle, name) - PTR handle; - const char *name; -{ - /* FIXME */ - debug_error ("debug_end_common_block: not implemented"); - return false; -} - -/* Record a named integer constant. */ - -boolean -debug_record_int_const (handle, name, val) - PTR handle; - const char *name; - bfd_vma val; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_name *n; - - if (name == NULL) - return false; - - n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_INT_CONSTANT, - DEBUG_LINKAGE_NONE); - if (n == NULL) - return false; - - n->u.int_constant = val; - - return true; -} - -/* Record a named floating point constant. */ - -boolean -debug_record_float_const (handle, name, val) - PTR handle; - const char *name; - double val; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_name *n; - - if (name == NULL) - return false; - - n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_FLOAT_CONSTANT, - DEBUG_LINKAGE_NONE); - if (n == NULL) - return false; - - n->u.float_constant = val; - - return true; -} - -/* Record a typed constant with an integral value. */ - -boolean -debug_record_typed_const (handle, name, type, val) - PTR handle; - const char *name; - debug_type type; - bfd_vma val; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_name *n; - struct debug_typed_constant *tc; - - if (name == NULL || type == NULL) - return false; - - n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_TYPED_CONSTANT, - DEBUG_LINKAGE_NONE); - if (n == NULL) - return false; - - tc = (struct debug_typed_constant *) xmalloc (sizeof *tc); - memset (tc, 0, sizeof *tc); - - tc->type = type; - tc->val = val; - - n->u.typed_constant = tc; - - return true; -} - -/* Record a label. */ - -boolean -debug_record_label (handle, name, type, addr) - PTR handle; - const char *name; - debug_type type; - bfd_vma addr; -{ - /* FIXME. */ - debug_error ("debug_record_label not implemented"); - return false; -} - -/* Record a variable. */ - -boolean -debug_record_variable (handle, name, type, kind, val) - PTR handle; - const char *name; - debug_type type; - enum debug_var_kind kind; - bfd_vma val; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_namespace **nsp; - enum debug_object_linkage linkage; - struct debug_name *n; - struct debug_variable *v; - - if (name == NULL || type == NULL) - return false; - - if (info->current_unit == NULL - || info->current_file == NULL) - { - debug_error ("debug_record_variable: no current file"); - return false; - } - - if (kind == DEBUG_GLOBAL || kind == DEBUG_STATIC) - { - nsp = &info->current_file->globals; - if (kind == DEBUG_GLOBAL) - linkage = DEBUG_LINKAGE_GLOBAL; - else - linkage = DEBUG_LINKAGE_STATIC; - } - else - { - if (info->current_block == NULL) - { - debug_error ("debug_record_variable: no current block"); - return false; - } - nsp = &info->current_block->locals; - linkage = DEBUG_LINKAGE_AUTOMATIC; - } - - n = debug_add_to_namespace (info, nsp, name, DEBUG_OBJECT_VARIABLE, linkage); - if (n == NULL) - return false; - - v = (struct debug_variable *) xmalloc (sizeof *v); - memset (v, 0, sizeof *v); - - v->kind = kind; - v->type = type; - v->val = val; - - n->u.variable = v; - - return true; -} - -/* Make a type with a given kind and size. */ - -/*ARGSUSED*/ -static struct debug_type * -debug_make_type (info, kind, size) - struct debug_handle *info; - enum debug_type_kind kind; - unsigned int size; -{ - struct debug_type *t; - - t = (struct debug_type *) xmalloc (sizeof *t); - memset (t, 0, sizeof *t); - - t->kind = kind; - t->size = size; - - return t; -} - -/* Make an indirect type which may be used as a placeholder for a type - which is referenced before it is defined. */ - -debug_type -debug_make_indirect_type (handle, slot, tag) - PTR handle; - debug_type *slot; - const char *tag; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - struct debug_indirect_type *i; - - t = debug_make_type (info, DEBUG_KIND_INDIRECT, 0); - if (t == NULL) - return DEBUG_TYPE_NULL; - - i = (struct debug_indirect_type *) xmalloc (sizeof *i); - memset (i, 0, sizeof *i); - - i->slot = slot; - i->tag = tag; - - t->u.kindirect = i; - - return t; -} - -/* Make a void type. There is only one of these. */ - -debug_type -debug_make_void_type (handle) - PTR handle; -{ - struct debug_handle *info = (struct debug_handle *) handle; - - return debug_make_type (info, DEBUG_KIND_VOID, 0); -} - -/* Make an integer type of a given size. The boolean argument is true - if the integer is unsigned. */ - -debug_type -debug_make_int_type (handle, size, unsignedp) - PTR handle; - unsigned int size; - boolean unsignedp; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - - t = debug_make_type (info, DEBUG_KIND_INT, size); - if (t == NULL) - return DEBUG_TYPE_NULL; - - t->u.kint = unsignedp; - - return t; -} - -/* Make a floating point type of a given size. FIXME: On some - platforms, like an Alpha, you probably need to be able to specify - the format. */ - -debug_type -debug_make_float_type (handle, size) - PTR handle; - unsigned int size; -{ - struct debug_handle *info = (struct debug_handle *) handle; - - return debug_make_type (info, DEBUG_KIND_FLOAT, size); -} - -/* Make a boolean type of a given size. */ - -debug_type -debug_make_bool_type (handle, size) - PTR handle; - unsigned int size; -{ - struct debug_handle *info = (struct debug_handle *) handle; - - return debug_make_type (info, DEBUG_KIND_BOOL, size); -} - -/* Make a complex type of a given size. */ - -debug_type -debug_make_complex_type (handle, size) - PTR handle; - unsigned int size; -{ - struct debug_handle *info = (struct debug_handle *) handle; - - return debug_make_type (info, DEBUG_KIND_COMPLEX, size); -} - -/* Make a structure type. The second argument is true for a struct, - false for a union. The third argument is the size of the struct. - The fourth argument is a NULL terminated array of fields. */ - -debug_type -debug_make_struct_type (handle, structp, size, fields) - PTR handle; - boolean structp; - bfd_vma size; - debug_field *fields; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - struct debug_class_type *c; - - t = debug_make_type (info, - structp ? DEBUG_KIND_STRUCT : DEBUG_KIND_UNION, - size); - if (t == NULL) - return DEBUG_TYPE_NULL; - - c = (struct debug_class_type *) xmalloc (sizeof *c); - memset (c, 0, sizeof *c); - - c->fields = fields; - - t->u.kclass = c; - - return t; -} - -/* Make an object type. The first three arguments after the handle - are the same as for debug_make_struct_type. The next arguments are - a NULL terminated array of base classes, a NULL terminated array of - methods, the type of the object holding the virtual function table - if it is not this object, and a boolean which is true if this - object has its own virtual function table. */ - -debug_type -debug_make_object_type (handle, structp, size, fields, baseclasses, - methods, vptrbase, ownvptr) - PTR handle; - boolean structp; - bfd_vma size; - debug_field *fields; - debug_baseclass *baseclasses; - debug_method *methods; - debug_type vptrbase; - boolean ownvptr; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - struct debug_class_type *c; - - t = debug_make_type (info, - structp ? DEBUG_KIND_CLASS : DEBUG_KIND_UNION_CLASS, - size); - if (t == NULL) - return DEBUG_TYPE_NULL; - - c = (struct debug_class_type *) xmalloc (sizeof *c); - memset (c, 0, sizeof *c); - - c->fields = fields; - c->baseclasses = baseclasses; - c->methods = methods; - if (ownvptr) - c->vptrbase = t; - else - c->vptrbase = vptrbase; - - t->u.kclass = c; - - return t; -} - -/* Make an enumeration type. The arguments are a null terminated - array of strings, and an array of corresponding values. */ - -debug_type -debug_make_enum_type (handle, names, values) - PTR handle; - const char **names; - bfd_signed_vma *values; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - struct debug_enum_type *e; - - t = debug_make_type (info, DEBUG_KIND_ENUM, 0); - if (t == NULL) - return DEBUG_TYPE_NULL; - - e = (struct debug_enum_type *) xmalloc (sizeof *e); - memset (e, 0, sizeof *e); - - e->names = names; - e->values = values; - - t->u.kenum = e; - - return t; -} - -/* Make a pointer to a given type. */ - -debug_type -debug_make_pointer_type (handle, type) - PTR handle; - debug_type type; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - - if (type == NULL) - return DEBUG_TYPE_NULL; - - if (type->pointer != DEBUG_TYPE_NULL) - return type->pointer; - - t = debug_make_type (info, DEBUG_KIND_POINTER, 0); - if (t == NULL) - return DEBUG_TYPE_NULL; - - t->u.kpointer = type; - - type->pointer = t; - - return t; -} - -/* Make a function returning a given type. FIXME: We should be able - to record the parameter types. */ - -debug_type -debug_make_function_type (handle, type, arg_types, varargs) - PTR handle; - debug_type type; - debug_type *arg_types; - boolean varargs; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - struct debug_function_type *f; - - if (type == NULL) - return DEBUG_TYPE_NULL; - - t = debug_make_type (info, DEBUG_KIND_FUNCTION, 0); - if (t == NULL) - return DEBUG_TYPE_NULL; - - f = (struct debug_function_type *) xmalloc (sizeof *f); - memset (f, 0, sizeof *f); - - f->return_type = type; - f->arg_types = arg_types; - f->varargs = varargs; - - t->u.kfunction = f; - - return t; -} - -/* Make a reference to a given type. */ - -debug_type -debug_make_reference_type (handle, type) - PTR handle; - debug_type type; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - - if (type == NULL) - return DEBUG_TYPE_NULL; - - t = debug_make_type (info, DEBUG_KIND_REFERENCE, 0); - if (t == NULL) - return DEBUG_TYPE_NULL; - - t->u.kreference = type; - - return t; -} - -/* Make a range of a given type from a lower to an upper bound. */ - -debug_type -debug_make_range_type (handle, type, lower, upper) - PTR handle; - debug_type type; - bfd_signed_vma lower; - bfd_signed_vma upper; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - struct debug_range_type *r; - - if (type == NULL) - return DEBUG_TYPE_NULL; - - t = debug_make_type (info, DEBUG_KIND_RANGE, 0); - if (t == NULL) - return DEBUG_TYPE_NULL; - - r = (struct debug_range_type *) xmalloc (sizeof *r); - memset (r, 0, sizeof *r); - - r->type = type; - r->lower = lower; - r->upper = upper; - - t->u.krange = r; - - return t; -} - -/* Make an array type. The second argument is the type of an element - of the array. The third argument is the type of a range of the - array. The fourth and fifth argument are the lower and upper - bounds, respectively. The sixth argument is true if this array is - actually a string, as in C. */ - -debug_type -debug_make_array_type (handle, element_type, range_type, lower, upper, - stringp) - PTR handle; - debug_type element_type; - debug_type range_type; - bfd_signed_vma lower; - bfd_signed_vma upper; - boolean stringp; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - struct debug_array_type *a; - - if (element_type == NULL || range_type == NULL) - return DEBUG_TYPE_NULL; - - t = debug_make_type (info, DEBUG_KIND_ARRAY, 0); - if (t == NULL) - return DEBUG_TYPE_NULL; - - a = (struct debug_array_type *) xmalloc (sizeof *a); - memset (a, 0, sizeof *a); - - a->element_type = element_type; - a->range_type = range_type; - a->lower = lower; - a->upper = upper; - a->stringp = stringp; - - t->u.karray = a; - - return t; -} - -/* Make a set of a given type. For example, a Pascal set type. The - boolean argument is true if this set is actually a bitstring, as in - CHILL. */ - -debug_type -debug_make_set_type (handle, type, bitstringp) - PTR handle; - debug_type type; - boolean bitstringp; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - struct debug_set_type *s; - - if (type == NULL) - return DEBUG_TYPE_NULL; - - t = debug_make_type (info, DEBUG_KIND_SET, 0); - if (t == NULL) - return DEBUG_TYPE_NULL; - - s = (struct debug_set_type *) xmalloc (sizeof *s); - memset (s, 0, sizeof *s); - - s->type = type; - s->bitstringp = bitstringp; - - t->u.kset = s; - - return t; -} - -/* Make a type for a pointer which is relative to an object. The - second argument is the type of the object to which the pointer is - relative. The third argument is the type that the pointer points - to. */ - -debug_type -debug_make_offset_type (handle, base_type, target_type) - PTR handle; - debug_type base_type; - debug_type target_type; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - struct debug_offset_type *o; - - if (base_type == NULL || target_type == NULL) - return DEBUG_TYPE_NULL; - - t = debug_make_type (info, DEBUG_KIND_OFFSET, 0); - if (t == NULL) - return DEBUG_TYPE_NULL; - - o = (struct debug_offset_type *) xmalloc (sizeof *o); - memset (o, 0, sizeof *o); - - o->base_type = base_type; - o->target_type = target_type; - - t->u.koffset = o; - - return t; -} - -/* Make a type for a method function. The second argument is the - return type, the third argument is the domain, and the fourth - argument is a NULL terminated array of argument types. */ - -debug_type -debug_make_method_type (handle, return_type, domain_type, arg_types, varargs) - PTR handle; - debug_type return_type; - debug_type domain_type; - debug_type *arg_types; - boolean varargs; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - struct debug_method_type *m; - - if (return_type == NULL) - return DEBUG_TYPE_NULL; - - t = debug_make_type (info, DEBUG_KIND_METHOD, 0); - if (t == NULL) - return DEBUG_TYPE_NULL; - - m = (struct debug_method_type *) xmalloc (sizeof *m); - memset (m, 0, sizeof *m); - - m->return_type = return_type; - m->domain_type = domain_type; - m->arg_types = arg_types; - m->varargs = varargs; - - t->u.kmethod = m; - - return t; -} - -/* Make a const qualified version of a given type. */ - -debug_type -debug_make_const_type (handle, type) - PTR handle; - debug_type type; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - - if (type == NULL) - return DEBUG_TYPE_NULL; - - t = debug_make_type (info, DEBUG_KIND_CONST, 0); - if (t == NULL) - return DEBUG_TYPE_NULL; - - t->u.kconst = type; - - return t; -} - -/* Make a volatile qualified version of a given type. */ - -debug_type -debug_make_volatile_type (handle, type) - PTR handle; - debug_type type; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - - if (type == NULL) - return DEBUG_TYPE_NULL; - - t = debug_make_type (info, DEBUG_KIND_VOLATILE, 0); - if (t == NULL) - return DEBUG_TYPE_NULL; - - t->u.kvolatile = type; - - return t; -} - -/* Make an undefined tagged type. For example, a struct which has - been mentioned, but not defined. */ - -debug_type -debug_make_undefined_tagged_type (handle, name, kind) - PTR handle; - const char *name; - enum debug_type_kind kind; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - - if (name == NULL) - return DEBUG_TYPE_NULL; - - switch (kind) - { - case DEBUG_KIND_STRUCT: - case DEBUG_KIND_UNION: - case DEBUG_KIND_CLASS: - case DEBUG_KIND_UNION_CLASS: - case DEBUG_KIND_ENUM: - break; - - default: - debug_error ("debug_make_undefined_type: unsupported kind"); - return DEBUG_TYPE_NULL; - } - - t = debug_make_type (info, kind, 0); - if (t == NULL) - return DEBUG_TYPE_NULL; - - return debug_tag_type (handle, name, t); -} - -/* Make a base class for an object. The second argument is the base - class type. The third argument is the bit position of this base - class in the object (always 0 unless doing multiple inheritance). - The fourth argument is whether this is a virtual class. The fifth - argument is the visibility of the base class. */ - -/*ARGSUSED*/ -debug_baseclass -debug_make_baseclass (handle, type, bitpos, virtual, visibility) - PTR handle; - debug_type type; - bfd_vma bitpos; - boolean virtual; - enum debug_visibility visibility; -{ - struct debug_baseclass *b; - - b = (struct debug_baseclass *) xmalloc (sizeof *b); - memset (b, 0, sizeof *b); - - b->type = type; - b->bitpos = bitpos; - b->virtual = virtual; - b->visibility = visibility; - - return b; -} - -/* Make a field for a struct. The second argument is the name. The - third argument is the type of the field. The fourth argument is - the bit position of the field. The fifth argument is the size of - the field (it may be zero). The sixth argument is the visibility - of the field. */ - -/*ARGSUSED*/ -debug_field -debug_make_field (handle, name, type, bitpos, bitsize, visibility) - PTR handle; - const char *name; - debug_type type; - bfd_vma bitpos; - bfd_vma bitsize; - enum debug_visibility visibility; -{ - struct debug_field *f; - - f = (struct debug_field *) xmalloc (sizeof *f); - memset (f, 0, sizeof *f); - - f->name = name; - f->type = type; - f->static_member = false; - f->u.f.bitpos = bitpos; - f->u.f.bitsize = bitsize; - f->visibility = visibility; - - return f; -} - -/* Make a static member of an object. The second argument is the - name. The third argument is the type of the member. The fourth - argument is the physical name of the member (i.e., the name as a - global variable). The fifth argument is the visibility of the - member. */ - -/*ARGSUSED*/ -debug_field -debug_make_static_member (handle, name, type, physname, visibility) - PTR handle; - const char *name; - debug_type type; - const char *physname; - enum debug_visibility visibility; -{ - struct debug_field *f; - - f = (struct debug_field *) xmalloc (sizeof *f); - memset (f, 0, sizeof *f); - - f->name = name; - f->type = type; - f->static_member = true; - f->u.s.physname = physname; - f->visibility = visibility; - - return f; -} - -/* Make a method. The second argument is the name, and the third - argument is a NULL terminated array of method variants. */ - -/*ARGSUSED*/ -debug_method -debug_make_method (handle, name, variants) - PTR handle; - const char *name; - debug_method_variant *variants; -{ - struct debug_method *m; - - m = (struct debug_method *) xmalloc (sizeof *m); - memset (m, 0, sizeof *m); - - m->name = name; - m->variants = variants; - - return m; -} - -/* Make a method argument. The second argument is the real name of - the function. The third argument is the type of the function. The - fourth argument is the visibility. The fifth argument is whether - this is a const function. The sixth argument is whether this is a - volatile function. The seventh argument is the offset in the - virtual function table, if any. The eighth argument is the virtual - function context. FIXME: Are the const and volatile arguments - necessary? Could we just use debug_make_const_type? */ - -/*ARGSUSED*/ -debug_method_variant -debug_make_method_variant (handle, physname, type, visibility, constp, - volatilep, voffset, context) - PTR handle; - const char *physname; - debug_type type; - enum debug_visibility visibility; - boolean constp; - boolean volatilep; - bfd_vma voffset; - debug_type context; -{ - struct debug_method_variant *m; - - m = (struct debug_method_variant *) xmalloc (sizeof *m); - memset (m, 0, sizeof *m); - - m->physname = physname; - m->type = type; - m->visibility = visibility; - m->constp = constp; - m->volatilep = volatilep; - m->voffset = voffset; - m->context = context; - - return m; -} - -/* Make a static method argument. The arguments are the same as for - debug_make_method_variant, except that the last two are omitted - since a static method can not also be virtual. */ - -debug_method_variant -debug_make_static_method_variant (handle, physname, type, visibility, - constp, volatilep) - PTR handle; - const char *physname; - debug_type type; - enum debug_visibility visibility; - boolean constp; - boolean volatilep; -{ - struct debug_method_variant *m; - - m = (struct debug_method_variant *) xmalloc (sizeof *m); - memset (m, 0, sizeof *m); - - m->physname = physname; - m->type = type; - m->visibility = visibility; - m->constp = constp; - m->volatilep = volatilep; - m->voffset = VOFFSET_STATIC_METHOD; - - return m; -} - -/* Name a type. */ - -debug_type -debug_name_type (handle, name, type) - PTR handle; - const char *name; - debug_type type; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - struct debug_named_type *n; - struct debug_name *nm; - - if (name == NULL || type == NULL) - return DEBUG_TYPE_NULL; - - if (info->current_unit == NULL - || info->current_file == NULL) - { - debug_error ("debug_name_type: no current file"); - return DEBUG_TYPE_NULL; - /* return false; */ - } - - t = debug_make_type (info, DEBUG_KIND_NAMED, 0); - if (t == NULL) - return DEBUG_TYPE_NULL; - - n = (struct debug_named_type *) xmalloc (sizeof *n); - memset (n, 0, sizeof *n); - - n->type = type; - - t->u.knamed = n; - - /* We always add the name to the global namespace. This is probably - wrong in some cases, but it seems to be right for stabs. FIXME. */ - - nm = debug_add_to_namespace (info, &info->current_file->globals, name, - DEBUG_OBJECT_TYPE, DEBUG_LINKAGE_NONE); - if (nm == NULL) - return DEBUG_TYPE_NULL; - - nm->u.type = t; - - n->name = nm; - - return t; -} - -/* Tag a type. */ - -debug_type -debug_tag_type (handle, name, type) - PTR handle; - const char *name; - debug_type type; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_type *t; - struct debug_named_type *n; - struct debug_name *nm; - - if (name == NULL || type == NULL) - return DEBUG_TYPE_NULL; - - if (info->current_file == NULL) - { - debug_error ("debug_tag_type: no current file"); - return DEBUG_TYPE_NULL; - } - - if (type->kind == DEBUG_KIND_TAGGED) - { - if (strcmp (type->u.knamed->name->name, name) == 0) - return type; - debug_error ("debug_tag_type: extra tag attempted"); - return DEBUG_TYPE_NULL; - } - - t = debug_make_type (info, DEBUG_KIND_TAGGED, 0); - if (t == NULL) - return DEBUG_TYPE_NULL; - - n = (struct debug_named_type *) xmalloc (sizeof *n); - memset (n, 0, sizeof *n); - - n->type = type; - - t->u.knamed = n; - - /* We keep a global namespace of tags for each compilation unit. I - don't know if that is the right thing to do. */ - - nm = debug_add_to_namespace (info, &info->current_file->globals, name, - DEBUG_OBJECT_TAG, DEBUG_LINKAGE_NONE); - if (nm == NULL) - return DEBUG_TYPE_NULL; - - nm->u.tag = t; - - n->name = nm; - - return t; -} - -/* Record the size of a given type. */ - -/*ARGSUSED*/ -boolean -debug_record_type_size (handle, type, size) - PTR handle; - debug_type type; - unsigned int size; -{ -#if 0 - if (type->size != 0 && type->size != size) - fprintf (stderr, "Warning: changing type size from %d to %d\n", - type->size, size); -#endif - - type->size = size; - - return true; -} - -/* Find a named type. */ - -debug_type -debug_find_named_type (handle, name) - PTR handle; - const char *name; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_block *b; - struct debug_file *f; - - /* We only search the current compilation unit. I don't know if - this is right or not. */ - - if (info->current_unit == NULL) - { - debug_error ("debug_find_named_type: no current compilation unit"); - return DEBUG_TYPE_NULL; - } - - for (b = info->current_block; b != NULL; b = b->parent) - { - if (b->locals != NULL) - { - struct debug_name *n; - - for (n = b->locals->list; n != NULL; n = n->next) - { - if (n->kind == DEBUG_OBJECT_TYPE - && n->name[0] == name[0] - && strcmp (n->name, name) == 0) - return n->u.type; - } - } - } - - for (f = info->current_unit->files; f != NULL; f = f->next) - { - if (f->globals != NULL) - { - struct debug_name *n; - - for (n = f->globals->list; n != NULL; n = n->next) - { - if (n->kind == DEBUG_OBJECT_TYPE - && n->name[0] == name[0] - && strcmp (n->name, name) == 0) - return n->u.type; - } - } - } - - return DEBUG_TYPE_NULL; -} - -/* Find a tagged type. */ - -debug_type -debug_find_tagged_type (handle, name, kind) - PTR handle; - const char *name; - enum debug_type_kind kind; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_unit *u; - - /* We search the globals of all the compilation units. I don't know - if this is correct or not. It would be easy to change. */ - - for (u = info->units; u != NULL; u = u->next) - { - struct debug_file *f; - - for (f = u->files; f != NULL; f = f->next) - { - struct debug_name *n; - - if (f->globals != NULL) - { - for (n = f->globals->list; n != NULL; n = n->next) - { - if (n->kind == DEBUG_OBJECT_TAG - && (kind == DEBUG_KIND_ILLEGAL - || n->u.tag->kind == kind) - && n->name[0] == name[0] - && strcmp (n->name, name) == 0) - return n->u.tag; - } - } - } - } - - return DEBUG_TYPE_NULL; -} - -/* Get a base type. */ - -static struct debug_type * -debug_get_real_type (handle, type) - PTR handle; - debug_type type; -{ - switch (type->kind) - { - default: - return type; - case DEBUG_KIND_INDIRECT: - if (*type->u.kindirect->slot != NULL) - return debug_get_real_type (handle, *type->u.kindirect->slot); - return type; - case DEBUG_KIND_NAMED: - case DEBUG_KIND_TAGGED: - return debug_get_real_type (handle, type->u.knamed->type); - } - /*NOTREACHED*/ -} - -/* Get the kind of a type. */ - -enum debug_type_kind -debug_get_type_kind (handle, type) - PTR handle; - debug_type type; -{ - if (type == NULL) - return DEBUG_KIND_ILLEGAL; - type = debug_get_real_type (handle, type); - return type->kind; -} - -/* Get the name of a type. */ - -const char * -debug_get_type_name (handle, type) - PTR handle; - debug_type type; -{ - if (type->kind == DEBUG_KIND_INDIRECT) - { - if (*type->u.kindirect->slot != NULL) - return debug_get_type_name (handle, *type->u.kindirect->slot); - return type->u.kindirect->tag; - } - if (type->kind == DEBUG_KIND_NAMED - || type->kind == DEBUG_KIND_TAGGED) - return type->u.knamed->name->name; - return NULL; -} - -/* Get the size of a type. */ - -bfd_vma -debug_get_type_size (handle, type) - PTR handle; - debug_type type; -{ - if (type == NULL) - return 0; - - /* We don't call debug_get_real_type, because somebody might have - called debug_record_type_size on a named or indirect type. */ - - if (type->size != 0) - return type->size; - - switch (type->kind) - { - default: - return 0; - case DEBUG_KIND_INDIRECT: - if (*type->u.kindirect->slot != NULL) - return debug_get_type_size (handle, *type->u.kindirect->slot); - return 0; - case DEBUG_KIND_NAMED: - case DEBUG_KIND_TAGGED: - return debug_get_type_size (handle, type->u.knamed->type); - } - /*NOTREACHED*/ -} - -/* Get the return type of a function or method type. */ - -debug_type -debug_get_return_type (handle, type) - PTR handle; - debug_type type; -{ - if (type == NULL) - return DEBUG_TYPE_NULL; - type = debug_get_real_type (handle, type); - switch (type->kind) - { - default: - return DEBUG_TYPE_NULL; - case DEBUG_KIND_FUNCTION: - return type->u.kfunction->return_type; - case DEBUG_KIND_METHOD: - return type->u.kmethod->return_type; - } - /*NOTREACHED*/ -} - -/* Get the parameter types of a function or method type (except that - we don't currently store the parameter types of a function). */ - -const debug_type * -debug_get_parameter_types (handle, type, pvarargs) - PTR handle; - debug_type type; - boolean *pvarargs; -{ - if (type == NULL) - return NULL; - type = debug_get_real_type (handle, type); - switch (type->kind) - { - default: - return NULL; - case DEBUG_KIND_FUNCTION: - *pvarargs = type->u.kfunction->varargs; - return type->u.kfunction->arg_types; - case DEBUG_KIND_METHOD: - *pvarargs = type->u.kmethod->varargs; - return type->u.kmethod->arg_types; - } - /*NOTREACHED*/ -} - -/* Get the target type of a type. */ - -debug_type -debug_get_target_type (handle, type) - PTR handle; - debug_type type; -{ - if (type == NULL) - return NULL; - type = debug_get_real_type (handle, type); - switch (type->kind) - { - default: - return NULL; - case DEBUG_KIND_POINTER: - return type->u.kpointer; - case DEBUG_KIND_REFERENCE: - return type->u.kreference; - case DEBUG_KIND_CONST: - return type->u.kconst; - case DEBUG_KIND_VOLATILE: - return type->u.kvolatile; - } - /*NOTREACHED*/ -} - -/* Get the NULL terminated array of fields for a struct, union, or - class. */ - -const debug_field * -debug_get_fields (handle, type) - PTR handle; - debug_type type; -{ - if (type == NULL) - return NULL; - type = debug_get_real_type (handle, type); - switch (type->kind) - { - default: - return NULL; - case DEBUG_KIND_STRUCT: - case DEBUG_KIND_UNION: - case DEBUG_KIND_CLASS: - case DEBUG_KIND_UNION_CLASS: - return type->u.kclass->fields; - } - /*NOTREACHED*/ -} - -/* Get the type of a field. */ - -/*ARGSUSED*/ -debug_type -debug_get_field_type (handle, field) - PTR handle; - debug_field field; -{ - if (field == NULL) - return NULL; - return field->type; -} - -/* Get the name of a field. */ - -/*ARGSUSED*/ -const char * -debug_get_field_name (handle, field) - PTR handle; - debug_field field; -{ - if (field == NULL) - return NULL; - return field->name; -} - -/* Get the bit position of a field. */ - -/*ARGSUSED*/ -bfd_vma -debug_get_field_bitpos (handle, field) - PTR handle; - debug_field field; -{ - if (field == NULL || field->static_member) - return (bfd_vma) -1; - return field->u.f.bitpos; -} - -/* Get the bit size of a field. */ - -/*ARGSUSED*/ -bfd_vma -debug_get_field_bitsize (handle, field) - PTR handle; - debug_field field; -{ - if (field == NULL || field->static_member) - return (bfd_vma) -1; - return field->u.f.bitsize; -} - -/* Get the visibility of a field. */ - -/*ARGSUSED*/ -enum debug_visibility -debug_get_field_visibility (handle, field) - PTR handle; - debug_field field; -{ - if (field == NULL) - return DEBUG_VISIBILITY_IGNORE; - return field->visibility; -} - -/* Get the physical name of a field. */ - -const char * -debug_get_field_physname (handle, field) - PTR handle; - debug_field field; -{ - if (field == NULL || ! field->static_member) - return NULL; - return field->u.s.physname; -} - -/* Write out the debugging information. This is given a handle to - debugging information, and a set of function pointers to call. */ - -boolean -debug_write (handle, fns, fhandle) - PTR handle; - const struct debug_write_fns *fns; - PTR fhandle; -{ - struct debug_handle *info = (struct debug_handle *) handle; - struct debug_unit *u; - - /* We use a mark to tell whether we have already written out a - particular name. We use an integer, so that we don't have to - clear the mark fields if we happen to write out the same - information more than once. */ - ++info->mark; - - /* The base_id field holds an ID value which will never be used, so - that we can tell whether we have assigned an ID during this call - to debug_write. */ - info->base_id = info->class_id; - - /* We keep a linked list of classes for which was have assigned ID's - during this call to debug_write. */ - info->id_list = NULL; - - for (u = info->units; u != NULL; u = u->next) - { - struct debug_file *f; - boolean first_file; - - info->current_write_lineno = u->linenos; - info->current_write_lineno_index = 0; - - if (! (*fns->start_compilation_unit) (fhandle, u->files->filename)) - return false; - - first_file = true; - for (f = u->files; f != NULL; f = f->next) - { - struct debug_name *n; - - if (first_file) - first_file = false; - else - { - if (! (*fns->start_source) (fhandle, f->filename)) - return false; - } - - if (f->globals != NULL) - { - for (n = f->globals->list; n != NULL; n = n->next) - { - if (! debug_write_name (info, fns, fhandle, n)) - return false; - } - } - } - - /* Output any line number information which hasn't already been - handled. */ - if (! debug_write_linenos (info, fns, fhandle, (bfd_vma) -1)) - return false; - } - - return true; -} - -/* Write out an element in a namespace. */ - -static boolean -debug_write_name (info, fns, fhandle, n) - struct debug_handle *info; - const struct debug_write_fns *fns; - PTR fhandle; - struct debug_name *n; -{ - switch (n->kind) - { - case DEBUG_OBJECT_TYPE: - if (! debug_write_type (info, fns, fhandle, n->u.type, n) - || ! (*fns->typdef) (fhandle, n->name)) - return false; - return true; - case DEBUG_OBJECT_TAG: - if (! debug_write_type (info, fns, fhandle, n->u.tag, n)) - return false; - return (*fns->tag) (fhandle, n->name); - case DEBUG_OBJECT_VARIABLE: - if (! debug_write_type (info, fns, fhandle, n->u.variable->type, - (struct debug_name *) NULL)) - return false; - return (*fns->variable) (fhandle, n->name, n->u.variable->kind, - n->u.variable->val); - case DEBUG_OBJECT_FUNCTION: - return debug_write_function (info, fns, fhandle, n->name, - n->linkage, n->u.function); - case DEBUG_OBJECT_INT_CONSTANT: - return (*fns->int_constant) (fhandle, n->name, n->u.int_constant); - case DEBUG_OBJECT_FLOAT_CONSTANT: - return (*fns->float_constant) (fhandle, n->name, n->u.float_constant); - case DEBUG_OBJECT_TYPED_CONSTANT: - if (! debug_write_type (info, fns, fhandle, n->u.typed_constant->type, - (struct debug_name *) NULL)) - return false; - return (*fns->typed_constant) (fhandle, n->name, - n->u.typed_constant->val); - default: - abort (); - return false; - } - /*NOTREACHED*/ -} - -/* Write out a type. If the type is DEBUG_KIND_NAMED or - DEBUG_KIND_TAGGED, then the name argument is the name for which we - are about to call typedef or tag. If the type is anything else, - then the name argument is a tag from a DEBUG_KIND_TAGGED type which - points to this one. */ - -static boolean -debug_write_type (info, fns, fhandle, type, name) - struct debug_handle *info; - const struct debug_write_fns *fns; - PTR fhandle; - struct debug_type *type; - struct debug_name *name; -{ - unsigned int i; - int is; - const char *tag; - - /* If we have a name for this type, just output it. We only output - typedef names after they have been defined. We output type tags - whenever we are not actually defining them. */ - if ((type->kind == DEBUG_KIND_NAMED - || type->kind == DEBUG_KIND_TAGGED) - && (type->u.knamed->name->mark == info->mark - || (type->kind == DEBUG_KIND_TAGGED - && type->u.knamed->name != name))) - { - if (type->kind == DEBUG_KIND_NAMED) - return (*fns->typedef_type) (fhandle, type->u.knamed->name->name); - else - { - struct debug_type *real; - unsigned int id; - - real = debug_get_real_type ((PTR) info, type); - id = 0; - if ((real->kind == DEBUG_KIND_STRUCT - || real->kind == DEBUG_KIND_UNION - || real->kind == DEBUG_KIND_CLASS - || real->kind == DEBUG_KIND_UNION_CLASS) - && real->u.kclass != NULL) - { - if (real->u.kclass->id <= info->base_id) - { - if (! debug_set_class_id (info, - type->u.knamed->name->name, - real)) - return false; - } - id = real->u.kclass->id; - } - - return (*fns->tag_type) (fhandle, type->u.knamed->name->name, id, - real->kind); - } - } - - /* Mark the name after we have already looked for a known name, so - that we don't just define a type in terms of itself. We need to - mark the name here so that a struct containing a pointer to - itself will work. */ - if (name != NULL) - name->mark = info->mark; - - tag = NULL; - if (name != NULL - && type->kind != DEBUG_KIND_NAMED - && type->kind != DEBUG_KIND_TAGGED) - { - assert (name->kind == DEBUG_OBJECT_TAG); - tag = name->name; - } - - switch (type->kind) - { - case DEBUG_KIND_ILLEGAL: - debug_error ("debug_write_type: illegal type encountered"); - return false; - case DEBUG_KIND_INDIRECT: - if (*type->u.kindirect->slot == DEBUG_TYPE_NULL) - return (*fns->empty_type) (fhandle); - return debug_write_type (info, fns, fhandle, *type->u.kindirect->slot, - name); - case DEBUG_KIND_VOID: - return (*fns->void_type) (fhandle); - case DEBUG_KIND_INT: - return (*fns->int_type) (fhandle, type->size, type->u.kint); - case DEBUG_KIND_FLOAT: - return (*fns->float_type) (fhandle, type->size); - case DEBUG_KIND_COMPLEX: - return (*fns->complex_type) (fhandle, type->size); - case DEBUG_KIND_BOOL: - return (*fns->bool_type) (fhandle, type->size); - case DEBUG_KIND_STRUCT: - case DEBUG_KIND_UNION: - if (type->u.kclass != NULL) - { - if (type->u.kclass->id <= info->base_id) - { - if (! debug_set_class_id (info, tag, type)) - return false; - } - - if (info->mark == type->u.kclass->mark) - { - /* We are currently outputting this struct, or we have - already output it. I don't know if this can happen, - but it can happen for a class. */ - assert (type->u.kclass->id > info->base_id); - return (*fns->tag_type) (fhandle, tag, type->u.kclass->id, - type->kind); - } - type->u.kclass->mark = info->mark; - } - - if (! (*fns->start_struct_type) (fhandle, tag, - (type->u.kclass != NULL - ? type->u.kclass->id - : 0), - type->kind == DEBUG_KIND_STRUCT, - type->size)) - return false; - if (type->u.kclass != NULL - && type->u.kclass->fields != NULL) - { - for (i = 0; type->u.kclass->fields[i] != NULL; i++) - { - struct debug_field *f; - - f = type->u.kclass->fields[i]; - if (! debug_write_type (info, fns, fhandle, f->type, - (struct debug_name *) NULL) - || ! (*fns->struct_field) (fhandle, f->name, f->u.f.bitpos, - f->u.f.bitsize, f->visibility)) - return false; - } - } - return (*fns->end_struct_type) (fhandle); - case DEBUG_KIND_CLASS: - case DEBUG_KIND_UNION_CLASS: - return debug_write_class_type (info, fns, fhandle, type, tag); - case DEBUG_KIND_ENUM: - if (type->u.kenum == NULL) - return (*fns->enum_type) (fhandle, tag, (const char **) NULL, - (bfd_signed_vma *) NULL); - return (*fns->enum_type) (fhandle, tag, type->u.kenum->names, - type->u.kenum->values); - case DEBUG_KIND_POINTER: - if (! debug_write_type (info, fns, fhandle, type->u.kpointer, - (struct debug_name *) NULL)) - return false; - return (*fns->pointer_type) (fhandle); - case DEBUG_KIND_FUNCTION: - if (! debug_write_type (info, fns, fhandle, - type->u.kfunction->return_type, - (struct debug_name *) NULL)) - return false; - if (type->u.kfunction->arg_types == NULL) - is = -1; - else - { - for (is = 0; type->u.kfunction->arg_types[is] != NULL; is++) - if (! debug_write_type (info, fns, fhandle, - type->u.kfunction->arg_types[is], - (struct debug_name *) NULL)) - return false; - } - return (*fns->function_type) (fhandle, is, - type->u.kfunction->varargs); - case DEBUG_KIND_REFERENCE: - if (! debug_write_type (info, fns, fhandle, type->u.kreference, - (struct debug_name *) NULL)) - return false; - return (*fns->reference_type) (fhandle); - case DEBUG_KIND_RANGE: - if (! debug_write_type (info, fns, fhandle, type->u.krange->type, - (struct debug_name *) NULL)) - return false; - return (*fns->range_type) (fhandle, type->u.krange->lower, - type->u.krange->upper); - case DEBUG_KIND_ARRAY: - if (! debug_write_type (info, fns, fhandle, type->u.karray->element_type, - (struct debug_name *) NULL) - || ! debug_write_type (info, fns, fhandle, - type->u.karray->range_type, - (struct debug_name *) NULL)) - return false; - return (*fns->array_type) (fhandle, type->u.karray->lower, - type->u.karray->upper, - type->u.karray->stringp); - case DEBUG_KIND_SET: - if (! debug_write_type (info, fns, fhandle, type->u.kset->type, - (struct debug_name *) NULL)) - return false; - return (*fns->set_type) (fhandle, type->u.kset->bitstringp); - case DEBUG_KIND_OFFSET: - if (! debug_write_type (info, fns, fhandle, type->u.koffset->base_type, - (struct debug_name *) NULL) - || ! debug_write_type (info, fns, fhandle, - type->u.koffset->target_type, - (struct debug_name *) NULL)) - return false; - return (*fns->offset_type) (fhandle); - case DEBUG_KIND_METHOD: - if (! debug_write_type (info, fns, fhandle, - type->u.kmethod->return_type, - (struct debug_name *) NULL)) - return false; - if (type->u.kmethod->arg_types == NULL) - is = -1; - else - { - for (is = 0; type->u.kmethod->arg_types[is] != NULL; is++) - if (! debug_write_type (info, fns, fhandle, - type->u.kmethod->arg_types[is], - (struct debug_name *) NULL)) - return false; - } - if (type->u.kmethod->domain_type != NULL) - { - if (! debug_write_type (info, fns, fhandle, - type->u.kmethod->domain_type, - (struct debug_name *) NULL)) - return false; - } - return (*fns->method_type) (fhandle, - type->u.kmethod->domain_type != NULL, - is, - type->u.kmethod->varargs); - case DEBUG_KIND_CONST: - if (! debug_write_type (info, fns, fhandle, type->u.kconst, - (struct debug_name *) NULL)) - return false; - return (*fns->const_type) (fhandle); - case DEBUG_KIND_VOLATILE: - if (! debug_write_type (info, fns, fhandle, type->u.kvolatile, - (struct debug_name *) NULL)) - return false; - return (*fns->volatile_type) (fhandle); - case DEBUG_KIND_NAMED: - return debug_write_type (info, fns, fhandle, type->u.knamed->type, - (struct debug_name *) NULL); - case DEBUG_KIND_TAGGED: - return debug_write_type (info, fns, fhandle, type->u.knamed->type, - type->u.knamed->name); - default: - abort (); - return false; - } -} - -/* Write out a class type. */ - -static boolean -debug_write_class_type (info, fns, fhandle, type, tag) - struct debug_handle *info; - const struct debug_write_fns *fns; - PTR fhandle; - struct debug_type *type; - const char *tag; -{ - unsigned int i; - unsigned int id; - struct debug_type *vptrbase; - - if (type->u.kclass == NULL) - { - id = 0; - vptrbase = NULL; - } - else - { - if (type->u.kclass->id <= info->base_id) - { - if (! debug_set_class_id (info, tag, type)) - return false; - } - - if (info->mark == type->u.kclass->mark) - { - /* We are currently outputting this class, or we have - already output it. This can happen when there are - methods for an anonymous class. */ - assert (type->u.kclass->id > info->base_id); - return (*fns->tag_type) (fhandle, tag, type->u.kclass->id, - type->kind); - } - type->u.kclass->mark = info->mark; - id = type->u.kclass->id; - - vptrbase = type->u.kclass->vptrbase; - if (vptrbase != NULL && vptrbase != type) - { - if (! debug_write_type (info, fns, fhandle, vptrbase, - (struct debug_name *) NULL)) - return false; - } - } - - if (! (*fns->start_class_type) (fhandle, tag, id, - type->kind == DEBUG_KIND_CLASS, - type->size, - vptrbase != NULL, - vptrbase == type)) - return false; - - if (type->u.kclass != NULL) - { - if (type->u.kclass->fields != NULL) - { - for (i = 0; type->u.kclass->fields[i] != NULL; i++) - { - struct debug_field *f; - - f = type->u.kclass->fields[i]; - if (! debug_write_type (info, fns, fhandle, f->type, - (struct debug_name *) NULL)) - return false; - if (f->static_member) - { - if (! (*fns->class_static_member) (fhandle, f->name, - f->u.s.physname, - f->visibility)) - return false; - } - else - { - if (! (*fns->struct_field) (fhandle, f->name, f->u.f.bitpos, - f->u.f.bitsize, f->visibility)) - return false; - } - } - } - - if (type->u.kclass->baseclasses != NULL) - { - for (i = 0; type->u.kclass->baseclasses[i] != NULL; i++) - { - struct debug_baseclass *b; - - b = type->u.kclass->baseclasses[i]; - if (! debug_write_type (info, fns, fhandle, b->type, - (struct debug_name *) NULL)) - return false; - if (! (*fns->class_baseclass) (fhandle, b->bitpos, b->virtual, - b->visibility)) - return false; - } - } - - if (type->u.kclass->methods != NULL) - { - for (i = 0; type->u.kclass->methods[i] != NULL; i++) - { - struct debug_method *m; - unsigned int j; - - m = type->u.kclass->methods[i]; - if (! (*fns->class_start_method) (fhandle, m->name)) - return false; - for (j = 0; m->variants[j] != NULL; j++) - { - struct debug_method_variant *v; - - v = m->variants[j]; - if (v->context != NULL) - { - if (! debug_write_type (info, fns, fhandle, v->context, - (struct debug_name *) NULL)) - return false; - } - if (! debug_write_type (info, fns, fhandle, v->type, - (struct debug_name *) NULL)) - return false; - if (v->voffset != VOFFSET_STATIC_METHOD) - { - if (! (*fns->class_method_variant) (fhandle, v->physname, - v->visibility, - v->constp, - v->volatilep, - v->voffset, - v->context != NULL)) - return false; - } - else - { - if (! (*fns->class_static_method_variant) (fhandle, - v->physname, - v->visibility, - v->constp, - v->volatilep)) - return false; - } - } - if (! (*fns->class_end_method) (fhandle)) - return false; - } - } - } - - return (*fns->end_class_type) (fhandle); -} - -/* Write out information for a function. */ - -static boolean -debug_write_function (info, fns, fhandle, name, linkage, function) - struct debug_handle *info; - const struct debug_write_fns *fns; - PTR fhandle; - const char *name; - enum debug_object_linkage linkage; - struct debug_function *function; -{ - struct debug_parameter *p; - struct debug_block *b; - - if (! debug_write_linenos (info, fns, fhandle, function->blocks->start)) - return false; - - if (! debug_write_type (info, fns, fhandle, function->return_type, - (struct debug_name *) NULL)) - return false; - - if (! (*fns->start_function) (fhandle, name, - linkage == DEBUG_LINKAGE_GLOBAL)) - return false; - - for (p = function->parameters; p != NULL; p = p->next) - { - if (! debug_write_type (info, fns, fhandle, p->type, - (struct debug_name *) NULL) - || ! (*fns->function_parameter) (fhandle, p->name, p->kind, p->val)) - return false; - } - - for (b = function->blocks; b != NULL; b = b->next) - { - if (! debug_write_block (info, fns, fhandle, b)) - return false; - } - - return (*fns->end_function) (fhandle); -} - -/* Write out information for a block. */ - -static boolean -debug_write_block (info, fns, fhandle, block) - struct debug_handle *info; - const struct debug_write_fns *fns; - PTR fhandle; - struct debug_block *block; -{ - struct debug_name *n; - struct debug_block *b; - - if (! debug_write_linenos (info, fns, fhandle, block->start)) - return false; - - /* I can't see any point to writing out a block with no local - variables, so we don't bother, except for the top level block. */ - if (block->locals != NULL || block->parent == NULL) - { - if (! (*fns->start_block) (fhandle, block->start)) - return false; - } - - if (block->locals != NULL) - { - for (n = block->locals->list; n != NULL; n = n->next) - { - if (! debug_write_name (info, fns, fhandle, n)) - return false; - } - } - - for (b = block->children; b != NULL; b = b->next) - { - if (! debug_write_block (info, fns, fhandle, b)) - return false; - } - - if (! debug_write_linenos (info, fns, fhandle, block->end)) - return false; - - if (block->locals != NULL || block->parent == NULL) - { - if (! (*fns->end_block) (fhandle, block->end)) - return false; - } - - return true; -} - -/* Write out line number information up to ADDRESS. */ - -static boolean -debug_write_linenos (info, fns, fhandle, address) - struct debug_handle *info; - const struct debug_write_fns *fns; - PTR fhandle; - bfd_vma address; -{ - while (info->current_write_lineno != NULL) - { - struct debug_lineno *l; - - l = info->current_write_lineno; - - while (info->current_write_lineno_index < DEBUG_LINENO_COUNT) - { - if (l->linenos[info->current_write_lineno_index] - == (unsigned long) -1) - break; - - if (l->addrs[info->current_write_lineno_index] >= address) - return true; - - if (! (*fns->lineno) (fhandle, l->file->filename, - l->linenos[info->current_write_lineno_index], - l->addrs[info->current_write_lineno_index])) - return false; - - ++info->current_write_lineno_index; - } - - info->current_write_lineno = l->next; - info->current_write_lineno_index = 0; - } - - return true; -} - -/* Get the ID number for a class. If during the same call to - debug_write we find a struct with the same definition with the same - name, we use the same ID. This type of things happens because the - same struct will be defined by multiple compilation units. */ - -static boolean -debug_set_class_id (info, tag, type) - struct debug_handle *info; - const char *tag; - struct debug_type *type; -{ - struct debug_class_type *c; - struct debug_class_id *l; - - assert (type->kind == DEBUG_KIND_STRUCT - || type->kind == DEBUG_KIND_UNION - || type->kind == DEBUG_KIND_CLASS - || type->kind == DEBUG_KIND_UNION_CLASS); - - c = type->u.kclass; - - if (c->id > info->base_id) - return true; - - for (l = info->id_list; l != NULL; l = l->next) - { - if (l->type->kind != type->kind) - continue; - - if (tag == NULL) - { - if (l->tag != NULL) - continue; - } - else - { - if (l->tag == NULL - || l->tag[0] != tag[0] - || strcmp (l->tag, tag) != 0) - continue; - } - - if (debug_type_samep (info, l->type, type)) - { - c->id = l->type->u.kclass->id; - return true; - } - } - - /* There are no identical types. Use a new ID, and add it to the - list. */ - ++info->class_id; - c->id = info->class_id; - - l = (struct debug_class_id *) xmalloc (sizeof *l); - memset (l, 0, sizeof *l); - - l->type = type; - l->tag = tag; - - l->next = info->id_list; - info->id_list = l; - - return true; -} - -/* See if two types are the same. At this point, we don't care about - tags and the like. */ - -static boolean -debug_type_samep (info, t1, t2) - struct debug_handle *info; - struct debug_type *t1; - struct debug_type *t2; -{ - struct debug_type_compare_list *l; - struct debug_type_compare_list top; - boolean ret; - - if (t1 == NULL) - return t2 == NULL; - if (t2 == NULL) - return false; - - while (t1->kind == DEBUG_KIND_INDIRECT) - { - t1 = *t1->u.kindirect->slot; - if (t1 == NULL) - return false; - } - while (t2->kind == DEBUG_KIND_INDIRECT) - { - t2 = *t2->u.kindirect->slot; - if (t2 == NULL) - return false; - } - - if (t1 == t2) - return true; - - /* As a special case, permit a typedef to match a tag, since C++ - debugging output will sometimes add a typedef where C debugging - output will not. */ - if (t1->kind == DEBUG_KIND_NAMED - && t2->kind == DEBUG_KIND_TAGGED) - return debug_type_samep (info, t1->u.knamed->type, t2); - else if (t1->kind == DEBUG_KIND_TAGGED - && t2->kind == DEBUG_KIND_NAMED) - return debug_type_samep (info, t1, t2->u.knamed->type); - - if (t1->kind != t2->kind - || t1->size != t2->size) - return false; - - /* Get rid of the trivial cases first. */ - switch (t1->kind) - { - default: - break; - case DEBUG_KIND_VOID: - case DEBUG_KIND_FLOAT: - case DEBUG_KIND_COMPLEX: - case DEBUG_KIND_BOOL: - return true; - case DEBUG_KIND_INT: - return t1->u.kint == t2->u.kint; - } - - /* We have to avoid an infinite recursion. We do this by keeping a - list of types which we are comparing. We just keep the list on - the stack. If we encounter a pair of types we are currently - comparing, we just assume that they are equal. */ - for (l = info->compare_list; l != NULL; l = l->next) - { - if (l->t1 == t1 && l->t2 == t2) - return true; - } - - top.t1 = t1; - top.t2 = t2; - top.next = info->compare_list; - info->compare_list = ⊤ - - switch (t1->kind) - { - default: - abort (); - ret = false; - break; - - case DEBUG_KIND_STRUCT: - case DEBUG_KIND_UNION: - case DEBUG_KIND_CLASS: - case DEBUG_KIND_UNION_CLASS: - if (t1->u.kclass == NULL) - ret = t2->u.kclass == NULL; - else if (t2->u.kclass == NULL) - ret = false; - else if (t1->u.kclass->id > info->base_id - && t1->u.kclass->id == t2->u.kclass->id) - ret = true; - else - ret = debug_class_type_samep (info, t1, t2); - break; - - case DEBUG_KIND_ENUM: - if (t1->u.kenum == NULL) - ret = t2->u.kenum == NULL; - else if (t2->u.kenum == NULL) - ret = false; - else - { - const char **pn1, **pn2; - bfd_signed_vma *pv1, *pv2; - - pn1 = t1->u.kenum->names; - pn2 = t2->u.kenum->names; - pv1 = t1->u.kenum->values; - pv2 = t2->u.kenum->values; - while (*pn1 != NULL && *pn2 != NULL) - { - if (**pn1 != **pn2 - || *pv1 != *pv2 - || strcmp (*pn1, *pn2) != 0) - break; - ++pn1; - ++pn2; - ++pv1; - ++pv2; - } - ret = *pn1 == NULL && *pn2 == NULL; - } - break; - - case DEBUG_KIND_POINTER: - ret = debug_type_samep (info, t1->u.kpointer, t2->u.kpointer); - break; - - case DEBUG_KIND_FUNCTION: - if (t1->u.kfunction->varargs != t2->u.kfunction->varargs - || ! debug_type_samep (info, t1->u.kfunction->return_type, - t2->u.kfunction->return_type) - || ((t1->u.kfunction->arg_types == NULL) - != (t2->u.kfunction->arg_types == NULL))) - ret = false; - else if (t1->u.kfunction->arg_types == NULL) - ret = true; - else - { - struct debug_type **a1, **a2; - - a1 = t1->u.kfunction->arg_types; - a2 = t2->u.kfunction->arg_types; - while (*a1 != NULL && *a2 != NULL) - if (! debug_type_samep (info, *a1, *a2)) - break; - ret = *a1 == NULL && *a2 == NULL; - } - break; - - case DEBUG_KIND_REFERENCE: - ret = debug_type_samep (info, t1->u.kreference, t2->u.kreference); - break; - - case DEBUG_KIND_RANGE: - ret = (t1->u.krange->lower == t2->u.krange->lower - && t1->u.krange->upper == t2->u.krange->upper - && debug_type_samep (info, t1->u.krange->type, - t2->u.krange->type)); - - case DEBUG_KIND_ARRAY: - ret = (t1->u.karray->lower == t2->u.karray->lower - && t1->u.karray->upper == t2->u.karray->upper - && t1->u.karray->stringp == t2->u.karray->stringp - && debug_type_samep (info, t1->u.karray->element_type, - t2->u.karray->element_type)); - break; - - case DEBUG_KIND_SET: - ret = (t1->u.kset->bitstringp == t2->u.kset->bitstringp - && debug_type_samep (info, t1->u.kset->type, t2->u.kset->type)); - break; - - case DEBUG_KIND_OFFSET: - ret = (debug_type_samep (info, t1->u.koffset->base_type, - t2->u.koffset->base_type) - && debug_type_samep (info, t1->u.koffset->target_type, - t2->u.koffset->target_type)); - break; - - case DEBUG_KIND_METHOD: - if (t1->u.kmethod->varargs != t2->u.kmethod->varargs - || ! debug_type_samep (info, t1->u.kmethod->return_type, - t2->u.kmethod->return_type) - || ! debug_type_samep (info, t1->u.kmethod->domain_type, - t2->u.kmethod->domain_type) - || ((t1->u.kmethod->arg_types == NULL) - != (t2->u.kmethod->arg_types == NULL))) - ret = false; - else if (t1->u.kmethod->arg_types == NULL) - ret = true; - else - { - struct debug_type **a1, **a2; - - a1 = t1->u.kmethod->arg_types; - a2 = t2->u.kmethod->arg_types; - while (*a1 != NULL && *a2 != NULL) - if (! debug_type_samep (info, *a1, *a2)) - break; - ret = *a1 == NULL && *a2 == NULL; - } - break; - - case DEBUG_KIND_CONST: - ret = debug_type_samep (info, t1->u.kconst, t2->u.kconst); - break; - - case DEBUG_KIND_VOLATILE: - ret = debug_type_samep (info, t1->u.kvolatile, t2->u.kvolatile); - break; - - case DEBUG_KIND_NAMED: - case DEBUG_KIND_TAGGED: - ret = (strcmp (t1->u.knamed->name->name, t2->u.knamed->name->name) == 0 - && debug_type_samep (info, t1->u.knamed->type, - t2->u.knamed->type)); - break; - } - - info->compare_list = top.next; - - return ret; -} - -/* See if two classes are the same. This is a subroutine of - debug_type_samep. */ - -static boolean -debug_class_type_samep (info, t1, t2) - struct debug_handle *info; - struct debug_type *t1; - struct debug_type *t2; -{ - struct debug_class_type *c1, *c2; - - c1 = t1->u.kclass; - c2 = t2->u.kclass; - - if ((c1->fields == NULL) != (c2->fields == NULL) - || (c1->baseclasses == NULL) != (c2->baseclasses == NULL) - || (c1->methods == NULL) != (c2->methods == NULL) - || (c1->vptrbase == NULL) != (c2->vptrbase == NULL)) - return false; - - if (c1->fields != NULL) - { - struct debug_field **pf1, **pf2; - - for (pf1 = c1->fields, pf2 = c2->fields; - *pf1 != NULL && *pf2 != NULL; - pf1++, pf2++) - { - struct debug_field *f1, *f2; - - f1 = *pf1; - f2 = *pf2; - if (f1->name[0] != f2->name[0] - || f1->visibility != f2->visibility - || f1->static_member != f2->static_member) - return false; - if (f1->static_member) - { - if (strcmp (f1->u.s.physname, f2->u.s.physname) != 0) - return false; - } - else - { - if (f1->u.f.bitpos != f2->u.f.bitpos - || f1->u.f.bitsize != f2->u.f.bitsize) - return false; - } - /* We do the checks which require function calls last. We - don't require that the types of fields have the same - names, since that sometimes fails in the presence of - typedefs and we really don't care. */ - if (strcmp (f1->name, f2->name) != 0 - || ! debug_type_samep (info, - debug_get_real_type ((PTR) info, - f1->type), - debug_get_real_type ((PTR) info, - f2->type))) - return false; - } - if (*pf1 != NULL || *pf2 != NULL) - return false; - } - - if (c1->vptrbase != NULL) - { - if (! debug_type_samep (info, c1->vptrbase, c2->vptrbase)) - return false; - } - - if (c1->baseclasses != NULL) - { - struct debug_baseclass **pb1, **pb2; - - for (pb1 = c1->baseclasses, pb2 = c2->baseclasses; - *pb1 != NULL && *pb2 != NULL; - ++pb1, ++pb2) - { - struct debug_baseclass *b1, *b2; - - b1 = *pb1; - b2 = *pb2; - if (b1->bitpos != b2->bitpos - || b1->virtual != b2->virtual - || b1->visibility != b2->visibility - || ! debug_type_samep (info, b1->type, b2->type)) - return false; - } - if (*pb1 != NULL || *pb2 != NULL) - return false; - } - - if (c1->methods != NULL) - { - struct debug_method **pm1, **pm2; - - for (pm1 = c1->methods, pm2 = c2->methods; - *pm1 != NULL && *pm2 != NULL; - ++pm1, ++pm2) - { - struct debug_method *m1, *m2; - - m1 = *pm1; - m2 = *pm2; - if (m1->name[0] != m2->name[0] - || strcmp (m1->name, m2->name) != 0 - || (m1->variants == NULL) != (m2->variants == NULL)) - return false; - if (m1->variants == NULL) - { - struct debug_method_variant **pv1, **pv2; - - for (pv1 = m1->variants, pv2 = m2->variants; - *pv1 != NULL && *pv2 != NULL; - ++pv1, ++pv2) - { - struct debug_method_variant *v1, *v2; - - v1 = *pv1; - v2 = *pv2; - if (v1->physname[0] != v2->physname[0] - || v1->visibility != v2->visibility - || v1->constp != v2->constp - || v1->volatilep != v2->volatilep - || v1->voffset != v2->voffset - || (v1->context == NULL) != (v2->context == NULL) - || strcmp (v1->physname, v2->physname) != 0 - || ! debug_type_samep (info, v1->type, v2->type)) - return false; - if (v1->context != NULL) - { - if (! debug_type_samep (info, v1->context, - v2->context)) - return false; - } - } - if (*pv1 != NULL || *pv2 != NULL) - return false; - } - } - if (*pm1 != NULL || *pm2 != NULL) - return false; - } - - return true; -} diff --git a/pstack/debug.h b/pstack/debug.h deleted file mode 100644 index a4d3d8306cd..00000000000 --- a/pstack/debug.h +++ /dev/null @@ -1,798 +0,0 @@ -/* debug.h -- Describe generic debugging information. - Copyright (C) 1995, 1996 Free Software Foundation, Inc. - Written by Ian Lance Taylor . - - This file is part of GNU Binutils. - - 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; either version 2 of the License, or - (at your option) any later version. - - 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., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ - -#ifndef DEBUG_H -#define DEBUG_H - -/* This header file describes a generic debugging information format. - We may eventually have readers which convert different formats into - this generic format, and writers which write it out. The initial - impetus for this was writing a convertor from stabs to HP IEEE-695 - debugging format. */ - -/* Different kinds of types. */ - -enum debug_type_kind -{ - /* Not used. */ - DEBUG_KIND_ILLEGAL, - /* Indirect via a pointer. */ - DEBUG_KIND_INDIRECT, - /* Void. */ - DEBUG_KIND_VOID, - /* Integer. */ - DEBUG_KIND_INT, - /* Floating point. */ - DEBUG_KIND_FLOAT, - /* Complex. */ - DEBUG_KIND_COMPLEX, - /* Boolean. */ - DEBUG_KIND_BOOL, - /* Struct. */ - DEBUG_KIND_STRUCT, - /* Union. */ - DEBUG_KIND_UNION, - /* Class. */ - DEBUG_KIND_CLASS, - /* Union class (can this really happen?). */ - DEBUG_KIND_UNION_CLASS, - /* Enumeration type. */ - DEBUG_KIND_ENUM, - /* Pointer. */ - DEBUG_KIND_POINTER, - /* Function. */ - DEBUG_KIND_FUNCTION, - /* Reference. */ - DEBUG_KIND_REFERENCE, - /* Range. */ - DEBUG_KIND_RANGE, - /* Array. */ - DEBUG_KIND_ARRAY, - /* Set. */ - DEBUG_KIND_SET, - /* Based pointer. */ - DEBUG_KIND_OFFSET, - /* Method. */ - DEBUG_KIND_METHOD, - /* Const qualified type. */ - DEBUG_KIND_CONST, - /* Volatile qualified type. */ - DEBUG_KIND_VOLATILE, - /* Named type. */ - DEBUG_KIND_NAMED, - /* Tagged type. */ - DEBUG_KIND_TAGGED -}; - -/* Different kinds of variables. */ - -enum debug_var_kind -{ - /* Not used. */ - DEBUG_VAR_ILLEGAL, - /* A global variable. */ - DEBUG_GLOBAL, - /* A static variable. */ - DEBUG_STATIC, - /* A local static variable. */ - DEBUG_LOCAL_STATIC, - /* A local variable. */ - DEBUG_LOCAL, - /* A register variable. */ - DEBUG_REGISTER -}; - -/* Different kinds of function parameters. */ - -enum debug_parm_kind -{ - /* Not used. */ - DEBUG_PARM_ILLEGAL, - /* A stack based parameter. */ - DEBUG_PARM_STACK, - /* A register parameter. */ - DEBUG_PARM_REG, - /* A stack based reference parameter. */ - DEBUG_PARM_REFERENCE, - /* A register reference parameter. */ - DEBUG_PARM_REF_REG -}; - -/* Different kinds of visibility. */ - -enum debug_visibility -{ - /* A public field (e.g., a field in a C struct). */ - DEBUG_VISIBILITY_PUBLIC, - /* A protected field. */ - DEBUG_VISIBILITY_PROTECTED, - /* A private field. */ - DEBUG_VISIBILITY_PRIVATE, - /* A field which should be ignored. */ - DEBUG_VISIBILITY_IGNORE -}; - -/* A type. */ - -typedef struct debug_type *debug_type; - -#define DEBUG_TYPE_NULL ((debug_type) NULL) - -/* A field in a struct or union. */ - -typedef struct debug_field *debug_field; - -#define DEBUG_FIELD_NULL ((debug_field) NULL) - -/* A base class for an object. */ - -typedef struct debug_baseclass *debug_baseclass; - -#define DEBUG_BASECLASS_NULL ((debug_baseclass) NULL) - -/* A method of an object. */ - -typedef struct debug_method *debug_method; - -#define DEBUG_METHOD_NULL ((debug_method) NULL) - -/* The arguments to a method function of an object. These indicate - which method to run. */ - -typedef struct debug_method_variant *debug_method_variant; - -#define DEBUG_METHOD_VARIANT_NULL ((debug_method_variant) NULL) - -/* This structure is passed to debug_write. It holds function - pointers that debug_write will call based on the accumulated - debugging information. */ - -struct debug_write_fns -{ - /* This is called at the start of each new compilation unit with the - name of the main file in the new unit. */ - boolean (*start_compilation_unit) PARAMS ((PTR, const char *)); - - /* This is called at the start of each source file within a - compilation unit, before outputting any global information for - that file. The argument is the name of the file. */ - boolean (*start_source) PARAMS ((PTR, const char *)); - - /* Each writer must keep a stack of types. */ - - /* Push an empty type onto the type stack. This type can appear if - there is a reference to a type which is never defined. */ - boolean (*empty_type) PARAMS ((PTR)); - - /* Push a void type onto the type stack. */ - boolean (*void_type) PARAMS ((PTR)); - - /* Push an integer type onto the type stack, given the size and - whether it is unsigned. */ - boolean (*int_type) PARAMS ((PTR, unsigned int, boolean)); - - /* Push a floating type onto the type stack, given the size. */ - boolean (*float_type) PARAMS ((PTR, unsigned int)); - - /* Push a complex type onto the type stack, given the size. */ - boolean (*complex_type) PARAMS ((PTR, unsigned int)); - - /* Push a boolean type onto the type stack, given the size. */ - boolean (*bool_type) PARAMS ((PTR, unsigned int)); - - /* Push an enum type onto the type stack, given the tag, a NULL - terminated array of names and the associated values. If there is - no tag, the tag argument will be NULL. If this is an undefined - enum, the names and values arguments will be NULL. */ - boolean (*enum_type) PARAMS ((PTR, const char *, const char **, - bfd_signed_vma *)); - - /* Pop the top type on the type stack, and push a pointer to that - type onto the type stack. */ - boolean (*pointer_type) PARAMS ((PTR)); - - /* Push a function type onto the type stack. The second argument - indicates the number of argument types that have been pushed onto - the stack. If the number of argument types is passed as -1, then - the argument types of the function are unknown, and no types have - been pushed onto the stack. The third argument is true if the - function takes a variable number of arguments. The return type - of the function is pushed onto the type stack below the argument - types, if any. */ - boolean (*function_type) PARAMS ((PTR, int, boolean)); - - /* Pop the top type on the type stack, and push a reference to that - type onto the type stack. */ - boolean (*reference_type) PARAMS ((PTR)); - - /* Pop the top type on the type stack, and push a range of that type - with the given lower and upper bounds onto the type stack. */ - boolean (*range_type) PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma)); - - /* Push an array type onto the type stack. The top type on the type - stack is the range, and the next type on the type stack is the - element type. These should be popped before the array type is - pushed. The arguments are the lower bound, the upper bound, and - whether the array is a string. */ - boolean (*array_type) PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, - boolean)); - - /* Pop the top type on the type stack, and push a set of that type - onto the type stack. The argument indicates whether this set is - a bitstring. */ - boolean (*set_type) PARAMS ((PTR, boolean)); - - /* Push an offset type onto the type stack. The top type on the - type stack is the target type, and the next type on the type - stack is the base type. These should be popped before the offset - type is pushed. */ - boolean (*offset_type) PARAMS ((PTR)); - - /* Push a method type onto the type stack. If the second argument - is true, the top type on the stack is the class to which the - method belongs; otherwise, the class must be determined by the - class to which the method is attached. The third argument is the - number of argument types; these are pushed onto the type stack in - reverse order (the first type popped is the last argument to the - method). A value of -1 for the third argument means that no - argument information is available. The fourth argument is true - if the function takes a variable number of arguments. The next - type on the type stack below the domain and the argument types is - the return type of the method. All these types must be popped, - and then the method type must be pushed. */ - boolean (*method_type) PARAMS ((PTR, boolean, int, boolean)); - - /* Pop the top type off the type stack, and push a const qualified - version of that type onto the type stack. */ - boolean (*const_type) PARAMS ((PTR)); - - /* Pop the top type off the type stack, and push a volatile - qualified version of that type onto the type stack. */ - boolean (*volatile_type) PARAMS ((PTR)); - - /* Start building a struct. This is followed by calls to the - struct_field function, and finished by a call to the - end_struct_type function. The second argument is the tag; this - will be NULL if there isn't one. If the second argument is NULL, - the third argument is a constant identifying this struct for use - with tag_type. The fourth argument is true for a struct, false - for a union. The fifth argument is the size. If this is an - undefined struct or union, the size will be 0 and struct_field - will not be called before end_struct_type is called. */ - boolean (*start_struct_type) PARAMS ((PTR, const char *, unsigned int, - boolean, unsigned int)); - - /* Add a field to the struct type currently being built. The type - of the field should be popped off the type stack. The arguments - are the name, the bit position, the bit size (may be zero if the - field is not packed), and the visibility. */ - boolean (*struct_field) PARAMS ((PTR, const char *, bfd_vma, bfd_vma, - enum debug_visibility)); - - /* Finish building a struct, and push it onto the type stack. */ - boolean (*end_struct_type) PARAMS ((PTR)); - - /* Start building a class. This is followed by calls to several - functions: struct_field, class_static_member, class_baseclass, - class_start_method, class_method_variant, - class_static_method_variant, and class_end_method. The class is - finished by a call to end_class_type. The first five arguments - are the same as for start_struct_type. The sixth argument is - true if there is a virtual function table; if there is, the - seventh argument is true if the virtual function table can be - found in the type itself, and is false if the type of the object - holding the virtual function table should be popped from the type - stack. */ - boolean (*start_class_type) PARAMS ((PTR, const char *, unsigned int, - boolean, unsigned int, boolean, - boolean)); - - /* Add a static member to the class currently being built. The - arguments are the field name, the physical name, and the - visibility. The type must be popped off the type stack. */ - boolean (*class_static_member) PARAMS ((PTR, const char *, const char *, - enum debug_visibility)); - - /* Add a baseclass to the class currently being built. The type of - the baseclass must be popped off the type stack. The arguments - are the bit position, whether the class is virtual, and the - visibility. */ - boolean (*class_baseclass) PARAMS ((PTR, bfd_vma, boolean, - enum debug_visibility)); - - /* Start adding a method to the class currently being built. This - is followed by calls to class_method_variant and - class_static_method_variant to describe different variants of the - method which take different arguments. The method is finished - with a call to class_end_method. The argument is the method - name. */ - boolean (*class_start_method) PARAMS ((PTR, const char *)); - - /* Describe a variant to the class method currently being built. - The type of the variant must be popped off the type stack. The - second argument is the physical name of the function. The - following arguments are the visibility, whether the variant is - const, whether the variant is volatile, the offset in the virtual - function table, and whether the context is on the type stack - (below the variant type). */ - boolean (*class_method_variant) PARAMS ((PTR, const char *, - enum debug_visibility, - boolean, boolean, - bfd_vma, boolean)); - - /* Describe a static variant to the class method currently being - built. The arguments are the same as for class_method_variant, - except that the last two arguments are omitted. The type of the - variant must be popped off the type stack. */ - boolean (*class_static_method_variant) PARAMS ((PTR, const char *, - enum debug_visibility, - boolean, boolean)); - - /* Finish describing a class method. */ - boolean (*class_end_method) PARAMS ((PTR)); - - /* Finish describing a class, and push it onto the type stack. */ - boolean (*end_class_type) PARAMS ((PTR)); - - /* Push a type on the stack which was given a name by an earlier - call to typdef. */ - boolean (*typedef_type) PARAMS ((PTR, const char *)); - - /* Push a tagged type on the stack which was defined earlier. If - the second argument is not NULL, the type was defined by a call - to tag. If the second argument is NULL, the type was defined by - a call to start_struct_type or start_class_type with a tag of - NULL and the number of the third argument. Either way, the - fourth argument is the tag kind. Note that this may be called - for a struct (class) being defined, in between the call to - start_struct_type (start_class_type) and the call to - end_struct_type (end_class_type). */ - boolean (*tag_type) PARAMS ((PTR, const char *, unsigned int, - enum debug_type_kind)); - - /* Pop the type stack, and typedef it to the given name. */ - boolean (*typdef) PARAMS ((PTR, const char *)); - - /* Pop the type stack, and declare it as a tagged struct or union or - enum or whatever. The tag passed down here is redundant, since - was also passed when enum_type, start_struct_type, or - start_class_type was called. */ - boolean (*tag) PARAMS ((PTR, const char *)); - - /* This is called to record a named integer constant. */ - boolean (*int_constant) PARAMS ((PTR, const char *, bfd_vma)); - - /* This is called to record a named floating point constant. */ - boolean (*float_constant) PARAMS ((PTR, const char *, double)); - - /* This is called to record a typed integer constant. The type is - popped off the type stack. */ - boolean (*typed_constant) PARAMS ((PTR, const char *, bfd_vma)); - - /* This is called to record a variable. The type is popped off the - type stack. */ - boolean (*variable) PARAMS ((PTR, const char *, enum debug_var_kind, - bfd_vma)); - - /* Start writing out a function. The return type must be popped off - the stack. The boolean is true if the function is global. This - is followed by calls to function_parameter, followed by block - information. */ - boolean (*start_function) PARAMS ((PTR, const char *, boolean)); - - /* Record a function parameter for the current function. The type - must be popped off the stack. */ - boolean (*function_parameter) PARAMS ((PTR, const char *, - enum debug_parm_kind, bfd_vma)); - - /* Start writing out a block. There is at least one top level block - per function. Blocks may be nested. The argument is the - starting address of the block. */ - boolean (*start_block) PARAMS ((PTR, bfd_vma)); - - /* Finish writing out a block. The argument is the ending address - of the block. */ - boolean (*end_block) PARAMS ((PTR, bfd_vma)); - - /* Finish writing out a function. */ - boolean (*end_function) PARAMS ((PTR)); - - /* Record line number information for the current compilation unit. */ - boolean (*lineno) PARAMS ((PTR, const char *, unsigned long, bfd_vma)); -}; - -/* Exported functions. */ - -/* The first argument to most of these functions is a handle. This - handle is returned by the debug_init function. The purpose of the - handle is to permit the debugging routines to not use static - variables, and hence to be reentrant. This would be useful for a - program which wanted to handle two executables simultaneously. */ - -/* Return a debugging handle. */ - -extern PTR debug_init PARAMS ((void)); - -/* Set the source filename. This implicitly starts a new compilation - unit. */ - -extern boolean debug_set_filename PARAMS ((PTR, const char *)); - -/* Change source files to the given file name. This is used for - include files in a single compilation unit. */ - -extern boolean debug_start_source PARAMS ((PTR, const char *)); - -/* Record a function definition. This implicitly starts a function - block. The debug_type argument is the type of the return value. - The boolean indicates whether the function is globally visible. - The bfd_vma is the address of the start of the function. Currently - the parameter types are specified by calls to - debug_record_parameter. */ - -extern boolean debug_record_function - PARAMS ((PTR, const char *, debug_type, boolean, bfd_vma)); - -/* Record a parameter for the current function. */ - -extern boolean debug_record_parameter - PARAMS ((PTR, const char *, debug_type, enum debug_parm_kind, bfd_vma)); - -/* End a function definition. The argument is the address where the - function ends. */ - -extern boolean debug_end_function PARAMS ((PTR, bfd_vma)); - -/* Start a block in a function. All local information will be - recorded in this block, until the matching call to debug_end_block. - debug_start_block and debug_end_block may be nested. The argument - is the address at which this block starts. */ - -extern boolean debug_start_block PARAMS ((PTR, bfd_vma)); - -/* Finish a block in a function. This matches the call to - debug_start_block. The argument is the address at which this block - ends. */ - -extern boolean debug_end_block PARAMS ((PTR, bfd_vma)); - -/* Associate a line number in the current source file with a given - address. */ - -extern boolean debug_record_line PARAMS ((PTR, unsigned long, bfd_vma)); - -/* Start a named common block. This is a block of variables that may - move in memory. */ - -extern boolean debug_start_common_block PARAMS ((PTR, const char *)); - -/* End a named common block. */ - -extern boolean debug_end_common_block PARAMS ((PTR, const char *)); - -/* Record a named integer constant. */ - -extern boolean debug_record_int_const PARAMS ((PTR, const char *, bfd_vma)); - -/* Record a named floating point constant. */ - -extern boolean debug_record_float_const PARAMS ((PTR, const char *, double)); - -/* Record a typed constant with an integral value. */ - -extern boolean debug_record_typed_const - PARAMS ((PTR, const char *, debug_type, bfd_vma)); - -/* Record a label. */ - -extern boolean debug_record_label - PARAMS ((PTR, const char *, debug_type, bfd_vma)); - -/* Record a variable. */ - -extern boolean debug_record_variable - PARAMS ((PTR, const char *, debug_type, enum debug_var_kind, bfd_vma)); - -/* Make an indirect type. The first argument is a pointer to the - location where the real type will be placed. The second argument - is the type tag, if there is one; this may be NULL; the only - purpose of this argument is so that debug_get_type_name can return - something useful. This function may be used when a type is - referenced before it is defined. */ - -extern debug_type debug_make_indirect_type - PARAMS ((PTR, debug_type *, const char *)); - -/* Make a void type. */ - -extern debug_type debug_make_void_type PARAMS ((PTR)); - -/* Make an integer type of a given size. The boolean argument is true - if the integer is unsigned. */ - -extern debug_type debug_make_int_type PARAMS ((PTR, unsigned int, boolean)); - -/* Make a floating point type of a given size. FIXME: On some - platforms, like an Alpha, you probably need to be able to specify - the format. */ - -extern debug_type debug_make_float_type PARAMS ((PTR, unsigned int)); - -/* Make a boolean type of a given size. */ - -extern debug_type debug_make_bool_type PARAMS ((PTR, unsigned int)); - -/* Make a complex type of a given size. */ - -extern debug_type debug_make_complex_type PARAMS ((PTR, unsigned int)); - -/* Make a structure type. The second argument is true for a struct, - false for a union. The third argument is the size of the struct. - The fourth argument is a NULL terminated array of fields. */ - -extern debug_type debug_make_struct_type - PARAMS ((PTR, boolean, bfd_vma, debug_field *)); - -/* Make an object type. The first three arguments after the handle - are the same as for debug_make_struct_type. The next arguments are - a NULL terminated array of base classes, a NULL terminated array of - methods, the type of the object holding the virtual function table - if it is not this object, and a boolean which is true if this - object has its own virtual function table. */ - -extern debug_type debug_make_object_type - PARAMS ((PTR, boolean, bfd_vma, debug_field *, debug_baseclass *, - debug_method *, debug_type, boolean)); - -/* Make an enumeration type. The arguments are a null terminated - array of strings, and an array of corresponding values. */ - -extern debug_type debug_make_enum_type - PARAMS ((PTR, const char **, bfd_signed_vma *)); - -/* Make a pointer to a given type. */ - -extern debug_type debug_make_pointer_type - PARAMS ((PTR, debug_type)); - -/* Make a function type. The second argument is the return type. The - third argument is a NULL terminated array of argument types. The - fourth argument is true if the function takes a variable number of - arguments. If the third argument is NULL, then the argument types - are unknown. */ - -extern debug_type debug_make_function_type - PARAMS ((PTR, debug_type, debug_type *, boolean)); - -/* Make a reference to a given type. */ - -extern debug_type debug_make_reference_type PARAMS ((PTR, debug_type)); - -/* Make a range of a given type from a lower to an upper bound. */ - -extern debug_type debug_make_range_type - PARAMS ((PTR, debug_type, bfd_signed_vma, bfd_signed_vma)); - -/* Make an array type. The second argument is the type of an element - of the array. The third argument is the type of a range of the - array. The fourth and fifth argument are the lower and upper - bounds, respectively (if the bounds are not known, lower should be - 0 and upper should be -1). The sixth argument is true if this - array is actually a string, as in C. */ - -extern debug_type debug_make_array_type - PARAMS ((PTR, debug_type, debug_type, bfd_signed_vma, bfd_signed_vma, - boolean)); - -/* Make a set of a given type. For example, a Pascal set type. The - boolean argument is true if this set is actually a bitstring, as in - CHILL. */ - -extern debug_type debug_make_set_type PARAMS ((PTR, debug_type, boolean)); - -/* Make a type for a pointer which is relative to an object. The - second argument is the type of the object to which the pointer is - relative. The third argument is the type that the pointer points - to. */ - -extern debug_type debug_make_offset_type - PARAMS ((PTR, debug_type, debug_type)); - -/* Make a type for a method function. The second argument is the - return type. The third argument is the domain. The fourth - argument is a NULL terminated array of argument types. The fifth - argument is true if the function takes a variable number of - arguments, in which case the array of argument types indicates the - types of the first arguments. The domain and the argument array - may be NULL, in which case this is a stub method and that - information is not available. Stabs debugging uses this, and gets - the argument types from the mangled name. */ - -extern debug_type debug_make_method_type - PARAMS ((PTR, debug_type, debug_type, debug_type *, boolean)); - -/* Make a const qualified version of a given type. */ - -extern debug_type debug_make_const_type PARAMS ((PTR, debug_type)); - -/* Make a volatile qualified version of a given type. */ - -extern debug_type debug_make_volatile_type PARAMS ((PTR, debug_type)); - -/* Make an undefined tagged type. For example, a struct which has - been mentioned, but not defined. */ - -extern debug_type debug_make_undefined_tagged_type - PARAMS ((PTR, const char *, enum debug_type_kind)); - -/* Make a base class for an object. The second argument is the base - class type. The third argument is the bit position of this base - class in the object. The fourth argument is whether this is a - virtual class. The fifth argument is the visibility of the base - class. */ - -extern debug_baseclass debug_make_baseclass - PARAMS ((PTR, debug_type, bfd_vma, boolean, enum debug_visibility)); - -/* Make a field for a struct. The second argument is the name. The - third argument is the type of the field. The fourth argument is - the bit position of the field. The fifth argument is the size of - the field (it may be zero). The sixth argument is the visibility - of the field. */ - -extern debug_field debug_make_field - PARAMS ((PTR, const char *, debug_type, bfd_vma, bfd_vma, - enum debug_visibility)); - -/* Make a static member of an object. The second argument is the - name. The third argument is the type of the member. The fourth - argument is the physical name of the member (i.e., the name as a - global variable). The fifth argument is the visibility of the - member. */ - -extern debug_field debug_make_static_member - PARAMS ((PTR, const char *, debug_type, const char *, - enum debug_visibility)); - -/* Make a method. The second argument is the name, and the third - argument is a NULL terminated array of method variants. Each - method variant is a method with this name but with different - argument types. */ - -extern debug_method debug_make_method - PARAMS ((PTR, const char *, debug_method_variant *)); - -/* Make a method variant. The second argument is the physical name of - the function. The third argument is the type of the function, - probably constructed by debug_make_method_type. The fourth - argument is the visibility. The fifth argument is whether this is - a const function. The sixth argument is whether this is a volatile - function. The seventh argument is the index in the virtual - function table, if any. The eighth argument is the virtual - function context. */ - -extern debug_method_variant debug_make_method_variant - PARAMS ((PTR, const char *, debug_type, enum debug_visibility, boolean, - boolean, bfd_vma, debug_type)); - -/* Make a static method argument. The arguments are the same as for - debug_make_method_variant, except that the last two are omitted - since a static method can not also be virtual. */ - -extern debug_method_variant debug_make_static_method_variant - PARAMS ((PTR, const char *, debug_type, enum debug_visibility, boolean, - boolean)); - -/* Name a type. This returns a new type with an attached name. */ - -extern debug_type debug_name_type PARAMS ((PTR, const char *, debug_type)); - -/* Give a tag to a type, such as a struct or union. This returns a - new type with an attached tag. */ - -extern debug_type debug_tag_type PARAMS ((PTR, const char *, debug_type)); - -/* Record the size of a given type. */ - -extern boolean debug_record_type_size PARAMS ((PTR, debug_type, unsigned int)); - -/* Find a named type. */ - -extern debug_type debug_find_named_type PARAMS ((PTR, const char *)); - -/* Find a tagged type. */ - -extern debug_type debug_find_tagged_type - PARAMS ((PTR, const char *, enum debug_type_kind)); - -/* Get the kind of a type. */ - -extern enum debug_type_kind debug_get_type_kind PARAMS ((PTR, debug_type)); - -/* Get the name of a type. */ - -extern const char *debug_get_type_name PARAMS ((PTR, debug_type)); - -/* Get the size of a type. */ - -extern bfd_vma debug_get_type_size PARAMS ((PTR, debug_type)); - -/* Get the return type of a function or method type. */ - -extern debug_type debug_get_return_type PARAMS ((PTR, debug_type)); - -/* Get the NULL terminated array of parameter types for a function or - method type (actually, parameter types are not currently stored for - function types). This may be used to determine whether a method - type is a stub method or not. The last argument points to a - boolean which is set to true if the function takes a variable - number of arguments. */ - -extern const debug_type *debug_get_parameter_types PARAMS ((PTR, - debug_type, - boolean *)); - -/* Get the target type of a pointer or reference or const or volatile - type. */ - -extern debug_type debug_get_target_type PARAMS ((PTR, debug_type)); - -/* Get the NULL terminated array of fields for a struct, union, or - class. */ - -extern const debug_field *debug_get_fields PARAMS ((PTR, debug_type)); - -/* Get the type of a field. */ - -extern debug_type debug_get_field_type PARAMS ((PTR, debug_field)); - -/* Get the name of a field. */ - -extern const char *debug_get_field_name PARAMS ((PTR, debug_field)); - -/* Get the bit position of a field within the containing structure. - If the field is a static member, this will return (bfd_vma) -1. */ - -extern bfd_vma debug_get_field_bitpos PARAMS ((PTR, debug_field)); - -/* Get the bit size of a field. If the field is a static member, this - will return (bfd_vma) -1. */ - -extern bfd_vma debug_get_field_bitsize PARAMS ((PTR, debug_field)); - -/* Get the visibility of a field. */ - -extern enum debug_visibility debug_get_field_visibility - PARAMS ((PTR, debug_field)); - -/* Get the physical name of a field, if it is a static member. If the - field is not a static member, this will return NULL. */ - -extern const char *debug_get_field_physname PARAMS ((PTR, debug_field)); - -/* Write out the recorded debugging information. This takes a set of - function pointers which are called to do the actual writing. The - first PTR is the debugging handle. The second PTR is a handle - which is passed to the functions. */ - -extern boolean debug_write PARAMS ((PTR, const struct debug_write_fns *, PTR)); - -#endif /* DEBUG_H */ diff --git a/pstack/demangle.h b/pstack/demangle.h deleted file mode 100644 index a961436ca77..00000000000 --- a/pstack/demangle.h +++ /dev/null @@ -1,90 +0,0 @@ -/* Defs for interface to demanglers. - Copyright 1992, 1995, 1996 Free Software Foundation, Inc. - - 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; either version 2, or (at your option) - any later version. - - 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., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - - -#if !defined (DEMANGLE_H) -#define DEMANGLE_H - -#ifdef IN_GCC -#include "gansidecl.h" -#define PARAMS(ARGS) PROTO(ARGS) -#else /* ! IN_GCC */ -#include -#endif /* IN_GCC */ - -/* Options passed to cplus_demangle (in 2nd parameter). */ - -#define DMGL_NO_OPTS 0 /* For readability... */ -#define DMGL_PARAMS (1 << 0) /* Include function args */ -#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ -#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */ - -#define DMGL_AUTO (1 << 8) -#define DMGL_GNU (1 << 9) -#define DMGL_LUCID (1 << 10) -#define DMGL_ARM (1 << 11) -/* If none of these are set, use 'current_demangling_style' as the default. */ -#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM) - -/* Enumeration of possible demangling styles. - - Lucid and ARM styles are still kept logically distinct, even though - they now both behave identically. The resulting style is actual the - union of both. I.E. either style recognizes both "__pt__" and "__rf__" - for operator "->", even though the first is lucid style and the second - is ARM style. (FIXME?) */ - -extern enum demangling_styles -{ - unknown_demangling = 0, - auto_demangling = DMGL_AUTO, - gnu_demangling = DMGL_GNU, - lucid_demangling = DMGL_LUCID, - arm_demangling = DMGL_ARM -} current_demangling_style; - -/* Define string names for the various demangling styles. */ - -#define AUTO_DEMANGLING_STYLE_STRING "auto" -#define GNU_DEMANGLING_STYLE_STRING "gnu" -#define LUCID_DEMANGLING_STYLE_STRING "lucid" -#define ARM_DEMANGLING_STYLE_STRING "arm" - -/* Some macros to test what demangling style is active. */ - -#define CURRENT_DEMANGLING_STYLE current_demangling_style -#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO) -#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU) -#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID) -#define ARM_DEMANGLING (CURRENT_DEMANGLING_STYLE & DMGL_ARM) - -extern char * -cplus_demangle PARAMS ((const char *mangled, int options)); - -extern int -cplus_demangle_opname PARAMS ((const char *opname, char *result, int options)); - -extern const char * -cplus_mangle_opname PARAMS ((const char *opname, int options)); - -/* Note: This sets global state. FIXME if you care about multi-threading. */ - -extern void -set_cplus_marker_for_demangling PARAMS ((int ch)); - -#endif /* DEMANGLE_H */ diff --git a/pstack/filemode.c b/pstack/filemode.c deleted file mode 100644 index 58b52ba7489..00000000000 --- a/pstack/filemode.c +++ /dev/null @@ -1,266 +0,0 @@ -/* filemode.c -- make a string describing file modes - Copyright (C) 1985, 90, 91, 94, 95, 1997 Free Software Foundation, Inc. - - 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; either version 2, or (at your option) - any later version. - - 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., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ - -#include "bfd.h" -#include "bucomm.h" - -static char ftypelet PARAMS ((unsigned long)); -static void setst PARAMS ((unsigned long, char *)); - -/* filemodestring - fill in string STR with an ls-style ASCII - representation of the st_mode field of file stats block STATP. - 10 characters are stored in STR; no terminating null is added. - The characters stored in STR are: - - 0 File type. 'd' for directory, 'c' for character - special, 'b' for block special, 'm' for multiplex, - 'l' for symbolic link, 's' for socket, 'p' for fifo, - '-' for any other file type - - 1 'r' if the owner may read, '-' otherwise. - - 2 'w' if the owner may write, '-' otherwise. - - 3 'x' if the owner may execute, 's' if the file is - set-user-id, '-' otherwise. - 'S' if the file is set-user-id, but the execute - bit isn't set. - - 4 'r' if group members may read, '-' otherwise. - - 5 'w' if group members may write, '-' otherwise. - - 6 'x' if group members may execute, 's' if the file is - set-group-id, '-' otherwise. - 'S' if it is set-group-id but not executable. - - 7 'r' if any user may read, '-' otherwise. - - 8 'w' if any user may write, '-' otherwise. - - 9 'x' if any user may execute, 't' if the file is "sticky" - (will be retained in swap space after execution), '-' - otherwise. - 'T' if the file is sticky but not executable. */ - -#if 0 - -/* This is not used; only mode_string is used. */ - -void -filemodestring (statp, str) - struct stat *statp; - char *str; -{ - mode_string ((unsigned long) statp->st_mode, str); -} - -#endif - -/* Get definitions for the file permission bits. */ - -#ifndef S_IRWXU -#define S_IRWXU 0700 -#endif -#ifndef S_IRUSR -#define S_IRUSR 0400 -#endif -#ifndef S_IWUSR -#define S_IWUSR 0200 -#endif -#ifndef S_IXUSR -#define S_IXUSR 0100 -#endif - -#ifndef S_IRWXG -#define S_IRWXG 0070 -#endif -#ifndef S_IRGRP -#define S_IRGRP 0040 -#endif -#ifndef S_IWGRP -#define S_IWGRP 0020 -#endif -#ifndef S_IXGRP -#define S_IXGRP 0010 -#endif - -#ifndef S_IRWXO -#define S_IRWXO 0007 -#endif -#ifndef S_IROTH -#define S_IROTH 0004 -#endif -#ifndef S_IWOTH -#define S_IWOTH 0002 -#endif -#ifndef S_IXOTH -#define S_IXOTH 0001 -#endif - -/* Like filemodestring, but only the relevant part of the `struct stat' - is given as an argument. */ - -void -mode_string (mode, str) - unsigned long mode; - char *str; -{ - str[0] = ftypelet ((unsigned long) mode); - str[1] = (mode & S_IRUSR) != 0 ? 'r' : '-'; - str[2] = (mode & S_IWUSR) != 0 ? 'w' : '-'; - str[3] = (mode & S_IXUSR) != 0 ? 'x' : '-'; - str[4] = (mode & S_IRGRP) != 0 ? 'r' : '-'; - str[5] = (mode & S_IWGRP) != 0 ? 'w' : '-'; - str[6] = (mode & S_IXGRP) != 0 ? 'x' : '-'; - str[7] = (mode & S_IROTH) != 0 ? 'r' : '-'; - str[8] = (mode & S_IWOTH) != 0 ? 'w' : '-'; - str[9] = (mode & S_IXOTH) != 0 ? 'x' : '-'; - setst ((unsigned long) mode, str); -} - -/* Return a character indicating the type of file described by - file mode BITS: - 'd' for directories - 'b' for block special files - 'c' for character special files - 'm' for multiplexor files - 'l' for symbolic links - 's' for sockets - 'p' for fifos - '-' for any other file type. */ - -#ifndef S_ISDIR -#ifdef S_IFDIR -#define S_ISDIR(i) (((i) & S_IFMT) == S_IFDIR) -#else /* ! defined (S_IFDIR) */ -#define S_ISDIR(i) (((i) & 0170000) == 040000) -#endif /* ! defined (S_IFDIR) */ -#endif /* ! defined (S_ISDIR) */ - -#ifndef S_ISBLK -#ifdef S_IFBLK -#define S_ISBLK(i) (((i) & S_IFMT) == S_IFBLK) -#else /* ! defined (S_IFBLK) */ -#define S_ISBLK(i) 0 -#endif /* ! defined (S_IFBLK) */ -#endif /* ! defined (S_ISBLK) */ - -#ifndef S_ISCHR -#ifdef S_IFCHR -#define S_ISCHR(i) (((i) & S_IFMT) == S_IFCHR) -#else /* ! defined (S_IFCHR) */ -#define S_ISCHR(i) 0 -#endif /* ! defined (S_IFCHR) */ -#endif /* ! defined (S_ISCHR) */ - -#ifndef S_ISFIFO -#ifdef S_IFIFO -#define S_ISFIFO(i) (((i) & S_IFMT) == S_IFIFO) -#else /* ! defined (S_IFIFO) */ -#define S_ISFIFO(i) 0 -#endif /* ! defined (S_IFIFO) */ -#endif /* ! defined (S_ISFIFO) */ - -#ifndef S_ISSOCK -#ifdef S_IFSOCK -#define S_ISSOCK(i) (((i) & S_IFMT) == S_IFSOCK) -#else /* ! defined (S_IFSOCK) */ -#define S_ISSOCK(i) 0 -#endif /* ! defined (S_IFSOCK) */ -#endif /* ! defined (S_ISSOCK) */ - -#ifndef S_ISLNK -#ifdef S_IFLNK -#define S_ISLNK(i) (((i) & S_IFMT) == S_IFLNK) -#else /* ! defined (S_IFLNK) */ -#define S_ISLNK(i) 0 -#endif /* ! defined (S_IFLNK) */ -#endif /* ! defined (S_ISLNK) */ - -static char -ftypelet (bits) - unsigned long bits; -{ - if (S_ISDIR (bits)) - return 'd'; - if (S_ISLNK (bits)) - return 'l'; - if (S_ISBLK (bits)) - return 'b'; - if (S_ISCHR (bits)) - return 'c'; - if (S_ISSOCK (bits)) - return 's'; - if (S_ISFIFO (bits)) - return 'p'; - -#ifdef S_IFMT -#ifdef S_IFMPC - if ((bits & S_IFMT) == S_IFMPC - || (bits & S_IFMT) == S_IFMPB) - return 'm'; -#endif -#ifdef S_IFNWK - if ((bits & S_IFMT) == S_IFNWK) - return 'n'; -#endif -#endif - - return '-'; -} - -/* Set the 's' and 't' flags in file attributes string CHARS, - according to the file mode BITS. */ - -static void -setst (bits, chars) - unsigned long bits; - char *chars; -{ -#ifdef S_ISUID - if (bits & S_ISUID) - { - if (chars[3] != 'x') - /* Set-uid, but not executable by owner. */ - chars[3] = 'S'; - else - chars[3] = 's'; - } -#endif -#ifdef S_ISGID - if (bits & S_ISGID) - { - if (chars[6] != 'x') - /* Set-gid, but not executable by group. */ - chars[6] = 'S'; - else - chars[6] = 's'; - } -#endif -#ifdef S_ISVTX - if (bits & S_ISVTX) - { - if (chars[9] != 'x') - /* Sticky, but not executable by others. */ - chars[9] = 'T'; - else - chars[9] = 't'; - } -#endif -} diff --git a/pstack/ieee.c b/pstack/ieee.c deleted file mode 100644 index 8084656a5ef..00000000000 --- a/pstack/ieee.c +++ /dev/null @@ -1,7602 +0,0 @@ -/* ieee.c -- Read and write IEEE-695 debugging information. - Copyright (C) 1996 Free Software Foundation, Inc. - Written by Ian Lance Taylor . - - This file is part of GNU Binutils. - - 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; either version 2 of the License, or - (at your option) any later version. - - 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., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ - -/* This file reads and writes IEEE-695 debugging information. */ - -#include -#include - -#include -#include "ieee.h" -#include "bucomm.h" -#include -#include "debug.h" -#include "budbg.h" - -/* This structure holds an entry on the block stack. */ - -struct ieee_block -{ - /* The kind of block. */ - int kind; - /* The source file name, for a BB5 block. */ - const char *filename; - /* The index of the function type, for a BB4 or BB6 block. */ - unsigned int fnindx; - /* True if this function is being skipped. */ - boolean skip; -}; - -/* This structure is the block stack. */ - -#define BLOCKSTACK_SIZE (16) - -struct ieee_blockstack -{ - /* The stack pointer. */ - struct ieee_block *bsp; - /* The stack. */ - struct ieee_block stack[BLOCKSTACK_SIZE]; -}; - -/* This structure holds information for a variable. */ - -struct ieee_var -{ - /* Start of name. */ - const char *name; - /* Length of name. */ - unsigned long namlen; - /* Type. */ - debug_type type; - /* Slot if we make an indirect type. */ - debug_type *pslot; - /* Kind of variable or function. */ - enum - { - IEEE_UNKNOWN, - IEEE_EXTERNAL, - IEEE_GLOBAL, - IEEE_STATIC, - IEEE_LOCAL, - IEEE_FUNCTION - } kind; -}; - -/* This structure holds all the variables. */ - -struct ieee_vars -{ - /* Number of slots allocated. */ - unsigned int alloc; - /* Variables. */ - struct ieee_var *vars; -}; - -/* This structure holds information for a type. We need this because - we don't want to represent bitfields as real types. */ - -struct ieee_type -{ - /* Type. */ - debug_type type; - /* Slot if this is type is referenced before it is defined. */ - debug_type *pslot; - /* Slots for arguments if we make indirect types for them. */ - debug_type *arg_slots; - /* If this is a bitfield, this is the size in bits. If this is not - a bitfield, this is zero. */ - unsigned long bitsize; -}; - -/* This structure holds all the type information. */ - -struct ieee_types -{ - /* Number of slots allocated. */ - unsigned int alloc; - /* Types. */ - struct ieee_type *types; - /* Builtin types. */ -#define BUILTIN_TYPE_COUNT (60) - debug_type builtins[BUILTIN_TYPE_COUNT]; -}; - -/* This structure holds a linked last of structs with their tag names, - so that we can convert them to C++ classes if necessary. */ - -struct ieee_tag -{ - /* Next tag. */ - struct ieee_tag *next; - /* This tag name. */ - const char *name; - /* The type of the tag. */ - debug_type type; - /* The tagged type is an indirect type pointing at this slot. */ - debug_type slot; - /* This is an array of slots used when a field type is converted - into a indirect type, in case it needs to be later converted into - a reference type. */ - debug_type *fslots; -}; - -/* This structure holds the information we pass around to the parsing - functions. */ - -struct ieee_info -{ - /* The debugging handle. */ - PTR dhandle; - /* The BFD. */ - bfd *abfd; - /* The start of the bytes to be parsed. */ - const bfd_byte *bytes; - /* The end of the bytes to be parsed. */ - const bfd_byte *pend; - /* The block stack. */ - struct ieee_blockstack blockstack; - /* Whether we have seen a BB1 or BB2. */ - boolean saw_filename; - /* The variables. */ - struct ieee_vars vars; - /* The global variables, after a global typedef block. */ - struct ieee_vars *global_vars; - /* The types. */ - struct ieee_types types; - /* The global types, after a global typedef block. */ - struct ieee_types *global_types; - /* The list of tagged structs. */ - struct ieee_tag *tags; -}; - -/* Basic builtin types, not including the pointers. */ - -enum builtin_types -{ - builtin_unknown = 0, - builtin_void = 1, - builtin_signed_char = 2, - builtin_unsigned_char = 3, - builtin_signed_short_int = 4, - builtin_unsigned_short_int = 5, - builtin_signed_long = 6, - builtin_unsigned_long = 7, - builtin_signed_long_long = 8, - builtin_unsigned_long_long = 9, - builtin_float = 10, - builtin_double = 11, - builtin_long_double = 12, - builtin_long_long_double = 13, - builtin_quoted_string = 14, - builtin_instruction_address = 15, - builtin_int = 16, - builtin_unsigned = 17, - builtin_unsigned_int = 18, - builtin_char = 19, - builtin_long = 20, - builtin_short = 21, - builtin_unsigned_short = 22, - builtin_short_int = 23, - builtin_signed_short = 24, - builtin_bcd_float = 25 -}; - -/* These are the values found in the derivation flags of a 'b' - component record of a 'T' type extension record in a C++ pmisc - record. These are bitmasks. */ - -/* Set for a private base class, clear for a public base class. - Protected base classes are not supported. */ -#define BASEFLAGS_PRIVATE (0x1) -/* Set for a virtual base class. */ -#define BASEFLAGS_VIRTUAL (0x2) -/* Set for a friend class, clear for a base class. */ -#define BASEFLAGS_FRIEND (0x10) - -/* These are the values found in the specs flags of a 'd', 'm', or 'v' - component record of a 'T' type extension record in a C++ pmisc - record. The same flags are used for a 'M' record in a C++ pmisc - record. */ - -/* The lower two bits hold visibility information. */ -#define CXXFLAGS_VISIBILITY (0x3) -/* This value in the lower two bits indicates a public member. */ -#define CXXFLAGS_VISIBILITY_PUBLIC (0x0) -/* This value in the lower two bits indicates a private member. */ -#define CXXFLAGS_VISIBILITY_PRIVATE (0x1) -/* This value in the lower two bits indicates a protected member. */ -#define CXXFLAGS_VISIBILITY_PROTECTED (0x2) -/* Set for a static member. */ -#define CXXFLAGS_STATIC (0x4) -/* Set for a virtual override. */ -#define CXXFLAGS_OVERRIDE (0x8) -/* Set for a friend function. */ -#define CXXFLAGS_FRIEND (0x10) -/* Set for a const function. */ -#define CXXFLAGS_CONST (0x20) -/* Set for a volatile function. */ -#define CXXFLAGS_VOLATILE (0x40) -/* Set for an overloaded function. */ -#define CXXFLAGS_OVERLOADED (0x80) -/* Set for an operator function. */ -#define CXXFLAGS_OPERATOR (0x100) -/* Set for a constructor or destructor. */ -#define CXXFLAGS_CTORDTOR (0x400) -/* Set for a constructor. */ -#define CXXFLAGS_CTOR (0x200) -/* Set for an inline function. */ -#define CXXFLAGS_INLINE (0x800) - -/* Local functions. */ - -static void ieee_error - PARAMS ((struct ieee_info *, const bfd_byte *, const char *)); -static void ieee_eof PARAMS ((struct ieee_info *)); -static char *savestring PARAMS ((const char *, unsigned long)); -static boolean ieee_read_number - PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *)); -static boolean ieee_read_optional_number - PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *, boolean *)); -static boolean ieee_read_id - PARAMS ((struct ieee_info *, const bfd_byte **, const char **, - unsigned long *)); -static boolean ieee_read_optional_id - PARAMS ((struct ieee_info *, const bfd_byte **, const char **, - unsigned long *, boolean *)); -static boolean ieee_read_expression - PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *)); -static debug_type ieee_builtin_type - PARAMS ((struct ieee_info *, const bfd_byte *, unsigned int)); -static boolean ieee_alloc_type - PARAMS ((struct ieee_info *, unsigned int, boolean)); -static boolean ieee_read_type_index - PARAMS ((struct ieee_info *, const bfd_byte **, debug_type *)); -static int ieee_regno_to_genreg PARAMS ((bfd *, int)); -static int ieee_genreg_to_regno PARAMS ((bfd *, int)); -static boolean parse_ieee_bb PARAMS ((struct ieee_info *, const bfd_byte **)); -static boolean parse_ieee_be PARAMS ((struct ieee_info *, const bfd_byte **)); -static boolean parse_ieee_nn PARAMS ((struct ieee_info *, const bfd_byte **)); -static boolean parse_ieee_ty PARAMS ((struct ieee_info *, const bfd_byte **)); -static boolean parse_ieee_atn PARAMS ((struct ieee_info *, const bfd_byte **)); -static boolean ieee_read_cxx_misc - PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long)); -static boolean ieee_read_cxx_class - PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long)); -static boolean ieee_read_cxx_defaults - PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long)); -static boolean ieee_read_reference - PARAMS ((struct ieee_info *, const bfd_byte **)); -static boolean ieee_require_asn - PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *)); -static boolean ieee_require_atn65 - PARAMS ((struct ieee_info *, const bfd_byte **, const char **, - unsigned long *)); - -/* Report an error in the IEEE debugging information. */ - -static void -ieee_error (info, p, s) - struct ieee_info *info; - const bfd_byte *p; - const char *s; -{ - if (p != NULL) - fprintf (stderr, "%s: 0x%lx: %s (0x%x)\n", bfd_get_filename (info->abfd), - (unsigned long) (p - info->bytes), s, *p); - else - fprintf (stderr, "%s: %s\n", bfd_get_filename (info->abfd), s); -} - -/* Report an unexpected EOF in the IEEE debugging information. */ - -static void -ieee_eof (info) - struct ieee_info *info; -{ - ieee_error (info, (const bfd_byte *) NULL, - "unexpected end of debugging information"); -} - -/* Save a string in memory. */ - -static char * -savestring (start, len) - const char *start; - unsigned long len; -{ - char *ret; - - ret = (char *) xmalloc (len + 1); - memcpy (ret, start, len); - ret[len] = '\0'; - return ret; -} - -/* Read a number which must be present in an IEEE file. */ - -static boolean -ieee_read_number (info, pp, pv) - struct ieee_info *info; - const bfd_byte **pp; - bfd_vma *pv; -{ - return ieee_read_optional_number (info, pp, pv, (boolean *) NULL); -} - -/* Read a number in an IEEE file. If ppresent is not NULL, the number - need not be there. */ - -static boolean -ieee_read_optional_number (info, pp, pv, ppresent) - struct ieee_info *info; - const bfd_byte **pp; - bfd_vma *pv; - boolean *ppresent; -{ - ieee_record_enum_type b; - - if (*pp >= info->pend) - { - if (ppresent != NULL) - { - *ppresent = false; - return true; - } - ieee_eof (info); - return false; - } - - b = (ieee_record_enum_type) **pp; - ++*pp; - - if (b <= ieee_number_end_enum) - { - *pv = (bfd_vma) b; - if (ppresent != NULL) - *ppresent = true; - return true; - } - - if (b >= ieee_number_repeat_start_enum && b <= ieee_number_repeat_end_enum) - { - unsigned int i; - - i = (int) b - (int) ieee_number_repeat_start_enum; - if (*pp + i - 1 >= info->pend) - { - ieee_eof (info); - return false; - } - - *pv = 0; - for (; i > 0; i--) - { - *pv <<= 8; - *pv += **pp; - ++*pp; - } - - if (ppresent != NULL) - *ppresent = true; - - return true; - } - - if (ppresent != NULL) - { - --*pp; - *ppresent = false; - return true; - } - - ieee_error (info, *pp - 1, "invalid number"); - return false; -} - -/* Read a required string from an IEEE file. */ - -static boolean -ieee_read_id (info, pp, pname, pnamlen) - struct ieee_info *info; - const bfd_byte **pp; - const char **pname; - unsigned long *pnamlen; -{ - return ieee_read_optional_id (info, pp, pname, pnamlen, (boolean *) NULL); -} - -/* Read a string from an IEEE file. If ppresent is not NULL, the - string is optional. */ - -static boolean -ieee_read_optional_id (info, pp, pname, pnamlen, ppresent) - struct ieee_info *info; - const bfd_byte **pp; - const char **pname; - unsigned long *pnamlen; - boolean *ppresent; -{ - bfd_byte b; - unsigned long len; - - if (*pp >= info->pend) - { - ieee_eof (info); - return false; - } - - b = **pp; - ++*pp; - - if (b <= 0x7f) - len = b; - else if ((ieee_record_enum_type) b == ieee_extension_length_1_enum) - { - len = **pp; - ++*pp; - } - else if ((ieee_record_enum_type) b == ieee_extension_length_2_enum) - { - len = (**pp << 8) + (*pp)[1]; - *pp += 2; - } - else - { - if (ppresent != NULL) - { - --*pp; - *ppresent = false; - return true; - } - ieee_error (info, *pp - 1, "invalid string length"); - return false; - } - - if ((unsigned long) (info->pend - *pp) < len) - { - ieee_eof (info); - return false; - } - - *pname = (const char *) *pp; - *pnamlen = len; - *pp += len; - - if (ppresent != NULL) - *ppresent = true; - - return true; -} - -/* Read an expression from an IEEE file. Since this code is only used - to parse debugging information, I haven't bothered to write a full - blown IEEE expression parser. I've only thrown in the things I've - seen in debugging information. This can be easily extended if - necessary. */ - -static boolean -ieee_read_expression (info, pp, pv) - struct ieee_info *info; - const bfd_byte **pp; - bfd_vma *pv; -{ - const bfd_byte *expr_start; -#define EXPR_STACK_SIZE (10) - bfd_vma expr_stack[EXPR_STACK_SIZE]; - bfd_vma *esp; - - expr_start = *pp; - - esp = expr_stack; - - while (1) - { - const bfd_byte *start; - bfd_vma val; - boolean present; - ieee_record_enum_type c; - - start = *pp; - - if (! ieee_read_optional_number (info, pp, &val, &present)) - return false; - - if (present) - { - if (esp - expr_stack >= EXPR_STACK_SIZE) - { - ieee_error (info, start, "expression stack overflow"); - return false; - } - *esp++ = val; - continue; - } - - c = (ieee_record_enum_type) **pp; - - if (c >= ieee_module_beginning_enum) - break; - - ++*pp; - - if (c == ieee_comma) - break; - - switch (c) - { - default: - ieee_error (info, start, "unsupported IEEE expression operator"); - break; - - case ieee_variable_R_enum: - { - bfd_vma indx; - asection *s; - - if (! ieee_read_number (info, pp, &indx)) - return false; - for (s = info->abfd->sections; s != NULL; s = s->next) - if ((bfd_vma) s->target_index == indx) - break; - if (s == NULL) - { - ieee_error (info, start, "unknown section"); - return false; - } - - if (esp - expr_stack >= EXPR_STACK_SIZE) - { - ieee_error (info, start, "expression stack overflow"); - return false; - } - - *esp++ = bfd_get_section_vma (info->abfd, s); - } - break; - - case ieee_function_plus_enum: - case ieee_function_minus_enum: - { - bfd_vma v1, v2; - - if (esp - expr_stack < 2) - { - ieee_error (info, start, "expression stack underflow"); - return false; - } - - v1 = *--esp; - v2 = *--esp; - *esp++ = v1 + v2; - } - break; - } - } - - if (esp - 1 != expr_stack) - { - ieee_error (info, expr_start, "expression stack mismatch"); - return false; - } - - *pv = *--esp; - - return true; -} - -/* Return an IEEE builtin type. */ - -static debug_type -ieee_builtin_type (info, p, indx) - struct ieee_info *info; - const bfd_byte *p; - unsigned int indx; -{ - PTR dhandle; - debug_type type; - const char *name; - - if (indx < BUILTIN_TYPE_COUNT - && info->types.builtins[indx] != DEBUG_TYPE_NULL) - return info->types.builtins[indx]; - - dhandle = info->dhandle; - - if (indx >= 32 && indx < 64) - { - type = debug_make_pointer_type (dhandle, - ieee_builtin_type (info, p, indx - 32)); - assert (indx < BUILTIN_TYPE_COUNT); - info->types.builtins[indx] = type; - return type; - } - - switch ((enum builtin_types) indx) - { - default: - ieee_error (info, p, "unknown builtin type"); - return NULL; - - case builtin_unknown: - type = debug_make_void_type (dhandle); - name = NULL; - break; - - case builtin_void: - type = debug_make_void_type (dhandle); - name = "void"; - break; - - case builtin_signed_char: - type = debug_make_int_type (dhandle, 1, false); - name = "signed char"; - break; - - case builtin_unsigned_char: - type = debug_make_int_type (dhandle, 1, true); - name = "unsigned char"; - break; - - case builtin_signed_short_int: - type = debug_make_int_type (dhandle, 2, false); - name = "signed short int"; - break; - - case builtin_unsigned_short_int: - type = debug_make_int_type (dhandle, 2, true); - name = "unsigned short int"; - break; - - case builtin_signed_long: - type = debug_make_int_type (dhandle, 4, false); - name = "signed long"; - break; - - case builtin_unsigned_long: - type = debug_make_int_type (dhandle, 4, true); - name = "unsigned long"; - break; - - case builtin_signed_long_long: - type = debug_make_int_type (dhandle, 8, false); - name = "signed long long"; - break; - - case builtin_unsigned_long_long: - type = debug_make_int_type (dhandle, 8, true); - name = "unsigned long long"; - break; - - case builtin_float: - type = debug_make_float_type (dhandle, 4); - name = "float"; - break; - - case builtin_double: - type = debug_make_float_type (dhandle, 8); - name = "double"; - break; - - case builtin_long_double: - /* FIXME: The size for this type should depend upon the - processor. */ - type = debug_make_float_type (dhandle, 12); - name = "long double"; - break; - - case builtin_long_long_double: - type = debug_make_float_type (dhandle, 16); - name = "long long double"; - break; - - case builtin_quoted_string: - type = debug_make_array_type (dhandle, - ieee_builtin_type (info, p, - ((unsigned int) - builtin_char)), - ieee_builtin_type (info, p, - ((unsigned int) - builtin_int)), - 0, -1, true); - name = "QUOTED STRING"; - break; - - case builtin_instruction_address: - /* FIXME: This should be a code address. */ - type = debug_make_int_type (dhandle, 4, true); - name = "instruction address"; - break; - - case builtin_int: - /* FIXME: The size for this type should depend upon the - processor. */ - type = debug_make_int_type (dhandle, 4, false); - name = "int"; - break; - - case builtin_unsigned: - /* FIXME: The size for this type should depend upon the - processor. */ - type = debug_make_int_type (dhandle, 4, true); - name = "unsigned"; - break; - - case builtin_unsigned_int: - /* FIXME: The size for this type should depend upon the - processor. */ - type = debug_make_int_type (dhandle, 4, true); - name = "unsigned int"; - break; - - case builtin_char: - type = debug_make_int_type (dhandle, 1, false); - name = "char"; - break; - - case builtin_long: - type = debug_make_int_type (dhandle, 4, false); - name = "long"; - break; - - case builtin_short: - type = debug_make_int_type (dhandle, 2, false); - name = "short"; - break; - - case builtin_unsigned_short: - type = debug_make_int_type (dhandle, 2, true); - name = "unsigned short"; - break; - - case builtin_short_int: - type = debug_make_int_type (dhandle, 2, false); - name = "short int"; - break; - - case builtin_signed_short: - type = debug_make_int_type (dhandle, 2, false); - name = "signed short"; - break; - - case builtin_bcd_float: - ieee_error (info, p, "BCD float type not supported"); - return DEBUG_TYPE_NULL; - } - - if (name != NULL) - type = debug_name_type (dhandle, name, type); - - assert (indx < BUILTIN_TYPE_COUNT); - - info->types.builtins[indx] = type; - - return type; -} - -/* Allocate more space in the type table. If ref is true, this is a - reference to the type; if it is not already defined, we should set - up an indirect type. */ - -static boolean -ieee_alloc_type (info, indx, ref) - struct ieee_info *info; - unsigned int indx; - boolean ref; -{ - unsigned int nalloc; - register struct ieee_type *t; - struct ieee_type *tend; - - if (indx >= info->types.alloc) - { - nalloc = info->types.alloc; - if (nalloc == 0) - nalloc = 4; - while (indx >= nalloc) - nalloc *= 2; - - info->types.types = ((struct ieee_type *) - xrealloc (info->types.types, - nalloc * sizeof *info->types.types)); - - memset (info->types.types + info->types.alloc, 0, - (nalloc - info->types.alloc) * sizeof *info->types.types); - - tend = info->types.types + nalloc; - for (t = info->types.types + info->types.alloc; t < tend; t++) - t->type = DEBUG_TYPE_NULL; - - info->types.alloc = nalloc; - } - - if (ref) - { - t = info->types.types + indx; - if (t->type == NULL) - { - t->pslot = (debug_type *) xmalloc (sizeof *t->pslot); - *t->pslot = DEBUG_TYPE_NULL; - t->type = debug_make_indirect_type (info->dhandle, t->pslot, - (const char *) NULL); - if (t->type == NULL) - return false; - } - } - - return true; -} - -/* Read a type index and return the corresponding type. */ - -static boolean -ieee_read_type_index (info, pp, ptype) - struct ieee_info *info; - const bfd_byte **pp; - debug_type *ptype; -{ - const bfd_byte *start; - bfd_vma indx; - - start = *pp; - - if (! ieee_read_number (info, pp, &indx)) - return false; - - if (indx < 256) - { - *ptype = ieee_builtin_type (info, start, indx); - if (*ptype == NULL) - return false; - return true; - } - - indx -= 256; - if (! ieee_alloc_type (info, indx, true)) - return false; - - *ptype = info->types.types[indx].type; - - return true; -} - -/* Parse IEEE debugging information for a file. This is passed the - bytes which compose the Debug Information Part of an IEEE file. */ - -boolean -parse_ieee (dhandle, abfd, bytes, len) - PTR dhandle; - bfd *abfd; - const bfd_byte *bytes; - bfd_size_type len; -{ - struct ieee_info info; - unsigned int i; - const bfd_byte *p, *pend; - - info.dhandle = dhandle; - info.abfd = abfd; - info.bytes = bytes; - info.pend = bytes + len; - info.blockstack.bsp = info.blockstack.stack; - info.saw_filename = false; - info.vars.alloc = 0; - info.vars.vars = NULL; - info.types.alloc = 0; - info.types.types = NULL; - info.tags = NULL; - for (i = 0; i < BUILTIN_TYPE_COUNT; i++) - info.types.builtins[i] = DEBUG_TYPE_NULL; - - p = bytes; - pend = info.pend; - while (p < pend) - { - const bfd_byte *record_start; - ieee_record_enum_type c; - - record_start = p; - - c = (ieee_record_enum_type) *p++; - - if (c == ieee_at_record_enum) - c = (ieee_record_enum_type) (((unsigned int) c << 8) | *p++); - - if (c <= ieee_number_repeat_end_enum) - { - ieee_error (&info, record_start, "unexpected number"); - return false; - } - - switch (c) - { - default: - ieee_error (&info, record_start, "unexpected record type"); - return false; - - case ieee_bb_record_enum: - if (! parse_ieee_bb (&info, &p)) - return false; - break; - - case ieee_be_record_enum: - if (! parse_ieee_be (&info, &p)) - return false; - break; - - case ieee_nn_record: - if (! parse_ieee_nn (&info, &p)) - return false; - break; - - case ieee_ty_record_enum: - if (! parse_ieee_ty (&info, &p)) - return false; - break; - - case ieee_atn_record_enum: - if (! parse_ieee_atn (&info, &p)) - return false; - break; - } - } - - if (info.blockstack.bsp != info.blockstack.stack) - { - ieee_error (&info, (const bfd_byte *) NULL, - "blocks left on stack at end"); - return false; - } - - return true; -} - -/* Handle an IEEE BB record. */ - -static boolean -parse_ieee_bb (info, pp) - struct ieee_info *info; - const bfd_byte **pp; -{ - const bfd_byte *block_start; - bfd_byte b; - bfd_vma size; - const char *name; - unsigned long namlen; - char *namcopy = NULL; - unsigned int fnindx; - boolean skip; - - block_start = *pp; - - b = **pp; - ++*pp; - - if (! ieee_read_number (info, pp, &size) - || ! ieee_read_id (info, pp, &name, &namlen)) - return false; - - fnindx = (unsigned int) -1; - skip = false; - - switch (b) - { - case 1: - /* BB1: Type definitions local to a module. */ - namcopy = savestring (name, namlen); - if (namcopy == NULL) - return false; - if (! debug_set_filename (info->dhandle, namcopy)) - return false; - info->saw_filename = true; - - /* Discard any variables or types we may have seen before. */ - if (info->vars.vars != NULL) - free (info->vars.vars); - info->vars.vars = NULL; - info->vars.alloc = 0; - if (info->types.types != NULL) - free (info->types.types); - info->types.types = NULL; - info->types.alloc = 0; - - /* Initialize the types to the global types. */ - if (info->global_types != NULL) - { - info->types.alloc = info->global_types->alloc; - info->types.types = ((struct ieee_type *) - xmalloc (info->types.alloc - * sizeof (*info->types.types))); - memcpy (info->types.types, info->global_types->types, - info->types.alloc * sizeof (*info->types.types)); - } - - break; - - case 2: - /* BB2: Global type definitions. The name is supposed to be - empty, but we don't check. */ - if (! debug_set_filename (info->dhandle, "*global*")) - return false; - info->saw_filename = true; - break; - - case 3: - /* BB3: High level module block begin. We don't have to do - anything here. The name is supposed to be the same as for - the BB1, but we don't check. */ - break; - - case 4: - /* BB4: Global function. */ - { - bfd_vma stackspace, typindx, offset; - debug_type return_type; - - if (! ieee_read_number (info, pp, &stackspace) - || ! ieee_read_number (info, pp, &typindx) - || ! ieee_read_expression (info, pp, &offset)) - return false; - - /* We have no way to record the stack space. FIXME. */ - - if (typindx < 256) - { - return_type = ieee_builtin_type (info, block_start, typindx); - if (return_type == DEBUG_TYPE_NULL) - return false; - } - else - { - typindx -= 256; - if (! ieee_alloc_type (info, typindx, true)) - return false; - fnindx = typindx; - return_type = info->types.types[typindx].type; - if (debug_get_type_kind (info->dhandle, return_type) - == DEBUG_KIND_FUNCTION) - return_type = debug_get_return_type (info->dhandle, - return_type); - } - - namcopy = savestring (name, namlen); - if (namcopy == NULL) - return false; - if (! debug_record_function (info->dhandle, namcopy, return_type, - true, offset)) - return false; - } - break; - - case 5: - /* BB5: File name for source line numbers. */ - { - unsigned int i; - - /* We ignore the date and time. FIXME. */ - for (i = 0; i < 6; i++) - { - bfd_vma ignore; - boolean present; - - if (! ieee_read_optional_number (info, pp, &ignore, &present)) - return false; - if (! present) - break; - } - - namcopy = savestring (name, namlen); - if (namcopy == NULL) - return false; - if (! debug_start_source (info->dhandle, namcopy)) - return false; - } - break; - - case 6: - /* BB6: Local function or block. */ - { - bfd_vma stackspace, typindx, offset; - - if (! ieee_read_number (info, pp, &stackspace) - || ! ieee_read_number (info, pp, &typindx) - || ! ieee_read_expression (info, pp, &offset)) - return false; - - /* We have no way to record the stack space. FIXME. */ - - if (namlen == 0) - { - if (! debug_start_block (info->dhandle, offset)) - return false; - /* Change b to indicate that this is a block - rather than a function. */ - b = 0x86; - } - else - { - /* The MRI C++ compiler will output a fake function named - __XRYCPP to hold C++ debugging information. We skip - that function. This is not crucial, but it makes - converting from IEEE to other debug formats work - better. */ - if (strncmp (name, "__XRYCPP", namlen) == 0) - skip = true; - else - { - debug_type return_type; - - if (typindx < 256) - { - return_type = ieee_builtin_type (info, block_start, - typindx); - if (return_type == NULL) - return false; - } - else - { - typindx -= 256; - if (! ieee_alloc_type (info, typindx, true)) - return false; - fnindx = typindx; - return_type = info->types.types[typindx].type; - if (debug_get_type_kind (info->dhandle, return_type) - == DEBUG_KIND_FUNCTION) - return_type = debug_get_return_type (info->dhandle, - return_type); - } - - namcopy = savestring (name, namlen); - if (namcopy == NULL) - return false; - if (! debug_record_function (info->dhandle, namcopy, - return_type, false, offset)) - return false; - } - } - } - break; - - case 10: - /* BB10: Assembler module scope. In the normal case, we - completely ignore all this information. FIXME. */ - { - const char *inam, *vstr; - unsigned long inamlen, vstrlen; - bfd_vma tool_type; - boolean present; - unsigned int i; - - if (! info->saw_filename) - { - namcopy = savestring (name, namlen); - if (namcopy == NULL) - return false; - if (! debug_set_filename (info->dhandle, namcopy)) - return false; - info->saw_filename = true; - } - - if (! ieee_read_id (info, pp, &inam, &inamlen) - || ! ieee_read_number (info, pp, &tool_type) - || ! ieee_read_optional_id (info, pp, &vstr, &vstrlen, &present)) - return false; - for (i = 0; i < 6; i++) - { - bfd_vma ignore; - - if (! ieee_read_optional_number (info, pp, &ignore, &present)) - return false; - if (! present) - break; - } - } - break; - - case 11: - /* BB11: Module section. We completely ignore all this - information. FIXME. */ - { - bfd_vma sectype, secindx, offset, map; - boolean present; - - if (! ieee_read_number (info, pp, §ype) - || ! ieee_read_number (info, pp, &secindx) - || ! ieee_read_expression (info, pp, &offset) - || ! ieee_read_optional_number (info, pp, &map, &present)) - return false; - } - break; - - default: - ieee_error (info, block_start, "unknown BB type"); - return false; - } - - - /* Push this block on the block stack. */ - - if (info->blockstack.bsp >= info->blockstack.stack + BLOCKSTACK_SIZE) - { - ieee_error (info, (const bfd_byte *) NULL, "stack overflow"); - return false; - } - - info->blockstack.bsp->kind = b; - if (b == 5) - info->blockstack.bsp->filename = namcopy; - info->blockstack.bsp->fnindx = fnindx; - info->blockstack.bsp->skip = skip; - ++info->blockstack.bsp; - - return true; -} - -/* Handle an IEEE BE record. */ - -static boolean -parse_ieee_be (info, pp) - struct ieee_info *info; - const bfd_byte **pp; -{ - bfd_vma offset; - - if (info->blockstack.bsp <= info->blockstack.stack) - { - ieee_error (info, *pp, "stack underflow"); - return false; - } - --info->blockstack.bsp; - - switch (info->blockstack.bsp->kind) - { - case 2: - /* When we end the global typedefs block, we copy out the the - contents of info->vars. This is because the variable indices - may be reused in the local blocks. However, we need to - preserve them so that we can locate a function returning a - reference variable whose type is named in the global typedef - block. */ - info->global_vars = ((struct ieee_vars *) - xmalloc (sizeof *info->global_vars)); - info->global_vars->alloc = info->vars.alloc; - info->global_vars->vars = ((struct ieee_var *) - xmalloc (info->vars.alloc - * sizeof (*info->vars.vars))); - memcpy (info->global_vars->vars, info->vars.vars, - info->vars.alloc * sizeof (*info->vars.vars)); - - /* We also copy out the non builtin parts of info->types, since - the types are discarded when we start a new block. */ - info->global_types = ((struct ieee_types *) - xmalloc (sizeof *info->global_types)); - info->global_types->alloc = info->types.alloc; - info->global_types->types = ((struct ieee_type *) - xmalloc (info->types.alloc - * sizeof (*info->types.types))); - memcpy (info->global_types->types, info->types.types, - info->types.alloc * sizeof (*info->types.types)); - memset (info->global_types->builtins, 0, - sizeof (info->global_types->builtins)); - - break; - - case 4: - case 6: - if (! ieee_read_expression (info, pp, &offset)) - return false; - if (! info->blockstack.bsp->skip) - { - if (! debug_end_function (info->dhandle, offset + 1)) - return false; - } - break; - - case 0x86: - /* This is BE6 when BB6 started a block rather than a local - function. */ - if (! ieee_read_expression (info, pp, &offset)) - return false; - if (! debug_end_block (info->dhandle, offset + 1)) - return false; - break; - - case 5: - /* When we end a BB5, we look up the stack for the last BB5, if - there is one, so that we can call debug_start_source. */ - if (info->blockstack.bsp > info->blockstack.stack) - { - struct ieee_block *bl; - - bl = info->blockstack.bsp; - do - { - --bl; - if (bl->kind == 5) - { - if (! debug_start_source (info->dhandle, bl->filename)) - return false; - break; - } - } - while (bl != info->blockstack.stack); - } - break; - - case 11: - if (! ieee_read_expression (info, pp, &offset)) - return false; - /* We just ignore the module size. FIXME. */ - break; - - default: - /* Other block types do not have any trailing information. */ - break; - } - - return true; -} - -/* Parse an NN record. */ - -static boolean -parse_ieee_nn (info, pp) - struct ieee_info *info; - const bfd_byte **pp; -{ - const bfd_byte *nn_start; - bfd_vma varindx; - const char *name; - unsigned long namlen; - - nn_start = *pp; - - if (! ieee_read_number (info, pp, &varindx) - || ! ieee_read_id (info, pp, &name, &namlen)) - return false; - - if (varindx < 32) - { - ieee_error (info, nn_start, "illegal variable index"); - return false; - } - varindx -= 32; - - if (varindx >= info->vars.alloc) - { - unsigned int alloc; - - alloc = info->vars.alloc; - if (alloc == 0) - alloc = 4; - while (varindx >= alloc) - alloc *= 2; - info->vars.vars = ((struct ieee_var *) - xrealloc (info->vars.vars, - alloc * sizeof *info->vars.vars)); - memset (info->vars.vars + info->vars.alloc, 0, - (alloc - info->vars.alloc) * sizeof *info->vars.vars); - info->vars.alloc = alloc; - } - - info->vars.vars[varindx].name = name; - info->vars.vars[varindx].namlen = namlen; - - return true; -} - -/* Parse a TY record. */ - -static boolean -parse_ieee_ty (info, pp) - struct ieee_info *info; - const bfd_byte **pp; -{ - const bfd_byte *ty_start, *ty_var_start, *ty_code_start; - bfd_vma typeindx, varindx, tc; - PTR dhandle; - boolean tag, typdef; - debug_type *arg_slots; - unsigned long type_bitsize; - debug_type type; - - ty_start = *pp; - - if (! ieee_read_number (info, pp, &typeindx)) - return false; - - if (typeindx < 256) - { - ieee_error (info, ty_start, "illegal type index"); - return false; - } - - typeindx -= 256; - if (! ieee_alloc_type (info, typeindx, false)) - return false; - - if (**pp != 0xce) - { - ieee_error (info, *pp, "unknown TY code"); - return false; - } - ++*pp; - - ty_var_start = *pp; - - if (! ieee_read_number (info, pp, &varindx)) - return false; - - if (varindx < 32) - { - ieee_error (info, ty_var_start, "illegal variable index"); - return false; - } - varindx -= 32; - - if (varindx >= info->vars.alloc || info->vars.vars[varindx].name == NULL) - { - ieee_error (info, ty_var_start, "undefined variable in TY"); - return false; - } - - ty_code_start = *pp; - - if (! ieee_read_number (info, pp, &tc)) - return false; - - dhandle = info->dhandle; - - tag = false; - typdef = false; - arg_slots = NULL; - type_bitsize = 0; - switch (tc) - { - default: - ieee_error (info, ty_code_start, "unknown TY code"); - return false; - - case '!': - /* Unknown type, with size. We treat it as int. FIXME. */ - { - bfd_vma size; - - if (! ieee_read_number (info, pp, &size)) - return false; - type = debug_make_int_type (dhandle, size, false); - } - break; - - case 'A': /* Array. */ - case 'a': /* FORTRAN array in column/row order. FIXME: Not - distinguished from normal array. */ - { - debug_type ele_type; - bfd_vma lower, upper; - - if (! ieee_read_type_index (info, pp, &ele_type) - || ! ieee_read_number (info, pp, &lower) - || ! ieee_read_number (info, pp, &upper)) - return false; - type = debug_make_array_type (dhandle, ele_type, - ieee_builtin_type (info, ty_code_start, - ((unsigned int) - builtin_int)), - (bfd_signed_vma) lower, - (bfd_signed_vma) upper, - false); - } - break; - - case 'E': - /* Simple enumeration. */ - { - bfd_vma size; - unsigned int alloc; - const char **names; - unsigned int c; - bfd_signed_vma *vals; - unsigned int i; - - if (! ieee_read_number (info, pp, &size)) - return false; - /* FIXME: we ignore the enumeration size. */ - - alloc = 10; - names = (const char **) xmalloc (alloc * sizeof *names); - memset (names, 0, alloc * sizeof *names); - c = 0; - while (1) - { - const char *name; - unsigned long namlen; - boolean present; - - if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) - return false; - if (! present) - break; - - if (c + 1 >= alloc) - { - alloc += 10; - names = ((const char **) - xrealloc (names, alloc * sizeof *names)); - } - - names[c] = savestring (name, namlen); - if (names[c] == NULL) - return false; - ++c; - } - - names[c] = NULL; - - vals = (bfd_signed_vma *) xmalloc (c * sizeof *vals); - for (i = 0; i < c; i++) - vals[i] = i; - - type = debug_make_enum_type (dhandle, names, vals); - tag = true; - } - break; - - case 'G': - /* Struct with bit fields. */ - { - bfd_vma size; - unsigned int alloc; - debug_field *fields; - unsigned int c; - - if (! ieee_read_number (info, pp, &size)) - return false; - - alloc = 10; - fields = (debug_field *) xmalloc (alloc * sizeof *fields); - c = 0; - while (1) - { - const char *name; - unsigned long namlen; - boolean present; - debug_type ftype; - bfd_vma bitpos, bitsize; - - if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) - return false; - if (! present) - break; - if (! ieee_read_type_index (info, pp, &ftype) - || ! ieee_read_number (info, pp, &bitpos) - || ! ieee_read_number (info, pp, &bitsize)) - return false; - - if (c + 1 >= alloc) - { - alloc += 10; - fields = ((debug_field *) - xrealloc (fields, alloc * sizeof *fields)); - } - - fields[c] = debug_make_field (dhandle, savestring (name, namlen), - ftype, bitpos, bitsize, - DEBUG_VISIBILITY_PUBLIC); - if (fields[c] == NULL) - return false; - ++c; - } - - fields[c] = NULL; - - type = debug_make_struct_type (dhandle, true, size, fields); - tag = true; - } - break; - - case 'N': - /* Enumeration. */ - { - unsigned int alloc; - const char **names; - bfd_signed_vma *vals; - unsigned int c; - - alloc = 10; - names = (const char **) xmalloc (alloc * sizeof *names); - vals = (bfd_signed_vma *) xmalloc (alloc * sizeof *names); - c = 0; - while (1) - { - const char *name; - unsigned long namlen; - boolean present; - bfd_vma val; - - if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) - return false; - if (! present) - break; - if (! ieee_read_number (info, pp, &val)) - return false; - - /* If the length of the name is zero, then the value is - actually the size of the enum. We ignore this - information. FIXME. */ - if (namlen == 0) - continue; - - if (c + 1 >= alloc) - { - alloc += 10; - names = ((const char **) - xrealloc (names, alloc * sizeof *names)); - vals = ((bfd_signed_vma *) - xrealloc (vals, alloc * sizeof *vals)); - } - - names[c] = savestring (name, namlen); - if (names[c] == NULL) - return false; - vals[c] = (bfd_signed_vma) val; - ++c; - } - - names[c] = NULL; - - type = debug_make_enum_type (dhandle, names, vals); - tag = true; - } - break; - - case 'O': /* Small pointer. We don't distinguish small and large - pointers. FIXME. */ - case 'P': /* Large pointer. */ - { - debug_type t; - - if (! ieee_read_type_index (info, pp, &t)) - return false; - type = debug_make_pointer_type (dhandle, t); - } - break; - - case 'R': - /* Range. */ - { - bfd_vma low, high, signedp, size; - - if (! ieee_read_number (info, pp, &low) - || ! ieee_read_number (info, pp, &high) - || ! ieee_read_number (info, pp, &signedp) - || ! ieee_read_number (info, pp, &size)) - return false; - - type = debug_make_range_type (dhandle, - debug_make_int_type (dhandle, size, - ! signedp), - (bfd_signed_vma) low, - (bfd_signed_vma) high); - } - break; - - case 'S': /* Struct. */ - case 'U': /* Union. */ - { - bfd_vma size; - unsigned int alloc; - debug_field *fields; - unsigned int c; - - if (! ieee_read_number (info, pp, &size)) - return false; - - alloc = 10; - fields = (debug_field *) xmalloc (alloc * sizeof *fields); - c = 0; - while (1) - { - const char *name; - unsigned long namlen; - boolean present; - bfd_vma tindx; - bfd_vma offset; - debug_type ftype; - bfd_vma bitsize; - - if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) - return false; - if (! present) - break; - if (! ieee_read_number (info, pp, &tindx) - || ! ieee_read_number (info, pp, &offset)) - return false; - - if (tindx < 256) - { - ftype = ieee_builtin_type (info, ty_code_start, tindx); - bitsize = 0; - offset *= 8; - } - else - { - struct ieee_type *t; - - tindx -= 256; - if (! ieee_alloc_type (info, tindx, true)) - return false; - t = info->types.types + tindx; - ftype = t->type; - bitsize = t->bitsize; - if (bitsize == 0) - offset *= 8; - } - - if (c + 1 >= alloc) - { - alloc += 10; - fields = ((debug_field *) - xrealloc (fields, alloc * sizeof *fields)); - } - - fields[c] = debug_make_field (dhandle, savestring (name, namlen), - ftype, offset, bitsize, - DEBUG_VISIBILITY_PUBLIC); - if (fields[c] == NULL) - return false; - ++c; - } - - fields[c] = NULL; - - type = debug_make_struct_type (dhandle, tc == 'S', size, fields); - tag = true; - } - break; - - case 'T': - /* Typedef. */ - if (! ieee_read_type_index (info, pp, &type)) - return false; - typdef = true; - break; - - case 'X': - /* Procedure. FIXME: This is an extern declaration, which we - have no way of representing. */ - { - bfd_vma attr; - debug_type rtype; - bfd_vma nargs; - boolean present; - struct ieee_var *pv; - - /* FIXME: We ignore the attribute and the argument names. */ - - if (! ieee_read_number (info, pp, &attr) - || ! ieee_read_type_index (info, pp, &rtype) - || ! ieee_read_number (info, pp, &nargs)) - return false; - do - { - const char *name; - unsigned long namlen; - - if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) - return false; - } - while (present); - - pv = info->vars.vars + varindx; - pv->kind = IEEE_EXTERNAL; - if (pv->namlen > 0 - && debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER) - { - /* Set up the return type as an indirect type pointing to - the variable slot, so that we can change it to a - reference later if appropriate. */ - pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot); - *pv->pslot = rtype; - rtype = debug_make_indirect_type (dhandle, pv->pslot, - (const char *) NULL); - } - - type = debug_make_function_type (dhandle, rtype, (debug_type *) NULL, - false); - } - break; - - case 'V': - /* Void. This is not documented, but the MRI compiler emits it. */ - type = debug_make_void_type (dhandle); - break; - - case 'Z': - /* Array with 0 lower bound. */ - { - debug_type etype; - bfd_vma high; - - if (! ieee_read_type_index (info, pp, &etype) - || ! ieee_read_number (info, pp, &high)) - return false; - - type = debug_make_array_type (dhandle, etype, - ieee_builtin_type (info, ty_code_start, - ((unsigned int) - builtin_int)), - 0, (bfd_signed_vma) high, false); - } - break; - - case 'c': /* Complex. */ - case 'd': /* Double complex. */ - { - const char *name; - unsigned long namlen; - - /* FIXME: I don't know what the name means. */ - - if (! ieee_read_id (info, pp, &name, &namlen)) - return false; - - type = debug_make_complex_type (dhandle, tc == 'c' ? 4 : 8); - } - break; - - case 'f': - /* Pascal file name. FIXME. */ - ieee_error (info, ty_code_start, "Pascal file name not supported"); - return false; - - case 'g': - /* Bitfield type. */ - { - bfd_vma signedp, bitsize, dummy; - const bfd_byte *hold; - boolean present; - - if (! ieee_read_number (info, pp, &signedp) - || ! ieee_read_number (info, pp, &bitsize)) - return false; - - /* I think the documentation says that there is a type index, - but some actual files do not have one. */ - hold = *pp; - if (! ieee_read_optional_number (info, pp, &dummy, &present)) - return false; - if (! present) - { - /* FIXME: This is just a guess. */ - type = debug_make_int_type (dhandle, 4, - signedp ? false : true); - } - else - { - *pp = hold; - if (! ieee_read_type_index (info, pp, &type)) - return false; - } - type_bitsize = bitsize; - } - break; - - case 'n': - /* Qualifier. */ - { - bfd_vma kind; - debug_type t; - - if (! ieee_read_number (info, pp, &kind) - || ! ieee_read_type_index (info, pp, &t)) - return false; - - switch (kind) - { - default: - ieee_error (info, ty_start, "unsupported qualifer"); - return false; - - case 1: - type = debug_make_const_type (dhandle, t); - break; - - case 2: - type = debug_make_volatile_type (dhandle, t); - break; - } - } - break; - - case 's': - /* Set. */ - { - bfd_vma size; - debug_type etype; - - if (! ieee_read_number (info, pp, &size) - || ! ieee_read_type_index (info, pp, &etype)) - return false; - - /* FIXME: We ignore the size. */ - - type = debug_make_set_type (dhandle, etype, false); - } - break; - - case 'x': - /* Procedure with compiler dependencies. */ - { - struct ieee_var *pv; - bfd_vma attr, frame_type, push_mask, nargs, level, father; - debug_type rtype; - debug_type *arg_types; - boolean varargs; - boolean present; - - /* FIXME: We ignore some of this information. */ - - pv = info->vars.vars + varindx; - - if (! ieee_read_number (info, pp, &attr) - || ! ieee_read_number (info, pp, &frame_type) - || ! ieee_read_number (info, pp, &push_mask) - || ! ieee_read_type_index (info, pp, &rtype) - || ! ieee_read_number (info, pp, &nargs)) - return false; - if (nargs == (bfd_vma) -1) - { - arg_types = NULL; - varargs = false; - } - else - { - unsigned int i; - - arg_types = ((debug_type *) - xmalloc ((nargs + 1) * sizeof *arg_types)); - for (i = 0; i < nargs; i++) - if (! ieee_read_type_index (info, pp, arg_types + i)) - return false; - - /* If the last type is pointer to void, this is really a - varargs function. */ - varargs = false; - if (nargs > 0) - { - debug_type last; - - last = arg_types[nargs - 1]; - if (debug_get_type_kind (dhandle, last) == DEBUG_KIND_POINTER - && (debug_get_type_kind (dhandle, - debug_get_target_type (dhandle, - last)) - == DEBUG_KIND_VOID)) - { - --nargs; - varargs = true; - } - } - - /* If there are any pointer arguments, turn them into - indirect types in case we later need to convert them to - reference types. */ - for (i = 0; i < nargs; i++) - { - if (debug_get_type_kind (dhandle, arg_types[i]) - == DEBUG_KIND_POINTER) - { - if (arg_slots == NULL) - { - arg_slots = ((debug_type *) - xmalloc (nargs * sizeof *arg_slots)); - memset (arg_slots, 0, nargs * sizeof *arg_slots); - } - arg_slots[i] = arg_types[i]; - arg_types[i] = - debug_make_indirect_type (dhandle, - arg_slots + i, - (const char *) NULL); - } - } - - arg_types[nargs] = DEBUG_TYPE_NULL; - } - if (! ieee_read_number (info, pp, &level) - || ! ieee_read_optional_number (info, pp, &father, &present)) - return false; - - /* We can't distinguish between a global function and a static - function. */ - pv->kind = IEEE_FUNCTION; - - if (pv->namlen > 0 - && debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER) - { - /* Set up the return type as an indirect type pointing to - the variable slot, so that we can change it to a - reference later if appropriate. */ - pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot); - *pv->pslot = rtype; - rtype = debug_make_indirect_type (dhandle, pv->pslot, - (const char *) NULL); - } - - type = debug_make_function_type (dhandle, rtype, arg_types, varargs); - } - break; - } - - /* Record the type in the table. */ - - if (type == DEBUG_TYPE_NULL) - return false; - - info->vars.vars[varindx].type = type; - - if ((tag || typdef) - && info->vars.vars[varindx].namlen > 0) - { - const char *name; - - name = savestring (info->vars.vars[varindx].name, - info->vars.vars[varindx].namlen); - if (typdef) - type = debug_name_type (dhandle, name, type); - else if (tc == 'E' || tc == 'N') - type = debug_tag_type (dhandle, name, type); - else - { - struct ieee_tag *it; - - /* We must allocate all struct tags as indirect types, so - that if we later see a definition of the tag as a C++ - record we can update the indirect slot and automatically - change all the existing references. */ - it = (struct ieee_tag *) xmalloc (sizeof *it); - memset (it, 0, sizeof *it); - it->next = info->tags; - info->tags = it; - it->name = name; - it->slot = type; - - type = debug_make_indirect_type (dhandle, &it->slot, name); - type = debug_tag_type (dhandle, name, type); - - it->type = type; - } - if (type == NULL) - return false; - } - - info->types.types[typeindx].type = type; - info->types.types[typeindx].arg_slots = arg_slots; - info->types.types[typeindx].bitsize = type_bitsize; - - /* We may have already allocated type as an indirect type pointing - to slot. It does no harm to replace the indirect type with the - real type. Filling in slot as well handles the indirect types - which are already hanging around. */ - if (info->types.types[typeindx].pslot != NULL) - *info->types.types[typeindx].pslot = type; - - return true; -} - -/* Parse an ATN record. */ - -static boolean -parse_ieee_atn (info, pp) - struct ieee_info *info; - const bfd_byte **pp; -{ - const bfd_byte *atn_start, *atn_code_start; - bfd_vma varindx; - struct ieee_var *pvar; - debug_type type; - bfd_vma atn_code; - PTR dhandle; - bfd_vma v, v2, v3, v4, v5; - const char *name; - unsigned long namlen; - char *namcopy; - boolean present; - int blocktype; - - atn_start = *pp; - - if (! ieee_read_number (info, pp, &varindx) - || ! ieee_read_type_index (info, pp, &type)) - return false; - - atn_code_start = *pp; - - if (! ieee_read_number (info, pp, &atn_code)) - return false; - - if (varindx == 0) - { - pvar = NULL; - name = ""; - namlen = 0; - } - else if (varindx < 32) - { - ieee_error (info, atn_start, "illegal variable index"); - return false; - } - else - { - varindx -= 32; - if (varindx >= info->vars.alloc - || info->vars.vars[varindx].name == NULL) - { - /* The MRI compiler or linker sometimes omits the NN record - for a pmisc record. */ - if (atn_code == 62) - { - if (varindx >= info->vars.alloc) - { - unsigned int alloc; - - alloc = info->vars.alloc; - if (alloc == 0) - alloc = 4; - while (varindx >= alloc) - alloc *= 2; - info->vars.vars = ((struct ieee_var *) - xrealloc (info->vars.vars, - (alloc - * sizeof *info->vars.vars))); - memset (info->vars.vars + info->vars.alloc, 0, - ((alloc - info->vars.alloc) - * sizeof *info->vars.vars)); - info->vars.alloc = alloc; - } - - pvar = info->vars.vars + varindx; - pvar->name = ""; - pvar->namlen = 0; - } - else - { - ieee_error (info, atn_start, "undefined variable in ATN"); - return false; - } - } - - pvar = info->vars.vars + varindx; - - pvar->type = type; - - name = pvar->name; - namlen = pvar->namlen; - } - - dhandle = info->dhandle; - - /* If we are going to call debug_record_variable with a pointer - type, change the type to an indirect type so that we can later - change it to a reference type if we encounter a C++ pmisc 'R' - record. */ - if (pvar != NULL - && type != DEBUG_TYPE_NULL - && debug_get_type_kind (dhandle, type) == DEBUG_KIND_POINTER) - { - switch (atn_code) - { - case 1: - case 2: - case 3: - case 5: - case 8: - case 10: - pvar->pslot = (debug_type *) xmalloc (sizeof *pvar->pslot); - *pvar->pslot = type; - type = debug_make_indirect_type (dhandle, pvar->pslot, - (const char *) NULL); - pvar->type = type; - break; - } - } - - switch (atn_code) - { - default: - ieee_error (info, atn_code_start, "unknown ATN type"); - return false; - - case 1: - /* Automatic variable. */ - if (! ieee_read_number (info, pp, &v)) - return false; - namcopy = savestring (name, namlen); - if (type == NULL) - type = debug_make_void_type (dhandle); - if (pvar != NULL) - pvar->kind = IEEE_LOCAL; - return debug_record_variable (dhandle, namcopy, type, DEBUG_LOCAL, v); - - case 2: - /* Register variable. */ - if (! ieee_read_number (info, pp, &v)) - return false; - namcopy = savestring (name, namlen); - if (type == NULL) - type = debug_make_void_type (dhandle); - if (pvar != NULL) - pvar->kind = IEEE_LOCAL; - return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER, - ieee_regno_to_genreg (info->abfd, v)); - - case 3: - /* Static variable. */ - if (! ieee_require_asn (info, pp, &v)) - return false; - namcopy = savestring (name, namlen); - if (type == NULL) - type = debug_make_void_type (dhandle); - if (info->blockstack.bsp <= info->blockstack.stack) - blocktype = 0; - else - blocktype = info->blockstack.bsp[-1].kind; - if (pvar != NULL) - { - if (blocktype == 4 || blocktype == 6) - pvar->kind = IEEE_LOCAL; - else - pvar->kind = IEEE_STATIC; - } - return debug_record_variable (dhandle, namcopy, type, - (blocktype == 4 || blocktype == 6 - ? DEBUG_LOCAL_STATIC - : DEBUG_STATIC), - v); - - case 4: - /* External function. We don't currently record these. FIXME. */ - if (pvar != NULL) - pvar->kind = IEEE_EXTERNAL; - return true; - - case 5: - /* External variable. We don't currently record these. FIXME. */ - if (pvar != NULL) - pvar->kind = IEEE_EXTERNAL; - return true; - - case 7: - if (! ieee_read_number (info, pp, &v) - || ! ieee_read_number (info, pp, &v2) - || ! ieee_read_optional_number (info, pp, &v3, &present)) - return false; - if (present) - { - if (! ieee_read_optional_number (info, pp, &v4, &present)) - return false; - } - - /* We just ignore the two optional fields in v3 and v4, since - they are not defined. */ - - if (! ieee_require_asn (info, pp, &v3)) - return false; - - /* We have no way to record the column number. FIXME. */ - - return debug_record_line (dhandle, v, v3); - - case 8: - /* Global variable. */ - if (! ieee_require_asn (info, pp, &v)) - return false; - namcopy = savestring (name, namlen); - if (type == NULL) - type = debug_make_void_type (dhandle); - if (pvar != NULL) - pvar->kind = IEEE_GLOBAL; - return debug_record_variable (dhandle, namcopy, type, DEBUG_GLOBAL, v); - - case 9: - /* Variable lifetime information. */ - if (! ieee_read_number (info, pp, &v)) - return false; - - /* We have no way to record this information. FIXME. */ - return true; - - case 10: - /* Locked register. The spec says that there are two required - fields, but at least on occasion the MRI compiler only emits - one. */ - if (! ieee_read_number (info, pp, &v) - || ! ieee_read_optional_number (info, pp, &v2, &present)) - return false; - - /* I think this means a variable that is both in a register and - a frame slot. We ignore the frame slot. FIXME. */ - - namcopy = savestring (name, namlen); - if (type == NULL) - type = debug_make_void_type (dhandle); - if (pvar != NULL) - pvar->kind = IEEE_LOCAL; - return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER, v); - - case 11: - /* Reserved for FORTRAN common. */ - ieee_error (info, atn_code_start, "unsupported ATN11"); - - /* Return true to keep going. */ - return true; - - case 12: - /* Based variable. */ - v3 = 0; - v4 = 0x80; - v5 = 0; - if (! ieee_read_number (info, pp, &v) - || ! ieee_read_number (info, pp, &v2) - || ! ieee_read_optional_number (info, pp, &v3, &present)) - return false; - if (present) - { - if (! ieee_read_optional_number (info, pp, &v4, &present)) - return false; - if (present) - { - if (! ieee_read_optional_number (info, pp, &v5, &present)) - return false; - } - } - - /* We have no way to record this information. FIXME. */ - - ieee_error (info, atn_code_start, "unsupported ATN12"); - - /* Return true to keep going. */ - return true; - - case 16: - /* Constant. The description of this that I have is ambiguous, - so I'm not going to try to implement it. */ - if (! ieee_read_number (info, pp, &v) - || ! ieee_read_optional_number (info, pp, &v2, &present)) - return false; - if (present) - { - if (! ieee_read_optional_number (info, pp, &v2, &present)) - return false; - if (present) - { - if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) - return false; - } - } - - if ((ieee_record_enum_type) **pp == ieee_e2_first_byte_enum) - { - if (! ieee_require_asn (info, pp, &v3)) - return false; - } - - return true; - - case 19: - /* Static variable from assembler. */ - v2 = 0; - if (! ieee_read_number (info, pp, &v) - || ! ieee_read_optional_number (info, pp, &v2, &present) - || ! ieee_require_asn (info, pp, &v3)) - return false; - namcopy = savestring (name, namlen); - /* We don't really handle this correctly. FIXME. */ - return debug_record_variable (dhandle, namcopy, - debug_make_void_type (dhandle), - v2 != 0 ? DEBUG_GLOBAL : DEBUG_STATIC, - v3); - - case 62: - /* Procedure miscellaneous information. */ - case 63: - /* Variable miscellaneous information. */ - case 64: - /* Module miscellaneous information. */ - if (! ieee_read_number (info, pp, &v) - || ! ieee_read_number (info, pp, &v2) - || ! ieee_read_optional_id (info, pp, &name, &namlen, &present)) - return false; - - if (atn_code == 62 && v == 80) - { - if (present) - { - ieee_error (info, atn_code_start, - "unexpected string in C++ misc"); - return false; - } - return ieee_read_cxx_misc (info, pp, v2); - } - - /* We just ignore all of this stuff. FIXME. */ - - for (; v2 > 0; --v2) - { - switch ((ieee_record_enum_type) **pp) - { - default: - ieee_error (info, *pp, "bad misc record"); - return false; - - case ieee_at_record_enum: - if (! ieee_require_atn65 (info, pp, &name, &namlen)) - return false; - break; - - case ieee_e2_first_byte_enum: - if (! ieee_require_asn (info, pp, &v3)) - return false; - break; - } - } - - return true; - } - - /*NOTREACHED*/ -} - -/* Handle C++ debugging miscellaneous records. This is called for - procedure miscellaneous records of type 80. */ - -static boolean -ieee_read_cxx_misc (info, pp, count) - struct ieee_info *info; - const bfd_byte **pp; - unsigned long count; -{ - const bfd_byte *start; - bfd_vma category; - - start = *pp; - - /* Get the category of C++ misc record. */ - if (! ieee_require_asn (info, pp, &category)) - return false; - --count; - - switch (category) - { - default: - ieee_error (info, start, "unrecognized C++ misc record"); - return false; - - case 'T': - if (! ieee_read_cxx_class (info, pp, count)) - return false; - break; - - case 'M': - { - bfd_vma flags; - const char *name; - unsigned long namlen; - - /* The IEEE spec indicates that the 'M' record only has a - flags field. The MRI compiler also emits the name of the - function. */ - - if (! ieee_require_asn (info, pp, &flags)) - return false; - if (*pp < info->pend - && (ieee_record_enum_type) **pp == ieee_at_record_enum) - { - if (! ieee_require_atn65 (info, pp, &name, &namlen)) - return false; - } - - /* This is emitted for method functions, but I don't think we - care very much. It might help if it told us useful - information like the class with which this function is - associated, but it doesn't, so it isn't helpful. */ - } - break; - - case 'B': - if (! ieee_read_cxx_defaults (info, pp, count)) - return false; - break; - - case 'z': - { - const char *name, *mangled, *class; - unsigned long namlen, mangledlen, classlen; - bfd_vma control; - - /* Pointer to member. */ - - if (! ieee_require_atn65 (info, pp, &name, &namlen) - || ! ieee_require_atn65 (info, pp, &mangled, &mangledlen) - || ! ieee_require_atn65 (info, pp, &class, &classlen) - || ! ieee_require_asn (info, pp, &control)) - return false; - - /* FIXME: We should now track down name and change its type. */ - } - break; - - case 'R': - if (! ieee_read_reference (info, pp)) - return false; - break; - } - - return true; -} - -/* Read a C++ class definition. This is a pmisc type 80 record of - category 'T'. */ - -static boolean -ieee_read_cxx_class (info, pp, count) - struct ieee_info *info; - const bfd_byte **pp; - unsigned long count; -{ - const bfd_byte *start; - bfd_vma class; - const char *tag; - unsigned long taglen; - struct ieee_tag *it; - PTR dhandle; - debug_field *fields; - unsigned int field_count, field_alloc; - debug_baseclass *baseclasses; - unsigned int baseclasses_count, baseclasses_alloc; - const debug_field *structfields; - struct ieee_method - { - const char *name; - unsigned long namlen; - debug_method_variant *variants; - unsigned count; - unsigned int alloc; - } *methods; - unsigned int methods_count, methods_alloc; - debug_type vptrbase; - boolean ownvptr; - debug_method *dmethods; - - start = *pp; - - if (! ieee_require_asn (info, pp, &class)) - return false; - --count; - - if (! ieee_require_atn65 (info, pp, &tag, &taglen)) - return false; - --count; - - /* Find the C struct with this name. */ - for (it = info->tags; it != NULL; it = it->next) - if (it->name[0] == tag[0] - && strncmp (it->name, tag, taglen) == 0 - && strlen (it->name) == taglen) - break; - if (it == NULL) - { - ieee_error (info, start, "undefined C++ object"); - return false; - } - - dhandle = info->dhandle; - - fields = NULL; - field_count = 0; - field_alloc = 0; - baseclasses = NULL; - baseclasses_count = 0; - baseclasses_alloc = 0; - methods = NULL; - methods_count = 0; - methods_alloc = 0; - vptrbase = DEBUG_TYPE_NULL; - ownvptr = false; - - structfields = debug_get_fields (dhandle, it->type); - - while (count > 0) - { - bfd_vma id; - const bfd_byte *spec_start; - - spec_start = *pp; - - if (! ieee_require_asn (info, pp, &id)) - return false; - --count; - - switch (id) - { - default: - ieee_error (info, spec_start, "unrecognized C++ object spec"); - return false; - - case 'b': - { - bfd_vma flags, cinline; - const char *basename, *fieldname; - unsigned long baselen, fieldlen; - char *basecopy; - debug_type basetype; - bfd_vma bitpos; - boolean virtualp; - enum debug_visibility visibility; - debug_baseclass baseclass; - - /* This represents a base or friend class. */ - - if (! ieee_require_asn (info, pp, &flags) - || ! ieee_require_atn65 (info, pp, &basename, &baselen) - || ! ieee_require_asn (info, pp, &cinline) - || ! ieee_require_atn65 (info, pp, &fieldname, &fieldlen)) - return false; - count -= 4; - - /* We have no way of recording friend information, so we - just ignore it. */ - if ((flags & BASEFLAGS_FRIEND) != 0) - break; - - /* I assume that either all of the members of the - baseclass are included in the object, starting at the - beginning of the object, or that none of them are - included. */ - - if ((fieldlen == 0) == (cinline == 0)) - { - ieee_error (info, start, "unsupported C++ object type"); - return false; - } - - basecopy = savestring (basename, baselen); - basetype = debug_find_tagged_type (dhandle, basecopy, - DEBUG_KIND_ILLEGAL); - free (basecopy); - if (basetype == DEBUG_TYPE_NULL) - { - ieee_error (info, start, "C++ base class not defined"); - return false; - } - - if (fieldlen == 0) - bitpos = 0; - else - { - const debug_field *pf; - - if (structfields == NULL) - { - ieee_error (info, start, "C++ object has no fields"); - return false; - } - - for (pf = structfields; *pf != DEBUG_FIELD_NULL; pf++) - { - const char *fname; - - fname = debug_get_field_name (dhandle, *pf); - if (fname == NULL) - return false; - if (fname[0] == fieldname[0] - && strncmp (fname, fieldname, fieldlen) == 0 - && strlen (fname) == fieldlen) - break; - } - if (*pf == DEBUG_FIELD_NULL) - { - ieee_error (info, start, - "C++ base class not found in container"); - return false; - } - - bitpos = debug_get_field_bitpos (dhandle, *pf); - } - - if ((flags & BASEFLAGS_VIRTUAL) != 0) - virtualp = true; - else - virtualp = false; - if ((flags & BASEFLAGS_PRIVATE) != 0) - visibility = DEBUG_VISIBILITY_PRIVATE; - else - visibility = DEBUG_VISIBILITY_PUBLIC; - - baseclass = debug_make_baseclass (dhandle, basetype, bitpos, - virtualp, visibility); - if (baseclass == DEBUG_BASECLASS_NULL) - return false; - - if (baseclasses_count + 1 >= baseclasses_alloc) - { - baseclasses_alloc += 10; - baseclasses = ((debug_baseclass *) - xrealloc (baseclasses, - (baseclasses_alloc - * sizeof *baseclasses))); - } - - baseclasses[baseclasses_count] = baseclass; - ++baseclasses_count; - baseclasses[baseclasses_count] = DEBUG_BASECLASS_NULL; - } - break; - - case 'd': - { - bfd_vma flags; - const char *fieldname, *mangledname; - unsigned long fieldlen, mangledlen; - char *fieldcopy; - boolean staticp; - debug_type ftype; - const debug_field *pf = NULL; - enum debug_visibility visibility; - debug_field field; - - /* This represents a data member. */ - - if (! ieee_require_asn (info, pp, &flags) - || ! ieee_require_atn65 (info, pp, &fieldname, &fieldlen) - || ! ieee_require_atn65 (info, pp, &mangledname, &mangledlen)) - return false; - count -= 3; - - fieldcopy = savestring (fieldname, fieldlen); - - staticp = (flags & CXXFLAGS_STATIC) != 0 ? true : false; - - if (staticp) - { - struct ieee_var *pv, *pvend; - - /* See if we can find a definition for this variable. */ - pv = info->vars.vars; - pvend = pv + info->vars.alloc; - for (; pv < pvend; pv++) - if (pv->namlen == mangledlen - && strncmp (pv->name, mangledname, mangledlen) == 0) - break; - if (pv < pvend) - ftype = pv->type; - else - { - /* This can happen if the variable is never used. */ - ftype = ieee_builtin_type (info, start, - (unsigned int) builtin_void); - } - } - else - { - unsigned int findx; - - if (structfields == NULL) - { - ieee_error (info, start, "C++ object has no fields"); - return false; - } - - for (pf = structfields, findx = 0; - *pf != DEBUG_FIELD_NULL; - pf++, findx++) - { - const char *fname; - - fname = debug_get_field_name (dhandle, *pf); - if (fname == NULL) - return false; - if (fname[0] == mangledname[0] - && strncmp (fname, mangledname, mangledlen) == 0 - && strlen (fname) == mangledlen) - break; - } - if (*pf == DEBUG_FIELD_NULL) - { - ieee_error (info, start, - "C++ data member not found in container"); - return false; - } - - ftype = debug_get_field_type (dhandle, *pf); - - if (debug_get_type_kind (dhandle, ftype) == DEBUG_KIND_POINTER) - { - /* We might need to convert this field into a - reference type later on, so make it an indirect - type. */ - if (it->fslots == NULL) - { - unsigned int fcnt; - const debug_field *pfcnt; - - fcnt = 0; - for (pfcnt = structfields; - *pfcnt != DEBUG_FIELD_NULL; - pfcnt++) - ++fcnt; - it->fslots = ((debug_type *) - xmalloc (fcnt * sizeof *it->fslots)); - memset (it->fslots, 0, - fcnt * sizeof *it->fslots); - } - - if (ftype == DEBUG_TYPE_NULL) - return false; - it->fslots[findx] = ftype; - ftype = debug_make_indirect_type (dhandle, - it->fslots + findx, - (const char *) NULL); - } - } - if (ftype == DEBUG_TYPE_NULL) - return false; - - switch (flags & CXXFLAGS_VISIBILITY) - { - default: - ieee_error (info, start, "unknown C++ visibility"); - return false; - - case CXXFLAGS_VISIBILITY_PUBLIC: - visibility = DEBUG_VISIBILITY_PUBLIC; - break; - - case CXXFLAGS_VISIBILITY_PRIVATE: - visibility = DEBUG_VISIBILITY_PRIVATE; - break; - - case CXXFLAGS_VISIBILITY_PROTECTED: - visibility = DEBUG_VISIBILITY_PROTECTED; - break; - } - - if (staticp) - { - char *mangledcopy; - - mangledcopy = savestring (mangledname, mangledlen); - - field = debug_make_static_member (dhandle, fieldcopy, - ftype, mangledcopy, - visibility); - } - else - { - bfd_vma bitpos, bitsize; - - bitpos = debug_get_field_bitpos (dhandle, *pf); - bitsize = debug_get_field_bitsize (dhandle, *pf); - if (bitpos == (bfd_vma) -1 || bitsize == (bfd_vma) -1) - { - ieee_error (info, start, "bad C++ field bit pos or size"); - return false; - } - field = debug_make_field (dhandle, fieldcopy, ftype, bitpos, - bitsize, visibility); - } - - if (field == DEBUG_FIELD_NULL) - return false; - - if (field_count + 1 >= field_alloc) - { - field_alloc += 10; - fields = ((debug_field *) - xrealloc (fields, field_alloc * sizeof *fields)); - } - - fields[field_count] = field; - ++field_count; - fields[field_count] = DEBUG_FIELD_NULL; - } - break; - - case 'm': - case 'v': - { - bfd_vma flags, voffset, control; - const char *name, *mangled; - unsigned long namlen, mangledlen; - struct ieee_var *pv, *pvend; - debug_type type; - enum debug_visibility visibility; - boolean constp, volatilep; - char *mangledcopy; - debug_method_variant mv; - struct ieee_method *meth; - unsigned int im; - - if (! ieee_require_asn (info, pp, &flags) - || ! ieee_require_atn65 (info, pp, &name, &namlen) - || ! ieee_require_atn65 (info, pp, &mangled, &mangledlen)) - return false; - count -= 3; - if (id != 'v') - voffset = 0; - else - { - if (! ieee_require_asn (info, pp, &voffset)) - return false; - --count; - } - if (! ieee_require_asn (info, pp, &control)) - return false; - --count; - - /* We just ignore the control information. */ - - /* We have no way to represent friend information, so we - just ignore it. */ - if ((flags & CXXFLAGS_FRIEND) != 0) - break; - - /* We should already have seen a type for the function. */ - pv = info->vars.vars; - pvend = pv + info->vars.alloc; - for (; pv < pvend; pv++) - if (pv->namlen == mangledlen - && strncmp (pv->name, mangled, mangledlen) == 0) - break; - - if (pv >= pvend) - { - /* We won't have type information for this function if - it is not included in this file. We don't try to - handle this case. FIXME. */ - type = (debug_make_function_type - (dhandle, - ieee_builtin_type (info, start, - (unsigned int) builtin_void), - (debug_type *) NULL, - false)); - } - else - { - debug_type return_type; - const debug_type *arg_types; - boolean varargs; - - if (debug_get_type_kind (dhandle, pv->type) - != DEBUG_KIND_FUNCTION) - { - ieee_error (info, start, - "bad type for C++ method function"); - return false; - } - - return_type = debug_get_return_type (dhandle, pv->type); - arg_types = debug_get_parameter_types (dhandle, pv->type, - &varargs); - if (return_type == DEBUG_TYPE_NULL || arg_types == NULL) - { - ieee_error (info, start, - "no type information for C++ method function"); - return false; - } - - type = debug_make_method_type (dhandle, return_type, it->type, - (debug_type *) arg_types, - varargs); - } - if (type == DEBUG_TYPE_NULL) - return false; - - switch (flags & CXXFLAGS_VISIBILITY) - { - default: - ieee_error (info, start, "unknown C++ visibility"); - return false; - - case CXXFLAGS_VISIBILITY_PUBLIC: - visibility = DEBUG_VISIBILITY_PUBLIC; - break; - - case CXXFLAGS_VISIBILITY_PRIVATE: - visibility = DEBUG_VISIBILITY_PRIVATE; - break; - - case CXXFLAGS_VISIBILITY_PROTECTED: - visibility = DEBUG_VISIBILITY_PROTECTED; - break; - } - - constp = (flags & CXXFLAGS_CONST) != 0 ? true : false; - volatilep = (flags & CXXFLAGS_VOLATILE) != 0 ? true : false; - - mangledcopy = savestring (mangled, mangledlen); - - if ((flags & CXXFLAGS_STATIC) != 0) - { - if (id == 'v') - { - ieee_error (info, start, "C++ static virtual method"); - return false; - } - mv = debug_make_static_method_variant (dhandle, mangledcopy, - type, visibility, - constp, volatilep); - } - else - { - debug_type vcontext; - - if (id != 'v') - vcontext = DEBUG_TYPE_NULL; - else - { - /* FIXME: How can we calculate this correctly? */ - vcontext = it->type; - } - mv = debug_make_method_variant (dhandle, mangledcopy, type, - visibility, constp, - volatilep, voffset, - vcontext); - } - if (mv == DEBUG_METHOD_VARIANT_NULL) - return false; - - for (meth = methods, im = 0; im < methods_count; meth++, im++) - if (meth->namlen == namlen - && strncmp (meth->name, name, namlen) == 0) - break; - if (im >= methods_count) - { - if (methods_count >= methods_alloc) - { - methods_alloc += 10; - methods = ((struct ieee_method *) - xrealloc (methods, - methods_alloc * sizeof *methods)); - } - methods[methods_count].name = name; - methods[methods_count].namlen = namlen; - methods[methods_count].variants = NULL; - methods[methods_count].count = 0; - methods[methods_count].alloc = 0; - meth = methods + methods_count; - ++methods_count; - } - - if (meth->count + 1 >= meth->alloc) - { - meth->alloc += 10; - meth->variants = ((debug_method_variant *) - xrealloc (meth->variants, - (meth->alloc - * sizeof *meth->variants))); - } - - meth->variants[meth->count] = mv; - ++meth->count; - meth->variants[meth->count] = DEBUG_METHOD_VARIANT_NULL; - } - break; - - case 'o': - { - bfd_vma spec; - - /* We have no way to store this information, so we just - ignore it. */ - if (! ieee_require_asn (info, pp, &spec)) - return false; - --count; - if ((spec & 4) != 0) - { - const char *filename; - unsigned long filenamlen; - bfd_vma lineno; - - if (! ieee_require_atn65 (info, pp, &filename, &filenamlen) - || ! ieee_require_asn (info, pp, &lineno)) - return false; - count -= 2; - } - else if ((spec & 8) != 0) - { - const char *mangled; - unsigned long mangledlen; - - if (! ieee_require_atn65 (info, pp, &mangled, &mangledlen)) - return false; - --count; - } - else - { - ieee_error (info, start, - "unrecognized C++ object overhead spec"); - return false; - } - } - break; - - case 'z': - { - const char *vname, *basename; - unsigned long vnamelen, baselen; - bfd_vma vsize, control; - - /* A virtual table pointer. */ - - if (! ieee_require_atn65 (info, pp, &vname, &vnamelen) - || ! ieee_require_asn (info, pp, &vsize) - || ! ieee_require_atn65 (info, pp, &basename, &baselen) - || ! ieee_require_asn (info, pp, &control)) - return false; - count -= 4; - - /* We just ignore the control number. We don't care what - the virtual table name is. We have no way to store the - virtual table size, and I don't think we care anyhow. */ - - /* FIXME: We can't handle multiple virtual table pointers. */ - - if (baselen == 0) - ownvptr = true; - else - { - char *basecopy; - - basecopy = savestring (basename, baselen); - vptrbase = debug_find_tagged_type (dhandle, basecopy, - DEBUG_KIND_ILLEGAL); - free (basecopy); - if (vptrbase == DEBUG_TYPE_NULL) - { - ieee_error (info, start, "undefined C++ vtable"); - return false; - } - } - } - break; - } - } - - /* Now that we have seen all the method variants, we can call - debug_make_method for each one. */ - - if (methods_count == 0) - dmethods = NULL; - else - { - unsigned int i; - - dmethods = ((debug_method *) - xmalloc ((methods_count + 1) * sizeof *dmethods)); - for (i = 0; i < methods_count; i++) - { - char *namcopy; - - namcopy = savestring (methods[i].name, methods[i].namlen); - dmethods[i] = debug_make_method (dhandle, namcopy, - methods[i].variants); - if (dmethods[i] == DEBUG_METHOD_NULL) - return false; - } - dmethods[i] = DEBUG_METHOD_NULL; - free (methods); - } - - /* The struct type was created as an indirect type pointing at - it->slot. We update it->slot to automatically update all - references to this struct. */ - it->slot = debug_make_object_type (dhandle, - class != 'u', - debug_get_type_size (dhandle, - it->slot), - fields, baseclasses, dmethods, - vptrbase, ownvptr); - if (it->slot == DEBUG_TYPE_NULL) - return false; - - return true; -} - -/* Read C++ default argument value and reference type information. */ - -static boolean -ieee_read_cxx_defaults (info, pp, count) - struct ieee_info *info; - const bfd_byte **pp; - unsigned long count; -{ - const bfd_byte *start; - const char *fnname; - unsigned long fnlen; - bfd_vma defcount; - - start = *pp; - - /* Giving the function name before the argument count is an addendum - to the spec. The function name is demangled, though, so this - record must always refer to the current function. */ - - if (info->blockstack.bsp <= info->blockstack.stack - || info->blockstack.bsp[-1].fnindx == (unsigned int) -1) - { - ieee_error (info, start, "C++ default values not in a function"); - return false; - } - - if (! ieee_require_atn65 (info, pp, &fnname, &fnlen) - || ! ieee_require_asn (info, pp, &defcount)) - return false; - count -= 2; - - while (defcount-- > 0) - { - bfd_vma type, val; - const char *strval; - unsigned long strvallen; - - if (! ieee_require_asn (info, pp, &type)) - return false; - --count; - - switch (type) - { - case 0: - case 4: - break; - - case 1: - case 2: - if (! ieee_require_asn (info, pp, &val)) - return false; - --count; - break; - - case 3: - case 7: - if (! ieee_require_atn65 (info, pp, &strval, &strvallen)) - return false; - --count; - break; - - default: - ieee_error (info, start, "unrecognized C++ default type"); - return false; - } - - /* We have no way to record the default argument values, so we - just ignore them. FIXME. */ - } - - /* Any remaining arguments are indices of parameters that are really - reference type. */ - if (count > 0) - { - PTR dhandle; - debug_type *arg_slots; - - dhandle = info->dhandle; - arg_slots = info->types.types[info->blockstack.bsp[-1].fnindx].arg_slots; - while (count-- > 0) - { - bfd_vma indx; - debug_type target; - - if (! ieee_require_asn (info, pp, &indx)) - return false; - /* The index is 1 based. */ - --indx; - if (arg_slots == NULL - || arg_slots[indx] == DEBUG_TYPE_NULL - || (debug_get_type_kind (dhandle, arg_slots[indx]) - != DEBUG_KIND_POINTER)) - { - ieee_error (info, start, "reference parameter is not a pointer"); - return false; - } - - target = debug_get_target_type (dhandle, arg_slots[indx]); - arg_slots[indx] = debug_make_reference_type (dhandle, target); - if (arg_slots[indx] == DEBUG_TYPE_NULL) - return false; - } - } - - return true; -} - -/* Read a C++ reference definition. */ - -static boolean -ieee_read_reference (info, pp) - struct ieee_info *info; - const bfd_byte **pp; -{ - const bfd_byte *start; - bfd_vma flags; - const char *class, *name; - unsigned long classlen, namlen; - debug_type *pslot; - debug_type target; - - start = *pp; - - if (! ieee_require_asn (info, pp, &flags)) - return false; - - /* Giving the class name before the member name is in an addendum to - the spec. */ - if (flags == 3) - { - if (! ieee_require_atn65 (info, pp, &class, &classlen)) - return false; - } - - if (! ieee_require_atn65 (info, pp, &name, &namlen)) - return false; - - pslot = NULL; - if (flags != 3) - { - int pass; - - /* We search from the last variable indices to the first in - hopes of finding local variables correctly. We search the - local variables on the first pass, and the global variables - on the second. FIXME: This probably won't work in all cases. - On the other hand, I don't know what will. */ - for (pass = 0; pass < 2; pass++) - { - struct ieee_vars *vars; - int i; - struct ieee_var *pv = NULL; - - if (pass == 0) - vars = &info->vars; - else - { - vars = info->global_vars; - if (vars == NULL) - break; - } - - for (i = (int) vars->alloc - 1; i >= 0; i--) - { - boolean found; - - pv = vars->vars + i; - - if (pv->pslot == NULL - || pv->namlen != namlen - || strncmp (pv->name, name, namlen) != 0) - continue; - - found = false; - switch (flags) - { - default: - ieee_error (info, start, - "unrecognized C++ reference type"); - return false; - - case 0: - /* Global variable or function. */ - if (pv->kind == IEEE_GLOBAL - || pv->kind == IEEE_EXTERNAL - || pv->kind == IEEE_FUNCTION) - found = true; - break; - - case 1: - /* Global static variable or function. */ - if (pv->kind == IEEE_STATIC - || pv->kind == IEEE_FUNCTION) - found = true; - break; - - case 2: - /* Local variable. */ - if (pv->kind == IEEE_LOCAL) - found = true; - break; - } - - if (found) - break; - } - - if (i >= 0) - { - pslot = pv->pslot; - break; - } - } - } - else - { - struct ieee_tag *it; - - for (it = info->tags; it != NULL; it = it->next) - { - if (it->name[0] == class[0] - && strncmp (it->name, class, classlen) == 0 - && strlen (it->name) == classlen) - { - if (it->fslots != NULL) - { - const debug_field *pf; - unsigned int findx; - - pf = debug_get_fields (info->dhandle, it->type); - if (pf == NULL) - { - ieee_error (info, start, - "C++ reference in class with no fields"); - return false; - } - - for (findx = 0; *pf != DEBUG_FIELD_NULL; pf++, findx++) - { - const char *fname; - - fname = debug_get_field_name (info->dhandle, *pf); - if (fname == NULL) - return false; - if (strncmp (fname, name, namlen) == 0 - && strlen (fname) == namlen) - { - pslot = it->fslots + findx; - break; - } - } - } - - break; - } - } - } - - if (pslot == NULL) - { - ieee_error (info, start, "C++ reference not found"); - return false; - } - - /* We allocated the type of the object as an indirect type pointing - to *pslot, which we can now update to be a reference type. */ - if (debug_get_type_kind (info->dhandle, *pslot) != DEBUG_KIND_POINTER) - { - ieee_error (info, start, "C++ reference is not pointer"); - return false; - } - - target = debug_get_target_type (info->dhandle, *pslot); - *pslot = debug_make_reference_type (info->dhandle, target); - if (*pslot == DEBUG_TYPE_NULL) - return false; - - return true; -} - -/* Require an ASN record. */ - -static boolean -ieee_require_asn (info, pp, pv) - struct ieee_info *info; - const bfd_byte **pp; - bfd_vma *pv; -{ - const bfd_byte *start; - ieee_record_enum_type c; - bfd_vma varindx; - - start = *pp; - - c = (ieee_record_enum_type) **pp; - if (c != ieee_e2_first_byte_enum) - { - ieee_error (info, start, "missing required ASN"); - return false; - } - ++*pp; - - c = (ieee_record_enum_type) (((unsigned int) c << 8) | **pp); - if (c != ieee_asn_record_enum) - { - ieee_error (info, start, "missing required ASN"); - return false; - } - ++*pp; - - /* Just ignore the variable index. */ - if (! ieee_read_number (info, pp, &varindx)) - return false; - - return ieee_read_expression (info, pp, pv); -} - -/* Require an ATN65 record. */ - -static boolean -ieee_require_atn65 (info, pp, pname, pnamlen) - struct ieee_info *info; - const bfd_byte **pp; - const char **pname; - unsigned long *pnamlen; -{ - const bfd_byte *start; - ieee_record_enum_type c; - bfd_vma name_indx, type_indx, atn_code; - - start = *pp; - - c = (ieee_record_enum_type) **pp; - if (c != ieee_at_record_enum) - { - ieee_error (info, start, "missing required ATN65"); - return false; - } - ++*pp; - - c = (ieee_record_enum_type) (((unsigned int) c << 8) | **pp); - if (c != ieee_atn_record_enum) - { - ieee_error (info, start, "missing required ATN65"); - return false; - } - ++*pp; - - if (! ieee_read_number (info, pp, &name_indx) - || ! ieee_read_number (info, pp, &type_indx) - || ! ieee_read_number (info, pp, &atn_code)) - return false; - - /* Just ignore name_indx. */ - - if (type_indx != 0 || atn_code != 65) - { - ieee_error (info, start, "bad ATN65 record"); - return false; - } - - return ieee_read_id (info, pp, pname, pnamlen); -} - -/* Convert a register number in IEEE debugging information into a - generic register number. */ - -static int -ieee_regno_to_genreg (abfd, r) - bfd *abfd; - int r; -{ - switch (bfd_get_arch (abfd)) - { - case bfd_arch_m68k: - /* For some reasons stabs adds 2 to the floating point register - numbers. */ - if (r >= 16) - r += 2; - break; - - case bfd_arch_i960: - /* Stabs uses 0 to 15 for r0 to r15, 16 to 31 for g0 to g15, and - 32 to 35 for fp0 to fp3. */ - --r; - break; - - default: - break; - } - - return r; -} - -/* Convert a generic register number to an IEEE specific one. */ - -static int -ieee_genreg_to_regno (abfd, r) - bfd *abfd; - int r; -{ - switch (bfd_get_arch (abfd)) - { - case bfd_arch_m68k: - /* For some reason stabs add 2 to the floating point register - numbers. */ - if (r >= 18) - r -= 2; - break; - - case bfd_arch_i960: - /* Stabs uses 0 to 15 for r0 to r15, 16 to 31 for g0 to g15, and - 32 to 35 for fp0 to fp3. */ - ++r; - break; - - default: - break; - } - - return r; -} - -/* These routines build IEEE debugging information out of the generic - debugging information. */ - -/* We build the IEEE debugging information byte by byte. Rather than - waste time copying data around, we use a linked list of buffers to - hold the data. */ - -#define IEEE_BUFSIZE (490) - -struct ieee_buf -{ - /* Next buffer. */ - struct ieee_buf *next; - /* Number of data bytes in this buffer. */ - unsigned int c; - /* Bytes. */ - bfd_byte buf[IEEE_BUFSIZE]; -}; - -/* A list of buffers. */ - -struct ieee_buflist -{ - /* Head of list. */ - struct ieee_buf *head; - /* Tail--last buffer on list. */ - struct ieee_buf *tail; -}; - -/* In order to generate the BB11 blocks required by the HP emulator, - we keep track of ranges of addresses which correspond to a given - compilation unit. */ - -struct ieee_range -{ - /* Next range. */ - struct ieee_range *next; - /* Low address. */ - bfd_vma low; - /* High address. */ - bfd_vma high; -}; - -/* This structure holds information for a class on the type stack. */ - -struct ieee_type_class -{ - /* The name index in the debugging information. */ - unsigned int indx; - /* The pmisc records for the class. */ - struct ieee_buflist pmiscbuf; - /* The number of pmisc records. */ - unsigned int pmisccount; - /* The name of the class holding the virtual table, if not this - class. */ - const char *vclass; - /* Whether this class holds its own virtual table. */ - boolean ownvptr; - /* The largest virtual table offset seen so far. */ - bfd_vma voffset; - /* The current method. */ - const char *method; - /* Additional pmisc records used to record fields of reference type. */ - struct ieee_buflist refs; -}; - -/* This is how we store types for the writing routines. Most types - are simply represented by a type index. */ - -struct ieee_write_type -{ - /* Type index. */ - unsigned int indx; - /* The size of the type, if known. */ - unsigned int size; - /* The name of the type, if any. */ - const char *name; - /* If this is a function or method type, we build the type here, and - only add it to the output buffers if we need it. */ - struct ieee_buflist fndef; - /* If this is a struct, this is where the struct definition is - built. */ - struct ieee_buflist strdef; - /* If this is a class, this is where the class information is built. */ - struct ieee_type_class *classdef; - /* Whether the type is unsigned. */ - unsigned int unsignedp : 1; - /* Whether this is a reference type. */ - unsigned int referencep : 1; - /* Whether this is in the local type block. */ - unsigned int localp : 1; - /* Whether this is a duplicate struct definition which we are - ignoring. */ - unsigned int ignorep : 1; -}; - -/* This is the type stack used by the debug writing routines. FIXME: - We could generate more efficient output if we remembered when we - have output a particular type before. */ - -struct ieee_type_stack -{ - /* Next entry on stack. */ - struct ieee_type_stack *next; - /* Type information. */ - struct ieee_write_type type; -}; - -/* This is a list of associations between a name and some types. - These are used for typedefs and tags. */ - -struct ieee_name_type -{ - /* Next type for this name. */ - struct ieee_name_type *next; - /* ID number. For a typedef, this is the index of the type to which - this name is typedefed. */ - unsigned int id; - /* Type. */ - struct ieee_write_type type; - /* If this is a tag which has not yet been defined, this is the - kind. If the tag has been defined, this is DEBUG_KIND_ILLEGAL. */ - enum debug_type_kind kind; -}; - -/* We use a hash table to associate names and types. */ - -struct ieee_name_type_hash_table -{ - struct bfd_hash_table root; -}; - -struct ieee_name_type_hash_entry -{ - struct bfd_hash_entry root; - /* Information for this name. */ - struct ieee_name_type *types; -}; - -/* This is a list of enums. */ - -struct ieee_defined_enum -{ - /* Next enum. */ - struct ieee_defined_enum *next; - /* Type index. */ - unsigned int indx; - /* Whether this enum has been defined. */ - boolean defined; - /* Tag. */ - const char *tag; - /* Names. */ - const char **names; - /* Values. */ - bfd_signed_vma *vals; -}; - -/* We keep a list of modified versions of types, so that we don't - output them more than once. */ - -struct ieee_modified_type -{ - /* Pointer to this type. */ - unsigned int pointer; - /* Function with unknown arguments returning this type. */ - unsigned int function; - /* Const version of this type. */ - unsigned int const_qualified; - /* Volatile version of this type. */ - unsigned int volatile_qualified; - /* List of arrays of this type of various bounds. */ - struct ieee_modified_array_type *arrays; -}; - -/* A list of arrays bounds. */ - -struct ieee_modified_array_type -{ - /* Next array bounds. */ - struct ieee_modified_array_type *next; - /* Type index with these bounds. */ - unsigned int indx; - /* Low bound. */ - bfd_signed_vma low; - /* High bound. */ - bfd_signed_vma high; -}; - -/* This is a list of pending function parameter information. We don't - output them until we see the first block. */ - -struct ieee_pending_parm -{ - /* Next pending parameter. */ - struct ieee_pending_parm *next; - /* Name. */ - const char *name; - /* Type index. */ - unsigned int type; - /* Whether the type is a reference. */ - boolean referencep; - /* Kind. */ - enum debug_parm_kind kind; - /* Value. */ - bfd_vma val; -}; - -/* This is the handle passed down by debug_write. */ - -struct ieee_handle -{ - /* BFD we are writing to. */ - bfd *abfd; - /* Whether we got an error in a subroutine called via traverse or - map_over_sections. */ - boolean error; - /* Current data buffer list. */ - struct ieee_buflist *current; - /* Current data buffer. */ - struct ieee_buf *curbuf; - /* Filename of current compilation unit. */ - const char *filename; - /* Module name of current compilation unit. */ - const char *modname; - /* List of buffer for global types. */ - struct ieee_buflist global_types; - /* List of finished data buffers. */ - struct ieee_buflist data; - /* List of buffers for typedefs in the current compilation unit. */ - struct ieee_buflist types; - /* List of buffers for variables and functions in the current - compilation unit. */ - struct ieee_buflist vars; - /* List of buffers for C++ class definitions in the current - compilation unit. */ - struct ieee_buflist cxx; - /* List of buffers for line numbers in the current compilation unit. */ - struct ieee_buflist linenos; - /* Ranges for the current compilation unit. */ - struct ieee_range *ranges; - /* Ranges for all debugging information. */ - struct ieee_range *global_ranges; - /* Nested pending ranges. */ - struct ieee_range *pending_ranges; - /* Type stack. */ - struct ieee_type_stack *type_stack; - /* Next unallocated type index. */ - unsigned int type_indx; - /* Next unallocated name index. */ - unsigned int name_indx; - /* Typedefs. */ - struct ieee_name_type_hash_table typedefs; - /* Tags. */ - struct ieee_name_type_hash_table tags; - /* Enums. */ - struct ieee_defined_enum *enums; - /* Modified versions of types. */ - struct ieee_modified_type *modified; - /* Number of entries allocated in modified. */ - unsigned int modified_alloc; - /* 4 byte complex type. */ - unsigned int complex_float_index; - /* 8 byte complex type. */ - unsigned int complex_double_index; - /* The depth of block nesting. This is 0 outside a function, and 1 - just after start_function is called. */ - unsigned int block_depth; - /* The name of the current function. */ - const char *fnname; - /* List of buffers for the type of the function we are currently - writing out. */ - struct ieee_buflist fntype; - /* List of buffers for the parameters of the function we are - currently writing out. */ - struct ieee_buflist fnargs; - /* Number of arguments written to fnargs. */ - unsigned int fnargcount; - /* Pending function parameters. */ - struct ieee_pending_parm *pending_parms; - /* Current line number filename. */ - const char *lineno_filename; - /* Line number name index. */ - unsigned int lineno_name_indx; - /* Filename of pending line number. */ - const char *pending_lineno_filename; - /* Pending line number. */ - unsigned long pending_lineno; - /* Address of pending line number. */ - bfd_vma pending_lineno_addr; - /* Highest address seen at end of procedure. */ - bfd_vma highaddr; -}; - -static boolean ieee_init_buffer - PARAMS ((struct ieee_handle *, struct ieee_buflist *)); -static boolean ieee_change_buffer - PARAMS ((struct ieee_handle *, struct ieee_buflist *)); -static boolean ieee_append_buffer - PARAMS ((struct ieee_handle *, struct ieee_buflist *, - struct ieee_buflist *)); -static boolean ieee_real_write_byte PARAMS ((struct ieee_handle *, int)); -static boolean ieee_write_2bytes PARAMS ((struct ieee_handle *, int)); -static boolean ieee_write_number PARAMS ((struct ieee_handle *, bfd_vma)); -static boolean ieee_write_id PARAMS ((struct ieee_handle *, const char *)); -static boolean ieee_write_asn - PARAMS ((struct ieee_handle *, unsigned int, bfd_vma)); -static boolean ieee_write_atn65 - PARAMS ((struct ieee_handle *, unsigned int, const char *)); -static boolean ieee_push_type - PARAMS ((struct ieee_handle *, unsigned int, unsigned int, boolean, - boolean)); -static unsigned int ieee_pop_type PARAMS ((struct ieee_handle *)); -static void ieee_pop_unused_type PARAMS ((struct ieee_handle *)); -static unsigned int ieee_pop_type_used - PARAMS ((struct ieee_handle *, boolean)); -static boolean ieee_add_range - PARAMS ((struct ieee_handle *, boolean, bfd_vma, bfd_vma)); -static boolean ieee_start_range PARAMS ((struct ieee_handle *, bfd_vma)); -static boolean ieee_end_range PARAMS ((struct ieee_handle *, bfd_vma)); -static boolean ieee_define_type - PARAMS ((struct ieee_handle *, unsigned int, boolean, boolean)); -static boolean ieee_define_named_type - PARAMS ((struct ieee_handle *, const char *, unsigned int, unsigned int, - boolean, boolean, struct ieee_buflist *)); -static struct ieee_modified_type *ieee_get_modified_info - PARAMS ((struct ieee_handle *, unsigned int)); -static struct bfd_hash_entry *ieee_name_type_newfunc - PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); -static boolean ieee_write_undefined_tag - PARAMS ((struct ieee_name_type_hash_entry *, PTR)); -static boolean ieee_finish_compilation_unit PARAMS ((struct ieee_handle *)); -static void ieee_add_bb11_blocks PARAMS ((bfd *, asection *, PTR)); -static boolean ieee_add_bb11 - PARAMS ((struct ieee_handle *, asection *, bfd_vma, bfd_vma)); -static boolean ieee_output_pending_parms PARAMS ((struct ieee_handle *)); -static unsigned int ieee_vis_to_flags PARAMS ((enum debug_visibility)); -static boolean ieee_class_method_var - PARAMS ((struct ieee_handle *, const char *, enum debug_visibility, boolean, - boolean, boolean, bfd_vma, boolean)); - -static boolean ieee_start_compilation_unit PARAMS ((PTR, const char *)); -static boolean ieee_start_source PARAMS ((PTR, const char *)); -static boolean ieee_empty_type PARAMS ((PTR)); -static boolean ieee_void_type PARAMS ((PTR)); -static boolean ieee_int_type PARAMS ((PTR, unsigned int, boolean)); -static boolean ieee_float_type PARAMS ((PTR, unsigned int)); -static boolean ieee_complex_type PARAMS ((PTR, unsigned int)); -static boolean ieee_bool_type PARAMS ((PTR, unsigned int)); -static boolean ieee_enum_type - PARAMS ((PTR, const char *, const char **, bfd_signed_vma *)); -static boolean ieee_pointer_type PARAMS ((PTR)); -static boolean ieee_function_type PARAMS ((PTR, int, boolean)); -static boolean ieee_reference_type PARAMS ((PTR)); -static boolean ieee_range_type PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma)); -static boolean ieee_array_type - PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, boolean)); -static boolean ieee_set_type PARAMS ((PTR, boolean)); -static boolean ieee_offset_type PARAMS ((PTR)); -static boolean ieee_method_type PARAMS ((PTR, boolean, int, boolean)); -static boolean ieee_const_type PARAMS ((PTR)); -static boolean ieee_volatile_type PARAMS ((PTR)); -static boolean ieee_start_struct_type - PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int)); -static boolean ieee_struct_field - PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility)); -static boolean ieee_end_struct_type PARAMS ((PTR)); -static boolean ieee_start_class_type - PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int, boolean, - boolean)); -static boolean ieee_class_static_member - PARAMS ((PTR, const char *, const char *, enum debug_visibility)); -static boolean ieee_class_baseclass - PARAMS ((PTR, bfd_vma, boolean, enum debug_visibility)); -static boolean ieee_class_start_method PARAMS ((PTR, const char *)); -static boolean ieee_class_method_variant - PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean, - bfd_vma, boolean)); -static boolean ieee_class_static_method_variant - PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean)); -static boolean ieee_class_end_method PARAMS ((PTR)); -static boolean ieee_end_class_type PARAMS ((PTR)); -static boolean ieee_typedef_type PARAMS ((PTR, const char *)); -static boolean ieee_tag_type - PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind)); -static boolean ieee_typdef PARAMS ((PTR, const char *)); -static boolean ieee_tag PARAMS ((PTR, const char *)); -static boolean ieee_int_constant PARAMS ((PTR, const char *, bfd_vma)); -static boolean ieee_float_constant PARAMS ((PTR, const char *, double)); -static boolean ieee_typed_constant PARAMS ((PTR, const char *, bfd_vma)); -static boolean ieee_variable - PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma)); -static boolean ieee_start_function PARAMS ((PTR, const char *, boolean)); -static boolean ieee_function_parameter - PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma)); -static boolean ieee_start_block PARAMS ((PTR, bfd_vma)); -static boolean ieee_end_block PARAMS ((PTR, bfd_vma)); -static boolean ieee_end_function PARAMS ((PTR)); -static boolean ieee_lineno - PARAMS ((PTR, const char *, unsigned long, bfd_vma)); - -static const struct debug_write_fns ieee_fns = -{ - ieee_start_compilation_unit, - ieee_start_source, - ieee_empty_type, - ieee_void_type, - ieee_int_type, - ieee_float_type, - ieee_complex_type, - ieee_bool_type, - ieee_enum_type, - ieee_pointer_type, - ieee_function_type, - ieee_reference_type, - ieee_range_type, - ieee_array_type, - ieee_set_type, - ieee_offset_type, - ieee_method_type, - ieee_const_type, - ieee_volatile_type, - ieee_start_struct_type, - ieee_struct_field, - ieee_end_struct_type, - ieee_start_class_type, - ieee_class_static_member, - ieee_class_baseclass, - ieee_class_start_method, - ieee_class_method_variant, - ieee_class_static_method_variant, - ieee_class_end_method, - ieee_end_class_type, - ieee_typedef_type, - ieee_tag_type, - ieee_typdef, - ieee_tag, - ieee_int_constant, - ieee_float_constant, - ieee_typed_constant, - ieee_variable, - ieee_start_function, - ieee_function_parameter, - ieee_start_block, - ieee_end_block, - ieee_end_function, - ieee_lineno -}; - -/* Initialize a buffer to be empty. */ - -/*ARGSUSED*/ -static boolean -ieee_init_buffer (info, buflist) - struct ieee_handle *info; - struct ieee_buflist *buflist; -{ - buflist->head = NULL; - buflist->tail = NULL; - return true; -} - -/* See whether a buffer list has any data. */ - -#define ieee_buffer_emptyp(buflist) ((buflist)->head == NULL) - -/* Change the current buffer to a specified buffer chain. */ - -static boolean -ieee_change_buffer (info, buflist) - struct ieee_handle *info; - struct ieee_buflist *buflist; -{ - if (buflist->head == NULL) - { - struct ieee_buf *buf; - - buf = (struct ieee_buf *) xmalloc (sizeof *buf); - buf->next = NULL; - buf->c = 0; - buflist->head = buf; - buflist->tail = buf; - } - - info->current = buflist; - info->curbuf = buflist->tail; - - return true; -} - -/* Append a buffer chain. */ - -/*ARGSUSED*/ -static boolean -ieee_append_buffer (info, mainbuf, newbuf) - struct ieee_handle *info; - struct ieee_buflist *mainbuf; - struct ieee_buflist *newbuf; -{ - if (newbuf->head != NULL) - { - if (mainbuf->head == NULL) - mainbuf->head = newbuf->head; - else - mainbuf->tail->next = newbuf->head; - mainbuf->tail = newbuf->tail; - } - return true; -} - -/* Write a byte into the buffer. We use a macro for speed and a - function for the complex cases. */ - -#define ieee_write_byte(info, b) \ - ((info)->curbuf->c < IEEE_BUFSIZE \ - ? ((info)->curbuf->buf[(info)->curbuf->c++] = (b), true) \ - : ieee_real_write_byte ((info), (b))) - -static boolean -ieee_real_write_byte (info, b) - struct ieee_handle *info; - int b; -{ - if (info->curbuf->c >= IEEE_BUFSIZE) - { - struct ieee_buf *n; - - n = (struct ieee_buf *) xmalloc (sizeof *n); - n->next = NULL; - n->c = 0; - if (info->current->head == NULL) - info->current->head = n; - else - info->current->tail->next = n; - info->current->tail = n; - info->curbuf = n; - } - - info->curbuf->buf[info->curbuf->c] = b; - ++info->curbuf->c; - - return true; -} - -/* Write out two bytes. */ - -static boolean -ieee_write_2bytes (info, i) - struct ieee_handle *info; - int i; -{ - return (ieee_write_byte (info, i >> 8) - && ieee_write_byte (info, i & 0xff)); -} - -/* Write out an integer. */ - -static boolean -ieee_write_number (info, v) - struct ieee_handle *info; - bfd_vma v; -{ - bfd_vma t; - bfd_byte ab[20]; - bfd_byte *p; - unsigned int c; - - if (v <= (bfd_vma) ieee_number_end_enum) - return ieee_write_byte (info, (int) v); - - t = v; - p = ab + sizeof ab; - while (t != 0) - { - *--p = t & 0xff; - t >>= 8; - } - c = (ab + 20) - p; - - if (c > (unsigned int) (ieee_number_repeat_end_enum - - ieee_number_repeat_start_enum)) - { - fprintf (stderr, "IEEE numeric overflow: 0x"); - fprintf_vma (stderr, v); - fprintf (stderr, "\n"); - return false; - } - - if (! ieee_write_byte (info, (int) ieee_number_repeat_start_enum + c)) - return false; - for (; c > 0; --c, ++p) - { - if (! ieee_write_byte (info, *p)) - return false; - } - - return true; -} - -/* Write out a string. */ - -static boolean -ieee_write_id (info, s) - struct ieee_handle *info; - const char *s; -{ - unsigned int len; - - len = strlen (s); - if (len <= 0x7f) - { - if (! ieee_write_byte (info, len)) - return false; - } - else if (len <= 0xff) - { - if (! ieee_write_byte (info, (int) ieee_extension_length_1_enum) - || ! ieee_write_byte (info, len)) - return false; - } - else if (len <= 0xffff) - { - if (! ieee_write_byte (info, (int) ieee_extension_length_2_enum) - || ! ieee_write_2bytes (info, len)) - return false; - } - else - { - fprintf (stderr, "IEEE string length overflow: %u\n", len); - return false; - } - - for (; *s != '\0'; s++) - if (! ieee_write_byte (info, *s)) - return false; - - return true; -} - -/* Write out an ASN record. */ - -static boolean -ieee_write_asn (info, indx, val) - struct ieee_handle *info; - unsigned int indx; - bfd_vma val; -{ - return (ieee_write_2bytes (info, (int) ieee_asn_record_enum) - && ieee_write_number (info, indx) - && ieee_write_number (info, val)); -} - -/* Write out an ATN65 record. */ - -static boolean -ieee_write_atn65 (info, indx, s) - struct ieee_handle *info; - unsigned int indx; - const char *s; -{ - return (ieee_write_2bytes (info, (int) ieee_atn_record_enum) - && ieee_write_number (info, indx) - && ieee_write_number (info, 0) - && ieee_write_number (info, 65) - && ieee_write_id (info, s)); -} - -/* Push a type index onto the type stack. */ - -static boolean -ieee_push_type (info, indx, size, unsignedp, localp) - struct ieee_handle *info; - unsigned int indx; - unsigned int size; - boolean unsignedp; - boolean localp; -{ - struct ieee_type_stack *ts; - - ts = (struct ieee_type_stack *) xmalloc (sizeof *ts); - memset (ts, 0, sizeof *ts); - - ts->type.indx = indx; - ts->type.size = size; - ts->type.unsignedp = unsignedp; - ts->type.localp = localp; - - ts->next = info->type_stack; - info->type_stack = ts; - - return true; -} - -/* Pop a type index off the type stack. */ - -static unsigned int -ieee_pop_type (info) - struct ieee_handle *info; -{ - return ieee_pop_type_used (info, true); -} - -/* Pop an unused type index off the type stack. */ - -static void -ieee_pop_unused_type (info) - struct ieee_handle *info; -{ - (void) ieee_pop_type_used (info, false); -} - -/* Pop a used or unused type index off the type stack. */ - -static unsigned int -ieee_pop_type_used (info, used) - struct ieee_handle *info; - boolean used; -{ - struct ieee_type_stack *ts; - unsigned int ret; - - ts = info->type_stack; - assert (ts != NULL); - - /* If this is a function type, and we need it, we need to append the - actual definition to the typedef block now. */ - if (used && ! ieee_buffer_emptyp (&ts->type.fndef)) - { - struct ieee_buflist *buflist; - - if (ts->type.localp) - { - /* Make sure we have started the types block. */ - if (ieee_buffer_emptyp (&info->types)) - { - if (! ieee_change_buffer (info, &info->types) - || ! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 1) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, info->modname)) - return false; - } - buflist = &info->types; - } - else - { - /* Make sure we started the global type block. */ - if (ieee_buffer_emptyp (&info->global_types)) - { - if (! ieee_change_buffer (info, &info->global_types) - || ! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 2) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, "")) - return false; - } - buflist = &info->global_types; - } - - if (! ieee_append_buffer (info, buflist, &ts->type.fndef)) - return false; - } - - ret = ts->type.indx; - info->type_stack = ts->next; - free (ts); - return ret; -} - -/* Add a range of bytes included in the current compilation unit. */ - -static boolean -ieee_add_range (info, global, low, high) - struct ieee_handle *info; - boolean global; - bfd_vma low; - bfd_vma high; -{ - struct ieee_range **plist, *r, **pr; - - if (low == (bfd_vma) -1 || high == (bfd_vma) -1 || low == high) - return true; - - if (global) - plist = &info->global_ranges; - else - plist = &info->ranges; - - for (r = *plist; r != NULL; r = r->next) - { - if (high >= r->low && low <= r->high) - { - /* The new range overlaps r. */ - if (low < r->low) - r->low = low; - if (high > r->high) - r->high = high; - pr = &r->next; - while (*pr != NULL && (*pr)->low <= r->high) - { - struct ieee_range *n; - - if ((*pr)->high > r->high) - r->high = (*pr)->high; - n = (*pr)->next; - free (*pr); - *pr = n; - } - return true; - } - } - - r = (struct ieee_range *) xmalloc (sizeof *r); - memset (r, 0, sizeof *r); - - r->low = low; - r->high = high; - - /* Store the ranges sorted by address. */ - for (pr = plist; *pr != NULL; pr = &(*pr)->next) - if ((*pr)->low > high) - break; - r->next = *pr; - *pr = r; - - return true; -} - -/* Start a new range for which we only have the low address. */ - -static boolean -ieee_start_range (info, low) - struct ieee_handle *info; - bfd_vma low; -{ - struct ieee_range *r; - - r = (struct ieee_range *) xmalloc (sizeof *r); - memset (r, 0, sizeof *r); - r->low = low; - r->next = info->pending_ranges; - info->pending_ranges = r; - return true; -} - -/* Finish a range started by ieee_start_range. */ - -static boolean -ieee_end_range (info, high) - struct ieee_handle *info; - bfd_vma high; -{ - struct ieee_range *r; - bfd_vma low; - - assert (info->pending_ranges != NULL); - r = info->pending_ranges; - low = r->low; - info->pending_ranges = r->next; - free (r); - return ieee_add_range (info, false, low, high); -} - -/* Start defining a type. */ - -static boolean -ieee_define_type (info, size, unsignedp, localp) - struct ieee_handle *info; - unsigned int size; - boolean unsignedp; - boolean localp; -{ - return ieee_define_named_type (info, (const char *) NULL, - (unsigned int) -1, size, unsignedp, - localp, (struct ieee_buflist *) NULL); -} - -/* Start defining a named type. */ - -static boolean -ieee_define_named_type (info, name, indx, size, unsignedp, localp, buflist) - struct ieee_handle *info; - const char *name; - unsigned int indx; - unsigned int size; - boolean unsignedp; - boolean localp; - struct ieee_buflist *buflist; -{ - unsigned int type_indx; - unsigned int name_indx; - - if (indx != (unsigned int) -1) - type_indx = indx; - else - { - type_indx = info->type_indx; - ++info->type_indx; - } - - name_indx = info->name_indx; - ++info->name_indx; - - if (name == NULL) - name = ""; - - /* If we were given a buffer, use it; otherwise, use either the - local or the global type information, and make sure that the type - block is started. */ - if (buflist != NULL) - { - if (! ieee_change_buffer (info, buflist)) - return false; - } - else if (localp) - { - if (! ieee_buffer_emptyp (&info->types)) - { - if (! ieee_change_buffer (info, &info->types)) - return false; - } - else - { - if (! ieee_change_buffer (info, &info->types) - || ! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 1) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, info->modname)) - return false; - } - } - else - { - if (! ieee_buffer_emptyp (&info->global_types)) - { - if (! ieee_change_buffer (info, &info->global_types)) - return false; - } - else - { - if (! ieee_change_buffer (info, &info->global_types) - || ! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 2) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, "")) - return false; - } - } - - /* Push the new type on the type stack, write out an NN record, and - write out the start of a TY record. The caller will then finish - the TY record. */ - if (! ieee_push_type (info, type_indx, size, unsignedp, localp)) - return false; - - return (ieee_write_byte (info, (int) ieee_nn_record) - && ieee_write_number (info, name_indx) - && ieee_write_id (info, name) - && ieee_write_byte (info, (int) ieee_ty_record_enum) - && ieee_write_number (info, type_indx) - && ieee_write_byte (info, 0xce) - && ieee_write_number (info, name_indx)); -} - -/* Get an entry to the list of modified versions of a type. */ - -static struct ieee_modified_type * -ieee_get_modified_info (info, indx) - struct ieee_handle *info; - unsigned int indx; -{ - if (indx >= info->modified_alloc) - { - unsigned int nalloc; - - nalloc = info->modified_alloc; - if (nalloc == 0) - nalloc = 16; - while (indx >= nalloc) - nalloc *= 2; - info->modified = ((struct ieee_modified_type *) - xrealloc (info->modified, - nalloc * sizeof *info->modified)); - memset (info->modified + info->modified_alloc, 0, - (nalloc - info->modified_alloc) * sizeof *info->modified); - info->modified_alloc = nalloc; - } - - return info->modified + indx; -} - -/* Routines for the hash table mapping names to types. */ - -/* Initialize an entry in the hash table. */ - -static struct bfd_hash_entry * -ieee_name_type_newfunc (entry, table, string) - struct bfd_hash_entry *entry; - struct bfd_hash_table *table; - const char *string; -{ - struct ieee_name_type_hash_entry *ret = - (struct ieee_name_type_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == NULL) - ret = ((struct ieee_name_type_hash_entry *) - bfd_hash_allocate (table, sizeof *ret)); - if (ret == NULL) - return NULL; - - /* Call the allocation method of the superclass. */ - ret = ((struct ieee_name_type_hash_entry *) - bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); - if (ret) - { - /* Set local fields. */ - ret->types = NULL; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Look up an entry in the hash table. */ - -#define ieee_name_type_hash_lookup(table, string, create, copy) \ - ((struct ieee_name_type_hash_entry *) \ - bfd_hash_lookup (&(table)->root, (string), (create), (copy))) - -/* Traverse the hash table. */ - -#define ieee_name_type_hash_traverse(table, func, info) \ - (bfd_hash_traverse \ - (&(table)->root, \ - (boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) (func), \ - (info))) - -/* The general routine to write out IEEE debugging information. */ - -boolean -write_ieee_debugging_info (abfd, dhandle) - bfd *abfd; - PTR dhandle; -{ - struct ieee_handle info; - asection *s; - const char *err; - struct ieee_buf *b; - - memset (&info, 0, sizeof info); - info.abfd = abfd; - info.type_indx = 256; - info.name_indx = 32; - - if (! bfd_hash_table_init (&info.typedefs.root, ieee_name_type_newfunc) - || ! bfd_hash_table_init (&info.tags.root, ieee_name_type_newfunc)) - return false; - - if (! ieee_init_buffer (&info, &info.global_types) - || ! ieee_init_buffer (&info, &info.data) - || ! ieee_init_buffer (&info, &info.types) - || ! ieee_init_buffer (&info, &info.vars) - || ! ieee_init_buffer (&info, &info.cxx) - || ! ieee_init_buffer (&info, &info.linenos) - || ! ieee_init_buffer (&info, &info.fntype) - || ! ieee_init_buffer (&info, &info.fnargs)) - return false; - - if (! debug_write (dhandle, &ieee_fns, (PTR) &info)) - return false; - - if (info.filename != NULL) - { - if (! ieee_finish_compilation_unit (&info)) - return false; - } - - /* Put any undefined tags in the global typedef information. */ - info.error = false; - ieee_name_type_hash_traverse (&info.tags, - ieee_write_undefined_tag, - (PTR) &info); - if (info.error) - return false; - - /* Prepend the global typedef information to the other data. */ - if (! ieee_buffer_emptyp (&info.global_types)) - { - /* The HP debugger seems to have a bug in which it ignores the - last entry in the global types, so we add a dummy entry. */ - if (! ieee_change_buffer (&info, &info.global_types) - || ! ieee_write_byte (&info, (int) ieee_nn_record) - || ! ieee_write_number (&info, info.name_indx) - || ! ieee_write_id (&info, "") - || ! ieee_write_byte (&info, (int) ieee_ty_record_enum) - || ! ieee_write_number (&info, info.type_indx) - || ! ieee_write_byte (&info, 0xce) - || ! ieee_write_number (&info, info.name_indx) - || ! ieee_write_number (&info, 'P') - || ! ieee_write_number (&info, (int) builtin_void + 32) - || ! ieee_write_byte (&info, (int) ieee_be_record_enum)) - return false; - - if (! ieee_append_buffer (&info, &info.global_types, &info.data)) - return false; - info.data = info.global_types; - } - - /* Make sure that we have declare BB11 blocks for each range in the - file. They are added to info->vars. */ - info.error = false; - if (! ieee_init_buffer (&info, &info.vars)) - return false; - bfd_map_over_sections (abfd, ieee_add_bb11_blocks, (PTR) &info); - if (info.error) - return false; - if (! ieee_buffer_emptyp (&info.vars)) - { - if (! ieee_change_buffer (&info, &info.vars) - || ! ieee_write_byte (&info, (int) ieee_be_record_enum)) - return false; - - if (! ieee_append_buffer (&info, &info.data, &info.vars)) - return false; - } - - /* Now all the data is in info.data. Write it out to the BFD. We - normally would need to worry about whether all the other sections - are set up yet, but the IEEE backend will handle this particular - case correctly regardless. */ - if (ieee_buffer_emptyp (&info.data)) - { - /* There is no debugging information. */ - return true; - } - err = NULL; - s = bfd_make_section (abfd, ".debug"); - if (s == NULL) - err = "bfd_make_section"; - if (err == NULL) - { - if (! bfd_set_section_flags (abfd, s, SEC_DEBUGGING | SEC_HAS_CONTENTS)) - err = "bfd_set_section_flags"; - } - if (err == NULL) - { - bfd_size_type size; - - size = 0; - for (b = info.data.head; b != NULL; b = b->next) - size += b->c; - if (! bfd_set_section_size (abfd, s, size)) - err = "bfd_set_section_size"; - } - if (err == NULL) - { - file_ptr offset; - - offset = 0; - for (b = info.data.head; b != NULL; b = b->next) - { - if (! bfd_set_section_contents (abfd, s, b->buf, offset, b->c)) - { - err = "bfd_set_section_contents"; - break; - } - offset += b->c; - } - } - - if (err != NULL) - { - fprintf (stderr, "%s: %s: %s\n", bfd_get_filename (abfd), err, - bfd_errmsg (bfd_get_error ())); - return false; - } - - bfd_hash_table_free (&info.typedefs.root); - bfd_hash_table_free (&info.tags.root); - - return true; -} - -/* Write out information for an undefined tag. This is called via - ieee_name_type_hash_traverse. */ - -static boolean -ieee_write_undefined_tag (h, p) - struct ieee_name_type_hash_entry *h; - PTR p; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - struct ieee_name_type *nt; - - for (nt = h->types; nt != NULL; nt = nt->next) - { - unsigned int name_indx; - char code; - - if (nt->kind == DEBUG_KIND_ILLEGAL) - continue; - - if (ieee_buffer_emptyp (&info->global_types)) - { - if (! ieee_change_buffer (info, &info->global_types) - || ! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 2) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, "")) - { - info->error = true; - return false; - } - } - else - { - if (! ieee_change_buffer (info, &info->global_types)) - { - info->error = true; - return false; - } - } - - name_indx = info->name_indx; - ++info->name_indx; - if (! ieee_write_byte (info, (int) ieee_nn_record) - || ! ieee_write_number (info, name_indx) - || ! ieee_write_id (info, nt->type.name) - || ! ieee_write_byte (info, (int) ieee_ty_record_enum) - || ! ieee_write_number (info, nt->type.indx) - || ! ieee_write_byte (info, 0xce) - || ! ieee_write_number (info, name_indx)) - { - info->error = true; - return false; - } - - switch (nt->kind) - { - default: - abort (); - info->error = true; - return false; - case DEBUG_KIND_STRUCT: - case DEBUG_KIND_CLASS: - code = 'S'; - break; - case DEBUG_KIND_UNION: - case DEBUG_KIND_UNION_CLASS: - code = 'U'; - break; - case DEBUG_KIND_ENUM: - code = 'E'; - break; - } - if (! ieee_write_number (info, code) - || ! ieee_write_number (info, 0)) - { - info->error = true; - return false; - } - } - - return true; -} - -/* Start writing out information for a compilation unit. */ - -static boolean -ieee_start_compilation_unit (p, filename) - PTR p; - const char *filename; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - const char *modname; - char *c, *s; - unsigned int nindx; - - if (info->filename != NULL) - { - if (! ieee_finish_compilation_unit (info)) - return false; - } - - info->filename = filename; - modname = strrchr (filename, '/'); - if (modname != NULL) - ++modname; - else - { - modname = strrchr (filename, '\\'); - if (modname != NULL) - ++modname; - else - modname = filename; - } - c = xstrdup (modname); - s = strrchr (c, '.'); - if (s != NULL) - *s = '\0'; - info->modname = c; - - if (! ieee_init_buffer (info, &info->types) - || ! ieee_init_buffer (info, &info->vars) - || ! ieee_init_buffer (info, &info->cxx) - || ! ieee_init_buffer (info, &info->linenos)) - return false; - info->ranges = NULL; - - /* Always include a BB1 and a BB3 block. That is what the output of - the MRI linker seems to look like. */ - if (! ieee_change_buffer (info, &info->types) - || ! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 1) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, info->modname)) - return false; - - nindx = info->name_indx; - ++info->name_indx; - if (! ieee_change_buffer (info, &info->vars) - || ! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 3) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, info->modname)) - return false; - - return true; -} - -/* Finish up a compilation unit. */ - -static boolean -ieee_finish_compilation_unit (info) - struct ieee_handle *info; -{ - struct ieee_range *r; - - if (! ieee_buffer_emptyp (&info->types)) - { - if (! ieee_change_buffer (info, &info->types) - || ! ieee_write_byte (info, (int) ieee_be_record_enum)) - return false; - } - - if (! ieee_buffer_emptyp (&info->cxx)) - { - /* Append any C++ information to the global function and - variable information. */ - assert (! ieee_buffer_emptyp (&info->vars)); - if (! ieee_change_buffer (info, &info->vars)) - return false; - - /* We put the pmisc records in a dummy procedure, just as the - MRI compiler does. */ - if (! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 6) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, "__XRYCPP") - || ! ieee_write_number (info, 0) - || ! ieee_write_number (info, 0) - || ! ieee_write_number (info, info->highaddr - 1) - || ! ieee_append_buffer (info, &info->vars, &info->cxx) - || ! ieee_change_buffer (info, &info->vars) - || ! ieee_write_byte (info, (int) ieee_be_record_enum) - || ! ieee_write_number (info, info->highaddr - 1)) - return false; - } - - if (! ieee_buffer_emptyp (&info->vars)) - { - if (! ieee_change_buffer (info, &info->vars) - || ! ieee_write_byte (info, (int) ieee_be_record_enum)) - return false; - } - - if (info->pending_lineno_filename != NULL) - { - /* Force out the pending line number. */ - if (! ieee_lineno ((PTR) info, (const char *) NULL, 0, (bfd_vma) -1)) - return false; - } - if (! ieee_buffer_emptyp (&info->linenos)) - { - if (! ieee_change_buffer (info, &info->linenos) - || ! ieee_write_byte (info, (int) ieee_be_record_enum)) - return false; - if (strcmp (info->filename, info->lineno_filename) != 0) - { - /* We were not in the main file. We just closed the - included line number block, and now we must close the - main line number block. */ - if (! ieee_write_byte (info, (int) ieee_be_record_enum)) - return false; - } - } - - if (! ieee_append_buffer (info, &info->data, &info->types) - || ! ieee_append_buffer (info, &info->data, &info->vars) - || ! ieee_append_buffer (info, &info->data, &info->linenos)) - return false; - - /* Build BB10/BB11 blocks based on the ranges we recorded. */ - if (! ieee_change_buffer (info, &info->data)) - return false; - - if (! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 10) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, info->modname) - || ! ieee_write_id (info, "") - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, "GNU objcopy")) - return false; - - for (r = info->ranges; r != NULL; r = r->next) - { - bfd_vma low, high; - asection *s; - int kind; - - low = r->low; - high = r->high; - - /* Find the section corresponding to this range. */ - for (s = info->abfd->sections; s != NULL; s = s->next) - { - if (bfd_get_section_vma (info->abfd, s) <= low - && high <= (bfd_get_section_vma (info->abfd, s) - + bfd_section_size (info->abfd, s))) - break; - } - - if (s == NULL) - { - /* Just ignore this range. */ - continue; - } - - /* Coalesce ranges if it seems reasonable. */ - while (r->next != NULL - && high + 0x1000 >= r->next->low - && (r->next->high - <= (bfd_get_section_vma (info->abfd, s) - + bfd_section_size (info->abfd, s)))) - { - r = r->next; - high = r->high; - } - - if ((s->flags & SEC_CODE) != 0) - kind = 1; - else if ((s->flags & SEC_READONLY) != 0) - kind = 3; - else - kind = 2; - - if (! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 11) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, "") - || ! ieee_write_number (info, kind) - || ! ieee_write_number (info, s->index + IEEE_SECTION_NUMBER_BASE) - || ! ieee_write_number (info, low) - || ! ieee_write_byte (info, (int) ieee_be_record_enum) - || ! ieee_write_number (info, high - low)) - return false; - - /* Add this range to the list of global ranges. */ - if (! ieee_add_range (info, true, low, high)) - return false; - } - - if (! ieee_write_byte (info, (int) ieee_be_record_enum)) - return false; - - return true; -} - -/* Add BB11 blocks describing each range that we have not already - described. */ - -static void -ieee_add_bb11_blocks (abfd, sec, data) - bfd *abfd; - asection *sec; - PTR data; -{ - struct ieee_handle *info = (struct ieee_handle *) data; - bfd_vma low, high; - struct ieee_range *r; - - low = bfd_get_section_vma (abfd, sec); - high = low + bfd_section_size (abfd, sec); - - /* Find the first range at or after this section. The ranges are - sorted by address. */ - for (r = info->global_ranges; r != NULL; r = r->next) - if (r->high > low) - break; - - while (low < high) - { - if (r == NULL || r->low >= high) - { - if (! ieee_add_bb11 (info, sec, low, high)) - info->error = true; - return; - } - - if (low < r->low - && r->low - low > 0x100) - { - if (! ieee_add_bb11 (info, sec, low, r->low)) - { - info->error = true; - return; - } - } - low = r->high; - - r = r->next; - } -} - -/* Add a single BB11 block for a range. We add it to info->vars. */ - -static boolean -ieee_add_bb11 (info, sec, low, high) - struct ieee_handle *info; - asection *sec; - bfd_vma low; - bfd_vma high; -{ - int kind; - - if (! ieee_buffer_emptyp (&info->vars)) - { - if (! ieee_change_buffer (info, &info->vars)) - return false; - } - else - { - const char *filename, *modname; - char *c, *s; - - /* Start the enclosing BB10 block. */ - filename = bfd_get_filename (info->abfd); - modname = strrchr (filename, '/'); - if (modname != NULL) - ++modname; - else - { - modname = strrchr (filename, '\\'); - if (modname != NULL) - ++modname; - else - modname = filename; - } - c = xstrdup (modname); - s = strrchr (c, '.'); - if (s != NULL) - *s = '\0'; - - if (! ieee_change_buffer (info, &info->vars) - || ! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 10) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, c) - || ! ieee_write_id (info, "") - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, "GNU objcopy")) - return false; - - free (c); - } - - if ((sec->flags & SEC_CODE) != 0) - kind = 1; - else if ((sec->flags & SEC_READONLY) != 0) - kind = 3; - else - kind = 2; - - if (! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 11) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, "") - || ! ieee_write_number (info, kind) - || ! ieee_write_number (info, sec->index + IEEE_SECTION_NUMBER_BASE) - || ! ieee_write_number (info, low) - || ! ieee_write_byte (info, (int) ieee_be_record_enum) - || ! ieee_write_number (info, high - low)) - return false; - - return true; -} - -/* Start recording information from a particular source file. This is - used to record which file defined which types, variables, etc. It - is not used for line numbers, since the lineno entry point passes - down the file name anyhow. IEEE debugging information doesn't seem - to store this information anywhere. */ - -/*ARGSUSED*/ -static boolean -ieee_start_source (p, filename) - PTR p; - const char *filename; -{ - return true; -} - -/* Make an empty type. */ - -static boolean -ieee_empty_type (p) - PTR p; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - - return ieee_push_type (info, (int) builtin_unknown, 0, false, false); -} - -/* Make a void type. */ - -static boolean -ieee_void_type (p) - PTR p; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - - return ieee_push_type (info, (int) builtin_void, 0, false, false); -} - -/* Make an integer type. */ - -static boolean -ieee_int_type (p, size, unsignedp) - PTR p; - unsigned int size; - boolean unsignedp; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - unsigned int indx; - - switch (size) - { - case 1: - indx = (int) builtin_signed_char; - break; - case 2: - indx = (int) builtin_signed_short_int; - break; - case 4: - indx = (int) builtin_signed_long; - break; - case 8: - indx = (int) builtin_signed_long_long; - break; - default: - fprintf (stderr, "IEEE unsupported integer type size %u\n", size); - return false; - } - - if (unsignedp) - ++indx; - - return ieee_push_type (info, indx, size, unsignedp, false); -} - -/* Make a floating point type. */ - -static boolean -ieee_float_type (p, size) - PTR p; - unsigned int size; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - unsigned int indx; - - switch (size) - { - case 4: - indx = (int) builtin_float; - break; - case 8: - indx = (int) builtin_double; - break; - case 12: - /* FIXME: This size really depends upon the processor. */ - indx = (int) builtin_long_double; - break; - case 16: - indx = (int) builtin_long_long_double; - break; - default: - fprintf (stderr, "IEEE unsupported float type size %u\n", size); - return false; - } - - return ieee_push_type (info, indx, size, false, false); -} - -/* Make a complex type. */ - -static boolean -ieee_complex_type (p, size) - PTR p; - unsigned int size; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - char code; - - switch (size) - { - case 4: - if (info->complex_float_index != 0) - return ieee_push_type (info, info->complex_float_index, size * 2, - false, false); - code = 'c'; - break; - case 12: - case 16: - /* These cases can be output by gcc -gstabs. Outputting the - wrong type is better than crashing. */ - case 8: - if (info->complex_double_index != 0) - return ieee_push_type (info, info->complex_double_index, size * 2, - false, false); - code = 'd'; - break; - default: - fprintf (stderr, "IEEE unsupported complex type size %u\n", size); - return false; - } - - /* FIXME: I don't know what the string is for. */ - if (! ieee_define_type (info, size * 2, false, false) - || ! ieee_write_number (info, code) - || ! ieee_write_id (info, "")) - return false; - - if (size == 4) - info->complex_float_index = info->type_stack->type.indx; - else - info->complex_double_index = info->type_stack->type.indx; - - return true; -} - -/* Make a boolean type. IEEE doesn't support these, so we just make - an integer type instead. */ - -static boolean -ieee_bool_type (p, size) - PTR p; - unsigned int size; -{ - return ieee_int_type (p, size, true); -} - -/* Make an enumeration. */ - -static boolean -ieee_enum_type (p, tag, names, vals) - PTR p; - const char *tag; - const char **names; - bfd_signed_vma *vals; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - struct ieee_defined_enum *e; - boolean localp, simple; - unsigned int indx; - int i = 0; - - localp = false; - indx = (unsigned int) -1; - for (e = info->enums; e != NULL; e = e->next) - { - if (tag == NULL) - { - if (e->tag != NULL) - continue; - } - else - { - if (e->tag == NULL - || tag[0] != e->tag[0] - || strcmp (tag, e->tag) != 0) - continue; - } - - if (! e->defined) - { - /* This enum tag has been seen but not defined. */ - indx = e->indx; - break; - } - - if (names != NULL && e->names != NULL) - { - for (i = 0; names[i] != NULL && e->names[i] != NULL; i++) - { - if (names[i][0] != e->names[i][0] - || vals[i] != e->vals[i] - || strcmp (names[i], e->names[i]) != 0) - break; - } - } - - if ((names == NULL && e->names == NULL) - || (names != NULL - && e->names != NULL - && names[i] == NULL - && e->names[i] == NULL)) - { - /* We've seen this enum before. */ - return ieee_push_type (info, e->indx, 0, true, false); - } - - if (tag != NULL) - { - /* We've already seen an enum of the same name, so we must make - sure to output this one locally. */ - localp = true; - break; - } - } - - /* If this is a simple enumeration, in which the values start at 0 - and always increment by 1, we can use type E. Otherwise we must - use type N. */ - - simple = true; - if (names != NULL) - { - for (i = 0; names[i] != NULL; i++) - { - if (vals[i] != i) - { - simple = false; - break; - } - } - } - - if (! ieee_define_named_type (info, tag, indx, 0, true, localp, - (struct ieee_buflist *) NULL) - || ! ieee_write_number (info, simple ? 'E' : 'N')) - return false; - if (simple) - { - /* FIXME: This is supposed to be the enumeration size, but we - don't store that. */ - if (! ieee_write_number (info, 4)) - return false; - } - if (names != NULL) - { - for (i = 0; names[i] != NULL; i++) - { - if (! ieee_write_id (info, names[i])) - return false; - if (! simple) - { - if (! ieee_write_number (info, vals[i])) - return false; - } - } - } - - if (! localp) - { - if (indx == (unsigned int) -1) - { - e = (struct ieee_defined_enum *) xmalloc (sizeof *e); - memset (e, 0, sizeof *e); - e->indx = info->type_stack->type.indx; - e->tag = tag; - - e->next = info->enums; - info->enums = e; - } - - e->names = names; - e->vals = vals; - e->defined = true; - } - - return true; -} - -/* Make a pointer type. */ - -static boolean -ieee_pointer_type (p) - PTR p; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - boolean localp; - unsigned int indx; - struct ieee_modified_type *m = NULL; - - localp = info->type_stack->type.localp; - indx = ieee_pop_type (info); - - /* A pointer to a simple builtin type can be obtained by adding 32. - FIXME: Will this be a short pointer, and will that matter? */ - if (indx < 32) - return ieee_push_type (info, indx + 32, 0, true, false); - - if (! localp) - { - m = ieee_get_modified_info (p, indx); - if (m == NULL) - return false; - - /* FIXME: The size should depend upon the architecture. */ - if (m->pointer > 0) - return ieee_push_type (info, m->pointer, 4, true, false); - } - - if (! ieee_define_type (info, 4, true, localp) - || ! ieee_write_number (info, 'P') - || ! ieee_write_number (info, indx)) - return false; - - if (! localp) - m->pointer = info->type_stack->type.indx; - - return true; -} - -/* Make a function type. This will be called for a method, but we - don't want to actually add it to the type table in that case. We - handle this by defining the type in a private buffer, and only - adding that buffer to the typedef block if we are going to use it. */ - -static boolean -ieee_function_type (p, argcount, varargs) - PTR p; - int argcount; - boolean varargs; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - boolean localp; - unsigned int *args = NULL; - int i; - unsigned int retindx; - struct ieee_buflist fndef; - struct ieee_modified_type *m; - - localp = false; - - if (argcount > 0) - { - args = (unsigned int *) xmalloc (argcount * sizeof *args); - for (i = argcount - 1; i >= 0; i--) - { - if (info->type_stack->type.localp) - localp = true; - args[i] = ieee_pop_type (info); - } - } - else if (argcount < 0) - varargs = false; - - if (info->type_stack->type.localp) - localp = true; - retindx = ieee_pop_type (info); - - m = NULL; - if (argcount < 0 && ! localp) - { - m = ieee_get_modified_info (p, retindx); - if (m == NULL) - return false; - - if (m->function > 0) - return ieee_push_type (info, m->function, 0, true, false); - } - - /* An attribute of 0x41 means that the frame and push mask are - unknown. */ - if (! ieee_init_buffer (info, &fndef) - || ! ieee_define_named_type (info, (const char *) NULL, - (unsigned int) -1, 0, true, localp, - &fndef) - || ! ieee_write_number (info, 'x') - || ! ieee_write_number (info, 0x41) - || ! ieee_write_number (info, 0) - || ! ieee_write_number (info, 0) - || ! ieee_write_number (info, retindx) - || ! ieee_write_number (info, (bfd_vma) argcount + (varargs ? 1 : 0))) - return false; - if (argcount > 0) - { - for (i = 0; i < argcount; i++) - if (! ieee_write_number (info, args[i])) - return false; - free (args); - } - if (varargs) - { - /* A varargs function is represented by writing out the last - argument as type void *, although this makes little sense. */ - if (! ieee_write_number (info, (bfd_vma) builtin_void + 32)) - return false; - } - - if (! ieee_write_number (info, 0)) - return false; - - /* We wrote the information into fndef, in case we don't need it. - It will be appended to info->types by ieee_pop_type. */ - info->type_stack->type.fndef = fndef; - - if (m != NULL) - m->function = info->type_stack->type.indx; - - return true; -} - -/* Make a reference type. */ - -static boolean -ieee_reference_type (p) - PTR p; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - - /* IEEE appears to record a normal pointer type, and then use a - pmisc record to indicate that it is really a reference. */ - - if (! ieee_pointer_type (p)) - return false; - info->type_stack->type.referencep = true; - return true; -} - -/* Make a range type. */ - -static boolean -ieee_range_type (p, low, high) - PTR p; - bfd_signed_vma low; - bfd_signed_vma high; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - unsigned int size; - boolean unsignedp, localp; - - size = info->type_stack->type.size; - unsignedp = info->type_stack->type.unsignedp; - localp = info->type_stack->type.localp; - ieee_pop_unused_type (info); - return (ieee_define_type (info, size, unsignedp, localp) - && ieee_write_number (info, 'R') - && ieee_write_number (info, (bfd_vma) low) - && ieee_write_number (info, (bfd_vma) high) - && ieee_write_number (info, unsignedp ? 0 : 1) - && ieee_write_number (info, size)); -} - -/* Make an array type. */ - -/*ARGSUSED*/ -static boolean -ieee_array_type (p, low, high, stringp) - PTR p; - bfd_signed_vma low; - bfd_signed_vma high; - boolean stringp; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - unsigned int eleindx; - boolean localp; - unsigned int size; - struct ieee_modified_type *m = NULL; - struct ieee_modified_array_type *a; - - /* IEEE does not store the range, so we just ignore it. */ - ieee_pop_unused_type (info); - localp = info->type_stack->type.localp; - size = info->type_stack->type.size; - eleindx = ieee_pop_type (info); - - /* If we don't know the range, treat the size as exactly one - element. */ - if (low < high) - size *= (high - low) + 1; - - if (! localp) - { - m = ieee_get_modified_info (info, eleindx); - if (m == NULL) - return false; - - for (a = m->arrays; a != NULL; a = a->next) - { - if (a->low == low && a->high == high) - return ieee_push_type (info, a->indx, size, false, false); - } - } - - if (! ieee_define_type (info, size, false, localp) - || ! ieee_write_number (info, low == 0 ? 'Z' : 'C') - || ! ieee_write_number (info, eleindx)) - return false; - if (low != 0) - { - if (! ieee_write_number (info, low)) - return false; - } - - if (! ieee_write_number (info, high + 1)) - return false; - - if (! localp) - { - a = (struct ieee_modified_array_type *) xmalloc (sizeof *a); - memset (a, 0, sizeof *a); - - a->indx = info->type_stack->type.indx; - a->low = low; - a->high = high; - - a->next = m->arrays; - m->arrays = a; - } - - return true; -} - -/* Make a set type. */ - -static boolean -ieee_set_type (p, bitstringp) - PTR p; - boolean bitstringp; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - boolean localp; - unsigned int eleindx; - - localp = info->type_stack->type.localp; - eleindx = ieee_pop_type (info); - - /* FIXME: We don't know the size, so we just use 4. */ - - return (ieee_define_type (info, 0, true, localp) - && ieee_write_number (info, 's') - && ieee_write_number (info, 4) - && ieee_write_number (info, eleindx)); -} - -/* Make an offset type. */ - -static boolean -ieee_offset_type (p) - PTR p; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - unsigned int targetindx, baseindx; - - targetindx = ieee_pop_type (info); - baseindx = ieee_pop_type (info); - - /* FIXME: The MRI C++ compiler does not appear to generate any - useful type information about an offset type. It just records a - pointer to member as an integer. The MRI/HP IEEE spec does - describe a pmisc record which can be used for a pointer to - member. Unfortunately, it does not describe the target type, - which seems pretty important. I'm going to punt this for now. */ - - return ieee_int_type (p, 4, true); -} - -/* Make a method type. */ - -static boolean -ieee_method_type (p, domain, argcount, varargs) - PTR p; - boolean domain; - int argcount; - boolean varargs; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - - /* FIXME: The MRI/HP IEEE spec defines a pmisc record to use for a - method, but the definition is incomplete. We just output an 'x' - type. */ - - if (domain) - ieee_pop_unused_type (info); - - return ieee_function_type (p, argcount, varargs); -} - -/* Make a const qualified type. */ - -static boolean -ieee_const_type (p) - PTR p; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - unsigned int size; - boolean unsignedp, localp; - unsigned int indx; - struct ieee_modified_type *m = NULL; - - size = info->type_stack->type.size; - unsignedp = info->type_stack->type.unsignedp; - localp = info->type_stack->type.localp; - indx = ieee_pop_type (info); - - if (! localp) - { - m = ieee_get_modified_info (info, indx); - if (m == NULL) - return false; - - if (m->const_qualified > 0) - return ieee_push_type (info, m->const_qualified, size, unsignedp, - false); - } - - if (! ieee_define_type (info, size, unsignedp, localp) - || ! ieee_write_number (info, 'n') - || ! ieee_write_number (info, 1) - || ! ieee_write_number (info, indx)) - return false; - - if (! localp) - m->const_qualified = info->type_stack->type.indx; - - return true; -} - -/* Make a volatile qualified type. */ - -static boolean -ieee_volatile_type (p) - PTR p; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - unsigned int size; - boolean unsignedp, localp; - unsigned int indx; - struct ieee_modified_type *m = NULL; - - size = info->type_stack->type.size; - unsignedp = info->type_stack->type.unsignedp; - localp = info->type_stack->type.localp; - indx = ieee_pop_type (info); - - if (! localp) - { - m = ieee_get_modified_info (info, indx); - if (m == NULL) - return false; - - if (m->volatile_qualified > 0) - return ieee_push_type (info, m->volatile_qualified, size, unsignedp, - false); - } - - if (! ieee_define_type (info, size, unsignedp, localp) - || ! ieee_write_number (info, 'n') - || ! ieee_write_number (info, 2) - || ! ieee_write_number (info, indx)) - return false; - - if (! localp) - m->volatile_qualified = info->type_stack->type.indx; - - return true; -} - -/* Convert an enum debug_visibility into a CXXFLAGS value. */ - -static unsigned int -ieee_vis_to_flags (visibility) - enum debug_visibility visibility; -{ - switch (visibility) - { - default: - abort (); - case DEBUG_VISIBILITY_PUBLIC: - return CXXFLAGS_VISIBILITY_PUBLIC; - case DEBUG_VISIBILITY_PRIVATE: - return CXXFLAGS_VISIBILITY_PRIVATE; - case DEBUG_VISIBILITY_PROTECTED: - return CXXFLAGS_VISIBILITY_PROTECTED; - } - /*NOTREACHED*/ -} - -/* Start defining a struct type. We build it in the strdef field on - the stack, to avoid confusing type definitions required by the - fields with the struct type itself. */ - -static boolean -ieee_start_struct_type (p, tag, id, structp, size) - PTR p; - const char *tag; - unsigned int id; - boolean structp; - unsigned int size; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - boolean localp, ignorep; - boolean copy; - char ab[20]; - const char *look; - struct ieee_name_type_hash_entry *h; - struct ieee_name_type *nt, *ntlook; - struct ieee_buflist strdef; - - localp = false; - ignorep = false; - - /* We need to create a tag for internal use even if we don't want - one for external use. This will let us refer to an anonymous - struct. */ - if (tag != NULL) - { - look = tag; - copy = false; - } - else - { - sprintf (ab, "__anon%u", id); - look = ab; - copy = true; - } - - /* If we already have references to the tag, we must use the - existing type index. */ - h = ieee_name_type_hash_lookup (&info->tags, look, true, copy); - if (h == NULL) - return false; - - nt = NULL; - for (ntlook = h->types; ntlook != NULL; ntlook = ntlook->next) - { - if (ntlook->id == id) - nt = ntlook; - else if (! ntlook->type.localp) - { - /* We are creating a duplicate definition of a globally - defined tag. Force it to be local to avoid - confusion. */ - localp = true; - } - } - - if (nt != NULL) - { - assert (localp == nt->type.localp); - if (nt->kind == DEBUG_KIND_ILLEGAL && ! localp) - { - /* We've already seen a global definition of the type. - Ignore this new definition. */ - ignorep = true; - } - } - else - { - nt = (struct ieee_name_type *) xmalloc (sizeof *nt); - memset (nt, 0, sizeof *nt); - nt->id = id; - nt->type.name = h->root.string; - nt->next = h->types; - h->types = nt; - nt->type.indx = info->type_indx; - ++info->type_indx; - } - - nt->kind = DEBUG_KIND_ILLEGAL; - - if (! ieee_init_buffer (info, &strdef) - || ! ieee_define_named_type (info, tag, nt->type.indx, size, true, - localp, &strdef) - || ! ieee_write_number (info, structp ? 'S' : 'U') - || ! ieee_write_number (info, size)) - return false; - - if (! ignorep) - { - const char *hold; - - /* We never want nt->type.name to be NULL. We want the rest of - the type to be the object set up on the type stack; it will - have a NULL name if tag is NULL. */ - hold = nt->type.name; - nt->type = info->type_stack->type; - nt->type.name = hold; - } - - info->type_stack->type.name = tag; - info->type_stack->type.strdef = strdef; - info->type_stack->type.ignorep = ignorep; - - return true; -} - -/* Add a field to a struct. */ - -static boolean -ieee_struct_field (p, name, bitpos, bitsize, visibility) - PTR p; - const char *name; - bfd_vma bitpos; - bfd_vma bitsize; - enum debug_visibility visibility; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - unsigned int size; - boolean unsignedp; - boolean referencep; - boolean localp; - unsigned int indx; - bfd_vma offset; - - assert (info->type_stack != NULL - && info->type_stack->next != NULL - && ! ieee_buffer_emptyp (&info->type_stack->next->type.strdef)); - - /* If we are ignoring this struct definition, just pop and ignore - the type. */ - if (info->type_stack->next->type.ignorep) - { - ieee_pop_unused_type (info); - return true; - } - - size = info->type_stack->type.size; - unsignedp = info->type_stack->type.unsignedp; - referencep = info->type_stack->type.referencep; - localp = info->type_stack->type.localp; - indx = ieee_pop_type (info); - - if (localp) - info->type_stack->type.localp = true; - - if (info->type_stack->type.classdef != NULL) - { - unsigned int flags; - unsigned int nindx; - - /* This is a class. We must add a description of this field to - the class records we are building. */ - - flags = ieee_vis_to_flags (visibility); - nindx = info->type_stack->type.classdef->indx; - if (! ieee_change_buffer (info, - &info->type_stack->type.classdef->pmiscbuf) - || ! ieee_write_asn (info, nindx, 'd') - || ! ieee_write_asn (info, nindx, flags) - || ! ieee_write_atn65 (info, nindx, name) - || ! ieee_write_atn65 (info, nindx, name)) - return false; - info->type_stack->type.classdef->pmisccount += 4; - - if (referencep) - { - unsigned int nindx; - - /* We need to output a record recording that this field is - really of reference type. We put this on the refs field - of classdef, so that it can be appended to the C++ - records after the class is defined. */ - - nindx = info->name_indx; - ++info->name_indx; - - if (! ieee_change_buffer (info, - &info->type_stack->type.classdef->refs) - || ! ieee_write_byte (info, (int) ieee_nn_record) - || ! ieee_write_number (info, nindx) - || ! ieee_write_id (info, "") - || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) - || ! ieee_write_number (info, nindx) - || ! ieee_write_number (info, 0) - || ! ieee_write_number (info, 62) - || ! ieee_write_number (info, 80) - || ! ieee_write_number (info, 4) - || ! ieee_write_asn (info, nindx, 'R') - || ! ieee_write_asn (info, nindx, 3) - || ! ieee_write_atn65 (info, nindx, info->type_stack->type.name) - || ! ieee_write_atn65 (info, nindx, name)) - return false; - } - } - - /* If the bitsize doesn't match the expected size, we need to output - a bitfield type. */ - if (size == 0 || bitsize == 0 || bitsize == size * 8) - offset = bitpos / 8; - else - { - if (! ieee_define_type (info, 0, unsignedp, - info->type_stack->type.localp) - || ! ieee_write_number (info, 'g') - || ! ieee_write_number (info, unsignedp ? 0 : 1) - || ! ieee_write_number (info, bitsize) - || ! ieee_write_number (info, indx)) - return false; - indx = ieee_pop_type (info); - offset = bitpos; - } - - /* Switch to the struct we are building in order to output this - field definition. */ - return (ieee_change_buffer (info, &info->type_stack->type.strdef) - && ieee_write_id (info, name) - && ieee_write_number (info, indx) - && ieee_write_number (info, offset)); -} - -/* Finish up a struct type. */ - -static boolean -ieee_end_struct_type (p) - PTR p; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - struct ieee_buflist *pb; - - assert (info->type_stack != NULL - && ! ieee_buffer_emptyp (&info->type_stack->type.strdef)); - - /* If we were ignoring this struct definition because it was a - duplicate defintion, just through away whatever bytes we have - accumulated. Leave the type on the stack. */ - if (info->type_stack->type.ignorep) - return true; - - /* If this is not a duplicate definition of this tag, then localp - will be false, and we can put it in the global type block. - FIXME: We should avoid outputting duplicate definitions which are - the same. */ - if (! info->type_stack->type.localp) - { - /* Make sure we have started the global type block. */ - if (ieee_buffer_emptyp (&info->global_types)) - { - if (! ieee_change_buffer (info, &info->global_types) - || ! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 2) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, "")) - return false; - } - pb = &info->global_types; - } - else - { - /* Make sure we have started the types block. */ - if (ieee_buffer_emptyp (&info->types)) - { - if (! ieee_change_buffer (info, &info->types) - || ! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 1) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, info->modname)) - return false; - } - pb = &info->types; - } - - /* Append the struct definition to the types. */ - if (! ieee_append_buffer (info, pb, &info->type_stack->type.strdef) - || ! ieee_init_buffer (info, &info->type_stack->type.strdef)) - return false; - - /* Leave the struct on the type stack. */ - - return true; -} - -/* Start a class type. */ - -static boolean -ieee_start_class_type (p, tag, id, structp, size, vptr, ownvptr) - PTR p; - const char *tag; - unsigned int id; - boolean structp; - unsigned int size; - boolean vptr; - boolean ownvptr; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - const char *vclass; - struct ieee_buflist pmiscbuf; - unsigned int indx; - struct ieee_type_class *classdef; - - /* A C++ class is output as a C++ struct along with a set of pmisc - records describing the class. */ - - /* We need to have a name so that we can associate the struct and - the class. */ - if (tag == NULL) - { - char *t; - - t = (char *) xmalloc (20); - sprintf (t, "__anon%u", id); - tag = t; - } - - /* We can't write out the virtual table information until we have - finished the class, because we don't know the virtual table size. - We get the size from the largest voffset we see. */ - vclass = NULL; - if (vptr && ! ownvptr) - { - vclass = info->type_stack->type.name; - assert (vclass != NULL); - /* We don't call ieee_pop_unused_type, since the class should - get defined. */ - (void) ieee_pop_type (info); - } - - if (! ieee_start_struct_type (p, tag, id, structp, size)) - return false; - - indx = info->name_indx; - ++info->name_indx; - - /* We write out pmisc records into the classdef field. We will - write out the pmisc start after we know the number of records we - need. */ - if (! ieee_init_buffer (info, &pmiscbuf) - || ! ieee_change_buffer (info, &pmiscbuf) - || ! ieee_write_asn (info, indx, 'T') - || ! ieee_write_asn (info, indx, structp ? 'o' : 'u') - || ! ieee_write_atn65 (info, indx, tag)) - return false; - - classdef = (struct ieee_type_class *) xmalloc (sizeof *classdef); - memset (classdef, 0, sizeof *classdef); - - classdef->indx = indx; - classdef->pmiscbuf = pmiscbuf; - classdef->pmisccount = 3; - classdef->vclass = vclass; - classdef->ownvptr = ownvptr; - - info->type_stack->type.classdef = classdef; - - return true; -} - -/* Add a static member to a class. */ - -static boolean -ieee_class_static_member (p, name, physname, visibility) - PTR p; - const char *name; - const char *physname; - enum debug_visibility visibility; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - unsigned int flags; - unsigned int nindx; - - /* We don't care about the type. Hopefully there will be a call to - ieee_variable declaring the physical name and the type, since - that is where an IEEE consumer must get the type. */ - ieee_pop_unused_type (info); - - assert (info->type_stack != NULL - && info->type_stack->type.classdef != NULL); - - flags = ieee_vis_to_flags (visibility); - flags |= CXXFLAGS_STATIC; - - nindx = info->type_stack->type.classdef->indx; - - if (! ieee_change_buffer (info, &info->type_stack->type.classdef->pmiscbuf) - || ! ieee_write_asn (info, nindx, 'd') - || ! ieee_write_asn (info, nindx, flags) - || ! ieee_write_atn65 (info, nindx, name) - || ! ieee_write_atn65 (info, nindx, physname)) - return false; - info->type_stack->type.classdef->pmisccount += 4; - - return true; -} - -/* Add a base class to a class. */ - -static boolean -ieee_class_baseclass (p, bitpos, virtual, visibility) - PTR p; - bfd_vma bitpos; - boolean virtual; - enum debug_visibility visibility; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - const char *bname; - boolean localp; - unsigned int bindx; - char *fname; - unsigned int flags; - unsigned int nindx; - - assert (info->type_stack != NULL - && info->type_stack->type.name != NULL - && info->type_stack->next != NULL - && info->type_stack->next->type.classdef != NULL - && ! ieee_buffer_emptyp (&info->type_stack->next->type.strdef)); - - bname = info->type_stack->type.name; - localp = info->type_stack->type.localp; - bindx = ieee_pop_type (info); - - /* We are currently defining both a struct and a class. We must - write out a field definition in the struct which holds the base - class. The stabs debugging reader will create a field named - _vb$CLASS for a virtual base class, so we just use that. FIXME: - we should not depend upon a detail of stabs debugging. */ - if (virtual) - { - fname = (char *) xmalloc (strlen (bname) + sizeof "_vb$"); - sprintf (fname, "_vb$%s", bname); - flags = BASEFLAGS_VIRTUAL; - } - else - { - if (localp) - info->type_stack->type.localp = true; - - fname = (char *) xmalloc (strlen (bname) + sizeof "_b$"); - sprintf (fname, "_b$%s", bname); - - if (! ieee_change_buffer (info, &info->type_stack->type.strdef) - || ! ieee_write_id (info, fname) - || ! ieee_write_number (info, bindx) - || ! ieee_write_number (info, bitpos / 8)) - return false; - flags = 0; - } - - if (visibility == DEBUG_VISIBILITY_PRIVATE) - flags |= BASEFLAGS_PRIVATE; - - nindx = info->type_stack->type.classdef->indx; - - if (! ieee_change_buffer (info, &info->type_stack->type.classdef->pmiscbuf) - || ! ieee_write_asn (info, nindx, 'b') - || ! ieee_write_asn (info, nindx, flags) - || ! ieee_write_atn65 (info, nindx, bname) - || ! ieee_write_asn (info, nindx, 0) - || ! ieee_write_atn65 (info, nindx, fname)) - return false; - info->type_stack->type.classdef->pmisccount += 5; - - free (fname); - - return true; -} - -/* Start building a method for a class. */ - -static boolean -ieee_class_start_method (p, name) - PTR p; - const char *name; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - - assert (info->type_stack != NULL - && info->type_stack->type.classdef != NULL - && info->type_stack->type.classdef->method == NULL); - - info->type_stack->type.classdef->method = name; - - return true; -} - -/* Define a new method variant, either static or not. */ - -static boolean -ieee_class_method_var (info, physname, visibility, staticp, constp, - volatilep, voffset, context) - struct ieee_handle *info; - const char *physname; - enum debug_visibility visibility; - boolean staticp; - boolean constp; - boolean volatilep; - bfd_vma voffset; - boolean context; -{ - unsigned int flags; - unsigned int nindx; - boolean virtual; - - /* We don't need the type of the method. An IEEE consumer which - wants the type must track down the function by the physical name - and get the type from that. */ - ieee_pop_unused_type (info); - - /* We don't use the context. FIXME: We probably ought to use it to - adjust the voffset somehow, but I don't really know how. */ - if (context) - ieee_pop_unused_type (info); - - assert (info->type_stack != NULL - && info->type_stack->type.classdef != NULL - && info->type_stack->type.classdef->method != NULL); - - flags = ieee_vis_to_flags (visibility); - - /* FIXME: We never set CXXFLAGS_OVERRIDE, CXXFLAGS_OPERATOR, - CXXFLAGS_CTORDTOR, CXXFLAGS_CTOR, or CXXFLAGS_INLINE. */ - - if (staticp) - flags |= CXXFLAGS_STATIC; - if (constp) - flags |= CXXFLAGS_CONST; - if (volatilep) - flags |= CXXFLAGS_VOLATILE; - - nindx = info->type_stack->type.classdef->indx; - - virtual = context || voffset > 0; - - if (! ieee_change_buffer (info, - &info->type_stack->type.classdef->pmiscbuf) - || ! ieee_write_asn (info, nindx, virtual ? 'v' : 'm') - || ! ieee_write_asn (info, nindx, flags) - || ! ieee_write_atn65 (info, nindx, - info->type_stack->type.classdef->method) - || ! ieee_write_atn65 (info, nindx, physname)) - return false; - - if (virtual) - { - if (voffset > info->type_stack->type.classdef->voffset) - info->type_stack->type.classdef->voffset = voffset; - if (! ieee_write_asn (info, nindx, voffset)) - return false; - ++info->type_stack->type.classdef->pmisccount; - } - - if (! ieee_write_asn (info, nindx, 0)) - return false; - - info->type_stack->type.classdef->pmisccount += 5; - - return true; -} - -/* Define a new method variant. */ - -static boolean -ieee_class_method_variant (p, physname, visibility, constp, volatilep, - voffset, context) - PTR p; - const char *physname; - enum debug_visibility visibility; - boolean constp; - boolean volatilep; - bfd_vma voffset; - boolean context; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - - return ieee_class_method_var (info, physname, visibility, false, constp, - volatilep, voffset, context); -} - -/* Define a new static method variant. */ - -static boolean -ieee_class_static_method_variant (p, physname, visibility, constp, volatilep) - PTR p; - const char *physname; - enum debug_visibility visibility; - boolean constp; - boolean volatilep; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - - return ieee_class_method_var (info, physname, visibility, true, constp, - volatilep, 0, false); -} - -/* Finish up a method. */ - -static boolean -ieee_class_end_method (p) - PTR p; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - - assert (info->type_stack != NULL - && info->type_stack->type.classdef != NULL - && info->type_stack->type.classdef->method != NULL); - - info->type_stack->type.classdef->method = NULL; - - return true; -} - -/* Finish up a class. */ - -static boolean -ieee_end_class_type (p) - PTR p; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - unsigned int nindx; - - assert (info->type_stack != NULL - && info->type_stack->type.classdef != NULL); - - /* If we were ignoring this class definition because it was a - duplicate definition, just through away whatever bytes we have - accumulated. Leave the type on the stack. */ - if (info->type_stack->type.ignorep) - return true; - - nindx = info->type_stack->type.classdef->indx; - - /* If we have a virtual table, we can write out the information now. */ - if (info->type_stack->type.classdef->vclass != NULL - || info->type_stack->type.classdef->ownvptr) - { - if (! ieee_change_buffer (info, - &info->type_stack->type.classdef->pmiscbuf) - || ! ieee_write_asn (info, nindx, 'z') - || ! ieee_write_atn65 (info, nindx, "") - || ! ieee_write_asn (info, nindx, - info->type_stack->type.classdef->voffset)) - return false; - if (info->type_stack->type.classdef->ownvptr) - { - if (! ieee_write_atn65 (info, nindx, "")) - return false; - } - else - { - if (! ieee_write_atn65 (info, nindx, - info->type_stack->type.classdef->vclass)) - return false; - } - if (! ieee_write_asn (info, nindx, 0)) - return false; - info->type_stack->type.classdef->pmisccount += 5; - } - - /* Now that we know the number of pmisc records, we can write out - the atn62 which starts the pmisc records, and append them to the - C++ buffers. */ - - if (! ieee_change_buffer (info, &info->cxx) - || ! ieee_write_byte (info, (int) ieee_nn_record) - || ! ieee_write_number (info, nindx) - || ! ieee_write_id (info, "") - || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) - || ! ieee_write_number (info, nindx) - || ! ieee_write_number (info, 0) - || ! ieee_write_number (info, 62) - || ! ieee_write_number (info, 80) - || ! ieee_write_number (info, - info->type_stack->type.classdef->pmisccount)) - return false; - - if (! ieee_append_buffer (info, &info->cxx, - &info->type_stack->type.classdef->pmiscbuf)) - return false; - if (! ieee_buffer_emptyp (&info->type_stack->type.classdef->refs)) - { - if (! ieee_append_buffer (info, &info->cxx, - &info->type_stack->type.classdef->refs)) - return false; - } - - return ieee_end_struct_type (p); -} - -/* Push a previously seen typedef onto the type stack. */ - -static boolean -ieee_typedef_type (p, name) - PTR p; - const char *name; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - struct ieee_name_type_hash_entry *h; - struct ieee_name_type *nt; - - h = ieee_name_type_hash_lookup (&info->typedefs, name, false, false); - - /* h should never be NULL, since that would imply that the generic - debugging code has asked for a typedef which it has not yet - defined. */ - assert (h != NULL); - - /* We always use the most recently defined type for this name, which - will be the first one on the list. */ - - nt = h->types; - if (! ieee_push_type (info, nt->type.indx, nt->type.size, - nt->type.unsignedp, nt->type.localp)) - return false; - - /* Copy over any other type information we may have. */ - info->type_stack->type = nt->type; - - return true; -} - -/* Push a tagged type onto the type stack. */ - -static boolean -ieee_tag_type (p, name, id, kind) - PTR p; - const char *name; - unsigned int id; - enum debug_type_kind kind; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - boolean localp; - boolean copy; - char ab[20]; - struct ieee_name_type_hash_entry *h; - struct ieee_name_type *nt; - - if (kind == DEBUG_KIND_ENUM) - { - struct ieee_defined_enum *e; - - if (name == NULL) - abort (); - for (e = info->enums; e != NULL; e = e->next) - if (e->tag != NULL && strcmp (e->tag, name) == 0) - return ieee_push_type (info, e->indx, 0, true, false); - - e = (struct ieee_defined_enum *) xmalloc (sizeof *e); - memset (e, 0, sizeof *e); - - e->indx = info->type_indx; - ++info->type_indx; - e->tag = name; - e->defined = false; - - e->next = info->enums; - info->enums = e; - - return ieee_push_type (info, e->indx, 0, true, false); - } - - localp = false; - - copy = false; - if (name == NULL) - { - sprintf (ab, "__anon%u", id); - name = ab; - copy = true; - } - - h = ieee_name_type_hash_lookup (&info->tags, name, true, copy); - if (h == NULL) - return false; - - for (nt = h->types; nt != NULL; nt = nt->next) - { - if (nt->id == id) - { - if (! ieee_push_type (info, nt->type.indx, nt->type.size, - nt->type.unsignedp, nt->type.localp)) - return false; - /* Copy over any other type information we may have. */ - info->type_stack->type = nt->type; - return true; - } - - if (! nt->type.localp) - { - /* This is a duplicate of a global type, so it must be - local. */ - localp = true; - } - } - - nt = (struct ieee_name_type *) xmalloc (sizeof *nt); - memset (nt, 0, sizeof *nt); - - nt->id = id; - nt->type.name = h->root.string; - nt->type.indx = info->type_indx; - nt->type.localp = localp; - ++info->type_indx; - nt->kind = kind; - - nt->next = h->types; - h->types = nt; - - if (! ieee_push_type (info, nt->type.indx, 0, false, localp)) - return false; - - info->type_stack->type.name = h->root.string; - - return true; -} - -/* Output a typedef. */ - -static boolean -ieee_typdef (p, name) - PTR p; - const char *name; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - struct ieee_write_type type; - unsigned int indx; - boolean found; - boolean localp; - struct ieee_name_type_hash_entry *h; - struct ieee_name_type *nt; - - type = info->type_stack->type; - indx = type.indx; - - /* If this is a simple builtin type using a builtin name, we don't - want to output the typedef itself. We also want to change the - type index to correspond to the name being used. We recognize - names used in stabs debugging output even if they don't exactly - correspond to the names used for the IEEE builtin types. */ - found = false; - if (indx <= (unsigned int) builtin_bcd_float) - { - switch ((enum builtin_types) indx) - { - default: - break; - - case builtin_void: - if (strcmp (name, "void") == 0) - found = true; - break; - - case builtin_signed_char: - case builtin_char: - if (strcmp (name, "signed char") == 0) - { - indx = (unsigned int) builtin_signed_char; - found = true; - } - else if (strcmp (name, "char") == 0) - { - indx = (unsigned int) builtin_char; - found = true; - } - break; - - case builtin_unsigned_char: - if (strcmp (name, "unsigned char") == 0) - found = true; - break; - - case builtin_signed_short_int: - case builtin_short: - case builtin_short_int: - case builtin_signed_short: - if (strcmp (name, "signed short int") == 0) - { - indx = (unsigned int) builtin_signed_short_int; - found = true; - } - else if (strcmp (name, "short") == 0) - { - indx = (unsigned int) builtin_short; - found = true; - } - else if (strcmp (name, "short int") == 0) - { - indx = (unsigned int) builtin_short_int; - found = true; - } - else if (strcmp (name, "signed short") == 0) - { - indx = (unsigned int) builtin_signed_short; - found = true; - } - break; - - case builtin_unsigned_short_int: - case builtin_unsigned_short: - if (strcmp (name, "unsigned short int") == 0 - || strcmp (name, "short unsigned int") == 0) - { - indx = builtin_unsigned_short_int; - found = true; - } - else if (strcmp (name, "unsigned short") == 0) - { - indx = builtin_unsigned_short; - found = true; - } - break; - - case builtin_signed_long: - case builtin_int: /* FIXME: Size depends upon architecture. */ - case builtin_long: - if (strcmp (name, "signed long") == 0) - { - indx = builtin_signed_long; - found = true; - } - else if (strcmp (name, "int") == 0) - { - indx = builtin_int; - found = true; - } - else if (strcmp (name, "long") == 0 - || strcmp (name, "long int") == 0) - { - indx = builtin_long; - found = true; - } - break; - - case builtin_unsigned_long: - case builtin_unsigned: /* FIXME: Size depends upon architecture. */ - case builtin_unsigned_int: /* FIXME: Like builtin_unsigned. */ - if (strcmp (name, "unsigned long") == 0 - || strcmp (name, "long unsigned int") == 0) - { - indx = builtin_unsigned_long; - found = true; - } - else if (strcmp (name, "unsigned") == 0) - { - indx = builtin_unsigned; - found = true; - } - else if (strcmp (name, "unsigned int") == 0) - { - indx = builtin_unsigned_int; - found = true; - } - break; - - case builtin_signed_long_long: - if (strcmp (name, "signed long long") == 0 - || strcmp (name, "long long int") == 0) - found = true; - break; - - case builtin_unsigned_long_long: - if (strcmp (name, "unsigned long long") == 0 - || strcmp (name, "long long unsigned int") == 0) - found = true; - break; - - case builtin_float: - if (strcmp (name, "float") == 0) - found = true; - break; - - case builtin_double: - if (strcmp (name, "double") == 0) - found = true; - break; - - case builtin_long_double: - if (strcmp (name, "long double") == 0) - found = true; - break; - - case builtin_long_long_double: - if (strcmp (name, "long long double") == 0) - found = true; - break; - } - - if (found) - type.indx = indx; - } - - h = ieee_name_type_hash_lookup (&info->typedefs, name, true, false); - if (h == NULL) - return false; - - /* See if we have already defined this type with this name. */ - localp = type.localp; - for (nt = h->types; nt != NULL; nt = nt->next) - { - if (nt->id == indx) - { - /* If this is a global definition, then we don't need to - do anything here. */ - if (! nt->type.localp) - { - ieee_pop_unused_type (info); - return true; - } - } - else - { - /* This is a duplicate definition, so make this one local. */ - localp = true; - } - } - - /* We need to add a new typedef for this type. */ - - nt = (struct ieee_name_type *) xmalloc (sizeof *nt); - memset (nt, 0, sizeof *nt); - nt->id = indx; - nt->type = type; - nt->type.name = name; - nt->type.localp = localp; - nt->kind = DEBUG_KIND_ILLEGAL; - - nt->next = h->types; - h->types = nt; - - if (found) - { - /* This is one of the builtin typedefs, so we don't need to - actually define it. */ - ieee_pop_unused_type (info); - return true; - } - - indx = ieee_pop_type (info); - - if (! ieee_define_named_type (info, name, (unsigned int) -1, type.size, - type.unsignedp, localp, - (struct ieee_buflist *) NULL) - || ! ieee_write_number (info, 'T') - || ! ieee_write_number (info, indx)) - return false; - - /* Remove the type we just added to the type stack. This should not - be ieee_pop_unused_type, since the type is used, we just don't - need it now. */ - (void) ieee_pop_type (info); - - return true; -} - -/* Output a tag for a type. We don't have to do anything here. */ - -static boolean -ieee_tag (p, name) - PTR p; - const char *name; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - - /* This should not be ieee_pop_unused_type, since we want the type - to be defined. */ - (void) ieee_pop_type (info); - return true; -} - -/* Output an integer constant. */ - -static boolean -ieee_int_constant (p, name, val) - PTR p; - const char *name; - bfd_vma val; -{ - /* FIXME. */ - return true; -} - -/* Output a floating point constant. */ - -static boolean -ieee_float_constant (p, name, val) - PTR p; - const char *name; - double val; -{ - /* FIXME. */ - return true; -} - -/* Output a typed constant. */ - -static boolean -ieee_typed_constant (p, name, val) - PTR p; - const char *name; - bfd_vma val; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - - /* FIXME. */ - ieee_pop_unused_type (info); - return true; -} - -/* Output a variable. */ - -static boolean -ieee_variable (p, name, kind, val) - PTR p; - const char *name; - enum debug_var_kind kind; - bfd_vma val; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - unsigned int name_indx; - unsigned int size; - boolean referencep; - unsigned int type_indx; - boolean asn; - int refflag; - - size = info->type_stack->type.size; - referencep = info->type_stack->type.referencep; - type_indx = ieee_pop_type (info); - - assert (! ieee_buffer_emptyp (&info->vars)); - if (! ieee_change_buffer (info, &info->vars)) - return false; - - name_indx = info->name_indx; - ++info->name_indx; - - /* Write out an NN and an ATN record for this variable. */ - if (! ieee_write_byte (info, (int) ieee_nn_record) - || ! ieee_write_number (info, name_indx) - || ! ieee_write_id (info, name) - || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) - || ! ieee_write_number (info, name_indx) - || ! ieee_write_number (info, type_indx)) - return false; - switch (kind) - { - default: - abort (); - return false; - case DEBUG_GLOBAL: - if (! ieee_write_number (info, 8) - || ! ieee_add_range (info, false, val, val + size)) - return false; - refflag = 0; - asn = true; - break; - case DEBUG_STATIC: - if (! ieee_write_number (info, 3) - || ! ieee_add_range (info, false, val, val + size)) - return false; - refflag = 1; - asn = true; - break; - case DEBUG_LOCAL_STATIC: - if (! ieee_write_number (info, 3) - || ! ieee_add_range (info, false, val, val + size)) - return false; - refflag = 2; - asn = true; - break; - case DEBUG_LOCAL: - if (! ieee_write_number (info, 1) - || ! ieee_write_number (info, val)) - return false; - refflag = 2; - asn = false; - break; - case DEBUG_REGISTER: - if (! ieee_write_number (info, 2) - || ! ieee_write_number (info, - ieee_genreg_to_regno (info->abfd, val))) - return false; - refflag = 2; - asn = false; - break; - } - - if (asn) - { - if (! ieee_write_asn (info, name_indx, val)) - return false; - } - - /* If this is really a reference type, then we just output it with - pointer type, and must now output a C++ record indicating that it - is really reference type. */ - if (referencep) - { - unsigned int nindx; - - nindx = info->name_indx; - ++info->name_indx; - - /* If this is a global variable, we want to output the misc - record in the C++ misc record block. Otherwise, we want to - output it just after the variable definition, which is where - the current buffer is. */ - if (refflag != 2) - { - if (! ieee_change_buffer (info, &info->cxx)) - return false; - } - - if (! ieee_write_byte (info, (int) ieee_nn_record) - || ! ieee_write_number (info, nindx) - || ! ieee_write_id (info, "") - || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) - || ! ieee_write_number (info, nindx) - || ! ieee_write_number (info, 0) - || ! ieee_write_number (info, 62) - || ! ieee_write_number (info, 80) - || ! ieee_write_number (info, 3) - || ! ieee_write_asn (info, nindx, 'R') - || ! ieee_write_asn (info, nindx, refflag) - || ! ieee_write_atn65 (info, nindx, name)) - return false; - } - - return true; -} - -/* Start outputting information for a function. */ - -static boolean -ieee_start_function (p, name, global) - PTR p; - const char *name; - boolean global; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - boolean referencep; - unsigned int retindx, typeindx; - - referencep = info->type_stack->type.referencep; - retindx = ieee_pop_type (info); - - /* Besides recording a BB4 or BB6 block, we record the type of the - function in the BB1 typedef block. We can't write out the full - type until we have seen all the parameters, so we accumulate it - in info->fntype and info->fnargs. */ - if (! ieee_buffer_emptyp (&info->fntype)) - { - /* FIXME: This might happen someday if we support nested - functions. */ - abort (); - } - - info->fnname = name; - - /* An attribute of 0x40 means that the push mask is unknown. */ - if (! ieee_define_named_type (info, name, (unsigned int) -1, 0, false, true, - &info->fntype) - || ! ieee_write_number (info, 'x') - || ! ieee_write_number (info, 0x40) - || ! ieee_write_number (info, 0) - || ! ieee_write_number (info, 0) - || ! ieee_write_number (info, retindx)) - return false; - - typeindx = ieee_pop_type (info); - - if (! ieee_init_buffer (info, &info->fnargs)) - return false; - info->fnargcount = 0; - - /* If the function return value is actually a reference type, we - must add a record indicating that. */ - if (referencep) - { - unsigned int nindx; - - nindx = info->name_indx; - ++info->name_indx; - if (! ieee_change_buffer (info, &info->cxx) - || ! ieee_write_byte (info, (int) ieee_nn_record) - || ! ieee_write_number (info, nindx) - || ! ieee_write_id (info, "") - || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) - || ! ieee_write_number (info, nindx) - || ! ieee_write_number (info, 0) - || ! ieee_write_number (info, 62) - || ! ieee_write_number (info, 80) - || ! ieee_write_number (info, 3) - || ! ieee_write_asn (info, nindx, 'R') - || ! ieee_write_asn (info, nindx, global ? 0 : 1) - || ! ieee_write_atn65 (info, nindx, name)) - return false; - } - - assert (! ieee_buffer_emptyp (&info->vars)); - if (! ieee_change_buffer (info, &info->vars)) - return false; - - /* The address is written out as the first block. */ - - ++info->block_depth; - - return (ieee_write_byte (info, (int) ieee_bb_record_enum) - && ieee_write_byte (info, global ? 4 : 6) - && ieee_write_number (info, 0) - && ieee_write_id (info, name) - && ieee_write_number (info, 0) - && ieee_write_number (info, typeindx)); -} - -/* Add a function parameter. This will normally be called before the - first block, so we postpone them until we see the block. */ - -static boolean -ieee_function_parameter (p, name, kind, val) - PTR p; - const char *name; - enum debug_parm_kind kind; - bfd_vma val; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - struct ieee_pending_parm *m, **pm; - - assert (info->block_depth == 1); - - m = (struct ieee_pending_parm *) xmalloc (sizeof *m); - memset (m, 0, sizeof *m); - - m->next = NULL; - m->name = name; - m->referencep = info->type_stack->type.referencep; - m->type = ieee_pop_type (info); - m->kind = kind; - m->val = val; - - for (pm = &info->pending_parms; *pm != NULL; pm = &(*pm)->next) - ; - *pm = m; - - /* Add the type to the fnargs list. */ - if (! ieee_change_buffer (info, &info->fnargs) - || ! ieee_write_number (info, m->type)) - return false; - ++info->fnargcount; - - return true; -} - -/* Output pending function parameters. */ - -static boolean -ieee_output_pending_parms (info) - struct ieee_handle *info; -{ - struct ieee_pending_parm *m; - unsigned int refcount; - - refcount = 0; - for (m = info->pending_parms; m != NULL; m = m->next) - { - enum debug_var_kind vkind; - - switch (m->kind) - { - default: - abort (); - return false; - case DEBUG_PARM_STACK: - case DEBUG_PARM_REFERENCE: - vkind = DEBUG_LOCAL; - break; - case DEBUG_PARM_REG: - case DEBUG_PARM_REF_REG: - vkind = DEBUG_REGISTER; - break; - } - - if (! ieee_push_type (info, m->type, 0, false, false)) - return false; - info->type_stack->type.referencep = m->referencep; - if (m->referencep) - ++refcount; - if (! ieee_variable ((PTR) info, m->name, vkind, m->val)) - return false; - } - - /* If there are any reference parameters, we need to output a - miscellaneous record indicating them. */ - if (refcount > 0) - { - unsigned int nindx, varindx; - - /* FIXME: The MRI compiler outputs the demangled function name - here, but we are outputting the mangled name. */ - nindx = info->name_indx; - ++info->name_indx; - if (! ieee_change_buffer (info, &info->vars) - || ! ieee_write_byte (info, (int) ieee_nn_record) - || ! ieee_write_number (info, nindx) - || ! ieee_write_id (info, "") - || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) - || ! ieee_write_number (info, nindx) - || ! ieee_write_number (info, 0) - || ! ieee_write_number (info, 62) - || ! ieee_write_number (info, 80) - || ! ieee_write_number (info, refcount + 3) - || ! ieee_write_asn (info, nindx, 'B') - || ! ieee_write_atn65 (info, nindx, info->fnname) - || ! ieee_write_asn (info, nindx, 0)) - return false; - for (m = info->pending_parms, varindx = 1; - m != NULL; - m = m->next, varindx++) - { - if (m->referencep) - { - if (! ieee_write_asn (info, nindx, varindx)) - return false; - } - } - } - - m = info->pending_parms; - while (m != NULL) - { - struct ieee_pending_parm *next; - - next = m->next; - free (m); - m = next; - } - - info->pending_parms = NULL; - - return true; -} - -/* Start a block. If this is the first block, we output the address - to finish the BB4 or BB6, and then output the function parameters. */ - -static boolean -ieee_start_block (p, addr) - PTR p; - bfd_vma addr; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - - if (! ieee_change_buffer (info, &info->vars)) - return false; - - if (info->block_depth == 1) - { - if (! ieee_write_number (info, addr) - || ! ieee_output_pending_parms (info)) - return false; - } - else - { - if (! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 6) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, "") - || ! ieee_write_number (info, 0) - || ! ieee_write_number (info, 0) - || ! ieee_write_number (info, addr)) - return false; - } - - if (! ieee_start_range (info, addr)) - return false; - - ++info->block_depth; - - return true; -} - -/* End a block. */ - -static boolean -ieee_end_block (p, addr) - PTR p; - bfd_vma addr; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - - /* The address we are given is the end of the block, but IEEE seems - to want to the address of the last byte in the block, so we - subtract one. */ - if (! ieee_change_buffer (info, &info->vars) - || ! ieee_write_byte (info, (int) ieee_be_record_enum) - || ! ieee_write_number (info, addr - 1)) - return false; - - if (! ieee_end_range (info, addr)) - return false; - - --info->block_depth; - - if (addr > info->highaddr) - info->highaddr = addr; - - return true; -} - -/* End a function. */ - -static boolean -ieee_end_function (p) - PTR p; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - - assert (info->block_depth == 1); - - --info->block_depth; - - /* Now we can finish up fntype, and add it to the typdef section. - At this point, fntype is the 'x' type up to the argument count, - and fnargs is the argument types. We must add the argument - count, and we must add the level. FIXME: We don't record varargs - functions correctly. In fact, stabs debugging does not give us - enough information to do so. */ - if (! ieee_change_buffer (info, &info->fntype) - || ! ieee_write_number (info, info->fnargcount) - || ! ieee_change_buffer (info, &info->fnargs) - || ! ieee_write_number (info, 0)) - return false; - - /* Make sure the typdef block has been started. */ - if (ieee_buffer_emptyp (&info->types)) - { - if (! ieee_change_buffer (info, &info->types) - || ! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 1) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, info->modname)) - return false; - } - - if (! ieee_append_buffer (info, &info->types, &info->fntype) - || ! ieee_append_buffer (info, &info->types, &info->fnargs)) - return false; - - info->fnname = NULL; - if (! ieee_init_buffer (info, &info->fntype) - || ! ieee_init_buffer (info, &info->fnargs)) - return false; - info->fnargcount = 0; - - return true; -} - -/* Record line number information. */ - -static boolean -ieee_lineno (p, filename, lineno, addr) - PTR p; - const char *filename; - unsigned long lineno; - bfd_vma addr; -{ - struct ieee_handle *info = (struct ieee_handle *) p; - - assert (info->filename != NULL); - - /* The HP simulator seems to get confused when more than one line is - listed for the same address, at least if they are in different - files. We handle this by always listing the last line for a - given address, since that seems to be the one that gdb uses. */ - if (info->pending_lineno_filename != NULL - && addr != info->pending_lineno_addr) - { - /* Make sure we have a line number block. */ - if (! ieee_buffer_emptyp (&info->linenos)) - { - if (! ieee_change_buffer (info, &info->linenos)) - return false; - } - else - { - info->lineno_name_indx = info->name_indx; - ++info->name_indx; - if (! ieee_change_buffer (info, &info->linenos) - || ! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 5) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, info->filename) - || ! ieee_write_byte (info, (int) ieee_nn_record) - || ! ieee_write_number (info, info->lineno_name_indx) - || ! ieee_write_id (info, "")) - return false; - info->lineno_filename = info->filename; - } - - if (strcmp (info->pending_lineno_filename, info->lineno_filename) != 0) - { - if (strcmp (info->filename, info->lineno_filename) != 0) - { - /* We were not in the main file. Close the block for the - included file. */ - if (! ieee_write_byte (info, (int) ieee_be_record_enum)) - return false; - if (strcmp (info->filename, info->pending_lineno_filename) == 0) - { - /* We need a new NN record, and we aren't about to - output one. */ - info->lineno_name_indx = info->name_indx; - ++info->name_indx; - if (! ieee_write_byte (info, (int) ieee_nn_record) - || ! ieee_write_number (info, info->lineno_name_indx) - || ! ieee_write_id (info, "")) - return false; - } - } - if (strcmp (info->filename, info->pending_lineno_filename) != 0) - { - /* We are not changing to the main file. Open a block for - the new included file. */ - info->lineno_name_indx = info->name_indx; - ++info->name_indx; - if (! ieee_write_byte (info, (int) ieee_bb_record_enum) - || ! ieee_write_byte (info, 5) - || ! ieee_write_number (info, 0) - || ! ieee_write_id (info, info->pending_lineno_filename) - || ! ieee_write_byte (info, (int) ieee_nn_record) - || ! ieee_write_number (info, info->lineno_name_indx) - || ! ieee_write_id (info, "")) - return false; - } - info->lineno_filename = info->pending_lineno_filename; - } - - if (! ieee_write_2bytes (info, (int) ieee_atn_record_enum) - || ! ieee_write_number (info, info->lineno_name_indx) - || ! ieee_write_number (info, 0) - || ! ieee_write_number (info, 7) - || ! ieee_write_number (info, info->pending_lineno) - || ! ieee_write_number (info, 0) - || ! ieee_write_asn (info, info->lineno_name_indx, - info->pending_lineno_addr)) - return false; - } - - info->pending_lineno_filename = filename; - info->pending_lineno = lineno; - info->pending_lineno_addr = addr; - - return true; -} diff --git a/pstack/ieee.h b/pstack/ieee.h deleted file mode 100644 index 56634b2819a..00000000000 --- a/pstack/ieee.h +++ /dev/null @@ -1,138 +0,0 @@ -/* IEEE Standard 695-1980 "Universal Format for Object Modules" header file - Contributed by Cygnus Support. */ - -#define N_W_VARIABLES 8 -#define Module_Beginning 0xe0 - -typedef struct ieee_module { - char *processor; - char *module_name; -} ieee_module_begin_type; - -#define Address_Descriptor 0xec -typedef struct ieee_address { -bfd_vma number_of_bits_mau; - bfd_vma number_of_maus_in_address; - - unsigned char byte_order; -#define IEEE_LITTLE 0xcc -#define IEEE_BIG 0xcd -} ieee_address_descriptor_type; - -typedef union ieee_w_variable { - file_ptr offset[N_W_VARIABLES]; - struct { - file_ptr extension_record; - file_ptr environmental_record; - file_ptr section_part; - file_ptr external_part; - file_ptr debug_information_part; - file_ptr data_part; - file_ptr trailer_part; - file_ptr me_record; - } r; -} ieee_w_variable_type; - - - - - -typedef enum ieee_record -{ - ieee_number_start_enum = 0x00, - ieee_number_end_enum=0x7f, - ieee_number_repeat_start_enum = 0x80, - ieee_number_repeat_end_enum = 0x88, - ieee_number_repeat_4_enum = 0x84, - ieee_number_repeat_3_enum = 0x83, - ieee_number_repeat_2_enum = 0x82, - ieee_number_repeat_1_enum = 0x81, - ieee_module_beginning_enum = 0xe0, - ieee_module_end_enum = 0xe1, - ieee_extension_length_1_enum = 0xde, - ieee_extension_length_2_enum = 0xdf, - ieee_section_type_enum = 0xe6, - ieee_section_alignment_enum = 0xe7, - ieee_external_symbol_enum = 0xe8, - ieee_comma = 0x90, - ieee_external_reference_enum = 0xe9, - ieee_set_current_section_enum = 0xe5, - ieee_address_descriptor_enum = 0xec, - ieee_load_constant_bytes_enum = 0xed, - ieee_load_with_relocation_enum = 0xe4, - - ieee_variable_A_enum = 0xc1, - ieee_variable_B_enum = 0xc2, - ieee_variable_C_enum = 0xc3, - ieee_variable_D_enum = 0xc4, - ieee_variable_E_enum = 0xc5, - ieee_variable_F_enum = 0xc6, - ieee_variable_G_enum = 0xc7, - ieee_variable_H_enum = 0xc8, - ieee_variable_I_enum = 0xc9, - ieee_variable_J_enum = 0xca, - ieee_variable_K_enum = 0xcb, - ieee_variable_L_enum = 0xcc, - ieee_variable_M_enum = 0xcd, - ieee_variable_N_enum = 0xce, - ieee_variable_O_enum = 0xcf, - ieee_variable_P_enum = 0xd0, - ieee_variable_Q_enum = 0xd1, - ieee_variable_R_enum = 0xd2, - ieee_variable_S_enum = 0xd3, - ieee_variable_T_enum = 0xd4, - ieee_variable_U_enum = 0xd5, - ieee_variable_V_enum = 0xd6, - ieee_variable_W_enum = 0xd7, - ieee_variable_X_enum = 0xd8, - ieee_variable_Y_enum = 0xd9, - ieee_variable_Z_enum = 0xda, - ieee_function_plus_enum = 0xa5, - ieee_function_minus_enum = 0xa6, - ieee_function_signed_open_b_enum = 0xba, - ieee_function_signed_close_b_enum = 0xbb, - - ieee_function_unsigned_open_b_enum = 0xbc, - ieee_function_unsigned_close_b_enum = 0xbd, - - ieee_function_either_open_b_enum = 0xbe, - ieee_function_either_close_b_enum = 0xbf, - ieee_record_seperator_enum = 0xdb, - - ieee_e2_first_byte_enum = 0xe2, - ieee_section_size_enum = 0xe2d3, - ieee_physical_region_size_enum = 0xe2c1, - ieee_region_base_address_enum = 0xe2c2, - ieee_mau_size_enum = 0xe2c6, - ieee_m_value_enum = 0xe2cd, - ieee_section_base_address_enum = 0xe2cc, - ieee_asn_record_enum = 0xe2ce, - ieee_section_offset_enum = 0xe2d2, - ieee_value_starting_address_enum = 0xe2c7, - ieee_assign_value_to_variable_enum = 0xe2d7, - ieee_set_current_pc_enum = 0xe2d0, - ieee_value_record_enum = 0xe2c9, - ieee_nn_record = 0xf0, - ieee_at_record_enum = 0xf1, - ieee_ty_record_enum = 0xf2, - ieee_attribute_record_enum = 0xf1c9, - ieee_atn_record_enum = 0xf1ce, - ieee_external_reference_info_record_enum = 0xf1d8, - ieee_weak_external_reference_enum= 0xf4, - ieee_repeat_data_enum = 0xf7, - ieee_bb_record_enum = 0xf8, - ieee_be_record_enum = 0xf9 -} ieee_record_enum_type; - - -typedef struct ieee_section { - unsigned int section_index; - unsigned int section_type; - char *section_name; - unsigned int parent_section_index; - unsigned int sibling_section_index; - unsigned int context_index; -} ieee_section_type; -#define IEEE_REFERENCE_BASE 11 -#define IEEE_PUBLIC_BASE 32 -#define IEEE_SECTION_NUMBER_BASE 1 diff --git a/pstack/libiberty.h b/pstack/libiberty.h deleted file mode 100644 index ca0043d31c6..00000000000 --- a/pstack/libiberty.h +++ /dev/null @@ -1,180 +0,0 @@ -/* Function declarations for libiberty. - Written by Cygnus Support, 1994. - - The libiberty library provides a number of functions which are - missing on some operating systems. We do not declare those here, - to avoid conflicts with the system header files on operating - systems that do support those functions. In this file we only - declare those functions which are specific to libiberty. */ - -#ifndef LIBIBERTY_H -#define LIBIBERTY_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "ansidecl.h" - -/* Build an argument vector from a string. Allocates memory using - malloc. Use freeargv to free the vector. */ - -extern char **buildargv PARAMS ((char *)); - -/* Free a vector returned by buildargv. */ - -extern void freeargv PARAMS ((char **)); - -/* Duplicate an argument vector. Allocates memory using malloc. Use - freeargv to free the vector. */ - -extern char **dupargv PARAMS ((char **)); - - -/* Return the last component of a path name. Note that we can't use a - prototype here because the parameter is declared inconsistently - across different systems, sometimes as "char *" and sometimes as - "const char *" */ - -#if defined (__GNU_LIBRARY__ ) || defined (__linux__) || defined (__FreeBSD__) -extern char *basename PARAMS ((const char *)); -#else -extern char *basename (); -#endif - -/* Concatenate an arbitrary number of strings, up to (char *) NULL. - Allocates memory using xmalloc. */ - -extern char *concat PARAMS ((const char *, ...)); - -/* Check whether two file descriptors refer to the same file. */ - -extern int fdmatch PARAMS ((int fd1, int fd2)); - -/* Get the amount of time the process has run, in microseconds. */ - -extern long get_run_time PARAMS ((void)); - -/* Choose a temporary directory to use for scratch files. */ - -extern char *choose_temp_base PARAMS ((void)); - -/* Allocate memory filled with spaces. Allocates using malloc. */ - -extern const char *spaces PARAMS ((int count)); - -/* Return the maximum error number for which strerror will return a - string. */ - -extern int errno_max PARAMS ((void)); - -/* Return the name of an errno value (e.g., strerrno (EINVAL) returns - "EINVAL"). */ - -extern const char *strerrno PARAMS ((int)); - -/* Given the name of an errno value, return the value. */ - -extern int strtoerrno PARAMS ((const char *)); - -/* ANSI's strerror(), but more robust. */ - -extern char *xstrerror PARAMS ((int)); - -/* Return the maximum signal number for which strsignal will return a - string. */ - -extern int signo_max PARAMS ((void)); - -/* Return a signal message string for a signal number - (e.g., strsignal (SIGHUP) returns something like "Hangup"). */ -/* This is commented out as it can conflict with one in system headers. - We still document its existence though. */ - -/*extern const char *strsignal PARAMS ((int));*/ - -/* Return the name of a signal number (e.g., strsigno (SIGHUP) returns - "SIGHUP"). */ - -extern const char *strsigno PARAMS ((int)); - -/* Given the name of a signal, return its number. */ - -extern int strtosigno PARAMS ((const char *)); - -/* Register a function to be run by xexit. Returns 0 on success. */ - -extern int xatexit PARAMS ((void (*fn) (void))); - -/* Exit, calling all the functions registered with xatexit. */ - -#ifndef __GNUC__ -extern void xexit PARAMS ((int status)); -#else -void xexit PARAMS ((int status)) __attribute__ ((noreturn)); -#endif - -/* Set the program name used by xmalloc. */ - -extern void xmalloc_set_program_name PARAMS ((const char *)); - -/* Allocate memory without fail. If malloc fails, this will print a - message to stderr (using the name set by xmalloc_set_program_name, - if any) and then call xexit. */ - -#ifdef ANSI_PROTOTYPES -/* Get a definition for size_t. */ -#include -#endif -extern PTR xmalloc PARAMS ((size_t)); - -/* Reallocate memory without fail. This works like xmalloc. - - FIXME: We do not declare the parameter types for the same reason as - xmalloc. */ - -extern PTR xrealloc PARAMS ((PTR, size_t)); - -/* Allocate memory without fail and set it to zero. This works like - xmalloc. */ - -extern PTR xcalloc PARAMS ((size_t, size_t)); - -/* Copy a string into a memory buffer without fail. */ - -extern char *xstrdup PARAMS ((const char *)); - -/* hex character manipulation routines */ - -#define _hex_array_size 256 -#define _hex_bad 99 -extern char _hex_value[_hex_array_size]; -extern void hex_init PARAMS ((void)); -#define hex_p(c) (hex_value (c) != _hex_bad) -/* If you change this, note well: Some code relies on side effects in - the argument being performed exactly once. */ -#define hex_value(c) (_hex_value[(unsigned char) (c)]) - -/* Definitions used by the pexecute routine. */ - -#define PEXECUTE_FIRST 1 -#define PEXECUTE_LAST 2 -#define PEXECUTE_ONE (PEXECUTE_FIRST + PEXECUTE_LAST) -#define PEXECUTE_SEARCH 4 -#define PEXECUTE_VERBOSE 8 - -/* Execute a program. */ - -extern int pexecute PARAMS ((const char *, char * const *, const char *, - const char *, char **, char **, int)); - -/* Wait for pexecute to finish. */ - -extern int pwait PARAMS ((int, int *, int)); - -#ifdef __cplusplus -} -#endif - - -#endif /* ! defined (LIBIBERTY_H) */ diff --git a/pstack/linuxthreads.c b/pstack/linuxthreads.c deleted file mode 100644 index 8624bd21782..00000000000 --- a/pstack/linuxthreads.c +++ /dev/null @@ -1,90 +0,0 @@ -/* $Header$ */ - -/* - * LinuxThreads specific stuff. - */ - -#include - -#include -#include /* PTHREAD_THREADS_MAX */ -#include -#include -#include -#include -#include - -#include "linuxthreads.h" - -#define AT_INT(intval) *((int32_t*)(intval)) - -/* - * Internal LinuxThreads variables. - * Official interface exposed to GDB. - */ -#if 1 -extern volatile int __pthread_threads_debug; -extern volatile char __pthread_handles; -extern char __pthread_initial_thread; -/*extern volatile Elf32_Sym* __pthread_manager_thread;*/ -extern const int __pthread_sizeof_handle; -extern const int __pthread_offsetof_descr; -extern const int __pthread_offsetof_pid; -extern volatile int __pthread_handles_num; -#endif /* 0 */ - -/* - * Notify others. - */ -int -linuxthreads_notify_others( const int signotify) -{ - const pid_t mypid = getpid(); - //const pthread_t mytid = pthread_self(); - int i; - int threadcount = 0; - int threads[PTHREAD_THREADS_MAX]; - int pid; - - TRACE_FPRINTF((stderr, "theadcount:%d\n", __pthread_handles_num)); - if (__pthread_handles_num==2) { - /* no threads beside the initial thread */ - return 0; - } - /*assert(maxthreads>=3); - assert(maxthreads>=__pthread_handles_num+2);*/ - - // take the initial thread with us - pid = AT_INT(&__pthread_initial_thread + __pthread_offsetof_pid); - if (pid!=mypid && pid!=0) - threads[threadcount++] = pid; - // don't know why, but always handles[0]==handles[1] - for (i=1; i<__pthread_handles_num; ++i) { - const int descr = AT_INT(&__pthread_handles+i*__pthread_sizeof_handle+__pthread_offsetof_descr); - assert(descr!=0); - pid = AT_INT(descr+__pthread_offsetof_pid); - if (pid!=mypid && pid!=0) - threads[threadcount++] = pid; - } - /* TRACE_FPRINTF((stderr, "Stopping threads...")); */ - //for (i=0; i -#include "pstacktrace.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Tell other threads to dump stacks... - */ -int -linuxthreads_notify_others( const int signotify); - -#ifdef __cplusplus -} -#endif - -#endif /* pstack_linuxthreads_h_ */ - diff --git a/pstack/pstack.c b/pstack/pstack.c deleted file mode 100644 index 4cdd80d68b5..00000000000 --- a/pstack/pstack.c +++ /dev/null @@ -1,2746 +0,0 @@ -/* - pstack.c -- asynchronous stack trace of a running process - Copyright (c) 1999 Ross Thompson - Author: Ross Thompson - Critical bug fix: Tim Waugh -*/ - -/* - This file 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; either version 2 of the License, or - (at your option) any later version. - - 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -/* RESTRICTIONS: - - pstack currently works only on Linux, only on an x86 machine running - 32 bit ELF binaries (64 bit not supported). Also, for symbolic - information, you need to use a GNU compiler to generate your - program, and you can't strip symbols from the binaries. For thread - information to be dumped, you have to use the debug-aware version - of libpthread.so. (To check, run 'nm' on your libpthread.so, and - make sure that the symbol "__pthread_threads_debug" is defined.) - - The details of pulling stuff out of ELF files and running through - program images is very platform specific, and I don't want to - try to support modes or machine types I can't test in or on. - If someone wants to generalize this to other architectures, I would - be happy to help and coordinate the activity. Please send me whatever - changes you make to support these machines, so that I can own the - central font of all truth (at least as regards this program). - - Thanks -*/ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* PTHREAD_THREADS_MAX */ - - -#include - -#include "libiberty.h" - -#include "pstack.h" /* just one function */ -#include "budbg.h" /* binutils stuff related to debugging symbols. */ -#include "bucomm.h" /* some common stuff */ -#include "debug.h" /* and more binutils stuff... */ -#include "budbg.h" -#include "linuxthreads.h" /* LinuxThreads specific stuff... */ - - -/* - * fprintf for file descriptors :) NOTE: we have to use fixed-size buffer :)( - * due to malloc's unavalaibility. - */ -int -fdprintf( int fd, - const char* fmt,...) -{ - char xbuf[2048];// FIXME: enough? - va_list ap; - int r; - if (fd<0) - return -1; - va_start(ap, fmt); - r = vsnprintf(xbuf, sizeof(xbuf), fmt, ap); - va_end(ap); - return write(fd, xbuf, r); -} - -int -fdputc( char c, - int fd) -{ - if (fd<0) - return -1; - return write(fd, &c, sizeof(c)); -} - -int -fdputs( const char* s, - int fd) -{ - if (fd<0) - return -1; - return write(fd, s, strlen(s)); -} - -/* - * Use this function to open log file. - * Flags: truncate on opening. - */ -static const char* path_format = "stack-trace-on-segv-%d.txt"; -static int -open_log_file( const pthread_t tid, - const pid_t pid) -{ - char fname[PATH_MAX]; - int r; - snprintf(fname, sizeof(fname), path_format, tid, pid); - r = open(fname, O_WRONLY|O_CREAT|O_TRUNC, - S_IRUSR|S_IWUSR); - if (r<0) - perror("open"); - return r; -} -/* - * Add additional debugging information for functions. - */ - -/* - * Lineno - */ -typedef struct { - int lineno; - bfd_vma addr; -} debug_lineno_t; - -/* - * Block - a {} pair. - */ -typedef struct debug_block_st { - bfd_vma begin_addr; /* where did it start */ - bfd_vma end_addr; /* where did it end */ - struct debug_block_st* parent; - struct debug_block_st* childs; - int childs_count; -} debug_block_t; - -/* - * Function parameter. - */ -typedef struct { - bfd_vma offset; /* Offset in the stack */ - const char* name; /* And name. */ -} debug_parameter_t; - -/* - * Extra information about functions. - */ -typedef struct { - asymbol* symbol; /* mangled function name, addr */ - debug_lineno_t* lines; - int lines_count; - int max_lines_count; - const char* name; - const char* filename;/* a file name it occured in... */ - debug_block_t* block; /* each function has a block, or not, you know */ - debug_parameter_t* argv; /* argument types. */ - int argc; - int max_argc; -} debug_function_t; - -/* This is the structure we use as a handle for these routines. */ -struct pr_handle -{ - /* File to print information to. */ - FILE *f; - /* Current indentation level. */ - unsigned int indent; - /* Type stack. */ - struct pr_stack *stack; - /* Parameter number we are about to output. */ - int parameter; - debug_block_t* block; /* current block */ - debug_function_t* function; /* current function */ - debug_function_t* functions; /* all functions */ - int functions_size; /* current size */ - int functions_maxsize; /* maximum size */ -}; - -/* The type stack. */ - -struct pr_stack -{ - /* Next element on the stack. */ - struct pr_stack *next; - /* This element. */ - char *type; - /* Current visibility of fields if this is a class. */ - enum debug_visibility visibility; - /* Name of the current method we are handling. */ - const char *method; -}; - -static void indent PARAMS ((struct pr_handle *)); -static boolean push_type PARAMS ((struct pr_handle *, const char *)); -static boolean prepend_type PARAMS ((struct pr_handle *, const char *)); -static boolean append_type PARAMS ((struct pr_handle *, const char *)); -static boolean substitute_type PARAMS ((struct pr_handle *, const char *)); -static boolean indent_type PARAMS ((struct pr_handle *)); -static char *pop_type PARAMS ((struct pr_handle *)); -static void print_vma PARAMS ((bfd_vma, char *, boolean, boolean)); -static boolean pr_fix_visibility - PARAMS ((struct pr_handle *, enum debug_visibility)); - -static boolean pr_start_compilation_unit PARAMS ((PTR, const char *)); -static boolean pr_start_source PARAMS ((PTR, const char *)); -static boolean pr_empty_type PARAMS ((PTR)); -static boolean pr_void_type PARAMS ((PTR)); -static boolean pr_int_type PARAMS ((PTR, unsigned int, boolean)); -static boolean pr_float_type PARAMS ((PTR, unsigned int)); -static boolean pr_complex_type PARAMS ((PTR, unsigned int)); -static boolean pr_bool_type PARAMS ((PTR, unsigned int)); -static boolean pr_enum_type - PARAMS ((PTR, const char *, const char **, bfd_signed_vma *)); -static boolean pr_pointer_type PARAMS ((PTR)); -static boolean pr_function_type PARAMS ((PTR, int, boolean)); -static boolean pr_reference_type PARAMS ((PTR)); -static boolean pr_range_type PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma)); -static boolean pr_array_type - PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, boolean)); -static boolean pr_set_type PARAMS ((PTR, boolean)); -static boolean pr_offset_type PARAMS ((PTR)); -static boolean pr_method_type PARAMS ((PTR, boolean, int, boolean)); -static boolean pr_const_type PARAMS ((PTR)); -static boolean pr_volatile_type PARAMS ((PTR)); -static boolean pr_start_struct_type - PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int)); -static boolean pr_struct_field - PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility)); -static boolean pr_end_struct_type PARAMS ((PTR)); -static boolean pr_start_class_type - PARAMS ((PTR, const char *, unsigned int, boolean, unsigned int, boolean, - boolean)); -static boolean pr_class_static_member - PARAMS ((PTR, const char *, const char *, enum debug_visibility)); -static boolean pr_class_baseclass - PARAMS ((PTR, bfd_vma, boolean, enum debug_visibility)); -static boolean pr_class_start_method PARAMS ((PTR, const char *)); -static boolean pr_class_method_variant - PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean, - bfd_vma, boolean)); -static boolean pr_class_static_method_variant - PARAMS ((PTR, const char *, enum debug_visibility, boolean, boolean)); -static boolean pr_class_end_method PARAMS ((PTR)); -static boolean pr_end_class_type PARAMS ((PTR)); -static boolean pr_typedef_type PARAMS ((PTR, const char *)); -static boolean pr_tag_type - PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind)); -static boolean pr_typdef PARAMS ((PTR, const char *)); -static boolean pr_tag PARAMS ((PTR, const char *)); -static boolean pr_int_constant PARAMS ((PTR, const char *, bfd_vma)); -static boolean pr_float_constant PARAMS ((PTR, const char *, double)); -static boolean pr_typed_constant PARAMS ((PTR, const char *, bfd_vma)); -static boolean pr_variable - PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma)); -static boolean pr_start_function PARAMS ((PTR, const char *, boolean)); -static boolean pr_function_parameter - PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma)); -static boolean pr_start_block PARAMS ((PTR, bfd_vma)); -static boolean pr_end_block PARAMS ((PTR, bfd_vma)); -static boolean pr_end_function PARAMS ((PTR)); -static boolean pr_lineno PARAMS ((PTR, const char *, unsigned long, bfd_vma)); - -static const struct debug_write_fns pr_fns = -{ - pr_start_compilation_unit, - pr_start_source, - pr_empty_type, - pr_void_type, - pr_int_type, - pr_float_type, - pr_complex_type, - pr_bool_type, - pr_enum_type, - pr_pointer_type, - pr_function_type, - pr_reference_type, - pr_range_type, - pr_array_type, - pr_set_type, - pr_offset_type, - pr_method_type, - pr_const_type, - pr_volatile_type, - pr_start_struct_type, - pr_struct_field, - pr_end_struct_type, - pr_start_class_type, - pr_class_static_member, - pr_class_baseclass, - pr_class_start_method, - pr_class_method_variant, - pr_class_static_method_variant, - pr_class_end_method, - pr_end_class_type, - pr_typedef_type, - pr_tag_type, - pr_typdef, - pr_tag, - pr_int_constant, - pr_float_constant, - pr_typed_constant, - pr_variable, - pr_start_function, - pr_function_parameter, - pr_start_block, - pr_end_block, - pr_end_function, - pr_lineno -}; - - -/* Indent to the current indentation level. */ - -static void -indent (info) - struct pr_handle *info; -{ - unsigned int i; - - for (i = 0; i < info->indent; i++) - TRACE_PUTC ((' ', info->f)); -} - -/* Push a type on the type stack. */ - -static boolean -push_type (info, type) - struct pr_handle *info; - const char *type; -{ - struct pr_stack *n; - - if (type == NULL) - return false; - - n = (struct pr_stack *) xmalloc (sizeof *n); - memset (n, 0, sizeof *n); - - n->type = xstrdup (type); - n->visibility = DEBUG_VISIBILITY_IGNORE; - n->method = NULL; - n->next = info->stack; - info->stack = n; - - return true; -} - -/* Prepend a string onto the type on the top of the type stack. */ - -static boolean -prepend_type (info, s) - struct pr_handle *info; - const char *s; -{ - char *n; - - assert (info->stack != NULL); - - n = (char *) xmalloc (strlen (s) + strlen (info->stack->type) + 1); - sprintf (n, "%s%s", s, info->stack->type); - free (info->stack->type); - info->stack->type = n; - - return true; -} - -/* Append a string to the type on the top of the type stack. */ - -static boolean -append_type (info, s) - struct pr_handle *info; - const char *s; -{ - unsigned int len; - - if (s == NULL) - return false; - - assert (info->stack != NULL); - - len = strlen (info->stack->type); - info->stack->type = (char *) xrealloc (info->stack->type, - len + strlen (s) + 1); - strcpy (info->stack->type + len, s); - - return true; -} - -/* We use an underscore to indicate where the name should go in a type - string. This function substitutes a string for the underscore. If - there is no underscore, the name follows the type. */ - -static boolean -substitute_type (info, s) - struct pr_handle *info; - const char *s; -{ - char *u; - - assert (info->stack != NULL); - - u = strchr (info->stack->type, '|'); - if (u != NULL) - { - char *n; - - n = (char *) xmalloc (strlen (info->stack->type) + strlen (s)); - - memcpy (n, info->stack->type, u - info->stack->type); - strcpy (n + (u - info->stack->type), s); - strcat (n, u + 1); - - free (info->stack->type); - info->stack->type = n; - - return true; - } - - if (strchr (s, '|') != NULL - && (strchr (info->stack->type, '{') != NULL - || strchr (info->stack->type, '(') != NULL)) - { - if (! prepend_type (info, "(") - || ! append_type (info, ")")) - return false; - } - - if (*s == '\0') - return true; - - return (append_type (info, " ") - && append_type (info, s)); -} - -/* Indent the type at the top of the stack by appending spaces. */ - -static boolean -indent_type (info) - struct pr_handle *info; -{ - unsigned int i; - - for (i = 0; i < info->indent; i++) - { - if (! append_type (info, " ")) - return false; - } - - return true; -} - -/* Pop a type from the type stack. */ - -static char * -pop_type (info) - struct pr_handle *info; -{ - struct pr_stack *o; - char *ret; - - assert (info->stack != NULL); - - o = info->stack; - info->stack = o->next; - ret = o->type; - free (o); - - return ret; -} - -/* Print a VMA value into a string. */ - -static void -print_vma (vma, buf, unsignedp, hexp) - bfd_vma vma; - char *buf; - boolean unsignedp; - boolean hexp; -{ - if (sizeof (vma) <= sizeof (unsigned long)) - { - if (hexp) - sprintf (buf, "0x%lx", (unsigned long) vma); - else if (unsignedp) - sprintf (buf, "%lu", (unsigned long) vma); - else - sprintf (buf, "%ld", (long) vma); - } - else - { - buf[0] = '0'; - buf[1] = 'x'; - sprintf_vma (buf + 2, vma); - } -} - -/* Start a new compilation unit. */ - -static boolean -pr_start_compilation_unit (p, filename) - PTR p; - const char *filename; -{ - struct pr_handle *info = (struct pr_handle *) p; - - assert (info->indent == 0); -/* - TRACE_FPRINTF( (info->f, "%s:\n", filename)); -*/ - return true; -} - -/* Start a source file within a compilation unit. */ - -static boolean -pr_start_source (p, filename) - PTR p; - const char *filename; -{ - struct pr_handle *info = (struct pr_handle *) p; - - assert (info->indent == 0); -/* - TRACE_FPRINTF( (info->f, " %s:\n", filename)); -*/ - return true; -} - -/* Push an empty type onto the type stack. */ - -static boolean -pr_empty_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - - return push_type (info, ""); -} - -/* Push a void type onto the type stack. */ - -static boolean -pr_void_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - - return push_type (info, "void"); -} - -/* Push an integer type onto the type stack. */ - -static boolean -pr_int_type (p, size, unsignedp) - PTR p; - unsigned int size; - boolean unsignedp; -{ - struct pr_handle *info = (struct pr_handle *) p; - char ab[10]; - - sprintf (ab, "%sint%d", unsignedp ? "u" : "", size * 8); - return push_type (info, ab); -} - -/* Push a floating type onto the type stack. */ - -static boolean -pr_float_type (p, size) - PTR p; - unsigned int size; -{ - struct pr_handle *info = (struct pr_handle *) p; - char ab[10]; - - if (size == 4) - return push_type (info, "float"); - else if (size == 8) - return push_type (info, "double"); - - sprintf (ab, "float%d", size * 8); - return push_type (info, ab); -} - -/* Push a complex type onto the type stack. */ - -static boolean -pr_complex_type (p, size) - PTR p; - unsigned int size; -{ - struct pr_handle *info = (struct pr_handle *) p; - - if (! pr_float_type (p, size)) - return false; - - return prepend_type (info, "complex "); -} - -/* Push a boolean type onto the type stack. */ - -static boolean -pr_bool_type (p, size) - PTR p; - unsigned int size; -{ - struct pr_handle *info = (struct pr_handle *) p; - char ab[10]; - - sprintf (ab, "bool%d", size * 8); - - return push_type (info, ab); -} - -/* Push an enum type onto the type stack. */ - -static boolean -pr_enum_type (p, tag, names, values) - PTR p; - const char *tag; - const char **names; - bfd_signed_vma *values; -{ - struct pr_handle *info = (struct pr_handle *) p; - unsigned int i; - bfd_signed_vma val; - - if (! push_type (info, "enum ")) - return false; - if (tag != NULL) - { - if (! append_type (info, tag) - || ! append_type (info, " ")) - return false; - } - if (! append_type (info, "{ ")) - return false; - - if (names == NULL) - { - if (! append_type (info, "/* undefined */")) - return false; - } - else - { - val = 0; - for (i = 0; names[i] != NULL; i++) - { - if (i > 0) - { - if (! append_type (info, ", ")) - return false; - } - - if (! append_type (info, names[i])) - return false; - - if (values[i] != val) - { - char ab[20]; - - print_vma (values[i], ab, false, false); - if (! append_type (info, " = ") - || ! append_type (info, ab)) - return false; - val = values[i]; - } - - ++val; - } - } - - return append_type (info, " }"); -} - -/* Turn the top type on the stack into a pointer. */ - -static boolean -pr_pointer_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *s; - - assert (info->stack != NULL); - - s = strchr (info->stack->type, '|'); - if (s != NULL && s[1] == '[') - return substitute_type (info, "(*|)"); - return substitute_type (info, "*|"); -} - -/* Turn the top type on the stack into a function returning that type. */ - -static boolean -pr_function_type (p, argcount, varargs) - PTR p; - int argcount; - boolean varargs; -{ - struct pr_handle *info = (struct pr_handle *) p; - char **arg_types; - unsigned int len; - char *s; - - assert (info->stack != NULL); - - len = 10; - - if (argcount <= 0) - { - arg_types = NULL; - len += 15; - } - else - { - int i; - - arg_types = (char **) xmalloc (argcount * sizeof *arg_types); - for (i = argcount - 1; i >= 0; i--) - { - if (! substitute_type (info, "")) - return false; - arg_types[i] = pop_type (info); - if (arg_types[i] == NULL) - return false; - len += strlen (arg_types[i]) + 2; - } - if (varargs) - len += 5; - } - - /* Now the return type is on the top of the stack. */ - - s = (char *) xmalloc (len); - strcpy (s, "(|) ("); - - if (argcount < 0) - { -#if 0 - /* Turn off unknown arguments. */ - strcat (s, "/* unknown */"); -#endif - } - else - { - int i; - - for (i = 0; i < argcount; i++) - { - if (i > 0) - strcat (s, ", "); - strcat (s, arg_types[i]); - } - if (varargs) - { - if (i > 0) - strcat (s, ", "); - strcat (s, "..."); - } - if (argcount > 0) - free (arg_types); - } - - strcat (s, ")"); - - if (! substitute_type (info, s)) - return false; - - free (s); - - return true; -} - -/* Turn the top type on the stack into a reference to that type. */ - -static boolean -pr_reference_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - - assert (info->stack != NULL); - - return substitute_type (info, "&|"); -} - -/* Make a range type. */ - -static boolean -pr_range_type (p, lower, upper) - PTR p; - bfd_signed_vma lower; - bfd_signed_vma upper; -{ - struct pr_handle *info = (struct pr_handle *) p; - char abl[20], abu[20]; - - assert (info->stack != NULL); - - if (! substitute_type (info, "")) - return false; - - print_vma (lower, abl, false, false); - print_vma (upper, abu, false, false); - - return (prepend_type (info, "range (") - && append_type (info, "):") - && append_type (info, abl) - && append_type (info, ":") - && append_type (info, abu)); -} - -/* Make an array type. */ - -/*ARGSUSED*/ -static boolean -pr_array_type (p, lower, upper, stringp) - PTR p; - bfd_signed_vma lower; - bfd_signed_vma upper; - boolean stringp; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *range_type; - char abl[20], abu[20], ab[50]; - - range_type = pop_type (info); - if (range_type == NULL) - return false; - - if (lower == 0) - { - if (upper == -1) - sprintf (ab, "|[]"); - else - { - print_vma (upper + 1, abu, false, false); - sprintf (ab, "|[%s]", abu); - } - } - else - { - print_vma (lower, abl, false, false); - print_vma (upper, abu, false, false); - sprintf (ab, "|[%s:%s]", abl, abu); - } - - if (! substitute_type (info, ab)) - return false; - - if (strcmp (range_type, "int") != 0) - { - if (! append_type (info, ":") - || ! append_type (info, range_type)) - return false; - } - - if (stringp) - { - if (! append_type (info, " /* string */")) - return false; - } - - return true; -} - -/* Make a set type. */ - -/*ARGSUSED*/ -static boolean -pr_set_type (p, bitstringp) - PTR p; - boolean bitstringp; -{ - struct pr_handle *info = (struct pr_handle *) p; - - if (! substitute_type (info, "")) - return false; - - if (! prepend_type (info, "set { ") - || ! append_type (info, " }")) - return false; - - if (bitstringp) - { - if (! append_type (info, "/* bitstring */")) - return false; - } - - return true; -} - -/* Make an offset type. */ - -static boolean -pr_offset_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *t; - - if (! substitute_type (info, "")) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - - return (substitute_type (info, "") - && prepend_type (info, " ") - && prepend_type (info, t) - && append_type (info, "::|")); -} - -/* Make a method type. */ - -static boolean -pr_method_type (p, domain, argcount, varargs) - PTR p; - boolean domain; - int argcount; - boolean varargs; -{ - struct pr_handle *info = (struct pr_handle *) p; - unsigned int len; - char *domain_type; - char **arg_types; - char *s; - - len = 10; - - if (! domain) - domain_type = NULL; - else - { - if (! substitute_type (info, "")) - return false; - domain_type = pop_type (info); - if (domain_type == NULL) - return false; - if (strncmp (domain_type, "class ", sizeof "class " - 1) == 0 - && strchr (domain_type + sizeof "class " - 1, ' ') == NULL) - domain_type += sizeof "class " - 1; - else if (strncmp (domain_type, "union class ", - sizeof "union class ") == 0 - && (strchr (domain_type + sizeof "union class " - 1, ' ') - == NULL)) - domain_type += sizeof "union class " - 1; - len += strlen (domain_type); - } - - if (argcount <= 0) - { - arg_types = NULL; - len += 15; - } - else - { - int i; - - arg_types = (char **) xmalloc (argcount * sizeof *arg_types); - for (i = argcount - 1; i >= 0; i--) - { - if (! substitute_type (info, "")) - return false; - arg_types[i] = pop_type (info); - if (arg_types[i] == NULL) - return false; - len += strlen (arg_types[i]) + 2; - } - if (varargs) - len += 5; - } - - /* Now the return type is on the top of the stack. */ - - s = (char *) xmalloc (len); - if (! domain) - *s = '\0'; - else - strcpy (s, domain_type); - strcat (s, "::| ("); - - if (argcount < 0) - strcat (s, "/* unknown */"); - else - { - int i; - - for (i = 0; i < argcount; i++) - { - if (i > 0) - strcat (s, ", "); - strcat (s, arg_types[i]); - } - if (varargs) - { - if (i > 0) - strcat (s, ", "); - strcat (s, "..."); - } - if (argcount > 0) - free (arg_types); - } - - strcat (s, ")"); - - if (! substitute_type (info, s)) - return false; - - free (s); - - return true; -} - -/* Make a const qualified type. */ - -static boolean -pr_const_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - - return substitute_type (info, "const |"); -} - -/* Make a volatile qualified type. */ - -static boolean -pr_volatile_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - - return substitute_type (info, "volatile |"); -} - -/* Start accumulating a struct type. */ - -static boolean -pr_start_struct_type (p, tag, id, structp, size) - PTR p; - const char *tag; - unsigned int id; - boolean structp; - unsigned int size; -{ - struct pr_handle *info = (struct pr_handle *) p; - - info->indent += 2; - - if (! push_type (info, structp ? "struct " : "union ")) - return false; - if (tag != NULL) - { - if (! append_type (info, tag)) - return false; - } - else - { - char idbuf[20]; - - sprintf (idbuf, "%%anon%u", id); - if (! append_type (info, idbuf)) - return false; - } - - if (! append_type (info, " {")) - return false; - if (size != 0 || tag != NULL) - { - char ab[30]; - - if (! append_type (info, " /*")) - return false; - - if (size != 0) - { - sprintf (ab, " size %u", size); - if (! append_type (info, ab)) - return false; - } - if (tag != NULL) - { - sprintf (ab, " id %u", id); - if (! append_type (info, ab)) - return false; - } - if (! append_type (info, " */")) - return false; - } - if (! append_type (info, "\n")) - return false; - - info->stack->visibility = DEBUG_VISIBILITY_PUBLIC; - - return indent_type (info); -} - -/* Output the visibility of a field in a struct. */ - -static boolean -pr_fix_visibility (info, visibility) - struct pr_handle *info; - enum debug_visibility visibility; -{ - const char *s; - char *t; - unsigned int len; - - assert (info->stack != NULL); - - if (info->stack->visibility == visibility) - return true; - - assert (info->stack->visibility != DEBUG_VISIBILITY_IGNORE); - - switch (visibility) - { - case DEBUG_VISIBILITY_PUBLIC: - s = "public"; - break; - case DEBUG_VISIBILITY_PRIVATE: - s = "private"; - break; - case DEBUG_VISIBILITY_PROTECTED: - s = "protected"; - break; - case DEBUG_VISIBILITY_IGNORE: - s = "/* ignore */"; - break; - default: - abort (); - return false; - } - - /* Trim off a trailing space in the struct string, to make the - output look a bit better, then stick on the visibility string. */ - - t = info->stack->type; - len = strlen (t); - assert (t[len - 1] == ' '); - t[len - 1] = '\0'; - - if (! append_type (info, s) - || ! append_type (info, ":\n") - || ! indent_type (info)) - return false; - - info->stack->visibility = visibility; - - return true; -} - -/* Add a field to a struct type. */ - -static boolean -pr_struct_field (p, name, bitpos, bitsize, visibility) - PTR p; - const char *name; - bfd_vma bitpos; - bfd_vma bitsize; - enum debug_visibility visibility; -{ - struct pr_handle *info = (struct pr_handle *) p; - char ab[20]; - char *t; - - if (! substitute_type (info, name)) - return false; - - if (! append_type (info, "; /* ")) - return false; - - if (bitsize != 0) - { - print_vma (bitsize, ab, true, false); - if (! append_type (info, "bitsize ") - || ! append_type (info, ab) - || ! append_type (info, ", ")) - return false; - } - - print_vma (bitpos, ab, true, false); - if (! append_type (info, "bitpos ") - || ! append_type (info, ab) - || ! append_type (info, " */\n") - || ! indent_type (info)) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - - if (! pr_fix_visibility (info, visibility)) - return false; - - return append_type (info, t); -} - -/* Finish a struct type. */ - -static boolean -pr_end_struct_type (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *s; - - assert (info->stack != NULL); - assert (info->indent >= 2); - - info->indent -= 2; - - /* Change the trailing indentation to have a close brace. */ - s = info->stack->type + strlen (info->stack->type) - 2; - assert (s[0] == ' ' && s[1] == ' ' && s[2] == '\0'); - - *s++ = '}'; - *s = '\0'; - - return true; -} - -/* Start a class type. */ - -static boolean -pr_start_class_type (p, tag, id, structp, size, vptr, ownvptr) - PTR p; - const char *tag; - unsigned int id; - boolean structp; - unsigned int size; - boolean vptr; - boolean ownvptr; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *tv = NULL; - - info->indent += 2; - - if (vptr && ! ownvptr) - { - tv = pop_type (info); - if (tv == NULL) - return false; - } - - if (! push_type (info, structp ? "class " : "union class ")) - return false; - if (tag != NULL) - { - if (! append_type (info, tag)) - return false; - } - else - { - char idbuf[20]; - - sprintf (idbuf, "%%anon%u", id); - if (! append_type (info, idbuf)) - return false; - } - - if (! append_type (info, " {")) - return false; - if (size != 0 || vptr || ownvptr || tag != NULL) - { - if (! append_type (info, " /*")) - return false; - - if (size != 0) - { - char ab[20]; - - sprintf (ab, "%u", size); - if (! append_type (info, " size ") - || ! append_type (info, ab)) - return false; - } - - if (vptr) - { - if (! append_type (info, " vtable ")) - return false; - if (ownvptr) - { - if (! append_type (info, "self ")) - return false; - } - else - { - if (! append_type (info, tv) - || ! append_type (info, " ")) - return false; - } - } - - if (tag != NULL) - { - char ab[30]; - - sprintf (ab, " id %u", id); - if (! append_type (info, ab)) - return false; - } - - if (! append_type (info, " */")) - return false; - } - - info->stack->visibility = DEBUG_VISIBILITY_PRIVATE; - - return (append_type (info, "\n") - && indent_type (info)); -} - -/* Add a static member to a class. */ - -static boolean -pr_class_static_member (p, name, physname, visibility) - PTR p; - const char *name; - const char *physname; - enum debug_visibility visibility; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *t; - - if (! substitute_type (info, name)) - return false; - - if (! prepend_type (info, "static ") - || ! append_type (info, "; /* ") - || ! append_type (info, physname) - || ! append_type (info, " */\n") - || ! indent_type (info)) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - - if (! pr_fix_visibility (info, visibility)) - return false; - - return append_type (info, t); -} - -/* Add a base class to a class. */ - -static boolean -pr_class_baseclass (p, bitpos, virtual, visibility) - PTR p; - bfd_vma bitpos; - boolean virtual; - enum debug_visibility visibility; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *t; - const char *prefix; - char ab[20]; - char *s, *l, *n; - - assert (info->stack != NULL && info->stack->next != NULL); - - if (! substitute_type (info, "")) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - - if (strncmp (t, "class ", sizeof "class " - 1) == 0) - t += sizeof "class " - 1; - - /* Push it back on to take advantage of the prepend_type and - append_type routines. */ - if (! push_type (info, t)) - return false; - - if (virtual) - { - if (! prepend_type (info, "virtual ")) - return false; - } - - switch (visibility) - { - case DEBUG_VISIBILITY_PUBLIC: - prefix = "public "; - break; - case DEBUG_VISIBILITY_PROTECTED: - prefix = "protected "; - break; - case DEBUG_VISIBILITY_PRIVATE: - prefix = "private "; - break; - default: - prefix = "/* unknown visibility */ "; - break; - } - - if (! prepend_type (info, prefix)) - return false; - - if (bitpos != 0) - { - print_vma (bitpos, ab, true, false); - if (! append_type (info, " /* bitpos ") - || ! append_type (info, ab) - || ! append_type (info, " */")) - return false; - } - - /* Now the top of the stack is something like "public A / * bitpos - 10 * /". The next element on the stack is something like "class - xx { / * size 8 * /\n...". We want to substitute the top of the - stack in before the {. */ - s = strchr (info->stack->next->type, '{'); - assert (s != NULL); - --s; - - /* If there is already a ':', then we already have a baseclass, and - we must append this one after a comma. */ - for (l = info->stack->next->type; l != s; l++) - if (*l == ':') - break; - if (! prepend_type (info, l == s ? " : " : ", ")) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - - n = (char *) xmalloc (strlen (info->stack->type) + strlen (t) + 1); - memcpy (n, info->stack->type, s - info->stack->type); - strcpy (n + (s - info->stack->type), t); - strcat (n, s); - - free (info->stack->type); - info->stack->type = n; - - free (t); - - return true; -} - -/* Start adding a method to a class. */ - -static boolean -pr_class_start_method (p, name) - PTR p; - const char *name; -{ - struct pr_handle *info = (struct pr_handle *) p; - - assert (info->stack != NULL); - info->stack->method = name; - return true; -} - -/* Add a variant to a method. */ - -static boolean -pr_class_method_variant (p, physname, visibility, constp, volatilep, voffset, - context) - PTR p; - const char *physname; - enum debug_visibility visibility; - boolean constp; - boolean volatilep; - bfd_vma voffset; - boolean context; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *method_type; - char *context_type; - - assert (info->stack != NULL); - assert (info->stack->next != NULL); - - /* Put the const and volatile qualifiers on the type. */ - if (volatilep) - { - if (! append_type (info, " volatile")) - return false; - } - if (constp) - { - if (! append_type (info, " const")) - return false; - } - - /* Stick the name of the method into its type. */ - if (! substitute_type (info, - (context - ? info->stack->next->next->method - : info->stack->next->method))) - return false; - - /* Get the type. */ - method_type = pop_type (info); - if (method_type == NULL) - return false; - - /* Pull off the context type if there is one. */ - if (! context) - context_type = NULL; - else - { - context_type = pop_type (info); - if (context_type == NULL) - return false; - } - - /* Now the top of the stack is the class. */ - - if (! pr_fix_visibility (info, visibility)) - return false; - - if (! append_type (info, method_type) - || ! append_type (info, " /* ") - || ! append_type (info, physname) - || ! append_type (info, " ")) - return false; - if (context || voffset != 0) - { - char ab[20]; - - if (context) - { - if (! append_type (info, "context ") - || ! append_type (info, context_type) - || ! append_type (info, " ")) - return false; - } - print_vma (voffset, ab, true, false); - if (! append_type (info, "voffset ") - || ! append_type (info, ab)) - return false; - } - - return (append_type (info, " */;\n") - && indent_type (info)); -} - -/* Add a static variant to a method. */ - -static boolean -pr_class_static_method_variant (p, physname, visibility, constp, volatilep) - PTR p; - const char *physname; - enum debug_visibility visibility; - boolean constp; - boolean volatilep; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *method_type; - - assert (info->stack != NULL); - assert (info->stack->next != NULL); - assert (info->stack->next->method != NULL); - - /* Put the const and volatile qualifiers on the type. */ - if (volatilep) - { - if (! append_type (info, " volatile")) - return false; - } - if (constp) - { - if (! append_type (info, " const")) - return false; - } - - /* Mark it as static. */ - if (! prepend_type (info, "static ")) - return false; - - /* Stick the name of the method into its type. */ - if (! substitute_type (info, info->stack->next->method)) - return false; - - /* Get the type. */ - method_type = pop_type (info); - if (method_type == NULL) - return false; - - /* Now the top of the stack is the class. */ - - if (! pr_fix_visibility (info, visibility)) - return false; - - return (append_type (info, method_type) - && append_type (info, " /* ") - && append_type (info, physname) - && append_type (info, " */;\n") - && indent_type (info)); -} - -/* Finish up a method. */ - -static boolean -pr_class_end_method (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - - info->stack->method = NULL; - return true; -} - -/* Finish up a class. */ - -static boolean -pr_end_class_type (p) - PTR p; -{ - return pr_end_struct_type (p); -} - -/* Push a type on the stack using a typedef name. */ - -static boolean -pr_typedef_type (p, name) - PTR p; - const char *name; -{ - struct pr_handle *info = (struct pr_handle *) p; - - return push_type (info, name); -} - -/* Push a type on the stack using a tag name. */ - -static boolean -pr_tag_type (p, name, id, kind) - PTR p; - const char *name; - unsigned int id; - enum debug_type_kind kind; -{ - struct pr_handle *info = (struct pr_handle *) p; - const char *t, *tag; - char idbuf[30]; - - switch (kind) - { - case DEBUG_KIND_STRUCT: - t = "struct "; - break; - case DEBUG_KIND_UNION: - t = "union "; - break; - case DEBUG_KIND_ENUM: - t = "enum "; - break; - case DEBUG_KIND_CLASS: - t = "class "; - break; - case DEBUG_KIND_UNION_CLASS: - t = "union class "; - break; - default: - abort (); - return false; - } - - if (! push_type (info, t)) - return false; - if (name != NULL) - tag = name; - else - { - sprintf (idbuf, "%%anon%u", id); - tag = idbuf; - } - - if (! append_type (info, tag)) - return false; - if (name != NULL && kind != DEBUG_KIND_ENUM) - { - sprintf (idbuf, " /* id %u */", id); - if (! append_type (info, idbuf)) - return false; - } - - return true; -} - -/* Output a typedef. */ - -static boolean -pr_typdef (p, name) - PTR p; - const char *name; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *s; - - if (! substitute_type (info, name)) - return false; - - s = pop_type (info); - if (s == NULL) - return false; -/* - indent (info); - TRACE_FPRINTF( (info->f, "typedef %s;\n", s)); -*/ - free (s); - - return true; -} - -/* Output a tag. The tag should already be in the string on the - stack, so all we have to do here is print it out. */ - -/*ARGSUSED*/ -static boolean -pr_tag (p, name) - PTR p; - const char *name; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *t; - - t = pop_type (info); - if (t == NULL) - return false; -/* - indent (info); - TRACE_FPRINTF( (info->f, "%s;\n", t)); -*/ - free (t); - - return true; -} - -/* Output an integer constant. */ - -static boolean -pr_int_constant (p, name, val) - PTR p; - const char *name; - bfd_vma val; -{ -/* - struct pr_handle *info = (struct pr_handle *) p; - char ab[20]; - indent (info); - print_vma (val, ab, false, false); - TRACE_FPRINTF( (info->f, "const int %s = %s;\n", name, ab)); - */ - return true; -} - -/* Output a floating point constant. */ - -static boolean -pr_float_constant (p, name, val) - PTR p; - const char *name; - double val; -{ -/* - struct pr_handle *info = (struct pr_handle *) p; - indent (info); - TRACE_FPRINTF( (info->f, "const double %s = %g;\n", name, val)); - */ - return true; -} - -/* Output a typed constant. */ - -static boolean -pr_typed_constant (p, name, val) - PTR p; - const char *name; - bfd_vma val; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *t; - - t = pop_type (info); - if (t == NULL) - return false; -/* - char ab[20]; - indent (info); - print_vma (val, ab, false, false); - TRACE_FPRINTF( (info->f, "const %s %s = %s;\n", t, name, ab)); -*/ - free (t); - - return true; -} - -/* Output a variable. */ - -static boolean -pr_variable (p, name, kind, val) - PTR p; - const char *name; - enum debug_var_kind kind; - bfd_vma val; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *t; - char ab[20]; - (void)ab; - - if (! substitute_type (info, name)) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - -#if 0 - indent (info); - switch (kind) - { - case DEBUG_STATIC: - case DEBUG_LOCAL_STATIC: - TRACE_FPRINTF( (info->f, "static ")); - break; - case DEBUG_REGISTER: - TRACE_FPRINTF( (info->f, "register ")); - break; - default: - break; - } - print_vma (val, ab, true, true); - TRACE_FPRINTF( (info->f, "%s /* %s */;\n", t, ab)); -#else /* 0 */ -#if 0 - if (kind==DEBUG_STATIC || kind==DEBUG_LOCAL_STATIC) { - print_vma (val, ab, true, true); - TRACE_FPRINTF( (info->f, "STATIC_VAR: %s /* %s */;\n", t, ab)); - } -#endif /* 0 */ -#endif /* !0 */ - - free (t); - - return true; -} - -/* Start outputting a function. */ - -static boolean -pr_start_function (p, name, global) - PTR p; - const char *name; - boolean global; -{ - struct pr_handle *info = (struct pr_handle *) p; - char *t; - - if (! substitute_type (info, name)) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - -#if 0 - indent (info); - if (! global) - TRACE_FPRINTF( (info->f, "static ")); - TRACE_FPRINTF( (info->f, "%s (", t)); - info->parameter = 1; -#else /* 0 */ - if (info->functions_size==info->functions_maxsize) { - info->functions_maxsize *= 2; - info->functions = xrealloc(info->functions, - info->functions_maxsize*sizeof(debug_function_t)); - assert(info->functions!=0); - } - /* info->functions[info->functions_size] = xmalloc(sizeof(debug_function_t)); */ - info->function = &info->functions[info->functions_size]; - ++info->functions_size; - info->function->symbol = NULL; - info->function->lines = NULL; - info->function->lines_count = 0; - info->function->max_lines_count = 0; - info->function->name = t; - info->function->filename = NULL; - info->function->block = NULL; - info->function->argv = NULL; - info->function->argc = 0; - info->function->max_argc = 0; -#endif /* !0 */ - return true; -} - -/* Output a function parameter. */ - -static boolean -pr_function_parameter (p, name, kind, val) - PTR p; - const char *name; - enum debug_parm_kind kind; - bfd_vma val; -{ - struct pr_handle *info = (struct pr_handle *) p; - debug_function_t* f = info->function; - char *t; - char ab[20]; - (void)ab; - - if (kind == DEBUG_PARM_REFERENCE - || kind == DEBUG_PARM_REF_REG) - { - if (! pr_reference_type (p)) - return false; - } - - if (! substitute_type (info, name)) - return false; - - t = pop_type (info); - if (t == NULL) - return false; - -#if 0 - if (info->parameter != 1) - TRACE_FPRINTF( (info->f, ", ")); - - if (kind == DEBUG_PARM_REG || kind == DEBUG_PARM_REF_REG) - TRACE_FPRINTF( (info->f, "register ")); - - print_vma (val, ab, true, true); - TRACE_FPRINTF( (info->f, "%s /* %s */", t, ab)); - free (t); - ++info->parameter; -#else /* 0 */ - assert(f!=NULL); - if (f->argv==NULL) { - f->max_argc = 7; /* rarely anyone has more than that many args... */ - f->argv = xmalloc(sizeof(debug_parameter_t)*f->max_argc); - } else if (f->argc==f->max_argc) { - f->max_argc *= 2; - f->argv = realloc(f->argv,sizeof(debug_parameter_t)*f->max_argc); - } - f->argv[f->argc].offset = val; - f->argv[f->argc].name = t; - ++f->argc; -#endif /* !0 */ - return true; -} - -/* Start writing out a block. */ - -static boolean -pr_start_block (p, addr) - PTR p; - bfd_vma addr; -{ - struct pr_handle *info = (struct pr_handle *) p; - char ab[20]; - debug_block_t* block = 0; - (void)ab; -#if 0 - if (info->parameter > 0) - { - TRACE_FPRINTF( (info->f, ")\n")); - info->parameter = 0; - } - indent (info); - print_vma (addr, ab, true, true); - TRACE_FPRINTF( (info->f, "{ /* %s */\n", ab)); - info->indent += 2; -#else - if (info->block) { - if (info->block->childs_count==0) - info->block->childs = xmalloc(sizeof(debug_block_t)); - else - info->block->childs = xrealloc(info->block->childs, - info->block->childs_count*sizeof(debug_block_t)); - block = &info->block->childs[info->block->childs_count]; - } else { - block = xmalloc(sizeof(debug_block_t)); - info->function->block = block; - } - block->begin_addr = addr; - block->end_addr = 0; - block->parent = info->block; - block->childs = NULL; - block->childs_count = 0; - info->block = block; -#endif - return true; -} - -/* Write out line number information. */ - -static boolean -pr_lineno (p, filename, lineno, addr) - PTR p; - const char *filename; - unsigned long lineno; - bfd_vma addr; -{ - struct pr_handle *info = (struct pr_handle *) p; - char ab[20]; - debug_function_t* f = info->function; - (void)ab; - -#if 0 - indent (info); - print_vma (addr, ab, true, true); - TRACE_FPRINTF( (info->f, "/* file %s line %lu addr %s */\n", filename, lineno, ab)); -#else /* 0 */ - if (f==NULL) /* FIXME: skips junk silently. */ - return true; - /* assert(f!=NULL); */ - if (f->filename==NULL) { - f->filename = filename; - assert(f->lines==0); - f->max_lines_count = 4; - f->lines = xmalloc(sizeof(debug_lineno_t)*f->max_lines_count); - } - if (f->lines_count==f->max_lines_count) { - f->max_lines_count *= 2; - f->lines = xrealloc(f->lines, sizeof(debug_lineno_t)*f->max_lines_count); - } - f->lines[f->lines_count].lineno = lineno; - f->lines[f->lines_count].addr = addr; - ++f->lines_count; -#endif /* !0 */ - - return true; -} - -/* Finish writing out a block. */ - -static boolean -pr_end_block (p, addr) - PTR p; - bfd_vma addr; -{ - struct pr_handle *info = (struct pr_handle *) p; - -#if 0 - char ab[20]; - - info->indent -= 2; - indent (info); - print_vma (addr, ab, true, true); - TRACE_FPRINTF( (info->f, "} /* %s */\n", ab)); -#else /* 0 */ - assert(info->block!=0); - info->block->end_addr = addr; - info->block = info->block->parent; -#endif /* !0 */ - - return true; -} - -/* Finish writing out a function. */ - -/*ARGSUSED*/ -static boolean -pr_end_function (p) - PTR p; -{ - struct pr_handle *info = (struct pr_handle *) p; - assert(info->block==0); - info->function = NULL; - return true; -} - -/* third parameter to segv_action. */ -/* Got it after a bit of head scratching and stack dumping. */ -typedef struct { - u_int32_t foo1; /* +0x00 */ - u_int32_t foo2; - u_int32_t foo3; - u_int32_t foo4; /* usually 2 */ - u_int32_t foo5; /* +0x10 */ - u_int32_t xgs; /* always zero */ - u_int32_t xfs; /* always zero */ - u_int32_t xes; /* always es=ds=ss */ - u_int32_t xds; /* +0x20 */ - u_int32_t edi; - u_int32_t esi; - u_int32_t ebp; - u_int32_t esp; /* +0x30 */ - u_int32_t ebx; - u_int32_t edx; - u_int32_t ecx; - u_int32_t eax; /* +0x40 */ - u_int32_t foo11; /* usually 0xe */ - u_int32_t foo12; /* usually 0x6 */ - u_int32_t eip; /* instruction pointer */ - u_int32_t xcs; /* +0x50 */ - u_int32_t foo21; /* usually 0x2 */ - u_int32_t foo22; /* second stack pointer?! Probably. */ - u_int32_t xss; - u_int32_t foo31; /* +0x60 */ /* usually 0x0 */ - u_int32_t foo32; /* usually 0x2 */ - u_int32_t fault_addr; /* Address which caused a fault */ - u_int32_t foo41; /* usually 0x2 */ -} signal_regs_t; - -signal_regs_t* ptrace_regs = 0; /* Tells my_ptrace to "ptrace" current process" */ -/* - * my_ptrace: small wrapper around ptrace. - * Act as normal ptrace if ptrace_regs==0. - * Read data from current process if ptrace_regs!=0. - */ -static int -my_ptrace( int request, - int pid, - int addr, - int data) -{ - if (ptrace_regs==0) - return ptrace(request, pid, addr, data); - /* we are tracing ourselves! */ - switch (request) { - case PTRACE_ATTACH: return 0; - case PTRACE_CONT: return 0; - case PTRACE_DETACH: return 0; - case PTRACE_PEEKUSER: - switch (addr / 4) { - case EIP: return ptrace_regs->eip; - case EBP: return ptrace_regs->ebp; - default: assert(0); - } - case PTRACE_PEEKTEXT: /* FALLTHROUGH */ - case PTRACE_PEEKDATA: return *(int*)(addr); - default: assert(0); - } - errno = 1; /* what to do here? */ - return 1; /* failed?! */ -} - -#define MAXARGS 6 - -/* - * To minimize the number of parameters. - */ -typedef struct { - asymbol** syms; /* Sorted! */ - int symcount; - debug_function_t** functions; - int functions_size; -} symbol_data_t; - -/* - * Perform a search. A binary search for a symbol. - */ -static void -decode_symbol( symbol_data_t* symbol_data, - const unsigned long addr, - char* buf, - const int bufsize) -{ - asymbol** syms = symbol_data->syms; - const int symcount = symbol_data->symcount; - int bottom = 0; - int top = symcount - 1; - int i; - if (symcount==0) { - sprintf(buf, "????"); - return; - } - while (top>bottom+1) { - i = (top+bottom) / 2; - if (bfd_asymbol_value(syms[i])==addr) { - sprintf(buf, "%s", syms[i]->name); - return; - } else if (bfd_asymbol_value(syms[i]) > addr) - top = i; - else - bottom = i; - } - i = bottom; - if (addr(syms[i]->section->vma+syms[i]->section->_cooked_size)) - sprintf(buf, "????"); - else - sprintf(buf, "%s + 0x%lx", syms[i]->name, addr-bfd_asymbol_value(syms[i])); -} - -/* - * 1. Perform a binary search for an debug_function_t. - * 2. Fill buf/bufsize with name, parameters and lineno, if found - * Or with '????' otherwise. - */ -static debug_function_t* -find_debug_function_t( symbol_data_t* symbol_data, - const pid_t pid, - const unsigned long fp, /* frame pointer */ - const unsigned long addr, - char* buf, /* string buffer */ - const int bufsize)/* FIXME: not used! */ -{ - debug_function_t** syms = symbol_data->functions; - debug_function_t* f = NULL; - debug_block_t* block = NULL; - debug_lineno_t* lineno = NULL; - const int symcount = symbol_data->functions_size; - int bottom = 0; - int top = symcount - 1; - int i; - char* bufptr = buf; - - if (symcount==0) { - sprintf(buf, "????"); - return NULL; - } - while (top>bottom+1) { - i = (top+bottom) / 2; - if (syms[i]->block->begin_addr==addr) { - f = syms[i]; - break; - } else if (syms[i]->block->begin_addr > addr) - top = i; - else - if (syms[i]->block->end_addr >= addr) { - f = syms[i]; - break; - } else - bottom = i; - } - i = bottom; - if (f!=0) - block = f->block; - else { - block = syms[i]->block; - if (block->begin_addr>=addr && block->end_addr<=addr) - f = syms[i]; - } - if (f==0) - sprintf(buf, "????"); - else { - /* - * Do the backtrace the GDB way... - */ - unsigned long arg; - /* assert(f->lines_count>0); */ - if (f->lines_count>0) { - lineno = &f->lines[f->lines_count-1]; - for (i=1; ilines_count; ++i) - if (f->lines[i].addr>addr) { - lineno = &f->lines[i-1]; - break; - } - } - bufptr[0] = 0; - bufptr += sprintf(bufptr, "%s+0x%lx (", f->name, addr-block->begin_addr); - for (i=0; iargc; ++i) { - bufptr += sprintf(bufptr, "%s = ", f->argv[i].name); - /* FIXME: better parameter printing */ - errno = 0; - arg = my_ptrace(PTRACE_PEEKDATA, pid, fp+f->argv[i].offset, 0); - assert(errno==0); - bufptr += sprintf(bufptr, "0x%x", arg); - if (i!=f->argc-1) - bufptr += sprintf(bufptr, ", "); - } - if (lineno!=0) - bufptr += sprintf(bufptr, ") at %s:%d", f->filename, lineno->lineno); - } - return f; -} - -/* - * Advance through the stacks and display frames as needed. - */ -static int -my_crawl( int pid, - symbol_data_t* symbol_data, - int fout) -{ - unsigned long pc = 0; - unsigned long fp = 0; - unsigned long nextfp; - unsigned long nargs; - unsigned long i; - unsigned long arg; - char buf[8096]; // FIXME: enough? - debug_function_t* f = 0; - - errno = 0; - - pc = my_ptrace(PTRACE_PEEKUSER, pid, EIP * 4, 0); - if (!errno) - fp = my_ptrace(PTRACE_PEEKUSER, pid, EBP * 4, 0); - - if (!errno) { -#if 1 - f = find_debug_function_t(symbol_data, pid, fp, pc, buf, sizeof(buf)); - fdprintf(fout,"0x%08lx: %s", pc, buf); - for ( ; !errno && fp; ) { - nextfp = my_ptrace(PTRACE_PEEKDATA, pid, fp, 0); - if (errno) - break; - - if (f==0) { - nargs = (nextfp - fp - 8) / 4; - if (nargs > MAXARGS) - nargs = MAXARGS; - if (nargs > 0) { - fdputs(" (", fout); - for (i = 1; i <= nargs; i++) { - arg = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4 * (i + 1), 0); - if (errno) - break; - fdprintf(fout,"%lx", arg); - if (i < nargs) - fdputs(", ", fout); - } - fdputc(')', fout); - nargs = nextfp - fp - 8 - (4 * nargs); - if (!errno && nargs > 0) - fdprintf(fout," + %lx\n", nargs); - else - fdputc('\n', fout); - } else - fdputc('\n', fout); - } else - fdputc('\n', fout); - - if (errno || !nextfp) - break; - pc = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4, 0); - fp = nextfp; - if (errno) - break; - f = find_debug_function_t(symbol_data, pid, fp, pc, buf, sizeof(buf)); - fdprintf(fout,"0x%08lx: %s", pc, buf); - } -#else /* 1 */ - decode_symbol(symbol_data, pc, buf, sizeof(buf)); - fdprintf(fout,"0x%08lx: %s", pc, buf); - for ( ; !errno && fp; ) { - nextfp = my_ptrace(PTRACE_PEEKDATA, pid, fp, 0); - if (errno) - break; - - nargs = (nextfp - fp - 8) / 4; - if (nargs > MAXARGS) - nargs = MAXARGS; - if (nargs > 0) { - fputs(" (", fout); - for (i = 1; i <= nargs; i++) { - arg = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4 * (i + 1), 0); - if (errno) - break; - fdprintf(fout,"%lx", arg); - if (i < nargs) - fputs(", ", fout); - } - fdputc(')', fout); - nargs = nextfp - fp - 8 - (4 * nargs); - if (!errno && nargs > 0) - fdprintf(fout," + %lx\n", nargs); - else - fdputc('\n', fout); - } else - fdputc('\n', fout); - - if (errno || !nextfp) - break; - pc = my_ptrace(PTRACE_PEEKDATA, pid, fp + 4, 0); - fp = nextfp; - if (errno) - break; - decode_symbol(symbol_data, pc, buf, sizeof(buf)); - fdprintf(fout,"0x%08lx: %s", pc, buf); - } -#endif /* !1 */ - } - if (errno) - perror("my_crawl"); - return errno; -} - -/* layout from /usr/src/linux/arch/i386/kernel/process.c */ -static void -show_regs( signal_regs_t* regs, - int fd) -{ - /* long cr0 = 0L, cr2 = 0L, cr3 = 0L; */ - - fdprintf(fd,"\n"); - fdprintf(fd,"FAULT ADDR: %08x\n", regs->fault_addr); - fdprintf(fd,"EIP: %04x:[<%08x>]",0xffff & regs->xcs,regs->eip); - if (regs->xcs & 3) - fdprintf(fd," ESP: %04x:%08x",0xffff & regs->xss,regs->esp); - /*fdprintf(fd," EFLAGS: %08lx\n",regs->eflags); */ - fdprintf(fd, "\n"); - fdprintf(fd,"EAX: %08x EBX: %08x ECX: %08x EDX: %08x\n", - regs->eax,regs->ebx,regs->ecx,regs->edx); - fdprintf(fd,"ESI: %08x EDI: %08x EBP: %08x", - regs->esi, regs->edi, regs->ebp); - fdprintf(fd," DS: %04x ES: %04x\n", - 0xffff & regs->xds,0xffff & regs->xes); - /* - __asm__("movl %%cr0, %0": "=r" (cr0)); - __asm__("movl %%cr2, %0": "=r" (cr2)); - __asm__("movl %%cr3, %0": "=r" (cr3)); - fprintf(stderr,"CR0: %08lx CR2: %08lx CR3: %08lx\n", cr0, cr2, cr3); */ -} - -/* - * Load a BFD for an executable based on PID. Return 0 on failure. - */ -static bfd* -load_bfd( const int pid) -{ - char filename[512]; - bfd* abfd = 0; - - /* Get the contents from procfs. */ -#if 1 - sprintf(filename, "/proc/%d/exe", pid); -#else - sprintf(filename, "crashing"); -#endif - - if ((abfd = bfd_openr (filename, 0))== NULL) - bfd_nonfatal (filename); - else { - char** matching; - assert(bfd_check_format(abfd, bfd_archive)!=true); - - /* - * There is no indication in BFD documentation that it should be done. - * God knows why... - */ - if (!bfd_check_format_matches (abfd, bfd_object, &matching)) { - bfd_nonfatal (bfd_get_filename (abfd)); - if (bfd_get_error () == bfd_error_file_ambiguously_recognized) { - list_matching_formats (matching); - free (matching); - } - } - } - return abfd; -} - -/* - * Those are for qsort. We need only function addresses, so all the others don't count. - */ -/* - * Compare two BFD::asymbol-s. - */ -static int -compare_symbols(const void* ap, - const void* bp) -{ - const asymbol *a = *(const asymbol **)ap; - const asymbol *b = *(const asymbol **)bp; - if (bfd_asymbol_value (a) > bfd_asymbol_value (b)) - return 1; - else if (bfd_asymbol_value (a) < bfd_asymbol_value (b)) - return -1; - return 0; -} - -/* - * Compare two debug_asymbol_t-s. - */ -static int -compare_debug_function_t(const void* ap, - const void* bp) -{ - const debug_function_t *a = *(const debug_function_t **)ap; - const debug_function_t *b = *(const debug_function_t **)bp; - assert(a->block!=0); - assert(b->block!=0); - { - const bfd_vma addr1 = a->block->begin_addr; - const bfd_vma addr2 = b->block->begin_addr; - if (addr1 > addr2) - return 1; - else if (addr2 > addr1) - return -1; - } - return 0; -} - -/* - * Filter out (in place) symbols that are useless for stack tracing. - * COUNT is the number of elements in SYMBOLS. - * Return the number of useful symbols. - */ - -static long -remove_useless_symbols( asymbol** symbols, - long count) -{ - asymbol** in_ptr = symbols; - asymbol** out_ptr = symbols; - - while (--count >= 0) { - asymbol *sym = *in_ptr++; - - if (sym->name == NULL || sym->name[0] == '\0' || sym->value==0) - continue; - if (sym->flags & (BSF_DEBUGGING)) - continue; - if (bfd_is_und_section (sym->section) || bfd_is_com_section (sym->section)) - continue; - *out_ptr++ = sym; - } - return out_ptr - symbols; -} - -/* - * Debugging information. - */ -static bfd* abfd = 0; -static PTR dhandle = 0; -static asymbol** syms = 0; -static long symcount = 0; -static asymbol** sorted_syms = 0; -static long sorted_symcount = 0; -static debug_function_t** functions = 0; -static int functions_size = 0; -static int sigreport = SIGUSR1; -static pthread_t segv_tid; /* What thread did SEGV? */ -static pid_t segv_pid; - -/* - * We'll get here after a SIGSEGV. But you can install it on other signals, too :) - * Because we are in the middle of the SIGSEGV, we are on our own. We can't do - * any malloc(), any fopen(), nothing. The last is actually a sin. We event can't - * fprintf(stderr,...)!!! - */ -static void -segv_action(int signo, siginfo_t* siginfo, void* ptr) -{ - symbol_data_t symbol_data; - int fd = -1; - - segv_pid = getpid(); - segv_tid = pthread_self(); - fd = open_log_file(segv_tid, segv_pid); - /* signal(SIGSEGV, SIG_DFL); */ - ptrace_regs = (signal_regs_t*)ptr; - assert(ptrace_regs!=0); - - /* Show user how guilty we are. */ - fdprintf(fd,"--------- SEGV in PROCESS %d, THREAD %d ---------------\n", segv_pid, pthread_self()); - show_regs(ptrace_regs, fd); - - /* Some form of stack trace, too. */ - fdprintf(fd, "STACK TRACE:\n"); - - symbol_data.syms = sorted_syms; - symbol_data.symcount = sorted_symcount; - symbol_data.functions = functions; - symbol_data.functions_size = functions_size; - my_crawl(segv_pid, &symbol_data, fd); - //fflush(stdout); - close(fd); - linuxthreads_notify_others(sigreport); -} - - -static void -report_action(int signo, siginfo_t* siginfo, void* ptr) -{ - const int pid = getpid(); - pthread_t tid = pthread_self(); - symbol_data_t symbol_data; - int fd; - if (pthread_equal(tid, segv_tid)) { - /* We have already printed our stack trace... */ - return; - } - - fd = open_log_file(tid, pid); - fdprintf(fd, "REPORT: CURRENT PROCESS:%d, THREAD:%d\n", getpid(), pthread_self()); - /* signal(SIGSEGV, SIG_DFL); */ - ptrace_regs = (signal_regs_t*)ptr; - assert(ptrace_regs!=0); - - /* Show user how guilty we are. */ - fdprintf(fd,"--------- STACK TRACE FOR PROCESS %d, THREAD %d ---------------\n", pid, pthread_self()); - show_regs(ptrace_regs, fd); - - /* Some form of stack trace, too. */ - fdprintf(fd, "STACK TRACE:\n"); - - symbol_data.syms = sorted_syms; - symbol_data.symcount = sorted_symcount; - symbol_data.functions = functions; - symbol_data.functions_size = functions_size; - my_crawl(pid, &symbol_data, fd); - //fflush(stdout); - close(fd); - /* Tell segv_thread to proceed after pause(). */ - /*pthread_kill(segv_tid, sigreport); - kill(segv_pid, sigreport); - pthread_cancel(tid); */ -} - -/* - * Main library routine. Just call it on your program. - */ -int -pstack_install_segv_action( const char* path_format_) -{ - const int pid = getpid(); - struct sigaction act; - - /* Store what we have to for later usage. */ - path_format = path_format_; - - /* We need a signal action for SIGSEGV and sigreport ! */ - sigreport = SIGUSR1; - act.sa_handler = 0; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO|SA_ONESHOT; /* Just one SIGSEGV. */ - act.sa_sigaction = segv_action; - act.sa_restorer = NULL; - if (sigaction(SIGSEGV, &act, NULL)!=0) { - perror("sigaction"); - return 1; - } - act.sa_sigaction = report_action; - act.sa_flags = SA_SIGINFO; /* But many sigreports. */ - if (sigaction(sigreport, &act, NULL)!=0) { - perror("sigaction"); - return 1; - } - - /* And a little setup for libiberty. */ - program_name = "crashing"; - xmalloc_set_program_name (program_name); - - /* Umm, and initialize BFD, too */ - bfd_init(); -#if 0 - list_supported_targets(0, stdout); - set_default_bfd_target(); -#endif /* 0 */ - - if ((abfd = load_bfd(pid))==0) - fprintf(stderr, "BFD load failed..\n"); - else { - long storage_needed= (bfd_get_file_flags(abfd) & HAS_SYMS) ? - bfd_get_symtab_upper_bound (abfd) : 0; - long i; - (void)i; - - if (storage_needed < 0) - fprintf(stderr, "Symbol table size estimation failure.\n"); - else if (storage_needed > 0) { - syms = (asymbol **) xmalloc (storage_needed); - symcount = bfd_canonicalize_symtab (abfd, syms); - - TRACE_FPRINTF((stderr, "TOTAL: %ld SYMBOLS.\n", symcount)); - /* We need debugging info, too! */ - if (symcount==0 || (dhandle = read_debugging_info (abfd, syms, symcount))==0) - fprintf(stderr, "NO DEBUGGING INFORMATION FOUND.\n"); - - /* We make a copy of syms to sort. We don't want to sort syms - because that will screw up the relocs. */ - sorted_syms = (asymbol **) xmalloc (symcount * sizeof (asymbol *)); - memcpy (sorted_syms, syms, symcount * sizeof (asymbol *)); - -#if 0 - for (i=0; iname!=0 && strlen(syms[i]->name)>0 && syms[i]->value!=0) - printf("%08lx T %s\n", syms[i]->section->vma + syms[i]->value, syms[i]->name); -#endif - sorted_symcount = remove_useless_symbols (sorted_syms, symcount); - TRACE_FPRINTF((stderr, "SORTED: %ld SYMBOLS.\n", sorted_symcount)); - - /* Sort the symbols into section and symbol order */ - qsort (sorted_syms, sorted_symcount, sizeof (asymbol *), compare_symbols); -#if 0 - for (i=0; iname!=0 && strlen(sorted_syms[i]->name)>0 && sorted_syms[i]->value!=0) - printf("%08lx T %s\n", sorted_syms[i]->section->vma + sorted_syms[i]->value, sorted_syms[i]->name); -#endif - /* We have symbols, we need debugging info somehow sorted out. */ - if (dhandle==0) { - fprintf(stderr, "STACK TRACE WILL BE UNCOMFORTABLE.\n"); - } else { - /* Start collecting the debugging information.... */ - struct pr_handle info; - - info.f = stdout; - info.indent = 0; - info.stack = NULL; - info.parameter = 0; - info.block = NULL; - info.function = NULL; - info.functions_size = 0; - info.functions_maxsize = 1000; - info.functions = (debug_function_t*)xmalloc(sizeof(debug_function_t)*info.functions_maxsize); - debug_write (dhandle, &pr_fns, (PTR) &info); - TRACE_FPRINTF((stdout, "\n%d DEBUG SYMBOLS\n", info.functions_size)); - assert(info.functions_size!=0); - functions = xmalloc(sizeof(debug_function_t*)*info.functions_size); - functions_size = info.functions_size; - for (i=0; ibegin_addr, info.functions[i].name); -#endif - fflush(stdout); - } - } else /* storage_needed == 0 */ - fprintf(stderr, "NO SYMBOLS FOUND.\n"); - } - return 0; -} - -/*********************************************************************/ -/*********************************************************************/ -/*********************************************************************/ diff --git a/pstack/pstack.h b/pstack/pstack.h deleted file mode 100644 index 4c4fad7e754..00000000000 --- a/pstack/pstack.h +++ /dev/null @@ -1,22 +0,0 @@ -/* $Header$ */ - -#ifndef pstack_pstack_h_ -#define pstack_pstack_h_ - -#include "pstacktrace.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Install the stack-trace-on-SEGV handler.... - */ -extern int -pstack_install_segv_action( const char* path_format); -#ifdef __cplusplus -} -#endif - -#endif /* pstack_pstack_h_ */ - diff --git a/pstack/pstacktrace.h b/pstack/pstacktrace.h deleted file mode 100644 index c884bcb9f87..00000000000 --- a/pstack/pstacktrace.h +++ /dev/null @@ -1,24 +0,0 @@ -/* $Header$ */ - -/* - * Debugging macros. - */ - -#ifndef pstacktrace_h_ -#define pstacktrace_h_ - -#define PSTACK_DEBUG 1 -#undef PSTACK_DEBUG - -#ifdef PSTACK_DEBUG -# define TRACE_PUTC(a) putc a -# define TRACE_FPUTS(a) fputs a -# define TRACE_FPRINTF(a) fprintf a -#else /* PSTACK_DEBUG */ -# define TRACE_PUTC(a) (void)0 -# define TRACE_FPUTS(a) (void)0 -# define TRACE_FPRINTF(a) (void)0 -#endif /* !PSTACK_DEBUG */ - -#endif /* pstacktrace_h_ */ - diff --git a/pstack/rddbg.c b/pstack/rddbg.c deleted file mode 100644 index be3dfc21c57..00000000000 --- a/pstack/rddbg.c +++ /dev/null @@ -1,462 +0,0 @@ -/* rddbg.c -- Read debugging information into a generic form. - Copyright (C) 1995, 96, 1997 Free Software Foundation, Inc. - Written by Ian Lance Taylor . - - This file is part of GNU Binutils. - - 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; either version 2 of the License, or - (at your option) any later version. - - 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., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ - -/* This file reads debugging information into a generic form. This - file knows how to dig the debugging information out of an object - file. */ - -#include -#include "bucomm.h" -#include -#include "debug.h" -#include "budbg.h" - -static boolean read_section_stabs_debugging_info - PARAMS ((bfd *, asymbol **, long, PTR, boolean *)); -static boolean read_symbol_stabs_debugging_info - PARAMS ((bfd *, asymbol **, long, PTR, boolean *)); -static boolean read_ieee_debugging_info PARAMS ((bfd *, PTR, boolean *)); -static void save_stab PARAMS ((int, int, bfd_vma, const char *)); -static void stab_context PARAMS ((void)); -static void free_saved_stabs PARAMS ((void)); - -/* Read debugging information from a BFD. Returns a generic debugging - pointer. */ - -PTR -read_debugging_info (abfd, syms, symcount) - bfd *abfd; - asymbol **syms; - long symcount; -{ - PTR dhandle; - boolean found; - - dhandle = debug_init (); - if (dhandle == NULL) - return NULL; - - if (! read_section_stabs_debugging_info (abfd, syms, symcount, dhandle, - &found)) - return NULL; - - if (bfd_get_flavour (abfd) == bfd_target_aout_flavour) - { - if (! read_symbol_stabs_debugging_info (abfd, syms, symcount, dhandle, - &found)) - return NULL; - } - - if (bfd_get_flavour (abfd) == bfd_target_ieee_flavour) - { - if (! read_ieee_debugging_info (abfd, dhandle, &found)) - return NULL; - } - - /* Try reading the COFF symbols if we didn't find any stabs in COFF - sections. */ - if (! found - && bfd_get_flavour (abfd) == bfd_target_coff_flavour - && symcount > 0) - { -#if 0 -/* - * JZ: Do we need coff? - */ - if (! parse_coff (abfd, syms, symcount, dhandle)) -#else - fprintf (stderr, "%s: COFF support temporarily disabled\n", - bfd_get_filename (abfd)); - return NULL; -#endif - return NULL; - found = true; - } - - if (! found) - { - fprintf (stderr, "%s: no recognized debugging information\n", - bfd_get_filename (abfd)); - return NULL; - } - - return dhandle; -} - -/* Read stabs in sections debugging information from a BFD. */ - -static boolean -read_section_stabs_debugging_info (abfd, syms, symcount, dhandle, pfound) - bfd *abfd; - asymbol **syms; - long symcount; - PTR dhandle; - boolean *pfound; -{ - static struct - { - const char *secname; - const char *strsecname; - } names[] = { { ".stab", ".stabstr" } }; - unsigned int i; - PTR shandle; - - *pfound = false; - shandle = NULL; - - for (i = 0; i < sizeof names / sizeof names[0]; i++) - { - asection *sec, *strsec; - - sec = bfd_get_section_by_name (abfd, names[i].secname); - strsec = bfd_get_section_by_name (abfd, names[i].strsecname); - if (sec != NULL && strsec != NULL) - { - bfd_size_type stabsize, strsize; - bfd_byte *stabs, *strings; - bfd_byte *stab; - bfd_size_type stroff, next_stroff; - - stabsize = bfd_section_size (abfd, sec); - stabs = (bfd_byte *) xmalloc (stabsize); - if (! bfd_get_section_contents (abfd, sec, stabs, 0, stabsize)) - { - fprintf (stderr, "%s: %s: %s\n", - bfd_get_filename (abfd), names[i].secname, - bfd_errmsg (bfd_get_error ())); - return false; - } - - strsize = bfd_section_size (abfd, strsec); - strings = (bfd_byte *) xmalloc (strsize); - if (! bfd_get_section_contents (abfd, strsec, strings, 0, strsize)) - { - fprintf (stderr, "%s: %s: %s\n", - bfd_get_filename (abfd), names[i].strsecname, - bfd_errmsg (bfd_get_error ())); - return false; - } - - if (shandle == NULL) - { - shandle = start_stab (dhandle, abfd, true, syms, symcount); - if (shandle == NULL) - return false; - } - - *pfound = true; - - stroff = 0; - next_stroff = 0; - for (stab = stabs; stab < stabs + stabsize; stab += 12) - { - bfd_size_type strx; - int type; - int other; - int desc; - bfd_vma value; - - /* This code presumes 32 bit values. */ - - strx = bfd_get_32 (abfd, stab); - type = bfd_get_8 (abfd, stab + 4); - other = bfd_get_8 (abfd, stab + 5); - desc = bfd_get_16 (abfd, stab + 6); - value = bfd_get_32 (abfd, stab + 8); - - if (type == 0) - { - /* Special type 0 stabs indicate the offset to the - next string table. */ - stroff = next_stroff; - next_stroff += value; - } - else - { - char *f, *s; - - f = NULL; - s = (char *) strings + stroff + strx; - while (s[strlen (s) - 1] == '\\' - && stab + 12 < stabs + stabsize) - { - char *p; - - stab += 12; - p = s + strlen (s) - 1; - *p = '\0'; - s = concat (s, - ((char *) strings - + stroff - + bfd_get_32 (abfd, stab)), - (const char *) NULL); - - /* We have to restore the backslash, because, if - the linker is hashing stabs strings, we may - see the same string more than once. */ - *p = '\\'; - - if (f != NULL) - free (f); - f = s; - } - - save_stab (type, desc, value, s); - - if (! parse_stab (dhandle, shandle, type, desc, value, s)) - { -#if 0 -/* - * JZ: skip the junk. - */ - stab_context (); - free_saved_stabs (); - return false; -#endif - } - - /* Don't free f, since I think the stabs code - expects strings to hang around. This should be - straightened out. FIXME. */ - } - } - - free_saved_stabs (); - free (stabs); - - /* Don't free strings, since I think the stabs code expects - the strings to hang around. This should be straightened - out. FIXME. */ - } - } - - if (shandle != NULL) - { - if (! finish_stab (dhandle, shandle)) - return false; - } - - return true; -} - -/* Read stabs in the symbol table. */ - -static boolean -read_symbol_stabs_debugging_info (abfd, syms, symcount, dhandle, pfound) - bfd *abfd; - asymbol **syms; - long symcount; - PTR dhandle; - boolean *pfound; -{ - PTR shandle; - asymbol **ps, **symend; - - shandle = NULL; - symend = syms + symcount; - for (ps = syms; ps < symend; ps++) - { - symbol_info i; - - bfd_get_symbol_info (abfd, *ps, &i); - - if (i.type == '-') - { - const char *s; - char *f; - - if (shandle == NULL) - { - shandle = start_stab (dhandle, abfd, false, syms, symcount); - if (shandle == NULL) - return false; - } - - *pfound = true; - - s = i.name; - f = NULL; - while (s[strlen (s) - 1] == '\\' - && ps + 1 < symend) - { - char *sc, *n; - - ++ps; - sc = xstrdup (s); - sc[strlen (sc) - 1] = '\0'; - n = concat (sc, bfd_asymbol_name (*ps), (const char *) NULL); - free (sc); - if (f != NULL) - free (f); - f = n; - s = n; - } - - save_stab (i.stab_type, i.stab_desc, i.value, s); - - if (! parse_stab (dhandle, shandle, i.stab_type, i.stab_desc, - i.value, s)) - { - stab_context (); - free_saved_stabs (); - return false; - } - - /* Don't free f, since I think the stabs code expects - strings to hang around. This should be straightened out. - FIXME. */ - } - } - - free_saved_stabs (); - - if (shandle != NULL) - { - if (! finish_stab (dhandle, shandle)) - return false; - } - - return true; -} - -/* Read IEEE debugging information. */ - -static boolean -read_ieee_debugging_info (abfd, dhandle, pfound) - bfd *abfd; - PTR dhandle; - boolean *pfound; -{ - asection *dsec; - bfd_size_type size; - bfd_byte *contents; - - /* The BFD backend puts the debugging information into a section - named .debug. */ - - dsec = bfd_get_section_by_name (abfd, ".debug"); - if (dsec == NULL) - return true; - - size = bfd_section_size (abfd, dsec); - contents = (bfd_byte *) xmalloc (size); - if (! bfd_get_section_contents (abfd, dsec, contents, 0, size)) - return false; - - if (! parse_ieee (dhandle, abfd, contents, size)) - return false; - - free (contents); - - *pfound = true; - - return true; -} - -/* Record stabs strings, so that we can give some context for errors. */ - -#define SAVE_STABS_COUNT (16) - -struct saved_stab -{ - int type; - int desc; - bfd_vma value; - char *string; -}; - -static struct saved_stab saved_stabs[SAVE_STABS_COUNT]; -static int saved_stabs_index; - -/* Save a stabs string. */ - -static void -save_stab (type, desc, value, string) - int type; - int desc; - bfd_vma value; - const char *string; -{ - if (saved_stabs[saved_stabs_index].string != NULL) - free (saved_stabs[saved_stabs_index].string); - saved_stabs[saved_stabs_index].type = type; - saved_stabs[saved_stabs_index].desc = desc; - saved_stabs[saved_stabs_index].value = value; - saved_stabs[saved_stabs_index].string = xstrdup (string); - saved_stabs_index = (saved_stabs_index + 1) % SAVE_STABS_COUNT; -} - -/* Provide context for an error. */ - -static void -stab_context () -{ - int i; - - fprintf (stderr, "Last stabs entries before error:\n"); - fprintf (stderr, "n_type n_desc n_value string\n"); - - i = saved_stabs_index; - do - { - struct saved_stab *stabp; - - stabp = saved_stabs + i; - if (stabp->string != NULL) - { - const char *s; - - s = bfd_get_stab_name (stabp->type); - if (s != NULL) - fprintf (stderr, "%-6s", s); - else if (stabp->type == 0) - fprintf (stderr, "HdrSym"); - else - fprintf (stderr, "%-6d", stabp->type); - fprintf (stderr, " %-6d ", stabp->desc); - fprintf_vma (stderr, stabp->value); - if (stabp->type != 0) - fprintf (stderr, " %s", stabp->string); - fprintf (stderr, "\n"); - } - i = (i + 1) % SAVE_STABS_COUNT; - } - while (i != saved_stabs_index); -} - -/* Free the saved stab strings. */ - -static void -free_saved_stabs () -{ - int i; - - for (i = 0; i < SAVE_STABS_COUNT; i++) - { - if (saved_stabs[i].string != NULL) - { - free (saved_stabs[i].string); - saved_stabs[i].string = NULL; - } - } - - saved_stabs_index = 0; -} diff --git a/pstack/stabs.c b/pstack/stabs.c deleted file mode 100644 index 076231d19cb..00000000000 --- a/pstack/stabs.c +++ /dev/null @@ -1,5082 +0,0 @@ -/* stabs.c -- Parse stabs debugging information - Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. - Written by Ian Lance Taylor . - - This file is part of GNU Binutils. - - 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; either version 2 of the License, or - (at your option) any later version. - - 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., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. */ - -/* This file contains code which parses stabs debugging information. - The organization of this code is based on the gdb stabs reading - code. The job it does is somewhat different, because it is not - trying to identify the correct address for anything. */ - -#include -#include - -#include -#include "bucomm.h" -#include -#include "demangle.h" -#include "debug.h" -#include "budbg.h" - -/* Meaningless definition needs by aout64.h. FIXME. */ -#define BYTES_IN_WORD 4 - -#include "aout/aout64.h" -#include "aout/stab_gnu.h" - -/* The number of predefined XCOFF types. */ - -#define XCOFF_TYPE_COUNT 34 - -/* This structure is used as a handle so that the stab parsing doesn't - need to use any static variables. */ - -struct stab_handle -{ - /* The BFD. */ - bfd *abfd; - /* True if this is stabs in sections. */ - boolean sections; - /* The symbol table. */ - asymbol **syms; - /* The number of symbols. */ - long symcount; - /* The accumulated file name string. */ - char *so_string; - /* The value of the last N_SO symbol. */ - bfd_vma so_value; - /* The value of the start of the file, so that we can handle file - relative N_LBRAC and N_RBRAC symbols. */ - bfd_vma file_start_offset; - /* The offset of the start of the function, so that we can handle - function relative N_LBRAC and N_RBRAC symbols. */ - bfd_vma function_start_offset; - /* The version number of gcc which compiled the current compilation - unit, 0 if not compiled by gcc. */ - int gcc_compiled; - /* Whether an N_OPT symbol was seen that was not generated by gcc, - so that we can detect the SunPRO compiler. */ - boolean n_opt_found; - /* The main file name. */ - char *main_filename; - /* A stack of unfinished N_BINCL files. */ - struct bincl_file *bincl_stack; - /* A list of finished N_BINCL files. */ - struct bincl_file *bincl_list; - /* Whether we are inside a function or not. */ - boolean within_function; - /* The address of the end of the function, used if we have seen an - N_FUN symbol while in a function. This is -1 if we have not seen - an N_FUN (the normal case). */ - bfd_vma function_end; - /* The depth of block nesting. */ - int block_depth; - /* List of pending variable definitions. */ - struct stab_pending_var *pending; - /* Number of files for which we have types. */ - unsigned int files; - /* Lists of types per file. */ - struct stab_types **file_types; - /* Predefined XCOFF types. */ - debug_type xcoff_types[XCOFF_TYPE_COUNT]; - /* Undefined tags. */ - struct stab_tag *tags; -}; - -/* A list of these structures is used to hold pending variable - definitions seen before the N_LBRAC of a block. */ - -struct stab_pending_var -{ - /* Next pending variable definition. */ - struct stab_pending_var *next; - /* Name. */ - const char *name; - /* Type. */ - debug_type type; - /* Kind. */ - enum debug_var_kind kind; - /* Value. */ - bfd_vma val; -}; - -/* A list of these structures is used to hold the types for a single - file. */ - -struct stab_types -{ - /* Next set of slots for this file. */ - struct stab_types *next; - /* Types indexed by type number. */ -#define STAB_TYPES_SLOTS (16) - debug_type types[STAB_TYPES_SLOTS]; -}; - -/* We keep a list of undefined tags that we encounter, so that we can - fill them in if the tag is later defined. */ - -struct stab_tag -{ - /* Next undefined tag. */ - struct stab_tag *next; - /* Tag name. */ - const char *name; - /* Type kind. */ - enum debug_type_kind kind; - /* Slot to hold real type when we discover it. If we don't, we fill - in an undefined tag type. */ - debug_type slot; - /* Indirect type we have created to point at slot. */ - debug_type type; -}; - -static char *savestring PARAMS ((const char *, int)); -static bfd_vma parse_number PARAMS ((const char **, boolean *)); -static void bad_stab PARAMS ((const char *)); -static void warn_stab PARAMS ((const char *, const char *)); -static boolean parse_stab_string - PARAMS ((PTR, struct stab_handle *, int, int, bfd_vma, const char *)); -static debug_type parse_stab_type - PARAMS ((PTR, struct stab_handle *, const char *, const char **, - debug_type **)); -static boolean parse_stab_type_number - PARAMS ((const char **, int *)); -static debug_type parse_stab_range_type - PARAMS ((PTR, struct stab_handle *, const char *, const char **, - const int *)); -static debug_type parse_stab_sun_builtin_type PARAMS ((PTR, const char **)); -static debug_type parse_stab_sun_floating_type - PARAMS ((PTR, const char **)); -static debug_type parse_stab_enum_type PARAMS ((PTR, const char **)); -static debug_type parse_stab_struct_type - PARAMS ((PTR, struct stab_handle *, const char *, const char **, boolean, - const int *)); -static boolean parse_stab_baseclasses - PARAMS ((PTR, struct stab_handle *, const char **, debug_baseclass **)); -static boolean parse_stab_struct_fields - PARAMS ((PTR, struct stab_handle *, const char **, debug_field **, - boolean *)); -static boolean parse_stab_cpp_abbrev - PARAMS ((PTR, struct stab_handle *, const char **, debug_field *)); -static boolean parse_stab_one_struct_field - PARAMS ((PTR, struct stab_handle *, const char **, const char *, - debug_field *, boolean *)); -static boolean parse_stab_members - PARAMS ((PTR, struct stab_handle *, const char *, const char **, - const int *, debug_method **)); -static debug_type parse_stab_argtypes - PARAMS ((PTR, struct stab_handle *, debug_type, const char *, const char *, - debug_type, const char *, boolean, boolean, const char **)); -static boolean parse_stab_tilde_field - PARAMS ((PTR, struct stab_handle *, const char **, const int *, - debug_type *, boolean *)); -static debug_type parse_stab_array_type - PARAMS ((PTR, struct stab_handle *, const char **, boolean)); -static void push_bincl PARAMS ((struct stab_handle *, const char *, bfd_vma)); -static const char *pop_bincl PARAMS ((struct stab_handle *)); -static boolean find_excl - PARAMS ((struct stab_handle *, const char *, bfd_vma)); -static boolean stab_record_variable - PARAMS ((PTR, struct stab_handle *, const char *, debug_type, - enum debug_var_kind, bfd_vma)); -static boolean stab_emit_pending_vars PARAMS ((PTR, struct stab_handle *)); -static debug_type *stab_find_slot - PARAMS ((struct stab_handle *, const int *)); -static debug_type stab_find_type - PARAMS ((PTR, struct stab_handle *, const int *)); -static boolean stab_record_type - PARAMS ((PTR, struct stab_handle *, const int *, debug_type)); -static debug_type stab_xcoff_builtin_type - PARAMS ((PTR, struct stab_handle *, int)); -static debug_type stab_find_tagged_type - PARAMS ((PTR, struct stab_handle *, const char *, int, - enum debug_type_kind)); -static debug_type *stab_demangle_argtypes - PARAMS ((PTR, struct stab_handle *, const char *, boolean *)); - -/* Save a string in memory. */ - -static char * -savestring (start, len) - const char *start; - int len; -{ - char *ret; - - ret = (char *) xmalloc (len + 1); - memcpy (ret, start, len); - ret[len] = '\0'; - return ret; -} - -/* Read a number from a string. */ - -static bfd_vma -parse_number (pp, poverflow) - const char **pp; - boolean *poverflow; -{ - unsigned long ul; - const char *orig; - - if (poverflow != NULL) - *poverflow = false; - - orig = *pp; - - errno = 0; - ul = strtoul (*pp, (char **) pp, 0); - if (ul + 1 != 0 || errno == 0) - return (bfd_vma) ul; - - /* Note that even though strtoul overflowed, it should have set *pp - to the end of the number, which is where we want it. */ - - if (sizeof (bfd_vma) > sizeof (unsigned long)) - { - const char *p; - boolean neg; - int base; - bfd_vma over, lastdig; - boolean overflow; - bfd_vma v; - - /* Our own version of strtoul, for a bfd_vma. */ - - p = orig; - - neg = false; - if (*p == '+') - ++p; - else if (*p == '-') - { - neg = true; - ++p; - } - - base = 10; - if (*p == '0') - { - if (p[1] == 'x' || p[1] == 'X') - { - base = 16; - p += 2; - } - else - { - base = 8; - ++p; - } - } - - over = ((bfd_vma) (bfd_signed_vma) -1) / (bfd_vma) base; - lastdig = ((bfd_vma) (bfd_signed_vma) -1) % (bfd_vma) base; - - overflow = false; - v = 0; - while (1) - { - int d; - - d = *p++; - if (isdigit ((unsigned char) d)) - d -= '0'; - else if (isupper ((unsigned char) d)) - d -= 'A'; - else if (islower ((unsigned char) d)) - d -= 'a'; - else - break; - - if (d >= base) - break; - - if (v > over || (v == over && (bfd_vma) d > lastdig)) - { - overflow = true; - break; - } - } - - if (! overflow) - { - if (neg) - v = - v; - return v; - } - } - - /* If we get here, the number is too large to represent in a - bfd_vma. */ - - if (poverflow != NULL) - *poverflow = true; - else - warn_stab (orig, "numeric overflow"); - - return 0; -} - -/* Give an error for a bad stab string. */ - -static void -bad_stab (p) - const char *p; -{ - fprintf (stderr, "Bad stab: %s\n", p); -} - -/* Warn about something in a stab string. */ - -static void -warn_stab (p, err) - const char *p; - const char *err; -{ - fprintf (stderr, "Warning: %s: %s\n", err, p); -} - -/* Create a handle to parse stabs symbols with. */ - -/*ARGSUSED*/ -PTR -start_stab (dhandle, abfd, sections, syms, symcount) - PTR dhandle; - bfd *abfd; - boolean sections; - asymbol **syms; - long symcount; -{ - struct stab_handle *ret; - - ret = (struct stab_handle *) xmalloc (sizeof *ret); - memset (ret, 0, sizeof *ret); - ret->abfd = abfd; - ret->sections = sections; - ret->syms = syms; - ret->symcount = symcount; - ret->files = 1; - ret->file_types = (struct stab_types **) xmalloc (sizeof *ret->file_types); - ret->file_types[0] = NULL; - ret->function_end = (bfd_vma) -1; - return (PTR) ret; -} - -/* When we have processed all the stabs information, we need to go - through and fill in all the undefined tags. */ - -boolean -finish_stab (dhandle, handle) - PTR dhandle; - PTR handle; -{ - struct stab_handle *info = (struct stab_handle *) handle; - struct stab_tag *st; - - if (info->within_function) - { - if (! stab_emit_pending_vars (dhandle, info) - || ! debug_end_function (dhandle, info->function_end)) - return false; - info->within_function = false; - info->function_end = (bfd_vma) -1; - } - - for (st = info->tags; st != NULL; st = st->next) - { - enum debug_type_kind kind; - - kind = st->kind; - if (kind == DEBUG_KIND_ILLEGAL) - kind = DEBUG_KIND_STRUCT; - st->slot = debug_make_undefined_tagged_type (dhandle, st->name, kind); - if (st->slot == DEBUG_TYPE_NULL) - return false; - } - - return true; -} - -/* Handle a single stabs symbol. */ - -boolean -parse_stab (dhandle, handle, type, desc, value, string) - PTR dhandle; - PTR handle; - int type; - int desc; - bfd_vma value; - const char *string; -{ - struct stab_handle *info = (struct stab_handle *) handle; - - /* gcc will emit two N_SO strings per compilation unit, one for the - directory name and one for the file name. We just collect N_SO - strings as we see them, and start the new compilation unit when - we see a non N_SO symbol. */ - if (info->so_string != NULL - && (type != N_SO || *string == '\0' || value != info->so_value)) - { - if (! debug_set_filename (dhandle, info->so_string)) - return false; - info->main_filename = info->so_string; - - info->gcc_compiled = 0; - info->n_opt_found = false; - - /* Generally, for stabs in the symbol table, the N_LBRAC and - N_RBRAC symbols are relative to the N_SO symbol value. */ - if (! info->sections) - info->file_start_offset = info->so_value; - - /* We need to reset the mapping from type numbers to types. We - can't free the old mapping, because of the use of - debug_make_indirect_type. */ - info->files = 1; - info->file_types = ((struct stab_types **) - xmalloc (sizeof *info->file_types)); - info->file_types[0] = NULL; - - info->so_string = NULL; - - /* Now process whatever type we just got. */ - } - - switch (type) - { - case N_FN: - case N_FN_SEQ: - break; - - case N_LBRAC: - /* Ignore extra outermost context from SunPRO cc and acc. */ - if (info->n_opt_found && desc == 1) - break; - - if (! info->within_function) - { - fprintf (stderr, "N_LBRAC not within function\n"); - return false; - } - - /* Start an inner lexical block. */ - if (! debug_start_block (dhandle, - (value - + info->file_start_offset - + info->function_start_offset))) - return false; - - /* Emit any pending variable definitions. */ - if (! stab_emit_pending_vars (dhandle, info)) - return false; - - ++info->block_depth; - break; - - case N_RBRAC: - /* Ignore extra outermost context from SunPRO cc and acc. */ - if (info->n_opt_found && desc == 1) - break; - - /* We shouldn't have any pending variable definitions here, but, - if we do, we probably need to emit them before closing the - block. */ - if (! stab_emit_pending_vars (dhandle, info)) - return false; - - /* End an inner lexical block. */ - if (! debug_end_block (dhandle, - (value - + info->file_start_offset - + info->function_start_offset))) - return false; - - --info->block_depth; - if (info->block_depth < 0) - { - fprintf (stderr, "Too many N_RBRACs\n"); - return false; - } - break; - - case N_SO: - /* This always ends a function. */ - if (info->within_function) - { - bfd_vma endval; - - endval = value; - if (*string != '\0' - && info->function_end != (bfd_vma) -1 - && info->function_end < endval) - endval = info->function_end; - if (! stab_emit_pending_vars (dhandle, info) - || ! debug_end_function (dhandle, endval)) - return false; - info->within_function = false; - info->function_end = (bfd_vma) -1; - } - - /* An empty string is emitted by gcc at the end of a compilation - unit. */ - if (*string == '\0') - return true; - - /* Just accumulate strings until we see a non N_SO symbol. If - the string starts with '/', we discard the previously - accumulated strings. */ - if (info->so_string == NULL) - info->so_string = xstrdup (string); - else - { - char *f; - - f = info->so_string; - if (*string == '/') - info->so_string = xstrdup (string); - else - info->so_string = concat (info->so_string, string, - (const char *) NULL); - free (f); - } - - info->so_value = value; - - break; - - case N_SOL: - /* Start an include file. */ - if (! debug_start_source (dhandle, string)) - return false; - break; - - case N_BINCL: - /* Start an include file which may be replaced. */ - push_bincl (info, string, value); - if (! debug_start_source (dhandle, string)) - return false; - break; - - case N_EINCL: - /* End an N_BINCL include. */ - if (! debug_start_source (dhandle, pop_bincl (info))) - return false; - break; - - case N_EXCL: - /* This is a duplicate of a header file named by N_BINCL which - was eliminated by the linker. */ - if (! find_excl (info, string, value)) - return false; - break; - - case N_SLINE: - if (! debug_record_line (dhandle, desc, - value + info->function_start_offset)) - return false; - break; - - case N_BCOMM: - if (! debug_start_common_block (dhandle, string)) - return false; - break; - - case N_ECOMM: - if (! debug_end_common_block (dhandle, string)) - return false; - break; - - case N_FUN: - if (*string == '\0') - { - if (info->within_function) - { - /* This always marks the end of a function; we don't - need to worry about info->function_end. */ - if (info->sections) - value += info->function_start_offset; - if (! stab_emit_pending_vars (dhandle, info) - || ! debug_end_function (dhandle, value)) - return false; - info->within_function = false; - info->function_end = (bfd_vma) -1; - } - break; - } - - /* A const static symbol in the .text section will have an N_FUN - entry. We need to use these to mark the end of the function, - in case we are looking at gcc output before it was changed to - always emit an empty N_FUN. We can't call debug_end_function - here, because it might be a local static symbol. */ - if (info->within_function - && (info->function_end == (bfd_vma) -1 - || value < info->function_end)) - info->function_end = value; - - /* Fall through. */ - /* FIXME: gdb checks the string for N_STSYM, N_LCSYM or N_ROSYM - symbols, and if it does not start with :S, gdb relocates the - value to the start of the section. gcc always seems to use - :S, so we don't worry about this. */ - /* Fall through. */ - default: - { - const char *colon; - - colon = strchr (string, ':'); - if (colon != NULL - && (colon[1] == 'f' || colon[1] == 'F')) - { - if (info->within_function) - { - bfd_vma endval; - - endval = value; - if (info->function_end != (bfd_vma) -1 - && info->function_end < endval) - endval = info->function_end; - if (! stab_emit_pending_vars (dhandle, info) - || ! debug_end_function (dhandle, endval)) - return false; - info->function_end = (bfd_vma) -1; - } - /* For stabs in sections, line numbers and block addresses - are offsets from the start of the function. */ - if (info->sections) - info->function_start_offset = value; - info->within_function = true; - } - - if (! parse_stab_string (dhandle, info, type, desc, value, string)) - return false; - } - break; - - case N_OPT: - if (string != NULL && strcmp (string, "gcc2_compiled.") == 0) - info->gcc_compiled = 2; - else if (string != NULL && strcmp (string, "gcc_compiled.") == 0) - info->gcc_compiled = 1; - else - info->n_opt_found = true; - break; - - case N_OBJ: - case N_ENDM: - case N_MAIN: - break; - } - - return true; -} - -/* Parse the stabs string. */ - -static boolean -parse_stab_string (dhandle, info, stabtype, desc, value, string) - PTR dhandle; - struct stab_handle *info; - int stabtype; - int desc; - bfd_vma value; - const char *string; -{ - const char *p; - char *name; - int type; - debug_type dtype; - boolean synonym; - unsigned int lineno; - debug_type *slot; - - p = strchr (string, ':'); - if (p == NULL) - return true; - - while (p[1] == ':') - { - p += 2; - p = strchr (p, ':'); - if (p == NULL) - { - bad_stab (string); - return false; - } - } - - /* GCC 2.x puts the line number in desc. SunOS apparently puts in - the number of bytes occupied by a type or object, which we - ignore. */ - if (info->gcc_compiled >= 2) - lineno = desc; - else - lineno = 0; - - /* FIXME: Sometimes the special C++ names start with '.'. */ - name = NULL; - if (string[0] == '$') - { - switch (string[1]) - { - case 't': - name = "this"; - break; - case 'v': - /* Was: name = "vptr"; */ - break; - case 'e': - name = "eh_throw"; - break; - case '_': - /* This was an anonymous type that was never fixed up. */ - break; - case 'X': - /* SunPRO (3.0 at least) static variable encoding. */ - break; - default: - warn_stab (string, "unknown C++ encoded name"); - break; - } - } - - if (name == NULL) - { - if (p == string || (string[0] == ' ' && p == string + 1)) - name = NULL; - else - name = savestring (string, p - string); - } - - ++p; - if (isdigit ((unsigned char) *p) || *p == '(' || *p == '-') - type = 'l'; - else - type = *p++; - - switch (type) - { - case 'c': - /* c is a special case, not followed by a type-number. - SYMBOL:c=iVALUE for an integer constant symbol. - SYMBOL:c=rVALUE for a floating constant symbol. - SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol. - e.g. "b:c=e6,0" for "const b = blob1" - (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */ - if (*p != '=') - { - bad_stab (string); - return false; - } - ++p; - switch (*p++) - { - case 'r': - /* Floating point constant. */ - if (! debug_record_float_const (dhandle, name, atof (p))) - return false; - break; - case 'i': - /* Integer constant. */ - /* Defining integer constants this way is kind of silly, - since 'e' constants allows the compiler to give not only - the value, but the type as well. C has at least int, - long, unsigned int, and long long as constant types; - other languages probably should have at least unsigned as - well as signed constants. */ - if (! debug_record_int_const (dhandle, name, atoi (p))) - return false; - break; - case 'e': - /* SYMBOL:c=eTYPE,INTVALUE for a constant symbol whose value - can be represented as integral. - e.g. "b:c=e6,0" for "const b = blob1" - (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */ - dtype = parse_stab_type (dhandle, info, (const char *) NULL, - &p, (debug_type **) NULL); - if (dtype == DEBUG_TYPE_NULL) - return false; - if (*p != ',') - { - bad_stab (string); - return false; - } - if (! debug_record_typed_const (dhandle, name, dtype, atoi (p))) - return false; - break; - default: - bad_stab (string); - return false; - } - - break; - - case 'C': - /* The name of a caught exception. */ - dtype = parse_stab_type (dhandle, info, (const char *) NULL, - &p, (debug_type **) NULL); - if (dtype == DEBUG_TYPE_NULL) - return false; - if (! debug_record_label (dhandle, name, dtype, value)) - return false; - break; - - case 'f': - case 'F': - /* A function definition. */ - dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, - (debug_type **) NULL); - if (dtype == DEBUG_TYPE_NULL) - return false; - if (! debug_record_function (dhandle, name, dtype, type == 'F', value)) - return false; - - /* Sun acc puts declared types of arguments here. We don't care - about their actual types (FIXME -- we should remember the whole - function prototype), but the list may define some new types - that we have to remember, so we must scan it now. */ - while (*p == ';') - { - ++p; - if (parse_stab_type (dhandle, info, (const char *) NULL, &p, - (debug_type **) NULL) - == DEBUG_TYPE_NULL) - return false; - } - - break; - - case 'G': - { - char leading; - long c; - asymbol **ps; - - /* A global symbol. The value must be extracted from the - symbol table. */ - dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, - (debug_type **) NULL); - if (dtype == DEBUG_TYPE_NULL) - return false; - leading = bfd_get_symbol_leading_char (info->abfd); - for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps) - { - const char *n; - - n = bfd_asymbol_name (*ps); - if (leading != '\0' && *n == leading) - ++n; - if (*n == *name && strcmp (n, name) == 0) - break; - } - if (c > 0) - value = bfd_asymbol_value (*ps); - if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL, - value)) - return false; - } - break; - - /* This case is faked by a conditional above, when there is no - code letter in the dbx data. Dbx data never actually - contains 'l'. */ - case 'l': - case 's': - dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, - (debug_type **) NULL); - if (dtype == DEBUG_TYPE_NULL) - return false; - if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL, - value)) - return false; - break; - - case 'p': - /* A function parameter. */ - if (*p != 'F') - dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, - (debug_type **) NULL); - else - { - /* pF is a two-letter code that means a function parameter in - Fortran. The type-number specifies the type of the return - value. Translate it into a pointer-to-function type. */ - ++p; - dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, - (debug_type **) NULL); - if (dtype != DEBUG_TYPE_NULL) - { - debug_type ftype; - - ftype = debug_make_function_type (dhandle, dtype, - (debug_type *) NULL, false); - dtype = debug_make_pointer_type (dhandle, ftype); - } - } - if (dtype == DEBUG_TYPE_NULL) - return false; - if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_STACK, - value)) - return false; - - /* FIXME: At this point gdb considers rearranging the parameter - address on a big endian machine if it is smaller than an int. - We have no way to do that, since we don't really know much - about the target. */ - - break; - - case 'P': - if (stabtype == N_FUN) - { - /* Prototype of a function referenced by this file. */ - while (*p == ';') - { - ++p; - if (parse_stab_type (dhandle, info, (const char *) NULL, &p, - (debug_type **) NULL) - == DEBUG_TYPE_NULL) - return false; - } - break; - } - /* Fall through. */ - case 'R': - /* Parameter which is in a register. */ - dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, - (debug_type **) NULL); - if (dtype == DEBUG_TYPE_NULL) - return false; - if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REG, - value)) - return false; - break; - - case 'r': - /* Register variable (either global or local). */ - dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, - (debug_type **) NULL); - if (dtype == DEBUG_TYPE_NULL) - return false; - if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_REGISTER, - value)) - return false; - - /* FIXME: At this point gdb checks to combine pairs of 'p' and - 'r' stabs into a single 'P' stab. */ - - break; - - case 'S': - /* Static symbol at top level of file */ - dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, - (debug_type **) NULL); - if (dtype == DEBUG_TYPE_NULL) - return false; - if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_STATIC, - value)) - return false; - break; - - case 't': - /* A typedef. */ - dtype = parse_stab_type (dhandle, info, name, &p, &slot); - if (dtype == DEBUG_TYPE_NULL) - return false; - if (name == NULL) - { - /* A nameless type. Nothing to do. */ - return true; - } - - dtype = debug_name_type (dhandle, name, dtype); - if (dtype == DEBUG_TYPE_NULL) - return false; - - if (slot != NULL) - *slot = dtype; - - break; - - case 'T': - /* Struct, union, or enum tag. For GNU C++, this can be be followed - by 't' which means we are typedef'ing it as well. */ - if (*p != 't') - { - synonym = false; - /* FIXME: gdb sets synonym to true if the current language - is C++. */ - } - else - { - synonym = true; - ++p; - } - - dtype = parse_stab_type (dhandle, info, name, &p, &slot); - if (dtype == DEBUG_TYPE_NULL) - return false; - if (name == NULL) - return true; - - dtype = debug_tag_type (dhandle, name, dtype); - if (dtype == DEBUG_TYPE_NULL) - return false; - if (slot != NULL) - *slot = dtype; - - /* See if we have a cross reference to this tag which we can now - fill in. */ - { - register struct stab_tag **pst; - - for (pst = &info->tags; *pst != NULL; pst = &(*pst)->next) - { - if ((*pst)->name[0] == name[0] - && strcmp ((*pst)->name, name) == 0) - { - (*pst)->slot = dtype; - *pst = (*pst)->next; - break; - } - } - } - - if (synonym) - { - dtype = debug_name_type (dhandle, name, dtype); - if (dtype == DEBUG_TYPE_NULL) - return false; - - if (slot != NULL) - *slot = dtype; - } - - break; - - case 'V': - /* Static symbol of local scope */ - dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, - (debug_type **) NULL); - if (dtype == DEBUG_TYPE_NULL) - return false; - /* FIXME: gdb checks os9k_stabs here. */ - if (! stab_record_variable (dhandle, info, name, dtype, - DEBUG_LOCAL_STATIC, value)) - return false; - break; - - case 'v': - /* Reference parameter. */ - dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, - (debug_type **) NULL); - if (dtype == DEBUG_TYPE_NULL) - return false; - if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REFERENCE, - value)) - return false; - break; - - case 'a': - /* Reference parameter which is in a register. */ - dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, - (debug_type **) NULL); - if (dtype == DEBUG_TYPE_NULL) - return false; - if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REF_REG, - value)) - return false; - break; - - case 'X': - /* This is used by Sun FORTRAN for "function result value". - Sun claims ("dbx and dbxtool interfaces", 2nd ed) - that Pascal uses it too, but when I tried it Pascal used - "x:3" (local symbol) instead. */ - dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, - (debug_type **) NULL); - if (dtype == DEBUG_TYPE_NULL) - return false; - if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL, - value)) - return false; - break; - - default: - bad_stab (string); - return false; - } - - /* FIXME: gdb converts structure values to structure pointers in a - couple of cases, depending upon the target. */ - - return true; -} - -/* Parse a stabs type. The typename argument is non-NULL if this is a - typedef or a tag definition. The pp argument points to the stab - string, and is updated. The slotp argument points to a place to - store the slot used if the type is being defined. */ - -static debug_type -parse_stab_type (dhandle, info, typename, pp, slotp) - PTR dhandle; - struct stab_handle *info; - const char *typename; - const char **pp; - debug_type **slotp; -{ - const char *orig; - int typenums[2]; - int size; - boolean stringp; - int descriptor; - debug_type dtype; - - if (slotp != NULL) - *slotp = NULL; - - orig = *pp; - - size = -1; - stringp = false; - - /* Read type number if present. The type number may be omitted. - for instance in a two-dimensional array declared with type - "ar1;1;10;ar1;1;10;4". */ - if (! isdigit ((unsigned char) **pp) && **pp != '(' && **pp != '-') - { - /* 'typenums=' not present, type is anonymous. Read and return - the definition, but don't put it in the type vector. */ - typenums[0] = typenums[1] = -1; - } - else - { - if (! parse_stab_type_number (pp, typenums)) - return DEBUG_TYPE_NULL; - - if (**pp != '=') - { - /* Type is not being defined here. Either it already - exists, or this is a forward reference to it. */ - return stab_find_type (dhandle, info, typenums); - } - - /* Only set the slot if the type is being defined. This means - that the mapping from type numbers to types will only record - the name of the typedef which defines a type. If we don't do - this, then something like - typedef int foo; - int i; - will record that i is of type foo. Unfortunately, stabs - information is ambiguous about variable types. For this code, - typedef int foo; - int i; - foo j; - the stabs information records both i and j as having the same - type. This could be fixed by patching the compiler. */ - if (slotp != NULL && typenums[0] >= 0 && typenums[1] >= 0) - *slotp = stab_find_slot (info, typenums); - - /* Type is being defined here. */ - /* Skip the '='. */ - ++*pp; - - while (**pp == '@') - { - const char *p = *pp + 1; - const char *attr; - - if (isdigit ((unsigned char) *p) || *p == '(' || *p == '-') - { - /* Member type. */ - break; - } - - /* Type attributes. */ - attr = p; - - for (; *p != ';'; ++p) - { - if (*p == '\0') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - } - *pp = p + 1; - - switch (*attr) - { - case 's': - size = atoi (attr + 1); - if (size <= 0) - size = -1; - break; - - case 'S': - stringp = true; - break; - - default: - /* Ignore unrecognized type attributes, so future - compilers can invent new ones. */ - break; - } - } - } - - descriptor = **pp; - ++*pp; - - switch (descriptor) - { - case 'x': - { - enum debug_type_kind code; - const char *q1, *q2, *p; - - /* A cross reference to another type. */ - - switch (**pp) - { - case 's': - code = DEBUG_KIND_STRUCT; - break; - case 'u': - code = DEBUG_KIND_UNION; - break; - case 'e': - code = DEBUG_KIND_ENUM; - break; - default: - /* Complain and keep going, so compilers can invent new - cross-reference types. */ - warn_stab (orig, "unrecognized cross reference type"); - code = DEBUG_KIND_STRUCT; - break; - } - ++*pp; - - q1 = strchr (*pp, '<'); - p = strchr (*pp, ':'); - if (p == NULL) - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - while (q1 != NULL && p > q1 && p[1] == ':') - { - q2 = strchr (q1, '>'); - if (q2 == NULL || q2 < p) - break; - p += 2; - p = strchr (p, ':'); - if (p == NULL) - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - } - - dtype = stab_find_tagged_type (dhandle, info, *pp, p - *pp, code); - - *pp = p + 1; - } - break; - - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '(': - { - const char *hold; - int xtypenums[2]; - - /* This type is defined as another type. */ - - (*pp)--; - hold = *pp; - - /* Peek ahead at the number to detect void. */ - if (! parse_stab_type_number (pp, xtypenums)) - return DEBUG_TYPE_NULL; - - if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1]) - { - /* This type is being defined as itself, which means that - it is void. */ - dtype = debug_make_void_type (dhandle); - } - else - { - *pp = hold; - - /* Go back to the number and have parse_stab_type get it. - This means that we can deal with something like - t(1,2)=(3,4)=... which the Lucid compiler uses. */ - dtype = parse_stab_type (dhandle, info, (const char *) NULL, - pp, (debug_type **) NULL); - if (dtype == DEBUG_TYPE_NULL) - return DEBUG_TYPE_NULL; - } - - if (typenums[0] != -1) - { - if (! stab_record_type (dhandle, info, typenums, dtype)) - return DEBUG_TYPE_NULL; - } - - break; - } - - case '*': - dtype = debug_make_pointer_type (dhandle, - parse_stab_type (dhandle, info, - (const char *) NULL, - pp, - (debug_type **) NULL)); - break; - - case '&': - /* Reference to another type. */ - dtype = (debug_make_reference_type - (dhandle, - parse_stab_type (dhandle, info, (const char *) NULL, pp, - (debug_type **) NULL))); - break; - - case 'f': - /* Function returning another type. */ - /* FIXME: gdb checks os9k_stabs here. */ - dtype = (debug_make_function_type - (dhandle, - parse_stab_type (dhandle, info, (const char *) NULL, pp, - (debug_type **) NULL), - (debug_type *) NULL, false)); - break; - - case 'k': - /* Const qualifier on some type (Sun). */ - /* FIXME: gdb accepts 'c' here if os9k_stabs. */ - dtype = debug_make_const_type (dhandle, - parse_stab_type (dhandle, info, - (const char *) NULL, - pp, - (debug_type **) NULL)); - break; - - case 'B': - /* Volatile qual on some type (Sun). */ - /* FIXME: gdb accepts 'i' here if os9k_stabs. */ - dtype = (debug_make_volatile_type - (dhandle, - parse_stab_type (dhandle, info, (const char *) NULL, pp, - (debug_type **) NULL))); - break; - - case '@': - /* Offset (class & variable) type. This is used for a pointer - relative to an object. */ - { - debug_type domain; - debug_type memtype; - - /* Member type. */ - - domain = parse_stab_type (dhandle, info, (const char *) NULL, pp, - (debug_type **) NULL); - if (domain == DEBUG_TYPE_NULL) - return DEBUG_TYPE_NULL; - - if (**pp != ',') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - ++*pp; - - memtype = parse_stab_type (dhandle, info, (const char *) NULL, pp, - (debug_type **) NULL); - if (memtype == DEBUG_TYPE_NULL) - return DEBUG_TYPE_NULL; - - dtype = debug_make_offset_type (dhandle, domain, memtype); - } - break; - - case '#': - /* Method (class & fn) type. */ - if (**pp == '#') - { - debug_type return_type; - - ++*pp; - return_type = parse_stab_type (dhandle, info, (const char *) NULL, - pp, (debug_type **) NULL); - if (return_type == DEBUG_TYPE_NULL) - return DEBUG_TYPE_NULL; - if (**pp != ';') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - ++*pp; - dtype = debug_make_method_type (dhandle, return_type, - DEBUG_TYPE_NULL, - (debug_type *) NULL, false); - } - else - { - debug_type domain; - debug_type return_type; - debug_type *args; - unsigned int n; - unsigned int alloc; - boolean varargs; - - domain = parse_stab_type (dhandle, info, (const char *) NULL, - pp, (debug_type **) NULL); - if (domain == DEBUG_TYPE_NULL) - return DEBUG_TYPE_NULL; - - if (**pp != ',') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - ++*pp; - - return_type = parse_stab_type (dhandle, info, (const char *) NULL, - pp, (debug_type **) NULL); - if (return_type == DEBUG_TYPE_NULL) - return DEBUG_TYPE_NULL; - - alloc = 10; - args = (debug_type *) xmalloc (alloc * sizeof *args); - n = 0; - while (**pp != ';') - { - if (**pp != ',') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - ++*pp; - - if (n + 1 >= alloc) - { - alloc += 10; - args = ((debug_type *) - xrealloc ((PTR) args, alloc * sizeof *args)); - } - - args[n] = parse_stab_type (dhandle, info, (const char *) NULL, - pp, (debug_type **) NULL); - if (args[n] == DEBUG_TYPE_NULL) - return DEBUG_TYPE_NULL; - ++n; - } - ++*pp; - - /* If the last type is not void, then this function takes a - variable number of arguments. Otherwise, we must strip - the void type. */ - if (n == 0 - || debug_get_type_kind (dhandle, args[n - 1]) != DEBUG_KIND_VOID) - varargs = true; - else - { - --n; - varargs = false; - } - - args[n] = DEBUG_TYPE_NULL; - - dtype = debug_make_method_type (dhandle, return_type, domain, args, - varargs); - } - break; - - case 'r': - /* Range type. */ - dtype = parse_stab_range_type (dhandle, info, typename, pp, typenums); - break; - - case 'b': - /* FIXME: gdb checks os9k_stabs here. */ - /* Sun ACC builtin int type. */ - dtype = parse_stab_sun_builtin_type (dhandle, pp); - break; - - case 'R': - /* Sun ACC builtin float type. */ - dtype = parse_stab_sun_floating_type (dhandle, pp); - break; - - case 'e': - /* Enumeration type. */ - dtype = parse_stab_enum_type (dhandle, pp); - break; - - case 's': - case 'u': - /* Struct or union type. */ - dtype = parse_stab_struct_type (dhandle, info, typename, pp, - descriptor == 's', typenums); - break; - - case 'a': - /* Array type. */ - if (**pp != 'r') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - ++*pp; - - dtype = parse_stab_array_type (dhandle, info, pp, stringp); - break; - - case 'S': - dtype = debug_make_set_type (dhandle, - parse_stab_type (dhandle, info, - (const char *) NULL, - pp, - (debug_type **) NULL), - stringp); - break; - - default: - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - - if (dtype == DEBUG_TYPE_NULL) - return DEBUG_TYPE_NULL; - - if (typenums[0] != -1) - { - if (! stab_record_type (dhandle, info, typenums, dtype)) - return DEBUG_TYPE_NULL; - } - - if (size != -1) - { - if (! debug_record_type_size (dhandle, dtype, (unsigned int) size)) - return DEBUG_TYPE_NULL; - } - - return dtype; -} - -/* Read a number by which a type is referred to in dbx data, or - perhaps read a pair (FILENUM, TYPENUM) in parentheses. Just a - single number N is equivalent to (0,N). Return the two numbers by - storing them in the vector TYPENUMS. */ - -static boolean -parse_stab_type_number (pp, typenums) - const char **pp; - int *typenums; -{ - const char *orig; - - orig = *pp; - - if (**pp != '(') - { - typenums[0] = 0; - typenums[1] = (int) parse_number (pp, (boolean *) NULL); - } - else - { - ++*pp; - typenums[0] = (int) parse_number (pp, (boolean *) NULL); - if (**pp != ',') - { - bad_stab (orig); - return false; - } - ++*pp; - typenums[1] = (int) parse_number (pp, (boolean *) NULL); - if (**pp != ')') - { - bad_stab (orig); - return false; - } - ++*pp; - } - - return true; -} - -/* Parse a range type. */ - -static debug_type -parse_stab_range_type (dhandle, info, typename, pp, typenums) - PTR dhandle; - struct stab_handle *info; - const char *typename; - const char **pp; - const int *typenums; -{ - const char *orig; - int rangenums[2]; - boolean self_subrange; - debug_type index_type; - const char *s2, *s3; - bfd_signed_vma n2, n3; - boolean ov2, ov3; - - orig = *pp; - - index_type = DEBUG_TYPE_NULL; - - /* First comes a type we are a subrange of. - In C it is usually 0, 1 or the type being defined. */ - if (! parse_stab_type_number (pp, rangenums)) - return DEBUG_TYPE_NULL; - - self_subrange = (rangenums[0] == typenums[0] - && rangenums[1] == typenums[1]); - - if (**pp == '=') - { - *pp = orig; - index_type = parse_stab_type (dhandle, info, (const char *) NULL, - pp, (debug_type **) NULL); - if (index_type == DEBUG_TYPE_NULL) - return DEBUG_TYPE_NULL; - } - - if (**pp == ';') - ++*pp; - - /* The remaining two operands are usually lower and upper bounds of - the range. But in some special cases they mean something else. */ - s2 = *pp; - n2 = parse_number (pp, &ov2); - if (**pp != ';') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - ++*pp; - - s3 = *pp; - n3 = parse_number (pp, &ov3); - if (**pp != ';') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - ++*pp; - - if (ov2 || ov3) - { - /* gcc will emit range stabs for long long types. Handle this - as a special case. FIXME: This needs to be more general. */ -#define LLLOW "01000000000000000000000;" -#define LLHIGH "0777777777777777777777;" -#define ULLHIGH "01777777777777777777777;" - if (index_type == DEBUG_TYPE_NULL) - { - if (strncmp (s2, LLLOW, sizeof LLLOW - 1) == 0 - && strncmp (s3, LLHIGH, sizeof LLHIGH - 1) == 0) - return debug_make_int_type (dhandle, 8, false); - if (! ov2 - && n2 == 0 - && strncmp (s3, ULLHIGH, sizeof ULLHIGH - 1) == 0) - return debug_make_int_type (dhandle, 8, true); - } - - warn_stab (orig, "numeric overflow"); - } - - if (index_type == DEBUG_TYPE_NULL) - { - /* A type defined as a subrange of itself, with both bounds 0, - is void. */ - if (self_subrange && n2 == 0 && n3 == 0) - return debug_make_void_type (dhandle); - - /* A type defined as a subrange of itself, with n2 positive and - n3 zero, is a complex type, and n2 is the number of bytes. */ - if (self_subrange && n3 == 0 && n2 > 0) - return debug_make_complex_type (dhandle, n2); - - /* If n3 is zero and n2 is positive, this is a floating point - type, and n2 is the number of bytes. */ - if (n3 == 0 && n2 > 0) - return debug_make_float_type (dhandle, n2); - - /* If the upper bound is -1, this is an unsigned int. */ - if (n2 == 0 && n3 == -1) - { - /* When gcc is used with -gstabs, but not -gstabs+, it will emit - long long int:t6=r1;0;-1; - long long unsigned int:t7=r1;0;-1; - We hack here to handle this reasonably. */ - if (typename != NULL) - { - if (strcmp (typename, "long long int") == 0) - return debug_make_int_type (dhandle, 8, false); - else if (strcmp (typename, "long long unsigned int") == 0) - return debug_make_int_type (dhandle, 8, true); - } - /* FIXME: The size here really depends upon the target. */ - return debug_make_int_type (dhandle, 4, true); - } - - /* A range of 0 to 127 is char. */ - if (self_subrange && n2 == 0 && n3 == 127) - return debug_make_int_type (dhandle, 1, false); - - /* FIXME: gdb checks for the language CHILL here. */ - - if (n2 == 0) - { - if (n3 < 0) - return debug_make_int_type (dhandle, - n3, true); - else if (n3 == 0xff) - return debug_make_int_type (dhandle, 1, true); - else if (n3 == 0xffff) - return debug_make_int_type (dhandle, 2, true); - /* -1 is used for the upper bound of (4 byte) "unsigned int" - and "unsigned long", and we already checked for that, so - don't need to test for it here. */ - } - else if (n3 == 0 - && n2 < 0 - && (self_subrange || n2 == -8)) - return debug_make_int_type (dhandle, - n2, true); - else if (n2 == - n3 - 1) - { - if (n3 == 0x7f) - return debug_make_int_type (dhandle, 1, false); - else if (n3 == 0x7fff) - return debug_make_int_type (dhandle, 2, false); - else if (n3 == 0x7fffffff) - return debug_make_int_type (dhandle, 4, false); - } - } - - /* At this point I don't have the faintest idea how to deal with a - self_subrange type; I'm going to assume that this is used as an - idiom, and that all of them are special cases. So . . . */ - if (self_subrange) - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - - index_type = stab_find_type (dhandle, info, rangenums); - if (index_type == DEBUG_TYPE_NULL) - { - /* Does this actually ever happen? Is that why we are worrying - about dealing with it rather than just calling error_type? */ - warn_stab (orig, "missing index type"); - index_type = debug_make_int_type (dhandle, 4, false); - } - - return debug_make_range_type (dhandle, index_type, n2, n3); -} - -/* Sun's ACC uses a somewhat saner method for specifying the builtin - typedefs in every file (for int, long, etc): - - type = b ; ; - signed = u or s. Possible c in addition to u or s (for char?). - offset = offset from high order bit to start bit of type. - width is # bytes in object of this type, nbits is # bits in type. - - The width/offset stuff appears to be for small objects stored in - larger ones (e.g. `shorts' in `int' registers). We ignore it for now, - FIXME. */ - -static debug_type -parse_stab_sun_builtin_type (dhandle, pp) - PTR dhandle; - const char **pp; -{ - const char *orig; - boolean unsignedp; - bfd_vma bits; - - orig = *pp; - - switch (**pp) - { - case 's': - unsignedp = false; - break; - case 'u': - unsignedp = true; - break; - default: - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - ++*pp; - - /* For some odd reason, all forms of char put a c here. This is strange - because no other type has this honor. We can safely ignore this because - we actually determine 'char'acterness by the number of bits specified in - the descriptor. */ - if (**pp == 'c') - ++*pp; - - /* The first number appears to be the number of bytes occupied - by this type, except that unsigned short is 4 instead of 2. - Since this information is redundant with the third number, - we will ignore it. */ - (void) parse_number (pp, (boolean *) NULL); - if (**pp != ';') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - ++*pp; - - /* The second number is always 0, so ignore it too. */ - (void) parse_number (pp, (boolean *) NULL); - if (**pp != ';') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - ++*pp; - - /* The third number is the number of bits for this type. */ - bits = parse_number (pp, (boolean *) NULL); - - /* The type *should* end with a semicolon. If it are embedded - in a larger type the semicolon may be the only way to know where - the type ends. If this type is at the end of the stabstring we - can deal with the omitted semicolon (but we don't have to like - it). Don't bother to complain(), Sun's compiler omits the semicolon - for "void". */ - if (**pp == ';') - ++*pp; - - if (bits == 0) - return debug_make_void_type (dhandle); - - return debug_make_int_type (dhandle, bits / 8, unsignedp); -} - -/* Parse a builtin floating type generated by the Sun compiler. */ - -static debug_type -parse_stab_sun_floating_type (dhandle, pp) - PTR dhandle; - const char **pp; -{ - const char *orig; - bfd_vma details; - bfd_vma bytes; - - orig = *pp; - - /* The first number has more details about the type, for example - FN_COMPLEX. */ - details = parse_number (pp, (boolean *) NULL); - if (**pp != ';') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - - /* The second number is the number of bytes occupied by this type */ - bytes = parse_number (pp, (boolean *) NULL); - if (**pp != ';') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - - if (details == NF_COMPLEX - || details == NF_COMPLEX16 - || details == NF_COMPLEX32) - return debug_make_complex_type (dhandle, bytes); - - return debug_make_float_type (dhandle, bytes); -} - -/* Handle an enum type. */ - -static debug_type -parse_stab_enum_type (dhandle, pp) - PTR dhandle; - const char **pp; -{ - const char *orig; - const char **names; - bfd_signed_vma *values; - unsigned int n; - unsigned int alloc; - - orig = *pp; - - /* FIXME: gdb checks os9k_stabs here. */ - - /* The aix4 compiler emits an extra field before the enum members; - my guess is it's a type of some sort. Just ignore it. */ - if (**pp == '-') - { - while (**pp != ':') - ++*pp; - ++*pp; - } - - /* Read the value-names and their values. - The input syntax is NAME:VALUE,NAME:VALUE, and so on. - A semicolon or comma instead of a NAME means the end. */ - alloc = 10; - names = (const char **) xmalloc (alloc * sizeof *names); - values = (bfd_signed_vma *) xmalloc (alloc * sizeof *values); - n = 0; - while (**pp != '\0' && **pp != ';' && **pp != ',') - { - const char *p; - char *name; - bfd_signed_vma val; - - p = *pp; - while (*p != ':') - ++p; - - name = savestring (*pp, p - *pp); - - *pp = p + 1; - val = (bfd_signed_vma) parse_number (pp, (boolean *) NULL); - if (**pp != ',') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - ++*pp; - - if (n + 1 >= alloc) - { - alloc += 10; - names = ((const char **) - xrealloc ((PTR) names, alloc * sizeof *names)); - values = ((bfd_signed_vma *) - xrealloc ((PTR) values, alloc * sizeof *values)); - } - - names[n] = name; - values[n] = val; - ++n; - } - - names[n] = NULL; - values[n] = 0; - - if (**pp == ';') - ++*pp; - - return debug_make_enum_type (dhandle, names, values); -} - -/* Read the description of a structure (or union type) and return an object - describing the type. - - PP points to a character pointer that points to the next unconsumed token - in the the stabs string. For example, given stabs "A:T4=s4a:1,0,32;;", - *PP will point to "4a:1,0,32;;". */ - -static debug_type -parse_stab_struct_type (dhandle, info, tagname, pp, structp, typenums) - PTR dhandle; - struct stab_handle *info; - const char *tagname; - const char **pp; - boolean structp; - const int *typenums; -{ - const char *orig; - bfd_vma size; - debug_baseclass *baseclasses; - debug_field *fields; - boolean statics; - debug_method *methods; - debug_type vptrbase; - boolean ownvptr; - - orig = *pp; - - /* Get the size. */ - size = parse_number (pp, (boolean *) NULL); - - /* Get the other information. */ - if (! parse_stab_baseclasses (dhandle, info, pp, &baseclasses) - || ! parse_stab_struct_fields (dhandle, info, pp, &fields, &statics) - || ! parse_stab_members (dhandle, info, tagname, pp, typenums, &methods) - || ! parse_stab_tilde_field (dhandle, info, pp, typenums, &vptrbase, - &ownvptr)) - return DEBUG_TYPE_NULL; - - if (! statics - && baseclasses == NULL - && methods == NULL - && vptrbase == DEBUG_TYPE_NULL - && ! ownvptr) - return debug_make_struct_type (dhandle, structp, size, fields); - - return debug_make_object_type (dhandle, structp, size, fields, baseclasses, - methods, vptrbase, ownvptr); -} - -/* The stabs for C++ derived classes contain baseclass information which - is marked by a '!' character after the total size. This function is - called when we encounter the baseclass marker, and slurps up all the - baseclass information. - - Immediately following the '!' marker is the number of base classes that - the class is derived from, followed by information for each base class. - For each base class, there are two visibility specifiers, a bit offset - to the base class information within the derived class, a reference to - the type for the base class, and a terminating semicolon. - - A typical example, with two base classes, would be "!2,020,19;0264,21;". - ^^ ^ ^ ^ ^ ^ ^ - Baseclass information marker __________________|| | | | | | | - Number of baseclasses __________________________| | | | | | | - Visibility specifiers (2) ________________________| | | | | | - Offset in bits from start of class _________________| | | | | - Type number for base class ___________________________| | | | - Visibility specifiers (2) _______________________________| | | - Offset in bits from start of class ________________________| | - Type number of base class ____________________________________| - - Return true for success, false for failure. */ - -static boolean -parse_stab_baseclasses (dhandle, info, pp, retp) - PTR dhandle; - struct stab_handle *info; - const char **pp; - debug_baseclass **retp; -{ - const char *orig; - unsigned int c, i; - debug_baseclass *classes; - - *retp = NULL; - - orig = *pp; - - if (**pp != '!') - { - /* No base classes. */ - return true; - } - ++*pp; - - c = (unsigned int) parse_number (pp, (boolean *) NULL); - - if (**pp != ',') - { - bad_stab (orig); - return false; - } - ++*pp; - - classes = (debug_baseclass *) xmalloc ((c + 1) * sizeof (**retp)); - - for (i = 0; i < c; i++) - { - boolean virtual; - enum debug_visibility visibility; - bfd_vma bitpos; - debug_type type; - - switch (**pp) - { - case '0': - virtual = false; - break; - case '1': - virtual = true; - break; - default: - warn_stab (orig, "unknown virtual character for baseclass"); - virtual = false; - break; - } - ++*pp; - - switch (**pp) - { - case '0': - visibility = DEBUG_VISIBILITY_PRIVATE; - break; - case '1': - visibility = DEBUG_VISIBILITY_PROTECTED; - break; - case '2': - visibility = DEBUG_VISIBILITY_PUBLIC; - break; - default: - warn_stab (orig, "unknown visibility character for baseclass"); - visibility = DEBUG_VISIBILITY_PUBLIC; - break; - } - ++*pp; - - /* The remaining value is the bit offset of the portion of the - object corresponding to this baseclass. Always zero in the - absence of multiple inheritance. */ - bitpos = parse_number (pp, (boolean *) NULL); - if (**pp != ',') - { - bad_stab (orig); - return false; - } - ++*pp; - - type = parse_stab_type (dhandle, info, (const char *) NULL, pp, - (debug_type **) NULL); - if (type == DEBUG_TYPE_NULL) - return false; - - classes[i] = debug_make_baseclass (dhandle, type, bitpos, virtual, - visibility); - if (classes[i] == DEBUG_BASECLASS_NULL) - return false; - - if (**pp != ';') - return false; - ++*pp; - } - - classes[i] = DEBUG_BASECLASS_NULL; - - *retp = classes; - - return true; -} - -/* Read struct or class data fields. They have the form: - - NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ; - - At the end, we see a semicolon instead of a field. - - In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for - a static field. - - The optional VISIBILITY is one of: - - '/0' (VISIBILITY_PRIVATE) - '/1' (VISIBILITY_PROTECTED) - '/2' (VISIBILITY_PUBLIC) - '/9' (VISIBILITY_IGNORE) - - or nothing, for C style fields with public visibility. - - Returns 1 for success, 0 for failure. */ - -static boolean -parse_stab_struct_fields (dhandle, info, pp, retp, staticsp) - PTR dhandle; - struct stab_handle *info; - const char **pp; - debug_field **retp; - boolean *staticsp; -{ - const char *orig; - const char *p; - debug_field *fields; - unsigned int c; - unsigned int alloc; - - *retp = NULL; - *staticsp = false; - - orig = *pp; - - c = 0; - alloc = 10; - fields = (debug_field *) xmalloc (alloc * sizeof *fields); - while (**pp != ';') - { - /* FIXME: gdb checks os9k_stabs here. */ - - p = *pp; - - /* Add 1 to c to leave room for NULL pointer at end. */ - if (c + 1 >= alloc) - { - alloc += 10; - fields = ((debug_field *) - xrealloc ((PTR) fields, alloc * sizeof *fields)); - } - - /* If it starts with CPLUS_MARKER it is a special abbreviation, - unless the CPLUS_MARKER is followed by an underscore, in - which case it is just the name of an anonymous type, which we - should handle like any other type name. We accept either '$' - or '.', because a field name can never contain one of these - characters except as a CPLUS_MARKER. */ - - if ((*p == '$' || *p == '.') && p[1] != '_') - { - ++*pp; - if (! parse_stab_cpp_abbrev (dhandle, info, pp, fields + c)) - return false; - ++c; - continue; - } - - /* Look for the ':' that separates the field name from the field - values. Data members are delimited by a single ':', while member - functions are delimited by a pair of ':'s. When we hit the member - functions (if any), terminate scan loop and return. */ - - p = strchr (p, ':'); - if (p == NULL) - { - bad_stab (orig); - return false; - } - - if (p[1] == ':') - break; - - if (! parse_stab_one_struct_field (dhandle, info, pp, p, fields + c, - staticsp)) - return false; - - ++c; - } - - fields[c] = DEBUG_FIELD_NULL; - - *retp = fields; - - return true; -} - -/* Special GNU C++ name. */ - -static boolean -parse_stab_cpp_abbrev (dhandle, info, pp, retp) - PTR dhandle; - struct stab_handle *info; - const char **pp; - debug_field *retp; -{ - const char *orig; - int cpp_abbrev; - debug_type context; - const char *name; - const char *typename; - debug_type type; - bfd_vma bitpos; - - *retp = DEBUG_FIELD_NULL; - - orig = *pp; - - if (**pp != 'v') - { - bad_stab (*pp); - return false; - } - ++*pp; - - cpp_abbrev = **pp; - ++*pp; - - /* At this point, *pp points to something like "22:23=*22...", where - the type number before the ':' is the "context" and everything - after is a regular type definition. Lookup the type, find it's - name, and construct the field name. */ - - context = parse_stab_type (dhandle, info, (const char *) NULL, pp, - (debug_type **) NULL); - if (context == DEBUG_TYPE_NULL) - return false; - - switch (cpp_abbrev) - { - case 'f': - /* $vf -- a virtual function table pointer. */ - name = "_vptr$"; - break; - case 'b': - /* $vb -- a virtual bsomethingorother */ - typename = debug_get_type_name (dhandle, context); - if (typename == NULL) - { - warn_stab (orig, "unnamed $vb type"); - typename = "FOO"; - } - name = concat ("_vb$", typename, (const char *) NULL); - break; - default: - warn_stab (orig, "unrecognized C++ abbreviation"); - name = "INVALID_CPLUSPLUS_ABBREV"; - break; - } - - if (**pp != ':') - { - bad_stab (orig); - return false; - } - ++*pp; - - type = parse_stab_type (dhandle, info, (const char *) NULL, pp, - (debug_type **) NULL); - if (**pp != ',') - { - bad_stab (orig); - return false; - } - ++*pp; - - bitpos = parse_number (pp, (boolean *) NULL); - if (**pp != ';') - { - bad_stab (orig); - return false; - } - ++*pp; - - *retp = debug_make_field (dhandle, name, type, bitpos, 0, - DEBUG_VISIBILITY_PRIVATE); - if (*retp == DEBUG_FIELD_NULL) - return false; - - return true; -} - -/* Parse a single field in a struct or union. */ - -static boolean -parse_stab_one_struct_field (dhandle, info, pp, p, retp, staticsp) - PTR dhandle; - struct stab_handle *info; - const char **pp; - const char *p; - debug_field *retp; - boolean *staticsp; -{ - const char *orig; - char *name; - enum debug_visibility visibility; - debug_type type; - bfd_vma bitpos; - bfd_vma bitsize; - - orig = *pp; - - /* FIXME: gdb checks ARM_DEMANGLING here. */ - - name = savestring (*pp, p - *pp); - - *pp = p + 1; - - if (**pp != '/') - visibility = DEBUG_VISIBILITY_PUBLIC; - else - { - ++*pp; - switch (**pp) - { - case '0': - visibility = DEBUG_VISIBILITY_PRIVATE; - break; - case '1': - visibility = DEBUG_VISIBILITY_PROTECTED; - break; - case '2': - visibility = DEBUG_VISIBILITY_PUBLIC; - break; - default: - warn_stab (orig, "unknown visibility character for field"); - visibility = DEBUG_VISIBILITY_PUBLIC; - break; - } - ++*pp; - } - - type = parse_stab_type (dhandle, info, (const char *) NULL, pp, - (debug_type **) NULL); - if (type == DEBUG_TYPE_NULL) - return false; - - if (**pp == ':') - { - char *varname; - - /* This is a static class member. */ - ++*pp; - p = strchr (*pp, ';'); - if (p == NULL) - { - bad_stab (orig); - return false; - } - - varname = savestring (*pp, p - *pp); - - *pp = p + 1; - - *retp = debug_make_static_member (dhandle, name, type, varname, - visibility); - *staticsp = true; - - return true; - } - - if (**pp != ',') - { - bad_stab (orig); - return false; - } - ++*pp; - - bitpos = parse_number (pp, (boolean *) NULL); - if (**pp != ',') - { - bad_stab (orig); - return false; - } - ++*pp; - - bitsize = parse_number (pp, (boolean *) NULL); - if (**pp != ';') - { - bad_stab (orig); - return false; - } - ++*pp; - - if (bitpos == 0 && bitsize == 0) - { - /* This can happen in two cases: (1) at least for gcc 2.4.5 or - so, it is a field which has been optimized out. The correct - stab for this case is to use VISIBILITY_IGNORE, but that is a - recent invention. (2) It is a 0-size array. For example - union { int num; char str[0]; } foo. Printing "" - for str in "p foo" is OK, since foo.str (and thus foo.str[3]) - will continue to work, and a 0-size array as a whole doesn't - have any contents to print. - - I suspect this probably could also happen with gcc -gstabs - (not -gstabs+) for static fields, and perhaps other C++ - extensions. Hopefully few people use -gstabs with gdb, since - it is intended for dbx compatibility. */ - visibility = DEBUG_VISIBILITY_IGNORE; - } - - /* FIXME: gdb does some stuff here to mark fields as unpacked. */ - - *retp = debug_make_field (dhandle, name, type, bitpos, bitsize, visibility); - - return true; -} - -/* Read member function stabs info for C++ classes. The form of each member - function data is: - - NAME :: TYPENUM[=type definition] ARGS : PHYSNAME ; - - An example with two member functions is: - - afunc1::20=##15;:i;2A.;afunc2::20:i;2A.; - - For the case of overloaded operators, the format is op$::*.funcs, where - $ is the CPLUS_MARKER (usually '$'), `*' holds the place for an operator - name (such as `+=') and `.' marks the end of the operator name. */ - -static boolean -parse_stab_members (dhandle, info, tagname, pp, typenums, retp) - PTR dhandle; - struct stab_handle *info; - const char *tagname; - const char **pp; - const int *typenums; - debug_method **retp; -{ - const char *orig; - debug_method *methods; - unsigned int c; - unsigned int alloc; - - *retp = NULL; - - orig = *pp; - - alloc = 0; - methods = NULL; - c = 0; - - while (**pp != ';') - { - const char *p; - char *name; - debug_method_variant *variants; - unsigned int cvars; - unsigned int allocvars; - debug_type look_ahead_type; - - p = strchr (*pp, ':'); - if (p == NULL || p[1] != ':') - break; - - /* FIXME: Some systems use something other than '$' here. */ - if ((*pp)[0] != 'o' || (*pp)[1] != 'p' || (*pp)[2] != '$') - { - name = savestring (*pp, p - *pp); - *pp = p + 2; - } - else - { - /* This is a completely wierd case. In order to stuff in the - names that might contain colons (the usual name delimiter), - Mike Tiemann defined a different name format which is - signalled if the identifier is "op$". In that case, the - format is "op$::XXXX." where XXXX is the name. This is - used for names like "+" or "=". YUUUUUUUK! FIXME! */ - *pp = p + 2; - for (p = *pp; *p != '.' && *p != '\0'; p++) - ; - if (*p != '.') - { - bad_stab (orig); - return false; - } - name = savestring (*pp, p - *pp); - *pp = p + 1; - } - - allocvars = 10; - variants = ((debug_method_variant *) - xmalloc (allocvars * sizeof *variants)); - cvars = 0; - - look_ahead_type = DEBUG_TYPE_NULL; - - do - { - debug_type type; - boolean stub; - char *argtypes; - enum debug_visibility visibility; - boolean constp, volatilep, staticp; - bfd_vma voffset; - debug_type context; - const char *physname; - boolean varargs; - - if (look_ahead_type != DEBUG_TYPE_NULL) - { - /* g++ version 1 kludge */ - type = look_ahead_type; - look_ahead_type = DEBUG_TYPE_NULL; - } - else - { - type = parse_stab_type (dhandle, info, (const char *) NULL, pp, - (debug_type **) NULL); - if (type == DEBUG_TYPE_NULL) - return false; - if (**pp != ':') - { - bad_stab (orig); - return false; - } - } - - ++*pp; - p = strchr (*pp, ';'); - if (p == NULL) - { - bad_stab (orig); - return false; - } - - stub = false; - if (debug_get_type_kind (dhandle, type) == DEBUG_KIND_METHOD - && debug_get_parameter_types (dhandle, type, &varargs) == NULL) - stub = true; - - argtypes = savestring (*pp, p - *pp); - *pp = p + 1; - - switch (**pp) - { - case '0': - visibility = DEBUG_VISIBILITY_PRIVATE; - break; - case '1': - visibility = DEBUG_VISIBILITY_PROTECTED; - break; - default: - visibility = DEBUG_VISIBILITY_PUBLIC; - break; - } - ++*pp; - - constp = false; - volatilep = false; - switch (**pp) - { - case 'A': - /* Normal function. */ - ++*pp; - break; - case 'B': - /* const member function. */ - constp = true; - ++*pp; - break; - case 'C': - /* volatile member function. */ - volatilep = true; - ++*pp; - break; - case 'D': - /* const volatile member function. */ - constp = true; - volatilep = true; - ++*pp; - break; - case '*': - case '?': - case '.': - /* File compiled with g++ version 1; no information. */ - break; - default: - warn_stab (orig, "const/volatile indicator missing"); - break; - } - - staticp = false; - switch (**pp) - { - case '*': - /* virtual member function, followed by index. The sign - bit is supposedly set to distinguish - pointers-to-methods from virtual function indicies. */ - ++*pp; - voffset = parse_number (pp, (boolean *) NULL); - if (**pp != ';') - { - bad_stab (orig); - return false; - } - ++*pp; - voffset &= 0x7fffffff; - - if (**pp == ';' || *pp == '\0') - { - /* Must be g++ version 1. */ - context = DEBUG_TYPE_NULL; - } - else - { - /* Figure out from whence this virtual function - came. It may belong to virtual function table of - one of its baseclasses. */ - look_ahead_type = parse_stab_type (dhandle, info, - (const char *) NULL, - pp, - (debug_type **) NULL); - if (**pp == ':') - { - /* g++ version 1 overloaded methods. */ - context = DEBUG_TYPE_NULL; - } - else - { - context = look_ahead_type; - look_ahead_type = DEBUG_TYPE_NULL; - if (**pp != ';') - { - bad_stab (orig); - return false; - } - ++*pp; - } - } - break; - - case '?': - /* static member function. */ - ++*pp; - staticp = true; - voffset = 0; - context = DEBUG_TYPE_NULL; - if (strncmp (argtypes, name, strlen (name)) != 0) - stub = true; - break; - - default: - warn_stab (orig, "member function type missing"); - voffset = 0; - context = DEBUG_TYPE_NULL; - break; - - case '.': - ++*pp; - voffset = 0; - context = DEBUG_TYPE_NULL; - break; - } - - /* If the type is not a stub, then the argtypes string is - the physical name of the function. Otherwise the - argtypes string is the mangled form of the argument - types, and the full type and the physical name must be - extracted from them. */ - if (! stub) - physname = argtypes; - else - { - debug_type class_type, return_type; - - class_type = stab_find_type (dhandle, info, typenums); - if (class_type == DEBUG_TYPE_NULL) - return false; - return_type = debug_get_return_type (dhandle, type); - if (return_type == DEBUG_TYPE_NULL) - { - bad_stab (orig); - return false; - } - type = parse_stab_argtypes (dhandle, info, class_type, name, - tagname, return_type, argtypes, - constp, volatilep, &physname); - if (type == DEBUG_TYPE_NULL) - return false; - } - - if (cvars + 1 >= allocvars) - { - allocvars += 10; - variants = ((debug_method_variant *) - xrealloc ((PTR) variants, - allocvars * sizeof *variants)); - } - - if (! staticp) - variants[cvars] = debug_make_method_variant (dhandle, physname, - type, visibility, - constp, volatilep, - voffset, context); - else - variants[cvars] = debug_make_static_method_variant (dhandle, - physname, - type, - visibility, - constp, - volatilep); - if (variants[cvars] == DEBUG_METHOD_VARIANT_NULL) - return false; - - ++cvars; - } - while (**pp != ';' && **pp != '\0'); - - variants[cvars] = DEBUG_METHOD_VARIANT_NULL; - - if (**pp != '\0') - ++*pp; - - if (c + 1 >= alloc) - { - alloc += 10; - methods = ((debug_method *) - xrealloc ((PTR) methods, alloc * sizeof *methods)); - } - - methods[c] = debug_make_method (dhandle, name, variants); - - ++c; - } - - if (methods != NULL) - methods[c] = DEBUG_METHOD_NULL; - - *retp = methods; - - return true; -} - -/* Parse a string representing argument types for a method. Stabs - tries to save space by packing argument types into a mangled - string. This string should give us enough information to extract - both argument types and the physical name of the function, given - the tag name. */ - -static debug_type -parse_stab_argtypes (dhandle, info, class_type, fieldname, tagname, - return_type, argtypes, constp, volatilep, pphysname) - PTR dhandle; - struct stab_handle *info; - debug_type class_type; - const char *fieldname; - const char *tagname; - debug_type return_type; - const char *argtypes; - boolean constp; - boolean volatilep; - const char **pphysname; -{ - boolean is_full_physname_constructor; - boolean is_constructor; - boolean is_destructor; - debug_type *args; - boolean varargs; - - /* Constructors are sometimes handled specially. */ - is_full_physname_constructor = ((argtypes[0] == '_' - && argtypes[1] == '_' - && (isdigit ((unsigned char) argtypes[2]) - || argtypes[2] == 'Q' - || argtypes[2] == 't')) - || strncmp (argtypes, "__ct", 4) == 0); - - is_constructor = (is_full_physname_constructor - || (tagname != NULL - && strcmp (fieldname, tagname) == 0)); - is_destructor = ((argtypes[0] == '_' - && (argtypes[1] == '$' || argtypes[1] == '.') - && argtypes[2] == '_') - || strncmp (argtypes, "__dt", 4) == 0); - - if (is_destructor || is_full_physname_constructor) - *pphysname = argtypes; - else - { - unsigned int len; - const char *const_prefix; - const char *volatile_prefix; - char buf[20]; - unsigned int mangled_name_len; - char *physname; - - len = tagname == NULL ? 0 : strlen (tagname); - const_prefix = constp ? "C" : ""; - volatile_prefix = volatilep ? "V" : ""; - - if (len == 0) - sprintf (buf, "__%s%s", const_prefix, volatile_prefix); - else if (tagname != NULL && strchr (tagname, '<') != NULL) - { - /* Template methods are fully mangled. */ - sprintf (buf, "__%s%s", const_prefix, volatile_prefix); - tagname = NULL; - len = 0; - } - else - sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len); - - mangled_name_len = ((is_constructor ? 0 : strlen (fieldname)) - + strlen (buf) - + len - + strlen (argtypes) - + 1); - - if (fieldname[0] == 'o' - && fieldname[1] == 'p' - && (fieldname[2] == '$' || fieldname[2] == '.')) - { - const char *opname; - - opname = cplus_mangle_opname (fieldname + 3, 0); - if (opname == NULL) - { - fprintf (stderr, "No mangling for \"%s\"\n", fieldname); - return DEBUG_TYPE_NULL; - } - mangled_name_len += strlen (opname); - physname = (char *) xmalloc (mangled_name_len); - strncpy (physname, fieldname, 3); - strcpy (physname + 3, opname); - } - else - { - physname = (char *) xmalloc (mangled_name_len); - if (is_constructor) - physname[0] = '\0'; - else - strcpy (physname, fieldname); - } - - strcat (physname, buf); - if (tagname != NULL) - strcat (physname, tagname); - strcat (physname, argtypes); - - *pphysname = physname; - } - - if (*argtypes == '\0' || is_destructor) - { - args = (debug_type *) xmalloc (sizeof *args); - *args = NULL; - return debug_make_method_type (dhandle, return_type, class_type, args, - false); - } - - args = stab_demangle_argtypes (dhandle, info, *pphysname, &varargs); - if (args == NULL) - return DEBUG_TYPE_NULL; - - return debug_make_method_type (dhandle, return_type, class_type, args, - varargs); -} - -/* The tail end of stabs for C++ classes that contain a virtual function - pointer contains a tilde, a %, and a type number. - The type number refers to the base class (possibly this class itself) which - contains the vtable pointer for the current class. - - This function is called when we have parsed all the method declarations, - so we can look for the vptr base class info. */ - -static boolean -parse_stab_tilde_field (dhandle, info, pp, typenums, retvptrbase, retownvptr) - PTR dhandle; - struct stab_handle *info; - const char **pp; - const int *typenums; - debug_type *retvptrbase; - boolean *retownvptr; -{ - const char *orig; - const char *hold; - int vtypenums[2]; - - *retvptrbase = DEBUG_TYPE_NULL; - *retownvptr = false; - - orig = *pp; - - /* If we are positioned at a ';', then skip it. */ - if (**pp == ';') - ++*pp; - - if (**pp != '~') - return true; - - ++*pp; - - if (**pp == '=' || **pp == '+' || **pp == '-') - { - /* Obsolete flags that used to indicate the presence of - constructors and/or destructors. */ - ++*pp; - } - - if (**pp != '%') - return true; - - ++*pp; - - hold = *pp; - - /* The next number is the type number of the base class (possibly - our own class) which supplies the vtable for this class. */ - if (! parse_stab_type_number (pp, vtypenums)) - return false; - - if (vtypenums[0] == typenums[0] - && vtypenums[1] == typenums[1]) - *retownvptr = true; - else - { - debug_type vtype; - const char *p; - - *pp = hold; - - vtype = parse_stab_type (dhandle, info, (const char *) NULL, pp, - (debug_type **) NULL); - for (p = *pp; *p != ';' && *p != '\0'; p++) - ; - if (*p != ';') - { - bad_stab (orig); - return false; - } - - *retvptrbase = vtype; - - *pp = p + 1; - } - - return true; -} - -/* Read a definition of an array type. */ - -static debug_type -parse_stab_array_type (dhandle, info, pp, stringp) - PTR dhandle; - struct stab_handle *info; - const char **pp; - boolean stringp; -{ - const char *orig; - const char *p; - int typenums[2]; - debug_type index_type; - boolean adjustable; - bfd_signed_vma lower, upper; - debug_type element_type; - - /* Format of an array type: - "ar;lower;upper;". - OS9000: "arlower,upper;". - - Fortran adjustable arrays use Adigits or Tdigits for lower or upper; - for these, produce a type like float[][]. */ - - orig = *pp; - - /* FIXME: gdb checks os9k_stabs here. */ - - /* If the index type is type 0, we take it as int. */ - p = *pp; - if (! parse_stab_type_number (&p, typenums)) - return DEBUG_TYPE_NULL; - if (typenums[0] == 0 && typenums[1] == 0 && **pp != '=') - { - index_type = debug_find_named_type (dhandle, "int"); - if (index_type == DEBUG_TYPE_NULL) - { - index_type = debug_make_int_type (dhandle, 4, false); - if (index_type == DEBUG_TYPE_NULL) - return DEBUG_TYPE_NULL; - } - *pp = p; - } - else - { - index_type = parse_stab_type (dhandle, info, (const char *) NULL, pp, - (debug_type **) NULL); - } - - if (**pp != ';') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - ++*pp; - - adjustable = false; - - if (! isdigit ((unsigned char) **pp) && **pp != '-') - { - ++*pp; - adjustable = true; - } - - lower = (bfd_signed_vma) parse_number (pp, (boolean *) NULL); - if (**pp != ';') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - ++*pp; - - if (! isdigit ((unsigned char) **pp) && **pp != '-') - { - ++*pp; - adjustable = true; - } - - upper = (bfd_signed_vma) parse_number (pp, (boolean *) NULL); - if (**pp != ';') - { - bad_stab (orig); - return DEBUG_TYPE_NULL; - } - ++*pp; - - element_type = parse_stab_type (dhandle, info, (const char *) NULL, pp, - (debug_type **) NULL); - if (element_type == DEBUG_TYPE_NULL) - return DEBUG_TYPE_NULL; - - if (adjustable) - { - lower = 0; - upper = -1; - } - - return debug_make_array_type (dhandle, element_type, index_type, lower, - upper, stringp); -} - -/* This struct holds information about files we have seen using - N_BINCL. */ - -struct bincl_file -{ - /* The next N_BINCL file. */ - struct bincl_file *next; - /* The next N_BINCL on the stack. */ - struct bincl_file *next_stack; - /* The file name. */ - const char *name; - /* The hash value. */ - bfd_vma hash; - /* The file index. */ - unsigned int file; - /* The list of types defined in this file. */ - struct stab_types *file_types; -}; - -/* Start a new N_BINCL file, pushing it onto the stack. */ - -static void -push_bincl (info, name, hash) - struct stab_handle *info; - const char *name; - bfd_vma hash; -{ - struct bincl_file *n; - - n = (struct bincl_file *) xmalloc (sizeof *n); - n->next = info->bincl_list; - n->next_stack = info->bincl_stack; - n->name = name; - n->hash = hash; - n->file = info->files; - n->file_types = NULL; - info->bincl_list = n; - info->bincl_stack = n; - - ++info->files; - info->file_types = ((struct stab_types **) - xrealloc ((PTR) info->file_types, - (info->files - * sizeof *info->file_types))); - info->file_types[n->file] = NULL; -} - -/* Finish an N_BINCL file, at an N_EINCL, popping the name off the - stack. */ - -static const char * -pop_bincl (info) - struct stab_handle *info; -{ - struct bincl_file *o; - - o = info->bincl_stack; - if (o == NULL) - return info->main_filename; - info->bincl_stack = o->next_stack; - - o->file_types = info->file_types[o->file]; - - if (info->bincl_stack == NULL) - return info->main_filename; - return info->bincl_stack->name; -} - -/* Handle an N_EXCL: get the types from the corresponding N_BINCL. */ - -static boolean -find_excl (info, name, hash) - struct stab_handle *info; - const char *name; - bfd_vma hash; -{ - struct bincl_file *l; - - ++info->files; - info->file_types = ((struct stab_types **) - xrealloc ((PTR) info->file_types, - (info->files - * sizeof *info->file_types))); - - for (l = info->bincl_list; l != NULL; l = l->next) - if (l->hash == hash && strcmp (l->name, name) == 0) - break; - if (l == NULL) - { - warn_stab (name, "Undefined N_EXCL"); - info->file_types[info->files - 1] = NULL; - return true; - } - - info->file_types[info->files - 1] = l->file_types; - - return true; -} - -/* Handle a variable definition. gcc emits variable definitions for a - block before the N_LBRAC, so we must hold onto them until we see - it. The SunPRO compiler emits variable definitions after the - N_LBRAC, so we can call debug_record_variable immediately. */ - -static boolean -stab_record_variable (dhandle, info, name, type, kind, val) - PTR dhandle; - struct stab_handle *info; - const char *name; - debug_type type; - enum debug_var_kind kind; - bfd_vma val; -{ - struct stab_pending_var *v; - - if ((kind == DEBUG_GLOBAL || kind == DEBUG_STATIC) - || ! info->within_function - || (info->gcc_compiled == 0 && info->n_opt_found)) - return debug_record_variable (dhandle, name, type, kind, val); - - v = (struct stab_pending_var *) xmalloc (sizeof *v); - memset (v, 0, sizeof *v); - - v->next = info->pending; - v->name = name; - v->type = type; - v->kind = kind; - v->val = val; - info->pending = v; - - return true; -} - -/* Emit pending variable definitions. This is called after we see the - N_LBRAC that starts the block. */ - -static boolean -stab_emit_pending_vars (dhandle, info) - PTR dhandle; - struct stab_handle *info; -{ - struct stab_pending_var *v; - - v = info->pending; - while (v != NULL) - { - struct stab_pending_var *next; - - if (! debug_record_variable (dhandle, v->name, v->type, v->kind, v->val)) - return false; - - next = v->next; - free (v); - v = next; - } - - info->pending = NULL; - - return true; -} - -/* Find the slot for a type in the database. */ - -static debug_type * -stab_find_slot (info, typenums) - struct stab_handle *info; - const int *typenums; -{ - int filenum; - int index; - struct stab_types **ps; - - filenum = typenums[0]; - index = typenums[1]; - - if (filenum < 0 || (unsigned int) filenum >= info->files) - { - fprintf (stderr, "Type file number %d out of range\n", filenum); - return NULL; - } - if (index < 0) - { - fprintf (stderr, "Type index number %d out of range\n", index); - return NULL; - } - - ps = info->file_types + filenum; - - while (index >= STAB_TYPES_SLOTS) - { - if (*ps == NULL) - { - *ps = (struct stab_types *) xmalloc (sizeof **ps); - memset (*ps, 0, sizeof **ps); - } - ps = &(*ps)->next; - index -= STAB_TYPES_SLOTS; - } - if (*ps == NULL) - { - *ps = (struct stab_types *) xmalloc (sizeof **ps); - memset (*ps, 0, sizeof **ps); - } - - return (*ps)->types + index; -} - -/* Find a type given a type number. If the type has not been - allocated yet, create an indirect type. */ - -static debug_type -stab_find_type (dhandle, info, typenums) - PTR dhandle; - struct stab_handle *info; - const int *typenums; -{ - debug_type *slot; - - if (typenums[0] == 0 && typenums[1] < 0) - { - /* A negative type number indicates an XCOFF builtin type. */ - return stab_xcoff_builtin_type (dhandle, info, typenums[1]); - } - - slot = stab_find_slot (info, typenums); - if (slot == NULL) - return DEBUG_TYPE_NULL; - - if (*slot == DEBUG_TYPE_NULL) - return debug_make_indirect_type (dhandle, slot, (const char *) NULL); - - return *slot; -} - -/* Record that a given type number refers to a given type. */ - -static boolean -stab_record_type (dhandle, info, typenums, type) - PTR dhandle; - struct stab_handle *info; - const int *typenums; - debug_type type; -{ - debug_type *slot; - - slot = stab_find_slot (info, typenums); - if (slot == NULL) - return false; - - /* gdb appears to ignore type redefinitions, so we do as well. */ - - *slot = type; - - return true; -} - -/* Return an XCOFF builtin type. */ - -static debug_type -stab_xcoff_builtin_type (dhandle, info, typenum) - PTR dhandle; - struct stab_handle *info; - int typenum; -{ - debug_type rettype; - const char *name; - - if (typenum >= 0 || typenum < -XCOFF_TYPE_COUNT) - { - fprintf (stderr, "Unrecognized XCOFF type %d\n", typenum); - return DEBUG_TYPE_NULL; - } - if (info->xcoff_types[-typenum] != NULL) - return info->xcoff_types[-typenum]; - - switch (-typenum) - { - case 1: - /* The size of this and all the other types are fixed, defined - by the debugging format. */ - name = "int"; - rettype = debug_make_int_type (dhandle, 4, false); - break; - case 2: - name = "char"; - rettype = debug_make_int_type (dhandle, 1, false); - break; - case 3: - name = "short"; - rettype = debug_make_int_type (dhandle, 2, false); - break; - case 4: - name = "long"; - rettype = debug_make_int_type (dhandle, 4, false); - break; - case 5: - name = "unsigned char"; - rettype = debug_make_int_type (dhandle, 1, true); - break; - case 6: - name = "signed char"; - rettype = debug_make_int_type (dhandle, 1, false); - break; - case 7: - name = "unsigned short"; - rettype = debug_make_int_type (dhandle, 2, true); - break; - case 8: - name = "unsigned int"; - rettype = debug_make_int_type (dhandle, 4, true); - break; - case 9: - name = "unsigned"; - rettype = debug_make_int_type (dhandle, 4, true); - case 10: - name = "unsigned long"; - rettype = debug_make_int_type (dhandle, 4, true); - break; - case 11: - name = "void"; - rettype = debug_make_void_type (dhandle); - break; - case 12: - /* IEEE single precision (32 bit). */ - name = "float"; - rettype = debug_make_float_type (dhandle, 4); - break; - case 13: - /* IEEE double precision (64 bit). */ - name = "double"; - rettype = debug_make_float_type (dhandle, 8); - break; - case 14: - /* This is an IEEE double on the RS/6000, and different machines - with different sizes for "long double" should use different - negative type numbers. See stabs.texinfo. */ - name = "long double"; - rettype = debug_make_float_type (dhandle, 8); - break; - case 15: - name = "integer"; - rettype = debug_make_int_type (dhandle, 4, false); - break; - case 16: - name = "boolean"; - rettype = debug_make_bool_type (dhandle, 4); - break; - case 17: - name = "short real"; - rettype = debug_make_float_type (dhandle, 4); - break; - case 18: - name = "real"; - rettype = debug_make_float_type (dhandle, 8); - break; - case 19: - /* FIXME */ - name = "stringptr"; - rettype = NULL; - break; - case 20: - /* FIXME */ - name = "character"; - rettype = debug_make_int_type (dhandle, 1, true); - break; - case 21: - name = "logical*1"; - rettype = debug_make_bool_type (dhandle, 1); - break; - case 22: - name = "logical*2"; - rettype = debug_make_bool_type (dhandle, 2); - break; - case 23: - name = "logical*4"; - rettype = debug_make_bool_type (dhandle, 4); - break; - case 24: - name = "logical"; - rettype = debug_make_bool_type (dhandle, 4); - break; - case 25: - /* Complex type consisting of two IEEE single precision values. */ - name = "complex"; - rettype = debug_make_complex_type (dhandle, 8); - break; - case 26: - /* Complex type consisting of two IEEE double precision values. */ - name = "double complex"; - rettype = debug_make_complex_type (dhandle, 16); - break; - case 27: - name = "integer*1"; - rettype = debug_make_int_type (dhandle, 1, false); - break; - case 28: - name = "integer*2"; - rettype = debug_make_int_type (dhandle, 2, false); - break; - case 29: - name = "integer*4"; - rettype = debug_make_int_type (dhandle, 4, false); - break; - case 30: - /* FIXME */ - name = "wchar"; - rettype = debug_make_int_type (dhandle, 2, false); - break; - case 31: - name = "long long"; - rettype = debug_make_int_type (dhandle, 8, false); - break; - case 32: - name = "unsigned long long"; - rettype = debug_make_int_type (dhandle, 8, true); - break; - case 33: - name = "logical*8"; - rettype = debug_make_bool_type (dhandle, 8); - break; - case 34: - name = "integer*8"; - rettype = debug_make_int_type (dhandle, 8, false); - break; - default: - abort (); - } - - rettype = debug_name_type (dhandle, name, rettype); - - info->xcoff_types[-typenum] = rettype; - - return rettype; -} - -/* Find or create a tagged type. */ - -static debug_type -stab_find_tagged_type (dhandle, info, p, len, kind) - PTR dhandle; - struct stab_handle *info; - const char *p; - int len; - enum debug_type_kind kind; -{ - char *name; - debug_type dtype; - struct stab_tag *st; - - name = savestring (p, len); - - /* We pass DEBUG_KIND_ILLEGAL because we want all tags in the same - namespace. This is right for C, and I don't know how to handle - other languages. FIXME. */ - dtype = debug_find_tagged_type (dhandle, name, DEBUG_KIND_ILLEGAL); - if (dtype != DEBUG_TYPE_NULL) - { - free (name); - return dtype; - } - - /* We need to allocate an entry on the undefined tag list. */ - for (st = info->tags; st != NULL; st = st->next) - { - if (st->name[0] == name[0] - && strcmp (st->name, name) == 0) - { - if (st->kind == DEBUG_KIND_ILLEGAL) - st->kind = kind; - free (name); - break; - } - } - if (st == NULL) - { - st = (struct stab_tag *) xmalloc (sizeof *st); - memset (st, 0, sizeof *st); - - st->next = info->tags; - st->name = name; - st->kind = kind; - st->slot = DEBUG_TYPE_NULL; - st->type = debug_make_indirect_type (dhandle, &st->slot, name); - info->tags = st; - } - - return st->type; -} - -/* In order to get the correct argument types for a stubbed method, we - need to extract the argument types from a C++ mangled string. - Since the argument types can refer back to the return type, this - means that we must demangle the entire physical name. In gdb this - is done by calling cplus_demangle and running the results back - through the C++ expression parser. Since we have no expression - parser, we must duplicate much of the work of cplus_demangle here. - - We assume that GNU style demangling is used, since this is only - done for method stubs, and only g++ should output that form of - debugging information. */ - -/* This structure is used to hold a pointer to type information which - demangling a string. */ - -struct stab_demangle_typestring -{ - /* The start of the type. This is not null terminated. */ - const char *typestring; - /* The length of the type. */ - unsigned int len; -}; - -/* This structure is used to hold information while demangling a - string. */ - -struct stab_demangle_info -{ - /* The debugging information handle. */ - PTR dhandle; - /* The stab information handle. */ - struct stab_handle *info; - /* The array of arguments we are building. */ - debug_type *args; - /* Whether the method takes a variable number of arguments. */ - boolean varargs; - /* The array of types we have remembered. */ - struct stab_demangle_typestring *typestrings; - /* The number of typestrings. */ - unsigned int typestring_count; - /* The number of typestring slots we have allocated. */ - unsigned int typestring_alloc; -}; - -static void stab_bad_demangle PARAMS ((const char *)); -static unsigned int stab_demangle_count PARAMS ((const char **)); -static boolean stab_demangle_get_count - PARAMS ((const char **, unsigned int *)); -static boolean stab_demangle_prefix - PARAMS ((struct stab_demangle_info *, const char **)); -static boolean stab_demangle_function_name - PARAMS ((struct stab_demangle_info *, const char **, const char *)); -static boolean stab_demangle_signature - PARAMS ((struct stab_demangle_info *, const char **)); -static boolean stab_demangle_qualified - PARAMS ((struct stab_demangle_info *, const char **, debug_type *)); -static boolean stab_demangle_template - PARAMS ((struct stab_demangle_info *, const char **)); -static boolean stab_demangle_class - PARAMS ((struct stab_demangle_info *, const char **, const char **)); -static boolean stab_demangle_args - PARAMS ((struct stab_demangle_info *, const char **, debug_type **, - boolean *)); -static boolean stab_demangle_arg - PARAMS ((struct stab_demangle_info *, const char **, debug_type **, - unsigned int *, unsigned int *)); -static boolean stab_demangle_type - PARAMS ((struct stab_demangle_info *, const char **, debug_type *)); -static boolean stab_demangle_fund_type - PARAMS ((struct stab_demangle_info *, const char **, debug_type *)); -static boolean stab_demangle_remember_type - PARAMS ((struct stab_demangle_info *, const char *, int)); - -/* Warn about a bad demangling. */ - -static void -stab_bad_demangle (s) - const char *s; -{ - fprintf (stderr, "bad mangled name `%s'\n", s); -} - -/* Get a count from a stab string. */ - -static unsigned int -stab_demangle_count (pp) - const char **pp; -{ - unsigned int count; - - count = 0; - while (isdigit ((unsigned char) **pp)) - { - count *= 10; - count += **pp - '0'; - ++*pp; - } - return count; -} - -/* Require a count in a string. The count may be multiple digits, in - which case it must end in an underscore. */ - -static boolean -stab_demangle_get_count (pp, pi) - const char **pp; - unsigned int *pi; -{ - if (! isdigit ((unsigned char) **pp)) - return false; - - *pi = **pp - '0'; - ++*pp; - if (isdigit ((unsigned char) **pp)) - { - unsigned int count; - const char *p; - - count = *pi; - p = *pp; - do - { - count *= 10; - count += *p - '0'; - ++p; - } - while (isdigit ((unsigned char) *p)); - if (*p == '_') - { - *pp = p + 1; - *pi = count; - } - } - - return true; -} - -/* This function demangles a physical name, returning a NULL - terminated array of argument types. */ - -static debug_type * -stab_demangle_argtypes (dhandle, info, physname, pvarargs) - PTR dhandle; - struct stab_handle *info; - const char *physname; - boolean *pvarargs; -{ - struct stab_demangle_info minfo; - - minfo.dhandle = dhandle; - minfo.info = info; - minfo.args = NULL; - minfo.varargs = false; - minfo.typestring_alloc = 10; - minfo.typestrings = ((struct stab_demangle_typestring *) - xmalloc (minfo.typestring_alloc - * sizeof *minfo.typestrings)); - minfo.typestring_count = 0; - - /* cplus_demangle checks for special GNU mangled forms, but we can't - see any of them in mangled method argument types. */ - - if (! stab_demangle_prefix (&minfo, &physname)) - goto error_return; - - if (*physname != '\0') - { - if (! stab_demangle_signature (&minfo, &physname)) - goto error_return; - } - - free (minfo.typestrings); - minfo.typestrings = NULL; - - if (minfo.args == NULL) - fprintf (stderr, "no argument types in mangled string\n"); - - *pvarargs = minfo.varargs; - return minfo.args; - - error_return: - if (minfo.typestrings != NULL) - free (minfo.typestrings); - return NULL; -} - -/* Demangle the prefix of the mangled name. */ - -static boolean -stab_demangle_prefix (minfo, pp) - struct stab_demangle_info *minfo; - const char **pp; -{ - const char *scan; - unsigned int i; - - /* cplus_demangle checks for global constructors and destructors, - but we can't see them in mangled argument types. */ - - /* Look for `__'. */ - scan = *pp; - do - { - scan = strchr (scan, '_'); - } - while (scan != NULL && *++scan != '_'); - - if (scan == NULL) - { - stab_bad_demangle (*pp); - return false; - } - - --scan; - - /* We found `__'; move ahead to the last contiguous `__' pair. */ - i = strspn (scan, "_"); - if (i > 2) - scan += i - 2; - - if (scan == *pp - && (isdigit ((unsigned char) scan[2]) - || scan[2] == 'Q' - || scan[2] == 't')) - { - /* This is a GNU style constructor name. */ - *pp = scan + 2; - return true; - } - else if (scan == *pp - && ! isdigit ((unsigned char) scan[2]) - && scan[2] != 't') - { - /* Look for the `__' that separates the prefix from the - signature. */ - while (*scan == '_') - ++scan; - scan = strstr (scan, "__"); - if (scan == NULL || scan[2] == '\0') - { - stab_bad_demangle (*pp); - return false; - } - - return stab_demangle_function_name (minfo, pp, scan); - } - else if (scan[2] != '\0') - { - /* The name doesn't start with `__', but it does contain `__'. */ - return stab_demangle_function_name (minfo, pp, scan); - } - else - { - stab_bad_demangle (*pp); - return false; - } - /*NOTREACHED*/ -} - -/* Demangle a function name prefix. The scan argument points to the - double underscore which separates the function name from the - signature. */ - -static boolean -stab_demangle_function_name (minfo, pp, scan) - struct stab_demangle_info *minfo; - const char **pp; - const char *scan; -{ - const char *name; - - /* The string from *pp to scan is the name of the function. We - don't care about the name, since we just looking for argument - types. However, for conversion operators, the name may include a - type which we must remember in order to handle backreferences. */ - - name = *pp; - *pp = scan + 2; - - if (*pp - name >= 5 - && strncmp (name, "type", 4) == 0 - && (name[4] == '$' || name[4] == '.')) - { - const char *tem; - - /* This is a type conversion operator. */ - tem = name + 5; - if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL)) - return false; - } - else if (name[0] == '_' - && name[1] == '_' - && name[2] == 'o' - && name[3] == 'p') - { - const char *tem; - - /* This is a type conversion operator. */ - tem = name + 4; - if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL)) - return false; - } - - return true; -} - -/* Demangle the signature. This is where the argument types are - found. */ - -static boolean -stab_demangle_signature (minfo, pp) - struct stab_demangle_info *minfo; - const char **pp; -{ - const char *orig; - boolean expect_func, func_done; - const char *hold; - - orig = *pp; - - expect_func = false; - func_done = false; - hold = NULL; - - while (**pp != '\0') - { - switch (**pp) - { - case 'Q': - hold = *pp; - if (! stab_demangle_qualified (minfo, pp, (debug_type *) NULL) - || ! stab_demangle_remember_type (minfo, hold, *pp - hold)) - return false; - expect_func = true; - hold = NULL; - break; - - case 'S': - /* Static member function. FIXME: Can this happen? */ - if (hold == NULL) - hold = *pp; - ++*pp; - break; - - case 'C': - /* Const member function. */ - if (hold == NULL) - hold = *pp; - ++*pp; - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - if (hold == NULL) - hold = *pp; - if (! stab_demangle_class (minfo, pp, (const char **) NULL) - || ! stab_demangle_remember_type (minfo, hold, *pp - hold)) - return false; - expect_func = true; - hold = NULL; - break; - - case 'F': - /* Function. I don't know if this actually happens with g++ - output. */ - hold = NULL; - func_done = true; - ++*pp; - if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) - return false; - break; - - case 't': - /* Template. */ - if (hold == NULL) - hold = *pp; - if (! stab_demangle_template (minfo, pp) - || ! stab_demangle_remember_type (minfo, hold, *pp - hold)) - return false; - hold = NULL; - expect_func = true; - break; - - case '_': - /* At the outermost level, we cannot have a return type - specified, so if we run into another '_' at this point we - are dealing with a mangled name that is either bogus, or - has been mangled by some algorithm we don't know how to - deal with. So just reject the entire demangling. */ - stab_bad_demangle (orig); - return false; - - default: - /* Assume we have stumbled onto the first outermost function - argument token, and start processing args. */ - func_done = true; - if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) - return false; - break; - } - - if (expect_func) - { - func_done = true; - if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) - return false; - } - } - - if (! func_done) - { - /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and - bar__3fooi is 'foo::bar(int)'. We get here when we find the - first case, and need to ensure that the '(void)' gets added - to the current declp. */ - if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) - return false; - } - - return true; -} - -/* Demangle a qualified name, such as "Q25Outer5Inner" which is the - mangled form of "Outer::Inner". */ - -static boolean -stab_demangle_qualified (minfo, pp, ptype) - struct stab_demangle_info *minfo; - const char **pp; - debug_type *ptype; -{ - const char *orig; - const char *p; - unsigned int qualifiers; - debug_type context; - - orig = *pp; - - switch ((*pp)[1]) - { - case '_': - /* GNU mangled name with more than 9 classes. The count is - preceded by an underscore (to distinguish it from the <= 9 - case) and followed by an underscore. */ - p = *pp + 2; - if (! isdigit ((unsigned char) *p) || *p == '0') - { - stab_bad_demangle (orig); - return false; - } - qualifiers = atoi (p); - while (isdigit ((unsigned char) *p)) - ++p; - if (*p != '_') - { - stab_bad_demangle (orig); - return false; - } - *pp = p + 1; - break; - - case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - qualifiers = (*pp)[1] - '0'; - /* Skip an optional underscore after the count. */ - if ((*pp)[2] == '_') - ++*pp; - *pp += 2; - break; - - case '0': - default: - stab_bad_demangle (orig); - return false; - } - - context = DEBUG_TYPE_NULL; - - /* Pick off the names. */ - while (qualifiers-- > 0) - { - if (**pp == '_') - ++*pp; - if (**pp == 't') - { - /* FIXME: I don't know how to handle the ptype != NULL case - here. */ - if (! stab_demangle_template (minfo, pp)) - return false; - } - else - { - unsigned int len; - - len = stab_demangle_count (pp); - if (strlen (*pp) < len) - { - stab_bad_demangle (orig); - return false; - } - - if (ptype != NULL) - { - const debug_field *fields; - - fields = NULL; - if (context != DEBUG_TYPE_NULL) - fields = debug_get_fields (minfo->dhandle, context); - - context = DEBUG_TYPE_NULL; - - if (fields != NULL) - { - char *name; - - /* Try to find the type by looking through the - fields of context until we find a field with the - same type. This ought to work for a class - defined within a class, but it won't work for, - e.g., an enum defined within a class. stabs does - not give us enough information to figure out the - latter case. */ - - name = savestring (*pp, len); - - for (; *fields != DEBUG_FIELD_NULL; fields++) - { - debug_type ft; - const char *dn; - - ft = debug_get_field_type (minfo->dhandle, *fields); - if (ft == NULL) - return false; - dn = debug_get_type_name (minfo->dhandle, ft); - if (dn != NULL && strcmp (dn, name) == 0) - { - context = ft; - break; - } - } - - free (name); - } - - if (context == DEBUG_TYPE_NULL) - { - /* We have to fall back on finding the type by name. - If there are more types to come, then this must - be a class. Otherwise, it could be anything. */ - - if (qualifiers == 0) - { - char *name; - - name = savestring (*pp, len); - context = debug_find_named_type (minfo->dhandle, - name); - free (name); - } - - if (context == DEBUG_TYPE_NULL) - { - context = stab_find_tagged_type (minfo->dhandle, - minfo->info, - *pp, len, - (qualifiers == 0 - ? DEBUG_KIND_ILLEGAL - : DEBUG_KIND_CLASS)); - if (context == DEBUG_TYPE_NULL) - return false; - } - } - } - - *pp += len; - } - } - - if (ptype != NULL) - *ptype = context; - - return true; -} - -/* Demangle a template. */ - -static boolean -stab_demangle_template (minfo, pp) - struct stab_demangle_info *minfo; - const char **pp; -{ - const char *orig; - unsigned int r, i; - - orig = *pp; - - ++*pp; - - /* Skip the template name. */ - r = stab_demangle_count (pp); - if (r == 0 || strlen (*pp) < r) - { - stab_bad_demangle (orig); - return false; - } - *pp += r; - - /* Get the size of the parameter list. */ - if (stab_demangle_get_count (pp, &r) == 0) - { - stab_bad_demangle (orig); - return false; - } - - for (i = 0; i < r; i++) - { - if (**pp == 'Z') - { - /* This is a type parameter. */ - ++*pp; - if (! stab_demangle_type (minfo, pp, (debug_type *) NULL)) - return false; - } - else - { - const char *old_p; - boolean pointerp, realp, integralp, charp, boolp; - boolean done; - - old_p = *pp; - pointerp = false; - realp = false; - integralp = false; - charp = false; - boolp = false; - done = false; - - /* This is a value parameter. */ - - if (! stab_demangle_type (minfo, pp, (debug_type *) NULL)) - return false; - - while (*old_p != '\0' && ! done) - { - switch (*old_p) - { - case 'P': - case 'p': - case 'R': - pointerp = true; - done = true; - break; - case 'C': /* Const. */ - case 'S': /* Signed. */ - case 'U': /* Unsigned. */ - case 'V': /* Volatile. */ - case 'F': /* Function. */ - case 'M': /* Member function. */ - case 'O': /* ??? */ - ++old_p; - break; - case 'Q': /* Qualified name. */ - integralp = true; - done = true; - break; - case 'T': /* Remembered type. */ - abort (); - case 'v': /* Void. */ - abort (); - case 'x': /* Long long. */ - case 'l': /* Long. */ - case 'i': /* Int. */ - case 's': /* Short. */ - case 'w': /* Wchar_t. */ - integralp = true; - done = true; - break; - case 'b': /* Bool. */ - boolp = true; - done = true; - break; - case 'c': /* Char. */ - charp = true; - done = true; - break; - case 'r': /* Long double. */ - case 'd': /* Double. */ - case 'f': /* Float. */ - realp = true; - done = true; - break; - default: - /* Assume it's a user defined integral type. */ - integralp = true; - done = true; - break; - } - } - - if (integralp) - { - if (**pp == 'm') - ++*pp; - while (isdigit ((unsigned char) **pp)) - ++*pp; - } - else if (charp) - { - unsigned int val; - - if (**pp == 'm') - ++*pp; - val = stab_demangle_count (pp); - if (val == 0) - { - stab_bad_demangle (orig); - return false; - } - } - else if (boolp) - { - unsigned int val; - - val = stab_demangle_count (pp); - if (val != 0 && val != 1) - { - stab_bad_demangle (orig); - return false; - } - } - else if (realp) - { - if (**pp == 'm') - ++*pp; - while (isdigit ((unsigned char) **pp)) - ++*pp; - if (**pp == '.') - { - ++*pp; - while (isdigit ((unsigned char) **pp)) - ++*pp; - } - if (**pp == 'e') - { - ++*pp; - while (isdigit ((unsigned char) **pp)) - ++*pp; - } - } - else if (pointerp) - { - unsigned int len; - - if (! stab_demangle_get_count (pp, &len)) - { - stab_bad_demangle (orig); - return false; - } - *pp += len; - } - } - } - - return true; -} - -/* Demangle a class name. */ - -static boolean -stab_demangle_class (minfo, pp, pstart) - struct stab_demangle_info *minfo; - const char **pp; - const char **pstart; -{ - const char *orig; - unsigned int n; - - orig = *pp; - - n = stab_demangle_count (pp); - if (strlen (*pp) < n) - { - stab_bad_demangle (orig); - return false; - } - - if (pstart != NULL) - *pstart = *pp; - - *pp += n; - - return true; -} - -/* Demangle function arguments. If the pargs argument is not NULL, it - is set to a NULL terminated array holding the arguments. */ - -static boolean -stab_demangle_args (minfo, pp, pargs, pvarargs) - struct stab_demangle_info *minfo; - const char **pp; - debug_type **pargs; - boolean *pvarargs; -{ - const char *orig; - unsigned int alloc, count; - - orig = *pp; - - alloc = 10; - if (pargs != NULL) - { - *pargs = (debug_type *) xmalloc (alloc * sizeof **pargs); - *pvarargs = false; - } - count = 0; - - while (**pp != '_' && **pp != '\0' && **pp != 'e') - { - if (**pp == 'N' || **pp == 'T') - { - char temptype; - unsigned int r, t; - - temptype = **pp; - ++*pp; - - if (temptype == 'T') - r = 1; - else - { - if (! stab_demangle_get_count (pp, &r)) - { - stab_bad_demangle (orig); - return false; - } - } - - if (! stab_demangle_get_count (pp, &t)) - { - stab_bad_demangle (orig); - return false; - } - - if (t >= minfo->typestring_count) - { - stab_bad_demangle (orig); - return false; - } - while (r-- > 0) - { - const char *tem; - - tem = minfo->typestrings[t].typestring; - if (! stab_demangle_arg (minfo, &tem, pargs, &count, &alloc)) - return false; - } - } - else - { - if (! stab_demangle_arg (minfo, pp, pargs, &count, &alloc)) - return false; - } - } - - if (pargs != NULL) - (*pargs)[count] = DEBUG_TYPE_NULL; - - if (**pp == 'e') - { - if (pargs != NULL) - *pvarargs = true; - ++*pp; - } - - return true; -} - -/* Demangle a single argument. */ - -static boolean -stab_demangle_arg (minfo, pp, pargs, pcount, palloc) - struct stab_demangle_info *minfo; - const char **pp; - debug_type **pargs; - unsigned int *pcount; - unsigned int *palloc; -{ - const char *start; - debug_type type; - - start = *pp; - if (! stab_demangle_type (minfo, pp, - pargs == NULL ? (debug_type *) NULL : &type) - || ! stab_demangle_remember_type (minfo, start, *pp - start)) - return false; - - if (pargs != NULL) - { - if (type == DEBUG_TYPE_NULL) - return false; - - if (*pcount + 1 >= *palloc) - { - *palloc += 10; - *pargs = ((debug_type *) - xrealloc (*pargs, *palloc * sizeof **pargs)); - } - (*pargs)[*pcount] = type; - ++*pcount; - } - - return true; -} - -/* Demangle a type. If the ptype argument is not NULL, *ptype is set - to the newly allocated type. */ - -static boolean -stab_demangle_type (minfo, pp, ptype) - struct stab_demangle_info *minfo; - const char **pp; - debug_type *ptype; -{ - const char *orig; - - orig = *pp; - - switch (**pp) - { - case 'P': - case 'p': - /* A pointer type. */ - ++*pp; - if (! stab_demangle_type (minfo, pp, ptype)) - return false; - if (ptype != NULL) - *ptype = debug_make_pointer_type (minfo->dhandle, *ptype); - break; - - case 'R': - /* A reference type. */ - ++*pp; - if (! stab_demangle_type (minfo, pp, ptype)) - return false; - if (ptype != NULL) - *ptype = debug_make_reference_type (minfo->dhandle, *ptype); - break; - - case 'A': - /* An array. */ - { - unsigned long high; - - ++*pp; - high = 0; - while (**pp != '\0' && **pp != '_') - { - if (! isdigit ((unsigned char) **pp)) - { - stab_bad_demangle (orig); - return false; - } - high *= 10; - high += **pp - '0'; - ++*pp; - } - if (**pp != '_') - { - stab_bad_demangle (orig); - return false; - } - ++*pp; - - if (! stab_demangle_type (minfo, pp, ptype)) - return false; - if (ptype != NULL) - { - debug_type int_type; - - int_type = debug_find_named_type (minfo->dhandle, "int"); - if (int_type == NULL) - int_type = debug_make_int_type (minfo->dhandle, 4, false); - *ptype = debug_make_array_type (minfo->dhandle, *ptype, int_type, - 0, high, false); - } - } - break; - - case 'T': - /* A back reference to a remembered type. */ - { - unsigned int i; - const char *p; - - ++*pp; - if (! stab_demangle_get_count (pp, &i)) - { - stab_bad_demangle (orig); - return false; - } - if (i >= minfo->typestring_count) - { - stab_bad_demangle (orig); - return false; - } - p = minfo->typestrings[i].typestring; - if (! stab_demangle_type (minfo, &p, ptype)) - return false; - } - break; - - case 'F': - /* A function. */ - { - debug_type *args; - boolean varargs; - - ++*pp; - if (! stab_demangle_args (minfo, pp, - (ptype == NULL - ? (debug_type **) NULL - : &args), - (ptype == NULL - ? (boolean *) NULL - : &varargs))) - return false; - if (**pp != '_') - { - /* cplus_demangle will accept a function without a return - type, but I don't know when that will happen, or what - to do if it does. */ - stab_bad_demangle (orig); - return false; - } - ++*pp; - if (! stab_demangle_type (minfo, pp, ptype)) - return false; - if (ptype != NULL) - *ptype = debug_make_function_type (minfo->dhandle, *ptype, args, - varargs); - - } - break; - - case 'M': - case 'O': - { - boolean memberp, constp, volatilep; - debug_type *args; - boolean varargs; - unsigned int n; - const char *name; - - memberp = **pp == 'M'; - constp = false; - volatilep = false; - args = NULL; - varargs = false; - - ++*pp; - if (! isdigit ((unsigned char) **pp)) - { - stab_bad_demangle (orig); - return false; - } - n = stab_demangle_count (pp); - if (strlen (*pp) < n) - { - stab_bad_demangle (orig); - return false; - } - name = *pp; - *pp += n; - - if (memberp) - { - if (**pp == 'C') - { - constp = true; - ++*pp; - } - else if (**pp == 'V') - { - volatilep = true; - ++*pp; - } - if (**pp != 'F') - { - stab_bad_demangle (orig); - return false; - } - ++*pp; - if (! stab_demangle_args (minfo, pp, - (ptype == NULL - ? (debug_type **) NULL - : &args), - (ptype == NULL - ? (boolean *) NULL - : &varargs))) - return false; - } - - if (**pp != '_') - { - stab_bad_demangle (orig); - return false; - } - ++*pp; - - if (! stab_demangle_type (minfo, pp, ptype)) - return false; - - if (ptype != NULL) - { - debug_type class_type; - - class_type = stab_find_tagged_type (minfo->dhandle, minfo->info, - name, (int) n, - DEBUG_KIND_CLASS); - if (class_type == DEBUG_TYPE_NULL) - return false; - - if (! memberp) - *ptype = debug_make_offset_type (minfo->dhandle, class_type, - *ptype); - else - { - /* FIXME: We have no way to record constp or - volatilep. */ - *ptype = debug_make_method_type (minfo->dhandle, *ptype, - class_type, args, varargs); - } - } - } - break; - - case 'G': - ++*pp; - if (! stab_demangle_type (minfo, pp, ptype)) - return false; - break; - - case 'C': - ++*pp; - if (! stab_demangle_type (minfo, pp, ptype)) - return false; - if (ptype != NULL) - *ptype = debug_make_const_type (minfo->dhandle, *ptype); - break; - - case 'Q': - { - const char *hold; - - hold = *pp; - if (! stab_demangle_qualified (minfo, pp, ptype)) - return false; - } - break; - - default: - if (! stab_demangle_fund_type (minfo, pp, ptype)) - return false; - break; - } - - return true; -} - -/* Demangle a fundamental type. If the ptype argument is not NULL, - *ptype is set to the newly allocated type. */ - -static boolean -stab_demangle_fund_type (minfo, pp, ptype) - struct stab_demangle_info *minfo; - const char **pp; - debug_type *ptype; -{ - const char *orig; - boolean constp, volatilep, unsignedp, signedp; - boolean done; - - orig = *pp; - - constp = false; - volatilep = false; - unsignedp = false; - signedp = false; - - done = false; - while (! done) - { - switch (**pp) - { - case 'C': - constp = true; - ++*pp; - break; - - case 'U': - unsignedp = true; - ++*pp; - break; - - case 'S': - signedp = true; - ++*pp; - break; - - case 'V': - volatilep = true; - ++*pp; - break; - - default: - done = true; - break; - } - } - - switch (**pp) - { - case '\0': - case '_': - /* cplus_demangle permits this, but I don't know what it means. */ - stab_bad_demangle (orig); - break; - - case 'v': /* void */ - if (ptype != NULL) - { - *ptype = debug_find_named_type (minfo->dhandle, "void"); - if (*ptype == DEBUG_TYPE_NULL) - *ptype = debug_make_void_type (minfo->dhandle); - } - ++*pp; - break; - - case 'x': /* long long */ - if (ptype != NULL) - { - *ptype = debug_find_named_type (minfo->dhandle, - (unsignedp - ? "long long unsigned int" - : "long long int")); - if (*ptype == DEBUG_TYPE_NULL) - *ptype = debug_make_int_type (minfo->dhandle, 8, unsignedp); - } - ++*pp; - break; - - case 'l': /* long */ - if (ptype != NULL) - { - *ptype = debug_find_named_type (minfo->dhandle, - (unsignedp - ? "long unsigned int" - : "long int")); - if (*ptype == DEBUG_TYPE_NULL) - *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp); - } - ++*pp; - break; - - case 'i': /* int */ - if (ptype != NULL) - { - *ptype = debug_find_named_type (minfo->dhandle, - (unsignedp - ? "unsigned int" - : "int")); - if (*ptype == DEBUG_TYPE_NULL) - *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp); - } - ++*pp; - break; - - case 's': /* short */ - if (ptype != NULL) - { - *ptype = debug_find_named_type (minfo->dhandle, - (unsignedp - ? "short unsigned int" - : "short int")); - if (*ptype == DEBUG_TYPE_NULL) - *ptype = debug_make_int_type (minfo->dhandle, 2, unsignedp); - } - ++*pp; - break; - - case 'b': /* bool */ - if (ptype != NULL) - { - *ptype = debug_find_named_type (minfo->dhandle, "bool"); - if (*ptype == DEBUG_TYPE_NULL) - *ptype = debug_make_bool_type (minfo->dhandle, 4); - } - ++*pp; - break; - - case 'c': /* char */ - if (ptype != NULL) - { - *ptype = debug_find_named_type (minfo->dhandle, - (unsignedp - ? "unsigned char" - : (signedp - ? "signed char" - : "char"))); - if (*ptype == DEBUG_TYPE_NULL) - *ptype = debug_make_int_type (minfo->dhandle, 1, unsignedp); - } - ++*pp; - break; - - case 'w': /* wchar_t */ - if (ptype != NULL) - { - *ptype = debug_find_named_type (minfo->dhandle, "__wchar_t"); - if (*ptype == DEBUG_TYPE_NULL) - *ptype = debug_make_int_type (minfo->dhandle, 2, true); - } - ++*pp; - break; - - case 'r': /* long double */ - if (ptype != NULL) - { - *ptype = debug_find_named_type (minfo->dhandle, "long double"); - if (*ptype == DEBUG_TYPE_NULL) - *ptype = debug_make_float_type (minfo->dhandle, 8); - } - ++*pp; - break; - - case 'd': /* double */ - if (ptype != NULL) - { - *ptype = debug_find_named_type (minfo->dhandle, "double"); - if (*ptype == DEBUG_TYPE_NULL) - *ptype = debug_make_float_type (minfo->dhandle, 8); - } - ++*pp; - break; - - case 'f': /* float */ - if (ptype != NULL) - { - *ptype = debug_find_named_type (minfo->dhandle, "float"); - if (*ptype == DEBUG_TYPE_NULL) - *ptype = debug_make_float_type (minfo->dhandle, 4); - } - ++*pp; - break; - - case 'G': - ++*pp; - if (! isdigit ((unsigned char) **pp)) - { - stab_bad_demangle (orig); - return false; - } - /* Fall through. */ - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - const char *hold; - - if (! stab_demangle_class (minfo, pp, &hold)) - return false; - if (ptype != NULL) - { - char *name; - - name = savestring (hold, *pp - hold); - *ptype = debug_find_named_type (minfo->dhandle, name); - if (*ptype == DEBUG_TYPE_NULL) - { - /* FIXME: It is probably incorrect to assume that - undefined types are tagged types. */ - *ptype = stab_find_tagged_type (minfo->dhandle, minfo->info, - hold, *pp - hold, - DEBUG_KIND_ILLEGAL); - } - free (name); - } - } - break; - - case 't': - if (! stab_demangle_template (minfo, pp)) - return false; - if (ptype != NULL) - { - debug_type t; - - /* FIXME: I really don't know how a template should be - represented in the current type system. Perhaps the - template should be demangled into a string, and the type - should be represented as a named type. However, I don't - know what the base type of the named type should be. */ - t = debug_make_void_type (minfo->dhandle); - t = debug_make_pointer_type (minfo->dhandle, t); - t = debug_name_type (minfo->dhandle, "TEMPLATE", t); - *ptype = t; - } - break; - - default: - stab_bad_demangle (orig); - return false; - } - - if (ptype != NULL) - { - if (constp) - *ptype = debug_make_const_type (minfo->dhandle, *ptype); - if (volatilep) - *ptype = debug_make_volatile_type (minfo->dhandle, *ptype); - } - - return true; -} - -/* Remember a type string in a demangled string. */ - -static boolean -stab_demangle_remember_type (minfo, p, len) - struct stab_demangle_info *minfo; - const char *p; - int len; -{ - if (minfo->typestring_count >= minfo->typestring_alloc) - { - minfo->typestring_alloc += 10; - minfo->typestrings = ((struct stab_demangle_typestring *) - xrealloc (minfo->typestrings, - (minfo->typestring_alloc - * sizeof *minfo->typestrings))); - } - - minfo->typestrings[minfo->typestring_count].typestring = p; - minfo->typestrings[minfo->typestring_count].len = (unsigned int) len; - ++minfo->typestring_count; - - return true; -} diff --git a/sql/Makefile.am b/sql/Makefile.am index 0b22481f850..40a3565cb91 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -41,7 +41,6 @@ mysqld_DEPENDENCIES= @mysql_plugin_libs@ $(SUPPORTING_LIBS) libndb.la LDADD = $(SUPPORTING_LIBS) @ZLIB_LIBS@ @NDB_SCI_LIBS@ mysqld_LDADD = libndb.la \ @MYSQLD_EXTRA_LDFLAGS@ \ - @pstack_libs@ \ @mysql_plugin_libs@ \ $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ \ $(yassl_libs) $(openssl_libs) @MYSQLD_EXTRA_LIBS@ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d9c4c7fc3f5..d17ccc47abb 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -70,10 +70,8 @@ #endif /* stack traces are only supported on linux intel */ -#if defined(__linux__) && defined(__i386__) && defined(USE_PSTACK) +#if defined(__linux__) && defined(__i386__) #define HAVE_STACK_TRACE_ON_SEGV -#include "../pstack/pstack.h" -char pstack_file_name[80]; #endif /* __linux__ */ /* We have HAVE_purify below as this speeds up the shutdown of MySQL */ @@ -2779,14 +2777,6 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) if (!opt_bootstrap) create_pid_file(); -#ifdef HAVE_STACK_TRACE_ON_SEGV - if (opt_do_pstack) - { - sprintf(pstack_file_name,"mysqld-%lu-%%d-%%d.backtrace", (ulong)getpid()); - pstack_install_segv_action(pstack_file_name); - } -#endif /* HAVE_STACK_TRACE_ON_SEGV */ - /* signal to start_signal_handler that we are ready This works by waiting for start_signal_handler to free mutex, @@ -5963,9 +5953,10 @@ struct my_option my_long_options[] = NO_ARG, 0, 0, 0, 0, 0, 0}, #endif #ifdef HAVE_STACK_TRACE_ON_SEGV - {"enable-pstack", OPT_DO_PSTACK, "Print a symbolic stack trace on failure.", - &opt_do_pstack, &opt_do_pstack, 0, GET_BOOL, NO_ARG, 0, 0, - 0, 0, 0, 0}, + {"enable-pstack", OPT_DO_PSTACK, "Print a symbolic stack trace on failure. " + "This option is deprecated and has no effect; a symbolic stack trace will " + "be printed after a crash whenever possible.", &opt_do_pstack, &opt_do_pstack, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif /* HAVE_STACK_TRACE_ON_SEGV */ {"engine-condition-pushdown", OPT_ENGINE_CONDITION_PUSHDOWN, @@ -8654,6 +8645,13 @@ mysqld_get_one_option(int optid, lower_case_table_names= argument ? atoi(argument) : 1; lower_case_table_names_used= 1; break; +#ifdef HAVE_STACK_TRACE_ON_SEGV + case OPT_DO_PSTACK: + sql_print_warning("'--enable-pstack' is deprecated and will be removed " + "in a future release. A symbolic stack trace will be " + "printed after a crash whenever possible."); + break; +#endif #if defined(ENABLED_DEBUG_SYNC) case OPT_DEBUG_SYNC_TIMEOUT: /* From 2c16c7e985f772154eb179ac56eabeef405b9443 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Wed, 10 Nov 2010 11:49:37 +0600 Subject: [PATCH 029/238] Fixed Bug#57386 - main.execution_constants segfault on MIPS64EL. sql/item_func.cc: Item_func::fix_fields modified: increased minimal required stack size in call to check_stack_overrun(). --- sql/item_func.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sql/item_func.cc b/sql/item_func.cc index eaf6a1b6d14..d8b5d46938e 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -157,7 +157,14 @@ Item_func::fix_fields(THD *thd, Item **ref) used_tables_cache= not_null_tables_cache= 0; const_item_cache=1; - if (check_stack_overrun(thd, STACK_MIN_SIZE, buff)) + /* + Use stack limit of STACK_MIN_SIZE * 2 since + on some platforms a recursive call to fix_fields + requires more than STACK_MIN_SIZE bytes (e.g. for + MIPS, it takes about 22kB to make one recursive + call to Item_func::fix_fields()) + */ + if (check_stack_overrun(thd, STACK_MIN_SIZE * 2, buff)) return TRUE; // Fatal error if flag is set! if (arg_count) { // Print purify happy From 4b0fe8870871c6af340ad0198dfec1c61700853d Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Wed, 10 Nov 2010 14:32:42 +0600 Subject: [PATCH 030/238] Fixed bug#56619 - Assertion failed during ALTER TABLE RENAME, DISABLE KEYS. The code of ALTER TABLE RENAME, DISABLE KEYS could issue a commit while holding LOCK_open mutex. This is a regression introduced by the fix for Bug 54453. This failed an assert guarding us against a potential deadlock with connections trying to execute FLUSH TABLES WITH READ LOCK. The fix is to move acquisition of LOCK_open outside the section that issues ha_autocommit_or_rollback(). LOCK_open is taken to protect against concurrent operations with .frms and the table definition cache, and doesn't need to cover the call to commit. A test case added to innodb_mysql.test. The patch is to be null-merged to 5.5, which already has 54453 null-merged to it. mysql-test/suite/innodb/r/innodb_mysql.result: Added test results for test for bug#56619. mysql-test/suite/innodb/t/innodb_mysql.test: Added test for bug#56619. sql/sql_table.cc: mysql_alter_table() modified: moved acquisition of LOCK_open after call to ha_autocommit_or_rollback. --- mysql-test/suite/innodb/r/innodb_mysql.result | 8 ++++++++ mysql-test/suite/innodb/t/innodb_mysql.test | 13 +++++++++++++ sql/sql_table.cc | 4 +++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/innodb/r/innodb_mysql.result b/mysql-test/suite/innodb/r/innodb_mysql.result index 65b7da143a4..6ac3e8e6302 100644 --- a/mysql-test/suite/innodb/r/innodb_mysql.result +++ b/mysql-test/suite/innodb/r/innodb_mysql.result @@ -2620,3 +2620,11 @@ t2 CREATE TABLE `t2` ( CONSTRAINT `x` FOREIGN KEY (`fk`) REFERENCES `t1` (`pk`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 drop table t2, t1; +# +# Test for bug #56619 - Assertion failed during +# ALTER TABLE RENAME, DISABLE KEYS +# +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1 (a INT, INDEX(a)) engine=innodb; +ALTER TABLE t1 RENAME TO t2, DISABLE KEYS; +DROP TABLE IF EXISTS t1, t2; diff --git a/mysql-test/suite/innodb/t/innodb_mysql.test b/mysql-test/suite/innodb/t/innodb_mysql.test index 09dc4c9f187..e99c3c27673 100644 --- a/mysql-test/suite/innodb/t/innodb_mysql.test +++ b/mysql-test/suite/innodb/t/innodb_mysql.test @@ -845,3 +845,16 @@ create table t2 (fk int, key x (fk), constraint x foreign key (FK) references t1 (PK)) engine=InnoDB; show create table t2; drop table t2, t1; + +--echo # +--echo # Test for bug #56619 - Assertion failed during +--echo # ALTER TABLE RENAME, DISABLE KEYS +--echo # +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +--enable_warnings +CREATE TABLE t1 (a INT, INDEX(a)) engine=innodb; +--disable_warnings +ALTER TABLE t1 RENAME TO t2, DISABLE KEYS; +DROP TABLE IF EXISTS t1, t2; +--enable_warnings diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 971e1022d63..b919ea9eae7 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6832,7 +6832,6 @@ view_err: table->alias); } - VOID(pthread_mutex_lock(&LOCK_open)); /* Unlike to the above case close_cached_table() below will remove ALL instances of TABLE from table cache (it will also remove table lock @@ -6853,6 +6852,7 @@ view_err: */ ha_autocommit_or_rollback(thd, 0); + VOID(pthread_mutex_lock(&LOCK_open)); /* Then do a 'simple' rename of the table. First we need to close all instances of 'source' table. @@ -6885,6 +6885,8 @@ view_err: } } } + else + VOID(pthread_mutex_lock(&LOCK_open)); if (error == HA_ERR_WRONG_COMMAND) { From 871f36357e696d12cc4a360a8c36d7be61516ac6 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Thu, 11 Nov 2010 10:52:51 +0600 Subject: [PATCH 031/238] Fixed bug#54375 - Error in stored procedure leaves connection in different default schema. In strict mode, when data truncation or conversion happens, THD::killed is set to THD::KILL_BAD_DATA. This is abuse of KILL mechanism to guarantee that execution of statement is aborted. The stored procedures execution, on the other hand, upon detection that a connection was killed, would terminate immediately, without trying to restore the caller's context, in particular, restore the caller's current schema. The fix is, when terminating a stored procedure execution, to only bypass cleanup if the entire connection was killed, not in case of other forms of KILL. mysql-test/r/sp-bugs.result: Added result for a test case for bug#54375. mysql-test/t/sp-bugs.test: Added test case for bug#54375. sql/sp_head.cc: sp_head::execute modified: restore saved current db if connection is not killed. --- mysql-test/r/sp-bugs.result | 36 ++++++++++++++++++++++++++++++++++++ mysql-test/t/sp-bugs.test | 37 +++++++++++++++++++++++++++++++++++++ sql/sp_head.cc | 2 +- 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/sp-bugs.result b/mysql-test/r/sp-bugs.result index 2374b433fba..507c73c2683 100644 --- a/mysql-test/r/sp-bugs.result +++ b/mysql-test/r/sp-bugs.result @@ -73,4 +73,40 @@ CALL p1 (); ERROR HY000: Trigger does not exist DROP TABLE t1; DROP PROCEDURE p1; +# +# Bug#54375: Error in stored procedure leaves connection +# in different default schema +# +SET @@SQL_MODE = 'STRICT_ALL_TABLES'; +DROP DATABASE IF EXISTS db1; +CREATE DATABASE db1; +USE db1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 int NOT NULL PRIMARY KEY); +INSERT INTO t1 VALUES (1); +CREATE FUNCTION f1 ( +some_value int +) +RETURNS smallint +DETERMINISTIC +BEGIN +INSERT INTO t1 SET c1 = some_value; +RETURN(LAST_INSERT_ID()); +END$$ +DROP DATABASE IF EXISTS db2; +CREATE DATABASE db2; +USE db2; +SELECT DATABASE(); +DATABASE() +db2 +SELECT db1.f1(1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +SELECT DATABASE(); +DATABASE() +db2 +USE test; +DROP FUNCTION db1.f1; +DROP TABLE db1.t1; +DROP DATABASE db1; +DROP DATABASE db2; End of 5.1 tests diff --git a/mysql-test/t/sp-bugs.test b/mysql-test/t/sp-bugs.test index 8aa0791e265..fe52632c784 100644 --- a/mysql-test/t/sp-bugs.test +++ b/mysql-test/t/sp-bugs.test @@ -101,4 +101,41 @@ CALL p1 (); DROP TABLE t1; DROP PROCEDURE p1; +--echo # +--echo # Bug#54375: Error in stored procedure leaves connection +--echo # in different default schema +--echo # + +--disable_warnings +SET @@SQL_MODE = 'STRICT_ALL_TABLES'; +DROP DATABASE IF EXISTS db1; +CREATE DATABASE db1; +USE db1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 int NOT NULL PRIMARY KEY); +INSERT INTO t1 VALUES (1); +DELIMITER $$; +CREATE FUNCTION f1 ( + some_value int +) +RETURNS smallint +DETERMINISTIC +BEGIN + INSERT INTO t1 SET c1 = some_value; + RETURN(LAST_INSERT_ID()); +END$$ +DELIMITER ;$$ +DROP DATABASE IF EXISTS db2; +CREATE DATABASE db2; +--enable_warnings +USE db2; +SELECT DATABASE(); +--error ER_DUP_ENTRY +SELECT db1.f1(1); +SELECT DATABASE(); +USE test; +DROP FUNCTION db1.f1; +DROP TABLE db1.t1; +DROP DATABASE db1; +DROP DATABASE db2; --echo End of 5.1 tests diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 66d5eff5112..2473abea3c7 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1372,7 +1372,7 @@ sp_head::execute(THD *thd) If the DB has changed, the pointer has changed too, but the original thd->db will then have been freed */ - if (cur_db_changed && !thd->killed) + if (cur_db_changed && thd->killed != THD::KILL_CONNECTION) { /* Force switching back to the saved current database, because it may be From 13bc5b3f3d6babe5b2b60256167b2cae1ef7d4c2 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 11 Nov 2010 13:03:17 +0300 Subject: [PATCH 032/238] BUG#58079 - Remove the IBM DB2 storage engine --- mysql-test/suite/ibmdb2i/include/have_i54.inc | 20 - mysql-test/suite/ibmdb2i/include/have_i61.inc | 20 - .../suite/ibmdb2i/include/have_ibmdb2i.inc | 6 - .../suite/ibmdb2i/r/ibmdb2i_bug_44020.result | 11 - .../suite/ibmdb2i/r/ibmdb2i_bug_44025.result | 4 - .../suite/ibmdb2i/r/ibmdb2i_bug_44232.result | 4 - .../suite/ibmdb2i/r/ibmdb2i_bug_44610.result | 18 - .../suite/ibmdb2i/r/ibmdb2i_bug_45196.result | 33 - .../suite/ibmdb2i/r/ibmdb2i_bug_45793.result | 7 - .../suite/ibmdb2i/r/ibmdb2i_bug_45983.result | 20 - .../suite/ibmdb2i/r/ibmdb2i_bug_49329.result | 9 - .../suite/ibmdb2i/r/ibmdb2i_collations.result | 1204 ------ .../suite/ibmdb2i/t/ibmdb2i_bug_44020.test | 9 - .../suite/ibmdb2i/t/ibmdb2i_bug_44025.test | 9 - .../suite/ibmdb2i/t/ibmdb2i_bug_44232.test | 8 - .../suite/ibmdb2i/t/ibmdb2i_bug_44610.test | 28 - .../suite/ibmdb2i/t/ibmdb2i_bug_45196.test | 26 - .../suite/ibmdb2i/t/ibmdb2i_bug_45793.test | 11 - .../suite/ibmdb2i/t/ibmdb2i_bug_45983.test | 47 - .../suite/ibmdb2i/t/ibmdb2i_bug_49329.test | 10 - .../suite/ibmdb2i/t/ibmdb2i_collations.test | 44 - storage/ibmdb2i/CMakeLists.txt | 25 - storage/ibmdb2i/Makefile.am | 54 - storage/ibmdb2i/db2i_blobCollection.cc | 107 - storage/ibmdb2i/db2i_blobCollection.h | 151 - storage/ibmdb2i/db2i_charsetSupport.cc | 826 ---- storage/ibmdb2i/db2i_charsetSupport.h | 65 - storage/ibmdb2i/db2i_collationSupport.cc | 355 -- storage/ibmdb2i/db2i_collationSupport.h | 48 - storage/ibmdb2i/db2i_constraints.cc | 672 ---- storage/ibmdb2i/db2i_conversion.cc | 1459 ------- storage/ibmdb2i/db2i_errors.cc | 297 -- storage/ibmdb2i/db2i_errors.h | 93 - storage/ibmdb2i/db2i_file.cc | 556 --- storage/ibmdb2i/db2i_file.h | 445 --- storage/ibmdb2i/db2i_global.h | 138 - storage/ibmdb2i/db2i_iconv.h | 51 - storage/ibmdb2i/db2i_ileBridge.cc | 1342 ------- storage/ibmdb2i/db2i_ileBridge.h | 499 --- storage/ibmdb2i/db2i_ioBuffers.cc | 332 -- storage/ibmdb2i/db2i_ioBuffers.h | 416 -- storage/ibmdb2i/db2i_misc.h | 129 - storage/ibmdb2i/db2i_myconv.cc | 1498 -------- storage/ibmdb2i/db2i_myconv.h | 3201 ---------------- storage/ibmdb2i/db2i_rir.cc | 686 ---- storage/ibmdb2i/db2i_safeString.h | 98 - storage/ibmdb2i/db2i_sqlStatementStream.cc | 86 - storage/ibmdb2i/db2i_sqlStatementStream.h | 151 - storage/ibmdb2i/db2i_validatedPointer.h | 162 - storage/ibmdb2i/ha_ibmdb2i.cc | 3359 ----------------- storage/ibmdb2i/ha_ibmdb2i.h | 822 ---- storage/ibmdb2i/plug.in | 12 - 52 files changed, 19683 deletions(-) delete mode 100755 mysql-test/suite/ibmdb2i/include/have_i54.inc delete mode 100644 mysql-test/suite/ibmdb2i/include/have_i61.inc delete mode 100644 mysql-test/suite/ibmdb2i/include/have_ibmdb2i.inc delete mode 100644 mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44020.result delete mode 100644 mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44025.result delete mode 100755 mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44232.result delete mode 100755 mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44610.result delete mode 100644 mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45196.result delete mode 100644 mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45793.result delete mode 100644 mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45983.result delete mode 100644 mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_49329.result delete mode 100644 mysql-test/suite/ibmdb2i/r/ibmdb2i_collations.result delete mode 100644 mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44020.test delete mode 100644 mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44025.test delete mode 100755 mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44232.test delete mode 100755 mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44610.test delete mode 100644 mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45196.test delete mode 100644 mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45793.test delete mode 100644 mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45983.test delete mode 100644 mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_49329.test delete mode 100644 mysql-test/suite/ibmdb2i/t/ibmdb2i_collations.test delete mode 100644 storage/ibmdb2i/CMakeLists.txt delete mode 100644 storage/ibmdb2i/Makefile.am delete mode 100644 storage/ibmdb2i/db2i_blobCollection.cc delete mode 100644 storage/ibmdb2i/db2i_blobCollection.h delete mode 100644 storage/ibmdb2i/db2i_charsetSupport.cc delete mode 100644 storage/ibmdb2i/db2i_charsetSupport.h delete mode 100644 storage/ibmdb2i/db2i_collationSupport.cc delete mode 100644 storage/ibmdb2i/db2i_collationSupport.h delete mode 100644 storage/ibmdb2i/db2i_constraints.cc delete mode 100644 storage/ibmdb2i/db2i_conversion.cc delete mode 100644 storage/ibmdb2i/db2i_errors.cc delete mode 100644 storage/ibmdb2i/db2i_errors.h delete mode 100644 storage/ibmdb2i/db2i_file.cc delete mode 100644 storage/ibmdb2i/db2i_file.h delete mode 100644 storage/ibmdb2i/db2i_global.h delete mode 100644 storage/ibmdb2i/db2i_iconv.h delete mode 100644 storage/ibmdb2i/db2i_ileBridge.cc delete mode 100644 storage/ibmdb2i/db2i_ileBridge.h delete mode 100644 storage/ibmdb2i/db2i_ioBuffers.cc delete mode 100644 storage/ibmdb2i/db2i_ioBuffers.h delete mode 100644 storage/ibmdb2i/db2i_misc.h delete mode 100644 storage/ibmdb2i/db2i_myconv.cc delete mode 100644 storage/ibmdb2i/db2i_myconv.h delete mode 100644 storage/ibmdb2i/db2i_rir.cc delete mode 100644 storage/ibmdb2i/db2i_safeString.h delete mode 100644 storage/ibmdb2i/db2i_sqlStatementStream.cc delete mode 100644 storage/ibmdb2i/db2i_sqlStatementStream.h delete mode 100644 storage/ibmdb2i/db2i_validatedPointer.h delete mode 100644 storage/ibmdb2i/ha_ibmdb2i.cc delete mode 100644 storage/ibmdb2i/ha_ibmdb2i.h delete mode 100644 storage/ibmdb2i/plug.in diff --git a/mysql-test/suite/ibmdb2i/include/have_i54.inc b/mysql-test/suite/ibmdb2i/include/have_i54.inc deleted file mode 100755 index 7054e196153..00000000000 --- a/mysql-test/suite/ibmdb2i/include/have_i54.inc +++ /dev/null @@ -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"; -} - - diff --git a/mysql-test/suite/ibmdb2i/include/have_i61.inc b/mysql-test/suite/ibmdb2i/include/have_i61.inc deleted file mode 100644 index 84b9a17c1d8..00000000000 --- a/mysql-test/suite/ibmdb2i/include/have_i61.inc +++ /dev/null @@ -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"; -} - - diff --git a/mysql-test/suite/ibmdb2i/include/have_ibmdb2i.inc b/mysql-test/suite/ibmdb2i/include/have_ibmdb2i.inc deleted file mode 100644 index f3ef0b4f1ac..00000000000 --- a/mysql-test/suite/ibmdb2i/include/have_ibmdb2i.inc +++ /dev/null @@ -1,6 +0,0 @@ -if (!`SELECT count(*) FROM information_schema.engines WHERE - (support = 'YES' OR support = 'DEFAULT') AND - engine = 'ibmdb2i'`) -{ - skip Need ibmdb2i engine; -} diff --git a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44020.result b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44020.result deleted file mode 100644 index ddf92db6bca..00000000000 --- a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44020.result +++ /dev/null @@ -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_@$#`; diff --git a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44025.result b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44025.result deleted file mode 100644 index 10a3070fcc4..00000000000 --- a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44025.result +++ /dev/null @@ -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; diff --git a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44232.result b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44232.result deleted file mode 100755 index 8276b401073..00000000000 --- a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44232.result +++ /dev/null @@ -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) diff --git a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44610.result b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44610.result deleted file mode 100755 index 311e800e1b0..00000000000 --- a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44610.result +++ /dev/null @@ -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; diff --git a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45196.result b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45196.result deleted file mode 100644 index 916e1d93ee5..00000000000 --- a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45196.result +++ /dev/null @@ -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; diff --git a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45793.result b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45793.result deleted file mode 100644 index 2392b746877..00000000000 --- a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45793.result +++ /dev/null @@ -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; diff --git a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45983.result b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45983.result deleted file mode 100644 index b9f4dcfc656..00000000000 --- a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45983.result +++ /dev/null @@ -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; diff --git a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_49329.result b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_49329.result deleted file mode 100644 index d5bfc2579fd..00000000000 --- a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_49329.result +++ /dev/null @@ -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; diff --git a/mysql-test/suite/ibmdb2i/r/ibmdb2i_collations.result b/mysql-test/suite/ibmdb2i/r/ibmdb2i_collations.result deleted file mode 100644 index 4f7d71cab2d..00000000000 --- a/mysql-test/suite/ibmdb2i/r/ibmdb2i_collations.result +++ /dev/null @@ -1,1204 +0,0 @@ -drop table if exists t1, ffd, fd; -CREATE TABLE t1 (armscii8_bin integer, c char(10), v varchar(20), index(c), index(v)) collate armscii8_bin engine=ibmdb2i; -CREATE TABLE t1 (armscii8_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate armscii8_general_ci engine=ibmdb2i; -CREATE TABLE t1 (ascii_bin integer, c char(10), v varchar(20), index(c), index(v)) collate ascii_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (ascii_bin char(10) primary key) collate ascii_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ascii_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ascii_general_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (ascii_general_ci char(10) primary key) collate ascii_general_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (big5_bin integer, c char(10), v varchar(20), index(c), index(v)) collate big5_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (big5_bin char(10) primary key) collate big5_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (big5_chinese_ci integer, c char(10), v varchar(20), index(c), index(v)) collate big5_chinese_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (big5_chinese_ci char(10) primary key) collate big5_chinese_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp1250_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp1250_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (cp1250_bin char(10) primary key) collate cp1250_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp1250_croatian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1250_croatian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (cp1250_croatian_ci char(10) primary key) collate cp1250_croatian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp1250_czech_cs integer, c char(10), v varchar(20), index(c), index(v)) collate cp1250_czech_cs engine=ibmdb2i; -CREATE TABLE t1 (cp1250_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1250_general_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (cp1250_general_ci char(10) primary key) collate cp1250_general_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp1250_polish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1250_polish_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (cp1250_polish_ci char(10) primary key) collate cp1250_polish_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp1251_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp1251_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (cp1251_bin char(10) primary key) collate cp1251_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp1251_bulgarian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1251_bulgarian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (cp1251_bulgarian_ci char(10) primary key) collate cp1251_bulgarian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp1251_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1251_general_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (cp1251_general_ci char(10) primary key) collate cp1251_general_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp1251_general_cs integer, c char(10), v varchar(20), index(c), index(v)) collate cp1251_general_cs engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (cp1251_general_cs char(10) primary key) collate cp1251_general_cs engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp1251_ukrainian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1251_ukrainian_ci engine=ibmdb2i; -CREATE TABLE t1 (cp1256_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp1256_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (cp1256_bin char(10) primary key) collate cp1256_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp1256_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1256_general_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (cp1256_general_ci char(10) primary key) collate cp1256_general_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp1257_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp1257_bin engine=ibmdb2i; -CREATE TABLE t1 (cp1257_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1257_general_ci engine=ibmdb2i; -CREATE TABLE t1 (cp1257_lithuanian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1257_lithuanian_ci engine=ibmdb2i; -CREATE TABLE t1 (cp850_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp850_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (cp850_bin char(10) primary key) collate cp850_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp850_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp850_general_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (cp850_general_ci char(10) primary key) collate cp850_general_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp852_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp852_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (cp852_bin char(10) primary key) collate cp852_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp852_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp852_general_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (cp852_general_ci char(10) primary key) collate cp852_general_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp866_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp866_bin engine=ibmdb2i; -CREATE TABLE t1 (cp866_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp866_general_ci engine=ibmdb2i; -CREATE TABLE t1 (cp932_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp932_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (cp932_bin char(10) primary key) collate cp932_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (cp932_japanese_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp932_japanese_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (cp932_japanese_ci char(10) primary key) collate cp932_japanese_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (dec8_bin integer, c char(10), v varchar(20), index(c), index(v)) collate dec8_bin engine=ibmdb2i; -CREATE TABLE t1 (dec8_swedish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate dec8_swedish_ci engine=ibmdb2i; -CREATE TABLE t1 (eucjpms_bin integer, c char(10), v varchar(20), index(c), index(v)) collate eucjpms_bin engine=ibmdb2i; -CREATE TABLE t1 (eucjpms_japanese_ci integer, c char(10), v varchar(20), index(c), index(v)) collate eucjpms_japanese_ci engine=ibmdb2i; -CREATE TABLE t1 (euckr_bin integer, c char(10), v varchar(20), index(c), index(v)) collate euckr_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (euckr_bin char(10) primary key) collate euckr_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (euckr_korean_ci integer, c char(10), v varchar(20), index(c), index(v)) collate euckr_korean_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (euckr_korean_ci char(10) primary key) collate euckr_korean_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (gb2312_bin integer, c char(10), v varchar(20), index(c), index(v)) collate gb2312_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (gb2312_bin char(10) primary key) collate gb2312_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (gb2312_chinese_ci integer, c char(10), v varchar(20), index(c), index(v)) collate gb2312_chinese_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (gb2312_chinese_ci char(10) primary key) collate gb2312_chinese_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (gbk_bin integer, c char(10), v varchar(20), index(c), index(v)) collate gbk_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (gbk_bin char(10) primary key) collate gbk_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (gbk_chinese_ci integer, c char(10), v varchar(20), index(c), index(v)) collate gbk_chinese_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (gbk_chinese_ci char(10) primary key) collate gbk_chinese_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (geostd8_bin integer, c char(10), v varchar(20), index(c), index(v)) collate geostd8_bin engine=ibmdb2i; -CREATE TABLE t1 (geostd8_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate geostd8_general_ci engine=ibmdb2i; -CREATE TABLE t1 (greek_bin integer, c char(10), v varchar(20), index(c), index(v)) collate greek_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (greek_bin char(10) primary key) collate greek_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (greek_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate greek_general_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (greek_general_ci char(10) primary key) collate greek_general_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (hebrew_bin integer, c char(10), v varchar(20), index(c), index(v)) collate hebrew_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (hebrew_bin char(10) primary key) collate hebrew_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (hebrew_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate hebrew_general_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (hebrew_general_ci char(10) primary key) collate hebrew_general_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (hp8_bin integer, c char(10), v varchar(20), index(c), index(v)) collate hp8_bin engine=ibmdb2i; -CREATE TABLE t1 (hp8_english_ci integer, c char(10), v varchar(20), index(c), index(v)) collate hp8_english_ci engine=ibmdb2i; -CREATE TABLE t1 (keybcs2_bin integer, c char(10), v varchar(20), index(c), index(v)) collate keybcs2_bin engine=ibmdb2i; -CREATE TABLE t1 (keybcs2_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate keybcs2_general_ci engine=ibmdb2i; -CREATE TABLE t1 (koi8r_bin integer, c char(10), v varchar(20), index(c), index(v)) collate koi8r_bin engine=ibmdb2i; -CREATE TABLE t1 (koi8r_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate koi8r_general_ci engine=ibmdb2i; -CREATE TABLE t1 (koi8u_bin integer, c char(10), v varchar(20), index(c), index(v)) collate koi8u_bin engine=ibmdb2i; -CREATE TABLE t1 (koi8u_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate koi8u_general_ci engine=ibmdb2i; -CREATE TABLE t1 (latin1_bin integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (latin1_bin char(10) primary key) collate latin1_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (latin1_danish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_danish_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (latin1_danish_ci char(10) primary key) collate latin1_danish_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (latin1_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_general_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (latin1_general_ci char(10) primary key) collate latin1_general_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (latin1_general_cs integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_general_cs engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (latin1_general_cs char(10) primary key) collate latin1_general_cs engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (latin1_german1_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_german1_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (latin1_german1_ci char(10) primary key) collate latin1_german1_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (latin1_german2_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_german2_ci engine=ibmdb2i; -CREATE TABLE t1 (latin1_spanish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_spanish_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (latin1_spanish_ci char(10) primary key) collate latin1_spanish_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (latin1_swedish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_swedish_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (latin1_swedish_ci char(10) primary key) collate latin1_swedish_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (latin2_bin integer, c char(10), v varchar(20), index(c), index(v)) collate latin2_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (latin2_bin char(10) primary key) collate latin2_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (latin2_croatian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin2_croatian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (latin2_croatian_ci char(10) primary key) collate latin2_croatian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (latin2_czech_cs integer, c char(10), v varchar(20), index(c), index(v)) collate latin2_czech_cs engine=ibmdb2i; -CREATE TABLE t1 (latin2_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin2_general_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (latin2_general_ci char(10) primary key) collate latin2_general_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (latin2_hungarian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin2_hungarian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (latin2_hungarian_ci char(10) primary key) collate latin2_hungarian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (latin5_bin integer, c char(10), v varchar(20), index(c), index(v)) collate latin5_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (latin5_bin char(10) primary key) collate latin5_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (latin5_turkish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin5_turkish_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (latin5_turkish_ci char(10) primary key) collate latin5_turkish_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (latin7_bin integer, c char(10), v varchar(20), index(c), index(v)) collate latin7_bin engine=ibmdb2i; -CREATE TABLE t1 (latin7_estonian_cs integer, c char(10), v varchar(20), index(c), index(v)) collate latin7_estonian_cs engine=ibmdb2i; -CREATE TABLE t1 (latin7_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin7_general_ci engine=ibmdb2i; -CREATE TABLE t1 (latin7_general_cs integer, c char(10), v varchar(20), index(c), index(v)) collate latin7_general_cs engine=ibmdb2i; -CREATE TABLE t1 (macce_bin integer, c char(10), v varchar(20), index(c), index(v)) collate macce_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (macce_bin char(10) primary key) collate macce_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (macce_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate macce_general_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (macce_general_ci char(10) primary key) collate macce_general_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (macroman_bin integer, c char(10), v varchar(20), index(c), index(v)) collate macroman_bin engine=ibmdb2i; -CREATE TABLE t1 (macroman_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate macroman_general_ci engine=ibmdb2i; -CREATE TABLE t1 (sjis_bin integer, c char(10), v varchar(20), index(c), index(v)) collate sjis_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (sjis_bin char(10) primary key) collate sjis_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (sjis_japanese_ci integer, c char(10), v varchar(20), index(c), index(v)) collate sjis_japanese_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (sjis_japanese_ci char(10) primary key) collate sjis_japanese_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (swe7_bin integer, c char(10), v varchar(20), index(c), index(v)) collate swe7_bin engine=ibmdb2i; -CREATE TABLE t1 (swe7_swedish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate swe7_swedish_ci engine=ibmdb2i; -CREATE TABLE t1 (tis620_bin integer, c char(10), v varchar(20), index(c), index(v)) collate tis620_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (tis620_bin char(10) primary key) collate tis620_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (tis620_thai_ci integer, c char(10), v varchar(20), index(c), index(v)) collate tis620_thai_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 11 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 23 NULL 6 Using where -drop table t1; -create table t1 (tis620_thai_ci char(10) primary key) collate tis620_thai_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_bin integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_bin char(10) primary key) collate ucs2_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_czech_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_czech_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_czech_ci char(10) primary key) collate ucs2_czech_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_danish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_danish_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_danish_ci char(10) primary key) collate ucs2_danish_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_esperanto_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_esperanto_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_esperanto_ci char(10) primary key) collate ucs2_esperanto_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_estonian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_estonian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_estonian_ci char(10) primary key) collate ucs2_estonian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_general_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_general_ci char(10) primary key) collate ucs2_general_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_hungarian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_hungarian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_hungarian_ci char(10) primary key) collate ucs2_hungarian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_icelandic_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_icelandic_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_icelandic_ci char(10) primary key) collate ucs2_icelandic_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_latvian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_latvian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_latvian_ci char(10) primary key) collate ucs2_latvian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_lithuanian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_lithuanian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_lithuanian_ci char(10) primary key) collate ucs2_lithuanian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_persian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_persian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_persian_ci char(10) primary key) collate ucs2_persian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_polish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_polish_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_polish_ci char(10) primary key) collate ucs2_polish_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_romanian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_romanian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_romanian_ci char(10) primary key) collate ucs2_romanian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_roman_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_roman_ci engine=ibmdb2i; -CREATE TABLE t1 (ucs2_slovak_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_slovak_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_slovak_ci char(10) primary key) collate ucs2_slovak_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_slovenian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_slovenian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_slovenian_ci char(10) primary key) collate ucs2_slovenian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_spanish2_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_spanish2_ci engine=ibmdb2i; -CREATE TABLE t1 (ucs2_spanish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_spanish_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_spanish_ci char(10) primary key) collate ucs2_spanish_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_swedish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_swedish_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_swedish_ci char(10) primary key) collate ucs2_swedish_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_turkish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_turkish_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_turkish_ci char(10) primary key) collate ucs2_turkish_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ucs2_unicode_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_unicode_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 21 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 43 NULL 6 Using where -drop table t1; -create table t1 (ucs2_unicode_ci char(10) primary key) collate ucs2_unicode_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ujis_bin integer, c char(10), v varchar(20), index(c), index(v)) collate ujis_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (ujis_bin char(10) primary key) collate ujis_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (ujis_japanese_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ujis_japanese_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (ujis_japanese_ci char(10) primary key) collate ujis_japanese_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_bin integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_bin engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_bin char(10) primary key) collate utf8_bin engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_czech_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_czech_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_czech_ci char(10) primary key) collate utf8_czech_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_danish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_danish_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_danish_ci char(10) primary key) collate utf8_danish_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_esperanto_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_esperanto_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_esperanto_ci char(10) primary key) collate utf8_esperanto_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_estonian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_estonian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_estonian_ci char(10) primary key) collate utf8_estonian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_general_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_general_ci char(10) primary key) collate utf8_general_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_hungarian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_hungarian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_hungarian_ci char(10) primary key) collate utf8_hungarian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_icelandic_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_icelandic_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_icelandic_ci char(10) primary key) collate utf8_icelandic_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_latvian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_latvian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_latvian_ci char(10) primary key) collate utf8_latvian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_lithuanian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_lithuanian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_lithuanian_ci char(10) primary key) collate utf8_lithuanian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_persian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_persian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_persian_ci char(10) primary key) collate utf8_persian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_polish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_polish_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_polish_ci char(10) primary key) collate utf8_polish_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_romanian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_romanian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_romanian_ci char(10) primary key) collate utf8_romanian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_roman_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_roman_ci engine=ibmdb2i; -CREATE TABLE t1 (utf8_slovak_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_slovak_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_slovak_ci char(10) primary key) collate utf8_slovak_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_slovenian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_slovenian_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_slovenian_ci char(10) primary key) collate utf8_slovenian_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_spanish2_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_spanish2_ci engine=ibmdb2i; -CREATE TABLE t1 (utf8_spanish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_spanish_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_spanish_ci char(10) primary key) collate utf8_spanish_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_swedish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_swedish_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_swedish_ci char(10) primary key) collate utf8_swedish_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_turkish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_turkish_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_turkish_ci char(10) primary key) collate utf8_turkish_ci engine=ibmdb2i; -drop table t1; -CREATE TABLE t1 (utf8_unicode_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_unicode_ci engine=ibmdb2i; -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%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 31 NULL 6 Using where -explain select c,v from t1 force index(v) where v like "de%"; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 63 NULL 6 Using where -drop table t1; -create table t1 (utf8_unicode_ci char(10) primary key) collate utf8_unicode_ci engine=ibmdb2i; -drop table t1; -create table ffd (WHCHD1 CHAR(20), WHCSID decimal(5,0)) engine=ibmdb2i; -create table fd (SQSSEQ CHAR(10)) engine=ibmdb2i; -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; -ccsid cs srtseq -500 "ascii_bin" QBLA101F4U -500 "ascii_general_ci" QALA101F4S -1200 "big5_bin" QBCHT04B0U -1200 "big5_chinese_ci" QACHT04B0S -1153 "cp1250_bin" QELA20481U -1153 "cp1250_croatian_ci" QALA20481S -1153 "cp1250_general_ci" QCLA20481S -1153 "cp1250_polish_ci" QDLA20481S -1025 "cp1251_bin" QCCYR0401U -1025 "cp1251_bulgarian_ci QACYR0401S -1025 "cp1251_general_ci" QBCYR0401S -1025 "cp1251_general_cs" QBCYR0401U -420 "cp1256_bin" QBARA01A4U -420 "cp1256_general_ci" QAARA01A4S -500 "cp850_bin" QDLA101F4U -500 "cp850_general_ci" QCLA101F4S -870 "cp852_bin" QBLA20366U -870 "cp852_general_ci" QALA20366S -1200 "cp932_bin" QBJPN04B0U -1200 "cp932_japanese_ci" QAJPN04B0S -1200 "euckr_bin" QBKOR04B0U -1200 "euckr_korean_ci" QAKOR04B0S -1200 "gb2312_bin" QBCHS04B0U -1200 "gb2312_chinese_ci" QACHS04B0S -1200 "gbk_bin" QDCHS04B0U -1200 "gbk_chinese_ci" QCCHS04B0S -875 "greek_bin" QBELL036BU -875 "greek_general_ci" QAELL036BS -424 "hebrew_bin" QBHEB01A8U -424 "hebrew_general_ci" QAHEB01A8S -1148 "latin1_bin" QFLA1047CU -1148 "latin1_danish_ci" QALA1047CS -1148 "latin1_general_ci" QBLA1047CS -1148 "latin1_general_cs" QBLA1047CU -1148 "latin1_german1_ci" QCLA1047CS -1148 "latin1_spanish_ci" QDLA1047CS -1148 "latin1_swedish_ci" QELA1047CS -870 "latin2_bin" QGLA20366U -870 "latin2_croatian_ci" QCLA20366S -870 "latin2_general_ci" QELA20366S -870 "latin2_hungarian_ci QFLA20366S -1026 "latin5_bin" QBTRK0402U -1026 "latin5_turkish_ci" QATRK0402S -870 "macce_bin" QILA20366U -870 "macce_general_ci" QHLA20366S -1200 "sjis_bin" QDJPN04B0U -1200 "sjis_japanese_ci" QCJPN04B0S -838 "tis620_bin" QBTHA0346U -838 "tis620_thai_ci" QATHA0346S -13488 "ucs2_bin" *HEX -13488 "ucs2_czech_ci" I34ACS_CZ -13488 "ucs2_danish_ci" I34ADA_DK -13488 "ucs2_esperanto_ci" I34AEO -13488 "ucs2_estonian_ci" I34AET -13488 "ucs2_general_ci" QAUCS04B0S -13488 "ucs2_hungarian_ci" I34AHU -13488 "ucs2_icelandic_ci" I34AIS -13488 "ucs2_latvian_ci" I34ALV -13488 "ucs2_lithuanian_ci" I34ALT -13488 "ucs2_persian_ci" I34AFA -13488 "ucs2_polish_ci" I34APL -13488 "ucs2_romanian_ci" I34ARO -13488 "ucs2_slovak_ci" I34ASK -13488 "ucs2_slovenian_ci" I34ASL -13488 "ucs2_spanish_ci" I34AES -13488 "ucs2_swedish_ci" I34ASW -13488 "ucs2_turkish_ci" I34ATR -13488 "ucs2_unicode_ci" I34AEN -1200 "ujis_bin" QFJPN04B0U -1200 "ujis_japanese_ci" QEJPN04B0S -1208 "utf8_bin" *HEX -1208 "utf8_czech_ci" I34ACS_CZ -1208 "utf8_danish_ci" I34ADA_DK -1208 "utf8_esperanto_ci" I34AEO -1208 "utf8_estonian_ci" I34AET -1200 "utf8_general_ci" QAUCS04B0S -1208 "utf8_hungarian_ci" I34AHU -1208 "utf8_icelandic_ci" I34AIS -1208 "utf8_latvian_ci" I34ALV -1208 "utf8_lithuanian_ci" I34ALT -1208 "utf8_persian_ci" I34AFA -1208 "utf8_polish_ci" I34APL -1208 "utf8_romanian_ci" I34ARO -1208 "utf8_slovak_ci" I34ASK -1208 "utf8_slovenian_ci" I34ASL -1208 "utf8_spanish_ci" I34AES -1208 "utf8_swedish_ci" I34ASW -1208 "utf8_turkish_ci" I34ATR -1208 "utf8_unicode_ci" I34AEN -drop table ffd, fd; diff --git a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44020.test b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44020.test deleted file mode 100644 index 09a7c75cfc0..00000000000 --- a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44020.test +++ /dev/null @@ -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_@$#`; diff --git a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44025.test b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44025.test deleted file mode 100644 index 9b033a2298f..00000000000 --- a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44025.test +++ /dev/null @@ -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; diff --git a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44232.test b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44232.test deleted file mode 100755 index ea29b5abcd4..00000000000 --- a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44232.test +++ /dev/null @@ -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; diff --git a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44610.test b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44610.test deleted file mode 100755 index da69b5d9148..00000000000 --- a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44610.test +++ /dev/null @@ -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; diff --git a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45196.test b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45196.test deleted file mode 100644 index 17b1d658975..00000000000 --- a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45196.test +++ /dev/null @@ -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; diff --git a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45793.test b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45793.test deleted file mode 100644 index 93fb78ff421..00000000000 --- a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45793.test +++ /dev/null @@ -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; diff --git a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45983.test b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45983.test deleted file mode 100644 index 695d8e90ada..00000000000 --- a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45983.test +++ /dev/null @@ -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; diff --git a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_49329.test b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_49329.test deleted file mode 100644 index 615df284d8f..00000000000 --- a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_49329.test +++ /dev/null @@ -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; diff --git a/mysql-test/suite/ibmdb2i/t/ibmdb2i_collations.test b/mysql-test/suite/ibmdb2i/t/ibmdb2i_collations.test deleted file mode 100644 index 899f330d360..00000000000 --- a/mysql-test/suite/ibmdb2i/t/ibmdb2i_collations.test +++ /dev/null @@ -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; diff --git a/storage/ibmdb2i/CMakeLists.txt b/storage/ibmdb2i/CMakeLists.txt deleted file mode 100644 index 11cc4300569..00000000000 --- a/storage/ibmdb2i/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (C) 2006 MySQL AB -# -# 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 - -SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") -SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX") - -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql - ${CMAKE_SOURCE_DIR}/regex - ${CMAKE_SOURCE_DIR}/extra/yassl/include) -ADD_LIBRARY(ibmdb2i 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) diff --git a/storage/ibmdb2i/Makefile.am b/storage/ibmdb2i/Makefile.am deleted file mode 100644 index b9602e392e0..00000000000 --- a/storage/ibmdb2i/Makefile.am +++ /dev/null @@ -1,54 +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 -# Don't update the files from bitkeeper -%::SCCS/s.% diff --git a/storage/ibmdb2i/db2i_blobCollection.cc b/storage/ibmdb2i/db2i_blobCollection.cc deleted file mode 100644 index 17101c9c0a4..00000000000 --- a/storage/ibmdb2i/db2i_blobCollection.cc +++ /dev/null @@ -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& -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(); -} diff --git a/storage/ibmdb2i/db2i_blobCollection.h b/storage/ibmdb2i/db2i_blobCollection.h deleted file mode 100644 index 6a60394555f..00000000000 --- a/storage/ibmdb2i/db2i_blobCollection.h +++ /dev/null @@ -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& 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 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& getBufferPtr(int fieldIndex) - { - int blobIndex = table->getBlobIdFromField(fieldIndex); - if ((char*)buffers[blobIndex].ptr() == NULL) - generateBuffer(fieldIndex); - - return buffers[blobIndex].ptr(); - } - - ValidatedPointer& 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 diff --git a/storage/ibmdb2i/db2i_charsetSupport.cc b/storage/ibmdb2i/db2i_charsetSupport.cc deleted file mode 100644 index 83bf1b9448b..00000000000 --- a/storage/ibmdb2i/db2i_charsetSupport.cc +++ /dev/null @@ -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)); - 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)); - 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); - hash_free(&textDescMapHash); - pthread_mutex_destroy(&iconvMapHashMutex); - 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 *) 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 *) 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; -} diff --git a/storage/ibmdb2i/db2i_charsetSupport.h b/storage/ibmdb2i/db2i_charsetSupport.h deleted file mode 100644 index 77051e1e0db..00000000000 --- a/storage/ibmdb2i/db2i_charsetSupport.h +++ /dev/null @@ -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 -#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 diff --git a/storage/ibmdb2i/db2i_collationSupport.cc b/storage/ibmdb2i/db2i_collationSupport.cc deleted file mode 100644 index 65a17fd2452..00000000000 --- a/storage/ibmdb2i/db2i_collationSupport.cc +++ /dev/null @@ -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); -} diff --git a/storage/ibmdb2i/db2i_collationSupport.h b/storage/ibmdb2i/db2i_collationSupport.h deleted file mode 100644 index b2ce09de1ea..00000000000 --- a/storage/ibmdb2i/db2i_collationSupport.h +++ /dev/null @@ -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 diff --git a/storage/ibmdb2i/db2i_constraints.cc b/storage/ibmdb2i/db2i_constraints.cc deleted file mode 100644 index 1fde0dd3d14..00000000000 --- a/storage/ibmdb2i/db2i_constraints.cc +++ /dev/null @@ -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 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) - { - 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, db2FKName, sizeof(db2FKName)); - appendHere.append(db2FKName); - } - - appendHere.append(STRING_WITH_LEN(" FOREIGN KEY (")); - - bool firstTime = true; - - List_iterator column(fk->columns); - Key_part_spec* curColumn; - - while (curColumn = column++) - { - if (!firstTime) - { - appendHere.append(','); - } - firstTime = false; - - convertMySQLNameToDB2Name(curColumn->field_name, 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) == 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 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, 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 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, MYF(0)); - } - 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 *f_key_list) -{ - DBUG_ENTER("ha_ibmdb2i::get_foreign_key_list"); - int rc = 0; - uint32 constraintSpaceLength; // Length of space passed to DB2 - ValidatedPointer 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.forein_id = thd_make_lex_string(thd, 0, - convName + 1, (uint) (FKCstDef->CstName.Len - 2), 1); - else // Not quoted - f_key_info.forein_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); -} diff --git a/storage/ibmdb2i/db2i_conversion.cc b/storage/ibmdb2i/db2i_conversion.cc deleted file mode 100644 index 9a85eb01c9b..00000000000 --- a/storage/ibmdb2i/db2i_conversion.cc +++ /dev/null @@ -1,1459 +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_ileBridge.h" -#include "mysql_priv.h" -#include "db2i_charsetSupport.h" -#include "ctype.h" -#include "ha_ibmdb2i.h" -#include "db2i_errors.h" -#include "wchar.h" - -const char ZERO_DATETIME_VALUE[] = "0000-00-00 00:00:00"; -const char ZERO_DATETIME_VALUE_SUBST[] = "0001-01-01 00:00:00"; -const char ZERO_DATE_VALUE[] = "0000-00-00"; -const char ZERO_DATE_VALUE_SUBST[] = "0001-01-01"; - - -/** - Put a BCD digit into a BCD string. - - @param[out] bcdString The BCD string to be modified - @param pos The position within the string to be updated. - @param val The value to be assigned into the string at pos. -*/ -static inline void bcdAssign(char* bcdString, uint pos, uint val) -{ - bcdString[pos/2] |= val << ((pos % 2) ? 0 : 4); -} - -/** - Read a BCD digit from a BCD string. - - @param[out] bcdString The BCD string to be read - @param pos The position within the string to be read. - - @return bcdGet The value of the BCD digit at pos. -*/ -static inline uint bcdGet(const char* bcdString, uint pos) -{ - return (bcdString[pos/2] >> ((pos % 2) ? 0 : 4)) & 0xf; -} - -/** - In-place convert a number in ASCII represenation to EBCDIC representation. - - @param string The string of ASCII characters - @param len The length of string -*/ -static inline void convertNumericToEbcdicFast(char* string, int len) -{ - for (int i = 0; i < len; ++i, ++string) - { - switch(*string) - { - case '-': - *string = 0x60; break; - case ':': - *string = 0x7A; break; - case '.': - *string = 0x4B; break; - default: - DBUG_ASSERT(isdigit(*string)); - *string += 0xF0 - '0'; - break; - } - } -} - - -/** - atoi()-like function for a 4-character EBCDIC string. - - @param string The EBCDIC string - @return a4toi_ebcdic The decimal value of the EBCDIC string -*/ -static inline uint16 a4toi_ebcdic(const uchar* string) -{ - return ((string[0]-0xF0) * 1000 + - (string[1]-0xF0) * 100 + - (string[2]-0xF0) * 10 + - (string[3]-0xF0)); -}; - - -/** - atoi()-like function for a 4-character EBCDIC string. - - @param string The EBCDIC string - @return a4toi_ebcdic The decimal value of the EBCDIC string -*/ -static inline uint8 a2toi_ebcdic(const uchar* string) -{ - return ((string[0]-0xF0) * 10 + - (string[1]-0xF0)); -}; - -/** - Perform character conversion for textual field data. -*/ -int ha_ibmdb2i::convertFieldChars(enum_conversionDirection direction, - uint16 fieldID, - const char* input, - char* output, - size_t ilen, - size_t olen, - size_t* outDataLen, - bool tacitErrors, - size_t* substChars) -{ - DBUG_PRINT("ha_ibmdb2i::convertFieldChars",("Direction: %d; length = %d", direction, ilen)); - - if (unlikely(ilen == 0)) - { - if (outDataLen) *outDataLen = 0; - return (0); - } - - iconv_t& conversion = db2Table->getConversionDefinition(direction, fieldID); - - if (unlikely(conversion == (iconv_t)(-1))) - { - return (DB2I_ERR_UNSUPP_CHARSET); - } - - size_t initOLen= olen; - size_t substitutedChars = 0; - int rc = iconv(conversion, (char**)&input, &ilen, &output, &olen, &substitutedChars ); - if (outDataLen) *outDataLen = initOLen - olen; - if (substChars) *substChars = substitutedChars; - if (unlikely(rc < 0)) - { - int er = errno; - if (er == EILSEQ) - { - if (!tacitErrors) getErrTxt(DB2I_ERR_ILL_CHAR, table->field[fieldID]->field_name); - return (DB2I_ERR_ILL_CHAR); - } - else - { - if (!tacitErrors) getErrTxt(DB2I_ERR_ICONV,er); - return (DB2I_ERR_ICONV); - } - } - if (unlikely(substitutedChars) && (!tacitErrors)) - { - warning(ha_thd(), DB2I_ERR_SUB_CHARS, table->field[fieldID]->field_name); - } - - return (0); -} - -/** - Append the appropriate default value clause onto a CREATE TABLE definition - - This was inspired by get_field_default_value in sql/sql_show.cc. - - @param field The field whose value is to be obtained - @param statement The string to receive the DEFAULT clause - @param quoteIt Does the data type require single quotes around the value? - @param ccsid The ccsid of the field value (if a string type); 0 if no conversion needed -*/ -static void get_field_default_value(Field *field, - String &statement, - bool quoteIt, - uint32 ccsid, - bool substituteZeroDates) -{ - if ((field->type() != FIELD_TYPE_BLOB && - !(field->flags & NO_DEFAULT_VALUE_FLAG) && - field->unireg_check != Field::NEXT_NUMBER)) - { - my_ptrdiff_t old_ptr= (my_ptrdiff_t) (field->table->s->default_values - field->table->record[0]); - field->move_field_offset(old_ptr); - - String defaultClause(64); - defaultClause.length(0); - defaultClause.append(" DEFAULT "); - if (!field->is_null()) - { - my_bitmap_map *old_map = tmp_use_all_columns(field->table, field->table->read_set); - char tmp[MAX_FIELD_WIDTH]; - - if (field->real_type() == MYSQL_TYPE_ENUM || - field->real_type() == MYSQL_TYPE_SET) - { - CHARSET_INFO *cs= &my_charset_bin; - uint len = (uint)(cs->cset->longlong10_to_str)(cs,tmp,sizeof(tmp), 10, field->val_int()); - tmp[len]=0; - defaultClause.append(tmp); - } - else - { - String type(tmp, sizeof(tmp), field->charset()); - field->val_str(&type); - if (type.length()) - { - if (field->type() == MYSQL_TYPE_DATE && - memcmp(type.ptr(), STRING_WITH_LEN(ZERO_DATE_VALUE)) == 0) - { - if (substituteZeroDates) - type.set(STRING_WITH_LEN(ZERO_DATE_VALUE_SUBST), field->charset()); - else - { - warning(current_thd, DB2I_ERR_WARN_COL_ATTRS, field->field_name); - return; - } - } - else if ((field->type() == MYSQL_TYPE_DATETIME || - field->type() == MYSQL_TYPE_TIMESTAMP) && - memcmp(type.ptr(), STRING_WITH_LEN(ZERO_DATETIME_VALUE)) == 0) - { - if (substituteZeroDates) - type.set(STRING_WITH_LEN(ZERO_DATETIME_VALUE_SUBST), field->charset()); - else - { - warning(current_thd, DB2I_ERR_WARN_COL_ATTRS, field->field_name); - return; - } - } - - - if (field->type() != MYSQL_TYPE_STRING && - field->type() != MYSQL_TYPE_VARCHAR && - field->type() != MYSQL_TYPE_BLOB && - field->type() != MYSQL_TYPE_BIT) - { - if (quoteIt) - defaultClause.append('\''); - defaultClause.append(type); - if (quoteIt) - defaultClause.append('\''); - } - else - { - int length; - char* out; - - // If a ccsid is specified, we need to make sure that the DEFAULT - // string is converted to that encoding. - if (ccsid != 0) - { - iconv_t iconvD; - if (getConversion(toDB2, field->charset(), ccsid, iconvD)) - { - warning(current_thd, DB2I_ERR_WARN_COL_ATTRS, field->field_name); - return; - } - - size_t ilen = type.length(); - size_t olen = 6 * ilen; - size_t origOlen = olen; - const char* in = type.ptr(); - const char* tempIn = in; - out = (char*)my_malloc(olen, MYF(MY_WME)); - char* tempOut = out; - size_t substitutedChars; - - if (iconv(iconvD, (char**)&tempIn, &ilen, &tempOut, &olen, &substitutedChars) < 0) - { - warning(current_thd, DB2I_ERR_WARN_COL_ATTRS, field->field_name); - my_free(out, MYF(0)); - return; - } - // Now we process the converted string to represent it as - // hexadecimal values. - - length = origOlen - olen; - } - else - { - length = type.length(); - out = (char*)my_malloc(length*2, MYF(MY_WME)); - memcpy(out, (char*)type.ptr(), length); - } - - if (length > 16370) - { - warning(current_thd, DB2I_ERR_WARN_COL_ATTRS, field->field_name); - my_free(out, MYF(0)); - return; - } - - if (ccsid == 1200) - defaultClause.append("ux'"); - else if (ccsid == 13488) - defaultClause.append("gx'"); - else if (field->charset() == &my_charset_bin) - defaultClause.append("binary(x'"); - else - defaultClause.append("x'"); - - const char hexMap[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; - for (int c = length-1; c >= 0; --c) - { - out[c*2+1] = hexMap[out[c] & 0xF]; - out[c*2] = hexMap[out[c] >> 4]; - } - - defaultClause.append(out, length*2); - defaultClause.append('\''); - if (field->charset() == &my_charset_bin) - defaultClause.append(")"); - - my_free(out, MYF(0)); - } - } - else - defaultClause.length(0); - } - tmp_restore_column_map(field->table->read_set, old_map); - } - else if (field->maybe_null()) - defaultClause.append(STRING_WITH_LEN("NULL")); - - if (old_ptr) - field->move_field_offset(-old_ptr); - - statement.append(defaultClause); - } -} - - - - -/** - Convert a MySQL field definition into its corresponding DB2 type. - - The result will be appended to mapping as a DB2 SQL phrase. - - @param field The MySQL field to be evaluated - @param[out] mapping The receiver for the DB2 SQL syntax - @param timeFormat The format to be used for mapping the TIME type -*/ -int ha_ibmdb2i::getFieldTypeMapping(Field* field, - String& mapping, - enum_TimeFormat timeFormat, - enum_BlobMapping blobMapping, - enum_ZeroDate zeroDateHandling, - bool propagateDefaults, - enum_YearFormat yearFormat) -{ - char stringBuildBuffer[257]; - uint32 fieldLength; - bool defaultNeedsQuotes = false; - uint16 db2Ccsid = 0; - - CHARSET_INFO* fieldCharSet = field->charset(); - switch (field->type()) - { - case MYSQL_TYPE_NEWDECIMAL: - { - uint precision= ((Field_new_decimal*)field)->precision; - uint scale= field->decimals(); - - if (precision <= MAX_DEC_PRECISION) - { - sprintf(stringBuildBuffer,"DECIMAL(%d, %d)",precision,scale); - } - else - { - if (scale > precision - MAX_DEC_PRECISION) - { - scale = scale - (precision - MAX_DEC_PRECISION); - precision = MAX_DEC_PRECISION; - sprintf(stringBuildBuffer,"DECIMAL(%d, %d)",precision,scale); - } - else - { - return HA_ERR_UNSUPPORTED; - } - warning(ha_thd(), DB2I_ERR_PRECISION); - } - - mapping.append(stringBuildBuffer); - } - break; - case MYSQL_TYPE_TINY: - mapping.append(STRING_WITH_LEN("SMALLINT")); - break; - case MYSQL_TYPE_SHORT: - if (((Field_num*)field)->unsigned_flag) - mapping.append(STRING_WITH_LEN("INT")); - else - mapping.append(STRING_WITH_LEN("SMALLINT")); - break; - case MYSQL_TYPE_LONG: - if (((Field_num*)field)->unsigned_flag) - mapping.append(STRING_WITH_LEN("BIGINT")); - else - mapping.append(STRING_WITH_LEN("INT")); - break; - case MYSQL_TYPE_FLOAT: - mapping.append(STRING_WITH_LEN("REAL")); - break; - case MYSQL_TYPE_DOUBLE: - mapping.append(STRING_WITH_LEN("DOUBLE")); - break; - case MYSQL_TYPE_LONGLONG: - if (((Field_num*)field)->unsigned_flag) - mapping.append(STRING_WITH_LEN("DECIMAL(20,0)")); - else - mapping.append(STRING_WITH_LEN("BIGINT")); - break; - case MYSQL_TYPE_INT24: - mapping.append(STRING_WITH_LEN("INTEGER")); - break; - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_NEWDATE: - mapping.append(STRING_WITH_LEN("DATE")); - defaultNeedsQuotes = true; - break; - case MYSQL_TYPE_TIME: - if (timeFormat == TIME_OF_DAY) - { - mapping.append(STRING_WITH_LEN("TIME")); - defaultNeedsQuotes = true; - } - else - mapping.append(STRING_WITH_LEN("INTEGER")); - break; - case MYSQL_TYPE_DATETIME: - mapping.append(STRING_WITH_LEN("TIMESTAMP")); - defaultNeedsQuotes = true; - break; - case MYSQL_TYPE_TIMESTAMP: - mapping.append(STRING_WITH_LEN("TIMESTAMP")); - - if (table_share->timestamp_field == field && propagateDefaults) - { - switch (((Field_timestamp*)field)->get_auto_set_type()) - { - case TIMESTAMP_NO_AUTO_SET: - break; - case TIMESTAMP_AUTO_SET_ON_INSERT: - mapping.append(STRING_WITH_LEN(" DEFAULT CURRENT_TIMESTAMP")); - break; - case TIMESTAMP_AUTO_SET_ON_UPDATE: - if (osVersion.v >= 6 && - !field->is_null()) - { - mapping.append(STRING_WITH_LEN(" GENERATED BY DEFAULT FOR EACH ROW ON UPDATE AS ROW CHANGE TIMESTAMP")); - warning(ha_thd(), DB2I_ERR_WARN_COL_ATTRS, field->field_name); - } - else - warning(ha_thd(), DB2I_ERR_WARN_COL_ATTRS, field->field_name); - break; - case TIMESTAMP_AUTO_SET_ON_BOTH: - if (osVersion.v >= 6 && - !field->is_null()) - mapping.append(STRING_WITH_LEN(" GENERATED BY DEFAULT FOR EACH ROW ON UPDATE AS ROW CHANGE TIMESTAMP")); - else - { - mapping.append(STRING_WITH_LEN(" DEFAULT CURRENT_TIMESTAMP")); - warning(ha_thd(), DB2I_ERR_WARN_COL_ATTRS, field->field_name); - } - break; - } - } - else - defaultNeedsQuotes = true; - break; - case MYSQL_TYPE_YEAR: - if (yearFormat == CHAR4) - { - mapping.append(STRING_WITH_LEN("CHAR(4) CCSID 1208")); - defaultNeedsQuotes = true; - } - else - { - mapping.append(STRING_WITH_LEN("SMALLINT")); - defaultNeedsQuotes = false; - } - break; - case MYSQL_TYPE_BIT: - sprintf(stringBuildBuffer, "BINARY(%d)", (field->max_display_length() / 8) + 1); - mapping.append(stringBuildBuffer); - break; - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_VARCHAR: - case MYSQL_TYPE_STRING: - { - if (field->real_type() == MYSQL_TYPE_ENUM || - field->real_type() == MYSQL_TYPE_SET) - { - mapping.append(STRING_WITH_LEN("BIGINT")); - } - else - { - defaultNeedsQuotes = true; - - fieldLength = field->max_display_length(); // Get field byte length - - if (fieldCharSet == &my_charset_bin) - { - if (field->type() == MYSQL_TYPE_STRING) - { - sprintf(stringBuildBuffer, "BINARY(%d)", max(fieldLength, 1)); - } - else - { - if (fieldLength <= MAX_VARCHAR_LENGTH) - { - sprintf(stringBuildBuffer, "VARBINARY(%d)", max(fieldLength, 1)); - } - else if (blobMapping == AS_VARCHAR && - (field->flags & PART_KEY_FLAG)) - { - sprintf(stringBuildBuffer, "LONG VARBINARY "); - } - else - { - fieldLength = min(MAX_BLOB_LENGTH, fieldLength); - sprintf(stringBuildBuffer, "BLOB(%d)", max(fieldLength, 1)); - } - } - mapping.append(stringBuildBuffer); - } - else - { - if (field->type() == MYSQL_TYPE_STRING) - { - if (fieldLength > MAX_CHAR_LENGTH) - return 1; - if (fieldCharSet->mbmaxlen > 1) - { - if (memcmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")-1) == 0 ) // UCS2 - { - sprintf(stringBuildBuffer, "GRAPHIC(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters - db2Ccsid = 13488; - } - else if (memcmp(fieldCharSet->name, "utf8_", sizeof("utf8_")-1) == 0 && - strcmp(fieldCharSet->name, "utf8_general_ci") != 0) - { - sprintf(stringBuildBuffer, "CHAR(%d)", max(fieldLength, 1)); // Number of bytes - db2Ccsid = 1208; - } - else - { - sprintf(stringBuildBuffer, "GRAPHIC(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters - db2Ccsid = 1200; - } - } - else - { - sprintf(stringBuildBuffer, "CHAR(%d)", max(fieldLength, 1)); - } - mapping.append(stringBuildBuffer); - } - else - { - if (fieldLength <= MAX_VARCHAR_LENGTH) - { - if (fieldCharSet->mbmaxlen > 1) - { - if (memcmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")-1) == 0 ) // UCS2 - { - sprintf(stringBuildBuffer, "VARGRAPHIC(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters - db2Ccsid = 13488; - } - else if (memcmp(fieldCharSet->name, "utf8_", sizeof("utf8_")-1) == 0 && - strcmp(fieldCharSet->name, "utf8_general_ci") != 0) - { - sprintf(stringBuildBuffer, "VARCHAR(%d)", max(fieldLength, 1)); // Number of bytes - db2Ccsid = 1208; - } - else - { - sprintf(stringBuildBuffer, "VARGRAPHIC(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters - db2Ccsid = 1200; - } - } - else - { - sprintf(stringBuildBuffer, "VARCHAR(%d)", max(fieldLength, 1)); - } - } - else if (blobMapping == AS_VARCHAR && - (field->flags & PART_KEY_FLAG)) - { - if (fieldCharSet->mbmaxlen > 1) - { - if (memcmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")-1) == 0 ) // UCS2 - { - sprintf(stringBuildBuffer, "LONG VARGRAPHIC "); - db2Ccsid = 13488; - } - else if (memcmp(fieldCharSet->name, "utf8_", sizeof("utf8_")-1) == 0 && - strcmp(fieldCharSet->name, "utf8_general_ci") != 0) - { - sprintf(stringBuildBuffer, "LONG VARCHAR "); - db2Ccsid = 1208; - } - else - { - sprintf(stringBuildBuffer, "LONG VARGRAPHIC "); - db2Ccsid = 1200; - } - } - else - { - sprintf(stringBuildBuffer, "LONG VARCHAR "); - } - } - else - { - fieldLength = min(MAX_BLOB_LENGTH, fieldLength); - - if (fieldCharSet->mbmaxlen > 1) - { - if (memcmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")-1) == 0 ) // UCS2 - { - sprintf(stringBuildBuffer, "DBCLOB(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters - db2Ccsid = 13488; - } - else if (memcmp(fieldCharSet->name, "utf8_", sizeof("utf8_")-1) == 0 && - strcmp(fieldCharSet->name, "utf8_general_ci") != 0) - { - sprintf(stringBuildBuffer, "CLOB(%d)", max(fieldLength, 1)); // Number of bytes - db2Ccsid = 1208; - } - else - { - sprintf(stringBuildBuffer, "DBCLOB(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters - db2Ccsid = 1200; - } - } - else - { - sprintf(stringBuildBuffer, "CLOB(%d)", max(fieldLength, 1)); // Number of characters - } - } - - mapping.append(stringBuildBuffer); - } - if (db2Ccsid == 0) // If not overriding CCSID - { - int32 rtnCode = convertIANAToDb2Ccsid(fieldCharSet->csname, &db2Ccsid); - if (rtnCode) - return rtnCode; - } - - if (db2Ccsid != 1208 && - db2Ccsid != 13488) - { - // Check whether there is a character conversion available. - iconv_t temp; - int32 rc = getConversion(toDB2, fieldCharSet, db2Ccsid, temp); - if (unlikely(rc)) - return rc; - } - - sprintf(stringBuildBuffer, " CCSID %d ", db2Ccsid); - mapping.append(stringBuildBuffer); - } - } - } - break; - - } - - if (propagateDefaults) - get_field_default_value(field, - mapping, - defaultNeedsQuotes, - db2Ccsid, - (zeroDateHandling==SUBSTITUTE_0001_01_01)); - - return 0; -} - - -/** - Convert MySQL field data into the equivalent DB2 format - - @param field The MySQL field to be converted - @param db2Field The corresponding DB2 field definition - @param db2Buf The buffer to receive the converted data - @param data NULL if field points to the correct data; otherwise, - the data to be converted (for use with keys) -*/ -int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char* db2Buf, const uchar* data) -{ - enum_field_types fieldType = field->type(); - switch (fieldType) - { - case MYSQL_TYPE_NEWDECIMAL: - { - uint precision= ((Field_new_decimal*)field)->precision; - uint scale= field->decimals(); - uint db2Precision = min(precision, MAX_DEC_PRECISION); - uint truncationAmount = precision - db2Precision; - - if (scale >= truncationAmount) - { - String tempString(precision+2); - - if (data == NULL) - { - field->val_str((String*)&tempString, (String*)(NULL)); - } - else - { - field->val_str(&tempString, data); - } - const char* temp = tempString.ptr(); - char packed[32]; - memset(&packed, 0, sizeof(packed)); - - int bcdPos = db2Precision - (db2Precision % 2 ? 1 : 0); - bcdAssign(packed, bcdPos+1, (temp[0] == '-' ? 0xD : 0xF)); - - int strPos=tempString.length() - 1 - truncationAmount; - - for (;strPos >= 0 && bcdPos >= 0; strPos--) - { - if (my_isdigit(&my_charset_latin1, temp[strPos])) - { - bcdAssign(packed, bcdPos, temp[strPos]-'0'); - --bcdPos; - } - } - memcpy(db2Buf, &packed, (db2Precision/2)+1); - } - - } - break; - case MYSQL_TYPE_TINY: - { - int16 temp = (data == NULL ? field->val_int() : field->val_int(data)); - memcpy(db2Buf , &temp, sizeof(temp)); - } - break; - case MYSQL_TYPE_SHORT: - { - if (((Field_num*)field)->unsigned_flag) - { - memset(db2Buf, 0, 2); - memcpy(db2Buf+2, (data == NULL ? field->ptr : data), 2); - } - else - { - memcpy(db2Buf, (data == NULL ? field->ptr : data), 2); - } - } - break; - case MYSQL_TYPE_LONG: - { - if (((Field_num*)field)->unsigned_flag) - { - memset(db2Buf, 0, 4); - memcpy(db2Buf+4, (data == NULL ? field->ptr : data), 4); - } - else - { - memcpy(db2Buf, (data == NULL ? field->ptr : data), 4); - } - } - break; - case MYSQL_TYPE_FLOAT: - { - memcpy(db2Buf, (data == NULL ? field->ptr : data), 4); - } - break; - case MYSQL_TYPE_DOUBLE: - { - memcpy(db2Buf, (data == NULL ? field->ptr : data), 8); - } - break; - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_DATETIME: - { - String tempString(27); - if (data == NULL) - { - field->val_str(&tempString, &tempString); - } - else - { - field->val_str(&tempString, data); - } - memset(db2Buf, '0', 26); - memcpy(db2Buf, tempString.ptr(), tempString.length()); - if (strncmp(db2Buf,ZERO_DATETIME_VALUE,strlen(ZERO_DATETIME_VALUE)) == 0) - { - if (cachedZeroDateOption == SUBSTITUTE_0001_01_01) - memcpy(db2Buf, ZERO_DATETIME_VALUE_SUBST, sizeof(ZERO_DATETIME_VALUE_SUBST)); - else - { - getErrTxt(DB2I_ERR_INVALID_COL_VALUE, field->field_name); - return(DB2I_ERR_INVALID_COL_VALUE); - } - } - (db2Buf)[10] = '-'; - (db2Buf)[13] = (db2Buf)[16] = (db2Buf)[19] = '.'; - - convertNumericToEbcdicFast(db2Buf, 26); - } - break; - case MYSQL_TYPE_LONGLONG: - { - if (((Field_num*)field)->unsigned_flag) - { - char temp[23]; - String tempString(temp, sizeof(temp), &my_charset_latin1); - - if (data == NULL) - { - field->val_str((String*)&tempString, (String*)(NULL)); - } - else - { - field->val_str(&tempString, data); - } - char packed[11]; - memset(packed, 0, sizeof(packed)); - bcdAssign(packed, 21, (temp[0] == '-' ? 0xD : 0xF)); - int strPos=tempString.length()-1; - int bcdPos=20; - - for (;strPos >= 0; strPos--) - { - if (my_isdigit(&my_charset_latin1, temp[strPos])) - { - bcdAssign(packed, bcdPos, temp[strPos]-'0'); - --bcdPos; - } - } - memcpy(db2Buf, &packed, 11); - } - else - { - *(uint64*)db2Buf = *(uint64*)(data == NULL ? field->ptr : data); - } - } - break; - case MYSQL_TYPE_INT24: - { - int32 temp= (data == NULL ? field->val_int() : field->val_int(data)); - memcpy(db2Buf , &temp, sizeof(temp)); - } - break; - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_NEWDATE: - { - String tempString(11); - if (data == NULL) - { - field->val_str(&tempString, (String*)NULL); - } - else - { - field->val_str(&tempString, data); - } - memcpy(db2Buf, tempString.ptr(), 10); - if (strncmp(db2Buf,ZERO_DATE_VALUE,strlen(ZERO_DATE_VALUE)) == 0) - { - if (cachedZeroDateOption == SUBSTITUTE_0001_01_01) - memcpy(db2Buf, ZERO_DATE_VALUE_SUBST, sizeof(ZERO_DATE_VALUE_SUBST)); - else - { - getErrTxt(DB2I_ERR_INVALID_COL_VALUE,field->field_name); - return(DB2I_ERR_INVALID_COL_VALUE); - } - } - - convertNumericToEbcdicFast(db2Buf,10); - } - break; - case MYSQL_TYPE_TIME: - { - if (db2Field.getType() == QMY_TIME) - { - String tempString(10); - if (data == NULL) - { - field->val_str(&tempString, (String*)NULL); - } - else - { - field->val_str(&tempString, data); - } - memcpy(db2Buf, tempString.ptr(), 8); - (db2Buf)[2]=(db2Buf)[5] = '.'; - - convertNumericToEbcdicFast(db2Buf, 8); - } - else - { - int32 temp = sint3korr(data == NULL ? field->ptr : data); - memcpy(db2Buf, &temp, sizeof(temp)); - } - } - break; - case MYSQL_TYPE_YEAR: - { - String tempString(5); - if (db2Field.getType() == QMY_CHAR) - { - if (data == NULL) - { - field->val_str(&tempString, (String*)NULL); - } - else - { - field->val_str(&tempString, data); - } - memcpy(db2Buf, tempString.ptr(), 4); - } - else - { - uint8 temp = *(uint8*)(data == NULL ? field->ptr : data); - *(uint16*)(db2Buf) = (temp ? temp + 1900 : 0); - } - } - break; - case MYSQL_TYPE_BIT: - { - int bytesToCopy = db2Field.getByteLengthInRecord(); - - if (data == NULL) - { - uint64 temp = field->val_int(); - memcpy(db2Buf, - ((char*)&temp) + (sizeof(temp) - bytesToCopy), - bytesToCopy); - } - else - { - memcpy(db2Buf, - data, - bytesToCopy); - } - } - break; - case MYSQL_TYPE_VARCHAR: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_BLOB: - { - if (field->real_type() == MYSQL_TYPE_ENUM || - field->real_type() == MYSQL_TYPE_SET) - { - int64 temp= (data == NULL ? field->val_int() : field->val_int(data)); - *(int64*)db2Buf = temp; - } - else - { - const uchar* dataToStore; - uint32 bytesToStore; - uint32 bytesToPad = 0; - CHARSET_INFO* fieldCharSet = field->charset(); - uint32 maxDisplayLength = field->max_display_length(); - switch (fieldType) - { - case MYSQL_TYPE_STRING: - { - bytesToStore = maxDisplayLength; - if (data == NULL) - dataToStore = field->ptr; - else - dataToStore = data; - } - break; - case MYSQL_TYPE_VARCHAR: - { - - if (data == NULL) - { - bytesToStore = field->data_length(); - dataToStore = field->ptr + ((Field_varstring*)field)->length_bytes; - } - else - { - // Key lens are stored little-endian - bytesToStore = *(uint8*)data + ((*(uint8*)(data+1)) << 8); - dataToStore = data + 2; - } - bytesToPad = maxDisplayLength - bytesToStore; - } - break; - case MYSQL_TYPE_BLOB: - { - if (data == NULL) - { - bytesToStore = ((Field_blob*)field)->get_length(); - bytesToPad = maxDisplayLength - bytesToStore; - ((Field_blob*)field)->get_ptr((uchar**)&dataToStore); - } - else - { - // Key lens are stored little-endian - bytesToStore = *(uint8*)data + ((*(uint8*)(data+1)) << 8); - dataToStore = data + 2; - } - } - break; - } - - int32 rc; - uint16 db2FieldType = db2Field.getType(); - switch(db2FieldType) - { - case QMY_CHAR: - if (maxDisplayLength == 0) - bytesToPad = 1; - case QMY_VARCHAR: - if (db2FieldType == QMY_VARCHAR) - { - db2Buf += sizeof(uint16); - bytesToPad = 0; - } - - if (bytesToStore > db2Field.getDataLengthInRecord()) - { - bytesToStore = db2Field.getDataLengthInRecord(); - field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); - } - - if (fieldCharSet == &my_charset_bin) // If binary - { - if (bytesToStore) - memcpy(db2Buf, dataToStore, bytesToStore); - if (bytesToPad) - memset(db2Buf + bytesToStore, 0x00, bytesToPad); - } - else if (db2Field.getCCSID() == 1208) // utf8 - { - if (bytesToStore) - memcpy(db2Buf, dataToStore, bytesToStore); - if (bytesToPad) - memset(db2Buf + bytesToStore, ' ', bytesToPad); - } - else // single-byte ASCII to EBCDIC - { - DBUG_ASSERT(fieldCharSet->mbmaxlen == 1); - if (bytesToStore) - { - rc = convertFieldChars(toDB2, field->field_index, (char*)dataToStore, db2Buf, bytesToStore, bytesToStore, NULL); - if (rc) - return rc; - } - if (bytesToPad) - memset(db2Buf + bytesToStore, 0x40, bytesToPad); - } - - if (db2FieldType == QMY_VARCHAR) - *(uint16*)(db2Buf - sizeof(uint16)) = bytesToStore; - break; - case QMY_VARGRAPHIC: - db2Buf += sizeof(uint16); - bytesToPad = 0; - case QMY_GRAPHIC: - if (maxDisplayLength == 0 && db2FieldType == QMY_GRAPHIC) - bytesToPad = 2; - - if (db2Field.getCCSID() == 13488) - { - if (bytesToStore) - memcpy(db2Buf, dataToStore, bytesToStore); - if (bytesToPad) - memset16((db2Buf + bytesToStore), 0x0020, bytesToPad/2); - } - else - { - size_t db2BytesToStore; - size_t maxDb2BytesToStore; - - if (maxDisplayLength == 0 && db2FieldType == QMY_GRAPHIC) - maxDb2BytesToStore = 2; - else - maxDb2BytesToStore = min(((bytesToStore * 2) / fieldCharSet->mbminlen), - ((maxDisplayLength * 2) / fieldCharSet->mbmaxlen)); - - if (bytesToStore == 0) - db2BytesToStore = 0; - else - { - rc = convertFieldChars(toDB2, field->field_index, (char*)dataToStore, db2Buf, bytesToStore, maxDb2BytesToStore, &db2BytesToStore); - if (rc) - return rc; - bytesToStore = db2BytesToStore; - } - if (db2BytesToStore < maxDb2BytesToStore) // If need to pad - memset16((db2Buf + db2BytesToStore), 0x0020, (maxDb2BytesToStore - db2BytesToStore)/2); - } - - if (db2FieldType == QMY_VARGRAPHIC) - *(uint16*)(db2Buf-sizeof(uint16)) = bytesToStore/2; - break; - case QMY_BLOBCLOB: - case QMY_DBCLOB: - { - DBUG_ASSERT(data == NULL); - DB2LobField* lobField = (DB2LobField*)(db2Buf + db2Field.calcBlobPad()); - - if ((fieldCharSet == &my_charset_bin) || // binary or - (db2Field.getCCSID()==13488) || - (db2Field.getCCSID()==1208)) // binary UTF8 - { - } - else - { - char* temp; - int32 rc; - size_t db2BytesToStore; - if (fieldCharSet->mbmaxlen == 1) // single-byte ASCII to EBCDIC - { - temp = getCharacterConversionBuffer(field->field_index, bytesToStore); - rc = convertFieldChars(toDB2, field->field_index, (char*)dataToStore,temp,bytesToStore, bytesToStore, NULL); - if (rc) - return (rc); - } - else // Else Far East, special UTF8 or non-special UTF8/UCS2 - { - size_t maxDb2BytesToStore; - maxDb2BytesToStore = min(((bytesToStore * 2) / fieldCharSet->mbminlen), - ((maxDisplayLength * 2) / fieldCharSet->mbmaxlen)); - temp = getCharacterConversionBuffer(field->field_index, maxDb2BytesToStore); - rc = convertFieldChars(toDB2, field->field_index, (char*)dataToStore,temp,bytesToStore, maxDb2BytesToStore, &db2BytesToStore); - if (rc) - return (rc); - bytesToStore = db2BytesToStore; - } - dataToStore = (uchar*)temp; - } - - uint16 blobID = db2Table->getBlobIdFromField(field->field_index); - if (blobWriteBuffers[blobID] != (char*)dataToStore) - blobWriteBuffers[blobID].reassign((char*)dataToStore); - if ((void*)blobWriteBuffers[blobID]) - lobField->dataHandle = (ILEMemHandle)blobWriteBuffers[blobID]; - else - lobField->dataHandle = 0; - lobField->length = bytesToStore / (db2FieldType == QMY_DBCLOB ? 2 : 1); - } - break; - } - } - } - break; - default: - DBUG_ASSERT(0); - break; - } - - return (ha_thd()->is_error()); -} - - -/** - Convert DB2 field data into the equivalent MySQL format - - @param db2Field The DB2 field definition - @param field The MySQL field to receive the converted data - @param buf The DB2 data to be converted -*/ -int32 ha_ibmdb2i::convertDB2toMySQL(const DB2Field& db2Field, Field* field, const char* buf) -{ - int32 storeRC = 0; // Result of the field->store() operation - - const char* bufPtr = buf + db2Field.getBufferOffset(); - - switch (field->type()) - { - case MYSQL_TYPE_NEWDECIMAL: - { - uint precision= ((Field_new_decimal*)field)->precision; - uint scale= field->decimals(); - uint db2Precision = min(precision, MAX_DEC_PRECISION); - uint decimalPlace = precision-scale+1; - char temp[80]; - - if (precision <= MAX_DEC_PRECISION || - scale > precision - MAX_DEC_PRECISION) - { - uint numNibbles = db2Precision + (db2Precision % 2 ? 0 : 1); - - temp[0] = (bcdGet(bufPtr, numNibbles) == 0xD ? '-' : ' '); - int strPos=1; - int bcdPos=(db2Precision % 2 ? 0 : 1); - - for (;bcdPos < numNibbles; bcdPos++, strPos++) - { - if (strPos == decimalPlace) - { - temp[strPos] = '.'; - strPos++; - } - - temp[strPos] = bcdGet(bufPtr, bcdPos) + '0'; - } - - temp[strPos] = 0; - - storeRC = field->store(temp, strPos, &my_charset_latin1); - } - } - break; - case MYSQL_TYPE_TINY: - { - storeRC = field->store(*(int16*)bufPtr, ((Field_num*)field)->unsigned_flag); - } - break; - case MYSQL_TYPE_SHORT: - { - if (((Field_num*)field)->unsigned_flag) - { - storeRC = field->store(*(int32*)bufPtr, TRUE); - } - else - { - storeRC = field->store(*(int16*)bufPtr, FALSE); - } - } - break; - case MYSQL_TYPE_LONG: - { - if (((Field_num*)field)->unsigned_flag) - { - storeRC = field->store(*(int64*)bufPtr, TRUE); - } - else - { - storeRC = field->store(*(int32*)bufPtr, FALSE); - } - } - break; - case MYSQL_TYPE_FLOAT: - { - storeRC = field->store(*(float*)bufPtr); - } - break; - case MYSQL_TYPE_DOUBLE: - { - storeRC = field->store(*(double*)bufPtr); - } - break; - case MYSQL_TYPE_LONGLONG: - { - char temp[23]; - if (((Field_num*)field)->unsigned_flag) - { - temp[0] = (bcdGet(bufPtr, 21) == 0xD ? '-' : ' '); - int strPos=1; - int bcdPos=0; - - for (;bcdPos <= 20; bcdPos++, strPos++) - { - temp[strPos] = bcdGet(bufPtr, bcdPos) + '0'; - } - - temp[strPos] = 0; - - storeRC = field->store(temp, strPos, &my_charset_latin1); - } - else - { - storeRC = field->store(*(int64*)bufPtr, FALSE); - } - } - break; - case MYSQL_TYPE_INT24: - { - storeRC = field->store(*(int32*)bufPtr, ((Field_num*)field)->unsigned_flag); - } - break; - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_NEWDATE: - { - longlong value= a4toi_ebcdic((uchar*)bufPtr) * 10000 + - a2toi_ebcdic((uchar*)bufPtr+5) * 100 + - a2toi_ebcdic((uchar*)bufPtr+8); - - if (cachedZeroDateOption == SUBSTITUTE_0001_01_01 && - value == (10000 + 100 + 1)) - value = 0; - - storeRC = field->store(value); - } - break; - case MYSQL_TYPE_TIME: - { - if (db2Field.getType() == QMY_TIME) - { - longlong value= a2toi_ebcdic((uchar*)bufPtr) * 10000 + - a2toi_ebcdic((uchar*)bufPtr+3) * 100 + - a2toi_ebcdic((uchar*)bufPtr+6); - - storeRC = field->store(value); - } - else - storeRC = field->store(*((int32*)bufPtr)); - } - break; - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_DATETIME: - { - longlong value= (a4toi_ebcdic((uchar*)bufPtr) * 10000 + - a2toi_ebcdic((uchar*)bufPtr+5) * 100 + - a2toi_ebcdic((uchar*)bufPtr+8)) * 1000000LL + - (a2toi_ebcdic((uchar*)bufPtr+11) * 10000 + - a2toi_ebcdic((uchar*)bufPtr+14) * 100 + - a2toi_ebcdic((uchar*)bufPtr+17)); - - if (cachedZeroDateOption == SUBSTITUTE_0001_01_01 && - value == (10000 + 100 + 1) * 1000000LL) - value = 0; - - storeRC = field->store(value); - } - break; - case MYSQL_TYPE_YEAR: - { - if (db2Field.getType() == QMY_CHAR) - { - storeRC = field->store(bufPtr, 4, &my_charset_bin); - } - else - { - storeRC = field->store(*((uint16*)bufPtr)); - } - } - break; - case MYSQL_TYPE_BIT: - { - uint64 temp= 0; - int bytesToCopy= db2Field.getByteLengthInRecord(); - memcpy(((char*)&temp) + (sizeof(temp) - bytesToCopy), bufPtr, bytesToCopy); - storeRC = field->store(temp, TRUE); - } - break; - case MYSQL_TYPE_VARCHAR: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_BLOB: - { - if (field->real_type() == MYSQL_TYPE_ENUM || - field->real_type() == MYSQL_TYPE_SET) - { - storeRC = field->store(*(int64*)bufPtr); - } - else - { - - const char* dataToStore = NULL; - uint32 bytesToStore = 0; - CHARSET_INFO* fieldCharSet = field->charset(); - switch(db2Field.getType()) - { - case QMY_CHAR: - case QMY_GRAPHIC: - { - bytesToStore = db2Field.getByteLengthInRecord(); - if (bytesToStore == 0) - bytesToStore = 1; - dataToStore = bufPtr; - } - break; - case QMY_VARCHAR: - { - bytesToStore = *(uint16*)bufPtr; - dataToStore = bufPtr+sizeof(uint16); - } - break; - case QMY_VARGRAPHIC: - { - /* For VARGRAPHIC, convert the number of double-byte characters - to the number of bytes. */ - bytesToStore = (*(uint16*)bufPtr)*2; - dataToStore = bufPtr+sizeof(uint16); - } - break; - case QMY_DBCLOB: - case QMY_BLOBCLOB: - { - DB2LobField* lobField = (DB2LobField* )(bufPtr + db2Field.calcBlobPad()); - bytesToStore = lobField->length * (db2Field.getType() == QMY_DBCLOB ? 2 : 1); - dataToStore = (char*)blobReadBuffers->getBufferPtr(field->field_index); - } - break; - - } - - if ((fieldCharSet != &my_charset_bin) && // not binary & - (db2Field.getCCSID() != 13488) && // not UCS2 & - (db2Field.getCCSID() != 1208)) - { - char* temp; - size_t db2BytesToStore; - int rc; - if (fieldCharSet->mbmaxlen > 1) - { - size_t maxDb2BytesToStore = ((bytesToStore / 2) * fieldCharSet->mbmaxlen); // Worst case for number of bytes - temp = getCharacterConversionBuffer(field->field_index, maxDb2BytesToStore); - rc = convertFieldChars(toMySQL, field->field_index, dataToStore, temp, bytesToStore, maxDb2BytesToStore, &db2BytesToStore); - bytesToStore = db2BytesToStore; - } - else // single-byte ASCII to EBCDIC - { - temp = getCharacterConversionBuffer(field->field_index, bytesToStore); - rc = convertFieldChars(toMySQL, field->field_index, dataToStore, temp, bytesToStore, bytesToStore, NULL); - } - if (rc) - return (rc); - dataToStore = temp; - } - - if ((field)->flags & BLOB_FLAG) - ((Field_blob*)(field))->set_ptr(bytesToStore, (uchar*)dataToStore); - else - storeRC = field->store(dataToStore, bytesToStore, &my_charset_bin); - } - } - break; - default: - DBUG_ASSERT(0); - break; - - } - - if (storeRC) - { - invalidDataFound = true; - } - - return 0; -} diff --git a/storage/ibmdb2i/db2i_errors.cc b/storage/ibmdb2i/db2i_errors.cc deleted file mode 100644 index dd50e40e61b..00000000000 --- a/storage/ibmdb2i/db2i_errors.cc +++ /dev/null @@ -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); -} - - diff --git a/storage/ibmdb2i/db2i_errors.h b/storage/ibmdb2i/db2i_errors.h deleted file mode 100644 index b6dd314ef50..00000000000 --- a/storage/ibmdb2i/db2i_errors.h +++ /dev/null @@ -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 diff --git a/storage/ibmdb2i/db2i_file.cc b/storage/ibmdb2i/db2i_file.cc deleted file mode 100644 index a16aa927527..00000000000 --- a/storage/ibmdb2i/db2i_file.cc +++ /dev/null @@ -1,556 +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 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 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 fileDefnSpace(sizeof(ShrDef)); - - physicalFile = new db2i_file(this); - physicalFile->fillILEDefn(fileDefnSpace, true); - - ValidatedPointer 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() -{ - if (blobFieldActualSizes) - my_free(blobFieldActualSizes, MYF(0)); - - if (conversionDefinitions[toMySQL]) - my_free(conversionDefinitions[toMySQL], MYF(0)); - - if (logicalFiles) - { - for (int k = 0; k < logicalFileCount; ++k) - { - delete logicalFiles[k]; - } - - delete[] logicalFiles; - } - delete physicalFile; - - my_free(db2LibNameEbcdic, 0); -} - -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, MYF(0)); - return min(outlen, strlen(out)); - } - ++cur; - } - - strncpy(out, test, outlen); - my_free(test, MYF(0)); - 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); -} - diff --git a/storage/ibmdb2i/db2i_file.h b/storage/ibmdb2i/db2i_file.h deleted file mode 100644 index 7b63b18c315..00000000000 --- a/storage/ibmdb2i/db2i_file.h +++ /dev/null @@ -1,445 +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 "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 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, MYF(0)); - } - - // 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 diff --git a/storage/ibmdb2i/db2i_global.h b/storage/ibmdb2i/db2i_global.h deleted file mode 100644 index d201fbd8124..00000000000 --- a/storage/ibmdb2i/db2i_global.h +++ /dev/null @@ -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*)), MYF(0)); - } -} - -#endif diff --git a/storage/ibmdb2i/db2i_iconv.h b/storage/ibmdb2i/db2i_iconv.h deleted file mode 100644 index 9fc6e4ed636..00000000000 --- a/storage/ibmdb2i/db2i_iconv.h +++ /dev/null @@ -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 diff --git a/storage/ibmdb2i/db2i_ileBridge.cc b/storage/ibmdb2i/db2i_ileBridge.cc deleted file mode 100644 index 68ae2c2bb72..00000000000 --- a/storage/ibmdb2i/db2i_ileBridge.cc +++ /dev/null @@ -1,1342 +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_ileBridge.h" -#include "my_dbug.h" -#include "db2i_global.h" -#include "db2i_charsetSupport.h" -#include "db2i_errors.h" - - -// static class member data -ILEpointer* db2i_ileBridge::functionSymbols; -db2i_ileBridge* db2i_ileBridge::globalBridge; -#ifndef DBUG_OFF -uint32 db2i_ileBridge::registeredPtrs; -#endif - -pthread_key(IleParms*, THR_ILEPARMS); - -static void ileParmsDtor(void* parmsToFree) -{ - if (parmsToFree) - { - free_aligned(parmsToFree); - DBUG_PRINT("db2i_ileBridge", ("Freeing space for parms")); - } -} - - -/** - Convert a timestamp in ILE time format into a unix time_t -*/ -static inline time_t convertILEtime(const ILE_time_t& input) -{ - tm temp; - - temp.tm_sec = input.Second; - temp.tm_min = input.Minute; - temp.tm_hour = input.Hour; - temp.tm_mday = input.Day; - temp.tm_mon = input.Month-1; - temp.tm_year = input.Year - 1900; - temp.tm_isdst = -1; - - return mktime(&temp); -} - -/** - Allocate and intialize a new bridge structure -*/ -db2i_ileBridge* db2i_ileBridge::createNewBridge(CONNECTION_HANDLE connID) -{ - DBUG_PRINT("db2i_ileBridge::createNewBridge",("Building new bridge...")); - db2i_ileBridge* newBridge = (db2i_ileBridge*)my_malloc(sizeof(db2i_ileBridge), MYF(MY_WME)); - - if (unlikely(newBridge == NULL)) - return NULL; - - newBridge->stmtTxActive = false; - newBridge->connErrText = NULL; - newBridge->pendingLockedHandles.head = NULL; - newBridge->cachedConnectionID = connID; - - return newBridge; -} - - -void db2i_ileBridge::destroyBridge(db2i_ileBridge* bridge) -{ - bridge->freeErrorStorage(); - my_free(bridge, MYF(0)); -} - - -void db2i_ileBridge::destroyBridgeForThread(const THD* thd) -{ - void* thdData = *thd_ha_data(thd, ibmdb2i_hton); - if (thdData != NULL) - { - destroyBridge((db2i_ileBridge*)thdData); - } -} - - -void db2i_ileBridge::registerPtr(const void* ptr, ILEMemHandle* receiver) -{ - static const arg_type_t ileSignature[] = { ARG_MEMPTR, ARG_END }; - - if (unlikely(ptr == NULL)) - { - *receiver = 0; - return; - } - - struct ArgList - { - ILEarglist_base base; - ILEpointer ptr; - } *arguments; - - char argBuf[sizeof(ArgList)+15]; - arguments = (ArgList*)roundToQuadWordBdy(argBuf); - - arguments->ptr.s.addr = (address64_t)(ptr); - - _ILECALL(&functionSymbols[funcRegisterSpace], - &arguments->base, - ileSignature, - RESULT_INT64); - -#ifndef DBUG_OFF - uint32 truncHandle = arguments->base.result.r_uint64; - DBUG_PRINT("db2i_ileBridge::registerPtr",("Register 0x%p with handle %d", ptr, truncHandle)); - getBridgeForThread()->registeredPtrs++; -#endif - - *receiver = arguments->base.result.r_uint64; - return; -} - -void db2i_ileBridge::unregisterPtr(ILEMemHandle handle) -{ - static const arg_type_t ileSignature[] = { ARG_UINT64, ARG_END }; - - if (unlikely(handle == NULL)) - return; - - struct ArgList - { - ILEarglist_base base; - uint64 handle; - } *arguments; - - char argBuf[sizeof(ArgList)+15]; - arguments = (ArgList*)roundToQuadWordBdy(argBuf); - - arguments->handle = (uint64)(handle); - - _ILECALL(&functionSymbols[funcUnregisterSpace], - &arguments->base, - ileSignature, - RESULT_VOID); - -#ifndef DBUG_OFF - DBUG_PRINT("db2i_ileBridge::unregisterPtr",("Unregister handle %d", (uint32)handle)); - getBridgeForThread()->registeredPtrs--; -#endif -} - - - -/** - Initialize the bridge component - - @details Resolves srvpgm and function names of the APIs. If this fails, - the approrpiate operating system support (PTFs) is probably not installed. - - WARNING: - Must be called before any other functions in this class are used!!!! - Can only be called by a single thread! -*/ -int db2i_ileBridge::setup() -{ - static const char funcNames[db2i_ileBridge::funcListEnd][32] = - { - {"QmyRegisterParameterSpaces"}, - {"QmyRegisterSpace"}, - {"QmyUnregisterSpace"}, - {"QmyProcessRequest"} - }; - - DBUG_ENTER("db2i_ileBridge::setup"); - - int actmark = _ILELOAD("QSYS/QMYSE", ILELOAD_LIBOBJ); - if ( actmark == -1 ) - { - DBUG_PRINT("db2i_ileBridge::setup", ("srvpgm activation failed")); - DBUG_RETURN(1); - } - - functionSymbols = (ILEpointer*)malloc_aligned(sizeof(ILEpointer) * db2i_ileBridge::funcListEnd); - - for (int i = 0; i < db2i_ileBridge::funcListEnd; i++) - { - if (_ILESYM(&functionSymbols[i], actmark, funcNames[i]) == -1) - { - DBUG_PRINT("db2i_ileBridge::setup", - ("resolve of %s failed", funcNames[i])); - DBUG_RETURN(errno); - } - } - - pthread_key_create(&THR_ILEPARMS, &ileParmsDtor); - -#ifndef DBUG_OFF - registeredPtrs = 0; -#endif - - globalBridge = createNewBridge(0); - - DBUG_RETURN(0); -} - -/** - Cleanup any resources before shutting down plug-in -*/ -void db2i_ileBridge::takedown() -{ - if (globalBridge) - destroyBridge(globalBridge); - free_aligned(functionSymbols); -} - -/** - Call off to QmyProcessRequest to perform the API that the caller prepared -*/ -inline int32 db2i_ileBridge::doIt() -{ - static const arg_type_t ileSignature[] = {ARG_END}; - - struct ArgList - { - ILEarglist_base base; - } *arguments; - - char argBuf[sizeof(ArgList)+15]; - arguments = (ArgList*)roundToQuadWordBdy(argBuf); - - _ILECALL(&functionSymbols[funcProcessRequest], - &arguments->base, - ileSignature, - RESULT_INT32); - - return translateErrorCode(arguments->base.result.s_int32.r_int32); -} - -/** - Call off to QmyProcessRequest to perform the API that the caller prepared and - log any errors that may occur. -*/ -inline int32 db2i_ileBridge::doItWithLog() -{ - int32 rc = doIt(); - - if (unlikely(rc)) - { - // Only report errors that we weren't expecting - if (rc != tacitErrors[0] && - rc != tacitErrors[1] && - rc != QMY_ERR_END_OF_BLOCK) - reportSystemAPIError(rc, (Qmy_Error_output_t*)parms()->outParms); - } - memset(tacitErrors, 0, sizeof(tacitErrors)); - - return rc; -} - - -/** - Interface to QMY_ALLOCATE_SHARE API - - See QMY_ALLOCATE_SHARE documentation for more information about - parameters and return codes. -*/ -int32 db2i_ileBridge::allocateFileDefn(ILEMemHandle definitionSpace, - ILEMemHandle handleSpace, - uint16 fileCount, - const char* schemaName, - uint16 schemaNameLength, - ILEMemHandle formatSpace, - uint32 formatSpaceLen) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - - IleParms* parmBlock = parms(); - Qmy_MAOS0100 *input = (Qmy_MAOS0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_ALLOCATE_SHARE; - input->ShrDefSpcHnd = definitionSpace; - input->ShrHndSpcHnd = handleSpace; - input->ShrDefCnt = fileCount; - input->FmtSpcHnd = formatSpace; - input->FmtSpcLen = formatSpaceLen; - - if (schemaNameLength > sizeof(input->SchNam)) - { - // This should never happen! - DBUG_ASSERT(0); - return HA_ERR_GENERIC; - } - - memcpy(input->SchNam, schemaName, schemaNameLength); - input->SchNamLen = schemaNameLength; - - input->CnnHnd = cachedConnectionID; - - int32 rc = doItWithLog(); - - return rc; -} - - -/** - Interface to QMY_ALLOCATE_INSTANCE API - - See QMY_ALLOCATE_INSTANCE documentation for more information about - parameters and return codes. -*/ -int32 db2i_ileBridge::allocateFileInstance(FILE_HANDLE defnHandle, - ILEMemHandle inuseSpace, - FILE_HANDLE* instance) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - - IleParms* parmBlock = parms(); - Qmy_MAOI0100 *input = (Qmy_MAOI0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_ALLOCATE_INSTANCE; - input->ShrHnd = defnHandle; - input->CnnHnd = cachedConnectionID; - input->UseSpcHnd = inuseSpace; - - int32 rc = doItWithLog(); - - if (likely(rc == 0)) - { - Qmy_MAOI0100_output* output = (Qmy_MAOI0100_output*)parmBlock->outParms; - DBUG_ASSERT(instance); - *instance = output->ObjHnd; - } - - return rc; -} - - -/** - Interface to QMY_DEALLOCATE_OBJECT API - - See QMY_DEALLOCATE_OBJECT documentation for more information about - parameters and return codes. -*/ -int32 db2i_ileBridge::deallocateFile(FILE_HANDLE rfileHandle, - bool postDropTable) -{ - IleParms* parmBlock = parms(); - Qmy_MDLC0100 *input = (Qmy_MDLC0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_DEALLOCATE_OBJECT; - input->ObjHnd = rfileHandle; - input->ObjDrp[0] = (postDropTable ? QMY_YES : QMY_NO); - - DBUG_PRINT("db2i_ileBridge::deallocateFile", ("Deallocating %d", (uint32)rfileHandle)); - - int32 rc = doItWithLog(); - - return rc; -} - - -/** - Interface to QMY_OBJECT_INITIALIZATION API - - See QMY_OBJECT_INITIALIZATION documentation for more information about - parameters and return codes. -*/ -int32 db2i_ileBridge::initFileForIO(FILE_HANDLE rfileHandle, - char accessIntent, - char commitLevel, - uint16* inRecSize, - uint16* inRecNullOffset, - uint16* outRecSize, - uint16* outRecNullOffset) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - IleParms* parmBlock = parms(); - Qmy_MOIX0100 *input = (Qmy_MOIX0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_OBJECT_INITIALIZATION; - input->CmtLvl[0] = commitLevel; - input->Intent[0] = accessIntent; - input->ObjHnd = rfileHandle; - input->CnnHnd = cachedConnectionID; - - int32 rc = doItWithLog(); - - if (likely(rc == 0)) - { - Qmy_MOIX0100_output* output = (Qmy_MOIX0100_output*)parmBlock->outParms; - *inRecSize = output->InNxtRowOff; - *inRecNullOffset = output->InNullMapOff; - *outRecSize = output->OutNxtRowOff; - *outRecNullOffset = output->OutNullMapOff; - } - - return rc; -} - - -/** - Interface to QMY_READ_ROWS API for reading a row with a specific RRN. - - See QMY_READ_ROWS documentation for more information about - parameters and return codes. -*/ -int32 db2i_ileBridge::readByRRN(FILE_HANDLE rfileHandle, - ILEMemHandle buf, - uint32 inRRN, - char accessIntent, - char commitLevel) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - IleParms* parmBlock = parms(); - Qmy_MRDX0100 *input = (Qmy_MRDX0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_READ_ROWS; - input->CmtLvl[0] = commitLevel; - input->ObjHnd = rfileHandle; - input->Intent[0] = accessIntent; - input->OutSpcHnd = (uint64)buf; - input->RelRowNbr = inRRN; - input->CnnHnd = cachedConnectionID; - - int32 rc = doItWithLog(); - - if (rc == QMY_ERR_END_OF_BLOCK) - { - rc = 0; - DBUG_PRINT("db2i_ileBridge::readByRRN", ("End of block signalled")); - } - - return rc; -} - - -/** - Interface to QMY_WRITE_ROWS API. - - See QMY_WRITE_ROWS documentation for more information about - parameters and return codes. -*/ -int32 db2i_ileBridge::writeRows(FILE_HANDLE rfileHandle, - ILEMemHandle buf, - char commitLevel, - int64* outIdVal, - bool* outIdGen, - uint32* dupKeyRRN, - char** dupKeyName, - uint32* dupKeyNameLen, - uint32* outIdIncrement) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - IleParms* parmBlock = parms(); - Qmy_MWRT0100 *input = (Qmy_MWRT0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_WRITE_ROWS; - input->CmtLvl[0] = commitLevel; - - input->ObjHnd = rfileHandle; - input->InSpcHnd = (uint64_t) buf; - input->CnnHnd = cachedConnectionID; - - int32 rc = doItWithLog(); - - Qmy_MWRT0100_output_t* output = (Qmy_MWRT0100_output_t*)parmBlock->outParms; - if (likely(rc == 0 || rc == HA_ERR_FOUND_DUPP_KEY)) - { - DBUG_ASSERT(dupKeyRRN && dupKeyName && dupKeyNameLen && outIdGen && outIdIncrement && outIdVal); - *dupKeyRRN = output->DupRRN; - *dupKeyName = (char*)parmBlock->outParms + output->DupObjNamOff; - *dupKeyNameLen = output->DupObjNamLen; - *outIdGen = (output->NewIdGen[0] == QMY_YES ? TRUE : FALSE); - if (*outIdGen == TRUE) - { - *outIdIncrement = output->IdIncrement; - *outIdVal = output->NewIdVal; - } - } - - return rc; - -} - -/** - Interface to QMY_EXECUTE_IMMEDIATE API. - - See QMY_EXECUTE_IMMEDIATE documentation for more information about - parameters and return codes. -*/ -uint32 db2i_ileBridge::execSQL(const char* statement, - uint32 statementCount, - uint8 commitLevel, - bool autoCreateSchema, - bool dropSchema, - bool noCommit, - FILE_HANDLE fileHandle) - -{ - IleParms* parmBlock = parms(); - Qmy_MSEI0100 *input = (Qmy_MSEI0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_EXECUTE_IMMEDIATE; - - registerPtr(statement, &input->StmtsSpcHnd); - - input->NbrStmts = statementCount; - *(uint16*)(&input->StmtCCSID) = 850; - input->AutoCrtSchema[0] = (autoCreateSchema == TRUE ? QMY_YES : QMY_NO); - input->DropSchema[0] = (dropSchema == TRUE ? QMY_YES : QMY_NO); - input->CmtLvl[0] = commitLevel; - if ((commitLevel == QMY_NONE && statementCount == 1) || noCommit) - { - input->CmtBefore[0] = QMY_NO; - input->CmtAfter[0] = QMY_NO; - } - else - { - input->CmtBefore[0] = QMY_YES; - input->CmtAfter[0] = QMY_YES; - } - input->CnnHnd = current_thd->thread_id; - input->ObjHnd = fileHandle; - - int32 rc = doItWithLog(); - - unregisterPtr(input->StmtsSpcHnd); - - return rc; -} - -/** - Interface to QMY_PREPARE_OPEN_CURSOR API. - - See QMY_PREPARE_OPEN_CURSOR documentation for more information about - parameters and return codes. -*/ -int32 db2i_ileBridge::prepOpen(const char* statement, - FILE_HANDLE* rfileHandle, - uint32* recLength) -{ - IleParms* parmBlock = parms(); - Qmy_MSPO0100 *input = (Qmy_MSPO0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_PREPARE_OPEN_CURSOR; - - registerPtr(statement, &input->StmtsSpcHnd ); - *(uint16*)(&input->StmtCCSID) = 850; - input->CnnHnd = current_thd->thread_id; - - int32 rc = doItWithLog(); - - if (likely(rc == 0)) - { - Qmy_MSPO0100_output* output = (Qmy_MSPO0100_output*)parmBlock->outParms; - *rfileHandle = output->ObjHnd; - *recLength = max(output->InNxtRowOff, output->OutNxtRowOff); - } - - - unregisterPtr(input->StmtsSpcHnd); - - return rc; -} - - -/** - Interface to QMY_DELETE_ROW API. - - See QMY_DELETE_ROW documentation for more information about - parameters and return codes. -*/ -int32 db2i_ileBridge::deleteRow(FILE_HANDLE rfileHandle, - uint32 rrn) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - IleParms* parmBlock = parms(); - Qmy_MDLT0100 *input = (Qmy_MDLT0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_DELETE_ROW; - input->ObjHnd = rfileHandle; - input->RelRowNbr = rrn; - input->CnnHnd = cachedConnectionID; - - int32 rc = doItWithLog(); - - return rc; -} - - -/** - Interface to QMY_UPDATE_ROW API. - - See QMY_UPDATE_ROW documentation for more information about - parameters and return codes. -*/ -int32 db2i_ileBridge::updateRow(FILE_HANDLE rfileHandle, - uint32 rrn, - ILEMemHandle buf, - uint32* dupKeyRRN, - char** dupKeyName, - uint32* dupKeyNameLen) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - IleParms* parmBlock = parms(); - Qmy_MUPD0100 *input = (Qmy_MUPD0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_UPDATE_ROW; - input->ObjHnd = rfileHandle; - input->InSpcHnd = (uint64)buf; - input->RelRowNbr = rrn; - input->CnnHnd = cachedConnectionID; - - int32 rc = doItWithLog(); - - if (rc == HA_ERR_FOUND_DUPP_KEY) - { - Qmy_MUPD0100_output* output = (Qmy_MUPD0100_output*)parmBlock->outParms; - DBUG_ASSERT(dupKeyRRN && dupKeyName && dupKeyNameLen); - *dupKeyRRN = output->DupRRN; - *dupKeyName = (char*)parmBlock->outParms + output->DupObjNamOff; - *dupKeyNameLen = output->DupObjNamLen; - } - - return rc; -} - -/** - Interface to QMY_DESCRIBE_RANGE API. - - See QMY_DESCRIBE_RANGE documentation for more information about - parameters and return codes. -*/ -int32 db2i_ileBridge::recordsInRange(FILE_HANDLE defnHandle, - ILEMemHandle inSpc, - uint32 inKeyCnt, - uint32 inLiteralCnt, - uint32 inBoundsOff, - uint32 inLitDefOff, - uint32 inLiteralsOff, - uint32 inCutoff, - uint32 inSpcLen, - uint16 inEndByte, - uint64* outRecCnt, - uint16* outRtnCode) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - - IleParms* parmBlock = parms(); - Qmy_MDRG0100 *input = (Qmy_MDRG0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_DESCRIBE_RANGE; - input->ShrHnd = defnHandle; - input->SpcHnd = (uint64)inSpc; - input->KeyCnt = inKeyCnt; - input->LiteralCnt = inLiteralCnt; - input->BoundsOff = inBoundsOff; - input->LitDefOff = inLitDefOff; - input->LiteralsOff = inLiteralsOff; - input->Cutoff = inCutoff; - input->SpcLen = inSpcLen; - input->EndByte = inEndByte; - input->CnnHnd = cachedConnectionID; - - int rc = doItWithLog(); - - if (likely(rc == 0)) - { - Qmy_MDRG0100_output* output = (Qmy_MDRG0100_output*)parmBlock->outParms; - DBUG_ASSERT(outRecCnt && outRtnCode); - *outRecCnt = output->RecCnt; - *outRtnCode = output->RtnCode; - } - - return rc; -} - - -/** - Interface to QMY_RELEASE_ROW API. - - See QMY_RELEASE_ROW documentation for more information about - parameters and return codes. -*/ -int32 db2i_ileBridge::rrlslck(FILE_HANDLE rfileHandle, char accessIntent) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - - IleParms* parmBlock = parms(); - Qmy_MRRX0100 *input = (Qmy_MRRX0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_RELEASE_ROW; - - input->ObjHnd = rfileHandle; - input->CnnHnd = cachedConnectionID; - input->Intent[0] = accessIntent; - - int32 rc = doItWithLog(); - - return rc; -} - -/** - Interface to QMY_LOCK_OBJECT API. - - See QMY_LOCK_OBJECT documentation for more information about - parameters and return codes. -*/ -int32 db2i_ileBridge::lockObj(FILE_HANDLE defnHandle, - uint64 lockVal, - char lockAction, - char lockType, - char lockTimeout) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - IleParms* parmBlock = parms(); - Qmy_MOLX0100 *input = (Qmy_MOLX0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_LOCK_OBJECT; - input->ShrHnd = defnHandle; - input->LckTimeoutVal = lockVal; - input->Action[0] = lockAction; - input->LckTyp[0] = lockType; - input->LckTimeout[0] = lockTimeout; - input->CnnHnd = cachedConnectionID; - - int32 rc = doItWithLog(); - - return rc; -} - -/** - Interface to QMY_DESCRIBE_CONSTRAINTS API. - - See QMY_DESCRIBE_CONSTRAINTS documentation for more information about - parameters and return codes. -*/ -int32 db2i_ileBridge::constraints(FILE_HANDLE defnHandle, - ILEMemHandle inSpc, - uint32 inSpcLen, - uint32* outLen, - uint32* outCnt) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - IleParms* parmBlock = parms(); - Qmy_MDCT0100 *input = (Qmy_MDCT0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_DESCRIBE_CONSTRAINTS; - input->ShrHnd = defnHandle; - input->CstSpcHnd = (uint64)inSpc; - input->CstSpcLen = inSpcLen; - input->CnnHnd = cachedConnectionID; - - int32 rc = doItWithLog(); - - if (likely(rc == 0)) - { - Qmy_MDCT0100_output* output = (Qmy_MDCT0100_output*)parmBlock->outParms; - DBUG_ASSERT(outLen && outCnt); - *outLen = output->NeededLen; - *outCnt = output->CstCnt; - } - - return rc; -} - - -/** - Interface to QMY_REORGANIZE_TABLE API. - - See QMY_REORGANIZE_TABLE documentation for more information about - parameters and return codes. -*/ -int32 db2i_ileBridge::optimizeTable(FILE_HANDLE defnHandle) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - IleParms* parmBlock = parms(); - Qmy_MRGX0100 *input = (Qmy_MRGX0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_REORGANIZE_TABLE; - input->ShrHnd = defnHandle; - input->CnnHnd = cachedConnectionID; - - int32 rc = doItWithLog(); - - return rc; -} - - -/** - Interface to QMY_PROCESS_COMMITMENT_CONTROL API. - - See QMY_PROCESS_COMMITMENT_CONTROL documentation for more information about - parameters and return codes. -*/ -int32 db2i_ileBridge::commitmentControl(uint8 function) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - IleParms* parmBlock = parms(); - Qmy_MCCX0100 *input = (Qmy_MCCX0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_PROCESS_COMMITMENT_CONTROL; - input->Function[0] = function; - input->CnnHnd = cachedConnectionID; - - int32 rc = doItWithLog(); - - return rc; -} - - -/** - Interface to QMY_PROCESS_SAVEPOINT API. - - See QMY_PROCESS_SAVEPOINT documentation for more information about parameters and - return codes. -*/ -int32 db2i_ileBridge::savepoint(uint8 function, - const char* savepointName) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - DBUG_PRINT("db2i_ileBridge::savepoint",("%d %s", (uint32)function, savepointName)); - - IleParms* parmBlock = parms(); - Qmy_MSPX0100 *input = (Qmy_MSPX0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - char* savPtNam = (char*)(input+1); - - input->Format = QMY_PROCESS_SAVEPOINT; - - if (strlen(savepointName) > MAX_DB2_SAVEPOINTNAME_LENGTH) - { - DBUG_ASSERT(0); - return HA_ERR_GENERIC; - } - strcpy(savPtNam, savepointName); - - input->Function[0] = function; - input->SavPtNamOff = savPtNam - (char*)(input); - input->SavPtNamLen = strlen(savepointName); - input->CnnHnd = cachedConnectionID; - - int32 rc = doItWithLog(); - - return rc; -} - -static ILEMemHandle traceSpcHandle; -/** - Do initialization for the QMY_* APIs. - - @parm aspName The name of the relational database to use for all - connections. - - @return 0 if successful; error otherwise -*/ -int32 db2i_ileBridge::initILE(const char* aspName, - uint16* traceCtlPtr) -{ - // We forego the typical thread-based parms space because MySQL doesn't - // allow us to clean it up before checking for memory leaks. As a result - // we get a complaint about leaked memory on server shutdown. - int32 rc; - char inParms[db2i_ileBridge_MAX_INPARM_SIZE]; - char outParms[db2i_ileBridge_MAX_OUTPARM_SIZE]; - if (rc = registerParmSpace(inParms, outParms)) - { - reportSystemAPIError(rc, NULL); - return rc; - } - - registerPtr(traceCtlPtr, &traceSpcHandle); - - struct ParmBlock - { - Qmy_MINI0100 parms; - } *parmBlock = (ParmBlock*)inParms; - - memset(inParms, 0, sizeof(ParmBlock)); - - parmBlock->parms.Format = QMY_INITIALIZATION; - - char paddedName[18]; - if (strlen(aspName) > sizeof(paddedName)) - { - getErrTxt(DB2I_ERR_BAD_RDB_NAME); - return DB2I_ERR_BAD_RDB_NAME; - } - - memset(paddedName, ' ', sizeof(paddedName)); - memcpy(paddedName, aspName, strlen(aspName)); - convToEbcdic(paddedName, parmBlock->parms.RDBName, strlen(paddedName)); - - parmBlock->parms.RDBNamLen = strlen(paddedName); - parmBlock->parms.TrcSpcHnd = traceSpcHandle; - - rc = doIt(); - - if (rc) - { - reportSystemAPIError(rc, (Qmy_Error_output_t*)outParms); - } - - return rc; -} - -/** - Signal to the QMY_ APIs to perform any cleanup they need to do. -*/ -int32 db2i_ileBridge::exitILE() -{ - IleParms* parmBlock = parms(); - Qmy_MCLN0100 *input = (Qmy_MCLN0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_CLEANUP; - - int32 rc = doIt(); - - if (rc) - { - reportSystemAPIError(rc, (Qmy_Error_output_t*)parmBlock->outParms); - } - - unregisterPtr(traceSpcHandle); - - DBUG_PRINT("db2i_ileBridge::exitILE", ("Registered ptrs remaining: %d", registeredPtrs)); -#ifndef DBUG_OFF - if (registeredPtrs != 0) - printf("Oh no! IBMDB2I left some pointers registered. Count was %d.\n", registeredPtrs); -#endif - - // This is needed to prevent SAFE_MALLOC from complaining at process termination. - my_pthread_setspecific_ptr(THR_ILEPARMS, NULL); - free_aligned(parmBlock); - - return rc; - -} - - -/** - Designate the specified addresses as parameter passing buffers. - - @parm in Input to the API will go here; format is defined by the individual API - @parm out Output from the API will be; format is defined by the individual API - - @return 0 if success; error otherwise -*/ -int db2i_ileBridge::registerParmSpace(char* in, char* out) -{ - static const arg_type_t ileSignature[] = { ARG_MEMPTR, ARG_MEMPTR, ARG_END }; - - struct ArgList - { - ILEarglist_base base; - ILEpointer input; - ILEpointer output; - } *arguments; - - char argBuf[sizeof(ArgList)+15]; - arguments = (ArgList*)roundToQuadWordBdy(argBuf); - - arguments->input.s.addr = (address64_t)(in); - arguments->output.s.addr = (address64_t)(out); - - _ILECALL(&functionSymbols[funcRegisterParameterSpaces], - &arguments->base, - ileSignature, - RESULT_INT32); - - return arguments->base.result.s_int32.r_int32; -} - - -/** - Interface to QMY_OBJECT_OVERRIDE API. - - See QMY_OBJECT_OVERRIDE documentation for more information about parameters and - return codes. -*/ -int32 db2i_ileBridge::objectOverride(FILE_HANDLE rfileHandle, - ILEMemHandle buf, - uint32 recordWidth) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - IleParms* parmBlock = parms(); - Qmy_MOOX0100 *input = (Qmy_MOOX0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_OBJECT_OVERRIDE; - input->ObjHnd = rfileHandle; - input->OutSpcHnd = (uint64)buf; - input->NxtRowOff = recordWidth; - input->CnnHnd = cachedConnectionID; - - int32 rc = doItWithLog(); - - return rc; -} - -/** - Interface to QMY_DESCRIBE_OBJECT API for obtaining table stats. - - See QMY_DESCRIBE_OBJECT documentation for more information about parameters and - return codes. -*/ -int32 db2i_ileBridge::retrieveTableInfo(FILE_HANDLE defnHandle, - uint16 dataRequested, - ha_statistics& stats, - ILEMemHandle inSpc) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - IleParms* parmBlock = parms(); - Qmy_MDSO0100 *input = (Qmy_MDSO0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_DESCRIBE_OBJECT; - input->ShrHnd = defnHandle; - input->CnnHnd = cachedConnectionID; - - if (dataRequested & objLength) - input->RtnObjLen[0] = QMY_YES; - if (dataRequested & rowCount) - input->RtnRowCnt[0] = QMY_YES; - if (dataRequested & deletedRowCount) - input->RtnDltRowCnt[0] = QMY_YES; - if (dataRequested & rowsPerKey) - { - input->RowKeyHnd = (uint64)inSpc; - input->RtnRowKey[0] = QMY_YES; - } - if (dataRequested & meanRowLen) - input->RtnMeanRowLen[0] = QMY_YES; - if (dataRequested & lastModTime) - input->RtnModTim[0] = QMY_YES; - if (dataRequested & createTime) - input->RtnCrtTim[0] = QMY_YES; - if (dataRequested & ioCount) - input->RtnEstIoCnt[0] = QMY_YES; - - int32 rc = doItWithLog(); - - if (likely(rc == 0)) - { - Qmy_MDSO0100_output* output = (Qmy_MDSO0100_output*)parmBlock->outParms; - if (dataRequested & objLength) - stats.data_file_length = output->ObjLen; - if (dataRequested & rowCount) - stats.records= output->RowCnt; - if (dataRequested & deletedRowCount) - stats.deleted = output->DltRowCnt; - if (dataRequested & meanRowLen) - stats.mean_rec_length = output->MeanRowLen; - if (dataRequested & lastModTime) - stats.update_time = convertILEtime(output->ModTim); - if (dataRequested & createTime) - stats.create_time = convertILEtime(output->CrtTim); - if (dataRequested & ioCount) - stats.data_file_length = output->EstIoCnt; - } - - return rc; -} - -/** - Interface to QMY_DESCRIBE_OBJECT API for finding index size. - - See QMY_DESCRIBE_OBJECT documentation for more information about parameters and - return codes. -*/ -int32 db2i_ileBridge::retrieveIndexInfo(FILE_HANDLE defnHandle, - uint64* outPageCnt) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - IleParms* parmBlock = parms(); - Qmy_MDSO0100 *input = (Qmy_MDSO0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_DESCRIBE_OBJECT; - input->ShrHnd = defnHandle; - input->CnnHnd = cachedConnectionID; - input->RtnPageCnt[0] = QMY_YES; - - int32 rc = doItWithLog(); - - if (likely(rc == 0)) - { - Qmy_MDSO0100_output* output = (Qmy_MDSO0100_output*)parmBlock->outParms; - *outPageCnt = output->PageCnt; - } - - return rc; -} - - -/** - Interface to QMY_CLOSE_CONNECTION API - - See QMY_CLOSE_CONNECTION documentation for more information about parameters and - return codes. -*/ -int32 db2i_ileBridge::closeConnection(CONNECTION_HANDLE conn) -{ - IleParms* parmBlock = parms(); - Qmy_MCCN0100 *input = (Qmy_MCCN0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_CLOSE_CONNECTION; - input->CnnHnd = conn; - - int32 rc = doItWithLog(); - - return rc; -} - - -/** - Interface to QMY_INTERRUPT API - - See QMY_INTERRUPT documentation for more information about parameters and - return codes. -*/ -int32 db2i_ileBridge::readInterrupt(FILE_HANDLE fileHandle) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - IleParms* parmBlock = parms(); - Qmy_MINT0100 *input = (Qmy_MINT0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_INTERRUPT; - input->CnnHnd = cachedConnectionID; - input->ObjHnd = fileHandle; - - int32 rc = doItWithLog(); - - if (rc == QMY_ERR_END_OF_BLOCK) - { - rc = 0; - DBUG_PRINT("db2i_ileBridge::readInterrupt", ("End of block signalled")); - } - - return rc; -} - -/** - Interface to QMY_READ_ROWS API - - See QMY_READ_ROWS documentation for more information about parameters and - return codes. -*/ -int32 db2i_ileBridge::read(FILE_HANDLE rfileHandle, - ILEMemHandle buf, - char accessIntent, - char commitLevel, - char orientation, - bool asyncRead, - ILEMemHandle rrn, - ILEMemHandle key, - uint32 keylen, - uint16 keyParts, - int pipeFD) -{ - DBUG_ASSERT(cachedStateIsCoherent()); - IleParms* parmBlock = parms(); - Qmy_MRDX0100 *input = (Qmy_MRDX0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_READ_ROWS; - input->CmtLvl[0] = commitLevel; - - input->ObjHnd = rfileHandle; - input->Intent[0] = accessIntent; - input->OutSpcHnd = (uint64)buf; - input->OutRRNSpcHnd = (uint64)rrn; - input->RtnData[0] = QMY_RETURN_DATA; - - if (key) - { - input->KeySpcHnd = (uint64)key; - input->KeyColsLen = keylen; - input->KeyColsNbr = keyParts; - } - - input->Async[0] = (asyncRead ? QMY_YES : QMY_NO); - input->PipeDesc = pipeFD; - input->Orientation[0] = orientation; - input->CnnHnd = cachedConnectionID; - - int32 rc = doItWithLog(); - - // QMY_ERR_END_OF_BLOCK is informational only, so we ignore it. - if (rc == QMY_ERR_END_OF_BLOCK) - { - rc = 0; - DBUG_PRINT("db2i_ileBridge::read", ("End of block signalled")); - } - - return rc; -} - - -/** - Interface to QMY_QUIESCE_OBJECT API - - See QMY_QUIESCE_OBJECT documentation for more information about parameters and - return codes. -*/ -int32 db2i_ileBridge::quiesceFileInstance(FILE_HANDLE rfileHandle) -{ - IleParms* parmBlock = parms(); - Qmy_MQSC0100 *input = (Qmy_MQSC0100*)&(parmBlock->inParms); - memset(input, 0, sizeof(*input)); - - input->Format = QMY_QUIESCE_OBJECT; - input->ObjHnd = rfileHandle; - - int32 rc = doItWithLog(); - -#ifndef DBUG_OFF - if (unlikely(rc)) - { - DBUG_ASSERT(0); - } -#endif - - return rc; -} - -void db2i_ileBridge::PreservedHandleList::add(const char* newname, FILE_HANDLE newhandle, IBMDB2I_SHARE* share) -{ - NameHandlePair *newPair = (NameHandlePair*)my_malloc(sizeof(NameHandlePair), MYF(MY_WME)); - - newPair->next = head; - head = newPair; - - strcpy(newPair->name, newname); - newPair->handle = newhandle; - newPair->share = share; - DBUG_PRINT("db2i_ileBridge", ("Added handle %d for %s", uint32(newhandle), newname)); -} - - -FILE_HANDLE db2i_ileBridge::PreservedHandleList::findAndRemove(const char* fileName, IBMDB2I_SHARE** share) -{ - NameHandlePair* current = head; - NameHandlePair* prev = NULL; - - while (current) - { - NameHandlePair* next = current->next; - if (strcmp(fileName, current->name) == 0) - { - FILE_HANDLE tmp = current->handle; - *share = current->share; - if (prev) - prev->next = next; - if (current == head) - head = next; - my_free(current, MYF(0)); - DBUG_PRINT("db2i_ileBridge", ("Found handle %d for %s", uint32(tmp), fileName)); - return tmp; - } - prev = current; - current = next; - } - - return 0; -} - - -IleParms* db2i_ileBridge::initParmsForThread() -{ - - IleParms* p = (IleParms*)malloc_aligned(sizeof(IleParms)); - DBUG_ASSERT((uint64)(&(p->outParms))% 16 == 0); // Guarantee that outParms are aligned correctly - - if (likely(p)) - { - int32 rc = registerParmSpace((p->inParms), (p->outParms)); - if (likely(rc == 0)) - { - my_pthread_setspecific_ptr(THR_ILEPARMS, p); - DBUG_PRINT("db2i_ileBridge", ("Inited space for parms")); - return p; - } - else - reportSystemAPIError(rc, NULL); - } - - return NULL; -} - diff --git a/storage/ibmdb2i/db2i_ileBridge.h b/storage/ibmdb2i/db2i_ileBridge.h deleted file mode 100644 index 10b9820d983..00000000000 --- a/storage/ibmdb2i/db2i_ileBridge.h +++ /dev/null @@ -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, MYF(0)); - 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 diff --git a/storage/ibmdb2i/db2i_ioBuffers.cc b/storage/ibmdb2i/db2i_ioBuffers.cc deleted file mode 100644 index 9525a6e34b5..00000000000 --- a/storage/ibmdb2i/db2i_ioBuffers.cc +++ /dev/null @@ -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; -} diff --git a/storage/ibmdb2i/db2i_ioBuffers.h b/storage/ibmdb2i/db2i_ioBuffers.h deleted file mode 100644 index 350d854f055..00000000000 --- a/storage/ibmdb2i/db2i_ioBuffers.h +++ /dev/null @@ -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 -#include -#include - -// 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& 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 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 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 */ -}; - diff --git a/storage/ibmdb2i/db2i_misc.h b/storage/ibmdb2i/db2i_misc.h deleted file mode 100644 index f0b527aaad0..00000000000 --- a/storage/ibmdb2i/db2i_misc.h +++ /dev/null @@ -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 diff --git a/storage/ibmdb2i/db2i_myconv.cc b/storage/ibmdb2i/db2i_myconv.cc deleted file mode 100644 index 7be6e1236cd..00000000000 --- a/storage/ibmdb2i/db2i_myconv.cc +++ /dev/null @@ -1,1498 +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 A direct map optimization of iconv and related functions - This was show to significantly reduce character conversion cost - for short strings when compared to calling iconv system code. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "db2i_myconv.h" -#include "db2i_global.h" - -int32_t myconvDebug=0; - -static char szGetTimeString[20]; -static char * GetTimeString(time_t now) -{ - struct tm * tm; - - now = time(&now); - tm = (struct tm *) localtime(&now); - sprintf(szGetTimeString, "%04d/%02d/%02d %02d:%02d:%02d", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - - return szGetTimeString; -} - -static MEM_ROOT dmapMemRoot; - -void initMyconv() -{ - init_alloc_root(&dmapMemRoot, 0x200, 0); -} - -void cleanupMyconv() -{ - free_root(&dmapMemRoot,0); -} - - -#ifdef DEBUG -/* type: */ -#define STDOUT_WITH_TIME -1 /* to stdout with time */ -#define STDERR_WITH_TIME -2 /* to stderr with time */ -#define STDOUT_WO_TIME 1 /* : to stdout */ -#define STDERR_WO_TIME 2 /* : to stderr */ - - -static void MyPrintf(long type, - char * fmt, ...) -{ - char StdoutFN[256]; - va_list ap; - char * p; - time_t now; - FILE * fd=stderr; - - if (type < 0) - { - now = time(&now); - fprintf(fd, "%s ", GetTimeString(now)); - } - va_start(ap, fmt); - vfprintf(fd, fmt, ap); - va_end(ap); -} -#endif - - - - -#define MAX_CONVERTER 128 - -mycstoccsid(const char* pname) -{ - if (strcmp(pname, "UTF-16")==0) - return 1200; - else if (strcmp(pname, "big5")==0) - return 950; - else - return cstoccsid(pname); -} -#define cstoccsid mycstoccsid - -static struct __myconv_rec myconv_rec [MAX_CONVERTER]; -static struct __dmap_rec dmap_rec [MAX_CONVERTER]; - -static int dmap_open(const char * to, - const char * from, - const int32_t idx) -{ - if (myconvIsSBCS(from) && myconvIsSBCS(to)) { - dmap_rec[idx].codingSchema = DMAP_S2S; - if ((dmap_rec[idx].dmapS2S = (uchar *) alloc_root(&dmapMemRoot, 0x100)) == NULL) { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d), CS=%d failed with malloc(), errno = %d in %s at %d\n", - to, from, idx, DMAP_S2S, errno, __FILE__,__LINE__); -#endif - return -1; - } - memset(dmap_rec[idx].dmapS2S, 0x00, 0x100); - myconv_rec[idx].allocatedSize=0x100; - - { - char dmapSrc[0x100]; - iconv_t cd; - int32_t i; - size_t inBytesLeft=0x100; - size_t outBytesLeft=0x100; - size_t len; - char * inBuf=dmapSrc; - char * outBuf=(char *) dmap_rec[idx].dmapS2S; - - if ((cd = iconv_open(to, from)) == (iconv_t) -1) { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed with iconv_open(), errno = %d in %s at %d\n", - to, from, idx, errno, __FILE__,__LINE__); -#endif - return -1; - } - - inBytesLeft = 0x100; - for (i = 0; i < inBytesLeft; ++i) - dmapSrc[i]=i; - - do { - if ((len = iconv(cd, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft)) != (size_t) 0) { -#ifdef DEBUG - if (myconvDebug) { - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d), CS=%d: iconv() returns %d, errno = %d in %s at %d\n", - to, from, idx, DMAP_S2S, len, errno, __FILE__,__LINE__); - MyPrintf(STDERR_WITH_TIME, - "inBytesLeft = %d, inBuf - dmapSrc = %d\n", inBytesLeft, inBuf-dmapSrc); - MyPrintf(STDERR_WITH_TIME, - "outBytesLeft = %d, outBuf - dmapS2S = %d\n", outBytesLeft, outBuf-(char *) dmap_rec[idx].dmapS2S); - } - if ((inBytesLeft == 86 || inBytesLeft == 64 || inBytesLeft == 1) && - memcmp(from, "IBM-1256", 9) == 0 && - memcmp(to, "IBM-420", 8) == 0) { - /* Known problem for IBM-1256_IBM-420 */ - --inBytesLeft; - ++inBuf; - *outBuf=0x00; - ++outBuf; - --outBytesLeft; - continue; - } else if ((inBytesLeft == 173 || inBytesLeft == 172 || - inBytesLeft == 74 || inBytesLeft == 73 || - inBytesLeft == 52 || inBytesLeft == 50 || - inBytesLeft == 31 || inBytesLeft == 20 || - inBytesLeft == 6) && - memcmp(to, "IBM-1256", 9) == 0 && - memcmp(from, "IBM-420", 8) == 0) { - /* Known problem for IBM-420_IBM-1256 */ - --inBytesLeft; - ++inBuf; - *outBuf=0x00; - ++outBuf; - --outBytesLeft; - continue; - } else if ((128 >= inBytesLeft) && - memcmp(to, "IBM-037", 8) == 0 && - memcmp(from, "IBM-367", 8) == 0) { - /* Known problem for IBM-367_IBM-037 */ - --inBytesLeft; - ++inBuf; - *outBuf=0x00; - ++outBuf; - --outBytesLeft; - continue; - } else if (((1 <= inBytesLeft && inBytesLeft <= 4) || (97 <= inBytesLeft && inBytesLeft <= 128)) && - memcmp(to, "IBM-838", 8) == 0 && - memcmp(from, "TIS-620", 8) == 0) { - /* Known problem for TIS-620_IBM-838 */ - --inBytesLeft; - ++inBuf; - *outBuf=0x00; - ++outBuf; - --outBytesLeft; - continue; - } - iconv_close(cd); - return -1; -#else - /* Tolerant to undefined conversions for any converter */ - --inBytesLeft; - ++inBuf; - *outBuf=0x00; - ++outBuf; - --outBytesLeft; - continue; -#endif - } - } while (inBytesLeft > 0); - - if (myconvIsISO(to)) - myconv_rec[idx].subS=0x1A; - else if (myconvIsASCII(to)) - myconv_rec[idx].subS=0x7F; - else if (myconvIsEBCDIC(to)) - myconv_rec[idx].subS=0x3F; - - if (myconvIsISO(from)) - myconv_rec[idx].srcSubS=0x1A; - else if (myconvIsASCII(from)) - myconv_rec[idx].srcSubS=0x7F; - else if (myconvIsEBCDIC(from)) - myconv_rec[idx].srcSubS=0x3F; - - iconv_close(cd); - } - } else if (((myconvIsSBCS(from) && myconvIsUnicode2(to)) && (dmap_rec[idx].codingSchema = DMAP_S2U)) || - ((myconvIsSBCS(from) && myconvIsUTF8(to)) && (dmap_rec[idx].codingSchema = DMAP_S28))) { - int i; - - /* single byte mapping */ - if ((dmap_rec[idx].dmapD12U = (UniChar *) alloc_root(&dmapMemRoot, 0x100 * 2)) == NULL) { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d), CS=%d failed with malloc(), errno = %d in %s at %d\n", - to, from, idx, DMAP_S2U, errno, __FILE__,__LINE__); -#endif - return -1; - } - memset(dmap_rec[idx].dmapD12U, 0x00, 0x100 * 2); - myconv_rec[idx].allocatedSize=0x100 * 2; - - - { - char dmapSrc[2]; - iconv_t cd; - int32_t i; - size_t inBytesLeft; - size_t outBytesLeft; - size_t len; - char * inBuf; - char * outBuf; - char SS=0x1A; -#ifdef support_surrogate - if ((cd = iconv_open("UTF-16", from)) == (iconv_t) -1) { -#else - if ((cd = iconv_open("UCS-2", from)) == (iconv_t) -1) { -#endif -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed with iconv_open(), errno = %d in %s at %d\n", - to, from, idx, errno, __FILE__,__LINE__); -#endif - return -1; - } - - for (i = 0; i < 0x100; ++i) { - dmapSrc[0]=i; - inBuf=dmapSrc; - inBytesLeft=1; - outBuf=(char *) &(dmap_rec[idx].dmapD12U[i]); - outBytesLeft=2; - if ((len = iconv(cd, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft)) != (size_t) 0) { - if ((errno == EILSEQ || errno == EINVAL) && - inBytesLeft == 1 && - outBytesLeft == 2) { - continue; - } else { -#ifdef DEBUG - if (myconvDebug) { - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed to initialize with iconv(cd,%02x,%d,%02x%02x,%d), errno = %d in %s at %d\n", - to, from, idx, dmapSrc[0], 1, - (&dmap_rec[idx].dmapD12U[i])[0],(&dmap_rec[idx].dmapD12U[i])[1], 2, - errno, __FILE__,__LINE__); - MyPrintf(STDERR_WITH_TIME, - "inBytesLeft=%d, outBytesLeft=%d, %02x%02x\n", - inBytesLeft, outBytesLeft, - (&dmap_rec[idx].dmapD12U[i])[0],(&dmap_rec[idx].dmapD12U[i])[1]); - } -#endif - iconv_close(cd); - return -1; - } - dmap_rec[idx].dmapD12U[i]=0x0000; - } - if (dmap_rec[idx].dmapE02U[i] == 0x001A && /* pick the first one */ - myconv_rec[idx].srcSubS == 0x00) { - myconv_rec[idx].srcSubS=i; - } - } - iconv_close(cd); - } - myconv_rec[idx].subS=0x1A; - myconv_rec[idx].subD=0xFFFD; - - - } else if (((myconvIsUCS2(from) && myconvIsSBCS(to)) && (dmap_rec[idx].codingSchema = DMAP_U2S)) || - ((myconvIsUTF16(from) && myconvIsSBCS(to)) && (dmap_rec[idx].codingSchema = DMAP_T2S)) || - ((myconvIsUTF8(from) && myconvIsSBCS(to)) && (dmap_rec[idx].codingSchema = DMAP_82S))) { - /* UTF-16 -> SBCS, the direct map a bit of waste of space, - * binary search may be reasonable alternative - */ - if ((dmap_rec[idx].dmapU2S = (uchar *) alloc_root(&dmapMemRoot, 0x10000 * 2)) == NULL) { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d), CS=%d failed with malloc(), errno = %d in %s at %d\n", - to, from, idx, DMAP_U2S, errno, __FILE__,__LINE__); -#endif - return -1; - } - memset(dmap_rec[idx].dmapU2S, 0x00, 0x10000); - myconv_rec[idx].allocatedSize=(0x10000 * 2); - - { - iconv_t cd; - int32_t i; - -#ifdef support_surrogate - if ((cd = iconv_open(to, "UTF-16")) == (iconv_t) -1) { -#else - if ((cd = iconv_open(to, "UCS-2")) == (iconv_t) -1) { -#endif -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed with iconv_open(), errno = %d in %s at %d\n", - to, from, idx, errno, __FILE__,__LINE__); -#endif - return -1; - } - - for (i = 0; i < 0x100; ++i) { - UniChar dmapSrc[0x100]; - int32_t j; - for (j = 0; j < 0x100; ++j) { - dmapSrc[j]=i * 0x100 + j; - } - char * inBuf=(char *) dmapSrc; - char * outBuf=(char *) &(dmap_rec[idx].dmapU2S[i*0x100]); - size_t inBytesLeft=sizeof(dmapSrc); - size_t outBytesLeft=0x100; - size_t len; - - if ((len = iconv(cd, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft)) != (size_t) 0) { - if (inBytesLeft == 0 && outBytesLeft == 0) { /* a number of substitution returns */ - continue; - } -#ifdef DEBUG - if (myconvDebug) { - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed to initialize with iconv(), errno = %d in %s at %d\n", - from, to, idx, errno, __FILE__,__LINE__); - MyPrintf(STDERR_WITH_TIME, - "iconv() retuns %d, errno=%d, InBytesLeft=%d, OutBytesLeft=%d\n", - len, errno, inBytesLeft, outBytesLeft, __FILE__,__LINE__); - } -#endif - iconv_close(cd); - return -1; - } - } - iconv_close(cd); - - myconv_rec[idx].subS = dmap_rec[idx].dmapU2S[0x1A]; - myconv_rec[idx].subD = dmap_rec[idx].dmapU2S[0xFFFD]; - myconv_rec[idx].srcSubS = 0x1A; - myconv_rec[idx].srcSubD = 0xFFFD; - } - - - - } else if (((myconvIsDBCS(from) && myconvIsUnicode2(to)) && (dmap_rec[idx].codingSchema = DMAP_D2U)) || - ((myconvIsDBCS(from) && myconvIsUTF8(to)) && (dmap_rec[idx].codingSchema = DMAP_D28))) { - int i; - /* single byte mapping */ - if ((dmap_rec[idx].dmapD12U = (UniChar *) alloc_root(&dmapMemRoot, 0x100 * 2)) == NULL) { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d), CS=%d failed with malloc(), errno = %d in %s at %d\n", - to, from, idx, DMAP_D2U, errno, __FILE__,__LINE__); -#endif - return -1; - } - memset(dmap_rec[idx].dmapD12U, 0x00, 0x100 * 2); - - /* double byte mapping, assume 7 bit ASCII is not use as the first byte of DBCS. */ - if ((dmap_rec[idx].dmapD22U = (UniChar *) alloc_root(&dmapMemRoot, 0x8000 * 2)) == NULL) { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d), CS=%d failed with malloc(), errno = %d in %s at %d\n", - to, from, idx, DMAP_D2U, errno, __FILE__,__LINE__); -#endif - return -1; - } - memset(dmap_rec[idx].dmapD22U, 0x00, 0x8000 * 2); - - myconv_rec[idx].allocatedSize=(0x100 + 0x8000) * 2; - - - { - char dmapSrc[2]; - iconv_t cd; - int32_t i; - size_t inBytesLeft; - size_t outBytesLeft; - size_t len; - char * inBuf; - char * outBuf; - char SS=0x1A; - -#ifdef support_surrogate - if ((cd = iconv_open("UTF-16", from)) == (iconv_t) -1) { -#else - if ((cd = iconv_open("UCS-2", from)) == (iconv_t) -1) { -#endif -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed with iconv_open(), errno = %d in %s at %d\n", - to, from, idx, errno, __FILE__,__LINE__); -#endif - return -1; - } - - for (i = 0; i < 0x100; ++i) { - dmapSrc[0]=i; - inBuf=dmapSrc; - inBytesLeft=1; - outBuf=(char *) (&dmap_rec[idx].dmapD12U[i]); - outBytesLeft=2; - if ((len = iconv(cd, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft)) != (size_t) 0) { - if ((errno == EILSEQ || errno == EINVAL) && - inBytesLeft == 1 && - outBytesLeft == 2) { - continue; - } else { -#ifdef DEBUG - if (myconvDebug) { - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed to initialize with iconv(cd,%02x,%d,%02x%02x,%d), errno = %d in %s at %d\n", - to, from, idx, dmapSrc[0], 1, - (&dmap_rec[idx].dmapD12U[i])[0],(&dmap_rec[idx].dmapD12U[i])[1], 2, - errno, __FILE__,__LINE__); - MyPrintf(STDERR_WITH_TIME, - "inBytesLeft=%d, outBytesLeft=%d, %02x%02x\n", - inBytesLeft, outBytesLeft, - (&dmap_rec[idx].dmapD12U[i])[0],(&dmap_rec[idx].dmapD12U[i])[1]); - } -#endif - iconv_close(cd); - return -1; - } - dmap_rec[idx].dmapD12U[i]=0x0000; - } - if (dmap_rec[idx].dmapD12U[i] == 0x001A && /* pick the first one */ - myconv_rec[idx].srcSubS == 0x00) { - myconv_rec[idx].srcSubS=i; - } - } - - - for (i = 0x80; i < 0x100; ++i) { - int j; - if (dmap_rec[idx].dmapD12U[i] != 0x0000) - continue; - for (j = 0x01; j < 0x100; ++j) { - dmapSrc[0]=i; - dmapSrc[1]=j; - int offset = i-0x80; - offset<<=8; - offset+=j; - - inBuf=dmapSrc; - inBytesLeft=2; - outBuf=(char *) &(dmap_rec[idx].dmapD22U[offset]); - outBytesLeft=2; - if ((len = iconv(cd, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft)) != (size_t) 0) { - if (inBytesLeft == 2 && outBytesLeft == 2 && (errno == EILSEQ || errno == EINVAL)) { - ; /* invalid DBCS character, dmapDD2U[offset] remains 0x0000 */ - } else { -#ifdef DEBUG - if (myconvDebug) { - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed to initialize with iconv(cd,%p,2,%p,2), errno = %d in %s at %d\n", - to, from, idx, - dmapSrc, &(dmap_rec[idx].dmapD22U[offset]), - errno, __FILE__,__LINE__); - MyPrintf(STDERR_WO_TIME, - "iconv(cd,0x%02x%02x,2,0x%04x,2) returns %d, inBytesLeft=%d, outBytesLeft=%d\n", - dmapSrc[0], dmapSrc[1], - dmap_rec[idx].dmapD22U[offset], - len, inBytesLeft, outBytesLeft); - } -#endif - iconv_close(cd); - return -1; - } - } else { -#ifdef TRACE_DMAP - if (myconvDebug) { - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed to initialize with iconv(), rc=%d, errno=%d in %s at %d\n", - to, from, idx, len, errno, __FILE__,__LINE__); - MyPrintf(STDERR_WITH_TIME, - "%04X: src=%04X%04X, inBuf=0x%02X%02X, inBytesLeft=%d, outBuf=%02X%02X%02X, outBytesLeft=%d\n", - i, dmapSrc[0], dmapSrc[1], inBuf[0], inBuf[1], - inBytesLeft, outBuf[-2], outBuf[-1], outBuf[0], outBytesLeft); - MyPrintf(STDERR_WITH_TIME, - "&dmapSrc=%p, inBuf=%p, %p, outBuf=%p\n", - dmapSrc, inBuf, dmap_rec[idx].dmapU2M3 + (i - 0x80) * 2, outBuf); - } -#endif - } - } - if (dmap_rec[idx].dmapD12U[i] == 0xFFFD) { /* pick the last one */ - myconv_rec[idx].srcSubD=i* 0x100 + j; - } - } - iconv_close(cd); - } - - myconv_rec[idx].subS=0x1A; - myconv_rec[idx].subD=0xFFFD; - myconv_rec[idx].srcSubD=0xFCFC; - - - } else if (((myconvIsUCS2(from) && myconvIsDBCS(to)) && (dmap_rec[idx].codingSchema = DMAP_U2D)) || - ((myconvIsUTF16(from) && myconvIsDBCS(to)) && (dmap_rec[idx].codingSchema = DMAP_T2D)) || - ((myconvIsUTF8(from) && myconvIsDBCS(to)) && (dmap_rec[idx].codingSchema = DMAP_82D))) { - /* UTF-16 -> DBCS single/double byte */ - /* A single table will cover all characters, assuming no second byte is 0x00. */ - if ((dmap_rec[idx].dmapU2D = (uchar *) alloc_root(&dmapMemRoot, 0x10000 * 2)) == NULL) { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d), CS=%d failed with malloc(), errno = %d in %s at %d\n", - to, from, idx, DMAP_U2D, errno, __FILE__,__LINE__); -#endif - return -1; - } - - memset(dmap_rec[idx].dmapU2D, 0x00, 0x10000 * 2); - myconv_rec[idx].allocatedSize=(0x10000 * 2); - - { - UniChar dmapSrc[1]; - iconv_t cd; - int32_t i; - size_t inBytesLeft; - size_t outBytesLeft; - size_t len; - char * inBuf; - char * outBuf; - -#ifdef support_surrogate - if ((cd = iconv_open(to, "UTF-16")) == (iconv_t) -1) { -#else - if ((cd = iconv_open(to, "UCS-2")) == (iconv_t) -1) { -#endif -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed with iconv_open(), errno = %d in %s at %d\n", - to, from, idx, errno, __FILE__,__LINE__); -#endif - return -1; - } - - /* easy implementation, convert 1 Unicode character at one time. */ - /* If the open performance is an issue, convert a chunk such as 128 chracters. */ - /* if the converted length is not the same as the original, convert one by one. */ - (dmap_rec[idx].dmapU2D)[0x0000]=0x00; - for (i = 1; i < 0x10000; ++i) { - dmapSrc[0]=i; - inBuf=(char *) dmapSrc; - inBytesLeft=2; - outBuf=(char *) &((dmap_rec[idx].dmapU2D)[2*i]); - outBytesLeft=2; - do { - if ((len = iconv(cd, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft)) != (size_t) 0) { - if (len == 1 && inBytesLeft == 0 && outBytesLeft == 1 && (dmap_rec[idx].dmapU2D)[2*i] == 0x1A) { - /* UCS-2_TIS-620:0x0080 => 0x1A, converted to SBCS replacement character */ - (dmap_rec[idx].dmapU2D)[2*i+1]=0x00; - break; - } else if (len == 1 && inBytesLeft == 0 && outBytesLeft == 0) { - break; - } - if (errno == EILSEQ || errno == EINVAL) { -#ifdef DEBUG - if (myconvDebug) { - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed to initialize with iconv(), errno = %d in %s at %d\n", - to, from, idx, errno, __FILE__,__LINE__); - MyPrintf(STDERR_WO_TIME, - "iconv(cd,%04x,2,%02x%02x,2) returns inBytesLeft=%d, outBytesLeft=%d\n", - dmapSrc[0], - (dmap_rec[idx].dmapU2D)[2*i], (dmap_rec[idx].dmapU2D)[2*i+1], - inBytesLeft, outBytesLeft); - if (outBuf - (char *) dmap_rec[idx].dmapU2M2 > 1) - MyPrintf(STDERR_WO_TIME, "outBuf[-2..2]=%02X%02X%02X%02X%02X\n", outBuf[-2],outBuf[-1],outBuf[0],outBuf[1],outBuf[2]); - else - MyPrintf(STDERR_WO_TIME, "outBuf[0..2]=%02X%02X%02X\n", outBuf[0],outBuf[1],outBuf[2]); - } -#endif - inBuf+=2; - inBytesLeft-=2; - memcpy(outBuf, (char *) &(myconv_rec[idx].subD), 2); - outBuf+=2; - outBytesLeft-=2; - } else { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "[%d] dmap_open(%s,%s,%d) failed to initialize with iconv(), errno = %d in %s at %d\n", - i, to, from, idx, errno, __FILE__,__LINE__); - MyPrintf(STDERR_WO_TIME, - "iconv(cd,%04x,2,%02x%02x,2) returns %d inBytesLeft=%d, outBytesLeft=%d\n", - dmapSrc[0], - (dmap_rec[idx].dmapU2D)[2*i], - (dmap_rec[idx].dmapU2D)[2*i+1], - len, inBytesLeft,outBytesLeft); - if (i == 1) { - MyPrintf(STDERR_WO_TIME, - " inBuf [-1..2]=%02x%02x%02x%02x\n", - inBuf[-1],inBuf[0],inBuf[1],inBuf[2]); - MyPrintf(STDERR_WO_TIME, - " outBuf [-1..2]=%02x%02x%02x%02x\n", - outBuf[-1],outBuf[0],outBuf[1],outBuf[2]); - } else { - MyPrintf(STDERR_WO_TIME, - " inBuf [-2..2]=%02x%02x%02x%02x%02x\n", - inBuf[-2],inBuf[-1],inBuf[0],inBuf[1],inBuf[2]); - MyPrintf(STDERR_WO_TIME, - " outBuf [-2..2]=%02x%02x%02x%02x%02x\n", - outBuf[-2],outBuf[-1],outBuf[0],outBuf[1],outBuf[2]); - } -#endif - iconv_close(cd); - return -1; - } - if (len == 0 && inBytesLeft == 0 && outBytesLeft == 1) { /* converted to SBCS */ - (dmap_rec[idx].dmapU2D)[2*i+1]=0x00; - break; - } - } - } while (inBytesLeft > 0); - } - iconv_close(cd); - myconv_rec[idx].subS = dmap_rec[idx].dmapU2D[2*0x1A]; - myconv_rec[idx].subD = dmap_rec[idx].dmapU2D[2*0xFFFD] * 0x100 - + dmap_rec[idx].dmapU2D[2*0xFFFD+1]; - myconv_rec[idx].srcSubS = 0x1A; - myconv_rec[idx].srcSubD = 0xFFFD; - } - - - } else if (((myconvIsEUC(from) && myconvIsUnicode2(to)) && (dmap_rec[idx].codingSchema = DMAP_E2U)) || - ((myconvIsEUC(from) && myconvIsUTF8(to)) && (dmap_rec[idx].codingSchema = DMAP_E28))) { - int i; - /* S0: 0x00 - 0x7F */ - if ((dmap_rec[idx].dmapE02U = (UniChar *) alloc_root(&dmapMemRoot, 0x100 * 2)) == NULL) { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d), CS=%d failed with malloc(), errno = %d in %s at %d\n", - to, from, idx, DMAP_E2U, errno, __FILE__,__LINE__); -#endif - return -1; - } - memset(dmap_rec[idx].dmapE02U, 0x00, 0x100 * 2); - - /* S1: 0xA0 - 0xFF, 0xA0 - 0xFF */ - if ((dmap_rec[idx].dmapE12U = (UniChar *) alloc_root(&dmapMemRoot, 0x60 * 0x60 * 2)) == NULL) { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d), CS=%d failed with malloc(), errno = %d in %s at %d\n", - to, from, idx, DMAP_E2U, errno, __FILE__,__LINE__); -#endif - return -1; - } - memset(dmap_rec[idx].dmapE12U, 0x00, 0x60 * 0x60 * 2); - - /* SS2: 0x8E + 0xA0 - 0xFF, 0xA0 - 0xFF */ - if ((dmap_rec[idx].dmapE22U = (UniChar *) alloc_root(&dmapMemRoot, 0x60 * 0x61 * 2)) == NULL) { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d), CS=%d failed with malloc(), errno = %d in %s at %d\n", - to, from, idx, DMAP_E2U, errno, __FILE__,__LINE__); -#endif - return -1; - } - memset(dmap_rec[idx].dmapE22U, 0x00, 0x60 * 0x61 * 2); - - /* SS3: 0x8F + 0xA0 - 0xFF, 0xA0 - 0xFF */ - if ((dmap_rec[idx].dmapE32U = (UniChar *) alloc_root(&dmapMemRoot, 0x60 * 0x61 * 2)) == NULL) { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d), CS=%d failed with malloc(), errno = %d in %s at %d\n", - to, from, idx, DMAP_E2U, errno, __FILE__,__LINE__); -#endif - return -1; - } - memset(dmap_rec[idx].dmapE32U, 0x00, 0x60 * 0x61 * 2); - - myconv_rec[idx].allocatedSize=(0x100 + 0x60 * 0x60 + 0x60 * 0x61* 2) * 2; - - - { - char dmapSrc[0x60 * 0x60 * 3]; - iconv_t cd; - int32_t i; - size_t inBytesLeft; - size_t outBytesLeft; - size_t len; - char * inBuf; - char * outBuf; - char SS=0x8E; - -#ifdef support_surrogate - if ((cd = iconv_open("UTF-16", from)) == (iconv_t) -1) { -#else - if ((cd = iconv_open("UCS-2", from)) == (iconv_t) -1) { -#endif -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed with iconv_open(), errno = %d in %s at %d\n", - to, from, idx, errno, __FILE__,__LINE__); -#endif - return -1; - } - - for (i = 0; i < 0x100; ++i) { - dmapSrc[0]=i; - inBuf=dmapSrc; - inBytesLeft=1; - outBuf=(char *) (&dmap_rec[idx].dmapE02U[i]); - outBytesLeft=2; - if ((len = iconv(cd, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft)) != (size_t) 0) { -#ifdef DEBUG - if (myconvDebug) { - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed to initialize with iconv(), errno = %d in %s at %d\n", - to, from, idx, errno, __FILE__,__LINE__); - } -#endif - dmap_rec[idx].dmapE02U[i]=0x0000; - } - if (dmap_rec[idx].dmapE02U[i] == 0x001A && /* pick the first one */ - myconv_rec[idx].srcSubS == 0x00) { - myconv_rec[idx].srcSubS=i; - } - } - - - inBuf=dmapSrc; - for (i = 0; i < 0x60; ++i) { - int j; - for (j = 0; j < 0x60; ++j) { - *inBuf=i+0xA0; - ++inBuf; - *inBuf=j+0xA0; - ++inBuf; - } - } - inBuf=dmapSrc; - inBytesLeft=0x60 * 0x60 * 2; - outBuf=(char *) dmap_rec[idx].dmapE12U; - outBytesLeft=0x60 * 0x60 * 2; - do { - if ((len = iconv(cd, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft)) != (size_t) 0) { - if (errno == EILSEQ) { -#ifdef DEBUG - if (myconvDebug) { - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed to initialize with iconv(), errno = %d in %s at %d\n", - to, from, idx, errno, __FILE__,__LINE__); - MyPrintf(STDERR_WO_TIME, "inBytesLeft=%d, outBytesLeft=%d\n", inBytesLeft, outBytesLeft); - if (inBuf - dmapSrc > 1 && inBuf - dmapSrc <= sizeof(dmapSrc) - 2) - MyPrintf(STDERR_WO_TIME, "inBuf[-2..2]=%02X%02X%02X%02X%02X\n", inBuf[-2],inBuf[-1],inBuf[0],inBuf[1],inBuf[2]); - else - MyPrintf(STDERR_WO_TIME, "inBuf[0..2]=%02X%02X%02X\n", inBuf[0],inBuf[1],inBuf[2]); - if (outBuf - (char *) dmap_rec[idx].dmapE12U > 1) - MyPrintf(STDERR_WO_TIME, "outBuf[-2..2]=%02X%02X%02X%02X%02X\n", outBuf[-2],outBuf[-1],outBuf[0],outBuf[1],outBuf[2]); - else - MyPrintf(STDERR_WO_TIME, "outBuf[0..2]=%02X%02X%02X\n", outBuf[0],outBuf[1],outBuf[2]); - } -#endif - inBuf+=2; - inBytesLeft-=2; - outBuf[0]=0x00; - outBuf[1]=0x00; - outBuf+=2; - outBytesLeft-=2; - } else { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed to initialize with iconv(), errno = %d in %s at %d\n", - to, from, idx, errno, __FILE__,__LINE__); -#endif - iconv_close(cd); - return -1; - } - } - } while (inBytesLeft > 0); - - /* SS2: 0x8E + 1 or 2 bytes */ - /* SS3: 0x8E + 1 or 2 bytes */ - while (SS != 0x00) { - int32_t numSuccess=0; - for (i = 0; i < 0x60; ++i) { - inBuf=dmapSrc; - inBuf[0]=SS; - inBuf[1]=i+0xA0; - inBytesLeft=2; - if (SS == 0x8E) - outBuf=(char *) &(dmap_rec[idx].dmapE22U[i]); - else - outBuf=(char *) &(dmap_rec[idx].dmapE32U[i]); - outBytesLeft=2; - if ((len = iconv(cd, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft)) != (size_t) 0) { - if (SS == 0x8E) - dmap_rec[idx].dmapE22U[i]=0x0000; - else - dmap_rec[idx].dmapE32U[i]=0x0000; - } else { - ++numSuccess; - } - } - if (numSuccess == 0) { /* SS2 is 2 bytes */ - inBuf=dmapSrc; - for (i = 0; i < 0x60; ++i) { - int j; - for (j = 0; j < 0x60; ++j) { - *inBuf=SS; - ++inBuf; - *inBuf=i+0xA0; - ++inBuf; - *inBuf=j+0xA0; - ++inBuf; - } - } - inBuf=dmapSrc; - inBytesLeft=0x60 * 0x60 * 3; - if (SS == 0x8E) - outBuf=(char *) &(dmap_rec[idx].dmapE22U[0x60]); - else - outBuf=(char *) &(dmap_rec[idx].dmapE32U[0x60]); - outBytesLeft=0x60 * 0x60 * 2; - do { - if ((len = iconv(cd, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft)) != (size_t) 0) { -#ifdef DEBUG - if (myconvDebug) { - MyPrintf(STDERR_WITH_TIME, - "%02X:dmap_open(%s,%s,%d) failed to initialize with iconv(), errno = %d in %s at %d\n", - SS, to, from, idx, errno, __FILE__,__LINE__); - MyPrintf(STDERR_WO_TIME, "inBytesLeft=%d, outBytesLeft=%d\n", inBytesLeft, outBytesLeft); - if (inBuf - dmapSrc > 1 && inBuf - dmapSrc <= sizeof(dmapSrc) - 2) - MyPrintf(STDERR_WO_TIME, "inBuf[-2..2]=%02X%02X%02X%02X%02X\n", inBuf[-2],inBuf[-1],inBuf[0],inBuf[1],inBuf[2]); - else - MyPrintf(STDERR_WO_TIME, "inBuf[0..2]=%02X%02X%02X\n", inBuf[0],inBuf[1],inBuf[2]); - } -#endif - if (errno == EILSEQ || errno == EINVAL) { - inBuf+=3; - inBytesLeft-=3; - outBuf[0]=0x00; - outBuf[1]=0x00; - outBuf+=2; - outBytesLeft-=2; - } else { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "%02X:dmap_open(%s,%s,%d) failed to initialize with iconv(), errno = %d in %s at %d\n", - SS, to, from, idx, errno, __FILE__,__LINE__); -#endif - iconv_close(cd); - return -1; - } - } - } while (inBytesLeft > 0); - } - if (SS == 0x8E) - SS=0x8F; - else - SS = 0x00; - } - iconv_close(cd); - - myconv_rec[idx].subS=0x1A; - myconv_rec[idx].subD=0xFFFD; - for (i = 0; i < 0x80; ++i) { - if (dmap_rec[idx].dmapE02U[i] == 0x001A) { - myconv_rec[idx].srcSubS=i; /* pick the first one */ - break; - } - } - - for (i = 0; i < 0x60 * 0x60; ++i) { - if (dmap_rec[idx].dmapE12U[i] == 0xFFFD) { - uchar byte1=i / 0x60; - uchar byte2=i % 0x60; - myconv_rec[idx].srcSubD=(byte1 + 0xA0) * 0x100 + (byte2 + 0xA0); /* pick the last one */ - } - } - - } - - } else if (((myconvIsUCS2(from) && myconvIsEUC(to)) && (dmap_rec[idx].codingSchema = DMAP_U2E)) || - ((myconvIsUTF16(from) && myconvIsEUC(to)) && (dmap_rec[idx].codingSchema = DMAP_T2E)) || - ((myconvIsUTF8(from) && myconvIsEUC(to)) && (dmap_rec[idx].codingSchema = DMAP_82E))) { - /* S0: 0x00 - 0xFF */ - if ((dmap_rec[idx].dmapU2S = (uchar *) alloc_root(&dmapMemRoot, 0x100)) == NULL) { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d), CS=%d failed with malloc(), errno = %d in %s at %d\n", - to, from, idx, DMAP_U2E, errno, __FILE__,__LINE__); -#endif - return -1; - } - memset(dmap_rec[idx].dmapU2S, 0x00, 0x100); - - /* U0080 - UFFFF -> S1: 0xA0 - 0xFF, 0xA0 - 0xFF */ - if ((dmap_rec[idx].dmapU2M2 = (uchar *) alloc_root(&dmapMemRoot, 0xFF80 * 2)) == NULL) { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d), CS=%d failed with malloc(), errno = %d in %s at %d\n", - to, from, idx, DMAP_U2E, errno, __FILE__,__LINE__); -#endif - return -1; - } - memset(dmap_rec[idx].dmapU2M2, 0x00, 0xFF80 * 2); - - /* U0080 - UFFFF -> SS2: 0x8E + 0xA0 - 0xFF, 0xA0 - 0xFF - * SS3: 0x8F + 0xA0 - 0xFF, 0xA0 - 0xFF */ - if ((dmap_rec[idx].dmapU2M3 = (uchar *) alloc_root(&dmapMemRoot, 0xFF80 * 3)) == NULL) { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d), CS=%d failed with malloc(), errno = %d in %s at %d\n", - to, from, idx, DMAP_U2E, errno, __FILE__,__LINE__); -#endif - return -1; - } - memset(dmap_rec[idx].dmapU2M3, 0x00, 0xFF80 * 3); - myconv_rec[idx].allocatedSize=(0x100 + 0xFF80 * 2 + 0xFF80 * 3); - - { - UniChar dmapSrc[0x80]; - iconv_t cd; - int32_t i; - size_t inBytesLeft; - size_t outBytesLeft; - size_t len; - char * inBuf; - char * outBuf; - -#ifdef support_surrogate - if ((cd = iconv_open(to, "UTF-16")) == (iconv_t) -1) { -#else - if ((cd = iconv_open(to, "UCS-2")) == (iconv_t) -1) { -#endif -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed with iconv_open(), errno = %d in %s at %d\n", - to, from, idx, errno, __FILE__,__LINE__); -#endif - return -1; - } - - for (i = 0; i < 0x80; ++i) - dmapSrc[i]=i; - inBuf=(char *) dmapSrc; - inBytesLeft=0x80 * 2; - outBuf=(char *) dmap_rec[idx].dmapU2S; - outBytesLeft=0x80; - do { - if ((len = iconv(cd, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft)) != (size_t) 0) { -#ifdef DEBUG - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed to initialize with iconv(), errno = %d in %s at %d\n", - to, from, idx, errno, __FILE__,__LINE__); -#endif - iconv_close(cd); - return -1; - } - } while (inBytesLeft > 0); - - myconv_rec[idx].srcSubS = 0x1A; - myconv_rec[idx].srcSubD = 0xFFFD; - myconv_rec[idx].subS = dmap_rec[idx].dmapU2S[0x1A]; - - outBuf=(char *) &(myconv_rec[idx].subD); - dmapSrc[0]=0xFFFD; - inBuf=(char *) dmapSrc; - inBytesLeft=2; - outBytesLeft=2; - if ((len = iconv(cd, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft)) != (size_t) 0) { -#ifdef DEBUG - if (myconvDebug) { - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed to initialize with iconv(), rc=%d, errno=%d in %s at %d\n", - to, from, idx, len, errno, __FILE__,__LINE__); - MyPrintf(STDERR_WO_TIME, "iconv(0x1A,1,%p,1) returns outBuf=%p, outBytesLeft=%d\n", - dmapSrc, outBuf, outBytesLeft); - } -#endif - if (outBytesLeft == 0) { - /* UCS-2_IBM-eucKR returns error. - myconv(iconv) rc=1, error=0, InBytesLeft=0, OutBytesLeft=18 - myconv(iconvRev) rc=-1, error=116, InBytesLeft=2, OutBytesLeft=20 - iconv: 0xFFFD => 0xAFFE => 0x rc=1,-1 sub=0,0 - */ - ; - } else { - iconv_close(cd); - return -1; - } - } - - for (i = 0x80; i < 0xFFFF; ++i) { - uchar eucBuf[3]; - dmapSrc[0]=i; - inBuf=(char *) dmapSrc; - inBytesLeft=2; - outBuf=(char *) eucBuf; - outBytesLeft=sizeof(eucBuf); - errno=0; - if ((len = iconv(cd, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft)) != (size_t) 0) { - if (len == 1 && errno == 0 && inBytesLeft == 0 && outBytesLeft == 1) { /* substitution occurred. */ continue; - } - - if (errno == EILSEQ) { -#ifdef DEBUG - if (myconvDebug) { - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed to initialize with iconv(), errno = %d in %s at %d\n", - to, from, idx, errno, __FILE__,__LINE__); - MyPrintf(STDERR_WO_TIME, "inBytesLeft=%d, outBytesLeft=%d\n", inBytesLeft, outBytesLeft); - if (inBuf - (char *) dmapSrc > 1 && inBuf - (char *) dmapSrc <= sizeof(dmapSrc) - 2) - MyPrintf(STDERR_WO_TIME, "inBuf[-2..2]=%02X%02X%02X%02X%02X\n", inBuf[-2],inBuf[-1],inBuf[0],inBuf[1],inBuf[2]); - else - MyPrintf(STDERR_WO_TIME, "inBuf[0..2]=%02X%02X%02X\n", inBuf[0],inBuf[1],inBuf[2]); - if (outBuf - (char *) dmap_rec[idx].dmapU2M2 > 1) - MyPrintf(STDERR_WO_TIME, "outBuf[-2..2]=%02X%02X%02X%02X%02X\n", outBuf[-2],outBuf[-1],outBuf[0],outBuf[1],outBuf[2]); - else - MyPrintf(STDERR_WO_TIME, "outBuf[0..2]=%02X%02X%02X\n", outBuf[0],outBuf[1],outBuf[2]); - } -#endif - inBuf+=2; - inBytesLeft-=2; - memcpy(outBuf, (char *) &(myconv_rec[idx].subD), 2); - outBuf+=2; - outBytesLeft-=2; - } else { -#ifdef DEBUG - if (myconvDebug) { - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed to initialize with iconv(), rc = %d, errno = %d in %s at %d\n", - to, from, idx, len, errno, __FILE__,__LINE__); - MyPrintf(STDERR_WITH_TIME, - "%04X: src=%04X%04X, inBuf=0x%02X%02X, inBytesLeft=%d, outBuf[-2..0]=%02X%02X%02X, outBytesLeft=%d\n", - i, dmapSrc[0], dmapSrc[1], inBuf[0], inBuf[1], - inBytesLeft, outBuf[-2], outBuf[-1], outBuf[0], outBytesLeft); - MyPrintf(STDERR_WITH_TIME, - "&dmapSrc=%p, inBuf=%p, dmapU2M2 + %d = %p, outBuf=%p\n", - dmapSrc, inBuf, (i - 0x80) * 2, dmap_rec[idx].dmapU2M2 + (i - 0x80) * 2, outBuf); - } -#endif - iconv_close(cd); - return -1; - } - } - if (sizeof(eucBuf) - outBytesLeft == 1) { - if (i < 0x100) { - (dmap_rec[idx].dmapU2S)[i]=eucBuf[0]; - } else { - dmap_rec[idx].dmapU2M2[(i - 0x80) * 2] = eucBuf[0]; - dmap_rec[idx].dmapU2M2[(i - 0x80) * 2 + 1] = 0x00; - } - } else if (sizeof(eucBuf) - outBytesLeft == 2) { /* 2 bytes */ - dmap_rec[idx].dmapU2M2[(i - 0x80) * 2] = eucBuf[0]; - dmap_rec[idx].dmapU2M2[(i - 0x80) * 2 + 1] = eucBuf[1]; - } else if (sizeof(eucBuf) - outBytesLeft == 3) { /* 3 byte SS2/SS3 */ - dmap_rec[idx].dmapU2M3[(i - 0x80) * 3] = eucBuf[0]; - dmap_rec[idx].dmapU2M3[(i - 0x80) * 3 + 1] = eucBuf[1]; - dmap_rec[idx].dmapU2M3[(i - 0x80) * 3 + 2] = eucBuf[2]; - } else { -#ifdef DEBUG - if (myconvDebug) { - MyPrintf(STDERR_WITH_TIME, - "dmap_open(%s,%s,%d) failed to initialize with iconv(), rc=%d, errno=%d in %s at %d\n", - to, from, idx, len, errno, __FILE__,__LINE__); - MyPrintf(STDERR_WITH_TIME, - "%04X: src=%04X%04X, inBuf=0x%02X%02X, inBytesLeft=%d, outBuf=%02X%02X%02X, outBytesLeft=%d\n", - i, dmapSrc[0], dmapSrc[1], inBuf[0], inBuf[1], - inBytesLeft, outBuf[-2], outBuf[-1], outBuf[0], outBytesLeft); - MyPrintf(STDERR_WITH_TIME, - "&dmapSrc=%p, inBuf=%p, %p, outBuf=%p\n", - dmapSrc, inBuf, dmap_rec[idx].dmapU2M3 + (i - 0x80) * 2, outBuf); - } -#endif - return -1; - } - - } - iconv_close(cd); - } - - } else if (myconvIsUTF16(from) && myconvIsUTF8(to)) { - dmap_rec[idx].codingSchema = DMAP_T28; - - } else if (myconvIsUCS2(from) && myconvIsUTF8(to)) { - dmap_rec[idx].codingSchema = DMAP_U28; - - } else if (myconvIsUTF8(from) && myconvIsUnicode2(to)) { - dmap_rec[idx].codingSchema = DMAP_82U; - - } else if (myconvIsUnicode2(from) && myconvIsUnicode2(to)) { - dmap_rec[idx].codingSchema = DMAP_U2U; - - } else { - - return -1; - } - myconv_rec[idx].cnv_dmap=&(dmap_rec[idx]); - return 0; -} - - - -static int bins_open(const char * to, - const char * from, - const int32_t idx) -{ - return -1; -} - - - -static int32_t dmap_close(const int32_t idx) -{ - if (dmap_rec[idx].codingSchema == DMAP_S2S) { - if (dmap_rec[idx].dmapS2S != NULL) { - dmap_rec[idx].dmapS2S=NULL; - } - } else if (dmap_rec[idx].codingSchema = DMAP_E2U) { - if (dmap_rec[idx].dmapE02U != NULL) { - dmap_rec[idx].dmapE02U=NULL; - } - if (dmap_rec[idx].dmapE12U != NULL) { - dmap_rec[idx].dmapE12U=NULL; - } - if (dmap_rec[idx].dmapE22U != NULL) { - dmap_rec[idx].dmapE22U=NULL; - } - if (dmap_rec[idx].dmapE32U != NULL) { - dmap_rec[idx].dmapE32U=NULL; - } - } - - return 0; -} - - -static int32_t bins_close(const int32_t idx) -{ - return 0; -} - - -myconv_t myconv_open(const char * toCode, - const char * fromCode, - int32_t converter) -{ - int32 i; - for (i = 0; i < MAX_CONVERTER; ++i) { - if (myconv_rec[i].converterType == 0) - break; - } - if (i >= MAX_CONVERTER) - return ((myconv_t) -1); - - myconv_rec[i].converterType = converter; - myconv_rec[i].index=i; - myconv_rec[i].fromCcsid=cstoccsid(fromCode); - if (myconv_rec[i].fromCcsid == 0 && memcmp(fromCode, "big5",5) == 0) - myconv_rec[i].fromCcsid=950; - myconv_rec[i].toCcsid=cstoccsid(toCode); - if (myconv_rec[i].toCcsid == 0 && memcmp(toCode, "big5",5) == 0) - myconv_rec[i].toCcsid=950; - strncpy(myconv_rec[i].from, fromCode, sizeof(myconv_rec[i].from)-1); - strncpy(myconv_rec[i].to, toCode, sizeof(myconv_rec[i].to)-1); - - if (converter == CONVERTER_ICONV) { - if ((myconv_rec[i].cnv_iconv=iconv_open(toCode, fromCode)) == (iconv_t) -1) { - return ((myconv_t) -1); - } - myconv_rec[i].allocatedSize = -1; - myconv_rec[i].srcSubS=myconvGetSubS(fromCode); - myconv_rec[i].srcSubD=myconvGetSubD(fromCode); - myconv_rec[i].subS=myconvGetSubS(toCode); - myconv_rec[i].subD=myconvGetSubD(toCode); - return &(myconv_rec[i]); - } else if (converter == CONVERTER_DMAP && - dmap_open(toCode, fromCode, i) != -1) { - return &(myconv_rec[i]); - } - return ((myconv_t) -1); -} - - - -int32_t myconv_close(myconv_t cd) -{ - int32_t ret=0; - - if (cd->converterType == CONVERTER_ICONV) { - ret=iconv_close(cd->cnv_iconv); - } else if (cd->converterType == CONVERTER_DMAP) { - ret=dmap_close(cd->index); - } - memset(&(myconv_rec[cd->index]), 0x00, sizeof(myconv_rec[cd->index])); - return ret; -} - - - - -/* reference: http://www-306.ibm.com/software/globalization/other/es.jsp */ -/* systemCL would be expensive, and myconvIsXXXXX is called frequently. - need to cache entries */ -#define MAX_CCSID 256 -static int ccsidList [MAX_CCSID]; -static int esList [MAX_CCSID]; -int32 getEncodingScheme(const uint16 inCcsid, int32& outEncodingScheme); -EXTERN int myconvGetES(CCSID ccsid) -{ - /* call QtqValidateCCSID in ILE to get encoding schema */ - /* return QtqValidateCCSID(ccsid); */ - int i; - for (i = 0; i < MAX_CCSID; ++i) { - if (ccsidList[i] == ccsid) - return esList[i]; - if (ccsidList[i] == 0x00) - break; - } - - if (i >= MAX_CCSID) { - i=MAX_CCSID-1; - } - - { - ccsidList[i]=ccsid; - getEncodingScheme(ccsid, esList[i]); -#ifdef DEBUG_PASE - if (myconvDebug) { - fprintf(stderr, "CCSID=%d, ES=0x%04X\n", ccsid, esList[i]); - } -#endif - return esList[i]; - } - return 0; -} - - -EXTERN int myconvIsEBCDIC(const char * pName) -{ - int es = myconvGetES(cstoccsid(pName)); - if (es == 0x1100 || - es == 0x1200 || - es == 0x6100 || - es == 0x6200 || - es == 0x1301 ) { - return TRUE; - } - return FALSE; -} - - -EXTERN int myconvIsISO(const char * pName) -{ - int es = myconvGetES(cstoccsid(pName)); - if (es == 0x4100 || - es == 0x4105 || - es == 0x4155 || - es == 0x5100 || - es == 0x5150 || - es == 0x5200 || - es == 0x5404 || - es == 0x5409 || - es == 0x540A || - es == 0x5700) { - return TRUE; - } - return FALSE; -} - - -EXTERN int myconvIsASCII(const char * pName) -{ - int es = myconvGetES(cstoccsid(pName)); - if (es == 0x2100 || - es == 0x3100 || - es == 0x8100 || - es == 0x2200 || - es == 0x3200 || - es == 0x9200 || - es == 0x2300 || - es == 0x2305 || - es == 0x3300 || - es == 0x2900 || - es == 0x2A00) { - return TRUE; - } else if (memcmp(pName, "big5", 5) == 0) { - return TRUE; - } - return FALSE; -} - - - -EXTERN int myconvIsUCS2(const char * pName) -{ - if (cstoccsid(pName) == 13488) { - return TRUE; - } - return FALSE; -} - - -EXTERN int myconvIsUTF16(const char * pName) -{ - if (cstoccsid(pName) == 1200) { - return TRUE; - } - return FALSE; -} - - -EXTERN int myconvIsUnicode2(const char * pName) -{ - int es = myconvGetES(cstoccsid(pName)); - if (es == 0x7200 || - es == 0x720B || - es == 0x720F) { - return TRUE; - } - return FALSE; -} - - -EXTERN int myconvIsUTF8(const char * pName) -{ - int es = myconvGetES(cstoccsid(pName)); - if (es == 0x7807) { - return TRUE; - } - return FALSE; -} - - -EXTERN int myconvIsUnicode(const char * pName) -{ - int es = myconvGetES(cstoccsid(pName)); - if (es == 0x7200 || - es == 0x720B || - es == 0x720F || - es == 0x7807) { - return TRUE; - } - return FALSE; -} - - -EXTERN int myconvIsEUC(const char * pName) -{ - int es = myconvGetES(cstoccsid(pName)); - if (es == 0x4403) { - return TRUE; - } - return FALSE; -} - - -EXTERN int myconvIsDBCS(const char * pName) -{ - int es = myconvGetES(cstoccsid(pName)); - if (es == 0x1200 || - es == 0x2200 || - es == 0x2300 || - es == 0x2305 || - es == 0x2A00 || - es == 0x3200 || - es == 0x3300 || - es == 0x5200 || - es == 0x6200 || - es == 0x9200) { - return TRUE; - } else if (memcmp(pName, "big5", 5) == 0) { - return TRUE; - } - return FALSE; -} - - -EXTERN int myconvIsSBCS(const char * pName) -{ - int es = myconvGetES(cstoccsid(pName)); - if (es == 0x1100 || - es == 0x2100 || - es == 0x3100 || - es == 0x4100 || - es == 0x4105 || - es == 0x5100 || - es == 0x5150 || - es == 0x6100 || - es == 0x8100) { - return TRUE; - } - return FALSE; -} - - - -EXTERN char myconvGetSubS(const char * code) -{ - if (myconvIsEBCDIC(code)) { - return 0x3F; - } else if (myconvIsASCII(code)) { - return 0x1A; - } else if (myconvIsISO(code)) { - return 0x1A; - } else if (myconvIsEUC(code)) { - return 0x1A; - } else if (myconvIsUCS2(code)) { - return 0x00; - } else if (myconvIsUTF8(code)) { - return 0x1A; - } - return 0x00; -} - - -EXTERN UniChar myconvGetSubD(const char * code) -{ - if (myconvIsEBCDIC(code)) { - return 0xFDFD; - } else if (myconvIsASCII(code)) { - return 0xFCFC; - } else if (myconvIsISO(code)) { - return 0x00; - } else if (myconvIsEUC(code)) { - return 0x00; - } else if (myconvIsUCS2(code)) { - return 0xFFFD; - } else if (myconvIsUTF8(code)) { - return 0x00; - } - return 0x00; -} - diff --git a/storage/ibmdb2i/db2i_myconv.h b/storage/ibmdb2i/db2i_myconv.h deleted file mode 100644 index 98032748148..00000000000 --- a/storage/ibmdb2i/db2i_myconv.h +++ /dev/null @@ -1,3201 +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 A direct map optimization of iconv and related functions - This was show to significantly reduce character conversion cost - for short strings when compared to calling iconv system code. -*/ - -#ifndef DB2I_MYCONV_H -#define DB2I_MYCONV_H - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -#ifdef __cplusplus -#define INTERN inline -#define EXTERN extern "C" -#else -#define INTERN static -#define EXTERN extern -#endif - - -/* ANSI integer data types */ -#if defined(__OS400_TGTVRM__) -/* for DTAMDL(*P128), datamodel(P128): int/long/pointer=4/4/16 */ -/* LLP64:4/4/8 is used for teraspace ?? */ -typedef short int16_t; -typedef unsigned short uint16_t; -typedef int int32_t; -typedef unsigned int uint32_t; -typedef long long int64_t; -typedef unsigned long long uint64_t; -#elif defined(PASE) -/* PASE uses IPL32: int/long/pointer=4/4/4 + long long */ -#elif defined(__64BIT__) -/* AIX 64 bit uses LP64: int/long/pointer=4/8/8 */ -#endif - -#define CONVERTER_ICONV 1 -#define CONVERTER_DMAP 2 - -#define DMAP_S2S 10 -#define DMAP_S2U 20 -#define DMAP_D2U 30 -#define DMAP_E2U 40 -#define DMAP_U2S 120 -#define DMAP_T2S 125 -#define DMAP_U2D 130 -#define DMAP_T2D 135 -#define DMAP_U2E 140 -#define DMAP_T2E 145 -#define DMAP_S28 220 -#define DMAP_D28 230 -#define DMAP_E28 240 -#define DMAP_82S 310 -#define DMAP_82D 320 -#define DMAP_82E 330 -#define DMAP_U28 410 -#define DMAP_82U 420 -#define DMAP_T28 425 -#define DMAP_U2U 510 - - -typedef struct __dmap_rec *dmap_t; - -struct __dmap_rec -{ - uint32_t codingSchema; - unsigned char * dmapS2S; /* SBCS -> SBCS */ - /* The following conversion needs be followed by conversion from UCS-2/UTF-16 to UTF-8 */ - UniChar * dmapD12U; /* DBCS(non-EUC) -> UCS-2/UTF-16 */ - UniChar * dmapD22U; /* DBCS(non-EUC) -> UCS-2/UTF-16 */ - UniChar * dmapE02U; /* EUC/SS0 -> UCS-2/UTF-16 */ - UniChar * dmapE12U; /* EUC/SS1 -> UCS-2/UTF-16 */ - UniChar * dmapE22U; /* EUC/0x8E + SS2 -> UCS-2/UTF-16 */ - UniChar * dmapE32U; /* EUC/0x8F + SS3 -> UCS-2/UTF-16 */ - uchar * dmapU2D; /* UCS-2 -> DBCS */ - uchar * dmapU2S; /* UCS-2 -> EUC SS0 */ - uchar * dmapU2M2; /* UCS-2 -> EUC SS1 */ - uchar * dmapU2M3; /* UCS-2 -> EUC SS2/SS3 */ - /* All of these pointers/tables are not used at the same time. - * You may be able save some space if you consolidate them. - */ - uchar * dmapS28; /* SBCS -> UTF-8 */ - uchar * dmapD28; /* DBCS -> UTF-8 */ -}; - -typedef struct __myconv_rec *myconv_t; -struct __myconv_rec -{ - uint32_t converterType; - uint32_t index; /* for close */ - union { - iconv_t cnv_iconv; - dmap_t cnv_dmap; - }; - int32_t allocatedSize; - int32_t fromCcsid; - int32_t toCcsid; - UniChar subD; /* DBCS substitution char */ - char subS; /* SBCS substitution char */ - UniChar srcSubD; /* DBCS substitution char of src codepage */ - char srcSubS; /* SBCS substitution char of src codepage */ - char from [41+1]; /* codepage name is up to 41 bytes */ - char to [41+1]; /* codepage name is up to 41 bytes */ -#ifdef __64BIT__ - char reserved[10]; /* align 128 */ -#else - char reserved[14]; /* align 128 */ -#endif -}; - - -EXTERN int32_t myconvDebug; - - - -EXTERN int myconvGetES(CCSID); -EXTERN int myconvIsEBCDIC(const char *); -EXTERN int myconvIsASCII(const char *); -EXTERN int myconvIsUnicode(const char *); /* UTF-8, UTF-16, or UCS-2 */ -EXTERN int myconvIsUnicode2(const char *); /* 2 byte Unicode */ -EXTERN int myconvIsUCS2(const char *); -EXTERN int myconvIsUTF16(const char *); -EXTERN int myconvIsUTF8(const char *); -EXTERN int myconvIsEUC(const char *); -EXTERN int myconvIsISO(const char *); -EXTERN int myconvIsSBCS(const char *); -EXTERN int myconvIsDBCS(const char *); -EXTERN char myconvGetSubS(const char *); -EXTERN UniChar myconvGetSubD(const char *); - - -EXTERN myconv_t myconv_open(const char*, const char*, int32_t); -EXTERN int myconv_close(myconv_t); - -INTERN size_t myconv_iconv(myconv_t cd , - char** inBuf, - size_t* inBytesLeft, - char** outBuf, - size_t* outBytesLeft, - size_t* numSub) -{ - return iconv(cd->cnv_iconv, inBuf, inBytesLeft, outBuf, outBytesLeft); -} - -INTERN size_t myconv_dmap(myconv_t cd, - char** inBuf, - size_t* inBytesLeft, - char** outBuf, - size_t* outBytesLeft, - size_t* numSub) -{ - if (cd->cnv_dmap->codingSchema == DMAP_S2S) { - register unsigned char * dmapS2S=cd->cnv_dmap->dmapS2S; - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register char subS=cd->subS; - register size_t numS=0; - while (0 < inLen) { - if (pLastOutBuf < pOut) - break; - if (*pIn == 0x00) { - *pOut=0x00; - } else { - *pOut=dmapS2S[*pIn]; - if (*pOut == 0x00) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(*inBytesLeft-inLen); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - if (*pOut == subS) { - if ((*pOut=dmapS2S[*pIn]) == subS) { - if (*pIn != cd->srcSubS) - ++numS; - } - } - } - ++pIn; - --inLen; - ++pOut; - } - *outBytesLeft-=(*inBytesLeft-inLen); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return 0; - - } else if (cd->cnv_dmap->codingSchema == DMAP_E2U) { - /* use uchar * instead of UniChar to avoid memcpy */ - register uchar * dmapE02U=(uchar *) (cd->cnv_dmap->dmapE02U); - register uchar * dmapE12U=(uchar *) (cd->cnv_dmap->dmapE12U); - register uchar * dmapE22U=(uchar *) (cd->cnv_dmap->dmapE22U); - register uchar * dmapE32U=(uchar *) (cd->cnv_dmap->dmapE32U); - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register int offset; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register size_t numS=0; - while (0 < inLen) { - if (pLastOutBuf < pOut) - break; - if (*pIn == 0x00) { - *pOut=0x00; - ++pOut; - *pOut=0x00; - ++pOut; - ++pIn; - --inLen; - } else { - if (*pIn == 0x8E) { /* SS2 */ - if (inLen < 2) { - if (cd->fromCcsid == 33722 || /* IBM-eucJP */ - cd->fromCcsid == 964) /* IBM-eucTW */ - errno=EINVAL; /* 22 */ - else - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - return -1; - } - ++pIn; - if (*pIn < 0xA0) { - if (cd->fromCcsid == 964) /* IBM-eucTW */ - errno=EINVAL; /* 22 */ - else - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - return -1; - } - offset=(*pIn - 0xA0); - offset<<=1; - if (dmapE22U[offset] == 0x00 && - dmapE22U[offset+1] == 0x00) { /* 2 bytes */ - if (inLen < 3) { - if (cd->fromCcsid == 964) /* IBM-eucTW */ - errno=EINVAL; /* 22 */ - else - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - return -1; - } - offset=(*pIn - 0xA0) * 0x60 + 0x60; - ++pIn; - if (*pIn < 0xA0) { - if (cd->fromCcsid == 964) /* IBM-eucTW */ - errno=EINVAL; /* 22 */ - else - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-2; - return -1; - } - offset+=(*pIn - 0xA0); - offset<<=1; - if (dmapE22U[offset] == 0x00 && - dmapE22U[offset+1] == 0x00) { - if (cd->fromCcsid == 964) /* IBM-eucTW */ - errno=EINVAL; /* 22 */ - else - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-2; - return -1; - } - *pOut=dmapE22U[offset]; - ++pOut; - *pOut=dmapE22U[offset+1]; - ++pOut; - if (dmapE22U[offset] == 0xFF && - dmapE22U[offset+1] == 0xFD) { - if (pIn[-2] * 0x100 + pIn[-1] != cd->srcSubD) - ++numS; - } - ++pIn; - inLen-=3; - } else { /* 1 bytes */ - *pOut=dmapE22U[offset]; - ++pOut; - *pOut=dmapE22U[offset+1]; - ++pOut; - ++pIn; - inLen-=2; - } - } else if (*pIn == 0x8F) { /* SS3 */ - if (inLen < 2) { - if (cd->fromCcsid == 33722) /* IBM-eucJP */ - errno=EINVAL; /* 22 */ - else - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - return -1; - } - ++pIn; - if (*pIn < 0xA0) { - if (cd->fromCcsid == 970 || /* IBM-eucKR */ - cd->fromCcsid == 964 || /* IBM-eucTW */ - cd->fromCcsid == 1383 || /* IBM-eucCN */ - (cd->fromCcsid == 33722 && 3 <= inLen)) /* IBM-eucJP */ - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - return -1; - } - offset=(*pIn - 0xA0); - offset<<=1; - if (dmapE32U[offset] == 0x00 && - dmapE32U[offset+1] == 0x00) { /* 0x8F + 2 bytes */ - if (inLen < 3) { - if (cd->fromCcsid == 33722) - errno=EINVAL; /* 22 */ - else - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - return -1; - } - offset=(*pIn - 0xA0) * 0x60 + 0x60; - ++pIn; - if (*pIn < 0xA0) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-2; - return -1; - } - offset+=(*pIn - 0xA0); - offset<<=1; - if (dmapE32U[offset] == 0x00 && - dmapE32U[offset+1] == 0x00) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-2; - return -1; - } - *pOut=dmapE32U[offset]; - ++pOut; - *pOut=dmapE32U[offset+1]; - ++pOut; - if (dmapE32U[offset] == 0xFF && - dmapE32U[offset+1] == 0xFD) { - if (pIn[-2] * 0x100 + pIn[-1] != cd->srcSubD) - ++numS; - } - ++pIn; - inLen-=3; - } else { /* 0x8F + 1 bytes */ - *pOut=dmapE32U[offset]; - ++pOut; - *pOut=dmapE32U[offset+1]; - ++pOut; - ++pIn; - inLen-=2; - } - - } else { - offset=*pIn; - offset<<=1; - if (dmapE02U[offset] == 0x00 && - dmapE02U[offset+1] == 0x00) { /* SS1 */ - if (inLen < 2) { - if ((cd->fromCcsid == 33722 && (*pIn == 0xA0 || (0xA9 <= *pIn && *pIn <= 0xAF) || *pIn == 0xFF)) || - (cd->fromCcsid == 970 && (*pIn == 0xA0 || *pIn == 0xAD || *pIn == 0xAE || *pIn == 0xAF || *pIn == 0xFF)) || - (cd->fromCcsid == 964 && (*pIn == 0xA0 || (0xAA <= *pIn && *pIn <= 0xC1) || *pIn == 0xC3 || *pIn == 0xFE || *pIn == 0xFF)) || - (cd->fromCcsid == 1383 && (*pIn == 0xA0 || *pIn == 0xFF))) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - return -1; - } - if (*pIn < 0xA0) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - return -1; - } - offset=(*pIn - 0xA0) * 0x60; - ++pIn; - if (*pIn < 0xA0) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - return -1; - } - offset+=(*pIn - 0xA0); - offset<<=1; - if (dmapE12U[offset] == 0x00 && - dmapE12U[offset+1] == 0x00) { /* undefined mapping */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - return -1; - } - *pOut=dmapE12U[offset]; - ++pOut; - *pOut=dmapE12U[offset+1]; - ++pOut; - if (dmapE12U[offset] == 0xFF && - dmapE12U[offset+1] == 0xFD) { - if (pIn[-1] * 0x100 + pIn[0] != cd->srcSubD) - ++numS; - } - ++pIn; - inLen-=2; - } else { - *pOut=dmapE02U[offset]; - ++pOut; - *pOut=dmapE02U[offset+1]; - ++pOut; - if (dmapE02U[offset] == 0x00 && - dmapE02U[offset+1] == 0x1A) { - if (*pIn != cd->srcSubS) - ++numS; - } - ++pIn; - --inLen; - } - } - } - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return 0; - - - } else if (cd->cnv_dmap->codingSchema == DMAP_E28) { - /* use uchar * instead of UniChar to avoid memcpy */ - register uchar * dmapE02U=(uchar *) (cd->cnv_dmap->dmapE02U); - register uchar * dmapE12U=(uchar *) (cd->cnv_dmap->dmapE12U); - register uchar * dmapE22U=(uchar *) (cd->cnv_dmap->dmapE22U); - register uchar * dmapE32U=(uchar *) (cd->cnv_dmap->dmapE32U); - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register int offset; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register size_t numS=0; - register UniChar in; /* copy part of U28 */ - register UniChar ucs2; - while (0 < inLen) { - if (pLastOutBuf < pOut) - break; - if (*pIn == 0x00) { - *pOut=0x00; - ++pOut; - ++pIn; - --inLen; - } else { - if (*pIn == 0x8E) { /* SS2 */ - if (inLen < 2) { - if (cd->fromCcsid == 33722 || /* IBM-eucJP */ - cd->fromCcsid == 964) /* IBM-eucTW */ - errno=EINVAL; /* 22 */ - else - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - return -1; - } - ++pIn; - if (*pIn < 0xA0) { - if (cd->fromCcsid == 964) /* IBM-eucTW */ - errno=EINVAL; /* 22 */ - else - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - return -1; - } - offset=(*pIn - 0xA0); - offset<<=1; - if (dmapE22U[offset] == 0x00 && - dmapE22U[offset+1] == 0x00) { /* 2 bytes */ - if (inLen < 3) { - if (cd->fromCcsid == 964) /* IBM-eucTW */ - errno=EINVAL; /* 22 */ - else - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - return -1; - } - offset=(*pIn - 0xA0) * 0x60 + 0x60; - ++pIn; - if (*pIn < 0xA0) { - if (cd->fromCcsid == 964) /* IBM-eucTW */ - errno=EINVAL; /* 22 */ - else - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-2; - return -1; - } - offset+=(*pIn - 0xA0); - offset<<=1; - if (dmapE22U[offset] == 0x00 && - dmapE22U[offset+1] == 0x00) { - if (cd->fromCcsid == 964) /* IBM-eucTW */ - errno=EINVAL; /* 22 */ - else - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-2; - return -1; - } - in=dmapE22U[offset]; - in<<=8; - in+=dmapE22U[offset+1]; - if (dmapE22U[offset] == 0xFF && - dmapE22U[offset+1] == 0xFD) { - if (pIn[-2] * 0x100 + pIn[-1] != cd->srcSubD) - ++numS; - } - ++pIn; - inLen-=3; - } else { /* 1 bytes */ - in=dmapE22U[offset]; - in<<=8; - in+=dmapE22U[offset+1]; - ++pIn; - inLen-=2; - } - } else if (*pIn == 0x8F) { /* SS3 */ - if (inLen < 2) { - if (cd->fromCcsid == 33722) /* IBM-eucJP */ - errno=EINVAL; /* 22 */ - else - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - return -1; - } - ++pIn; - if (*pIn < 0xA0) { - if (cd->fromCcsid == 970 || /* IBM-eucKR */ - cd->fromCcsid == 964 || /* IBM-eucTW */ - cd->fromCcsid == 1383 || /* IBM-eucCN */ - (cd->fromCcsid == 33722 && 3 <= inLen)) /* IBM-eucJP */ - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - return -1; - } - offset=(*pIn - 0xA0); - offset<<=1; - if (dmapE32U[offset] == 0x00 && - dmapE32U[offset+1] == 0x00) { /* 0x8F + 2 bytes */ - if (inLen < 3) { - if (cd->fromCcsid == 33722) - errno=EINVAL; /* 22 */ - else - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - return -1; - } - offset=(*pIn - 0xA0) * 0x60 + 0x60; - ++pIn; - if (*pIn < 0xA0) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-2; - return -1; - } - offset+=(*pIn - 0xA0); - offset<<=1; - if (dmapE32U[offset] == 0x00 && - dmapE32U[offset+1] == 0x00) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-2; - return -1; - } - in=dmapE32U[offset]; - in<<=8; - in+=dmapE32U[offset+1]; - if (dmapE32U[offset] == 0xFF && - dmapE32U[offset+1] == 0xFD) { - if (pIn[-2] * 0x100 + pIn[-1] != cd->srcSubD) - ++numS; - } - ++pIn; - inLen-=3; - } else { /* 0x8F + 1 bytes */ - in=dmapE32U[offset]; - in<<=8; - in+=dmapE32U[offset+1]; - ++pIn; - inLen-=2; - } - - } else { - offset=*pIn; - offset<<=1; - if (dmapE02U[offset] == 0x00 && - dmapE02U[offset+1] == 0x00) { /* SS1 */ - if (inLen < 2) { - if ((cd->fromCcsid == 33722 && (*pIn == 0xA0 || (0xA9 <= *pIn && *pIn <= 0xAF) || *pIn == 0xFF)) || - (cd->fromCcsid == 970 && (*pIn == 0xA0 || *pIn == 0xAD || *pIn == 0xAE || *pIn == 0xAF || *pIn == 0xFF)) || - (cd->fromCcsid == 964 && (*pIn == 0xA0 || (0xAA <= *pIn && *pIn <= 0xC1) || *pIn == 0xC3 || *pIn == 0xFE || *pIn == 0xFF)) || - (cd->fromCcsid == 1383 && (*pIn == 0xA0 || *pIn == 0xFF))) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - return -1; - } - if (*pIn < 0xA0) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - return -1; - } - offset=(*pIn - 0xA0) * 0x60; - ++pIn; - if (*pIn < 0xA0) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - return -1; - } - offset+=(*pIn - 0xA0); - offset<<=1; - if (dmapE12U[offset] == 0x00 && - dmapE12U[offset+1] == 0x00) { /* undefined mapping */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - return -1; - } - in=dmapE12U[offset]; - in<<=8; - in+=dmapE12U[offset+1]; - if (dmapE12U[offset] == 0xFF && - dmapE12U[offset+1] == 0xFD) { - if (pIn[-1] * 0x100 + pIn[0] != cd->srcSubD) - ++numS; - } - ++pIn; - inLen-=2; - } else { - in=dmapE02U[offset]; - in<<=8; - in+=dmapE02U[offset+1]; - if (dmapE02U[offset] == 0x00 && - dmapE02U[offset+1] == 0x1A) { - if (*pIn != cd->srcSubS) - ++numS; - } - ++pIn; - --inLen; - } - } - ucs2=in; - if ((in & 0xFF80) == 0x0000) { /* U28: in & 0b1111111110000000 == 0x0000 */ - *pOut=in; - ++pOut; - } else if ((in & 0xF800) == 0x0000) { /* in & 0b1111100000000000 == 0x0000 */ - register uchar byte; - in>>=6; - in&=0x001F; /* 0b0000000000011111 */ - in|=0x00C0; /* 0b0000000011000000 */ - *pOut=in; - ++pOut; - byte=ucs2; /* dmapD12U[offset+1]; */ - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - } else if ((in & 0xFC00) == 0xD800) { - *pOut=0xEF; - ++pOut; - *pOut=0xBF; - ++pOut; - *pOut=0xBD; - ++pOut; - } else { - register uchar byte; - register uchar work; - byte=(ucs2>>8); /* dmapD12U[offset]; */ - byte>>=4; - byte|=0xE0; /* 0b11100000; */ - *pOut=byte; - ++pOut; - - byte=(ucs2>>8); /* dmapD12U[offset]; */ - byte<<=2; - work=ucs2; /* dmapD12U[offset+1]; */ - work>>=6; - byte|=work; - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - - byte=ucs2; /* dmapD12U[offset+1]; */ - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - } - /* end of U28 */ - } - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return 0; - - } else if (cd->cnv_dmap->codingSchema == DMAP_U2E) { - register uchar * dmapU2S=cd->cnv_dmap->dmapU2S; - register uchar * dmapU2M2=cd->cnv_dmap->dmapU2M2 - 0x80 * 2; - register uchar * dmapU2M3=cd->cnv_dmap->dmapU2M3 - 0x80 * 3; - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register char subS=cd->subS; - register char * pSubD=(char *) &(cd->subD); - register size_t numS=0; - register size_t rc=0; - while (0 < inLen) { - register uint32_t in; - if (inLen == 1) { - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - return -1; - } - if (pLastOutBuf < pOut) - break; - in=pIn[0]; - in<<=8; - in+=pIn[1]; - if (in == 0x0000) { - *pOut=0x00; - ++pOut; - } else if (in < 0x100 && dmapU2S[in] != 0x0000) { - if ((*pOut=dmapU2S[in]) == subS) { - if (in != cd->srcSubS) - ++numS; - } - ++pOut; - } else { - in<<=1; - if (dmapU2M2[in] == 0x00) { /* not found in dmapU2M2 */ - in*=1.5; - if (dmapU2M3[in] == 0x00) { /* not found in dmapU2M3*/ - *pOut=pSubD[0]; - ++pOut; - *pOut=pSubD[1]; - ++pOut; - ++numS; - ++rc; - } else { - *pOut=dmapU2M3[in]; - ++pOut; - *pOut=dmapU2M3[1+in]; - ++pOut; - *pOut=dmapU2M3[2+in]; - ++pOut; - } - } else { - *pOut=dmapU2M2[in]; - ++pOut; - if (dmapU2M2[1+in] == 0x00) { - if (*pOut == subS) { - in>>=1; - if (in != cd->srcSubS) - ++numS; - } - } else { - *pOut=dmapU2M2[1+in]; - ++pOut; - if (memcmp(pOut-2, pSubD, 2) == 0) { - in>>=1; - if (in != cd->srcSubD) { - ++numS; - ++rc; - } - } - } - } - } - pIn+=2; - inLen-=2; - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return rc; /* compatibility to iconv() */ - - } else if (cd->cnv_dmap->codingSchema == DMAP_T2E) { - register uchar * dmapU2S=cd->cnv_dmap->dmapU2S; - register uchar * dmapU2M2=cd->cnv_dmap->dmapU2M2 - 0x80 * 2; - register uchar * dmapU2M3=cd->cnv_dmap->dmapU2M3 - 0x80 * 3; - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register char subS=cd->subS; - register char * pSubD=(char *) &(cd->subD); - register size_t numS=0; - register size_t rc=0; - while (0 < inLen) { - register uint32_t in; - if (inLen == 1) { - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen-1; - *outBuf=pOut; - *inBuf=pIn; - ++numS; - *numSub+=numS; - return 0; - } - if (pLastOutBuf < pOut) - break; - in=pIn[0]; - in<<=8; - in+=pIn[1]; - if (in == 0x0000) { - *pOut=0x00; - ++pOut; - } else if (0xD800 <= in && in <= 0xDBFF) { /* first byte of surrogate */ - errno=EINVAL; /* 22 */ - *inBytesLeft=inLen-2; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn+2; - ++numS; - *numSub+=numS; - return -1; - - } else if (0xDC00 <= in && in <= 0xDFFF) { /* second byte of surrogate */ - errno=EINVAL; /* 22 */ - *inBytesLeft=inLen-1; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn; - ++numS; - *numSub+=numS; - return -1; - - } else if (in < 0x100 && dmapU2S[in] != 0x0000) { - if ((*pOut=dmapU2S[in]) == subS) { - if (in != cd->srcSubS) - ++numS; - } - ++pOut; - } else { - in<<=1; - if (dmapU2M2[in] == 0x00) { /* not found in dmapU2M2 */ - in*=1.5; - if (dmapU2M3[in] == 0x00) { /* not found in dmapU2M3*/ - *pOut=pSubD[0]; - ++pOut; - *pOut=pSubD[1]; - ++pOut; - ++numS; - ++rc; - } else { - *pOut=dmapU2M3[in]; - ++pOut; - *pOut=dmapU2M3[1+in]; - ++pOut; - *pOut=dmapU2M3[2+in]; - ++pOut; - } - } else { - *pOut=dmapU2M2[in]; - ++pOut; - if (dmapU2M2[1+in] == 0x00) { - if (*pOut == subS) { - in>>=1; - if (in != cd->srcSubS) - ++numS; - } - } else { - *pOut=dmapU2M2[1+in]; - ++pOut; - if (memcmp(pOut-2, pSubD, 2) == 0) { - in>>=1; - if (in != cd->srcSubD) { - ++numS; - ++rc; - } - } - } - } - } - pIn+=2; - inLen-=2; - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return 0; - - } else if (cd->cnv_dmap->codingSchema == DMAP_82E) { - register uchar * dmapU2S=cd->cnv_dmap->dmapU2S; - register uchar * dmapU2M2=cd->cnv_dmap->dmapU2M2 - 0x80 * 2; - register uchar * dmapU2M3=cd->cnv_dmap->dmapU2M3 - 0x80 * 3; - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register char subS=cd->subS; - register char * pSubD=(char *) &(cd->subD); - register size_t numS=0; - register size_t rc=0; - while (0 < inLen) { - register uint32_t in; - uint32_t in2; - if (pLastOutBuf < pOut) - break; - /* convert from UTF-8 to UCS-2 */ - if (*pIn == 0x00) { - in=0x0000; - ++pIn; - --inLen; - } else { /* 82U: */ - register uchar byte1=*pIn; - if ((byte1 & 0x80) == 0x00) { /* if (byte1 & 0b10000000 == 0b00000000) { */ - /* 1 bytes sequence: 0xxxxxxx => 00000000 0xxxxxxx*/ - in=byte1; - ++pIn; - --inLen; - } else if ((byte1 & 0xE0) == 0xC0) { /* (byte1 & 0b11100000 == 0b11000000) { */ - if (inLen < 2) { - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - if (byte1 == 0xC0 || byte1 == 0xC1) { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - /* 2 bytes sequence: - 110yyyyy 10xxxxxx => 00000yyy yyxxxxxx */ - register uchar byte2; - ++pIn; - byte2=*pIn; - if ((byte2 & 0xC0) == 0x80) { /* byte2 & 0b11000000 == 0b10000000) { */ - register uchar work=byte1; - work<<=6; - byte2&=0x3F; /* 0b00111111; */ - byte2|=work; - - byte1&=0x1F; /* 0b00011111; */ - byte1>>=2; - in=byte1; - in<<=8; - in+=byte2; - inLen-=2; - ++pIn; - } else { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - *numSub+=numS; - return -1; - } - } else if ((byte1 & 0xF0) == 0xE0) { /* byte1 & 0b11110000 == 0b11100000 */ - /* 3 bytes sequence: - 1110zzzz 10yyyyyy 10xxxxxx => zzzzyyyy yyxxxxxx */ - register uchar byte2; - register uchar byte3; - if (inLen < 3) { - if (inLen == 2 && (pIn[1] & 0xC0) != 0x80) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - ++pIn; - byte2=*pIn; - ++pIn; - byte3=*pIn; - if ((byte2 & 0xC0) != 0x80 || - (byte3 & 0xC0) != 0x80 || - (byte1 == 0xE0 && byte2 < 0xA0)) { /* invalid sequence, only 0xA0-0xBF allowed after 0xE0 */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-2; - *numSub+=numS; - return -1; - } - { - register uchar work=byte2; - work<<=6; - byte3&=0x3F; /* 0b00111111; */ - byte3|=work; - - byte2&=0x3F; /* 0b00111111; */ - byte2>>=2; - - byte1<<=4; - in=byte1 | byte2;; - in<<=8; - in+=byte3; - inLen-=3; - ++pIn; - } - } else if ((0xF0 <= byte1 && byte1 <= 0xF4)) { /* (bytes1 & 11111000) == 0x1110000 */ - /* 4 bytes sequence - 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx => 110110ww wwzzzzyy 110111yy yyxxxxxx - where uuuuu = wwww + 1 */ - register uchar byte2; - register uchar byte3; - register uchar byte4; - if (inLen < 4) { - if ((inLen >= 2 && (pIn[1] & 0xC0) != 0x80) || - (inLen >= 3 && (pIn[2] & 0xC0) != 0x80) || - (cd->toCcsid == 13488) ) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - ++pIn; - byte2=*pIn; - ++pIn; - byte3=*pIn; - ++pIn; - byte4=*pIn; - if ((byte2 & 0xC0) == 0x80 && /* byte2 & 0b11000000 == 0b10000000 */ - (byte3 & 0xC0) == 0x80 && /* byte3 & 0b11000000 == 0b10000000 */ - (byte4 & 0xC0) == 0x80) { /* byte4 & 0b11000000 == 0b10000000 */ - register uchar work=byte2; - if (byte1 == 0xF0 && byte2 < 0x90) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-3; - *numSub+=numS; - return -1; - /* iconv() returns 0 for 0xF4908080 and convert to 0x00 - } else if (byte1 == 0xF4 && byte2 > 0x8F) { - errno=EINVAL; - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-3; - *numSub+=numS; - return -1; - */ - } - - work&=0x30; /* 0b00110000; */ - work>>=4; - byte1&=0x07; /* 0b00000111; */ - byte1<<=2; - byte1+=work; /* uuuuu */ - --byte1; /* wwww */ - - work=byte1 & 0x0F; - work>>=2; - work+=0xD8; /* 0b11011011; */ - in=work; - in<<=8; - - byte1<<=6; - byte2<<=2; - byte2&=0x3C; /* 0b00111100; */ - work=byte3; - work>>=4; - work&=0x03; /* 0b00000011; */ - work|=byte1; - work|=byte2; - in+=work; - - work=byte3; - work>>=2; - work&=0x03; /* 0b00000011; */ - work|=0xDC; /* 0b110111xx; */ - in2=work; - in2<<=8; - - byte3<<=6; - byte4&=0x3F; /* 0b00111111; */ - byte4|=byte3; - in2+=byte4; - inLen-=4; - ++pIn; -#ifdef match_with_GBK - if ((0xD800 == in && in2 < 0xDC80) || - (0xD840 == in && in2 < 0xDC80) || - (0xD880 == in && in2 < 0xDC80) || - (0xD8C0 == in && in2 < 0xDC80) || - (0xD900 == in && in2 < 0xDC80) || - (0xD940 == in && in2 < 0xDC80) || - (0xD980 == in && in2 < 0xDC80) || - (0xD9C0 == in && in2 < 0xDC80) || - (0xDA00 == in && in2 < 0xDC80) || - (0xDA40 == in && in2 < 0xDC80) || - (0xDA80 == in && in2 < 0xDC80) || - (0xDAC0 == in && in2 < 0xDC80) || - (0xDB00 == in && in2 < 0xDC80) || - (0xDB40 == in && in2 < 0xDC80) || - (0xDB80 == in && in2 < 0xDC80) || - (0xDBC0 == in && in2 < 0xDC80)) { -#else - if ((0xD800 <= in && in <= 0xDBFF) && - (0xDC00 <= in2 && in2 <= 0xDFFF)) { -#endif - *pOut=subS; - ++pOut; - ++numS; - continue; - } - } else { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-3; - *numSub+=numS; - return -1; - } - } else if (0xF5 <= byte1 && byte1 <= 0xFF) { /* minic iconv() behavior */ - if (inLen < 4 || - (inLen >= 4 && byte1 == 0xF8 && pIn[1] < 0x90) || - pIn[1] < 0x80 || 0xBF < pIn[1] || - pIn[2] < 0x80 || 0xBF < pIn[2] || - pIn[3] < 0x80 || 0xBF < pIn[3] ) { - if (inLen == 1) - errno=EINVAL; /* 22 */ - else if (inLen == 2 && (pIn[1] & 0xC0) != 0x80) - errno=EILSEQ; /* 116 */ - else if (inLen == 3 && ((pIn[1] & 0xC0) != 0x80 || (pIn[2] & 0xC0) != 0x80)) - errno=EILSEQ; /* 116 */ - else if (inLen >= 4 && (byte1 == 0xF8 || (pIn[1] & 0xC0) != 0x80 || (pIn[2] & 0xC0) != 0x80 || (pIn[3] & 0xC0) != 0x80)) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } else if ((pIn[1] == 0x80 || pIn[1] == 0x90 || pIn[1] == 0xA0 || pIn[1] == 0xB0) && - pIn[2] < 0x82) { - *pOut=subS; /* Though returns replacement character, which iconv() does not return. */ - ++pOut; - ++numS; - pIn+=4; - inLen-=4; - continue; - } else { - *pOut=pSubD[0]; /* Though returns replacement character, which iconv() does not return. */ - ++pOut; - *pOut=pSubD[1]; - ++pOut; - ++numS; - pIn+=4; - inLen-=4; - continue; - /* iconv() returns 0 with strange 1 byte converted values */ - } - - } else { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - } - /* end of UTF-8 to UCS-2 */ - if (in == 0x0000) { - *pOut=0x00; - ++pOut; - } else if (in < 0x100 && dmapU2S[in] != 0x0000) { - if ((*pOut=dmapU2S[in]) == subS) { - if (in != cd->srcSubS) - ++numS; - } - ++pOut; - } else { - in<<=1; - if (dmapU2M2[in] == 0x00) { /* not found in dmapU2M2 */ - in*=1.5; - if (dmapU2M3[in] == 0x00) { /* not found in dmapU2M3*/ - *pOut=pSubD[0]; - ++pOut; - *pOut=pSubD[1]; - ++pOut; - ++numS; - ++rc; - } else { - *pOut=dmapU2M3[in]; - ++pOut; - *pOut=dmapU2M3[1+in]; - ++pOut; - *pOut=dmapU2M3[2+in]; - ++pOut; - } - } else { - *pOut=dmapU2M2[in]; - ++pOut; - if (dmapU2M2[1+in] == 0x00) { - if (*pOut == subS) { - in>>=1; - if (in != cd->srcSubS) - ++numS; - } - } else { - *pOut=dmapU2M2[1+in]; - ++pOut; - if (memcmp(pOut-2, pSubD, 2) == 0) { - in>>=1; - if (in != cd->srcSubD) { - ++numS; - ++rc; - } - } - } - } - } - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return 0; - - } else if (cd->cnv_dmap->codingSchema == DMAP_S2U) { - /* use uchar * instead of UniChar to avoid memcpy */ - register uchar * dmapD12U=(uchar *) (cd->cnv_dmap->dmapD12U); - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register int offset; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register size_t numS=0; - while (0 < inLen) { - if (pLastOutBuf < pOut) - break; - if (*pIn == 0x00) { - *pOut=0x00; - ++pOut; - *pOut=0x00; - ++pOut; - ++pIn; - --inLen; - } else { - offset=*pIn; - offset<<=1; - *pOut=dmapD12U[offset]; - ++pOut; - *pOut=dmapD12U[offset+1]; - ++pOut; - if (dmapD12U[offset] == 0x00) { - if (dmapD12U[offset+1] == 0x1A) { - if (*pIn != cd->srcSubS) - ++numS; - } else if (dmapD12U[offset+1] == 0x00) { - pOut-=2; - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - } - ++pIn; - --inLen; - } - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return 0; - - } else if (cd->cnv_dmap->codingSchema == DMAP_S28) { - /* use uchar * instead of UniChar to avoid memcpy */ - register uchar * dmapD12U=(uchar *) (cd->cnv_dmap->dmapD12U); - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register int offset; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register size_t numS=0; - register UniChar in; /* copy part of U28 */ - while (0 < inLen) { - if (pLastOutBuf < pOut) - break; - if (*pIn == 0x00) { - *pOut=0x00; - ++pOut; - ++pIn; - --inLen; - } else { - offset=*pIn; - offset<<=1; - in=dmapD12U[offset]; - in<<=8; - in+=dmapD12U[offset+1]; - if ((in & 0xFF80) == 0x0000) { /* U28: in & 0b1111111110000000 == 0x0000 */ - if (in == 0x000) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - *pOut=in; - ++pOut; - } else if ((in & 0xF800) == 0x0000) { /* in & 0b1111100000000000 == 0x0000 */ - register uchar byte; - in>>=6; - in&=0x001F; /* 0b0000000000011111 */ - in|=0x00C0; /* 0b0000000011000000 */ - *pOut=in; - ++pOut; - byte=dmapD12U[offset+1]; - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - } else if ((in & 0xFC00) == 0xD800) { /* There should not be no surrogate character in SBCS. */ - *pOut=0xEF; - ++pOut; - *pOut=0xBF; - ++pOut; - *pOut=0xBD; - ++pOut; - } else { - register uchar byte; - register uchar work; - byte=dmapD12U[offset]; - byte>>=4; - byte|=0xE0; /* 0b11100000; */ - *pOut=byte; - ++pOut; - - byte=dmapD12U[offset]; - byte<<=2; - work=dmapD12U[offset+1]; - work>>=6; - byte|=work; - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - - byte=dmapD12U[offset+1]; - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - } - /* end of U28 */ - if (dmapD12U[offset] == 0x00) { - if (dmapD12U[offset+1] == 0x1A) { - if (*pIn != cd->srcSubS) - ++numS; - } - } - ++pIn; - --inLen; - } - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return 0; - - } else if (cd->cnv_dmap->codingSchema == DMAP_U2S) { - register uchar * dmapU2S=cd->cnv_dmap->dmapU2S; - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register char subS=cd->subS; - register size_t numS=0; - while (0 < inLen) { - register uint32_t in; - if (inLen == 1) { - errno=EINVAL; /* 22 */ - - *inBytesLeft=inLen; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn; - return -1; - } - if (pLastOutBuf < pOut) - break; - in=pIn[0]; - in<<=8; - in+=pIn[1]; - if (in == 0x0000) { - *pOut=0x00; - } else { - if ((*pOut=dmapU2S[in]) == 0x00) { - *pOut=subS; - ++numS; - errno=EINVAL; /* 22 */ - } else if (*pOut == subS) { - if (in != cd->srcSubS) - ++numS; - } - } - ++pOut; - pIn+=2; - inLen-=2; - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return numS; - - } else if (cd->cnv_dmap->codingSchema == DMAP_T2S) { - register uchar * dmapU2S=cd->cnv_dmap->dmapU2S; - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register char subS=cd->subS; - register size_t numS=0; - while (0 < inLen) { - register uint32_t in; - if (inLen == 1) { - errno=EINVAL; /* 22 */ - - *inBytesLeft=inLen-1; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn; - ++numS; - *numSub+=numS; - return 0; - } - if (pLastOutBuf < pOut) - break; - in=pIn[0]; - in<<=8; - in+=pIn[1]; - if (in == 0x0000) { - *pOut=0x00; - - } else if (0xD800 <= in && in <= 0xDFFF) { /* 0xD800-0xDFFF, surrogate first and second values */ - if (0xDC00 <= in ) { - errno=EINVAL; /* 22 */ - *inBytesLeft=inLen-1; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn; - return -1; - - } else if (inLen < 4) { - errno=EINVAL; /* 22 */ - *inBytesLeft=inLen-2; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn+2; - return -1; - - } else { - register uint32_t in2; - in2=pIn[2]; - in2<<=8; - in2+=pIn[3]; - if (0xDC00 <= in2 && in2 <= 0xDFFF) { /* second surrogate character =0xDC00 - 0xDFFF*/ - *pOut=subS; - ++numS; - pIn+=4; - } else { - errno=EINVAL; /* 22 */ - *inBytesLeft=inLen-1; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn; - return -1; - } - } - } else { - if ((*pOut=dmapU2S[in]) == 0x00) { - *pOut=subS; - ++numS; - errno=EINVAL; /* 22 */ - } else if (*pOut == subS) { - if (in != cd->srcSubS) - ++numS; - } - } - ++pOut; - pIn+=2; - inLen-=2; - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return 0; - - } else if (cd->cnv_dmap->codingSchema == DMAP_82S) { - register uchar * dmapU2S=cd->cnv_dmap->dmapU2S; - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register char subS=cd->subS; - register size_t numS=0; - while (0 < inLen) { - register uint32_t in; - uint32_t in2; /* The second surrogate value */ - if (pLastOutBuf < pOut) - break; - /* convert from UTF-8 to UCS-2 */ - if (*pIn == 0x00) { - in=0x0000; - ++pIn; - --inLen; - } else { /* 82U: */ - register uchar byte1=*pIn; - if ((byte1 & 0x80) == 0x00) { /* if (byte1 & 0b10000000 == 0b00000000) { */ - /* 1 bytes sequence: 0xxxxxxx => 00000000 0xxxxxxx*/ - in=byte1; - ++pIn; - --inLen; - } else if ((byte1 & 0xE0) == 0xC0) { /* (byte1 & 0b11100000 == 0b11000000) { */ - if (inLen < 2) { - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - if (byte1 == 0xC0 || byte1 == 0xC1) { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - /* 2 bytes sequence: - 110yyyyy 10xxxxxx => 00000yyy yyxxxxxx */ - register uchar byte2; - ++pIn; - byte2=*pIn; - if ((byte2 & 0xC0) == 0x80) { /* byte2 & 0b11000000 == 0b10000000) { */ - register uchar work=byte1; - work<<=6; - byte2&=0x3F; /* 0b00111111; */ - byte2|=work; - - byte1&=0x1F; /* 0b00011111; */ - byte1>>=2; - in=byte1; - in<<=8; - in+=byte2; - inLen-=2; - ++pIn; - } else { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - *numSub+=numS; - return -1; - } - } else if ((byte1 & 0xF0) == 0xE0) { /* byte1 & 0b11110000 == 0b11100000 */ - /* 3 bytes sequence: - 1110zzzz 10yyyyyy 10xxxxxx => zzzzyyyy yyxxxxxx */ - register uchar byte2; - register uchar byte3; - if (inLen < 3) { - if (inLen == 2 && (pIn[1] & 0xC0) != 0x80) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - ++pIn; - byte2=*pIn; - ++pIn; - byte3=*pIn; - if ((byte2 & 0xC0) != 0x80 || - (byte3 & 0xC0) != 0x80 || - (byte1 == 0xE0 && byte2 < 0xA0)) { /* invalid sequence, only 0xA0-0xBF allowed after 0xE0 */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-2; - *numSub+=numS; - return -1; - } - { - register uchar work=byte2; - work<<=6; - byte3&=0x3F; /* 0b00111111; */ - byte3|=work; - - byte2&=0x3F; /* 0b00111111; */ - byte2>>=2; - - byte1<<=4; - in=byte1 | byte2;; - in<<=8; - in+=byte3; - inLen-=3; - ++pIn; - } - } else if ((0xF0 <= byte1 && byte1 <= 0xF4) || /* (bytes1 & 11111000) == 0x1110000 */ - ((byte1&=0xF7) && 0xF0 <= byte1 && byte1 <= 0xF4)) { /* minic iconv() behavior */ - /* 4 bytes sequence - 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx => 110110ww wwzzzzyy 110111yy yyxxxxxx - where uuuuu = wwww + 1 */ - register uchar byte2; - register uchar byte3; - register uchar byte4; - if (inLen < 4) { - if ((inLen >= 2 && (pIn[1] & 0xC0) != 0x80) || - (inLen >= 3 && (pIn[2] & 0xC0) != 0x80) || - (cd->toCcsid == 13488) ) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - ++pIn; - byte2=*pIn; - ++pIn; - byte3=*pIn; - ++pIn; - byte4=*pIn; - if ((byte2 & 0xC0) == 0x80 && /* byte2 & 0b11000000 == 0b10000000 */ - (byte3 & 0xC0) == 0x80 && /* byte3 & 0b11000000 == 0b10000000 */ - (byte4 & 0xC0) == 0x80) { /* byte4 & 0b11000000 == 0b10000000 */ - register uchar work=byte2; - if (byte1 == 0xF0 && byte2 < 0x90) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-3; - *numSub+=numS; - return -1; - /* iconv() returns 0 for 0xF4908080 and convert to 0x00 - } else if (byte1 == 0xF4 && byte2 > 0x8F) { - errno=EINVAL; - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-3; - *numSub+=numS; - return -1; - */ - } - - work&=0x30; /* 0b00110000; */ - work>>=4; - byte1&=0x07; /* 0b00000111; */ - byte1<<=2; - byte1+=work; /* uuuuu */ - --byte1; /* wwww */ - - work=byte1 & 0x0F; - work>>=2; - work+=0xD8; /* 0b11011011; */ - in=work; - in<<=8; - - byte1<<=6; - byte2<<=2; - byte2&=0x3C; /* 0b00111100; */ - work=byte3; - work>>=4; - work&=0x03; /* 0b00000011; */ - work|=byte1; - work|=byte2; - in+=work; - - work=byte3; - work>>=2; - work&=0x03; /* 0b00000011; */ - work|=0xDC; /* 0b110111xx; */ - in2=work; - in2<<=8; - - byte3<<=6; - byte4&=0x3F; /* 0b00111111; */ - byte4|=byte3; - in2+=byte4; - inLen-=4; - ++pIn; - } else { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-3; - *numSub+=numS; - return -1; - } - } else if ((byte1 & 0xF0) == 0xF0) { /* minic iconv() behavior */ - if (inLen < 4 || - pIn[1] < 0x80 || 0xBF < pIn[1] || - pIn[2] < 0x80 || 0xBF < pIn[2] || - pIn[3] < 0x80 || 0xBF < pIn[3] ) { - if (inLen == 1) - errno=EINVAL; /* 22 */ - else if (inLen == 2 && (pIn[1] & 0xC0) != 0x80) - errno=EILSEQ; /* 116 */ - else if (inLen == 3 && ((pIn[1] & 0xC0) != 0x80 || (pIn[2] & 0xC0) != 0x80)) - errno=EILSEQ; /* 116 */ - else if (inLen >= 4 && ((pIn[1] & 0xC0) != 0x80 || (pIn[2] & 0xC0) != 0x80 || (pIn[3] & 0xC0) != 0x80)) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } else { - *pOut=subS; /* Though returns replacement character, which iconv() does not return. */ - ++pOut; - ++numS; - pIn+=4; - inLen-=4; - /* UTF-8_IBM-850 0xF0908080 : converted value does not match, iconv=0x00, dmap=0x7F - UTF-8_IBM-850 0xF0908081 : converted value does not match, iconv=0x01, dmap=0x7F - UTF-8_IBM-850 0xF0908082 : converted value does not match, iconv=0x02, dmap=0x7F - UTF-8_IBM-850 0xF0908083 : converted value does not match, iconv=0x03, dmap=0x7F - .... - UTF-8_IBM-850 0xF09081BE : converted value does not match, iconv=0x7E, dmap=0x7F - UTF-8_IBM-850 0xF09081BF : converted value does not match, iconv=0x1C, dmap=0x7F - UTF-8_IBM-850 0xF09082A0 : converted value does not match, iconv=0xFF, dmap=0x7F - UTF-8_IBM-850 0xF09082A1 : converted value does not match, iconv=0xAD, dmap=0x7F - .... - */ - continue; - /* iconv() returns 0 with strange 1 byte converted values */ - } - - } else { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - } - /* end of UTF-8 to UCS-2 */ - if (in == 0x0000) { - *pOut=0x00; - } else { - if ((*pOut=dmapU2S[in]) == 0x00) { - *pOut=subS; - ++numS; - errno=EINVAL; /* 22 */ - } else if (*pOut == subS) { - if (in != cd->srcSubS) { - ++numS; - } - } - } - ++pOut; - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return 0; - - } else if (cd->cnv_dmap->codingSchema == DMAP_D2U) { - /* use uchar * instead of UniChar to avoid memcpy */ - register uchar * dmapD12U=(uchar *) (cd->cnv_dmap->dmapD12U); - register uchar * dmapD22U=(uchar *) (cd->cnv_dmap->dmapD22U); - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register int offset; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register size_t numS=0; - while (0 < inLen) { - if (pLastOutBuf < pOut) - break; - if (*pIn == 0x00) { - *pOut=0x00; - ++pOut; - *pOut=0x00; - ++pOut; - ++pIn; - --inLen; - } else { - offset=*pIn; - offset<<=1; - if (dmapD12U[offset] == 0x00 && - dmapD12U[offset+1] == 0x00) { /* DBCS */ - if (inLen < 2) { - if (*pIn == 0x80 || *pIn == 0xFF || - (cd->fromCcsid == 943 && (*pIn == 0x85 || *pIn == 0x86 || *pIn == 0xA0 || *pIn == 0xEB || *pIn == 0xEC || *pIn == 0xEF || *pIn == 0xFD || *pIn == 0xFE)) || - (cd->fromCcsid == 932 && (*pIn == 0x85 || *pIn == 0x86 || *pIn == 0x87 || *pIn == 0xEB || *pIn == 0xEC || *pIn == 0xED || *pIn == 0xEE || *pIn == 0xEF)) || - (cd->fromCcsid == 1381 && ((0x85 <= *pIn && *pIn <= 0x8B) || (0xAA <= *pIn && *pIn <= 0xAF) || (0xF8 <= *pIn && *pIn <= 0xFE)))) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - return -1; - } - offset-=0x100; - ++pIn; - offset<<=8; - offset+=(*pIn * 2); - if (dmapD22U[offset] == 0x00 && - dmapD22U[offset+1] == 0x00) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - return -1; - } - *pOut=dmapD22U[offset]; - ++pOut; - *pOut=dmapD22U[offset+1]; - ++pOut; - if (dmapD22U[offset] == 0xFF && - dmapD22U[offset+1] == 0xFD) { - if (pIn[-1] * 0x100 + pIn[0] != cd->srcSubD) - ++numS; - } - ++pIn; - inLen-=2; - } else { /* SBCS */ - *pOut=dmapD12U[offset]; - ++pOut; - *pOut=dmapD12U[offset+1]; - ++pOut; - if (dmapD12U[offset] == 0x00 && - dmapD12U[offset+1] == 0x1A) { - if (*pIn != cd->srcSubS) - ++numS; - } - ++pIn; - --inLen; - } - } - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return 0; - - } else if (cd->cnv_dmap->codingSchema == DMAP_D28) { - /* use uchar * instead of UniChar to avoid memcpy */ - register uchar * dmapD12U=(uchar *) (cd->cnv_dmap->dmapD12U); - register uchar * dmapD22U=(uchar *) (cd->cnv_dmap->dmapD22U); - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register int offset; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register size_t numS=0; - register UniChar in; /* copy part of U28 */ - register UniChar ucs2; - while (0 < inLen) { - if (pLastOutBuf < pOut) - break; - if (*pIn == 0x00) { - *pOut=0x00; - ++pOut; - ++pIn; - --inLen; - } else { - offset=*pIn; - offset<<=1; - if (dmapD12U[offset] == 0x00 && - dmapD12U[offset+1] == 0x00) { /* DBCS */ - if (inLen < 2) { - if (*pIn == 0x80 || *pIn == 0xFF || - (cd->fromCcsid == 943 && (*pIn == 0x85 || *pIn == 0x86 || *pIn == 0xA0 || *pIn == 0xEB || *pIn == 0xEC || *pIn == 0xEF || *pIn == 0xFD || *pIn == 0xFE)) || - (cd->fromCcsid == 932 && (*pIn == 0x85 || *pIn == 0x86 || *pIn == 0x87 || *pIn == 0xEB || *pIn == 0xEC || *pIn == 0xED || *pIn == 0xEE || *pIn == 0xEF)) || - (cd->fromCcsid == 1381 && ((0x85 <= *pIn && *pIn <= 0x8B) || (0xAA <= *pIn && *pIn <= 0xAF) || (0xF8 <= *pIn && *pIn <= 0xFE)))) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - return -1; - } - offset-=0x100; - ++pIn; - offset<<=8; - offset+=(*pIn * 2); - if (dmapD22U[offset] == 0x00 && - dmapD22U[offset+1] == 0x00) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - return -1; - } - in=dmapD22U[offset]; - in<<=8; - in+=dmapD22U[offset+1]; - ucs2=in; - if (dmapD22U[offset] == 0xFF && - dmapD22U[offset+1] == 0xFD) { - if (in != cd->srcSubD) - ++numS; - } - ++pIn; - inLen-=2; - } else { /* SBCS */ - in=dmapD12U[offset]; - in<<=8; - in+=dmapD12U[offset+1]; - ucs2=in; - if (dmapD12U[offset] == 0x00 && - dmapD12U[offset+1] == 0x1A) { - if (in != cd->srcSubS) - ++numS; - } - ++pIn; - --inLen; - } - if ((in & 0xFF80) == 0x0000) { /* U28: in & 0b1111111110000000 == 0x0000 */ - *pOut=in; - ++pOut; - } else if ((in & 0xF800) == 0x0000) { /* in & 0b1111100000000000 == 0x0000 */ - register uchar byte; - in>>=6; - in&=0x001F; /* 0b0000000000011111 */ - in|=0x00C0; /* 0b0000000011000000 */ - *pOut=in; - ++pOut; - byte=ucs2; /* dmapD12U[offset+1]; */ - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - } else if ((in & 0xFC00) == 0xD800) { /* There should not be no surrogate character in SBCS. */ - *pOut=0xEF; - ++pOut; - *pOut=0xBF; - ++pOut; - *pOut=0xBD; - ++pOut; - } else { - register uchar byte; - register uchar work; - byte=(ucs2>>8); /* dmapD12U[offset]; */ - byte>>=4; - byte|=0xE0; /* 0b11100000; */ - *pOut=byte; - ++pOut; - - byte=(ucs2>>8); /* dmapD12U[offset]; */ - byte<<=2; - work=ucs2; /* dmapD12U[offset+1]; */ - work>>=6; - byte|=work; - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - - byte=ucs2; /* dmapD12U[offset+1]; */ - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - } - /* end of U28 */ - } - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return 0; - - } else if (cd->cnv_dmap->codingSchema == DMAP_U2D) { - register uchar * dmapU2D=cd->cnv_dmap->dmapU2D; - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register char subS=cd->subS; - register char * pSubD=(char *) &(cd->subD); - register size_t numS=0; - while (0 < inLen) { - register uint32_t in; - if (inLen == 1) { - errno=EINVAL; /* 22 */ - - *inBytesLeft=inLen; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn; - return -1; - } - if (pLastOutBuf < pOut) - break; - in=pIn[0]; - in<<=8; - in+=pIn[1]; - if (in == 0x0000) { - *pOut=0x00; - ++pOut; - } else { - in<<=1; - *pOut=dmapU2D[in]; - ++pOut; - if (dmapU2D[in+1] == 0x00) { /* SBCS */ - if (*pOut == subS) { - if (in != cd->srcSubS) - ++numS; - } - } else { - *pOut=dmapU2D[in+1]; - ++pOut; - if (dmapU2D[in] == pSubD[0] && - dmapU2D[in+1] == pSubD[1]) { - in>>=1; - if (in != cd->srcSubD) - ++numS; - } - } - } - pIn+=2; - inLen-=2; - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return numS; /* to minic iconv() behavior */ - - } else if (cd->cnv_dmap->codingSchema == DMAP_T2D) { - register uchar * dmapU2D=cd->cnv_dmap->dmapU2D; - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register char subS=cd->subS; - register char * pSubD=(char *) &(cd->subD); - register size_t numS=0; - while (0 < inLen) { - register uint32_t in; - if (inLen == 1) { - errno=EINVAL; /* 22 */ - *inBytesLeft=inLen-1; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn; - ++numS; - *numSub+=numS; - return 0; - } - if (pLastOutBuf < pOut) - break; - in=pIn[0]; - in<<=8; - in+=pIn[1]; - if (in == 0x0000) { - *pOut=0x00; - ++pOut; - } else if (0xD800 <= in && in <= 0xDBFF) { /* first byte of surrogate */ - errno=EINVAL; /* 22 */ - *inBytesLeft=inLen-2; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn+2; - ++numS; - *numSub+=numS; - return -1; - - } else if (0xDC00 <= in && in <= 0xDFFF) { /* second byte of surrogate */ - errno=EINVAL; /* 22 */ - *inBytesLeft=inLen-1; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn; - ++numS; - *numSub+=numS; - return -1; - - } else { - in<<=1; - *pOut=dmapU2D[in]; - ++pOut; - if (dmapU2D[in+1] == 0x00) { /* SBCS */ - if (*pOut == subS) { - if (in != cd->srcSubS) - ++numS; - } - } else { - *pOut=dmapU2D[in+1]; - ++pOut; - if (dmapU2D[in] == pSubD[0] && - dmapU2D[in+1] == pSubD[1]) { - in>>=1; - if (in != cd->srcSubD) - ++numS; - } - } - } - pIn+=2; - inLen-=2; - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return 0; /* to minic iconv() behavior */ - - } else if (cd->cnv_dmap->codingSchema == DMAP_82D) { - register uchar * dmapU2D=cd->cnv_dmap->dmapU2D; - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register char subS=cd->subS; - register char * pSubD=(char *) &(cd->subD); - register size_t numS=0; - while (0 < inLen) { - register uint32_t in; - uint32_t in2; - if (pLastOutBuf < pOut) - break; - /* convert from UTF-8 to UCS-2 */ - if (*pIn == 0x00) { - in=0x0000; - ++pIn; - --inLen; - } else { /* 82U: */ - register uchar byte1=*pIn; - if ((byte1 & 0x80) == 0x00) { /* if (byte1 & 0b10000000 == 0b00000000) { */ - /* 1 bytes sequence: 0xxxxxxx => 00000000 0xxxxxxx*/ - in=byte1; - ++pIn; - --inLen; - } else if ((byte1 & 0xE0) == 0xC0) { /* (byte1 & 0b11100000 == 0b11000000) { */ - if (inLen < 2) { - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - if (byte1 == 0xC0 || byte1 == 0xC1) { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - /* 2 bytes sequence: - 110yyyyy 10xxxxxx => 00000yyy yyxxxxxx */ - register uchar byte2; - ++pIn; - byte2=*pIn; - if ((byte2 & 0xC0) == 0x80) { /* byte2 & 0b11000000 == 0b10000000) { */ - register uchar work=byte1; - work<<=6; - byte2&=0x3F; /* 0b00111111; */ - byte2|=work; - - byte1&=0x1F; /* 0b00011111; */ - byte1>>=2; - in=byte1; - in<<=8; - in+=byte2; - inLen-=2; - ++pIn; - } else { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - *numSub+=numS; - return -1; - } - } else if ((byte1 & 0xF0) == 0xE0) { /* byte1 & 0b11110000 == 0b11100000 */ - /* 3 bytes sequence: - 1110zzzz 10yyyyyy 10xxxxxx => zzzzyyyy yyxxxxxx */ - register uchar byte2; - register uchar byte3; - if (inLen < 3) { - if (inLen == 2 && (pIn[1] & 0xC0) != 0x80) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - ++pIn; - byte2=*pIn; - ++pIn; - byte3=*pIn; - if ((byte2 & 0xC0) != 0x80 || - (byte3 & 0xC0) != 0x80 || - (byte1 == 0xE0 && byte2 < 0xA0)) { /* invalid sequence, only 0xA0-0xBF allowed after 0xE0 */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-2; - *numSub+=numS; - return -1; - } - { - register uchar work=byte2; - work<<=6; - byte3&=0x3F; /* 0b00111111; */ - byte3|=work; - - byte2&=0x3F; /* 0b00111111; */ - byte2>>=2; - - byte1<<=4; - in=byte1 | byte2;; - in<<=8; - in+=byte3; - inLen-=3; - ++pIn; - } - } else if ((0xF0 <= byte1 && byte1 <= 0xF4)) { /* (bytes1 & 11111000) == 0x1110000 */ - /* 4 bytes sequence - 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx => 110110ww wwzzzzyy 110111yy yyxxxxxx - where uuuuu = wwww + 1 */ - register uchar byte2; - register uchar byte3; - register uchar byte4; - if (inLen < 4) { - if ((inLen >= 2 && (pIn[1] & 0xC0) != 0x80) || - (inLen >= 3 && (pIn[2] & 0xC0) != 0x80) || - (cd->toCcsid == 13488) ) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - ++pIn; - byte2=*pIn; - ++pIn; - byte3=*pIn; - ++pIn; - byte4=*pIn; - if ((byte2 & 0xC0) == 0x80 && /* byte2 & 0b11000000 == 0b10000000 */ - (byte3 & 0xC0) == 0x80 && /* byte3 & 0b11000000 == 0b10000000 */ - (byte4 & 0xC0) == 0x80) { /* byte4 & 0b11000000 == 0b10000000 */ - register uchar work=byte2; - if (byte1 == 0xF0 && byte2 < 0x90) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-3; - *numSub+=numS; - return -1; - /* iconv() returns 0 for 0xF4908080 and convert to 0x00 - } else if (byte1 == 0xF4 && byte2 > 0x8F) { - errno=EINVAL; - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-3; - *numSub+=numS; - return -1; - */ - } - - work&=0x30; /* 0b00110000; */ - work>>=4; - byte1&=0x07; /* 0b00000111; */ - byte1<<=2; - byte1+=work; /* uuuuu */ - --byte1; /* wwww */ - - work=byte1 & 0x0F; - work>>=2; - work+=0xD8; /* 0b11011011; */ - in=work; - in<<=8; - - byte1<<=6; - byte2<<=2; - byte2&=0x3C; /* 0b00111100; */ - work=byte3; - work>>=4; - work&=0x03; /* 0b00000011; */ - work|=byte1; - work|=byte2; - in+=work; - - work=byte3; - work>>=2; - work&=0x03; /* 0b00000011; */ - work|=0xDC; /* 0b110111xx; */ - in2=work; - in2<<=8; - - byte3<<=6; - byte4&=0x3F; /* 0b00111111; */ - byte4|=byte3; - in2+=byte4; - inLen-=4; - ++pIn; -#ifdef match_with_GBK - if ((0xD800 == in && in2 < 0xDC80) || - (0xD840 == in && in2 < 0xDC80) || - (0xD880 == in && in2 < 0xDC80) || - (0xD8C0 == in && in2 < 0xDC80) || - (0xD900 == in && in2 < 0xDC80) || - (0xD940 == in && in2 < 0xDC80) || - (0xD980 == in && in2 < 0xDC80) || - (0xD9C0 == in && in2 < 0xDC80) || - (0xDA00 == in && in2 < 0xDC80) || - (0xDA40 == in && in2 < 0xDC80) || - (0xDA80 == in && in2 < 0xDC80) || - (0xDAC0 == in && in2 < 0xDC80) || - (0xDB00 == in && in2 < 0xDC80) || - (0xDB40 == in && in2 < 0xDC80) || - (0xDB80 == in && in2 < 0xDC80) || - (0xDBC0 == in && in2 < 0xDC80)) { -#else - if ((0xD800 <= in && in <= 0xDBFF) && - (0xDC00 <= in2 && in2 <= 0xDFFF)) { -#endif - *pOut=subS; - ++pOut; - ++numS; - continue; - } - } else { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-3; - *numSub+=numS; - return -1; - } - } else if (0xF5 <= byte1 && byte1 <= 0xFF) { /* minic iconv() behavior */ - if (inLen < 4 || - (inLen >= 4 && byte1 == 0xF8 && pIn[1] < 0x90) || - pIn[1] < 0x80 || 0xBF < pIn[1] || - pIn[2] < 0x80 || 0xBF < pIn[2] || - pIn[3] < 0x80 || 0xBF < pIn[3] ) { - if (inLen == 1) - errno=EINVAL; /* 22 */ - else if (inLen == 2 && (pIn[1] & 0xC0) != 0x80) - errno=EILSEQ; /* 116 */ - else if (inLen == 3 && ((pIn[1] & 0xC0) != 0x80 || (pIn[2] & 0xC0) != 0x80)) - errno=EILSEQ; /* 116 */ - else if (inLen >= 4 && (byte1 == 0xF8 || (pIn[1] & 0xC0) != 0x80 || (pIn[2] & 0xC0) != 0x80 || (pIn[3] & 0xC0) != 0x80)) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } else if ((pIn[1] == 0x80 || pIn[1] == 0x90 || pIn[1] == 0xA0 || pIn[1] == 0xB0) && - pIn[2] < 0x82) { - *pOut=subS; /* Though returns replacement character, which iconv() does not return. */ - ++pOut; - ++numS; - pIn+=4; - inLen-=4; - continue; - } else { - *pOut=pSubD[0]; /* Though returns replacement character, which iconv() does not return. */ - ++pOut; - *pOut=pSubD[1]; - ++pOut; - ++numS; - pIn+=4; - inLen-=4; - continue; - /* iconv() returns 0 with strange 1 byte converted values */ - } - - } else { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - } - /* end of UTF-8 to UCS-2 */ - if (in == 0x0000) { - *pOut=0x00; - ++pOut; - } else { - in<<=1; - *pOut=dmapU2D[in]; - ++pOut; - if (dmapU2D[in+1] == 0x00) { /* SBCS */ - if (dmapU2D[in] == subS) { - in>>=1; - if (in != cd->srcSubS) - ++numS; - } - } else { - *pOut=dmapU2D[in+1]; - ++pOut; - if (dmapU2D[in] == pSubD[0] && - dmapU2D[in+1] == pSubD[1]) { - in>>=1; - if (in != cd->srcSubD) - ++numS; - } - } - } - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return 0; - - } else if (cd->cnv_dmap->codingSchema == DMAP_82U) { - /* See http://unicode.org/versions/corrigendum1.html */ - /* convert from UTF-8 to UTF-16 can cover all conversion from UTF-8 to UCS-2 */ - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - register size_t numS=0; - while (0 < inLen) { - if (pLastOutBuf < pOut) - break; - if (*pIn == 0x00) { - *pOut=0x00; - ++pOut; - *pOut=0x00; - ++pOut; - ++pIn; - --inLen; - } else { /* 82U: */ - register uchar byte1=*pIn; - if ((byte1 & 0x80) == 0x00) { /* if (byte1 & 0b10000000 == 0b00000000) { */ - /* 1 bytes sequence: 0xxxxxxx => 00000000 0xxxxxxx*/ - *pOut=0x00; - ++pOut; - *pOut=byte1; - ++pOut; - ++pIn; - --inLen; - } else if ((byte1 & 0xE0) == 0xC0) { /* (byte1 & 0b11100000 == 0b11000000) { */ - if (inLen < 2) { - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - if (byte1 == 0xC0 || byte1 == 0xC1) { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - /* 2 bytes sequence: - 110yyyyy 10xxxxxx => 00000yyy yyxxxxxx */ - register uchar byte2; - ++pIn; - byte2=*pIn; - if ((byte2 & 0xC0) == 0x80) { /* byte2 & 0b11000000 == 0b10000000) { */ - register uchar work=byte1; - work<<=6; - byte2&=0x3F; /* 0b00111111; */ - byte2|=work; - - byte1&=0x1F; /* 0b00011111; */ - byte1>>=2; - *pOut=byte1; - ++pOut; - *pOut=byte2; - ++pOut; - inLen-=2; - ++pIn; - } else { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-1; - *numSub+=numS; - return -1; - } - } else if ((byte1 & 0xF0) == 0xE0) { /* byte1 & 0b11110000 == 0b11100000 */ - /* 3 bytes sequence: - 1110zzzz 10yyyyyy 10xxxxxx => zzzzyyyy yyxxxxxx */ - register uchar byte2; - register uchar byte3; - if (inLen < 3) { - if (inLen == 2 && (pIn[1] & 0xC0) != 0x80) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - ++pIn; - byte2=*pIn; - ++pIn; - byte3=*pIn; - if ((byte2 & 0xC0) != 0x80 || - (byte3 & 0xC0) != 0x80 || - (byte1 == 0xE0 && byte2 < 0xA0)) { /* invalid sequence, only 0xA0-0xBF allowed after 0xE0 */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-2; - *numSub+=numS; - return -1; - } - { - register uchar work=byte2; - work<<=6; - byte3&=0x3F; /* 0b00111111; */ - byte3|=work; - - byte2&=0x3F; /* 0b00111111; */ - byte2>>=2; - - byte1<<=4; - *pOut=byte1 | byte2;; - ++pOut; - *pOut=byte3; - ++pOut; - inLen-=3; - ++pIn; - } - } else if ((0xF0 <= byte1 && byte1 <= 0xF4) || /* (bytes1 & 11111000) == 0x1110000 */ - ((byte1&=0xF7) && 0xF0 <= byte1 && byte1 <= 0xF4)) { /* minic iconv() behavior */ - /* 4 bytes sequence - 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx => 110110ww wwzzzzyy 110111yy yyxxxxxx - where uuuuu = wwww + 1 */ - register uchar byte2; - register uchar byte3; - register uchar byte4; - if (inLen < 4 || cd->toCcsid == 13488) { - if ((inLen >= 2 && (pIn[1] & 0xC0) != 0x80) || - (inLen >= 3 && (pIn[2] & 0xC0) != 0x80) || - (cd->toCcsid == 13488) ) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - ++pIn; - byte2=*pIn; - ++pIn; - byte3=*pIn; - ++pIn; - byte4=*pIn; - if ((byte2 & 0xC0) == 0x80 && /* byte2 & 0b11000000 == 0b10000000 */ - (byte3 & 0xC0) == 0x80 && /* byte3 & 0b11000000 == 0b10000000 */ - (byte4 & 0xC0) == 0x80) { /* byte4 & 0b11000000 == 0b10000000 */ - register uchar work=byte2; - if (byte1 == 0xF0 && byte2 < 0x90) { - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-3; - *numSub+=numS; - return -1; - } else if (byte1 == 0xF4 && byte2 > 0x8F) { - errno=EINVAL; /* 22 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-3; - *numSub+=numS; - return -1; - } - - work&=0x30; /* 0b00110000; */ - work>>=4; - byte1&=0x07; /* 0b00000111; */ - byte1<<=2; - byte1+=work; /* uuuuu */ - --byte1; /* wwww */ - - work=byte1 & 0x0F; - work>>=2; - work+=0xD8; /* 0b11011011; */ - *pOut=work; - ++pOut; - - byte1<<=6; - byte2<<=2; - byte2&=0x3C; /* 0b00111100; */ - work=byte3; - work>>=4; - work&=0x03; /* 0b00000011; */ - work|=byte1; - work|=byte2; - *pOut=work; - ++pOut; - - work=byte3; - work>>=2; - work&=0x03; /* 0b00000011; */ - work|=0xDC; /* 0b110111xx; */ - *pOut=work; - ++pOut; - - byte3<<=6; - byte4&=0x3F; /* 0b00111111; */ - byte4|=byte3; - *pOut=byte4; - ++pOut; - inLen-=4; - ++pIn; - } else { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn-3; - *numSub+=numS; - return -1; - } - } else if ((byte1 & 0xF0) == 0xF0) { - if (cd->toCcsid == 13488) { - errno=EILSEQ; /* 116 */ - } else { - if (inLen == 1) - errno=EINVAL; /* 22 */ - else if (inLen == 2 && (pIn[1] & 0xC0) != 0x80) - errno=EILSEQ; /* 116 */ - else if (inLen == 3 && ((pIn[1] & 0xC0) != 0x80 || (pIn[2] & 0xC0) != 0x80)) - errno=EILSEQ; /* 116 */ - else if (inLen >= 4 && ((pIn[1] & 0xC0) != 0x80 || (pIn[2] & 0xC0) != 0x80 || (pIn[3] & 0xC0) != 0x80)) - errno=EILSEQ; /* 116 */ - else - errno=EINVAL; /* 22 */ - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - - } else { /* invalid sequence */ - errno=EILSEQ; /* 116 */ - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return -1; - } - } - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - *numSub+=numS; - return 0; - } else if (cd->cnv_dmap->codingSchema == DMAP_U28) { - /* See http://unicode.org/versions/corrigendum1.html */ - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - // register size_t numS=0; - while (0 < inLen) { - register uint32_t in; - if (inLen == 1) { - errno=EINVAL; /* 22 */ - *inBytesLeft=inLen; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn; - return -1; - } - if (pLastOutBuf < pOut) - break; - in=pIn[0]; - in<<=8; - in+=pIn[1]; - if (in == 0x0000) { - *pOut=0x00; - ++pOut; - } else if ((in & 0xFF80) == 0x0000) { /* U28: in & 0b1111111110000000 == 0x0000 */ - *pOut=in; - ++pOut; - } else if ((in & 0xF800) == 0x0000) { /* in & 0b1111100000000000 == 0x0000 */ - register uchar byte; - in>>=6; - in&=0x001F; /* 0b0000000000011111 */ - in|=0x00C0; /* 0b0000000011000000 */ - *pOut=in; - ++pOut; - byte=pIn[1]; - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - } else { - register uchar byte; - register uchar work; - byte=pIn[0]; - byte>>=4; - byte|=0xE0; /* 0b11100000; */ - *pOut=byte; - ++pOut; - - byte=pIn[0]; - byte<<=2; - work=pIn[1]; - work>>=6; - byte|=work; - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - - byte=pIn[1]; - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - } - pIn+=2; - inLen-=2; - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - // *numSub+=numS; - return 0; - - } else if (cd->cnv_dmap->codingSchema == DMAP_T28) { /* UTF-16_UTF-8 */ - /* See http://unicode.org/versions/corrigendum1.html */ - register int inLen=*inBytesLeft; - register char * pOut=*outBuf; - register char * pIn=*inBuf; - register char * pLastOutBuf = *outBuf + *outBytesLeft - 1; - // register size_t numS=0; - while (0 < inLen) { - register uint32_t in; - if (inLen == 1) { - errno=EINVAL; /* 22 */ - *inBytesLeft=0; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn; - return 0; - } - if (pLastOutBuf < pOut) - break; - in=pIn[0]; - in<<=8; - in+=pIn[1]; - if (in == 0x0000) { - *pOut=0x00; - ++pOut; - } else if ((in & 0xFF80) == 0x0000) { /* U28: in & 0b1111111110000000 == 0x0000 */ - *pOut=in; - ++pOut; - } else if ((in & 0xF800) == 0x0000) { /* in & 0b1111100000000000 == 0x0000 */ - register uchar byte; - in>>=6; - in&=0x001F; /* 0b0000000000011111 */ - in|=0x00C0; /* 0b0000000011000000 */ - *pOut=in; - ++pOut; - byte=pIn[1]; - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - } else if ((in & 0xFC00) == 0xD800) { /* in & 0b1111110000000000 == 0b1101100000000000, first surrogate character */ - if (0xDC00 <= in ) { - errno=EINVAL; /* 22 */ - *inBytesLeft=inLen-1; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn; - return -1; - - } else if (inLen < 4) { - errno=EINVAL; /* 22 */ - *inBytesLeft=inLen-2; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn+2; - return -1; - - } else if ((pIn[2] & 0xFC) != 0xDC) { /* pIn[2] & 0b11111100 == 0b11011100, second surrogate character */ - errno=EINVAL; /* 22 */ - *inBytesLeft=inLen-2; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn+2; - return -1; - - } else { - register uchar byte; - register uchar work; - in>>=6; - in&=0x000F; /* 0b0000000000001111 */ - byte=in; /* wwww */ - ++byte; /* uuuuu */ - work=byte; /* save uuuuu */ - byte>>=2; - byte|=0xF0; /* 0b11110000; */ - *pOut=byte; - ++pOut; - - byte=work; - byte&=0x03; /* 0b00000011; */ - byte<<=4; - byte|=0x80; /* 0b10000000; */ - work=pIn[1]; - work&=0x3C; /* 0b00111100; */ - work>>=2; - byte|=work; - *pOut=byte; - ++pOut; - - byte=pIn[1]; - byte&=0x03; /* 0b00000011; */ - byte<<=4; - byte|=0x80; /* 0b10000000; */ - work=pIn[2]; - work&=0x03; /* 0b00000011; */ - work<<=2; - byte|=work; - work=pIn[3]; - work>>=6; - byte|=work; - *pOut=byte; - ++pOut; - - byte=pIn[3]; - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - pIn+=2; - inLen-=2; - } - } else if ((in & 0xFC00) == 0xDC00) { /* in & 0b11111100 == 0b11011100, second surrogate character */ - errno=EINVAL; /* 22 */ - *inBytesLeft=inLen-1; - *outBytesLeft-=(pOut-*outBuf); - *outBuf=pOut; - *inBuf=pIn; - return -1; - - } else { - register uchar byte; - register uchar work; - byte=pIn[0]; - byte>>=4; - byte|=0xE0; /* 0b11100000; */ - *pOut=byte; - ++pOut; - - byte=pIn[0]; - byte<<=2; - work=pIn[1]; - work>>=6; - byte|=work; - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - - byte=pIn[1]; - byte&=0x3F; /* 0b00111111; */ - byte|=0x80; /* 0b10000000; */ - *pOut=byte; - ++pOut; - } - pIn+=2; - inLen-=2; - } - *outBytesLeft-=(pOut-*outBuf); - *inBytesLeft=inLen; - *outBuf=pOut; - *inBuf=pIn; - // *numSub+=numS; - return 0; - - } else if (cd->cnv_dmap->codingSchema == DMAP_U2U) { /* UTF-16_UCS-2 */ - register int inLen=*inBytesLeft; - register int outLen=*outBytesLeft; - if (inLen <= outLen) { - memcpy(*outBuf, *inBuf, inLen); - (*outBytesLeft)-=inLen; - (*inBuf)+=inLen; - (*outBuf)+=inLen; - *inBytesLeft=0; - return 0; - } - memcpy(*outBuf, *inBuf, outLen); - (*outBytesLeft)=0; - (*inBuf)+=outLen; - (*outBuf)+=outLen; - *inBytesLeft-=outLen; - return (*inBytesLeft); - - } else { - return -1; - } - return 0; -} - - -#ifdef DEBUG -inline size_t myconv(myconv_t cd , - char** inBuf, - size_t* inBytesLeft, - char** outBuf, - size_t* outBytesLeft, - size_t* numSub) -{ - if (cd->converterType == CONVERTER_ICONV) { - return myconv_iconv(cd,inBuf,inBytesLeft,outBuf,outBytesLeft,numSub); - } else if (cd->converterType == CONVERTER_DMAP) { - return myconv_dmap(cd,inBuf,inBytesLeft,outBuf,outBytesLeft,numSub); - } - return -1; -} - -inline char * converterName(int32_t type) -{ - if (type == CONVERTER_ICONV) - return "iconv"; - else if (type == CONVERTER_DMAP) - return "dmap"; - - return "?????"; -} -#else -#define myconv(a,b,c,d,e,f) \ -(((a)->converterType == CONVERTER_ICONV)? myconv_iconv((a),(b),(c),(d),(e),(f)): (((a)->converterType == CONVERTER_DMAP)? myconv_dmap((a),(b),(c),(d),(e),(f)): -1)) - - -#define converterName(a) \ -(((a) == CONVERTER_ICONV)? "iconv": ((a) == CONVERTER_DMAP)? "dmap": "?????") -#endif - -void initMyconv(); -void cleanupMyconv(); - -#endif diff --git a/storage/ibmdb2i/db2i_rir.cc b/storage/ibmdb2i/db2i_rir.cc deleted file mode 100644 index 091c4d98383..00000000000 --- a/storage/ibmdb2i/db2i_rir.cc +++ /dev/null @@ -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 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); -} diff --git a/storage/ibmdb2i/db2i_safeString.h b/storage/ibmdb2i/db2i_safeString.h deleted file mode 100644 index e353316c8fc..00000000000 --- a/storage/ibmdb2i/db2i_safeString.h +++ /dev/null @@ -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 -#include - -/** - @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 diff --git a/storage/ibmdb2i/db2i_sqlStatementStream.cc b/storage/ibmdb2i/db2i_sqlStatementStream.cc deleted file mode 100644 index 92a8b03fd00..00000000000 --- a/storage/ibmdb2i/db2i_sqlStatementStream.cc +++ /dev/null @@ -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; -} diff --git a/storage/ibmdb2i/db2i_sqlStatementStream.h b/storage/ibmdb2i/db2i_sqlStatementStream.h deleted file mode 100644 index 11db41a6c5d..00000000000 --- a/storage/ibmdb2i/db2i_sqlStatementStream.h +++ /dev/null @@ -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 - diff --git a/storage/ibmdb2i/db2i_validatedPointer.h b/storage/ibmdb2i/db2i_validatedPointer.h deleted file mode 100644 index c4e31d1f11b..00000000000 --- a/storage/ibmdb2i/db2i_validatedPointer.h +++ /dev/null @@ -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 ValidatedPointer -{ -public: - ValidatedPointer() : address(NULL), handle(NULL) {;} - - ValidatedPointer(size_t size) - { - alloc(size); - } - - ValidatedPointer(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 ValidatedObject : public ValidatedPointer -{ - public: - ValidatedObject() : ValidatedPointer(&value) {;} - - T& operator= (const T newVal) { value = newVal; return value; } - - private: - T value; -}; -#endif diff --git a/storage/ibmdb2i/ha_ibmdb2i.cc b/storage/ibmdb2i/ha_ibmdb2i.cc deleted file mode 100644 index 39096be7848..00000000000 --- a/storage/ibmdb2i/ha_ibmdb2i.cc +++ /dev/null @@ -1,3359 +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.cc - - @brief - The ha_ibmdb2i storage engine provides an interface from MySQL to IBM DB2 for i. - -*/ - -#ifdef USE_PRAGMA_IMPLEMENTATION -#pragma implementation // gcc: Class implementation -#endif - -#include "ha_ibmdb2i.h" -#include "mysql_priv.h" -#include -#include "db2i_ileBridge.h" -#include "db2i_charsetSupport.h" -#include -#include "db2i_safeString.h" - -static const char __NOT_NULL_VALUE_EBCDIC = 0xF0; // '0' -static const char __NULL_VALUE_EBCDIC = 0xF1; // '1' -static const char __DEFAULT_VALUE_EBCDIC = 0xC4; // 'D' -static const char BlankASPName[19] = " "; -static const int DEFAULT_MAX_ROWS_TO_BUFFER = 4096; - -static const char SAVEPOINT_PREFIX[] = {0xD4, 0xE8, 0xE2, 0xD7}; // MYSP (in EBCDIC) - -OSVersion osVersion; - - -// ================================================================ -// ================================================================ -// System variables -static char* ibmdb2i_rdb_name; -static MYSQL_SYSVAR_STR(rdb_name, ibmdb2i_rdb_name, - PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY, - "The name of the RDB to use", - NULL, - NULL, - BlankASPName); - -static MYSQL_THDVAR_BOOL(transaction_unsafe, - 0, - "Disable support for commitment control", - NULL, - NULL, - FALSE); - -static MYSQL_THDVAR_UINT(lob_alloc_size, - 0, - "Baseline allocation for lob read buffer", - NULL, - NULL, - 2*1024*1024, - 64*1024, - 128*1024*1024, - 1); - -static MYSQL_THDVAR_UINT(max_read_buffer_size, - 0, - "Maximum size of buffers used for read-ahead.", - NULL, - NULL, - 1*1024*1024, - 32*1024, - 16*1024*1024, - 1); - -static MYSQL_THDVAR_UINT(max_write_buffer_size, - 0, - "Maximum size of buffers used for bulk writes.", - NULL, - NULL, - 8*1024*1024, - 32*1024, - 64*1024*1024, - 1); - -static MYSQL_THDVAR_BOOL(compat_opt_time_as_duration, - 0, - "Control how new TIME columns should be defined in DB2. 0=time-of-day (default), 1=duration.", - NULL, - NULL, - FALSE); - -static MYSQL_THDVAR_UINT(compat_opt_year_as_int, - 0, - "Control how new YEAR columns should be defined in DB2. 0=CHAR(4) (default), 1=SMALLINT.", - NULL, - NULL, - 0, - 0, - 1, - 1); - -static MYSQL_THDVAR_UINT(compat_opt_blob_cols, - 0, - "Control how new TEXT and BLOB columns should be defined in DB2. 0=CLOB/BLOB (default), 1=VARCHAR/VARBINARY", - NULL, - NULL, - 0, - 0, - 1, - 1); - -static MYSQL_THDVAR_UINT(compat_opt_allow_zero_date_vals, - 0, - "Allow substitute values to be used when storing a column with a 0000-00-00 date component. 0=No substitution (default), 1=Substitute '0001-01-01'", - NULL, - NULL, - 0, - 0, - 1, - 1); - -static MYSQL_THDVAR_BOOL(propagate_default_col_vals, - 0, - "Should DEFAULT column values be propagated to the DB2 table definition.", - NULL, - NULL, - TRUE); - -static my_bool ibmdb2i_assume_exclusive_use; -static MYSQL_SYSVAR_BOOL(assume_exclusive_use, ibmdb2i_assume_exclusive_use, - 0, - "Can MySQL assume that this process is the only one modifying the DB2 tables. ", - NULL, - NULL, - FALSE); - -static MYSQL_THDVAR_BOOL(async_enabled, - 0, - "Should reads be done asynchronously when possible", - NULL, - NULL, - TRUE); - -static MYSQL_THDVAR_UINT(create_index_option, - 0, - "Control whether additional indexes are created. 0=No (default), 1=Create additional *HEX-based index", - NULL, - NULL, - 0, - 0, - 1, - 1); - -/* static MYSQL_THDVAR_UINT(discovery_mode, - 0, - "Unsupported", - NULL, - NULL, - 0, - 0, - 1, - 1); */ - -static uint32 ibmdb2i_system_trace; -static MYSQL_SYSVAR_UINT(system_trace_level, ibmdb2i_system_trace, - 0, - "Set system tracing level", - NULL, - NULL, - 0, - 0, - 63, - 1); - - -inline uint8 ha_ibmdb2i::getCommitLevel(THD* thd) -{ - if (!THDVAR(thd, transaction_unsafe)) - { - switch (thd_tx_isolation(thd)) - { - case ISO_READ_UNCOMMITTED: - return (accessIntent == QMY_READ_ONLY ? QMY_READ_UNCOMMITTED : QMY_REPEATABLE_READ); - case ISO_READ_COMMITTED: - return (accessIntent == QMY_READ_ONLY ? QMY_READ_COMMITTED : QMY_REPEATABLE_READ); - case ISO_REPEATABLE_READ: - return QMY_REPEATABLE_READ; - case ISO_SERIALIZABLE: - return QMY_SERIALIZABLE; - } - } - - return QMY_NONE; -} - -inline uint8 ha_ibmdb2i::getCommitLevel() -{ - return getCommitLevel(ha_thd()); -} - -//===================================================================== - -static handler *ibmdb2i_create_handler(handlerton *hton, - TABLE_SHARE *table, - MEM_ROOT *mem_root); -static void ibmdb2i_drop_database(handlerton *hton, char* path); -static int ibmdb2i_savepoint_set(handlerton *hton, THD* thd, void *sv); -static int ibmdb2i_savepoint_rollback(handlerton *hton, THD* thd, void *sv); -static int ibmdb2i_savepoint_release(handlerton *hton, THD* thd, void *sv); -static uint ibmdb2i_alter_table_flags(uint flags); - -handlerton *ibmdb2i_hton; -static bool was_ILE_inited; - -/* Tracks the number of open tables */ -static HASH ibmdb2i_open_tables; - -/* Mutex used to synchronize initialization of the hash */ -static pthread_mutex_t ibmdb2i_mutex; - - -/** - Create hash key for tracking open tables. -*/ - -static uchar* ibmdb2i_get_key(IBMDB2I_SHARE *share,size_t *length, - bool not_used __attribute__((unused))) -{ - *length=share->table_name_length; - return (uchar*) share->table_name; -} - - -int ibmdb2i_close_connection(handlerton* hton, THD *thd) -{ - DBUG_PRINT("ha_ibmdb2i::close_connection", ("Closing %d", thd->thread_id)); - db2i_ileBridge::getBridgeForThread(thd)->closeConnection(thd->thread_id); - db2i_ileBridge::destroyBridgeForThread(thd); - - return 0; -} - - -static int ibmdb2i_init_func(void *p) -{ - DBUG_ENTER("ibmdb2i_init_func"); - - utsname tempName; - uname(&tempName); - osVersion.v = atoi(tempName.version); - osVersion.r = atoi(tempName.release); - - was_ILE_inited = false; - ibmdb2i_hton= (handlerton *)p; - VOID(pthread_mutex_init(&ibmdb2i_mutex,MY_MUTEX_INIT_FAST)); - (void) hash_init(&ibmdb2i_open_tables,table_alias_charset,32,0,0, - (hash_get_key) ibmdb2i_get_key,0,0); - - ibmdb2i_hton->state= SHOW_OPTION_YES; - ibmdb2i_hton->create= ibmdb2i_create_handler; - ibmdb2i_hton->drop_database= ibmdb2i_drop_database; - ibmdb2i_hton->commit= ha_ibmdb2i::doCommit; - ibmdb2i_hton->rollback= ha_ibmdb2i::doRollback; - ibmdb2i_hton->savepoint_offset= 0; - ibmdb2i_hton->savepoint_set= ibmdb2i_savepoint_set; - ibmdb2i_hton->savepoint_rollback= ibmdb2i_savepoint_rollback; - ibmdb2i_hton->savepoint_release= ibmdb2i_savepoint_release; - ibmdb2i_hton->alter_table_flags=ibmdb2i_alter_table_flags; - ibmdb2i_hton->close_connection=ibmdb2i_close_connection; - - int rc; - - rc = initCharsetSupport(); - - if (!rc) - rc = db2i_ileBridge::setup(); - - if (!rc) - { - int nameLen = strlen(ibmdb2i_rdb_name); - for (int i = 0; i < nameLen; ++i) - { - ibmdb2i_rdb_name[i] = my_toupper(system_charset_info, (uchar)ibmdb2i_rdb_name[i]); - } - - rc = db2i_ileBridge::initILE(ibmdb2i_rdb_name, (uint16*)(((char*)&ibmdb2i_system_trace)+2)); - if (rc == 0) - { - was_ILE_inited = true; - } - } - - DBUG_RETURN(rc); -} - - -static int ibmdb2i_done_func(void *p) -{ - int error= 0; - DBUG_ENTER("ibmdb2i_done_func"); - - if (ibmdb2i_open_tables.records) - error= 1; - - if (was_ILE_inited) - db2i_ileBridge::exitILE(); - - db2i_ileBridge::takedown(); - - doneCharsetSupport(); - - hash_free(&ibmdb2i_open_tables); - pthread_mutex_destroy(&ibmdb2i_mutex); - - DBUG_RETURN(0); -} - - -IBMDB2I_SHARE *ha_ibmdb2i::get_share(const char *table_name, TABLE *table) -{ - IBMDB2I_SHARE *share; - uint length; - char *tmp_name; - - pthread_mutex_lock(&ibmdb2i_mutex); - length=(uint) strlen(table_name); - - if (!(share=(IBMDB2I_SHARE*) hash_search(&ibmdb2i_open_tables, - (uchar*)table_name, - length))) - { - if (!(share=(IBMDB2I_SHARE *) - my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), - &share, sizeof(*share), - &tmp_name, length+1, - NullS))) - { - pthread_mutex_unlock(&ibmdb2i_mutex); - return NULL; - } - - share->use_count=0; - share->table_name_length=length; - share->table_name=tmp_name; - strmov(share->table_name,table_name); - if (my_hash_insert(&ibmdb2i_open_tables, (uchar*) share)) - goto error; - thr_lock_init(&share->lock); - pthread_mutexattr_t mutexattr = MY_MUTEX_INIT_FAST; - pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&share->mutex, &mutexattr); - - share->db2Table = new db2i_table(table->s, table_name); - int32 rc = share->db2Table->initDB2Objects(table_name); - - if (rc) - { - delete share->db2Table; - hash_delete(&ibmdb2i_open_tables, (uchar*) share); - thr_lock_delete(&share->lock); - my_errno = rc; - goto error; - } - - memset(&share->cachedStats, 0, sizeof(share->cachedStats)); - } - share->use_count++; - pthread_mutex_unlock(&ibmdb2i_mutex); - - db2Table = share->db2Table; - - return share; - -error: - pthread_mutex_destroy(&share->mutex); - my_free((uchar*) share, MYF(0)); - pthread_mutex_unlock(&ibmdb2i_mutex); - - return NULL; -} - - - -int ha_ibmdb2i::free_share(IBMDB2I_SHARE *share) -{ - pthread_mutex_lock(&ibmdb2i_mutex); - if (!--share->use_count) - { - delete share->db2Table; - db2Table = NULL; - - hash_delete(&ibmdb2i_open_tables, (uchar*) share); - thr_lock_delete(&share->lock); - pthread_mutex_destroy(&share->mutex); - my_free(share, MYF(0)); - pthread_mutex_unlock(&ibmdb2i_mutex); - return 1; - } - pthread_mutex_unlock(&ibmdb2i_mutex); - - return 0; -} - -static handler* ibmdb2i_create_handler(handlerton *hton, - TABLE_SHARE *table, - MEM_ROOT *mem_root) -{ - return new (mem_root) ha_ibmdb2i(hton, table); -} - -static void ibmdb2i_drop_database(handlerton *hton, char* path) -{ - DBUG_ENTER("ha_ibmdb2i::ibmdb2i_drop_database"); - int rc = 0; - char queryBuffer[200]; - String query(queryBuffer, sizeof(queryBuffer), system_charset_info); - query.length(0); - query.append(STRING_WITH_LEN(" DROP SCHEMA \"")); - query.append(path+2, strchr(path+2, '/')-(path+2)); - query.append('"'); - - SqlStatementStream sqlStream(query); - - rc = db2i_ileBridge::getBridgeForThread()->execSQL(sqlStream.getPtrToData(), - sqlStream.getStatementCount(), - QMY_NONE, - FALSE, - TRUE); - DBUG_VOID_RETURN; -} - -inline static void genSavepointName(const void* sv, char* out) -{ - *(uint32*)out = *(uint32*)SAVEPOINT_PREFIX; - DBUG_ASSERT(sizeof(SAVEPOINT_PREFIX) == 4); - out += sizeof(SAVEPOINT_PREFIX); - - longlong2str((longlong)sv, out, 10); - while (*out) - { - out += 0xF0; - ++out; - } -} - - -/********************************************************************* -Sets a transaction savepoint. */ -static int ibmdb2i_savepoint_set(handlerton* hton, THD* thd, void* sv) -{ - DBUG_ENTER("ibmdb2i_savepoint_set"); - int rc = 0; - if (!THDVAR(thd ,transaction_unsafe)) - { - char name[64]; - genSavepointName(sv, name); - DBUG_PRINT("ibmdb2i_savepoint_set",("Setting %s", name)); - rc = ha_ibmdb2i::doSavepointSet(thd, name); - } - DBUG_RETURN(rc); -} - - -/********************************************************************* -Rollback a savepoint. */ -static int ibmdb2i_savepoint_rollback(handlerton* hton, THD* thd, void* sv) -{ - DBUG_ENTER("ibmdb2i_savepoint_rollback"); - int rc = 0; - if (!THDVAR(thd,transaction_unsafe)) - { - char name[64]; - genSavepointName(sv, name); - DBUG_PRINT("ibmdb2i_savepoint_rollback",("Rolling back %s", name)); - rc = ha_ibmdb2i::doSavepointRollback(thd, name); - } - DBUG_RETURN(rc); -} - - -/********************************************************************* -Release a savepoint. */ -static int ibmdb2i_savepoint_release(handlerton* hton, THD* thd, void* sv) -{ - DBUG_ENTER("ibmdb2i_savepoint_release"); - int rc = 0; - if (!THDVAR(thd,transaction_unsafe)) - { - char name[64]; - genSavepointName(sv, name); - DBUG_PRINT("ibmdb2i_savepoint_release",("Releasing %s", name)); - rc = ha_ibmdb2i::doSavepointRelease(thd, name); - } - DBUG_RETURN(rc); -} - -/* Thse flags allow for the online add and drop of an index via the CREATE INDEX, - DROP INDEX, and ALTER TABLE statements. These flags indicate that MySQL is not - required to lock the table before calling the storage engine to add or drop the - index(s). */ -static uint ibmdb2i_alter_table_flags(uint flags) -{ - return (HA_ONLINE_ADD_INDEX | HA_ONLINE_DROP_INDEX | - HA_ONLINE_ADD_UNIQUE_INDEX | HA_ONLINE_DROP_UNIQUE_INDEX | - HA_ONLINE_ADD_PK_INDEX | HA_ONLINE_DROP_PK_INDEX); -} - -ha_ibmdb2i::ha_ibmdb2i(handlerton *hton, TABLE_SHARE *table_arg) - :share(NULL), handler(hton, table_arg), - activeHandle(0), dataHandle(0), - activeReadBuf(NULL), activeWriteBuf(NULL), - blobReadBuffers(NULL), accessIntent(QMY_UPDATABLE), currentRRN(0), - releaseRowNeeded(FALSE), - indexReadSizeEstimates(NULL), - outstanding_start_bulk_insert(false), - last_rnd_init_rc(0), - last_index_init_rc(0), - last_start_bulk_insert_rc(0), - autoIncLockAcquired(false), - got_auto_inc_values(false), - next_identity_value(0), - indexHandles(0), - returnDupKeysImmediately(false), - onDupUpdate(false), - blobWriteBuffers(NULL), - forceSingleRowRead(false) - { - activeReferences = 0; - ref_length = sizeof(currentRRN); - if (table_share && table_share->keys > 0) - { - indexHandles = (FILE_HANDLE*)my_malloc(table_share->keys * sizeof(FILE_HANDLE), MYF(MY_WME | MY_ZEROFILL)); - } - clear_alloc_root(&conversionBufferMemroot); - } - - -ha_ibmdb2i::~ha_ibmdb2i() -{ - DBUG_ASSERT(activeReferences == 0 || outstanding_start_bulk_insert); - - if (indexHandles) - my_free(indexHandles, MYF(0)); - if (indexReadSizeEstimates) - my_free(indexReadSizeEstimates, MYF(0)); - - cleanupBuffers(); -} - - -static const char *ha_ibmdb2i_exts[] = { - FID_EXT, - NullS -}; - -const char **ha_ibmdb2i::bas_ext() const -{ - return ha_ibmdb2i_exts; -} - - -int ha_ibmdb2i::open(const char *name, int mode, uint test_if_locked) -{ - DBUG_ENTER("ha_ibmdb2i::open"); - - initBridge(); - - dataHandle = bridge()->findAndRemovePreservedHandle(name, &share); - - if (share) - db2Table = share->db2Table; - - if (!share && (!(share = get_share(name, table)))) - DBUG_RETURN(my_errno); - thr_lock_data_init(&share->lock,&lock,NULL); - - info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE); - - - DBUG_RETURN(0); -} - - - - -int ha_ibmdb2i::close(void) -{ - DBUG_ENTER("ha_ibmdb2i::close"); - int32 rc = 0; - bool preserveShare = false; - - db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread(); - - if (dataHandle) - { - if (bridge->expectErrors(QMY_ERR_PEND_LOCKS)->deallocateFile(dataHandle, FALSE) == QMY_ERR_PEND_LOCKS) - { - bridge->preserveHandle(share->table_name, dataHandle, share); - preserveShare = true; - } - dataHandle = 0; - } - - for (int idx = 0; idx < table_share->keys; ++idx) - { - if (indexHandles[idx] != 0) - { - bridge->deallocateFile(indexHandles[idx], FALSE); - } - } - - cleanupBuffers(); - - if (!preserveShare) - { - if (free_share(share)) - share = NULL; - } - - DBUG_RETURN(rc); -} - - - -int ha_ibmdb2i::write_row(uchar * buf) -{ - - DBUG_ENTER("ha_ibmdb2i::write_row"); - - if (last_start_bulk_insert_rc) - DBUG_RETURN( last_start_bulk_insert_rc ); - - ha_statistic_increment(&SSV::ha_write_count); - int rc = 0; - - bool fileHandleNeedsRelease = false; - - if (!activeHandle) - { - rc = useDataFile(); - if (rc) DBUG_RETURN(rc); - fileHandleNeedsRelease = true; - } - - if (!outstanding_start_bulk_insert) - rc = prepWriteBuffer(1, getFileForActiveHandle()); - - if (!rc) - { - if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) - table->timestamp_field->set_time(); - - char* writeBuffer = activeWriteBuf->addRow(); - rc = prepareRowForWrite(writeBuffer, - writeBuffer+activeWriteBuf->getRowNullOffset(), - true); - if (rc == 0) - { - // If we are doing block inserts, if the MI is supposed to generate an auto_increment - // (i.e. identity column) value for this record, and if this is not the first record in - // the block, then store the value (that the MI will generate for the identity column) - // into the MySQL write buffer. We can predetermine the value because the file is locked. - - if ((autoIncLockAcquired) && (default_identity_value) && (got_auto_inc_values)) - { - if (unlikely((next_identity_value - 1) == - maxValueForField(table->next_number_field))) - { - rc = QMY_ERR_MAXVALUE; - } - else - { - rc = table->next_number_field->store((longlong) next_identity_value, TRUE); - next_identity_value = next_identity_value + incrementByValue; - } - } - // If the buffer is full, or if we locked the file and this is the first or last row - // of a blocked insert, then flush the buffer. - if (!rc && (activeWriteBuf->endOfBuffer()) || - ((autoIncLockAcquired) && - ((!got_auto_inc_values))) || - (returnDupKeysImmediately)) - rc = flushWrite(activeHandle, buf); - } - else - activeWriteBuf->deleteRow(); - } - - if (fileHandleNeedsRelease) - releaseActiveHandle(); - - DBUG_RETURN(rc); -} - -/** - @brief - Helper function used by write_row and update_row to prepare the MySQL - row for insertion into DB2. -*/ -int ha_ibmdb2i::prepareRowForWrite(char* data, char* nulls, bool honorIdentCols) -{ - int rc = 0; - - // set null map all to non nulls - memset(nulls,__NOT_NULL_VALUE_EBCDIC, table->s->fields); - default_identity_value = FALSE; - - ulong sql_mode = ha_thd()->variables.sql_mode; - - my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); - for (Field **field = table->field; *field && !rc; ++field) - { - int fieldIndex = (*field)->field_index; - if ((*field)->Field::is_null()) - { - nulls[fieldIndex] = __NULL_VALUE_EBCDIC; - } - if (honorIdentCols && ((*field)->flags & AUTO_INCREMENT_FLAG) && - *field == table->next_number_field) -// && ((!autoIncLockAcquired) || (!got_auto_inc_values))) - { - if (sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO) - { - if (!table->auto_increment_field_not_null) - { - nulls[fieldIndex] = __DEFAULT_VALUE_EBCDIC; - default_identity_value = TRUE; - } - } - else if ((*field)->val_int() == 0) - { - nulls[fieldIndex] = __DEFAULT_VALUE_EBCDIC; - default_identity_value = TRUE; - } - } - - DB2Field& db2Field = db2Table->db2Field(fieldIndex); - if (nulls[fieldIndex] == __NOT_NULL_VALUE_EBCDIC || - db2Field.isBlob()) - { - rc = convertMySQLtoDB2(*field, db2Field, data + db2Field.getBufferOffset()); - } - } - - if (!rc && db2Table->hasBlobs()) - rc = db2i_ileBridge::getBridgeForThread()->objectOverride(activeHandle, - activeWriteBuf->ptr()); - - dbug_tmp_restore_column_map(table->read_set, old_map); - - return rc; -} - - - -int ha_ibmdb2i::update_row(const uchar * old_data, uchar * new_data) -{ - DBUG_ENTER("ha_ibmdb2i::update_row"); - ha_statistic_increment(&SSV::ha_update_count); - int rc; - - bool fileHandleNeedsRelease = false; - - if (!activeHandle) - { - rc = useFileByHandle(QMY_UPDATABLE, rrnAssocHandle); - if (rc) DBUG_RETURN(rc); - fileHandleNeedsRelease = true; - } - - if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) - table->timestamp_field->set_time(); - - char* writeBuf = activeWriteBuf->addRow(); - rc = prepareRowForWrite(writeBuf, - writeBuf+activeWriteBuf->getRowNullOffset(), - onDupUpdate); - - char* lastDupKeyNamePtr = NULL; - uint32 lastDupKeyNameLen = 0; - - if (!rc) - { - rc = db2i_ileBridge::getBridgeForThread()->updateRow(activeHandle, - currentRRN, - activeWriteBuf->ptr(), - &lastDupKeyRRN, - &lastDupKeyNamePtr, - &lastDupKeyNameLen); - } - - if (lastDupKeyNameLen) - { - lastDupKeyID = getKeyFromName(lastDupKeyNamePtr, lastDupKeyNameLen); - rrnAssocHandle = activeHandle; - } - - if (fileHandleNeedsRelease) - releaseActiveHandle(); - - activeWriteBuf->resetAfterWrite(); - - DBUG_RETURN(rc); -} - - -int ha_ibmdb2i::delete_row(const uchar * buf) -{ - DBUG_ENTER("ha_ibmdb2i::delete_row"); - ha_statistic_increment(&SSV::ha_delete_count); - - bool needReleaseFile = false; - int rc = 0; - - if (!activeHandle) // In some circumstances, MySQL comes here after - { // closing the active handle. We need to re-open. - rc = useFileByHandle(QMY_UPDATABLE, rrnAssocHandle); - needReleaseFile = true; - } - - if (likely(!rc)) - { - rc = db2i_ileBridge::getBridgeForThread()->deleteRow(activeHandle, - currentRRN); - invalidateCachedStats(); - if (needReleaseFile) - releaseActiveHandle(); - } - - DBUG_RETURN(rc); -} - - - -int ha_ibmdb2i::index_init(uint idx, bool sorted) -{ - DBUG_ENTER("ha_ibmdb2i::index_init"); - - int& rc = last_index_init_rc; - rc = 0; - - invalidDataFound=false; - tweakReadSet(); - - active_index=idx; - - rc = useIndexFile(idx); - - if (!rc) - { -// THD* thd = ha_thd(); -// if (accessIntent == QMY_UPDATABLE && -// thd_tx_isolation(thd) == ISO_REPEATABLE_READ && -// !THDVAR(thd, transaction_unsafe)) -// { -// readAccessIntent = QMY_READ_ONLY; -// } -// else -// { - readAccessIntent = accessIntent; -// } - - if (!rc && accessIntent != QMY_READ_ONLY) - rc = prepWriteBuffer(1, db2Table->indexFile(idx)); - - if (rc) - releaseIndexFile(idx); - } - - rrnAssocHandle= 0; - - DBUG_RETURN(rc); -} - - - -int ha_ibmdb2i::index_read(uchar * buf, const uchar * key, - uint key_len, - enum ha_rkey_function find_flag) -{ - DBUG_ENTER("ha_ibmdb2i::index_read"); - - if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc); - - int rc; - - ha_rows estimatedRows = getIndexReadEstimate(active_index); - rc = prepReadBuffer(estimatedRows, db2Table->indexFile(active_index), readAccessIntent); - if (unlikely(rc)) DBUG_RETURN(rc); - - DBUG_ASSERT(activeReadBuf); - - keyBuf.allocBuf(activeReadBuf->getRowLength(), - activeReadBuf->getRowNullOffset(), - activeReadBuf->getRowLength()); - keyBuf.zeroBuf(); - - char* db2KeyBufPtr = keyBuf.ptr(); - char* nullKeyMap = db2KeyBufPtr + activeReadBuf->getRowNullOffset(); - - const uchar* keyBegin = key; - int partsInUse; - - KEY& curKey = table->key_info[active_index]; - - for (partsInUse = 0; partsInUse < curKey.key_parts, key - keyBegin < key_len; ++partsInUse) - { - Field* field = curKey.key_part[partsInUse].field; - if ((curKey.key_part[partsInUse].null_bit) && - (char*)key[0]) - { - if (field->flags & AUTO_INCREMENT_FLAG) - { - table->status = STATUS_NOT_FOUND; - DBUG_RETURN(HA_ERR_END_OF_FILE); - } - else - { - nullKeyMap[partsInUse] = __NULL_VALUE_EBCDIC; - } - } - else - { - nullKeyMap[partsInUse] = __NOT_NULL_VALUE_EBCDIC; - convertMySQLtoDB2(field, - db2Table->db2Field(field->field_index), - db2KeyBufPtr, - (uchar*)key+((curKey.key_part[partsInUse].null_bit)? 1 : 0) ); // + (curKey.key_parts+7) / 8); - } - - db2KeyBufPtr += db2Table->db2Field(field->field_index).getByteLengthInRecord(); - key += curKey.key_part[partsInUse].store_length; - } - - keyLen = db2KeyBufPtr - (char*)keyBuf.ptr(); - - DBUG_PRINT("ha_ibmdb2i::index_read", ("find_flag: %d", find_flag)); - - char readDirection = QMY_NEXT; - - switch (find_flag) - { - case HA_READ_AFTER_KEY: - doInitialRead(QMY_AFTER_EQUAL, estimatedRows, - keyBuf.ptr(), keyLen, partsInUse); - break; - case HA_READ_BEFORE_KEY: - doInitialRead(QMY_BEFORE_EQUAL, estimatedRows, - keyBuf.ptr(), keyLen, partsInUse); - break; - case HA_READ_KEY_OR_NEXT: - doInitialRead(QMY_AFTER_OR_EQUAL, estimatedRows, - keyBuf.ptr(), keyLen, partsInUse); - break; - case HA_READ_KEY_OR_PREV: - DBUG_ASSERT(0); // This function is unused - doInitialRead(QMY_BEFORE_OR_EQUAL, estimatedRows, - keyBuf.ptr(), keyLen, partsInUse); - break; - case HA_READ_PREFIX_LAST_OR_PREV: - doInitialRead(QMY_LAST_PREVIOUS, estimatedRows, - keyBuf.ptr(), keyLen, partsInUse); - readDirection = QMY_PREVIOUS; - break; - case HA_READ_PREFIX_LAST: - doInitialRead(QMY_PREFIX_LAST, estimatedRows, - keyBuf.ptr(), keyLen, partsInUse); - readDirection = QMY_PREVIOUS; - break; - case HA_READ_KEY_EXACT: - doInitialRead(QMY_EQUAL, estimatedRows, keyBuf.ptr(), keyLen, partsInUse); - break; - default: - DBUG_ASSERT(0); - return HA_ERR_GENERIC; - break; - } - - ha_statistic_increment(&SSV::ha_read_key_count); - rc = readFromBuffer(buf, readDirection); - - table->status= (rc ? STATUS_NOT_FOUND: 0); - DBUG_RETURN(rc); -} - - -int ha_ibmdb2i::index_next(uchar * buf) -{ - DBUG_ENTER("ha_ibmdb2i::index_next"); - ha_statistic_increment(&SSV::ha_read_next_count); - - int rc = readFromBuffer(buf, QMY_NEXT); - - table->status= (rc ? STATUS_NOT_FOUND: 0); - DBUG_RETURN(rc); -} - - -int ha_ibmdb2i::index_next_same(uchar *buf, const uchar *key, uint keylen) -{ - DBUG_ENTER("ha_ibmdb2i::index_next_same"); - ha_statistic_increment(&SSV::ha_read_next_count); - - int rc = readFromBuffer(buf, QMY_NEXT_EQUAL); - - if (rc == HA_ERR_KEY_NOT_FOUND) - { - rc = HA_ERR_END_OF_FILE; - } - - table->status= (rc ? STATUS_NOT_FOUND: 0); - DBUG_RETURN(rc); -} - -int ha_ibmdb2i::index_read_last(uchar * buf, const uchar * key, uint key_len) -{ - DBUG_ENTER("ha_ibmdb2i::index_read_last"); - DBUG_RETURN(index_read(buf, key, key_len, HA_READ_PREFIX_LAST)); -} - - - -int ha_ibmdb2i::index_prev(uchar * buf) -{ - DBUG_ENTER("ha_ibmdb2i::index_prev"); - ha_statistic_increment(&SSV::ha_read_prev_count); - - int rc = readFromBuffer(buf, QMY_PREVIOUS); - - table->status= (rc ? STATUS_NOT_FOUND: 0); - DBUG_RETURN(rc); -} - - -int ha_ibmdb2i::index_first(uchar * buf) -{ - DBUG_ENTER("ha_ibmdb2i::index_first"); - - if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc); - - int rc = prepReadBuffer(DEFAULT_MAX_ROWS_TO_BUFFER, - db2Table->indexFile(active_index), - readAccessIntent); - - if (rc == 0) - { - doInitialRead(QMY_FIRST, DEFAULT_MAX_ROWS_TO_BUFFER); - ha_statistic_increment(&SSV::ha_read_first_count); - rc = readFromBuffer(buf, QMY_NEXT); - } - - table->status= (rc ? STATUS_NOT_FOUND: 0); - DBUG_RETURN(rc); -} - - -int ha_ibmdb2i::index_last(uchar * buf) -{ - DBUG_ENTER("ha_ibmdb2i::index_last"); - - if (unlikely(last_index_init_rc)) DBUG_RETURN(last_index_init_rc); - - int rc = prepReadBuffer(DEFAULT_MAX_ROWS_TO_BUFFER, - db2Table->indexFile(active_index), - readAccessIntent); - - if (rc == 0) - { - doInitialRead(QMY_LAST, DEFAULT_MAX_ROWS_TO_BUFFER); - ha_statistic_increment(&SSV::ha_read_last_count); - rc = readFromBuffer(buf, QMY_PREVIOUS); - } - - table->status= (rc ? STATUS_NOT_FOUND: 0); - DBUG_RETURN(rc); -} - - -int ha_ibmdb2i::rnd_init(bool scan) -{ - DBUG_ENTER("ha_ibmdb2i::rnd_init"); - - int& rc = last_rnd_init_rc; - rc = 0; - - tweakReadSet(); - invalidDataFound=false; - - uint32 rowsToBlockOnRead; - - if (!scan) - { - rowsToBlockOnRead = 1; - } - else - { - rowsToBlockOnRead = DEFAULT_MAX_ROWS_TO_BUFFER; - } - - rc = useDataFile(); - - if (!rc) - { -// THD* thd = ha_thd(); -// if (accessIntent == QMY_UPDATABLE && -// thd_tx_isolation(thd) == ISO_REPEATABLE_READ && -// !THDVAR(thd, transaction_unsafe)) -// { -// readAccessIntent = QMY_READ_ONLY; -// } -// else -// { - readAccessIntent = accessIntent; -// } - - rc = prepReadBuffer(rowsToBlockOnRead, db2Table->dataFile(), readAccessIntent); - - if (!rc && accessIntent != QMY_READ_ONLY) - rc = prepWriteBuffer(1, db2Table->dataFile()); - - if (!rc && scan) - doInitialRead(QMY_FIRST, rowsToBlockOnRead); - - if (rc) - releaseDataFile(); - } - - rrnAssocHandle= 0; - - DBUG_RETURN(0); // MySQL sometimes does not check the return code, causing - // an assert in ha_rnd_end later on if we return a non-zero - // value here. -} - -int ha_ibmdb2i::rnd_end() -{ - DBUG_ENTER("ha_ibmdb2i::rnd_end"); - - warnIfInvalidData(); - if (likely(activeReadBuf)) - activeReadBuf->endRead(); - if (last_rnd_init_rc == 0) - releaseActiveHandle(); - last_rnd_init_rc = 0; - DBUG_RETURN(0); -} - - -int32 ha_ibmdb2i::mungeDB2row(uchar* record, const char* dataPtr, const char* nullMapPtr, bool skipLOBs) -{ - DBUG_ASSERT(dataPtr); - - my_bitmap_map *old_write_map= dbug_tmp_use_all_columns(table, table->write_set); - my_bitmap_map *old_read_map; - - if (unlikely(readAllColumns)) - old_read_map = tmp_use_all_columns(table, table->read_set); - - resetCharacterConversionBuffers(); - - my_ptrdiff_t old_ptr= (my_ptrdiff_t) (record - table->record[0]); - int fieldIndex = 0; - for (Field **field = table->field; *field; ++field, ++fieldIndex) - { - if (unlikely(old_ptr)) - (*field)->move_field_offset(old_ptr); - if (nullMapPtr[fieldIndex] == __NULL_VALUE_EBCDIC || - (!bitmap_is_set(table->read_set, fieldIndex)) || - (skipLOBs && db2Table->db2Field(fieldIndex).isBlob())) - { - (*field)->set_null(); - } - else - { - (*field)->set_notnull(); - convertDB2toMySQL(db2Table->db2Field(fieldIndex), *field, dataPtr); - } - if (unlikely(old_ptr)) - (*field)->move_field_offset(-old_ptr); - - } - - if (unlikely(readAllColumns)) - tmp_restore_column_map(table->read_set, old_read_map); - dbug_tmp_restore_column_map(table->write_set, old_write_map); - - return 0; -} - - -int ha_ibmdb2i::rnd_next(uchar *buf) -{ - DBUG_ENTER("ha_ibmdb2i::rnd_next"); - - if (unlikely(last_rnd_init_rc)) DBUG_RETURN(last_rnd_init_rc); - ha_statistic_increment(&SSV::ha_read_rnd_next_count); - - int rc; - - rc = readFromBuffer(buf, QMY_NEXT); - - table->status= (rc ? STATUS_NOT_FOUND: 0); - DBUG_RETURN(rc); -} - - -void ha_ibmdb2i::position(const uchar *record) -{ - DBUG_ENTER("ha_ibmdb2i::position"); - my_store_ptr(ref, ref_length, currentRRN); - DBUG_VOID_RETURN; -} - - -int ha_ibmdb2i::rnd_pos(uchar * buf, uchar *pos) -{ - DBUG_ENTER("ha_ibmdb2i::rnd_pos"); - if (unlikely(last_rnd_init_rc)) DBUG_RETURN( last_rnd_init_rc); - ha_statistic_increment(&SSV::ha_read_rnd_count); - - currentRRN = my_get_ptr(pos, ref_length); - - tweakReadSet(); - - int rc = 0; - - if (rrnAssocHandle && - (activeHandle != rrnAssocHandle)) - { - if (activeHandle) releaseActiveHandle(); - rc = useFileByHandle(QMY_UPDATABLE, rrnAssocHandle); - } - - if (likely(rc == 0)) - { - rc = prepReadBuffer(1, getFileForActiveHandle(), accessIntent); - - if (likely(rc == 0) && accessIntent == QMY_UPDATABLE) - rc = prepWriteBuffer(1, getFileForActiveHandle()); - - if (likely(rc == 0)) - { - rc = db2i_ileBridge::getBridgeForThread()->readByRRN(activeHandle, - activeReadBuf->ptr(), - currentRRN, - accessIntent, - getCommitLevel()); - - if (likely(rc == 0)) - { - rrnAssocHandle = activeHandle; - const char* readBuf = activeReadBuf->getRowN(0); - rc = mungeDB2row(buf, readBuf, readBuf + activeReadBuf->getRowNullOffset(), false); - releaseRowNeeded = TRUE; - } - } - } - - DBUG_RETURN(rc); -} - - -int ha_ibmdb2i::info(uint flag) -{ - DBUG_ENTER("ha_ibmdb2i::info"); - - uint16 infoRequested = 0; - ValidatedPointer rowKeySpcPtr; // Space pointer passed to DB2 - uint32 rowKeySpcLen; // Length of space passed to DB2 - THD* thd = ha_thd(); - int command = thd_sql_command(thd); - - if (flag & HA_STATUS_AUTO) - stats.auto_increment_value = (ulonglong) 0; - - if (flag & HA_STATUS_ERRKEY) - { - errkey = lastDupKeyID; - my_store_ptr(dup_ref, ref_length, lastDupKeyRRN); - } - - if (flag & HA_STATUS_TIME) - { - if ((flag & HA_STATUS_NO_LOCK) && - ibmdb2i_assume_exclusive_use && - share && - (share->cachedStats.isInited(lastModTime))) - stats.update_time = share->cachedStats.getUpdateTime(); - else - infoRequested |= lastModTime; - } - - if (flag & HA_STATUS_CONST) - { - stats.block_size=4096; - infoRequested |= createTime; - - if (table->s->keys) - { - infoRequested |= rowsPerKey; - rowKeySpcLen = (table->s->keys) * MAX_DB2_KEY_PARTS * sizeof(uint64); - rowKeySpcPtr.alloc(rowKeySpcLen); - memset(rowKeySpcPtr, 0, rowKeySpcLen); // Clear the allocated space - } - } - - if (flag & HA_STATUS_VARIABLE) - { - if ((flag & HA_STATUS_NO_LOCK) && - (command != SQLCOM_SHOW_TABLE_STATUS) && - ibmdb2i_assume_exclusive_use && - share && - (share->cachedStats.isInited(rowCount | deletedRowCount | meanRowLen | ioCount)) && - (share->cachedStats.getRowCount() >= 2)) - { - stats.records = share->cachedStats.getRowCount(); - stats.deleted = share->cachedStats.getDelRowCount(); - stats.mean_rec_length = share->cachedStats.getMeanLength(); - stats.data_file_length = share->cachedStats.getAugmentedDataLength(); - } - else - { - infoRequested |= rowCount | deletedRowCount | meanRowLen; - if (command == SQLCOM_SHOW_TABLE_STATUS) - infoRequested |= objLength; - else - infoRequested |= ioCount; - } - } - - int rc = 0; - - if (infoRequested) - { - DBUG_PRINT("ha_ibmdb2i::info",("Retrieving fresh stats %d", flag)); - - initBridge(thd); - rc = bridge()->retrieveTableInfo((dataHandle ? dataHandle : db2Table->dataFile()->getMasterDefnHandle()), - infoRequested, - stats, - rowKeySpcPtr); - - if (!rc) - { - if ((flag & HA_STATUS_VARIABLE) && - (command != SQLCOM_SHOW_TABLE_STATUS)) - stats.data_file_length = stats.data_file_length * IO_SIZE; - - if ((ibmdb2i_assume_exclusive_use) && - (share) && - (command != SQLCOM_SHOW_TABLE_STATUS)) - { - if (flag & HA_STATUS_VARIABLE) - { - share->cachedStats.cacheRowCount(stats.records); - share->cachedStats.cacheDelRowCount(stats.deleted); - share->cachedStats.cacheMeanLength(stats.mean_rec_length); - share->cachedStats.cacheAugmentedDataLength(stats.data_file_length); - } - - if (flag & HA_STATUS_TIME) - { - share->cachedStats.cacheUpdateTime(stats.update_time); - } - } - - if (flag & HA_STATUS_CONST) - { - ulong i; // Loop counter for indexes - ulong j; // Loop counter for key parts - RowKey* rowKeyPtr; // Pointer to 'number of unique rows' array for this index - - rowKeyPtr = (RowKey_t*)(void*)rowKeySpcPtr; // Address first array of DB2 row counts - for (i = 0; i < table->s->keys; i++) // Do for each index, including primary - { - for (j = 0; j < table->key_info[i].key_parts; j++) - { - table->key_info[i].rec_per_key[j]= rowKeyPtr->RowKeyArray[j]; - } - rowKeyPtr = rowKeyPtr + 1; // Address next array of DB2 row counts - } - } - } - else if (rc == HA_ERR_LOCK_WAIT_TIMEOUT && share) - { - // If we couldn't retrieve the info because the object was locked, - // we'll do our best by returning the most recently cached data. - if ((infoRequested & rowCount) && - share->cachedStats.isInited(rowCount)) - stats.records = share->cachedStats.getRowCount(); - if ((infoRequested & deletedRowCount) && - share->cachedStats.isInited(deletedRowCount)) - stats.deleted = share->cachedStats.getDelRowCount(); - if ((infoRequested & meanRowLen) && - share->cachedStats.isInited(meanRowLen)) - stats.mean_rec_length = share->cachedStats.getMeanLength(); - if ((infoRequested & lastModTime) && - share->cachedStats.isInited(lastModTime)) - stats.update_time = share->cachedStats.getUpdateTime(); - - rc = 0; - } - } - - DBUG_RETURN(rc); -} - - -ha_rows ha_ibmdb2i::records() -{ - DBUG_ENTER("ha_ibmdb2i::records"); - int rc; - rc = bridge()->retrieveTableInfo((dataHandle ? dataHandle : db2Table->dataFile()->getMasterDefnHandle()), - rowCount, - stats); - - if (unlikely(rc)) - { - if (rc == HA_ERR_LOCK_WAIT_TIMEOUT && - share && - (share->cachedStats.isInited(rowCount))) - DBUG_RETURN(share->cachedStats.getRowCount()); - else - DBUG_RETURN(HA_POS_ERROR); - } - else if (share) - { - share->cachedStats.cacheRowCount(stats.records); - } - - DBUG_RETURN(stats.records); -} - - -int ha_ibmdb2i::extra(enum ha_extra_function operation) -{ - DBUG_ENTER("ha_ibmdb2i::extra"); - - switch(operation) - { - // Can these first five flags be replaced by attending to HA_EXTRA_WRITE_CACHE? - case HA_EXTRA_NO_IGNORE_DUP_KEY: - case HA_EXTRA_WRITE_CANNOT_REPLACE: - { - returnDupKeysImmediately = false; - onDupUpdate = false; - } - break; - case HA_EXTRA_INSERT_WITH_UPDATE: - { - returnDupKeysImmediately = true; - onDupUpdate = true; - } - break; - case HA_EXTRA_IGNORE_DUP_KEY: - case HA_EXTRA_WRITE_CAN_REPLACE: - returnDupKeysImmediately = true; - break; - case HA_EXTRA_FLUSH_CACHE: - if (outstanding_start_bulk_insert) - finishBulkInsert(); - break; - } - - - DBUG_RETURN(0); -} - -/** - @brief - The DB2 storage engine will ignore a MySQL generated value and will generate - a new value in SLIC. We arbitrarily set first_value to 1, and set the - interval to infinity for better performance on multi-row inserts. -*/ -void ha_ibmdb2i::get_auto_increment(ulonglong offset, ulonglong increment, - ulonglong nb_desired_values, - ulonglong *first_value, - ulonglong *nb_reserved_values) -{ - DBUG_ENTER("ha_ibmdb2i::get_auto_increment"); - *first_value= 1; - *nb_reserved_values= ULONGLONG_MAX; -} - - - -void ha_ibmdb2i::update_create_info(HA_CREATE_INFO *create_info) -{ - DBUG_ENTER("ha_ibmdb2i::update_create_info"); - - if ((!(create_info->used_fields & HA_CREATE_USED_AUTO)) && - (table->found_next_number_field != NULL)) - { - initBridge(); - - create_info->auto_increment_value= 1; - - ha_rows rowCount = records(); - - if (rowCount == 0) - { - create_info->auto_increment_value = db2Table->getStartId(); - DBUG_VOID_RETURN; - } - else if (rowCount == HA_POS_ERROR) - { - DBUG_VOID_RETURN; - } - - getNextIdVal(&create_info->auto_increment_value); - } - DBUG_VOID_RETURN; -} - - -int ha_ibmdb2i::getNextIdVal(ulonglong *value) -{ - DBUG_ENTER("ha_ibmdb2i::getNextIdVal"); - - char queryBuffer[MAX_DB2_COLNAME_LENGTH + MAX_DB2_QUALIFIEDNAME_LENGTH + 64]; - strcpy(queryBuffer, " SELECT CAST(MAX( "); - convertMySQLNameToDB2Name(table->found_next_number_field->field_name, - strend(queryBuffer), - MAX_DB2_COLNAME_LENGTH+1); - strcat(queryBuffer, ") AS BIGINT) FROM "); - db2Table->getDB2QualifiedName(strend(queryBuffer)); - DBUG_ASSERT(strlen(queryBuffer) < sizeof(queryBuffer)); - - SqlStatementStream sqlStream(queryBuffer); - DBUG_PRINT("ha_ibmdb2i::getNextIdVal", ("Sent to DB2: %s",queryBuffer)); - - int rc = 0; - FILE_HANDLE fileHandle2; - uint32 db2RowDataLen2; - rc = bridge()->prepOpen(sqlStream.getPtrToData(), - &fileHandle2, - &db2RowDataLen2); - if (likely(rc == 0)) - { - IOReadBuffer rowBuffer(1, db2RowDataLen2); - rc = bridge()->read(fileHandle2, - rowBuffer.ptr(), - QMY_READ_ONLY, - QMY_NONE, - QMY_FIRST); - - if (likely(rc == 0)) - { - /* This check is here for the case where the table is not empty, - but the auto_increment starting value has been changed since - the last record was written. */ - - longlong maxIdVal = *(longlong*)(rowBuffer.getRowN(0)); - if ((maxIdVal + 1) > db2Table->getStartId()) - *value = maxIdVal + 1; - else - *value = db2Table->getStartId(); - } - - bridge()->deallocateFile(fileHandle2); - } - DBUG_RETURN(rc); -} - - -/* - Updates index cardinalities. -*/ -int ha_ibmdb2i::analyze(THD* thd, HA_CHECK_OPT *check_opt) -{ - DBUG_ENTER("ha_ibmdb2i::analyze"); - info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE); - DBUG_RETURN(0); -} - -int ha_ibmdb2i::optimize(THD* thd, HA_CHECK_OPT *check_opt) -{ - DBUG_ENTER("ha_ibmdb2i::optimize"); - - initBridge(thd); - - if (unlikely(records() == 0)) - DBUG_RETURN(0); // DB2 doesn't like to reorganize a table with no data. - - quiesceAllFileHandles(); - - int32 rc = bridge()->optimizeTable(db2Table->dataFile()->getMasterDefnHandle()); - info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE); - - DBUG_RETURN(rc); -} - - -/** - @brief - Determines if an ALTER TABLE is allowed to switch the storage engine - for this table. If the table has a foreign key or is referenced by a - foreign key, then it cannot be switched. -*/ -bool ha_ibmdb2i::can_switch_engines(void) -/*=================================*/ -{ - DBUG_ENTER("ha_ibmdb2i::can_switch_engines"); - - int rc = 0; - FILE_HANDLE queryFile = 0; - uint32 resultRowLen; - uint count = 0; - bool can_switch = FALSE; // 1 if changing storage engine is allowed - - const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL); - const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL); - - String query(256); - query.append(STRING_WITH_LEN(" SELECT COUNT(*) FROM SYSIBM.SQLFOREIGNKEYS WHERE ((PKTABLE_SCHEM = '")); - query.append(libName+1, strlen(libName)-2); // Remove quotes from parent schema name - query.append(STRING_WITH_LEN("' AND PKTABLE_NAME = '")); - query.append(fileName+1,strlen(fileName)-2); // Remove quotes from file name - query.append(STRING_WITH_LEN("') OR (FKTABLE_SCHEM = '")); - query.append(libName+1,strlen(libName)-2); // Remove quotes from child schema - query.append(STRING_WITH_LEN("' AND FKTABLE_NAME = '")); - query.append(fileName+1,strlen(fileName)-2); // Remove quotes from child 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 = *(uint*)(rowBuffer.getRowN(0)); - if (count == 0) - can_switch = TRUE; - } - - bridge()->deallocateFile(queryFile); - } - DBUG_RETURN(can_switch); -} - - - -bool ha_ibmdb2i::check_if_incompatible_data(HA_CREATE_INFO *info, - uint table_changes) -{ - DBUG_ENTER("ha_ibmdb2i::check_if_incompatible_data"); - uint i; - /* Check that auto_increment value and field definitions were - not changed. */ - if ((info->used_fields & HA_CREATE_USED_AUTO && - info->auto_increment_value != 0) || - table_changes != IS_EQUAL_YES) - DBUG_RETURN(COMPATIBLE_DATA_NO); - /* Check if any fields were renamed. */ - for (i= 0; i < table->s->fields; i++) - { - Field *field= table->field[i]; - if (field->flags & FIELD_IS_RENAMED) - { - DBUG_PRINT("info", ("Field has been renamed, copy table")); - DBUG_RETURN(COMPATIBLE_DATA_NO); - } - } - DBUG_RETURN(COMPATIBLE_DATA_YES); -} - -int ha_ibmdb2i::reset_auto_increment(ulonglong value) - { - DBUG_ENTER("ha_ibmdb2i::reset_auto_increment"); - - int rc = 0; - - quiesceAllFileHandles(); - - const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL); - const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL); - - String query(512); - query.append(STRING_WITH_LEN(" ALTER TABLE ")); - query.append(libName); - query.append('.'); - query.append(fileName); - query.append(STRING_WITH_LEN(" ALTER COLUMN ")); - char colName[MAX_DB2_COLNAME_LENGTH+1]; - convertMySQLNameToDB2Name(table->found_next_number_field->field_name, - colName, - sizeof(colName)); - query.append(colName); - - char restart_value[22]; - CHARSET_INFO *cs= &my_charset_bin; - uint len = (uint)(cs->cset->longlong10_to_str)(cs,restart_value,sizeof(restart_value), 10, value); - restart_value[len] = 0; - - query.append(STRING_WITH_LEN(" RESTART WITH ")); - query.append(restart_value); - - SqlStatementStream sqlStream(query); - DBUG_PRINT("ha_ibmdb2i::reset_auto_increment", ("Sent to DB2: %s",query.c_ptr())); - - rc = db2i_ileBridge::getBridgeForThread()->execSQL(sqlStream.getPtrToData(), - sqlStream.getStatementCount(), - QMY_NONE, //getCommitLevel(), - FALSE, - FALSE, - TRUE, //FALSE, - dataHandle); - if (rc == 0) - db2Table->updateStartId(value); - - DBUG_RETURN(rc); -} - - -/** - @brief - This function receives an error code that was previously set by the handler. - It returns to MySQL the error string associated with that error. -*/ -bool ha_ibmdb2i::get_error_message(int error, String *buf) -{ - DBUG_ENTER("ha_ibmdb2i::get_error_message"); - if ((error >= DB2I_FIRST_ERR && error <= DB2I_LAST_ERR) || - (error >= QMY_ERR_MIN && error <= QMY_ERR_MAX)) - { - db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread(ha_thd()); - char* errMsg = bridge->getErrorStorage(); - buf->copy(errMsg, strlen(errMsg),system_charset_info); - bridge->freeErrorStorage(); - } - DBUG_RETURN(FALSE); -} - - -int ha_ibmdb2i::delete_all_rows() -{ - DBUG_ENTER("ha_ibmdb2i::delete_all_rows"); - int rc = 0; - char queryBuffer[MAX_DB2_QUALIFIEDNAME_LENGTH + 64]; - strcpy(queryBuffer, " DELETE FROM "); - db2Table->getDB2QualifiedName(strend(queryBuffer)); - DBUG_ASSERT(strlen(queryBuffer) < sizeof(queryBuffer)); - - SqlStatementStream sqlStream(queryBuffer); - DBUG_PRINT("ha_ibmdb2i::delete_all_rows", ("Sent to DB2: %s",queryBuffer)); - rc = bridge()->execSQL(sqlStream.getPtrToData(), - sqlStream.getStatementCount(), - getCommitLevel(), - false, - false, - true, - dataHandle); - - /* If this method was called on behalf of a TRUNCATE TABLE statement, and if */ - /* the table has an auto_increment field, then reset the starting value for */ - /* the auto_increment field to 1. - */ - if (rc == 0 && thd_sql_command(ha_thd()) == SQLCOM_TRUNCATE && - table->found_next_number_field ) - rc = reset_auto_increment(1); - - invalidateCachedStats(); - - DBUG_RETURN(rc); -} - - -int ha_ibmdb2i::external_lock(THD *thd, int lock_type) -{ - int rc = 0; - - DBUG_ENTER("ha_ibmdb2i::external_lock"); - DBUG_PRINT("ha_ibmdb2i::external_lock",("Lock type: %d", lock_type)); - - if (lock_type == F_RDLCK) - accessIntent = QMY_READ_ONLY; - else if (lock_type == F_WRLCK) - accessIntent = QMY_UPDATABLE; - - initBridge(thd); - int command = thd_sql_command(thd); - - if (!THDVAR(thd,transaction_unsafe)) - { - if (lock_type != F_UNLCK) - { - if (autoCommitIsOn(thd) == QMY_YES) - { - trans_register_ha(thd, FALSE, ibmdb2i_hton); - } - else - { - trans_register_ha(thd, TRUE, ibmdb2i_hton); - if (likely(command != SQLCOM_CREATE_TABLE)) - { - trans_register_ha(thd, FALSE, ibmdb2i_hton); - bridge()->beginStmtTx(); - } - } - } - } - - if (command == SQLCOM_LOCK_TABLES || - command == SQLCOM_ALTER_TABLE || - command == SQLCOM_UNLOCK_TABLES || - (accessIntent == QMY_UPDATABLE && - (command == SQLCOM_UPDATE || - command == SQLCOM_UPDATE_MULTI || - command == SQLCOM_DELETE || - command == SQLCOM_DELETE_MULTI || - command == SQLCOM_REPLACE || - command == SQLCOM_REPLACE_SELECT) && - getCommitLevel(thd) == QMY_NONE)) - { - char action; - char type; - if (lock_type == F_UNLCK) - { - action = QMY_UNLOCK; - type = accessIntent == QMY_READ_ONLY ? QMY_LSRD : QMY_LENR; - } - else - { - action = QMY_LOCK; - type = lock_type == F_RDLCK ? QMY_LSRD : QMY_LENR; - } - - DBUG_PRINT("ha_ibmdb2i::external_lock",("%socking table", action==QMY_LOCK ? "L" : "Unl")); - - if (!dataHandle) - rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection); - - rc = bridge()->lockObj(dataHandle, - 0, - action, - type, - (command == SQLCOM_LOCK_TABLES ? QMY_NO : QMY_YES)); - - } - - // Cache this away so we don't have to access it on each row operation - cachedZeroDateOption = (enum_ZeroDate)THDVAR(thd, compat_opt_allow_zero_date_vals); - - DBUG_RETURN(rc); -} - - -THR_LOCK_DATA **ha_ibmdb2i::store_lock(THD *thd, - THR_LOCK_DATA **to, - enum thr_lock_type lock_type) -{ - if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) - { - if ((lock_type >= TL_WRITE_CONCURRENT_INSERT && - lock_type <= TL_WRITE) && !(thd->in_lock_tables && thd_sql_command(thd) == SQLCOM_LOCK_TABLES)) - lock_type= TL_WRITE_ALLOW_WRITE; - lock.type=lock_type; - } - *to++= &lock; - return to; -} - - -int ha_ibmdb2i::delete_table(const char *name) -{ - DBUG_ENTER("ha_ibmdb2i::delete_table"); - THD* thd = ha_thd(); - db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread(thd); - - char db2Name[MAX_DB2_QUALIFIEDNAME_LENGTH]; - db2i_table::getDB2QualifiedNameFromPath(name, db2Name); - - String query(128); - query.append(STRING_WITH_LEN(" DROP TABLE ")); - query.append(db2Name); - - if (thd_sql_command(thd) == SQLCOM_DROP_TABLE && - thd->lex->drop_mode == DROP_RESTRICT) - query.append(STRING_WITH_LEN(" RESTRICT ")); - DBUG_PRINT("ha_ibmdb2i::delete_table", ("Sent to DB2: %s",query.c_ptr())); - - SqlStatementStream sqlStream(query); - - db2i_table::getDB2LibNameFromPath(name, db2Name); - bool isTemporary = (strcmp(db2Name, DB2I_TEMP_TABLE_SCHEMA) == 0 ? TRUE : FALSE); - - int rc = bridge->execSQL(sqlStream.getPtrToData(), - sqlStream.getStatementCount(), - (isTemporary ? QMY_NONE : getCommitLevel(thd)), - FALSE, - FALSE, - isTemporary); - - if (rc == HA_ERR_NO_SUCH_TABLE) - { - warning(thd, DB2I_ERR_TABLE_NOT_FOUND, name); - rc = 0; - } - - if (rc == 0) - { - db2i_table::deleteAssocFiles(name); - } - - FILE_HANDLE savedHandle = bridge->findAndRemovePreservedHandle(name, &share); - while (savedHandle) - { - bridge->deallocateFile(savedHandle, TRUE); - DBUG_ASSERT(share); - if (free_share(share)) - share = NULL; - savedHandle = bridge->findAndRemovePreservedHandle(name, &share); - } - - my_errno = rc; - DBUG_RETURN(rc); -} - - -int ha_ibmdb2i::rename_table(const char * from, const char * to) -{ - DBUG_ENTER("ha_ibmdb2i::rename_table "); - - char db2FromFileName[MAX_DB2_FILENAME_LENGTH + 1]; - char db2ToFileName[MAX_DB2_FILENAME_LENGTH+1]; - char db2FromLibName[MAX_DB2_SCHEMANAME_LENGTH+1]; - char db2ToLibName[MAX_DB2_SCHEMANAME_LENGTH+1]; - - db2i_table::getDB2LibNameFromPath(from, db2FromLibName); - db2i_table::getDB2LibNameFromPath(to, db2ToLibName); - - if (strcmp(db2FromLibName, db2ToLibName) != 0 ) - { - getErrTxt(DB2I_ERR_RENAME_MOVE,from,to); - DBUG_RETURN(DB2I_ERR_RENAME_MOVE); - } - - db2i_table::getDB2FileNameFromPath(from, db2FromFileName, db2i_table::ASCII_NATIVE); - db2i_table::getDB2FileNameFromPath(to, db2ToFileName); - - char escapedFromFileName[2 * MAX_DB2_FILENAME_LENGTH + 1]; - - uint o = 0; - uint i = 1; - do - { - escapedFromFileName[o++] = db2FromFileName[i]; - if (db2FromFileName[i] == '+') - escapedFromFileName[o++] = '+'; - } while (db2FromFileName[++i]); - escapedFromFileName[o-1] = 0; - - - int rc = 0; - - char queryBuffer[sizeof(db2FromLibName) + 2 * sizeof(db2FromFileName) + 256]; - SafeString selectQuery(queryBuffer, sizeof(queryBuffer)); - selectQuery.strncat(STRING_WITH_LEN("SELECT CAST(INDEX_NAME AS VARCHAR(128) CCSID 1208) FROM QSYS2.SYSINDEXES WHERE INDEX_NAME LIKE '%+_+_+_%")); - selectQuery.strcat(escapedFromFileName); - selectQuery.strncat(STRING_WITH_LEN("' ESCAPE '+' AND TABLE_NAME='")); - selectQuery.strncat(db2FromFileName+1, strlen(db2FromFileName)-2); - selectQuery.strncat(STRING_WITH_LEN("' AND TABLE_SCHEMA='")); - selectQuery.strncat(db2FromLibName+1, strlen(db2FromLibName)-2); - selectQuery.strcat('\''); - DBUG_ASSERT(!selectQuery.overflowed()); - - SqlStatementStream indexQuery(selectQuery.ptr()); - - FILE_HANDLE queryFile = 0; - uint32 resultRowLen; - - initBridge(); - rc = bridge()->prepOpen(indexQuery.getPtrToData(), - &queryFile, - &resultRowLen); - - if (unlikely(rc)) - DBUG_RETURN(rc); - - IOReadBuffer rowBuffer(1, resultRowLen); - - int tableNameLen = strlen(db2FromFileName) - 2; - - SqlStatementStream renameQuery(64); - String query; - while (rc == 0) - { - query.length(0); - - rc = bridge()->read(queryFile, - rowBuffer.ptr(), - QMY_READ_ONLY, - QMY_NONE, - QMY_NEXT); - - if (!rc) - { - const char* rowData = rowBuffer.getRowN(0); - char indexFileName[MAX_DB2_FILENAME_LENGTH]; - memset(indexFileName, 0, sizeof(indexFileName)); - - uint16 fileNameLen = *(uint16*)(rowData); - strncpy(indexFileName, rowData + sizeof(uint16), fileNameLen); - - int bytesToRetain = fileNameLen - tableNameLen; - if (bytesToRetain <= 0) - /* We can't handle index names in which the MySQL index name and - the table name together are longer than the max index name. */ - { - getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*"); - DBUG_RETURN(DB2I_ERR_INVALID_NAME); - } - char indexName[MAX_DB2_FILENAME_LENGTH]; - memset(indexName, 0, sizeof(indexName)); - - strncpy(indexName, - indexFileName, - bytesToRetain); - - char db2IndexName[MAX_DB2_FILENAME_LENGTH+1]; - - convertMySQLNameToDB2Name(indexFileName, db2IndexName, sizeof(db2IndexName)); - - query.append(STRING_WITH_LEN("RENAME INDEX ")); - query.append(db2FromLibName); - query.append('.'); - query.append(db2IndexName); - query.append(STRING_WITH_LEN(" TO ")); - if (db2i_table::appendQualifiedIndexFileName(indexName, db2ToFileName, query, db2i_table::ASCII_SQL, typeNone) == -1) - { - getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*"); - DBUG_RETURN(DB2I_ERR_INVALID_NAME ); - } - renameQuery.addStatement(query); - DBUG_PRINT("ha_ibmdb2i::rename_table", ("Sent to DB2: %s",query.c_ptr_safe())); - } - } - - - if (queryFile) - bridge()->deallocateFile(queryFile); - - if (rc != HA_ERR_END_OF_FILE) - DBUG_RETURN(rc); - - char db2Name[MAX_DB2_QUALIFIEDNAME_LENGTH]; - - /* Rename the table */ - query.length(0); - query.append(STRING_WITH_LEN(" RENAME TABLE ")); - db2i_table::getDB2QualifiedNameFromPath(from, db2Name); - query.append(db2Name); - query.append(STRING_WITH_LEN(" TO ")); - query.append(db2ToFileName); - DBUG_PRINT("ha_ibmdb2i::rename_table", ("Sent to DB2: %s",query.c_ptr_safe())); - renameQuery.addStatement(query); - rc = bridge()->execSQL(renameQuery.getPtrToData(), - renameQuery.getStatementCount(), - getCommitLevel()); - - if (!rc) - db2i_table::renameAssocFiles(from, to); - - DBUG_RETURN(rc); -} - - -int ha_ibmdb2i::create(const char *name, TABLE *table_arg, - HA_CREATE_INFO *create_info) -{ - DBUG_ENTER("ha_ibmdb2i::create"); - - int rc; - char fileSortSequence[11] = "*HEX"; - char fileSortSequenceLibrary[11] = ""; - char fileSortSequenceType = ' '; - char libName[MAX_DB2_SCHEMANAME_LENGTH+1]; - char fileName[MAX_DB2_FILENAME_LENGTH+1]; - char colName[MAX_DB2_COLNAME_LENGTH+1]; - bool isTemporary; - ulong auto_inc_value; - - db2i_table::getDB2LibNameFromPath(name, libName); - db2i_table::getDB2FileNameFromPath(name, fileName); - - if (osVersion.v < 6) - { - if (strlen(libName) > - MAX_DB2_V5R4_LIBNAME_LENGTH + (isOrdinaryIdentifier(libName) ? 2 : 0)) - { - getErrTxt(DB2I_ERR_TOO_LONG_SCHEMA,libName, MAX_DB2_V5R4_LIBNAME_LENGTH); - DBUG_RETURN(DB2I_ERR_TOO_LONG_SCHEMA); - } - } - else if (strlen(libName) > MAX_DB2_V6R1_LIBNAME_LENGTH) - { - getErrTxt(DB2I_ERR_TOO_LONG_SCHEMA,libName, MAX_DB2_V6R1_LIBNAME_LENGTH); - DBUG_RETURN(DB2I_ERR_TOO_LONG_SCHEMA); - } - - String query(256); - - if (strcmp(libName, DB2I_TEMP_TABLE_SCHEMA)) - { - query.append(STRING_WITH_LEN("CREATE TABLE ")); - query.append(libName); - query.append('.'); - query.append(fileName); - isTemporary = FALSE; - } - else - { - query.append(STRING_WITH_LEN("DECLARE GLOBAL TEMPORARY TABLE ")); - query.append(fileName); - isTemporary = TRUE; - } - query.append(STRING_WITH_LEN(" (")); - - THD* thd = ha_thd(); - enum_TimeFormat timeFormat = (enum_TimeFormat)(THDVAR(thd, compat_opt_time_as_duration)); - enum_YearFormat yearFormat = (enum_YearFormat)(THDVAR(thd, compat_opt_year_as_int)); - enum_BlobMapping blobMapping = (enum_BlobMapping)(THDVAR(thd, compat_opt_blob_cols)); - enum_ZeroDate zeroDate = (enum_ZeroDate)(THDVAR(thd, compat_opt_allow_zero_date_vals)); - bool propagateDefaults = THDVAR(thd, propagate_default_col_vals); - - Field **field; - for (field= table_arg->field; *field; field++) - { - if ( field != table_arg->field ) // Not the first one - query.append(STRING_WITH_LEN(" , ")); - - if (!convertMySQLNameToDB2Name((*field)->field_name, colName, sizeof(colName))) - { - getErrTxt(DB2I_ERR_INVALID_NAME,"field",(*field)->field_name); - DBUG_RETURN(DB2I_ERR_INVALID_NAME ); - } - - query.append(colName); - query.append(' '); - - if (rc = getFieldTypeMapping(*field, - query, - timeFormat, - blobMapping, - zeroDate, - propagateDefaults, - yearFormat)) - DBUG_RETURN(rc); - - if ( (*field)->flags & NOT_NULL_FLAG ) - { - query.append(STRING_WITH_LEN(" NOT NULL ")); - } - if ( (*field)->flags & AUTO_INCREMENT_FLAG ) - { -#ifdef WITH_PARTITION_STORAGE_ENGINE - if (table_arg->part_info) - { - getErrTxt(DB2I_ERR_PART_AUTOINC); - DBUG_RETURN(DB2I_ERR_PART_AUTOINC); - } -#endif - query.append(STRING_WITH_LEN(" GENERATED BY DEFAULT AS IDENTITY ") ); - if (create_info->auto_increment_value != 0) - { - /* Query was ALTER TABLE...AUTO_INCREMENT = x; or - CREATE TABLE ...AUTO_INCREMENT = x; Set the starting - value for the auto_increment column. */ - char stringValue[22]; - CHARSET_INFO *cs= &my_charset_bin; - uint len = (uint)(cs->cset->longlong10_to_str)(cs,stringValue,sizeof(stringValue), 10, create_info->auto_increment_value); - stringValue[len] = 0; - query.append(STRING_WITH_LEN(" (START WITH ")); - query.append(stringValue); - - uint64 maxValue=maxValueForField(*field); - - if (maxValue) - { - len = (uint)(cs->cset->longlong10_to_str)(cs,stringValue,sizeof(stringValue), 10, maxValue); - stringValue[len] = 0; - query.append(STRING_WITH_LEN(" MAXVALUE ")); - query.append(stringValue); - } - - query.append(STRING_WITH_LEN(") ")); - } - - } - } - - String fieldDefinition(128); - - if (table_arg->s->primary_key != MAX_KEY && !isTemporary) - { - query.append(STRING_WITH_LEN(", PRIMARY KEY ")); - rc = buildIndexFieldList(fieldDefinition, - table_arg->key_info[table_arg->s->primary_key], - true, - &fileSortSequenceType, - fileSortSequence, - fileSortSequenceLibrary); - if (rc) DBUG_RETURN(rc); - query.append(fieldDefinition); - } - - rc = buildDB2ConstraintString(thd->lex, - query, - name, - table_arg->field, - &fileSortSequenceType, - fileSortSequence, - fileSortSequenceLibrary); - if (rc) DBUG_RETURN (rc); - - query.append(STRING_WITH_LEN(" ) ")); - - if (isTemporary) - query.append(STRING_WITH_LEN(" ON COMMIT PRESERVE ROWS ")); - - if (create_info->alias) - generateAndAppendRCDFMT(create_info->alias, query); - else if (((TABLE_LIST*)(thd->lex->select_lex.table_list.first))->table_name) - generateAndAppendRCDFMT((char*)((TABLE_LIST*)(thd->lex->select_lex.table_list.first))->table_name, query); - - DBUG_PRINT("ha_ibmdb2i::create", ("Sent to DB2: %s",query.c_ptr())); - SqlStatementStream sqlStream(query.length()); - sqlStream.addStatement(query,fileSortSequence,fileSortSequenceLibrary); - - if (table_arg->s->primary_key != MAX_KEY && - !isTemporary && - (THDVAR(thd, create_index_option)==1) && - (fileSortSequenceType != 'B') && - (fileSortSequenceType != ' ')) - { - rc = generateShadowIndex(sqlStream, - table_arg->key_info[table_arg->s->primary_key], - libName, - fileName, - fieldDefinition); - if (rc) DBUG_RETURN(rc); - } - for (uint i = 0; i < table_arg->s->keys; ++i) - { - if (i != table_arg->s->primary_key || isTemporary) - { - rc = buildCreateIndexStatement(sqlStream, - table_arg->key_info[i], - false, - libName, - fileName); - if (rc) DBUG_RETURN (rc); - } - } - - bool noCommit = isTemporary || ((!autoCommitIsOn(thd)) && (thd_sql_command(thd) == SQLCOM_ALTER_TABLE)); - - initBridge(); - -// if (THDVAR(thd, discovery_mode) == 1) -// bridge()->expectErrors(QMY_ERR_TABLE_EXISTS); - - rc = bridge()->execSQL(sqlStream.getPtrToData(), - sqlStream.getStatementCount(), - (isTemporary ? QMY_NONE : getCommitLevel(thd)), - TRUE, - FALSE, - noCommit ); - - if (unlikely(rc == QMY_ERR_MSGID) && - memcmp(bridge()->getErrorMsgID(), DB2I_SQL0350, 7) == 0) - { - my_error(ER_BLOB_USED_AS_KEY, MYF(0), "*unknown*"); - rc = ER_BLOB_USED_AS_KEY; - } -/* else if (unlikely(rc == QMY_ERR_TABLE_EXISTS) && - THDVAR(thd, discovery_mode) == 1) - { - db2i_table* temp = new db2i_table(table_arg->s, name); - int32 rc = temp->fastInitForCreate(name); - delete temp; - - if (!rc) - warning(thd, DB2I_ERR_WARN_CREATE_DISCOVER); - - DBUG_RETURN(rc); - } -*/ - - if (!rc && !isTemporary) - { - db2i_table* temp = new db2i_table(table_arg->s, name); - rc = temp->fastInitForCreate(name); - delete temp; - if (rc) - delete_table(name); - } - - DBUG_RETURN(rc); -} - - -/** - @brief - Add an index on-line to a table. This method is called on behalf of - a CREATE INDEX or ALTER TABLE statement. - It is implemented via a composed DDL statement passed to DB2. -*/ -int ha_ibmdb2i::add_index(TABLE *table_arg, - KEY *key_info, - uint num_of_keys) -{ - DBUG_ENTER("ha_ibmdb2i::add_index"); - - int rc; - SqlStatementStream sqlStream(256); - const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL); - const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL); - - quiesceAllFileHandles(); - - uint primaryKey = MAX_KEY; - if (table_arg->s->primary_key >= MAX_KEY && !db2Table->isTemporary()) - { - for (int i = 0; i < num_of_keys; ++i) - { - if (strcmp(key_info[i].name, "PRIMARY") == 0) - { - primaryKey = i; - break; - } - else if (primaryKey == MAX_KEY && - key_info[i].flags & HA_NOSAME) - { - primaryKey = i; - for (int j=0 ; j < key_info[i].key_parts ;j++) - { - uint fieldnr= key_info[i].key_part[j].fieldnr; - if (table_arg->s->field[fieldnr]->null_ptr || - table_arg->s->field[fieldnr]->key_length() != - key_info[i].key_part[j].length) - { - primaryKey = MAX_KEY; - break; - } - } - } - } - } - - - for (int i = 0; i < num_of_keys; ++i) - { - KEY& curKey= key_info[i]; - rc = buildCreateIndexStatement(sqlStream, - curKey, - (i == primaryKey), - libName, - fileName); - if (rc) DBUG_RETURN (rc); - } - - rc = bridge()->execSQL(sqlStream.getPtrToData(), - sqlStream.getStatementCount(), - getCommitLevel(), - FALSE, - FALSE, - FALSE, - dataHandle); - - /* Handle the case where a unique index is being created but an error occurs - because the file contains duplicate key values. */ - if (rc == ER_DUP_ENTRY) - print_keydup_error(MAX_KEY,ER(ER_DUP_ENTRY_WITH_KEY_NAME)); - - DBUG_RETURN(rc); -} - -/** - @brief - Drop an index on-line from a table. This method is called on behalf of - a DROP INDEX or ALTER TABLE statement. - It is implemented via a composed DDL statement passed to DB2. -*/ -int ha_ibmdb2i::prepare_drop_index(TABLE *table_arg, - uint *key_num, uint num_of_keys) -{ - DBUG_ENTER("ha_ibmdb2i::prepare_drop_index"); - int rc; - int i = 0; - String query(64); - SqlStatementStream sqlStream(64 * num_of_keys); - SqlStatementStream shadowStream(64 * num_of_keys); - - quiesceAllFileHandles(); - - const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL); - const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL); - - while (i < num_of_keys) - { - query.length(0); - DBUG_PRINT("info", ("ha_ibmdb2i::prepare_drop_index %u", key_num[i])); - KEY& curKey= table_arg->key_info[key_num[i]]; - if (key_num[i] == table->s->primary_key && !db2Table->isTemporary()) - { - query.append(STRING_WITH_LEN("ALTER TABLE ")); - query.append(libName); - query.append(STRING_WITH_LEN(".")); - query.append(fileName); - query.append(STRING_WITH_LEN(" DROP PRIMARY KEY")); - } - else - { - query.append(STRING_WITH_LEN("DROP INDEX ")); - query.append(libName); - query.append(STRING_WITH_LEN(".")); - db2i_table::appendQualifiedIndexFileName(curKey.name, fileName, query); - } - DBUG_PRINT("ha_ibmdb2i::prepare_drop_index", ("Sent to DB2: %s",query.c_ptr_safe())); - sqlStream.addStatement(query); - - query.length(0); - query.append(STRING_WITH_LEN("DROP INDEX ")); - query.append(libName); - query.append(STRING_WITH_LEN(".")); - db2i_table::appendQualifiedIndexFileName(curKey.name, fileName, query, db2i_table::ASCII_SQL, typeHex); - - DBUG_PRINT("ha_ibmdb2i::prepare_drop_index", ("Sent to DB2: %s",query.c_ptr_safe())); - shadowStream.addStatement(query); - - ++i; - } - - rc = bridge()->execSQL(sqlStream.getPtrToData(), - sqlStream.getStatementCount(), - getCommitLevel(), - FALSE, - FALSE, - FALSE, - dataHandle); - - if (rc == 0) - bridge()->execSQL(shadowStream.getPtrToData(), - shadowStream.getStatementCount(), - getCommitLevel()); - - DBUG_RETURN(rc); -} - - -void -ha_ibmdb2i::unlock_row() -{ - DBUG_ENTER("ha_ibmdb2i::unlock_row"); - DBUG_VOID_RETURN; -} - -int -ha_ibmdb2i::index_end() -{ - DBUG_ENTER("ha_ibmdb2i::index_end"); - warnIfInvalidData(); - last_index_init_rc = 0; - if (likely(activeReadBuf)) - activeReadBuf->endRead(); - if (likely(!last_index_init_rc)) - releaseIndexFile(active_index); - active_index= MAX_KEY; - DBUG_RETURN (0); -} - -int ha_ibmdb2i::doCommit(handlerton *hton, THD *thd, bool all) -{ - if (!THDVAR(thd, transaction_unsafe)) - { - if (all || autoCommitIsOn(thd)) - { - DBUG_PRINT("ha_ibmdb2i::doCommit",("Committing all")); - return (db2i_ileBridge::getBridgeForThread(thd)->commitmentControl(QMY_COMMIT)); - } - else - { - DBUG_PRINT("ha_ibmdb2i::doCommit",("Committing stmt")); - return (db2i_ileBridge::getBridgeForThread(thd)->commitStmtTx()); - } - } - - return (0); -} - - -int ha_ibmdb2i::doRollback(handlerton *hton, THD *thd, bool all) -{ - if (!THDVAR(thd,transaction_unsafe)) - { - if (all || autoCommitIsOn(thd)) - { - DBUG_PRINT("ha_ibmdb2i::doRollback",("Rolling back all")); - return ( db2i_ileBridge::getBridgeForThread(thd)->commitmentControl(QMY_ROLLBACK)); - } - else - { - DBUG_PRINT("ha_ibmdb2i::doRollback",("Rolling back stmt")); - return (db2i_ileBridge::getBridgeForThread(thd)->rollbackStmtTx()); - } - } - return (0); -} - - -void ha_ibmdb2i::start_bulk_insert(ha_rows rows) -{ - DBUG_ENTER("ha_ibmdb2i::start_bulk_insert"); - DBUG_PRINT("ha_ibmdb2i::start_bulk_insert",("Rows hinted %d", rows)); - int rc; - THD* thd = ha_thd(); - int command = thd_sql_command(thd); - - if (db2Table->hasBlobs() || - (command == SQLCOM_REPLACE || command == SQLCOM_REPLACE_SELECT)) - rows = 1; - else if (rows == 0) - rows = DEFAULT_MAX_ROWS_TO_BUFFER; // Shoot the moon - - // If we're doing a multi-row insert, binlogging is active, and the table has an - // auto_increment column, then we'll attempt to lock the file while we perform a 'fast path' blocked - // insert. If we can't get the lock, then we'll do a row-by-row 'slow path' insert instead. The reason is - // because the MI generates the auto_increment (identity value), and if we can't lock the file, - // then we can't predetermine what that value will be for insertion into the MySQL write buffer. - - if ((rows > 1) && // Multi-row insert - (thd->options & OPTION_BIN_LOG) && // Binlogging is on - (table->found_next_number_field)) // Table has an auto_increment column - { - if (!dataHandle) - rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection); - - rc = bridge()->lockObj(dataHandle, 1, QMY_LOCK, QMY_LEAR, QMY_YES); - if (rc==0) // Got the lock - { - autoIncLockAcquired = TRUE; - got_auto_inc_values = FALSE; - } - else // Didn't get the lock - rows = 1; // No problem, but don't block inserts - } - - if (activeHandle == 0) - { - last_start_bulk_insert_rc = useDataFile(); - if (last_start_bulk_insert_rc == 0) - last_start_bulk_insert_rc = prepWriteBuffer(rows, db2Table->dataFile()); - } - - if (last_start_bulk_insert_rc == 0) - outstanding_start_bulk_insert = true; - else - { - if (autoIncLockAcquired == TRUE) - { - bridge()->lockObj(dataHandle, 0, QMY_UNLOCK, QMY_LEAR, QMY_YES); - autoIncLockAcquired = FALSE; - } - } - - DBUG_VOID_RETURN; -} - - -int ha_ibmdb2i::end_bulk_insert() -{ - DBUG_ENTER("ha_ibmdb2i::end_bulk_insert"); - int rc = 0; - - if (outstanding_start_bulk_insert) - { - rc = finishBulkInsert(); - } - - my_errno = rc; - - DBUG_RETURN(rc); -} - - -int ha_ibmdb2i::prepReadBuffer(ha_rows rowsToRead, const db2i_file* file, char intent) -{ - DBUG_ENTER("ha_ibmdb2i::prepReadBuffer"); - DBUG_ASSERT(rowsToRead > 0); - - THD* thd = ha_thd(); - char cmtLvl = getCommitLevel(thd); - - const db2i_file::RowFormat* format; - int rc = file->obtainRowFormat(activeHandle, intent, cmtLvl, &format); - - if (unlikely(rc)) DBUG_RETURN(rc); - - if (lobFieldsRequested()) - { - forceSingleRowRead = true; - rowsToRead = 1; - } - - rowsToRead = min(stats.records+1,min(rowsToRead, DEFAULT_MAX_ROWS_TO_BUFFER)); - - uint bufSize = min((format->readRowLen * rowsToRead), THDVAR(thd, max_read_buffer_size)); - multiRowReadBuf.allocBuf(format->readRowLen, format->readRowNullOffset, bufSize); - activeReadBuf = &multiRowReadBuf; - - if (db2Table->hasBlobs()) - { - if (!blobReadBuffers) - blobReadBuffers = new BlobCollection(db2Table, THDVAR(thd, lob_alloc_size)); - rc = prepareReadBufferForLobs(); - if (rc) DBUG_RETURN(rc); - } - -// if (accessIntent == QMY_UPDATABLE && -// thd_tx_isolation(thd) == ISO_REPEATABLE_READ && -// !THDVAR(thd, transaction_unsafe)) -// activeReadBuf->update(QMY_READ_ONLY, &releaseRowNeeded, QMY_REPEATABLE_READ); -// else - activeReadBuf->update(intent, &releaseRowNeeded, cmtLvl); - - DBUG_RETURN(rc); -} - - -int ha_ibmdb2i::prepWriteBuffer(ha_rows rowsToWrite, const db2i_file* file) -{ - DBUG_ENTER("ha_ibmdb2i::prepWriteBuffer"); - DBUG_ASSERT(accessIntent == QMY_UPDATABLE && rowsToWrite > 0); - - const db2i_file::RowFormat* format; - int rc = file->obtainRowFormat(activeHandle, - QMY_UPDATABLE, - getCommitLevel(ha_thd()), - &format); - - if (unlikely(rc)) DBUG_RETURN(rc); - - rowsToWrite = min(rowsToWrite, DEFAULT_MAX_ROWS_TO_BUFFER); - - uint bufSize = min((format->writeRowLen * rowsToWrite), THDVAR(ha_thd(), max_write_buffer_size)); - multiRowWriteBuf.allocBuf(format->writeRowLen, format->writeRowNullOffset, bufSize); - activeWriteBuf = &multiRowWriteBuf; - - if (!blobWriteBuffers && db2Table->hasBlobs()) - { - blobWriteBuffers = new ValidatedPointer[db2Table->getBlobCount()]; - } - DBUG_RETURN(rc); -} - - -int ha_ibmdb2i::flushWrite(FILE_HANDLE fileHandle, uchar* buf ) -{ - DBUG_ENTER("ha_ibmdb2i::flushWrite"); - int rc; - int64 generatedIdValue = 0; - bool IdValueWasGenerated = FALSE; - char* lastDupKeyNamePtr = NULL; - uint32 lastDupKeyNameLen = 0; - int loopCnt = 0; - bool retry_dup = FALSE; - - while (loopCnt == 0 || retry_dup == TRUE) - { - rc = bridge()->writeRows(fileHandle, - activeWriteBuf->ptr(), - getCommitLevel(), - &generatedIdValue, - &IdValueWasGenerated, - &lastDupKeyRRN, - &lastDupKeyNamePtr, - &lastDupKeyNameLen, - &incrementByValue); - loopCnt++; - retry_dup = FALSE; - invalidateCachedStats(); - if (lastDupKeyNameLen) - { - rrnAssocHandle = fileHandle; - - int command = thd_sql_command(ha_thd()); - - if (command == SQLCOM_REPLACE || - command == SQLCOM_REPLACE_SELECT) - lastDupKeyID = 0; - else - { - lastDupKeyID = getKeyFromName(lastDupKeyNamePtr, lastDupKeyNameLen); - - if (likely(lastDupKeyID != MAX_KEY)) - { - uint16 failedRow = activeWriteBuf->rowsWritten()+1; - - if (buf && (failedRow != activeWriteBuf->rowCount())) - { - const char* badRow = activeWriteBuf->getRowN(failedRow-1); - bool savedReadAllColumns = readAllColumns; - readAllColumns = true; - mungeDB2row(buf, - badRow, - badRow + activeWriteBuf->getRowNullOffset(), - true); - readAllColumns = savedReadAllColumns; - - if (table->found_next_number_field) - { - table->next_number_field->store(next_identity_value - (incrementByValue * (activeWriteBuf->rowCount() - (failedRow - 1)))); - } - } - - if (default_identity_value && // Table has ID colm and generating a value - (!autoIncLockAcquired || !got_auto_inc_values) && - // Writing first or only row in block - loopCnt == 1 && // Didn't already retry - lastDupKeyID == table->s->next_number_index) // Autoinc column is in failed index - { - if (alterStartWith() == 0) // Reset next Identity value to max+1 - retry_dup = TRUE; // Rtry the write operation - } - } - else - { - char unknownIndex[MAX_DB2_FILENAME_LENGTH+1]; - convFromEbcdic(lastDupKeyNamePtr, unknownIndex, min(lastDupKeyNameLen, MAX_DB2_FILENAME_LENGTH)); - unknownIndex[min(lastDupKeyNameLen, MAX_DB2_FILENAME_LENGTH)] = 0; - getErrTxt(DB2I_ERR_UNKNOWN_IDX, unknownIndex); - } - } - } - } - - if ((rc == 0 || rc == HA_ERR_FOUND_DUPP_KEY) - && default_identity_value && IdValueWasGenerated && - (!autoIncLockAcquired || !got_auto_inc_values)) - { - /* Save the generated identity value for the MySQL last_insert_id() function. */ - insert_id_for_cur_row = generatedIdValue; - - /* Store the value into MySQL's buf for row-based replication - or for an 'on duplicate key update' clause. */ - table->next_number_field->store((longlong) generatedIdValue, TRUE); - if (autoIncLockAcquired) - { - got_auto_inc_values = TRUE; - next_identity_value = generatedIdValue + incrementByValue; - } - } - else - { - if (!autoIncLockAcquired) // Don't overlay value for first row of a block - insert_id_for_cur_row = 0; - } - - - activeWriteBuf->resetAfterWrite(); - DBUG_RETURN(rc); -} - -int ha_ibmdb2i::alterStartWith() -{ - DBUG_ENTER("ha_ibmdb2i::alterStartWith"); - int rc = 0; - ulonglong nextIdVal; - if (!dataHandle) - rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection); - if (!rc) {rc = bridge()->lockObj(dataHandle, 1, QMY_LOCK, QMY_LENR, QMY_YES);} - if (!rc) - { - rc = getNextIdVal(&nextIdVal); - if (!rc) {rc = reset_auto_increment(nextIdVal);} - bridge()->lockObj(dataHandle, 0, QMY_UNLOCK, QMY_LENR, QMY_YES); - } - DBUG_RETURN(rc); -} - -bool ha_ibmdb2i::lobFieldsRequested() -{ - if (!db2Table->hasBlobs()) - { - DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("No LOBs")); - return (false); - } - - if (readAllColumns) - { - DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("All cols requested")); - return (true); - } - - for (int i = 0; i < db2Table->getBlobCount(); ++i) - { - if (bitmap_is_set(table->read_set, db2Table->blobFields[i])) - { - DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("LOB requested")); - return (true); - } - } - - DBUG_PRINT("ha_ibmdb2i::lobFieldsRequested",("No LOBs requested")); - return (false); -} - - -int ha_ibmdb2i::prepareReadBufferForLobs() -{ - DBUG_ENTER("ha_ibmdb2i::prepareReadBufferForLobs"); - DBUG_ASSERT(db2Table->hasBlobs()); - - uint32 activeLobFields = 0; - DB2LobField* lobField; - uint16 blobCount = db2Table->getBlobCount(); - - char* readBuf = activeReadBuf->getRowN(0); - - for (int i = 0; i < blobCount; ++i) - { - int fieldID = db2Table->blobFields[i]; - DB2Field& db2Field = db2Table->db2Field(fieldID); - lobField = db2Field.asBlobField(readBuf); - if (readAllColumns || - bitmap_is_set(table->read_set, fieldID)) - { - lobField->dataHandle = (ILEMemHandle)blobReadBuffers->getBufferPtr(fieldID); - activeLobFields++; - } - else - { - lobField->dataHandle = NULL; - } - } - - if (activeLobFields == 0) - { - for (int i = 0; i < blobCount; ++i) - { - DB2Field& db2Field = db2Table->db2Field(db2Table->blobFields[i]); - uint16 offset = db2Field.getBufferOffset() + db2Field.calcBlobPad(); - - for (int r = 1; r < activeReadBuf->getRowCapacity(); ++r) - { - lobField = (DB2LobField*)(activeReadBuf->getRowN(r) + offset); - lobField->dataHandle = NULL; - } - } - } - - activeReadBuf->setRowsToProcess((activeLobFields ? 1 : activeReadBuf->getRowCapacity())); - int rc = bridge()->objectOverride(activeHandle, - activeReadBuf->ptr(), - activeReadBuf->getRowLength()); - DBUG_RETURN(rc); -} - - -uint32 ha_ibmdb2i::adjustLobBuffersForRead() -{ - DBUG_ENTER("ha_ibmdb2i::adjustLobBuffersForRead"); - - char* readBuf = activeReadBuf->getRowN(0); - - for (int i = 0; i < db2Table->getBlobCount(); ++i) - { - DB2Field& db2Field = db2Table->db2Field(db2Table->blobFields[i]); - DB2LobField* lobField = db2Field.asBlobField(readBuf); - if (readAllColumns || - bitmap_is_set(table->read_set, db2Table->blobFields[i])) - { - lobField->dataHandle = (ILEMemHandle)blobReadBuffers->reallocBuffer(db2Table->blobFields[i], lobField->length); - - if (lobField->dataHandle == NULL) - DBUG_RETURN(HA_ERR_OUT_OF_MEM); - } - else - { - lobField->dataHandle = 0; - } - } - - int32 rc = bridge()->objectOverride(activeHandle, - activeReadBuf->ptr()); - DBUG_RETURN(rc); -} - - - -int ha_ibmdb2i::reset() -{ - DBUG_ENTER("ha_ibmdb2i::reset"); - - if (outstanding_start_bulk_insert) - { - finishBulkInsert(); - } - - if (activeHandle != 0) - { - releaseActiveHandle(); - } - - cleanupBuffers(); - - db2i_ileBridge::getBridgeForThread(ha_thd())->freeErrorStorage(); - - last_rnd_init_rc = last_index_init_rc = last_start_bulk_insert_rc = 0; - - returnDupKeysImmediately = false; - onDupUpdate = false; - forceSingleRowRead = false; - -#ifndef DBUG_OFF - cachedBridge=NULL; -#endif - - DBUG_RETURN(0); -} - - -int32 ha_ibmdb2i::buildCreateIndexStatement(SqlStatementStream& sqlStream, - KEY& key, - bool isPrimary, - const char* db2LibName, - const char* db2FileName) -{ - DBUG_ENTER("ha_ibmdb2i::buildCreateIndexStatement"); - - char fileSortSequence[11] = "*HEX"; - char fileSortSequenceLibrary[11] = ""; - char fileSortSequenceType = ' '; - String query(256); - query.length(0); - int rc = 0; - - if (isPrimary) - { - query.append(STRING_WITH_LEN("ALTER TABLE ")); - query.append(db2LibName); - query.append('.'); - query.append(db2FileName); - query.append(STRING_WITH_LEN(" ADD PRIMARY KEY ")); - } - else - { - query.append(STRING_WITH_LEN("CREATE")); - - if (key.flags & HA_NOSAME) - query.append(STRING_WITH_LEN(" UNIQUE WHERE NOT NULL")); - - query.append(STRING_WITH_LEN(" INDEX ")); - - query.append(db2LibName); - query.append('.'); - if (db2i_table::appendQualifiedIndexFileName(key.name, db2FileName, query)) - { - getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*"); - DBUG_RETURN(DB2I_ERR_INVALID_NAME ); - } - - query.append(STRING_WITH_LEN(" ON ")); - - query.append(db2LibName); - query.append('.'); - query.append(db2FileName); - } - - String fieldDefinition(128); - rc = buildIndexFieldList(fieldDefinition, - key, - isPrimary, - &fileSortSequenceType, - fileSortSequence, - fileSortSequenceLibrary); - - if (rc) DBUG_RETURN(rc); - - query.append(fieldDefinition); - - if ((THDVAR(ha_thd(), create_index_option)==1) && - (fileSortSequenceType != 'B') && - (fileSortSequenceType != ' ')) - { - rc = generateShadowIndex(sqlStream, - key, - db2LibName, - db2FileName, - fieldDefinition); - if (rc) DBUG_RETURN(rc); - } - - DBUG_PRINT("ha_ibmdb2i::buildCreateIndexStatement", ("Sent to DB2: %s",query.c_ptr_safe())); - sqlStream.addStatement(query,fileSortSequence,fileSortSequenceLibrary); - - DBUG_RETURN(0); -} - -/** - Generate the SQL syntax for the list of fields to be assigned to the - specified key. The corresponding sort sequence is also calculated. - - @param[out] appendHere The string to receive the generated SQL - @param key The key to evaluate - @param isPrimary True if this is being generated on behalf of the primary key - @param[out] fileSortSequenceType The type of the associated sort sequence - @param[out] fileSortSequence The name of the associated sort sequence - @param[out] fileSortSequenceLibrary The library of the associated sort sequence - - @return 0 if successful; error value otherwise -*/ -int32 ha_ibmdb2i::buildIndexFieldList(String& appendHere, - const KEY& key, - bool isPrimary, - char* fileSortSequenceType, - char* fileSortSequence, - char* fileSortSequenceLibrary) -{ - DBUG_ENTER("ha_ibmdb2i::buildIndexFieldList"); - appendHere.append(STRING_WITH_LEN(" ( ")); - for (int j = 0; j < key.key_parts; ++j) - { - char colName[MAX_DB2_COLNAME_LENGTH+1]; - if (j != 0) - { - appendHere.append(STRING_WITH_LEN(" , ")); - } - - KEY_PART_INFO& kpi = key.key_part[j]; - Field* field = kpi.field; - - convertMySQLNameToDB2Name(field->field_name, - colName, - sizeof(colName)); - appendHere.append(colName); - - int32 rc; - rc = updateAssociatedSortSequence(field->charset(), - fileSortSequenceType, - fileSortSequence, - fileSortSequenceLibrary); - if (rc) DBUG_RETURN (rc); - } - - appendHere.append(STRING_WITH_LEN(" ) ")); - - DBUG_RETURN(0); -} - - -/** - Generate an SQL statement that defines a *HEX sorted index to implement - the ibmdb2i_create_index. - - @param[out] stream The stream to append the generated statement to - @param key The key to evaluate - @param[out] libName The library containg the table - @param[out] fileName The DB2-compatible name of the table - @param[out] fieldDefinition The list of the fields in the index, in SQL syntax - - @return 0 if successful; error value otherwise -*/ -int32 ha_ibmdb2i::generateShadowIndex(SqlStatementStream& stream, - const KEY& key, - const char* libName, - const char* fileName, - const String& fieldDefinition) -{ - String shadowQuery(256); - shadowQuery.length(0); - shadowQuery.append(STRING_WITH_LEN("CREATE INDEX ")); - shadowQuery.append(libName); - shadowQuery.append('.'); - if (db2i_table::appendQualifiedIndexFileName(key.name, fileName, shadowQuery, db2i_table::ASCII_SQL, typeHex)) - { - getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*"); - return DB2I_ERR_INVALID_NAME; - } - shadowQuery.append(STRING_WITH_LEN(" ON ")); - shadowQuery.append(libName); - shadowQuery.append('.'); - shadowQuery.append(fileName); - shadowQuery.append(fieldDefinition); - DBUG_PRINT("ha_ibmdb2i::generateShadowIndex", ("Sent to DB2: %s",shadowQuery.c_ptr_safe())); - stream.addStatement(shadowQuery,"*HEX","QSYS"); - return 0; -} - - -void ha_ibmdb2i::doInitialRead(char orientation, - uint32 rowsToBuffer, - ILEMemHandle key, - int keyLength, - int keyParts) -{ - DBUG_ENTER("ha_ibmdb2i::doInitialRead"); - - if (forceSingleRowRead) - rowsToBuffer = 1; - else - rowsToBuffer = min(rowsToBuffer, activeReadBuf->getRowCapacity()); - - activeReadBuf->newReadRequest(activeHandle, - orientation, - rowsToBuffer, - THDVAR(ha_thd(), async_enabled), - key, - keyLength, - keyParts); - DBUG_VOID_RETURN; -} - - -int ha_ibmdb2i::start_stmt(THD *thd, thr_lock_type lock_type) -{ - DBUG_ENTER("ha_ibmdb2i::start_stmt"); - initBridge(thd); - if (!THDVAR(thd, transaction_unsafe)) - { - trans_register_ha(thd, FALSE, ibmdb2i_hton); - - if (!autoCommitIsOn(thd)) - { - bridge()->beginStmtTx(); - } - } - - DBUG_RETURN(0); -} - -int32 ha_ibmdb2i::handleLOBReadOverflow() -{ - DBUG_ENTER("ha_ibmdb2i::handleLOBReadOverflow"); - DBUG_ASSERT(db2Table->hasBlobs() && (activeReadBuf->getRowCapacity() == 1)); - - int32 rc = adjustLobBuffersForRead(); - - if (!rc) - { - activeReadBuf->rewind(); - rc = bridge()->expectErrors(QMY_ERR_END_OF_BLOCK) - ->read(activeHandle, - activeReadBuf->ptr(), - accessIntent, - getCommitLevel(), - QMY_SAME); - releaseRowNeeded = TRUE; - - } - DBUG_RETURN(rc); -} - - -int32 ha_ibmdb2i::finishBulkInsert() -{ - int32 rc = 0; - - if (activeWriteBuf->rowCount() && activeHandle) - rc = flushWrite(activeHandle, table->record[0]); - - if (activeHandle) - releaseActiveHandle(); - - if (autoIncLockAcquired == TRUE) - { - // We could check the return code on the unlock, but beware not - // to overlay the return code from the flushwrite or we will mask - // duplicate key errors.. - bridge()->lockObj(dataHandle, 0, QMY_UNLOCK, QMY_LEAR, QMY_YES); - autoIncLockAcquired = FALSE; - } - outstanding_start_bulk_insert = false; - multiRowWriteBuf.freeBuf(); - last_start_bulk_insert_rc = 0; - - resetCharacterConversionBuffers(); - - return rc; -} - -int ha_ibmdb2i::getKeyFromName(const char* name, size_t len) -{ - for (int i = 0; i < table_share->keys; ++i) - { - const char* indexName = db2Table->indexFile(i)->getDB2FileName(); - if ((strncmp(name, indexName, len) == 0) && - (strlen(indexName) == len)) - { - return i; - } - } - return MAX_KEY; -} - -/* -Determine the number of I/O's it takes to read through the table. - */ -double ha_ibmdb2i::scan_time() - { - DBUG_ENTER("ha_ibmdb2i::scan_time"); - DBUG_RETURN(ulonglong2double((stats.data_file_length)/IO_SIZE)); - } - - -/** - Estimate the number of I/O's it takes to read a set of ranges through - an index. - - @param index - @param ranges - @param rows - - @return The estimate number of I/Os -*/ - -double ha_ibmdb2i::read_time(uint index, uint ranges, ha_rows rows) -{ - DBUG_ENTER("ha_ibmdb2i::read_time"); - int rc; - uint64 idxPageCnt = 0; - double cost; - - if (unlikely(rows == HA_POS_ERROR)) - DBUG_RETURN(double(rows) + ranges); - - rc = bridge()->retrieveIndexInfo(db2Table->indexFile(index)->getMasterDefnHandle(), - &idxPageCnt); - if (!rc) - { - if ((idxPageCnt == 1) || // Retrieving rows in requested order or - (ranges == rows)) // 'Sweep' full records retrieval - cost = idxPageCnt/4; - else - { - uint64 totalRecords = stats.records + 1; - double dataPageCount = stats.data_file_length/IO_SIZE; - - cost = (rows * dataPageCount / totalRecords) + - min(idxPageCnt, (log_2(idxPageCnt) * ranges + - rows * (log_2(idxPageCnt) + log_2(rows) - log_2(totalRecords)))); - } - } - else - { - cost = rows2double(ranges+rows); // Use default costing - } - DBUG_RETURN(cost); -} - -int ha_ibmdb2i::useIndexFile(int idx) -{ - DBUG_ENTER("ha_ibmdb2i::useIndexFile"); - - if (activeHandle) - releaseActiveHandle(); - - int rc = 0; - - if (!indexHandles[idx]) - rc = db2Table->indexFile(idx)->allocateNewInstance(&indexHandles[idx], curConnection); - - if (rc == 0) - { - activeHandle = indexHandles[idx]; - bumpInUseCounter(1); - } - - DBUG_RETURN(rc); -} - - -ulong ha_ibmdb2i::index_flags(uint inx, uint part, bool all_parts) const -{ - return HA_READ_NEXT | HA_READ_PREV | HA_KEYREAD_ONLY | HA_READ_ORDER | HA_READ_RANGE; -} - - -static struct st_mysql_sys_var* ibmdb2i_system_variables[] = { - MYSQL_SYSVAR(rdb_name), - MYSQL_SYSVAR(transaction_unsafe), - MYSQL_SYSVAR(lob_alloc_size), - MYSQL_SYSVAR(max_read_buffer_size), - MYSQL_SYSVAR(max_write_buffer_size), - MYSQL_SYSVAR(async_enabled), - MYSQL_SYSVAR(assume_exclusive_use), - MYSQL_SYSVAR(compat_opt_blob_cols), - MYSQL_SYSVAR(compat_opt_time_as_duration), - MYSQL_SYSVAR(compat_opt_allow_zero_date_vals), - MYSQL_SYSVAR(compat_opt_year_as_int), - MYSQL_SYSVAR(propagate_default_col_vals), - MYSQL_SYSVAR(create_index_option), -// MYSQL_SYSVAR(discovery_mode), - MYSQL_SYSVAR(system_trace_level), - NULL -}; - - -struct st_mysql_storage_engine ibmdb2i_storage_engine= -{ MYSQL_HANDLERTON_INTERFACE_VERSION }; - -mysql_declare_plugin(ibmdb2i) -{ - MYSQL_STORAGE_ENGINE_PLUGIN, - &ibmdb2i_storage_engine, - "IBMDB2I", - "The IBM development team in Rochester, Minnesota", - "IBM DB2 for i Storage Engine", - PLUGIN_LICENSE_GPL, - ibmdb2i_init_func, /* Plugin Init */ - ibmdb2i_done_func, /* Plugin Deinit */ - 0x0100 /* 1.0 */, - NULL, /* status variables */ - ibmdb2i_system_variables, /* system variables */ - NULL /* config options */ -} -mysql_declare_plugin_end; diff --git a/storage/ibmdb2i/ha_ibmdb2i.h b/storage/ibmdb2i/ha_ibmdb2i.h deleted file mode 100644 index b2a43232f2d..00000000000 --- a/storage/ibmdb2i/ha_ibmdb2i.h +++ /dev/null @@ -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* 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 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 *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); -}; diff --git a/storage/ibmdb2i/plug.in b/storage/ibmdb2i/plug.in deleted file mode 100644 index 0913d72aabf..00000000000 --- a/storage/ibmdb2i/plug.in +++ /dev/null @@ -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]) From e0a8c25438dac90ec697f5edaa712d9681acf96b Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Thu, 11 Nov 2010 11:34:55 +0100 Subject: [PATCH 033/238] Bug#57890: Assertion failed: next_insert_id == 0 with on duplicate key update There was a missed corner case in the partitioning handler, which caused the next_insert_id to be changed in the second level handlers (i.e the hander of a partition), which caused this debug assertion. The solution was to always ensure that only the partitioning level generates auto_increment values, since if it was done within a partition, it may fail to match the partition function. mysql-test/suite/parts/inc/partition_auto_increment.inc: Added tests mysql-test/suite/parts/r/partition_auto_increment_blackhole.result: updated results mysql-test/suite/parts/r/partition_auto_increment_innodb.result: updated results mysql-test/suite/parts/r/partition_auto_increment_memory.result: updated results mysql-test/suite/parts/r/partition_auto_increment_myisam.result: updated results sql/ha_partition.cc: In ::write_row the auto_inc value is generated through handler::update_auto_increment (which calls ::get_auto_increment() if needed). If: * INSERT_ID was set to 0 * it was updated to 0 by 'INSERT ... ON DUPLICATE KEY UPDATE' and changed partitions for the row Then it would try to generate a auto_increment value in the ::write_row, which will trigger the assert. So the solution is to prevent this by, in ha_partition::write_row set auto_inc_field_not_null and add MODE_NO_AUTO_VALUE_ON_ZERO in ha_partition::update_row (when changing partition) temporary set table->next_number_field to NULL which calling the partitions ::write_row(). --- .../parts/inc/partition_auto_increment.inc | 49 +++++++++++++ .../partition_auto_increment_blackhole.result | 32 +++++++++ .../r/partition_auto_increment_innodb.result | 72 +++++++++++++++++++ .../r/partition_auto_increment_memory.result | 72 +++++++++++++++++++ .../r/partition_auto_increment_myisam.result | 72 +++++++++++++++++++ sql/ha_partition.cc | 37 +++++++++- 6 files changed, 332 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/parts/inc/partition_auto_increment.inc b/mysql-test/suite/parts/inc/partition_auto_increment.inc index 102e57d3d04..034460d49ac 100644 --- a/mysql-test/suite/parts/inc/partition_auto_increment.inc +++ b/mysql-test/suite/parts/inc/partition_auto_increment.inc @@ -105,6 +105,30 @@ OPTIMIZE TABLE t1; SHOW CREATE TABLE t1; DROP TABLE t1; +if (!$skip_update) +{ +eval CREATE TABLE t1 +(a INT NULL AUTO_INCREMENT, + UNIQUE KEY (a)) +ENGINE=$engine; +SET LAST_INSERT_ID = 999; +SET INSERT_ID = 0; +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +SELECT * FROM t1; +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +SELECT * FROM t1; +UPDATE t1 SET a = 1 WHERE a IS NULL; +SELECT LAST_INSERT_ID(); +SELECT * FROM t1; +UPDATE t1 SET a = NULL WHERE a = 1; +SELECT LAST_INSERT_ID(); +SELECT * FROM t1; +DROP TABLE t1; +SET INSERT_ID = 1; +} + -- echo # Simple test with NULL eval CREATE TABLE t1 ( c1 INT NOT NULL AUTO_INCREMENT, @@ -831,5 +855,30 @@ SELECT * FROM t ORDER BY c1 ASC; DROP TABLE t; +if (!$skip_update) +{ +eval CREATE TABLE t1 +(a INT NULL AUTO_INCREMENT, + UNIQUE KEY (a)) +ENGINE=$engine +PARTITION BY KEY(a) PARTITIONS 2; +SET LAST_INSERT_ID = 999; +SET INSERT_ID = 0; +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +SELECT * FROM t1; +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +SELECT * FROM t1; +UPDATE t1 SET a = 1 WHERE a IS NULL; +SELECT LAST_INSERT_ID(); +SELECT * FROM t1; +UPDATE t1 SET a = NULL WHERE a = 1; +SELECT LAST_INSERT_ID(); +SELECT * FROM t1; +DROP TABLE t1; +} + + --echo ############################################################################## } diff --git a/mysql-test/suite/parts/r/partition_auto_increment_blackhole.result b/mysql-test/suite/parts/r/partition_auto_increment_blackhole.result index d6ea8ba0fe4..2344f03ce3f 100644 --- a/mysql-test/suite/parts/r/partition_auto_increment_blackhole.result +++ b/mysql-test/suite/parts/r/partition_auto_increment_blackhole.result @@ -120,6 +120,38 @@ t1 CREATE TABLE `t1` ( PRIMARY KEY (`c1`) ) ENGINE=BLACKHOLE DEFAULT CHARSET=latin1 DROP TABLE t1; +CREATE TABLE t1 +(a INT NULL AUTO_INCREMENT, +UNIQUE KEY (a)) +ENGINE='Blackhole'; +SET LAST_INSERT_ID = 999; +SET INSERT_ID = 0; +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +UPDATE t1 SET a = 1 WHERE a IS NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +UPDATE t1 SET a = NULL WHERE a = 1; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +DROP TABLE t1; +SET INSERT_ID = 1; # Simple test with NULL CREATE TABLE t1 ( c1 INT NOT NULL AUTO_INCREMENT, diff --git a/mysql-test/suite/parts/r/partition_auto_increment_innodb.result b/mysql-test/suite/parts/r/partition_auto_increment_innodb.result index 4cd7aa57417..5fd576322d5 100644 --- a/mysql-test/suite/parts/r/partition_auto_increment_innodb.result +++ b/mysql-test/suite/parts/r/partition_auto_increment_innodb.result @@ -136,6 +136,42 @@ t1 CREATE TABLE `t1` ( PRIMARY KEY (`c1`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 DROP TABLE t1; +CREATE TABLE t1 +(a INT NULL AUTO_INCREMENT, +UNIQUE KEY (a)) +ENGINE='InnoDB'; +SET LAST_INSERT_ID = 999; +SET INSERT_ID = 0; +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +1 +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +UPDATE t1 SET a = 1 WHERE a IS NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +UPDATE t1 SET a = NULL WHERE a = 1; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +DROP TABLE t1; +SET INSERT_ID = 1; # Simple test with NULL CREATE TABLE t1 ( c1 INT NOT NULL AUTO_INCREMENT, @@ -1023,4 +1059,40 @@ c1 c2 2 20 127 40 DROP TABLE t; +CREATE TABLE t1 +(a INT NULL AUTO_INCREMENT, +UNIQUE KEY (a)) +ENGINE='InnoDB' +PARTITION BY KEY(a) PARTITIONS 2; +SET LAST_INSERT_ID = 999; +SET INSERT_ID = 0; +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +1 +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +UPDATE t1 SET a = 1 WHERE a IS NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +UPDATE t1 SET a = NULL WHERE a = 1; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +DROP TABLE t1; ############################################################################## diff --git a/mysql-test/suite/parts/r/partition_auto_increment_memory.result b/mysql-test/suite/parts/r/partition_auto_increment_memory.result index 1a27d1c2e52..c3a5073b029 100644 --- a/mysql-test/suite/parts/r/partition_auto_increment_memory.result +++ b/mysql-test/suite/parts/r/partition_auto_increment_memory.result @@ -136,6 +136,42 @@ t1 CREATE TABLE `t1` ( PRIMARY KEY (`c1`) ) ENGINE=MEMORY AUTO_INCREMENT=102 DEFAULT CHARSET=latin1 DROP TABLE t1; +CREATE TABLE t1 +(a INT NULL AUTO_INCREMENT, +UNIQUE KEY (a)) +ENGINE='Memory'; +SET LAST_INSERT_ID = 999; +SET INSERT_ID = 0; +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +1 +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +UPDATE t1 SET a = 1 WHERE a IS NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +UPDATE t1 SET a = NULL WHERE a = 1; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +DROP TABLE t1; +SET INSERT_ID = 1; # Simple test with NULL CREATE TABLE t1 ( c1 INT NOT NULL AUTO_INCREMENT, @@ -1051,4 +1087,40 @@ c1 c2 2 20 127 40 DROP TABLE t; +CREATE TABLE t1 +(a INT NULL AUTO_INCREMENT, +UNIQUE KEY (a)) +ENGINE='Memory' +PARTITION BY KEY(a) PARTITIONS 2; +SET LAST_INSERT_ID = 999; +SET INSERT_ID = 0; +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +1 +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +UPDATE t1 SET a = 1 WHERE a IS NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +UPDATE t1 SET a = NULL WHERE a = 1; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +DROP TABLE t1; ############################################################################## diff --git a/mysql-test/suite/parts/r/partition_auto_increment_myisam.result b/mysql-test/suite/parts/r/partition_auto_increment_myisam.result index 9885c78a921..ad440155d33 100644 --- a/mysql-test/suite/parts/r/partition_auto_increment_myisam.result +++ b/mysql-test/suite/parts/r/partition_auto_increment_myisam.result @@ -136,6 +136,42 @@ t1 CREATE TABLE `t1` ( PRIMARY KEY (`c1`) ) ENGINE=MyISAM AUTO_INCREMENT=102 DEFAULT CHARSET=latin1 DROP TABLE t1; +CREATE TABLE t1 +(a INT NULL AUTO_INCREMENT, +UNIQUE KEY (a)) +ENGINE='MyISAM'; +SET LAST_INSERT_ID = 999; +SET INSERT_ID = 0; +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +1 +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +UPDATE t1 SET a = 1 WHERE a IS NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +UPDATE t1 SET a = NULL WHERE a = 1; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +DROP TABLE t1; +SET INSERT_ID = 1; # Simple test with NULL CREATE TABLE t1 ( c1 INT NOT NULL AUTO_INCREMENT, @@ -1070,4 +1106,40 @@ c1 c2 2 20 127 40 DROP TABLE t; +CREATE TABLE t1 +(a INT NULL AUTO_INCREMENT, +UNIQUE KEY (a)) +ENGINE='MyISAM' +PARTITION BY KEY(a) PARTITIONS 2; +SET LAST_INSERT_ID = 999; +SET INSERT_ID = 0; +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +1 +INSERT INTO t1 SET a = 1 ON DUPLICATE KEY UPDATE a = NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +UPDATE t1 SET a = 1 WHERE a IS NULL; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +UPDATE t1 SET a = NULL WHERE a = 1; +SELECT LAST_INSERT_ID(); +LAST_INSERT_ID() +999 +SELECT * FROM t1; +a +0 +DROP TABLE t1; ############################################################################## diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 24c0f3e71f2..607f4ce2143 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -3050,7 +3050,9 @@ int ha_partition::write_row(uchar * buf) my_bitmap_map *old_map; HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data; THD *thd= ha_thd(); - timestamp_auto_set_type orig_timestamp_type= table->timestamp_field_type; + timestamp_auto_set_type saved_timestamp_type= table->timestamp_field_type; + ulong saved_sql_mode= thd->variables.sql_mode; + bool saved_auto_inc_field_not_null= table->auto_increment_field_not_null; #ifdef NOT_NEEDED uchar *rec0= m_rec0; #endif @@ -3086,6 +3088,22 @@ int ha_partition::write_row(uchar * buf) */ if (error) goto exit; + + /* + Don't allow generation of auto_increment value the partitions handler. + If a partitions handler would change the value, then it might not + match the partition any longer. + This can occur if 'SET INSERT_ID = 0; INSERT (NULL)', + So allow this by adding 'MODE_NO_AUTO_VALUE_ON_ZERO' to sql_mode. + The partitions handler::next_insert_id must always be 0. Otherwise + we need to forward release_auto_increment, or reset it for all + partitions. + */ + if (table->next_number_field->val_int() == 0) + { + table->auto_increment_field_not_null= TRUE; + thd->variables.sql_mode|= MODE_NO_AUTO_VALUE_ON_ZERO; + } } old_map= dbug_tmp_use_all_columns(table, table->read_set); @@ -3119,7 +3137,9 @@ int ha_partition::write_row(uchar * buf) set_auto_increment_if_higher(table->next_number_field); reenable_binlog(thd); exit: - table->timestamp_field_type= orig_timestamp_type; + thd->variables.sql_mode= saved_sql_mode; + table->auto_increment_field_not_null= saved_auto_inc_field_not_null; + table->timestamp_field_type= saved_timestamp_type; DBUG_RETURN(error); } @@ -3186,11 +3206,24 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data) } else { + Field *saved_next_number_field= table->next_number_field; + /* + Don't allow generation of auto_increment value for update. + table->next_number_field is never set on UPDATE. + But is set for INSERT ... ON DUPLICATE KEY UPDATE, + and since update_row() does not generate or update an auto_inc value, + we cannot have next_number_field set when moving a row + to another partition with write_row(), since that could + generate/update the auto_inc value. + This gives the same behavior for partitioned vs non partitioned tables. + */ + table->next_number_field= NULL; DBUG_PRINT("info", ("Update from partition %d to partition %d", old_part_id, new_part_id)); tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ error= m_file[new_part_id]->ha_write_row(new_data); reenable_binlog(thd); + table->next_number_field= saved_next_number_field; if (error) goto exit; From 47b514ffce0c5b1bdda27f745d1129496dff037f Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Mon, 15 Nov 2010 16:17:38 +0100 Subject: [PATCH 034/238] Bug#58197: main.variables-big fails on windows The test result differs on windows, since it writes out 'localhost:' instead of only 'localhost', since it uses tcp/ip instead of unix sockets on windows. Fixed by replacing that column. Also requires --big-test from some long running tests and added a weekly run of all test requiring --big-test. mysql-test/collections/default.weekly: Added a run of big-test (already exists in 5.5). mysql-test/r/variables-big.result: Updated results mysql-test/suite/parts/t/part_supported_sql_func_innodb.test: requiring --big-test since the test takes long time mysql-test/suite/parts/t/partition_alter1_1_2_innodb.test: requiring --big-test since the test takes long time mysql-test/suite/parts/t/partition_alter1_2_innodb.test: requiring --big-test since the test takes long time mysql-test/suite/parts/t/partition_alter4_innodb.test: requiring --big-test since the test takes long time mysql-test/t/disabled.def: Disabled two tests since they fail and was already reported as bugs (but was never run since they requires --big-test flag). mysql-test/t/variables-big.test: Replacing column 3 in process list since it is not the same on windows as in unix. --- mysql-test/collections/default.weekly | 2 ++ mysql-test/r/variables-big.result | 10 +++++----- .../suite/parts/t/part_supported_sql_func_innodb.test | 3 +++ .../suite/parts/t/partition_alter1_1_2_innodb.test | 3 +++ .../suite/parts/t/partition_alter1_2_innodb.test | 3 +++ mysql-test/suite/parts/t/partition_alter4_innodb.test | 3 +++ mysql-test/t/disabled.def | 2 ++ mysql-test/t/variables-big.test | 10 +++++----- 8 files changed, 26 insertions(+), 10 deletions(-) diff --git a/mysql-test/collections/default.weekly b/mysql-test/collections/default.weekly index e69de29bb2d..5865864f4cd 100644 --- a/mysql-test/collections/default.weekly +++ b/mysql-test/collections/default.weekly @@ -0,0 +1,2 @@ +perl mysql-test-run.pl --timer --force --comment=1st --experimental=collections/default.experimental 1st +perl mysql-test-run.pl --timer --force --comment=big-tests --experimental=collections/default.experimental --vardir=var-big-tests --big-test --testcase-timeout=60 --suite-timeout=600 parts.partition_alter1_2_ndb parts.part_supported_sql_func_innodb parts.partition_alter1_2_innodb parts.partition_alter4_innodb parts.partition_alter1_1_2_ndb parts.partition_alter1_1_2_innodb parts.partition_alter1_1_ndb large_tests.alter_table rpl_ndb.rpl_truncate_7ndb_2 main.archive-big main.sum_distinct-big main.mysqlbinlog_row_big main.alter_table-big main.variables-big main.type_newdecimal-big main.read_many_rows_innodb main.log_tables-big main.count_distinct3 main.events_time_zone main.merge-big main.create-big main.events_stress main.ssl-big diff --git a/mysql-test/r/variables-big.result b/mysql-test/r/variables-big.result index 960fc6d22f4..71b32393d82 100644 --- a/mysql-test/r/variables-big.result +++ b/mysql-test/r/variables-big.result @@ -1,20 +1,20 @@ SET SESSION transaction_prealloc_size=1024*1024*1024*1; SHOW PROCESSLIST; Id User Host db Command Time State Info - root localhost test Query