From e9b750d1a6a131b60453c8dd4efef9d572bae476 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 5 Jan 2002 22:51:42 +0200 Subject: [PATCH 01/14] Fix for FLUSH QUERY CACHE Fix for new bug in CREATE TABLE when sorting keys. Docs/manual.texi: Added FOUND_ROWS() section. include/my_base.h: Spatial index include/myisam.h: Spatial index include/mysql_com.h: Spatial index myisam/ft_dump.c: Remove warnings. mysys/hash.c: Fix for SUNPRO_C (Sun's Fortre compiler) sql/sql_cache.cc: Fix for FLUSH QUERY CACHE. sql/sql_cache.h: Fix for FLUSH QUERY CACHE. sql/sql_table.cc: Fix for new bug when sorting keys. --- Docs/manual.texi | 50 ++++++++++++++--- include/my_base.h | 22 +++++++- include/myisam.h | 1 + include/mysql_com.h | 3 +- myisam/ft_dump.c | 7 +-- mysys/hash.c | 2 +- sql/sql_cache.cc | 128 +++++++++++++++++++++++++++++++++++++------- sql/sql_cache.h | 3 ++ sql/sql_table.cc | 16 ++++-- 9 files changed, 195 insertions(+), 37 deletions(-) diff --git a/Docs/manual.texi b/Docs/manual.texi index c46546cc93f..67791aac9f4 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -5393,6 +5393,10 @@ You will need the following: A Windows 32 bits Operational System of the family Win9x, ME, NT and Win 2000. The NT family permits running the MySQL server as a service. @xref{NT start}. + +If you want to use tables bigger than 4G, you should install MySQL +on NTFS or newer file system. Don't forget to use @code{MAX_ROWS} and +@code{AVG_ROW_LENGTH} when you create the table. @xref{CREATE TABLE}. @item TCP/IP protocol support. @item @@ -32218,6 +32222,25 @@ returns immediately. The return value is the number of log events it had to wait to get to the specified position, or NULL in case of error. Useful for control of master-slave synchronisation, but was originally written to facilitate replication testing. + +@findex FOUND_ROWS() +@findex LIMIT +@item FOUND_ROWS() +Returns the number of rows that the last @code{SELECT CALC_FOUND_ROWS ...} +command would have returned, if wasn't restricted with @code{LIMIT}. + +@example +SELECT CALC_FOUND_ROWS * FROM table_name WHERE id > 100 LIMIT 10; +SELECT FOUND_ROWS(); +@end example + +The second select will return how many rows the SELECT should have +returned if we would remove the @code{LIMIT} clause. + +Note that if you are using @code{SELECT CALC_FOUND_ROWS ...} MySQL has +to calculate all rows in the result set. This is however faster than +if you would not use @code{LIMIT} as the result set doesn't have to be sent +to the client. @end table @@ -32404,7 +32427,7 @@ mysql> SELECT id,FLOOR(value/100) FROM tbl_name ORDER BY RAND(); @c help SELECT @example SELECT [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] - [SQL_CACHE | SQL_NO_CACHE] [HIGH_PRIORITY] + [SQL_CACHE | SQL_NO_CACHE] [CALC_FOUND_ROWS] [HIGH_PRIORITY] [DISTINCT | DISTINCTROW | ALL] select_expression,... [INTO @{OUTFILE | DUMPFILE@} 'file_name' export_options] @@ -32561,6 +32584,12 @@ result set will be small. In this case, MySQL will use fast temporary tables to store the resulting table instead of using sorting. In MySQL Version 3.23 this shouldn't normally be needed. +@item +@code{CALC_FOUND_ROWS} tells MySQL to calculate how many rows there +would be in the result, disregarding any @code{LIMIT} clause. The number +of rows can be obtained with @code{SELECT +FOUND_ROWS()}. @xref{Miscellaneous functions}. + @item @code{SQL_CACHE} tells MySQL to store the query result in the query cache if you are using @code{SQL_QUERY_CACHE_TYPE=2} (@code{DEMAND}). @@ -34493,12 +34522,14 @@ original tables, MySQL will not allow concurrent inserts during @item The @code{RAID_TYPE} option will help you to break the 2G/4G limit for the MyISAM data file (not the index file) on operating systems that -don't support big files. -You can get more speed from the I/O bottleneck by putting -@code{RAID} directories on different physical disks. @code{RAID_TYPE} -will work on any OS, as long as you have configured MySQL with -@code{--with-raid}. For now the only allowed @code{RAID_TYPE} is -@code{STRIPED} (@code{1} and @code{RAID0} are aliases for this). +don't support big files. Note that this option is not recommended for +file system that supports big files! + +You can get more speed from the I/O bottleneck by putting @code{RAID} +directories on different physical disks. @code{RAID_TYPE} will work on +any OS, as long as you have configured MySQL with @code{--with-raid}. +For now the only allowed @code{RAID_TYPE} is @code{STRIPED} (@code{1} +and @code{RAID0} are aliases for this). If you specify @code{RAID_TYPE=STRIPED} for a @code{MyISAM} table, @code{MyISAM} will create @code{RAID_CHUNKS} subdirectories named 00, @@ -43274,7 +43305,8 @@ No UDF functions. @item No stack trace on core dump. @item -No internal RAID support. +No internal RAID support. (This is not normally needed as most OS has +nowadays support for big files). @item You can set this up as a server or a master (no replication). @item @@ -47996,6 +48028,8 @@ Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}. @itemize @bullet @item +Fixed bug in @code{FLUSH QUERY CACHE}. +@item Added @code{CAST()} and @code{CONVERT()} functions. @item Changed order of how keys are created in tables. diff --git a/include/my_base.h b/include/my_base.h index 89d58bb3d51..dc88e248469 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -56,7 +56,19 @@ enum ha_rkey_function { HA_READ_AFTER_KEY, /* Find next rec. after key-record */ HA_READ_BEFORE_KEY, /* Find next rec. before key-record */ HA_READ_PREFIX, /* Key which as same prefix */ - HA_READ_PREFIX_LAST /* Last key with the same prefix */ + HA_READ_PREFIX_LAST, /* Last key with the same prefix */ + HA_READ_MBR_CONTAIN, + HA_READ_MBR_INTERSECT, + HA_READ_MBR_WITHIN, + HA_READ_MBR_DISJOINT, + HA_READ_MBR_EQUAL +}; + + /* Key algorithm types */ + +enum ha_key_alg { + HA_KEY_ALG_BTREE=0, /* B-tree, default one */ + HA_KEY_ALG_RTREE=1 /* R-tree, for spatial searches */ }; /* The following is parameter to ha_extra() */ @@ -136,6 +148,8 @@ enum ha_base_keytype { #define HA_BINARY_PACK_KEY 32 /* Packing of all keys to prev key */ #define HA_FULLTEXT 128 /* SerG: for full-text search */ #define HA_UNIQUE_CHECK 256 /* Check the key for uniqueness */ +#define HA_SPATIAL 1024 /* Alex Barkov: for spatial search */ + /* Automatic bits in key-flag */ @@ -239,6 +253,12 @@ enum ha_base_keytype { #define SEARCH_UPDATE 64 #define SEARCH_PREFIX 128 #define SEARCH_LAST 256 +#define MBR_CONTAIN 512 +#define MBR_INTERSECT 1024 +#define MBR_WITHIN 2048 +#define MBR_DISJOINT 4096 +#define MBR_EQUAL 8192 +#define MBR_DATA 16384 /* bits in opt_flag */ #define QUICK_USED 1 diff --git a/include/myisam.h b/include/myisam.h index 80dc9f73f5b..35953496a47 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -126,6 +126,7 @@ typedef struct st_mi_keydef /* Key definition with open & info */ uint16 keysegs; /* Number of key-segment */ uint16 flag; /* NOSAME, PACK_USED */ + uint8 key_alg; /* BTREE, RTREE */ uint16 block_length; /* Length of keyblock (auto) */ uint16 underflow_block_length; /* When to execute underflow */ uint16 keylength; /* Tot length of keyparts (auto) */ diff --git a/include/mysql_com.h b/include/mysql_com.h index a4e0b5f0223..eb3671ddfbd 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -150,7 +150,8 @@ enum enum_field_types { FIELD_TYPE_DECIMAL, FIELD_TYPE_TINY, FIELD_TYPE_LONG_BLOB=251, FIELD_TYPE_BLOB=252, FIELD_TYPE_VAR_STRING=253, - FIELD_TYPE_STRING=254 + FIELD_TYPE_STRING=254, + FIELD_TYPE_GEOMETRY=255 }; #define FIELD_TYPE_CHAR FIELD_TYPE_TINY /* For compability */ diff --git a/myisam/ft_dump.c b/myisam/ft_dump.c index a693878acd9..6308694b58e 100644 --- a/myisam/ft_dump.c +++ b/myisam/ft_dump.c @@ -33,7 +33,7 @@ static uint lengths[256]; int main(int argc,char *argv[]) { int error=0; - uint keylen, keylen2, inx, doc_cnt=0; + uint keylen, keylen2=0, inx, doc_cnt=0; float weight; double gws, min_gws=0, avg_gws=0; MI_INFO *info; @@ -151,7 +151,7 @@ int main(int argc,char *argv[]) for (inx=0;inx<256;inx++) { count+=lengths[inx]; - if (count >= total/2) + if ((ulong) count >= total/2) break; } printf("Total rows: %qu\nTotal words: %lu\n" @@ -170,7 +170,8 @@ int main(int argc,char *argv[]) count+=lengths[inx]; if (count && lengths[inx]) printf("%3u: %10lu %5.2f%% %20lu %4.1f%%\n", inx, - lengths[inx],100.0*lengths[inx]/total,count, 100.0*count/total); + (ulong) lengths[inx],100.0*lengths[inx]/total,(ulong) count, + 100.0*count/total); } } } diff --git a/mysys/hash.c b/mysys/hash.c index 64de2c71bef..0b326ebc508 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -177,7 +177,7 @@ uint calc_hashnr_caseup(const byte *key, uint len) #endif -#ifndef _FORTREC_ +#ifndef __SUNPRO_C /* SUNPRO can't handle this */ inline #endif uint rec_hashnr(HASH *hash,const byte *record) diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 142170d022c..c937e0243a4 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -615,8 +615,8 @@ void query_cache_abort(NET *net) query_cache.free_query(query_block); } net->query_cache_query=0; + DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1);); STRUCT_UNLOCK(&query_cache.structure_guard_mutex); - DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0);); } DBUG_VOID_RETURN; } @@ -1153,6 +1153,8 @@ void Query_cache::flush() flush_cache(); DUMP(this); } + + DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1);); STRUCT_UNLOCK(&structure_guard_mutex); DBUG_VOID_RETURN; } @@ -2407,13 +2409,15 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len, void Query_cache::pack_cache() { + DBUG_ENTER("Query_cache::pack_cache"); STRUCT_LOCK(&structure_guard_mutex); + DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1);); + byte *border = 0; Query_cache_block *before = 0; ulong gap = 0; my_bool ok = 1; Query_cache_block *block = first_block; - DBUG_ENTER("Query_cache::pack_cache"); DUMP(this); if (first_block) @@ -2438,6 +2442,8 @@ void Query_cache::pack_cache() } DUMP(this); } + + DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1);); STRUCT_UNLOCK(&structure_guard_mutex); DBUG_VOID_RETURN; } @@ -2502,22 +2508,14 @@ my_bool Query_cache::move_by_type(byte **border, Query_cache_block_table *nlist_root = new_block->table(0); nlist_root->n = 0; - if (tnext == list_root) - { - nlist_root->next = nlist_root; - nlist_root->prev = nlist_root; - } - else - { - nlist_root->next = tnext; - tnext->prev = nlist_root; - } - if (tprev != list_root) - { - nlist_root->prev = tnext; - tprev->next = nlist_root; - } - + nlist_root->next = tnext; + tnext->prev = nlist_root; + nlist_root->prev = tprev; + tprev->next = nlist_root; + DBUG_PRINT("qcache", + ("list_root: 0x%lx tnext 0x%lx tprev 0x%lx tprev->next 0x%lx tnext->prev 0x%lx", + (ulong) list_root, (ulong) tnext, (ulong) tprev, + (ulong)tprev->next, (ulong)tnext->prev)); /* Go through all queries that uses this table and change them to point to the new table object @@ -3076,10 +3074,23 @@ my_bool Query_cache::check_integrity(bool not_locked) case Query_cache_block::TABLE: if (in_list(tables_blocks[block->table()->type()], block, "tables")) result = 1; + if (in_table_list(block->table(0), block->table(0), "table list root")) + result = 1; break; case Query_cache_block::QUERY: if (in_list(queries_blocks, block, "query")) result = 1; + for (TABLE_COUNTER_TYPE j=0; j < block->n_tables; j++) + { + Query_cache_block_table *block_table = block->table(j); + Query_cache_block_table *block_table_root = + (Query_cache_block_table *) + (((byte*)block_table->parent) - + ALIGN_SIZE(sizeof(Query_cache_block_table))); + + if (in_table_list(block_table, block_table_root, "table list")) + result = 1; + } break; case Query_cache_block::RES_INCOMPLETE: // This type of block can be not lincked yet (in multithread environment) @@ -3341,4 +3352,85 @@ err2: return result; } +void dump_node(Query_cache_block_table * node, + const char * call, const char * descr) +{ + DBUG_PRINT("qcache", ("%s: %s: node: 0x%lx", call, descr, (ulong) node)); + DBUG_PRINT("qcache", ("%s: %s: node block: 0x%lx", + call, descr, (ulong) node->block())); + DBUG_PRINT("qcache", ("%s: %s: next: 0x%lx", call, descr, + (ulong) node->next)); + DBUG_PRINT("qcache", ("%s: %s: prev: 0x%lx", call, descr, + (ulong) node->prev)); +} + +my_bool Query_cache::in_table_list(Query_cache_block_table * root, + Query_cache_block_table * point, + const char *name) +{ + my_bool result = 0; + Query_cache_block_table *table = point; + dump_node(root, name, "parameter root"); + //back + do + { + dump_node(table, name, "list element << "); + if (table->prev->next != table) + { + DBUG_PRINT("error", + ("table 0x%lx(0x%lx) in list '%s' 0x%lx(0x%lx) is incorrect linked, prev table 0x%lx(0x%lx) refered as next to 0x%lx(0x%lx) (check from 0x%lx(0x%lx))", + (ulong) table, (ulong) table->block(), name, + (ulong) root, (ulong) root->block(), + (ulong) table->prev, (ulong) table->prev->block(), + (ulong) table->prev->next, + (ulong) table->prev->next->block(), + (ulong) point, (ulong) point->block())); + //back trace + for(; table != point; table = table->next) + DBUG_PRINT("error", ("back trace 0x%lx(0x%lx)", + (ulong) table, (ulong) table->block())); + result = 1; + goto err1; + } + table = table->prev; + } while (table != root && table != point); + if (table != root) + { + DBUG_PRINT("error", + ("table 0x%lx(0x%lx) (0x%lx(0x%lx)<-->0x%lx(0x%lx)) not owned by list '%s' 0x%lx(0x%lx)", + (ulong) table, (ulong) table->block(), + (ulong) table->prev, (ulong) table->prev->block(), + (ulong) table->next, (ulong) table->next->block(), + name, (ulong) root, (ulong) root->block())); + return 1; + } +err1: + // forward + table = point; + do + { + dump_node(table, name, "list element >> "); + if (table->next->prev != table) + { + DBUG_PRINT("error", + ("table 0x%lx(0x%lx) in list '%s' 0x%lx(0x%lx) is incorrect linked, next table 0x%lx(0x%lx) refered as prev to 0x%lx(0x%lx) (check from 0x%lx(0x%lx))", + (ulong) table, (ulong) table->block(), + name, (ulong) root, (ulong) root->block(), + (ulong) table->next, (ulong) table->next->block(), + (ulong) table->next->prev, + (ulong) table->next->prev->block(), + (ulong) point, (ulong) point->block())); + //back trace + for (; table != point; table = table->prev) + DBUG_PRINT("error", ("back trace 0x%lx(0x%lx)", + (ulong) table, (ulong) table->block())); + result = 1; + goto err2; + } + table = table->next; + } while (table != root); +err2: + return result; +} + #endif /* DBUG_OFF */ diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 4c1a5950546..23789d9f723 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -394,6 +394,9 @@ protected: my_bool check_integrity(bool not_locked); my_bool in_list(Query_cache_block * root, Query_cache_block * point, const char *name); + my_bool in_table_list(Query_cache_block_table * root, + Query_cache_block_table * point, + const char *name); my_bool in_blocks(Query_cache_block * point); }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 250c8fad5d1..14daf8c1924 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -212,8 +212,6 @@ int quick_rm_table(enum db_type base,const char *db, static int sort_keys(KEY *a, KEY *b) { - if (a == b) // Safety - return 0; if (a->flags & HA_NOSAME) { if (!(b->flags & HA_NOSAME)) @@ -235,7 +233,13 @@ static int sort_keys(KEY *a, KEY *b) { return (a->flags & HA_FULLTEXT) ? 1 : -1; } - return a < b ? -1 : 1; // Prefer original key order + /* + Prefer original key order. usable_key_parts contains here + the original key position. + */ + return ((a->usable_key_parts < b->usable_key_parts) ? -1 : + (a->usable_key_parts > b->usable_key_parts) ? 1 : + 0); } @@ -396,7 +400,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, List keys_in_order; // Add new keys here bool primary_key=0,unique_key=0; Key *key; - uint tmp; + uint tmp, key_number; tmp=min(file->max_keys(), MAX_KEY); if (key_count > tmp) { @@ -428,7 +432,8 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, DBUG_RETURN(-1); // Out of memory key_iterator.rewind(); - for (; (key=key_iterator++) ; key_info++) + key_number=0; + for (; (key=key_iterator++) ; key_info++, key_number++) { uint key_length=0; key_part_spec *column; @@ -437,6 +442,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, (key->type == Key::FULLTEXT) ? HA_FULLTEXT : HA_NOSAME; key_info->key_parts=(uint8) key->columns.elements; key_info->key_part=key_part_info; + key_info->usable_key_parts= key_number; if (key->type == Key::FULLTEXT) { From e8da7ea09ea7ccde96becbd04364df8c4e8424bd Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 6 Jan 2002 14:21:43 +0200 Subject: [PATCH 02/14] Make query cache code independent of the MYSQL_SERVER define. This fixes the query cache problem on windows. sql/net_serv.cc: Make query cache code independent of the MYSQL_SERVER define. --- sql/net_serv.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 9a8d6b5e967..22d89386516 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -54,6 +54,8 @@ ulong max_allowed_packet=65536; extern ulong net_read_timeout,net_write_timeout; extern uint test_flags; +#define USE_QUERY_CACHE +extern void query_cache_insert(NET *net, const char *packet, ulong length); #else ulong max_allowed_packet=16*1024*1024L; ulong net_read_timeout= NET_READ_TIMEOUT; @@ -72,8 +74,6 @@ void sql_print_error(const char *format,...); extern ulong mysqld_net_retry_count; extern ulong bytes_sent, bytes_received; extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received; - -extern void query_cache_insert(NET *net, const char *packet, ulong length); #else #undef statistic_add #define statistic_add(A,B,C) @@ -329,7 +329,7 @@ net_real_write(NET *net,const char *packet,ulong len) my_bool net_blocking = vio_is_blocking(net->vio); DBUG_ENTER("net_real_write"); -#ifdef MYSQL_SERVER +#ifdef USE_QUERY_CACHE if (net->query_cache_query != 0) query_cache_insert(net, packet, len); #endif From 1aae48ad409b62532dcdfc2c77e2c7807e407415 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 7 Jan 2002 16:10:54 +0200 Subject: [PATCH 03/14] mirrors.texi: Updated mirror listing slovenia.eps, slovenia.gif, slovenia.txt: new file Docs/mirrors.texi: Updated mirror listing --- Docs/Flags/slovenia.eps | 357 ++++++++++++++++++++++++++++++++++++++++ Docs/Flags/slovenia.gif | Bin 0 -> 705 bytes Docs/Flags/slovenia.txt | 0 Docs/mirrors.texi | 6 +- 4 files changed, 362 insertions(+), 1 deletion(-) create mode 100755 Docs/Flags/slovenia.eps create mode 100644 Docs/Flags/slovenia.gif create mode 100755 Docs/Flags/slovenia.txt diff --git a/Docs/Flags/slovenia.eps b/Docs/Flags/slovenia.eps new file mode 100755 index 00000000000..1588713978f --- /dev/null +++ b/Docs/Flags/slovenia.eps @@ -0,0 +1,357 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: Adobe Photoshop Version 5.5 +%%Title: slovenia.eps +%%CreationDate: Mon Jan 07 2002 15:19:42 +%%BoundingBox: 0 0 32 22 +%%HiResBoundingBox: 0 0 32 22 +%%SuppressDotGainCompensation +%%EndComments +%%BeginProlog +%%EndProlog +%%BeginSetup +%%EndSetup +%ImageData: 32 22 8 3 1 32 2 "beginimage" +%BeginPhotoshop: 1300 +% 3842494D03ED000000000010004800000001000200480000000100023842494D +% 040D000000000004000000783842494D03F30000000000080000000000000000 +% 3842494D040A00000000000100003842494D271000000000000A000100000000 +% 000000023842494D03F5000000000048002F66660001006C6666000600000000 +% 0001002F6666000100A1999A0006000000000001003200000001005A00000006 +% 000000000001003500000001002D000000060000000000013842494D03F80000 +% 000000700000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03E80000 +% 0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03E800000000FFFF +% FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03E800000000FFFFFFFFFFFF +% FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03E800003842494D0408000000000010 +% 000000010000024000000240000000003842494D041400000000000400000001 +% 3842494D040C0000000003960000000100000020000000160000006000000840 +% 0000037A00180001FFD8FFE000104A46494600010201004800480000FFEE000E +% 41646F626500648000000001FFDB0084000C08080809080C09090C110B0A0B11 +% 150F0C0C0F1518131315131318110C0C0C0C0C0C110C0C0C0C0C0C0C0C0C0C0C +% 0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C010D0B0B0D0E0D100E0E10140E0E0E +% 14140E0E0E0E14110C0C0C0C0C11110C0C0C0C0C0C110C0C0C0C0C0C0C0C0C0C +% 0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0CFFC0001108001600200301220002 +% 1101031101FFDD00040002FFC4013F0000010501010101010100000000000000 +% 030001020405060708090A0B0100010501010101010100000000000000010002 +% 030405060708090A0B1000010401030204020507060805030C33010002110304 +% 211231054151611322718132061491A1B14223241552C16233347282D1430725 +% 9253F0E1F163733516A2B283264493546445C2A3743617D255E265F2B384C3D3 +% 75E3F3462794A485B495C4D4E4F4A5B5C5D5E5F55666768696A6B6C6D6E6F637 +% 475767778797A7B7C7D7E7F71100020201020404030405060707060535010002 +% 1103213112044151617122130532819114A1B14223C152D1F0332462E1728292 +% 435315637334F1250616A2B283072635C2D2449354A317644555367465E2F2B3 +% 84C3D375E3F34694A485B495C4D4E4F4A5B5C5D5E5F55666768696A6B6C6D6E6 +% F62737475767778797A7B7C7FFDA000C03010002110311003F0096759D1BA4FD +% 55E837E1F47E9B9D99978D48BFD4C6AED7EEF46B76FB366DB373AC77E91EF577 +% EA93BA3F54CCCEC4EB1D0BA5E1D9850D8FB2D75CBB7D95BFF9EDFBB6FA6B84FA +% A3D5F2FA0751A73D949BA97B3D3BAB100BAB76D77B09FCF6ED6BD5AFAE5D7B27 +% EB1F516DD5D0EAB171DA59435F1BCEE3BACB2CDBEDDCF77E6AD38F2FCA911C47 +% 262F5478CF31EE438A12FDCF6B8BFC0641CBF32458C1908FF672FF00BD7D5FF6 +% 0FD4AFFCAFE97FF6CE3FFE45677D64E89F546AFABBD52CC7C1E9CCBD98790EA9 +% F5D5407878A9E58EADCC6EFDED77D0DABC6BECB91FE8CA85B8D7B6A7B8B0801A +% 493F2465C87282248E77192013578F5FFC711F77E646A706403FB93FFBD7FFD0 +% E231AD78C7A80A5E406375059074F3B113D6B3FD03FEF67FE945CEA4B3A5567E +% 5DFF00ACF6587DCF6E1FCEFCB1FF0031D9E8BD6B3FD03FEF67FE9443C9B5E71E +% D06978058ED49640D3CAC5829251AB1F2EFF00D6566F73DB9FF3BF2CBFCC767F +% FFD93842494D03FD000000000006000000000000 +%EndPhotoshop +%%BeginICCProfile: (Photoshop Profile) -1 Hex +% 00000C484C696E6F021000006D6E74725247422058595A2007CE000200090006 +% 00310000616373704D5346540000000049454320735247420000000000000000 +% 000000000000F6D6000100000000D32D48502020000000000000000000000000 +% 0000000000000000000000000000000000000000000000000000000000000000 +% 0000001163707274000001500000003364657363000001840000006C77747074 +% 000001F000000014626B707400000204000000147258595A0000021800000014 +% 6758595A0000022C000000146258595A0000024000000014646D6E6400000254 +% 00000070646D6464000002C400000088767565640000034C0000008676696577 +% 000003D4000000246C756D69000003F8000000146D6561730000040C00000024 +% 74656368000004300000000C725452430000043C0000080C675452430000043C +% 0000080C625452430000043C0000080C7465787400000000436F707972696768 +% 74202863292031393938204865776C6574742D5061636B61726420436F6D7061 +% 6E790000646573630000000000000012735247422049454336313936362D322E +% 31000000000000000000000012735247422049454336313936362D322E310000 +% 0000000000000000000000000000000000000000000000000000000000000000 +% 0000000000000000000000000000000058595A20000000000000F35100010000 +% 000116CC58595A200000000000000000000000000000000058595A2000000000 +% 00006FA2000038F50000039058595A2000000000000062990000B785000018DA +% 58595A2000000000000024A000000F840000B6CF646573630000000000000016 +% 49454320687474703A2F2F7777772E6965632E63680000000000000000000000 +% 1649454320687474703A2F2F7777772E6965632E636800000000000000000000 +% 0000000000000000000000000000000000000000000000000000000000000000 +% 0000000064657363000000000000002E4945432036313936362D322E31204465 +% 6661756C742052474220636F6C6F7572207370616365202D2073524742000000 +% 00000000000000002E4945432036313936362D322E312044656661756C742052 +% 474220636F6C6F7572207370616365202D207352474200000000000000000000 +% 00000000000000000000000064657363000000000000002C5265666572656E63 +% 652056696577696E6720436F6E646974696F6E20696E2049454336313936362D +% 322E3100000000000000000000002C5265666572656E63652056696577696E67 +% 20436F6E646974696F6E20696E2049454336313936362D322E31000000000000 +% 000000000000000000000000000000000000000076696577000000000013A4FE +% 00145F2E0010CF140003EDCC0004130B00035C9E0000000158595A2000000000 +% 004C09560050000000571FE76D65617300000000000000010000000000000000 +% 00000000000000000000028F0000000273696720000000004352542063757276 +% 000000000000040000000005000A000F00140019001E00230028002D00320037 +% 003B00400045004A004F00540059005E00630068006D00720077007C00810086 +% 008B00900095009A009F00A400A900AE00B200B700BC00C100C600CB00D000D5 +% 00DB00E000E500EB00F000F600FB01010107010D01130119011F0125012B0132 +% 0138013E0145014C0152015901600167016E0175017C0183018B0192019A01A1 +% 01A901B101B901C101C901D101D901E101E901F201FA0203020C0214021D0226 +% 022F02380241024B0254025D02670271027A0284028E029802A202AC02B602C1 +% 02CB02D502E002EB02F50300030B03160321032D03380343034F035A03660372 +% 037E038A039603A203AE03BA03C703D303E003EC03F9040604130420042D043B +% 0448045504630471047E048C049A04A804B604C404D304E104F004FE050D051C +% 052B053A05490558056705770586059605A605B505C505D505E505F606060616 +% 0627063706480659066A067B068C069D06AF06C006D106E306F507070719072B +% 073D074F076107740786079907AC07BF07D207E507F8080B081F08320846085A +% 086E0882089608AA08BE08D208E708FB09100925093A094F09640979098F09A4 +% 09BA09CF09E509FB0A110A270A3D0A540A6A0A810A980AAE0AC50ADC0AF30B0B +% 0B220B390B510B690B800B980BB00BC80BE10BF90C120C2A0C430C5C0C750C8E +% 0CA70CC00CD90CF30D0D0D260D400D5A0D740D8E0DA90DC30DDE0DF80E130E2E +% 0E490E640E7F0E9B0EB60ED20EEE0F090F250F410F5E0F7A0F960FB30FCF0FEC +% 1009102610431061107E109B10B910D710F511131131114F116D118C11AA11C9 +% 11E81207122612451264128412A312C312E31303132313431363138313A413C5 +% 13E5140614271449146A148B14AD14CE14F01512153415561578159B15BD15E0 +% 160316261649166C168F16B216D616FA171D17411765178917AE17D217F7181B +% 18401865188A18AF18D518FA19201945196B199119B719DD1A041A2A1A511A77 +% 1A9E1AC51AEC1B141B3B1B631B8A1BB21BDA1C021C2A1C521C7B1CA31CCC1CF5 +% 1D1E1D471D701D991DC31DEC1E161E401E6A1E941EBE1EE91F131F3E1F691F94 +% 1FBF1FEA20152041206C209820C420F0211C2148217521A121CE21FB22272255 +% 228222AF22DD230A23382366239423C223F0241F244D247C24AB24DA25092538 +% 2568259725C725F726272657268726B726E827182749277A27AB27DC280D283F +% 287128A228D429062938296B299D29D02A022A352A682A9B2ACF2B022B362B69 +% 2B9D2BD12C052C392C6E2CA22CD72D0C2D412D762DAB2DE12E162E4C2E822EB7 +% 2EEE2F242F5A2F912FC72FFE3035306C30A430DB3112314A318231BA31F2322A +% 3263329B32D4330D3346337F33B833F1342B3465349E34D83513354D358735C2 +% 35FD3637367236AE36E937243760379C37D738143850388C38C839053942397F +% 39BC39F93A363A743AB23AEF3B2D3B6B3BAA3BE83C273C653CA43CE33D223D61 +% 3DA13DE03E203E603EA03EE03F213F613FA23FE24023406440A640E74129416A +% 41AC41EE4230427242B542F7433A437D43C044034447448A44CE45124555459A +% 45DE4622466746AB46F04735477B47C04805484B489148D7491D496349A949F0 +% 4A374A7D4AC44B0C4B534B9A4BE24C2A4C724CBA4D024D4A4D934DDC4E254E6E +% 4EB74F004F494F934FDD5027507150BB51065150519B51E65231527C52C75313 +% 535F53AA53F65442548F54DB5528557555C2560F565C56A956F75744579257E0 +% 582F587D58CB591A596959B85A075A565AA65AF55B455B955BE55C355C865CD6 +% 5D275D785DC95E1A5E6C5EBD5F0F5F615FB36005605760AA60FC614F61A261F5 +% 6249629C62F06343639763EB6440649464E9653D659265E7663D669266E8673D +% 679367E9683F689668EC6943699A69F16A486A9F6AF76B4F6BA76BFF6C576CAF +% 6D086D606DB96E126E6B6EC46F1E6F786FD1702B708670E0713A719571F0724B +% 72A67301735D73B87414747074CC7528758575E1763E769B76F8775677B37811 +% 786E78CC792A798979E77A467AA57B047B637BC27C217C817CE17D417DA17E01 +% 7E627EC27F237F847FE5804780A8810A816B81CD8230829282F4835783BA841D +% 848084E3854785AB860E867286D7873B879F8804886988CE8933899989FE8A64 +% 8ACA8B308B968BFC8C638CCA8D318D988DFF8E668ECE8F368F9E9006906E90D6 +% 913F91A89211927A92E3934D93B69420948A94F4955F95C99634969F970A9775 +% 97E0984C98B89924999099FC9A689AD59B429BAF9C1C9C899CF79D649DD29E40 +% 9EAE9F1D9F8B9FFAA069A0D8A147A1B6A226A296A306A376A3E6A456A4C7A538 +% A5A9A61AA68BA6FDA76EA7E0A852A8C4A937A9A9AA1CAA8FAB02AB75ABE9AC5C +% ACD0AD44ADB8AE2DAEA1AF16AF8BB000B075B0EAB160B1D6B24BB2C2B338B3AE +% B425B49CB513B58AB601B679B6F0B768B7E0B859B8D1B94AB9C2BA3BBAB5BB2E +% BBA7BC21BC9BBD15BD8FBE0ABE84BEFFBF7ABFF5C070C0ECC167C1E3C25FC2DB +% C358C3D4C451C4CEC54BC5C8C646C6C3C741C7BFC83DC8BCC93AC9B9CA38CAB7 +% CB36CBB6CC35CCB5CD35CDB5CE36CEB6CF37CFB8D039D0BAD13CD1BED23FD2C1 +% D344D3C6D449D4CBD54ED5D1D655D6D8D75CD7E0D864D8E8D96CD9F1DA76DAFB +% DB80DC05DC8ADD10DD96DE1CDEA2DF29DFAFE036E0BDE144E1CCE253E2DBE363 +% E3EBE473E4FCE584E60DE696E71FE7A9E832E8BCE946E9D0EA5BEAE5EB70EBFB +% EC86ED11ED9CEE28EEB4EF40EFCCF058F0E5F172F1FFF28CF319F3A7F434F4C2 +% F550F5DEF66DF6FBF78AF819F8A8F938F9C7FA57FAE7FB77FC07FC98FD29FDBA +% FE4BFEDCFF6DFFFF +%%EndICCProfile +gsave % EPS gsave +/hascolor +/deviceinfo where +{pop deviceinfo /Colors known +{deviceinfo /Colors get exec 1 gt} +{false} ifelse} +{/statusdict where +{pop statusdict /processcolors known +{statusdict /processcolors get exec 1 gt} +{false} ifelse} +{false} ifelse} +ifelse +def +40 dict begin +/_image systemdict /image get def +/_setgray systemdict /setgray get def +/_currentgray systemdict /currentgray get def +/_settransfer systemdict /settransfer get def +/_currenttransfer systemdict /currenttransfer get def +/blank 0 _currenttransfer exec +1 _currenttransfer exec eq def +/negative blank +{0 _currenttransfer exec 0.5 lt} +{0 _currenttransfer exec 1 _currenttransfer exec gt} +ifelse def +/inverted? negative def +/level2 systemdict /languagelevel known +{languagelevel 2 ge} {false} ifelse def +/level3 systemdict /languagelevel known +{languagelevel 3 ge} {false} ifelse def +/foureq {4 index eq 8 1 roll +4 index eq 8 1 roll +4 index eq 8 1 roll +4 index eq 8 1 roll +pop pop pop pop and and and} def +hascolor {/band 0 def} {/band 5 def} ifelse +/setcmykcolor where {pop +1 0 0 0 setcmykcolor _currentgray 1 exch sub +0 1 0 0 setcmykcolor _currentgray 1 exch sub +0 0 1 0 setcmykcolor _currentgray 1 exch sub +0 0 0 1 setcmykcolor _currentgray 1 exch sub +4 {4 copy} repeat +1 0 0 0 foureq {/band 1 store} if +0 1 0 0 foureq {/band 2 store} if +0 0 1 0 foureq {/band 3 store} if +0 0 0 1 foureq {/band 4 store} if +0 0 0 0 foureq {/band 6 store} if} if +blank {/band 6 store} if +gsave % Image Header gsave +/rows 22 def +/cols 32 def +32 22 scale +level2 { +band 0 eq { +/DeviceRGB +} {/DeviceGray} ifelse +setcolorspace currentdict /PhotoshopDuotoneColorSpace undef currentdict /PhotoshopDuotoneAltColorSpace undef } if +/picstr1 32 string def +/picstr2 32 string def +/picstr3 32 string def +/picstr4 32 string def +/readdata {currentfile exch readhexstring pop} def +/image2 level2 {/image load def} {{begin +Width Height BitsPerComponent ImageMatrix +Decode length 2 eq +{/DataSource load image} if +Decode length 6 eq +{DataSource 0 get DataSource 1 get DataSource 2 get +true 3 colorimage} if +Decode length 8 eq +{DataSource 0 get DataSource 1 get +DataSource 2 get DataSource 3 get +true 4 colorimage} if +end} def} ifelse +/_image2 level2 {/_image load def} {{begin +Width Height BitsPerComponent ImageMatrix +/DataSource load _image end} def} ifelse +/beginimage { +band 0 eq band 4 eq or band 5 eq or +{image2} +{negative {{pop 0}} {{pop 1}} ifelse +_settransfer _image2} ifelse +} def +12 dict begin +/ImageType 1 def +/Width cols def +/Height rows def +/ImageMatrix [cols 0 0 rows neg 0 rows] def +/BitsPerComponent 8 def +band 0 eq +{/Decode [0 1 0 1 0 1] def +/MultipleDataSources true def +/DataSource [ +{picstr1 readdata} +{picstr2 readdata} +{picstr3 readdata picstr4 readdata pop} +] def} +{/Decode [0 1] def +/DataSource { +picstr1 readdata pop +picstr2 readdata pop +picstr3 readdata pop +picstr4 readdata +} def} +ifelse +currentdict end +%%BeginBinary: 5821 +beginimage +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +00F7F7F7F8FAF9F9F9F9F9F9F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7F7F9FBFBFBFBFBFBFBF8F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7F7F8F9F9F9F9F9F9F9F8F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7F7F9FAFAFAFAFAFAFAF8F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7F7F7F2F2F6F6F6F1F4F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7F7F2E9E8ECECECE7EAF4F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7F7F1EEEEEBEBEBEFEDF3F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7F7F3ECECEFEFEFEBEDF5F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7FDAB5B5D3F3C426657D5FCF7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7FE8134381A151C422BB5FEF7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7FDB8808CA3A4A0848ECCFDF7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7FE94484C3430365443C1FDF7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7FF8D33320833004623C8FEF7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7FF6B2C310831004617A9FFF7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7FDBE7F92B18FB98099CBFDF7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7FF7E373C1B3C144C29B6FEF7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7FF990000194E06000CCEFEF7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7FF7700001148000000AFFFF7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7FDB9ADBBA883B5BBAEC9FDF7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00F7F7FF8813152450161517BBFEF7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F700 +00FFFFFF9E0000248205000BD7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +00FFFFFF7C00001D7E000000B8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +00FAFAFFBBA8B2BFDEB5B3ABCCFFFAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFA00 +00FEFEFF8D1214318A151416C3FFFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFE00 +00A4A4A968443E72FC37562B8EA8A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A400 +00A1A1A7493B3A6DFC30521B71A7A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A1A100 +00E0E0E5ABBCC5D2F9C2CCB5B7E5E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E000 +00A9A9AE5D4C4A7AFC42613181AEA9A9A9A9A9A9A9A9A9A9A9A9A9A9A9A9A900 +0002020034D6E1E1FFD2EEA71900020202020202020202020202020202020200 +0000000010D6E4DDFECEF59E0000000000000000000000000000000000000000 +00B3B3B69AE8F3F0FAECF9D39BB6B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B300 +001414142AD8E5E0FED2F3A71914141414141414141414141414141414141400 +000707012BBFC8E8EEDEC4A70D04070707070707070707070707070707070700 +000000000FCEF4F6F4F5F69A0000000000000000000000000000000000000000 +00B5B5B6A3DCFCF8F6F8FEBEA9B6B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B500 +0016161428CBE8F2F2EEE8A21615161616161616161616161616161616161600 +000808070479D4B6B7B3CE460008080808080808080808080808080808080800 +00000000005DF5E7E4EADE270000000000000000000000000000000000000000 +00B5B5B5B0ACF5F7F4FAE4A2B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B500 +00161616156EEBDAD8DBDA3E1416161616161616161616161616161616161600 +000808080315B9EDD4F187030708080808080808080808080808080808080800 +0000000000028DFDF6F257000000000000000000000000000000000000000000 +00B5B5B5B7A6B6F8FEEEA6AFB6B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B5B500 +00161616151A9FF8EDF16E141616161616161616161616161616161616161600 +00070707070015AFF37F02040707070707070707070707070707070707070700 +0000000000000184D55100000000000000000000000000000000000000000000 +00B6B6B6B6B8A5B5D7A5ADB8B6B6B6B6B6B6B6B6B6B6B6B6B6B6B6B6B6B6B600 +0016161616141996DE6814151616161616161616161616161616161616161600 +0003030303030007270000030303030303030303030303030303030303030300 +0000000000000000080000000000000000000000000000000000000000000000 +00BABABABABABCB0A1B6BCBABABABABABABABABABABABABABABABABABABABA00 +0015151515151515221415151515151515151515151515151515151515151500 +00828282828282807B8182828282828282828282828282828282828282828200 +0000000000000000000000000000000000000000000000000000000000000000 +0041414141414142434140414141414141414141414141414141414141414100 +002E2E2E2E2E2E2E2C2E2E2E2E2E2E2E2E2E2E2E2E2E2E2E2E2E2E2E2E2E2E00 +00D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +003E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E00 +00C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C600 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +003B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B00 +00C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C600 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +003B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B00 +00C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C600 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +003B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B00 +00C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C600 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +003B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B00 +00C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C600 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +003B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B3B00 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 + +%%EndBinary +grestore end % Image Trailer grestore +grestore % EPS grestore diff --git a/Docs/Flags/slovenia.gif b/Docs/Flags/slovenia.gif new file mode 100644 index 0000000000000000000000000000000000000000..d16dadf3923eb4e82d77a8606db4280d77285df9 GIT binary patch literal 705 zcmV;y0zUmmNk%w1VITk&0OkMy00030|NryV*YxV`f&f5*06~EOL4W{4djLc7>F)CA z?$@}?)wRs==kLz1$+?ZT$f?V(gte=IxQAD!e^I4oLWG`tyIVAXnRmHYD~??_jE!r) zj&ZlAn!b5mtY}HAJQbur8lyrSpfnJgMkk^t2%+KK@GB3a833E7p3~CK>=gl}6#}L! z8?{bIgCiH2Gc11$0ImxFs|^6DL_53(0Ja7IwFdyT2mrMQ0I(Sms3aY~H!#9hQp|E~ z(t>{8q@m!cr{x0xxY0|2)K0Ja4HwE_UM1OTuD0Ivc7tv))%GBJ`fF^{OH@_w@7k^6~cU>(BrI#sC2K_xJz*{{R30A^8LW004dfEC2ui z03ZMs000O7fB=GngoTEOg?)-}a&C@~Yl@PSl#_yzc?k-7oDBnbm7$cEeQy#M8X+Je z6&Va|qOqiQ8!${-O;KAf5OJ}hvlv)VIxaR)F%G`Jm4bA10Tx+TJ3mHNG7ACE+}+;X zfwMP1BnMUV!)6IL!!#YlPFW7)VPrdiwA7V%$bm+hRT~M1=ZMDL&}N> z0w^dM!n3H+qcsExS-SK|juKOzFr7-Z>QX@kvT8kmzyJZQV8e>dDrk?{vuM+*U29el npSN%x Date: Mon, 7 Jan 2002 18:15:56 +0200 Subject: [PATCH 04/14] mirrors.texi: Update mirror listing Docs/mirrors.texi: Update mirror listing --- Docs/mirrors.texi | 1 + 1 file changed, 1 insertion(+) diff --git a/Docs/mirrors.texi b/Docs/mirrors.texi index 34e7a706b3c..60cb0dd12d4 100644 --- a/Docs/mirrors.texi +++ b/Docs/mirrors.texi @@ -172,6 +172,7 @@ FTP (@uref{ftp://ftp.chg.ru/pub/databases/mysql/}) @item @image{Flags/slovenia} Slovenia [ARNES] @@ +WWW (@uref{http://ftp.arnes.si/mysql/}) FTP (@uref{ftp://ftp.arnes.si/packages/mysql/}) @item From a4db469acad94a82bb1fefbdf85e232b8a38f666 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 8 Jan 2002 08:38:33 +0200 Subject: [PATCH 05/14] TODO reorganization --- sql/sql_cache.cc | 59 ++++++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 40 deletions(-) diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index c937e0243a4..37f2a5bc294 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -268,6 +268,23 @@ are stored in one block. +-------------+ +-------------+ If join_results allocated new block(s) then we need call pack_cache again. + +TODO list: + + - Invalidate queries that use innoDB tables changed in transaction & remove + invalidation by table type + - Allocate bigger blocks for results (may be we should estimate the + allocatedblock's size dynamicaly) and shrink last block with + results in query_cache_end_of_result. + - Delayed till after-parsing qache answer (for column rights processing) + - Optimize cache resizing + - if new_size < old_size then pack & shrink + - if new_size > old_size copy cached query to new cache + - Move MRG_MYISAM table type processing to handlers, something like: + tables_used->table->file->register_used_filenames(callback, + first_argument); + - In Query_cache::insert_table eliminate strlen(). To do this we have to + add db_len to the TABLE_LIST and TABLE structures. */ #include "mysql_priv.h" @@ -705,13 +722,6 @@ Query_cache::Query_cache(ulong query_cache_limit, ulong Query_cache::resize(ulong query_cache_size) { - /* - TODO: - When will be realized pack() optimize case when - query_cache_size < this->query_cache_size - - Try to copy old cache in new memory - */ DBUG_ENTER("Query_cache::resize"); DBUG_PRINT("qcache", ("from %lu to %lu",this->query_cache_size, query_cache_size)); @@ -723,11 +733,6 @@ ulong Query_cache::resize(ulong query_cache_size) void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) { - /* - TODO: - Maybe better convert keywords to upper case when query stored/compared. - (Not important at this stage) - */ TABLE_COUNTER_TYPE tables; ulong tot_length; DBUG_ENTER("Query_cache::store_query"); @@ -879,18 +884,9 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) /* Check that we haven't forgot to reset the query cache variables */ DBUG_ASSERT(thd->net.query_cache_query == 0); - /* - We can't cache the query if we are using a temporary table because - we don't know if the query is using a temporary table. - - TODO: We could parse the query and then check if the query used - a temporary table. - */ - if (thd->temporary_tables != 0 || !thd->safe_to_cache_query) + if (thd->temporary_tables != 0 ) { - DBUG_PRINT("qcache", ("SELECT is non-cacheable: tmp_tables: %d safe: %d", - thd->temporary_tables, - thd->safe_to_cache_query)); + DBUG_PRINT("qcache", ("SELECT is non-cacheable")); goto err; } @@ -1066,12 +1062,8 @@ void Query_cache::invalidate(TABLE *table) DBUG_VOID_RETURN; } - /* Remove all cached queries that uses the given table type. - TODO: This is currently used to invalidate InnoDB tables on commit. - We should remove this function and only invalidate tables - used in the transaction. */ void Query_cache::invalidate(Query_cache_table::query_cache_table_type type) @@ -1596,7 +1588,6 @@ Query_cache::append_result_data(Query_cache_block **current_block, // If no space in last block (even after join) allocate new block if (last_block_free_space < data_len) { - // TODO: Try get memory from next free block (if exist) (is it needed?) DBUG_PRINT("qcache", ("allocate new block for %lu bytes", data_len-last_block_free_space)); Query_cache_block *new_block = 0; @@ -1827,15 +1818,7 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block, Query_cache_table::type_convertion(tables_used->table-> db_type))) break; - /* - TODO: (Low priority) - The following has to be recoded to not test for a specific table - type but instead call a handler function that does this for us. - Something like the following: - tables_used->table->file->register_used_filenames(callback, - first_argument); - */ if (tables_used->table->db_type == DB_TYPE_MRG_MYISAM) { ha_myisammrg *handler = (ha_myisammrg *) tables_used->table->file; @@ -1913,10 +1896,6 @@ Query_cache::insert_table(uint key_len, char *key, DBUG_RETURN(0); } char *db = header->db(); - /* - TODO: Eliminate strlen() by sending this to the function - To do this we have to add db_len to the TABLE_LIST and TABLE structures. - */ header->table(db + strlen(db) + 1); } From 8ce7217b22af93f700d46237e69cfc11c0cc5726 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 8 Jan 2002 08:48:05 +0200 Subject: [PATCH 06/14] Typo fixing --- sql/sql_cache.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 37f2a5bc294..391fdc1abf4 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -884,7 +884,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) /* Check that we haven't forgot to reset the query cache variables */ DBUG_ASSERT(thd->net.query_cache_query == 0); - if (thd->temporary_tables != 0 ) + if (!thd->safe_to_cache_query) { DBUG_PRINT("qcache", ("SELECT is non-cacheable")); goto err; From 106c0a85231b92410f86610eb3d71862a4ac7d1a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 8 Jan 2002 17:17:16 +0200 Subject: [PATCH 07/14] mirrors.texi: Update mirror listing Docs/mirrors.texi: Update mirror listing --- Docs/mirrors.texi | 1 + 1 file changed, 1 insertion(+) diff --git a/Docs/mirrors.texi b/Docs/mirrors.texi index 60cb0dd12d4..5409c610cf4 100644 --- a/Docs/mirrors.texi +++ b/Docs/mirrors.texi @@ -322,6 +322,7 @@ FTP (@uref{ftp://ftp.shellhung.org/pub/Mirror/mysql/}) @item @image{Flags/indonesia} Indonesia [incaf.net] @@ WWW (@uref{http://mysql.incaf.net/}) +FTP (@uref{ftp://mysql.incaf.net/}) @item @image{Flags/indonesia} Indonesia [web.id] @@ From ef6119f569e4f6d34e99c2b8ff8389d0fad235bc Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 8 Jan 2002 20:17:54 +0200 Subject: [PATCH 08/14] A small fix for a VERY small Monty's bug ... --- sql/sql_parse.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2fbdf05e826..abce1322ddc 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1216,7 +1216,6 @@ mysql_execute_command(void) #endif } - thread_safe_increment(com_stat[lex->sql_command],&LOCK_thread_count); /* Skip if we are in the slave thread, some table rules have been given and the table list says the query should not be replicated From 23a6f068854fefd2435d564f267776cef9ff0da1 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 9 Jan 2002 13:17:19 +1000 Subject: [PATCH 09/14] Little fixups in change log. --- Docs/manual.texi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Docs/manual.texi b/Docs/manual.texi index 67791aac9f4..2ad5fe9b257 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -48055,7 +48055,7 @@ Fixed shutdown problem on HPUX. @item Added functions @code{des_encrypt()} and @code{des_decrypt()}. @item -Added statement FLUSH DES_KEY_FILE. +Added statement @code{FLUSH DES_KEY_FILE}. @item Added mysqld option @code{--des-key-file}. @item @@ -48108,7 +48108,7 @@ Added boolean fulltext search code. It should be considered early alpha. Extended @code{MODIFY} and @code{CHANGE} in @code{ALTER TABLE} to accept the @code{AFTER} keyword. @item -Index are now used with @code{ORDER} BY on a whole InnoDB table. +Index are now used with @code{ORDER BY} on a whole @code{InnoDB} table. @end itemize @node News-4.0.0, , News-4.0.1, News-4.0.x @@ -48123,7 +48123,7 @@ Added documentation for @code{libmysqld}, the embedded MySQL server library. Also added example programs (a @code{mysql} client and @code{mysqltest} test program) which use @code{libmysqld}. @item -Removed all Gemini hooks from MySQL. +Removed all Gemini hooks from MySQL server. @item Removed @code{my_thread_init()} and @code{my_thread_end()} from mysql_com.h, and added @code{mysql_thread_init()} and From 87ec5559477643e2574872fca93a5b4898868de0 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 9 Jan 2002 05:38:48 -0200 Subject: [PATCH 10/14] Win32 Embedded Server Changes libmysql/libmysql.def: For to have the same order of the 3.23.XX stuff libmysqld/lib_load.cc: For to have the file extension for VC++ libmysqld/lib_sql.cc: The VC++ compiler returns duplication define from net_serv.cc. If the same happens with Unix then those lines should be removed. VC++ file extension. sql/mysqld.cc: Changes for Win32 Embedded Server. sql/net_serv.cc: Sanja Fixes. sql/sql_cache.cc: To avoid the crash on Win9x --- libmysql/libmysql.def | 144 ++++++++++++++++++++++++++-------------- libmysqld/lib_load.cc | 5 ++ libmysqld/lib_sql.cc | 6 ++ libmysqld/libmysqld.def | 72 ++++++++++++++++++++ sql/mysqld.cc | 13 +++- sql/net_serv.cc | 33 +++++---- sql/sql_cache.cc | 5 ++ 7 files changed, 209 insertions(+), 69 deletions(-) create mode 100644 libmysqld/libmysqld.def diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index 47e182b6de4..9405ecd58ff 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -2,33 +2,95 @@ LIBRARY LIBMYSQL DESCRIPTION 'MySQL 4.0 Client Library' VERSION 4.0 EXPORTS - - mysql_num_rows - mysql_num_fields - mysql_eof - mysql_fetch_field_direct - mysql_fetch_fields - mysql_row_tell - mysql_field_tell - mysql_field_count mysql_affected_rows - mysql_insert_id + mysql_close + mysql_connect + mysql_create_db + mysql_data_seek + mysql_debug + mysql_drop_db + mysql_dump_debug_info + mysql_eof mysql_errno mysql_error + mysql_escape_string + mysql_fetch_field + mysql_fetch_field_direct + mysql_fetch_fields + mysql_fetch_lengths + mysql_fetch_row + mysql_field_count + mysql_field_seek + mysql_field_tell + mysql_free_result + mysql_get_client_info + mysql_get_host_info + mysql_get_proto_info + mysql_get_server_info mysql_info - mysql_thread_id - mysql_character_set_name mysql_init - mysql_ssl_set - mysql_ssl_clear - mysql_change_user - mysql_real_connect - mysql_close - mysql_select_db + mysql_insert_id + mysql_kill + mysql_list_dbs + mysql_list_fields + mysql_list_processes + mysql_list_tables + mysql_num_fields + mysql_num_rows + mysql_odbc_escape_string + mysql_options + mysql_ping mysql_query + mysql_real_connect + mysql_real_query + mysql_refresh + mysql_row_seek + mysql_row_tell + mysql_select_db + mysql_shutdown + mysql_stat + mysql_store_result + mysql_thread_id + mysql_use_result + bmove_upp + delete_dynamic + _dig_vec + init_dynamic_array + insert_dynamic + int2str + is_prefix + list_add + list_delete + max_allowed_packet + my_casecmp + my_init + my_end + my_strdup + my_malloc + my_memdup + my_no_flags_free + my_realloc + my_thread_end + my_thread_init + net_buffer_length + set_dynamic + strcend + strdup_root + strfill + strinstr + strmake + strmov + strxmov + myodbc_remove_escape + mysql_thread_safe + mysql_character_set_name + mysql_change_user mysql_send_query mysql_read_query_result - mysql_real_query + mysql_real_escape_string + mysql_ssl_set + mysql_ssl_clear + mysql_real_connect mysql_master_query mysql_master_send_query mysql_slave_query @@ -43,34 +105,18 @@ EXPORTS mysql_rpl_probe mysql_set_master mysql_add_slave - mysql_shutdown - mysql_dump_debug_info - mysql_refresh - mysql_kill - mysql_ping - mysql_stat - mysql_get_server_info - mysql_get_client_info - mysql_get_host_info - mysql_get_proto_info - mysql_list_dbs - mysql_list_tables - mysql_list_fields - mysql_list_processes - mysql_store_result - mysql_use_result - mysql_options - mysql_free_result - mysql_data_seek - mysql_row_seek - mysql_field_seek - mysql_fetch_row - mysql_fetch_lengths - mysql_fetch_field - mysql_escape_string - mysql_real_escape_string - mysql_debug - mysql_odbc_escape_string - myodbc_remove_escape - mysql_thread_safe + + + + + + + + + + + + + + diff --git a/libmysqld/lib_load.cc b/libmysqld/lib_load.cc index 37bd611b483..3db5a2488d1 100644 --- a/libmysqld/lib_load.cc +++ b/libmysqld/lib_load.cc @@ -36,4 +36,9 @@ mysql_load(THD * thd, sql_exchange * ex, TABLE_LIST * table_list, #define mysql_load mysql_load_internal + +#if defined (__WIN__) +#include "../sql/sql_load.cpp" +#else #include "../sql/sql_load.cc" +#endif diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index ed666659af1..1e3ed54ac88 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -24,8 +24,10 @@ #define main main1 #define mysql_unix_port mysql_inix_port1 #define mysql_port mysql_port1 +#if !defined(__WIN__) #define net_read_timeout net_read_timeout1 #define net_write_timeout net_write_timeout1 +#endif #define changeable_vars changeable_vars1 extern "C" @@ -45,7 +47,11 @@ static bool check_user(THD *thd, enum_server_command command, void free_defaults_internal(char ** argv) {if (argv) free_defaults(argv);} #define free_defaults free_defaults_internal +#if defined (__WIN__) +#include "../sql/mysqld.cpp" +#else #include "../sql/mysqld.cc" +#endif #define SCRAMBLE_LENGTH 8 C_MODE_START diff --git a/libmysqld/libmysqld.def b/libmysqld/libmysqld.def new file mode 100644 index 00000000000..0e126aa9ceb --- /dev/null +++ b/libmysqld/libmysqld.def @@ -0,0 +1,72 @@ +LIBRARY LIBMYSQLD +DESCRIPTION 'MySQL 4.0 Embedded Server Library' +VERSION 4.0 +EXPORTS + mysql_server_end + mysql_server_init + mysql_use_result + mysql_thread_safe + mysql_thread_id + mysql_store_result + mysql_stat + mysql_shutdown + mysql_select_db + mysql_row_tell + mysql_row_seek + mysql_real_query + mysql_real_connect + mysql_query + mysql_ping + mysql_options + mysql_num_rows + mysql_num_fields + mysql_list_tables + mysql_list_processes + mysql_list_fields + mysql_list_dbs + mysql_kill + mysql_insert_id + mysql_init + mysql_info + mysql_get_server_info + mysql_get_proto_info + mysql_get_host_info + mysql_get_client_info + mysql_free_result + mysql_field_tell + mysql_field_count + mysql_field_seek + mysql_fetch_row + mysql_fetch_lengths + mysql_fetch_fields + mysql_fetch_field_direct + mysql_fetch_field + mysql_escape_string + mysql_real_escape_string + mysql_error + mysql_errno + mysql_eof + mysql_dump_debug_info + mysql_drop_db + mysql_debug + mysql_data_seek + mysql_create_db + mysql_character_set_name + mysql_change_user + mysql_connect + mysql_close + mysql_affected_rows + mysql_thread_init + mysql_thread_end + mysql_send_query + mysql_read_query_result + mysql_refresh + mysql_odbc_escape_string + myodbc_remove_escape + + + + + + + diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8e9ff17387c..01fc23cdd38 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -380,10 +380,12 @@ enum db_type default_table_type=DB_TYPE_MYISAM; #ifdef __WIN__ #undef getpid #include +#if !defined(EMBEDDED_LIBRARY) HANDLE hEventShutdown; #include "nt_servc.h" static NTService Service; // Service object for WinNT #endif +#endif #ifdef OS2 pthread_cond_t eventShutdown; @@ -609,6 +611,7 @@ void kill_mysql(void) #endif #if defined(__WIN__) +#if !defined(EMBEDDED_LIBRARY) { if (!SetEvent(hEventShutdown)) { @@ -621,6 +624,7 @@ void kill_mysql(void) CloseHandle(hEvent); */ } +#endif #elif defined(OS2) pthread_cond_signal( &eventShutdown); // post semaphore #elif defined(HAVE_PTHREAD_KILL) @@ -1558,8 +1562,9 @@ pthread_handler_decl(handle_shutdown,arg) /* this call should create the message queue for this thread */ PeekMessage(&msg, NULL, 1, 65534,PM_NOREMOVE); - +#if !defined(EMBEDDED_LIBRARY) if (WaitForSingleObject(hEventShutdown,INFINITE)==WAIT_OBJECT_0) +#endif kill_server(MYSQL_KILL_SIGNAL); return 0; } @@ -1976,7 +1981,7 @@ The server will not act as a slave."); } } (void) thr_setconcurrency(concurrency); // 10 by default -#ifdef __WIN__ //IRENA +#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY) //IRENA { hEventShutdown=CreateEvent(0, FALSE, FALSE, "MySqlShutdown"); pthread_t hThread; @@ -2084,6 +2089,7 @@ The server will not act as a slave."); sql_print_error("After lock_thread_count"); #endif #else +#if !defined(EMBEDDED_LIBRARY) if (Service.IsNT()) { if(start_mode) @@ -2103,6 +2109,7 @@ The server will not act as a slave."); if(hEventShutdown) CloseHandle(hEventShutdown); } #endif +#endif #ifdef HAVE_OPENSSL my_free((gptr)ssl_acceptor_fd,MYF(MY_ALLOW_ZERO_PTR)); #endif /* HAVE_OPENSSL */ @@ -2123,7 +2130,7 @@ The server will not act as a slave."); } -#ifdef __WIN__ +#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY) /* ------------------------------------------------------------------------ main and thread entry function for Win32 (all this is needed only to run mysqld as a service on WinNT) diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 22d89386516..7a1d25e980d 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -62,12 +62,12 @@ ulong net_read_timeout= NET_READ_TIMEOUT; ulong net_write_timeout= NET_WRITE_TIMEOUT; #endif -#ifdef __WIN__ -/* The following is because alarms doesn't work on windows. */ -#undef MYSQL_SERVER +#if defined(__WIN__) || !defined(MYSQL_SERVER) + /* The following is because alarms doesn't work on windows. */ +#define NO_ALARM #endif - -#ifdef MYSQL_SERVER + +#ifndef NO_ALARM #include "my_pthread.h" void sql_print_error(const char *format,...); #define RETRY_COUNT mysqld_net_retry_count @@ -79,7 +79,7 @@ extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received; #define statistic_add(A,B,C) #define DONT_USE_THR_ALARM #define RETRY_COUNT 1 -#endif /* MYSQL_SERVER */ +#endif /* NO_ALARM */ #include "thr_alarm.h" @@ -322,14 +322,14 @@ net_real_write(NET *net,const char *packet,ulong len) long int length; char *pos,*end; thr_alarm_t alarmed; -#if defined(MYSQL_SERVER) +#ifndef NO_ALARM ALARM alarm_buff; #endif uint retry_count=0; my_bool net_blocking = vio_is_blocking(net->vio); DBUG_ENTER("net_real_write"); -#ifdef USE_QUERY_CACHE +#ifdef MYSQL_SERVER if (net->query_cache_query != 0) query_cache_insert(net, packet, len); #endif @@ -371,13 +371,13 @@ net_real_write(NET *net,const char *packet,ulong len) #endif /* HAVE_COMPRESS */ /* DBUG_DUMP("net",packet,len); */ -#ifdef MYSQL_SERVER +#ifndef NO_ALARM thr_alarm_init(&alarmed); if (net_blocking) thr_alarm(&alarmed,(uint) net_write_timeout,&alarm_buff); #else alarmed=0; -#endif /* MYSQL_SERVER */ +#endif /* NO_ALARM */ pos=(char*) packet; end=pos+len; while (pos != end) @@ -459,8 +459,7 @@ net_real_write(NET *net,const char *packet,ulong len) ** Read something from server/clinet *****************************************************************************/ -#ifdef MYSQL_SERVER - +#ifndef NO_ALARM /* Help function to clear the commuication buffer when we get a too big packet @@ -493,7 +492,7 @@ static void my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed) statistic_add(bytes_received,length,&LOCK_bytes_received); } } -#endif /* MYSQL_SERVER */ +#endif /* NO_ALARM */ /* @@ -510,7 +509,7 @@ my_real_read(NET *net, ulong *complen) uint i,retry_count=0; ulong len=packet_error; thr_alarm_t alarmed; -#if defined(MYSQL_SERVER) +#ifndef NO_ALARM ALARM alarm_buff; #endif my_bool net_blocking=vio_is_blocking(net->vio); @@ -520,10 +519,10 @@ my_real_read(NET *net, ulong *complen) net->reading_or_writing=1; thr_alarm_init(&alarmed); -#ifdef MYSQL_SERVER +#ifndef NO_ALARM if (net_blocking) thr_alarm(&alarmed,net->timeout,&alarm_buff); -#endif /* MYSQL_SERVER */ +#endif /* NO_ALARM */ pos = net->buff + net->where_b; /* net->packet -4 */ for (i=0 ; i < 2 ; i++) @@ -646,7 +645,7 @@ my_real_read(NET *net, ulong *complen) { if (net_realloc(net,helping)) { -#ifdef MYSQL_SERVER +#ifndef NO_ALARM if (i == 1) my_net_skip_rest(net, (uint32) len, &alarmed); #endif diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 391fdc1abf4..759aeceea76 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1167,6 +1167,11 @@ void Query_cache::pack(ulong join_limit, uint iteration_limit) void Query_cache::destroy() { + if ( !initialized ) + { + DBUG_PRINT("qcache", ("Query Cache not initialized")); + return; + } DBUG_ENTER("Query_cache::destroy"); free_cache(1); pthread_mutex_destroy(&structure_guard_mutex); From 2bf244d83f095d0c56a3263d6ddd755ac68891d5 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 12 Jan 2002 14:22:59 +0100 Subject: [PATCH 11/14] manual.texi Added CAST and CONVERT descriptions into the release notes Docs/manual.texi: Added CAST and CONVERT descriptions into the release notes BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted --- BitKeeper/etc/logging_ok | 1 + Docs/manual.texi | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index abb1d5edb2c..e623ae4add0 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -39,3 +39,4 @@ tonu@x3.internalnet jcole@sarvik.tfr.cafe.ee venu@work.mysql.com bell@sanja.is.com.ua +kaj@work.mysql.com diff --git a/Docs/manual.texi b/Docs/manual.texi index 2ad5fe9b257..5d0e3869fc4 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -48030,7 +48030,10 @@ Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}. @item Fixed bug in @code{FLUSH QUERY CACHE}. @item -Added @code{CAST()} and @code{CONVERT()} functions. +Added @code{CAST()} and @code{CONVERT()} functions. The @code{CAST} and +@code{CONVERT} functions are nearly identical and mainly useful when you +want to create a column with a specific type in a @code{CREATE ... SELECT}. +For more information, read @ref{Cast Functions}. @item Changed order of how keys are created in tables. @item From 985763d6496dcc85400b07773807b5221b449527 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 12 Jan 2002 15:40:52 +0200 Subject: [PATCH 12/14] New result block allocation strategy mysql-test/r/query_cache.result: Test changed according with new block sizes mysql-test/t/query_cache.test: Test changed according with new block sizes --- mysql-test/r/query_cache.result | 30 +++++++++---------- mysql-test/t/query_cache.test | 31 ++++++++++---------- sql/sql_cache.cc | 52 ++++++++++++++++++++++++--------- sql/sql_cache.h | 20 +++++++++---- 4 files changed, 85 insertions(+), 48 deletions(-) diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index 632f64e25de..af14575a812 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -179,23 +179,23 @@ create table t2 (a text not null); create table t21 (a text not null); create table t3 (a text not null); insert into t1 values("1111111111111111111111111111111111111111111111111111"); +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; insert into t11 select * from t1; insert into t21 select * from t1; -insert into t2 select * from t1; -insert into t1 select * from t2; -insert into t2 select * from t1; -insert into t1 select * from t2; -insert into t2 select * from t1; -insert into t1 select * from t2; -insert into t2 select * from t1; -insert into t1 select * from t2; -insert into t2 select * from t1; -insert into t1 select * from t2; -insert into t2 select * from t1; -insert into t1 select * from t2; -insert into t2 select * from t1; -insert into t1 select * from t2; -insert into t2 select * from t1; insert into t1 select * from t2; insert into t2 select * from t1; insert into t1 select * from t2; diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test index 280f2202af1..b4d00639587 100644 --- a/mysql-test/t/query_cache.test +++ b/mysql-test/t/query_cache.test @@ -93,23 +93,24 @@ create table t2 (a text not null); create table t21 (a text not null); create table t3 (a text not null); insert into t1 values("1111111111111111111111111111111111111111111111111111"); +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +# t11 and t21 must be over 4Kb (QUERY_CACHE_MIN_RESULT_DATA_SIZE) insert into t11 select * from t1; insert into t21 select * from t1; -insert into t2 select * from t1; -insert into t1 select * from t2; -insert into t2 select * from t1; -insert into t1 select * from t2; -insert into t2 select * from t1; -insert into t1 select * from t2; -insert into t2 select * from t1; -insert into t1 select * from t2; -insert into t2 select * from t1; -insert into t1 select * from t2; -insert into t2 select * from t1; -insert into t1 select * from t2; -insert into t2 select * from t1; -insert into t1 select * from t2; -insert into t2 select * from t1; insert into t1 select * from t2; insert into t2 select * from t1; insert into t1 select * from t2; diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 759aeceea76..73b15ff3cf1 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -273,9 +273,6 @@ TODO list: - Invalidate queries that use innoDB tables changed in transaction & remove invalidation by table type - - Allocate bigger blocks for results (may be we should estimate the - allocatedblock's size dynamicaly) and shrink last block with - results in query_cache_end_of_result. - Delayed till after-parsing qache answer (for column rights processing) - Optimize cache resizing - if new_size < old_size then pack & shrink @@ -657,9 +654,14 @@ void query_cache_end_of_result(NET *net) { DUMP(&query_cache); BLOCK_LOCK_WR(query_block); + Query_cache_query *header = query_block->query(); + Query_cache_block *last_result_block = header->result()->prev; + ulong allign_size = ALIGN_SIZE(last_result_block->used); + ulong len = max(query_cache.min_allocation_unit, allign_size); + if (last_result_block->length >= query_cache.min_allocation_unit + len) + query_cache.split_block(last_result_block,len); STRUCT_UNLOCK(&query_cache.structure_guard_mutex); - Query_cache_query *header = query_block->query(); #ifndef DBUG_OFF if (header->result() == 0) { @@ -1585,10 +1587,11 @@ Query_cache::append_result_data(Query_cache_block **current_block, */ // Try join blocks if physically next block is free... + ulong tail = data_len - last_block_free_space; + ulong append_min = get_min_append_result_data_size(); if (last_block_free_space < data_len && append_next_free_block(last_block, - max(data_len - last_block_free_space, - QUERY_CACHE_MIN_RESULT_DATA_SIZE))) + max(tail, append_min))) last_block_free_space = last_block->length - last_block->used; // If no space in last block (even after join) allocate new block if (last_block_free_space < data_len) @@ -1648,7 +1651,8 @@ my_bool Query_cache::write_result_data(Query_cache_block **result_block, structure_guard_mutex and copy data. */ - my_bool success = allocate_data_chain(result_block, data_len, query_block); + my_bool success = allocate_data_chain(result_block, data_len, query_block, + type == Query_cache_block::RES_BEG); if (success) { // It is success (nobody can prevent us write data) @@ -1693,13 +1697,28 @@ my_bool Query_cache::write_result_data(Query_cache_block **result_block, DBUG_RETURN(success); } +inline ulong Query_cache::get_min_first_result_data_size() +{ + if (queries_in_cache < QUERY_CACHE_MIN_ESTIMATED_QUERIES_NUMBER) + return min_result_data_size; + ulong avg_result = (query_cache_size - free_memory) / queries_in_cache; + avg_result = min(avg_result, query_cache_limit); + return max(min_result_data_size, avg_result); +} + +inline ulong Query_cache::get_min_append_result_data_size() +{ + return min_result_data_size; +} + /* Allocate one or more blocks to hold data */ my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block, ulong data_len, - Query_cache_block *query_block) + Query_cache_block *query_block, + my_bool first_block) { ulong all_headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) + ALIGN_SIZE(sizeof(Query_cache_result))); @@ -1708,7 +1727,10 @@ my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block, DBUG_PRINT("qcache", ("data_len %lu, all_headers_len %lu", data_len, all_headers_len)); - *result_block = allocate_block(max(min_result_data_size,len), + ulong min_size = (first_block ? + get_min_first_result_data_size(): + get_min_append_result_data_size()); + *result_block = allocate_block(max(min_size,len), min_result_data_size == 0, all_headers_len + min_result_data_size, 1); @@ -1732,7 +1754,7 @@ my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block, Query_cache_block *next_block; if ((success = allocate_data_chain(&next_block, len - new_block->length, - query_block))) + query_block, first_block))) double_linked_list_join(new_block, next_block); } if (success) @@ -1964,7 +1986,7 @@ Query_cache::allocate_block(ulong len, my_bool not_less, ulong min, if (block != 0) // If we found a suitable block { - if (block->length > ALIGN_SIZE(len) + min_allocation_unit) + if (block->length >= ALIGN_SIZE(len) + min_allocation_unit) split_block(block,ALIGN_SIZE(len)); } @@ -2069,7 +2091,7 @@ void Query_cache::free_memory_block(Query_cache_block *block) } -void Query_cache::split_block(Query_cache_block *block,ulong len) +void Query_cache::split_block(Query_cache_block *block, ulong len) { DBUG_ENTER("Query_cache::split_block"); Query_cache_block *new_block = (Query_cache_block*)(((byte*) block)+len); @@ -2082,7 +2104,11 @@ void Query_cache::split_block(Query_cache_block *block,ulong len) new_block->pprev = block; new_block->pnext->pprev = new_block; - insert_into_free_memory_list(new_block); + if (block->type == Query_cache_block::FREE) + // if block was free then it already joined with all free neighbours + insert_into_free_memory_list(new_block); + else + free_memory_block(new_block); DBUG_PRINT("qcache", ("split 0x%lx (%lu) new 0x%lx", (ulong) block, len, (ulong) new_block)); diff --git a/sql/sql_cache.h b/sql/sql_cache.h index 23789d9f723..b1d8eb23198 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -25,14 +25,22 @@ if QUERY_CACHE_MIN_ALLOCATION_UNIT == 0 then QUERY_CACHE_MIN_ALLOCATION_UNIT choosed automaticaly */ -#define QUERY_CACHE_MIN_ALLOCATION_UNIT 0 +#define QUERY_CACHE_MIN_ALLOCATION_UNIT 512 /* inittial size of hashes */ #define QUERY_CACHE_DEF_QUERY_HASH_SIZE 1024 #define QUERY_CACHE_DEF_TABLE_HASH_SIZE 1024 /* minimal result data size when data allocated */ -#define QUERY_CACHE_MIN_RESULT_DATA_SIZE 1024 +#define QUERY_CACHE_MIN_RESULT_DATA_SIZE 1024*4 + +/* + start estimation of first result block size only when number of queries + bigger then: +*/ +#define QUERY_CACHE_MIN_ESTIMATED_QUERIES_NUMBER 3 + + /* memory bins size spacing (see at Query_cache::init_cache (sql_cache.cc)) */ #define QUERY_CACHE_MEM_BIN_FIRST_STEP_PWR2 4 @@ -234,8 +242,7 @@ protected: query structure we locked an internal query block mutex. LOCK SEQUENCE (to prevent deadlocks): 1. structure_guard_mutex - 2. query block / table block / free block - 3. results blocks (only when must become free). + 2. query block (for operation inside query (query block/results)) */ pthread_mutex_t structure_guard_mutex; byte *cache; // cache memory @@ -271,7 +278,8 @@ protected: void free_query(Query_cache_block *point); my_bool allocate_data_chain(Query_cache_block **result_block, ulong data_len, - Query_cache_block *query_block); + Query_cache_block *query_block, + my_bool first_block); void invalidate_table(TABLE_LIST *table); void invalidate_table(TABLE *table); void invalidate_table(Query_cache_block *table_block); @@ -328,6 +336,8 @@ protected: Query_cache_block *parent, Query_cache_block::block_type type=Query_cache_block::RESULT); + inline ulong get_min_first_result_data_size(); + inline ulong get_min_append_result_data_size(); Query_cache_block *allocate_block(ulong len, my_bool not_less, ulong min, my_bool under_guard=0); From e9b8c183a2cc53ea2fd12f1dacc9cd1d422fc47a Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 12 Jan 2002 19:51:10 +0200 Subject: [PATCH 13/14] Some changes in multi-table deletes, with some speed-ups and incorporations of the new stuff. When Monty approves / corrects it, I will "port" it to multi-table updates. sql/sql_insert.cc: A small bug fix sql/sql_update.cc: query cache invalidation --- sql/sql_class.h | 2 +- sql/sql_delete.cc | 45 +++++++++++++++++++-------------------------- sql/sql_insert.cc | 2 +- sql/sql_parse.cc | 6 +++--- sql/sql_update.cc | 2 ++ 5 files changed, 26 insertions(+), 31 deletions(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index b608892f7af..7b6c4f5af57 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -656,7 +656,7 @@ public: uint num_of_tables; int error; thr_lock_type lock_option; - bool do_delete; + bool do_delete, not_trans_safe; public: multi_delete(THD *thd, TABLE_LIST *dt, thr_lock_type lock_option_arg, uint num_of_tables); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index eed6e4e5f81..f6f0b11fd94 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -216,6 +216,7 @@ multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, do_delete(false) { uint counter=0; + not_trans_safe=false; tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables-1)); (void) dt->table->file->extra(HA_EXTRA_NO_READCHECK); @@ -225,8 +226,9 @@ multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, for (dt=dt->next ; dt ; dt=dt->next,counter++) { TABLE *table=dt->table; - (void) dt->table->file->extra(HA_EXTRA_NO_READCHECK); - (void) dt->table->file->extra(HA_EXTRA_NO_KEYREAD); + (void) table->file->extra(HA_EXTRA_NO_READCHECK); + (void) table->file->extra(HA_EXTRA_NO_KEYREAD); + table->used_keys=0; tempfiles[counter] = new Unique (refposcmp2, (void *) &table->file->ref_length, table->file->ref_length, @@ -279,8 +281,11 @@ multi_delete::initialize_tables(JOIN *join) walk=walk->next; if (tab == join->join_tab) tab->table->no_keyread=1; + if (!not_trans_safe && !tab->table->file->has_transactions()) + not_trans_safe=true; } } + init_ftfuncs(thd,1); } @@ -290,7 +295,11 @@ multi_delete::~multi_delete() for (table_being_deleted=delete_tables ; table_being_deleted ; table_being_deleted=table_being_deleted->next) - (void) table_being_deleted->table->file->extra(HA_EXTRA_READCHECK); + { + TABLE *t=table_being_deleted->table; + (void) t->file->extra(HA_EXTRA_READCHECK); + t->no_keyread=0; + } for (uint counter = 0; counter < num_of_tables-1; counter++) { @@ -339,28 +348,13 @@ bool multi_delete::send_data(List &values) return 0; } - - -/* Return true if some table is not transaction safe */ - -static bool some_table_is_not_transaction_safe (TABLE_LIST *tl) -{ - for (; tl ; tl=tl->next) - { - if (!(tl->table->file->has_transactions())) - return true; - } - return false; -} - - void multi_delete::send_error(uint errcode,const char *err) { /* First send error what ever it is ... */ ::send_error(&thd->net,errcode,err); /* reset used flags */ - delete_tables->table->no_keyread=0; +// delete_tables->table->no_keyread=0; /* If nothing deleted return */ if (!deleted) @@ -376,8 +370,7 @@ void multi_delete::send_error(uint errcode,const char *err) In all other cases do attempt deletes ... */ if ((table_being_deleted->table->file->has_transactions() && - table_being_deleted == delete_tables) || - !some_table_is_not_transaction_safe(delete_tables->next)) + table_being_deleted == delete_tables) || !not_trans_safe) ha_rollback_stmt(thd); else if (do_delete) VOID(do_deletes(true)); @@ -441,7 +434,6 @@ int multi_delete::do_deletes (bool from_send_error) READ_RECORD info; init_read_record(&info,thd,table,NULL,0,0); - bool not_trans_safe = some_table_is_not_transaction_safe(delete_tables); while (!(error=info.read_record(&info)) && (!thd->killed || from_send_error || not_trans_safe)) { @@ -468,7 +460,7 @@ bool multi_delete::send_eof() int error = do_deletes(false); /* do_deletes returns 0 if success */ /* reset used flags */ - delete_tables->table->no_keyread=0; +// delete_tables->table->no_keyread=0; // Will stay in comment until Monty approves changes thd->proc_info="end"; if (error) { @@ -481,20 +473,21 @@ bool multi_delete::send_eof() was a non-transaction-safe table involved, since modifications in it cannot be rolled back. */ - if (deleted || some_table_is_not_transaction_safe(delete_tables)) + if (deleted || not_trans_safe) { mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { Query_log_event qinfo(thd, thd->query); if (mysql_bin_log.write(&qinfo) && - !some_table_is_not_transaction_safe(delete_tables)) + !not_trans_safe) error=1; // Log write failed: roll back the SQL statement } /* Commit or rollback the current SQL statement */ VOID(ha_autocommit_or_rollback(thd,error > 0)); } - + if (deleted) + query_cache.invalidate(delete_tables); ::send_ok(&thd->net,deleted); return 0; } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 75feca8d759..0898ad4bffb 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1328,7 +1328,7 @@ void select_insert::send_error(uint errcode,const char *err) ::send_error(&thd->net,errcode,err); table->file->extra(HA_EXTRA_NO_CACHE); table->file->activate_all_index(thd); - ha_rollback(thd); + ha_rollback_stmt(thd); if (info.copied || info.deleted) query_cache.invalidate(table); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index abce1322ddc..a178dfbc829 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1862,8 +1862,8 @@ mysql_execute_command(void) /* Fix tables-to-be-deleted-from list to point at opened tables */ for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next) auxi->table= ((TABLE_LIST*) auxi->table)->table; - if ((result=new multi_delete(thd,aux_tables,lex->lock_option, - table_count)) && ! thd->fatal_error) + if (!thd->fatal_error && (result=new multi_delete(thd,aux_tables, + lex->lock_option,table_count))) { res=mysql_select(thd,tables,select_lex->item_list, select_lex->where, @@ -1872,10 +1872,10 @@ mysql_execute_command(void) select_lex->options | thd->options | SELECT_NO_JOIN_CACHE, result); + delete result; } else res= -1; // Error is not sent - delete result; close_thread_tables(thd); break; } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 5e36d22744b..b9cf7478e0c 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -792,6 +792,8 @@ bool multi_update::send_eof() char buff[80]; sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated, (long) thd->cuted_fields); + if (updated) + query_cache.invalidate(update_tables); ::send_ok(&thd->net, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, thd->insert_id_used ? thd->insert_id() : 0L,buff); From 1c603ad1ef7b648fbe55ec3fdbad5d8d4cb14cba Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 13 Jan 2002 01:32:05 -0600 Subject: [PATCH 14/14] mysqldump.c: Added missing 'Q' for -Q option client/mysqldump.c: Added missing 'Q' for -Q option BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted --- BitKeeper/etc/logging_ok | 1 + client/mysqldump.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index e623ae4add0..81ba5daa043 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -40,3 +40,4 @@ jcole@sarvik.tfr.cafe.ee venu@work.mysql.com bell@sanja.is.com.ua kaj@work.mysql.com +mwagner@cash.mwagner.org diff --git a/client/mysqldump.c b/client/mysqldump.c index 25768dbe188..660b9941b84 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -35,7 +35,7 @@ ** and adapted to mysqldump 05/11/01 by Jani Tolonen */ -#define DUMP_VERSION "8.20" +#define DUMP_VERSION "8.21" #include #include @@ -309,7 +309,7 @@ static int get_options(int *argc,char ***argv) load_defaults("my",load_default_groups,argc,argv); set_all_changeable_vars(md_changeable_vars); while ((c=getopt_long(*argc,*argv, - "#::p::h:u:O:P:r:S:T:EBaAcCdefFKlnqtvVw:?IxX", + "#::p::h:u:O:P:r:S:T:EBaAcCdefFKlnqQtvVw:?IxX", long_options, &option_index)) != EOF) { switch(c) {