From e23d1768a0ac10c58513714489412d180c2ac89d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 6 Apr 2005 15:52:32 +0300 Subject: [PATCH 01/78] Fixed that create_time is set properly for cached threads --- sql/mysqld.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d75efbd0b00..c76ccf5daf7 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1488,6 +1488,7 @@ void end_thread(THD *thd, bool put_in_cache) thd=thread_cache.get(); thd->real_id=pthread_self(); (void) thd->store_globals(); + thd->thr_create_time= time(NULL); threads.append(thd); pthread_mutex_unlock(&LOCK_thread_count); DBUG_VOID_RETURN; From 57fa327069da8c1119601e427bef69336ba8125e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 6 Apr 2005 16:52:41 +0300 Subject: [PATCH 02/78] Small fixes done while reviewing pushed code mysql-test/r/innodb-replace.result: Added proper cleanup for test mysql-test/t/innodb-replace.test: Added proper cleanup for test sql/share/english/errmsg.txt: Don't extend the possible length of error message too much for common errors are MySQL 4.0 clients has a limit of 200 characters --- mysql-test/r/innodb-replace.result | 1 + mysql-test/t/innodb-replace.test | 4 ++++ sql/share/english/errmsg.txt | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/innodb-replace.result b/mysql-test/r/innodb-replace.result index a27806640ad..b7edcc49e56 100644 --- a/mysql-test/r/innodb-replace.result +++ b/mysql-test/r/innodb-replace.result @@ -1,3 +1,4 @@ +drop table if exists t1; create table t1 (c1 char(5) unique not null, c2 int, stamp timestamp) engine=innodb; select * from t1; c1 c2 stamp diff --git a/mysql-test/t/innodb-replace.test b/mysql-test/t/innodb-replace.test index e7e96da1443..516f058a68e 100644 --- a/mysql-test/t/innodb-replace.test +++ b/mysql-test/t/innodb-replace.test @@ -2,6 +2,10 @@ # embedded server ignores 'delayed', so skip this -- source include/not_embedded.inc +--disable_warnings +drop table if exists t1; +--enable_warnings + # # Bug #1078 # diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 3bfc83a4b41..1ae4e79bf01 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -67,7 +67,7 @@ character-set=latin1 "Column '%-.64s' cannot be null", "Unknown database '%-.64s'", "Table '%-.64s' already exists", -"Unknown table '%-.180s'", +"Unknown table '%-.100s'", "Column '%-.64s' in %-.64s is ambiguous", "Server shutdown in progress", "Unknown column '%-.64s' in '%-.64s'", From 11652c1f45f1c6be6c15abfe926da1cef1b8b4f9 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 18 Apr 2005 07:26:23 +0400 Subject: [PATCH 03/78] Fix for BUG#9298: Make int->string conversion sign-aware in Protocol_simple::store_long mysql-test/r/group_by.result: Testcase for BUG#9298 mysql-test/t/group_by.test: Testcase for BUG#9298 --- mysql-test/r/group_by.result | 9 +++++++++ mysql-test/t/group_by.test | 7 +++++++ sql/protocol.cc | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index a8766907fa5..b0c00a51722 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -702,3 +702,12 @@ c val-74 val-98 drop table t1,t2; +create table t1 (b int4 unsigned not null); +insert into t1 values(3000000000); +select * from t1; +b +3000000000 +select min(b) from t1; +min(b) +3000000000 +drop table t1; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 46e58cd00fd..fbd39019e6d 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -515,3 +515,10 @@ explain select c from t2 where a = 2 and b = 'val-2' group by c; select c from t2 where a = 2 and b = 'val-2' group by c; drop table t1,t2; +# Test for BUG#9298 "Wrong handling of int4 unsigned columns in GROUP functions" +# (the actual problem was with protocol code, not GROUP BY) +create table t1 (b int4 unsigned not null); +insert into t1 values(3000000000); +select * from t1; +select min(b) from t1; +drop table t1; diff --git a/sql/protocol.cc b/sql/protocol.cc index 773bbe697a3..485605ce8cd 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -810,7 +810,7 @@ bool Protocol_simple::store_long(longlong from) #endif char buff[20]; return net_store_data((char*) buff, - (uint) (int10_to_str((int) from,buff, -10)-buff)); + (uint) (int10_to_str((int)from,buff, (from <0)?-10:10)-buff)); } From a437b82affd3323bd02dc60ae0b4565825f1418d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Apr 2005 14:44:54 +0500 Subject: [PATCH 04/78] A fix (bug #9837: round(1, 6) delivers wrong value in create table context). sql/item_func.cc: A fix (bug #9837: round(1, 6) delivers wrong value in create table context). As we change decimals, we should change max_length accordingly. --- mysql-test/r/func_math.result | 11 +++++++++++ mysql-test/t/func_math.test | 13 +++++++++++++ sql/item_func.cc | 2 ++ 3 files changed, 26 insertions(+) diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index 3a28cccfac5..9cb1e4a56d6 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -1,3 +1,4 @@ +drop table if exists t1; select floor(5.5),floor(-5.5); floor(5.5) floor(-5.5) 5 -6 @@ -126,3 +127,13 @@ Warnings: Note 1003 select degrees(pi()) AS `degrees(pi())`,radians(360) AS `radians(360)` select rand(rand); ERROR 42S22: Unknown column 'rand' in 'field list' +create table t1 select round(1, 6); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `round(1, 6)` double(7,6) NOT NULL default '0.000000' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select * from t1; +round(1, 6) +1.000000 +drop table t1; diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index 668aefc2d8d..4c24dae8c5d 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -2,6 +2,10 @@ # Test of math functions # +--disable_warnings +drop table if exists t1; +--enable_warnings + select floor(5.5),floor(-5.5); explain extended select floor(5.5),floor(-5.5); select ceiling(5.5),ceiling(-5.5); @@ -58,3 +62,12 @@ explain extended select degrees(pi()),radians(360); --error 1054 select rand(rand); + +# +# Bug #9837: problem with round() +# + +create table t1 select round(1, 6); +show create table t1; +select * from t1; +drop table t1; diff --git a/sql/item_func.cc b/sql/item_func.cc index eb6e395c266..2b38584fe23 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1072,6 +1072,8 @@ void Item_func_round::fix_length_and_dec() decimals=0; else decimals=min(tmp,NOT_FIXED_DEC); + if ((tmp= decimals - args[0]->decimals) > 0) + max_length+= tmp; } } From 273d78e115019e44af774e8b62a0ab595bd467db Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Apr 2005 19:27:46 +0300 Subject: [PATCH 05/78] Many files: Semi-synchronous replication for InnoDB type tables; before telling the client that a commit has been processed, wait that the replication thread has returned from my_net_send() where it sends the binlog to the slave; note that TCP/IP, even with the TCP_NODELAY option does not guarantee that the slave has RECEIVED the data - this is just heuristic at the moment; this is useful in failover: in almost all cases, every transaction that has returned from the commit has been sent and processed in the slave, which makes failover to the slave simpler if the master crashes; the code does not work yet as is, because MySQL should call innobase_report_binlog_offset_and_commit() in a commit; we will most probably return that call to 5.0.x, to make InnoDB Hot Backup and group commit to work again; XA code broke them temporarily in 5.0.3 sql/ha_innodb.cc: Semi-synchronous replication for InnoDB type tables; before telling the client that a commit has been processed, wait that the replication thread has returned from my_net_send() where it sends the binlog to the slave; note that TCP/IP, even with the TCP_NODELAY option does not guarantee that the slave has RECEIVED the data - this is just heuristic at the moment; this is useful in failover: in almost all cases, every transaction that has returned from the commit has been sent and processed in the slave, which makes failover to the slave simpler if the master crashes; the code does not work yet as is, because MySQL should call innobase_report_binlog_offset_and_commit() in a commit; we will most probably return that call to 5.0.x, to make InnoDB Hot Backup and group commit to work again; XA code broke them temporarily in 5.0.3 sql/handler.cc: Semi-synchronous replication for InnoDB type tables; before telling the client that a commit has been processed, wait that the replication thread has returned from my_net_send() where it sends the binlog to the slave; note that TCP/IP, even with the TCP_NODELAY option does not guarantee that the slave has RECEIVED the data - this is just heuristic at the moment; this is useful in failover: in almost all cases, every transaction that has returned from the commit has been sent and processed in the slave, which makes failover to the slave simpler if the master crashes; the code does not work yet as is, because MySQL should call innobase_report_binlog_offset_and_commit() in a commit; we will most probably return that call to 5.0.x, to make InnoDB Hot Backup and group commit to work again; XA code broke them temporarily in 5.0.3 sql/mysqld.cc: Semi-synchronous replication for InnoDB type tables; before telling the client that a commit has been processed, wait that the replication thread has returned from my_net_send() where it sends the binlog to the slave; note that TCP/IP, even with the TCP_NODELAY option does not guarantee that the slave has RECEIVED the data - this is just heuristic at the moment; this is useful in failover: in almost all cases, every transaction that has returned from the commit has been sent and processed in the slave, which makes failover to the slave simpler if the master crashes; the code does not work yet as is, because MySQL should call innobase_report_binlog_offset_and_commit() in a commit; we will most probably return that call to 5.0.x, to make InnoDB Hot Backup and group commit to work again; XA code broke them temporarily in 5.0.3 sql/set_var.cc: Semi-synchronous replication for InnoDB type tables; before telling the client that a commit has been processed, wait that the replication thread has returned from my_net_send() where it sends the binlog to the slave; note that TCP/IP, even with the TCP_NODELAY option does not guarantee that the slave has RECEIVED the data - this is just heuristic at the moment; this is useful in failover: in almost all cases, every transaction that has returned from the commit has been sent and processed in the slave, which makes failover to the slave simpler if the master crashes; the code does not work yet as is, because MySQL should call innobase_report_binlog_offset_and_commit() in a commit; we will most probably return that call to 5.0.x, to make InnoDB Hot Backup and group commit to work again; XA code broke them temporarily in 5.0.3 sql/sql_repl.cc: Semi-synchronous replication for InnoDB type tables; before telling the client that a commit has been processed, wait that the replication thread has returned from my_net_send() where it sends the binlog to the slave; note that TCP/IP, even with the TCP_NODELAY option does not guarantee that the slave has RECEIVED the data - this is just heuristic at the moment; this is useful in failover: in almost all cases, every transaction that has returned from the commit has been sent and processed in the slave, which makes failover to the slave simpler if the master crashes; the code does not work yet as is, because MySQL should call innobase_report_binlog_offset_and_commit() in a commit; we will most probably return that call to 5.0.x, to make InnoDB Hot Backup and group commit to work again; XA code broke them temporarily in 5.0.3 sql/ha_innodb.h: Semi-synchronous replication for InnoDB type tables; before telling the client that a commit has been processed, wait that the replication thread has returned from my_net_send() where it sends the binlog to the slave; note that TCP/IP, even with the TCP_NODELAY option does not guarantee that the slave has RECEIVED the data - this is just heuristic at the moment; this is useful in failover: in almost all cases, every transaction that has returned from the commit has been sent and processed in the slave, which makes failover to the slave simpler if the master crashes; the code does not work yet as is, because MySQL should call innobase_report_binlog_offset_and_commit() in a commit; we will most probably return that call to 5.0.x, to make InnoDB Hot Backup and group commit to work again; XA code broke them temporarily in 5.0.3 sql/handler.h: Semi-synchronous replication for InnoDB type tables; before telling the client that a commit has been processed, wait that the replication thread has returned from my_net_send() where it sends the binlog to the slave; note that TCP/IP, even with the TCP_NODELAY option does not guarantee that the slave has RECEIVED the data - this is just heuristic at the moment; this is useful in failover: in almost all cases, every transaction that has returned from the commit has been sent and processed in the slave, which makes failover to the slave simpler if the master crashes; the code does not work yet as is, because MySQL should call innobase_report_binlog_offset_and_commit() in a commit; we will most probably return that call to 5.0.x, to make InnoDB Hot Backup and group commit to work again; XA code broke them temporarily in 5.0.3 --- sql/ha_innodb.cc | 287 ++++++++++++++++++++++++++++++++++++++++++++++- sql/ha_innodb.h | 2 + sql/handler.cc | 57 ++++++++++ sql/handler.h | 6 +- sql/mysqld.cc | 2 - sql/set_var.cc | 2 - sql/sql_repl.cc | 37 ++++++ 7 files changed, 382 insertions(+), 11 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 3f592e36219..e68a85bdac9 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -45,10 +45,58 @@ have disables the InnoDB inlining in this file. */ #include "ha_innodb.h" -pthread_mutex_t innobase_share_mutex, // to protect innobase_open_files - prepare_commit_mutex; // to force correct commit order in binlog +pthread_mutex_t innobase_share_mutex, /* to protect innobase_open_files */ + prepare_commit_mutex; /* to force correct commit order in + binlog */ bool innodb_inited= 0; +/*-----------------------------------------------------------------*/ +/* These variables are used to implement (semi-)synchronous MySQL binlog +replication for InnoDB tables. */ + +pthread_cond_t innobase_repl_cond; /* Posix cond variable; + this variable is signaled + when enough binlog has been + sent to slave, so that a + waiting trx can return the + 'ok' message to the client + for a commit */ +pthread_mutex_t innobase_repl_cond_mutex; /* Posix cond variable mutex + that also protects the next + innobase_repl_... variables */ +uint innobase_repl_state; /* 1 if synchronous replication + is switched on and is working + ok; else 0 */ +uint innobase_repl_file_name_inited = 0; /* This is set to 1 when + innobase_repl_file_name + contains meaningful data */ +char* innobase_repl_file_name; /* The binlog name up to which + we have sent some binlog to + the slave */ +my_off_t innobase_repl_pos; /* The position in that file + up to which we have sent the + binlog to the slave */ +uint innobase_repl_n_wait_threads = 0; /* This tells how many + transactions currently are + waiting for the binlog to be + sent to the client */ +uint innobase_repl_wait_file_name_inited = 0; /* This is set to 1 + when we know the 'smallest' + wait position */ +char* innobase_repl_wait_file_name; /* NULL, or the 'smallest' + innobase_repl_file_name that + a transaction is waiting for */ +my_off_t innobase_repl_wait_pos; /* The smallest position in + that file that a trx is + waiting for: the trx can + proceed and send an 'ok' to + the client when MySQL has sent + the binlog up to this position + to the slave */ +/*-----------------------------------------------------------------*/ + + + /* Store MySQL definition of 'byte': in Linux it is char while InnoDB uses unsigned char; the header univ.i which we include next defines 'byte' as a macro which expands to 'unsigned char' */ @@ -97,7 +145,7 @@ long innobase_mirrored_log_groups, innobase_log_files_in_group, innobase_log_file_size, innobase_log_buffer_size, innobase_buffer_pool_awe_mem_mb, innobase_buffer_pool_size, innobase_additional_mem_pool_size, - innobase_file_io_threads, innobase_lock_wait_timeout, + innobase_file_io_threads, innobase_lock_wait_timeout, innobase_thread_concurrency, innobase_force_recovery, innobase_open_files; @@ -1531,10 +1579,10 @@ innobase_commit( DBUG_RETURN(0); } -/* The following defined-out code will be enabled later when we put the +/* TODO: put the MySQL-4.1 functionality back to 5.0. This is needed to get InnoDB Hot Backup to work. */ -#if 0 + /********************************************************************* This is called when MySQL writes the binlog entry for the current transaction. Writes to the InnoDB tablespace info which tells where the @@ -1563,6 +1611,24 @@ innobase_report_binlog_offset_and_commit( trx->mysql_log_file_name = log_file_name; trx->mysql_log_offset = (ib_longlong)end_offset; + if (thd->variables.sync_replication) { + /* Let us store the binlog file name and the position, so that + we know how long to wait for the binlog to the replicated to + the slave in synchronous replication. */ + + if (trx->repl_wait_binlog_name == NULL) { + + trx->repl_wait_binlog_name = + (char*)mem_alloc(FN_REFLEN + 100); + } + + ut_a(strlen(log_file_name) <= FN_REFLEN + 100); + + strcpy(trx->repl_wait_binlog_name, log_file_name); + + trx->repl_wait_binlog_pos = (ib_longlong)end_offset; + } + trx->flush_log_later = TRUE; innobase_commit(thd, trx_handle); @@ -1572,6 +1638,7 @@ innobase_report_binlog_offset_and_commit( return(0); } +#if 0 /*********************************************************************** This function stores the binlog offset and flushes logs. */ @@ -1602,7 +1669,6 @@ innobase_store_binlog_offset_and_flush_log( /* Syncronous flush of the log buffer to disk */ log_buffer_flush_to_disk(); } - #endif /********************************************************************* @@ -1615,7 +1681,10 @@ innobase_commit_complete( /* out: 0 */ THD* thd) /* in: user thread */ { + struct timespec abstime; trx_t* trx; + int cmp; + int ret; trx = (trx_t*) thd->ha_data[innobase_hton.slot]; @@ -1631,9 +1700,215 @@ innobase_commit_complete( trx_commit_complete_for_mysql(trx); } + printf("Wait binlog name %s, repl state %lu\n", + trx->repl_wait_binlog_name, + (uint)innobase_repl_state); + + if (thd->variables.sync_replication + && trx->repl_wait_binlog_name + && innobase_repl_state != 0) { + + /* In synchronous replication, let us wait until the MySQL + replication has sent the relevant binlog segment to the + replication slave. */ + +/* TODO: Make sure MySQL uses some way (TCP_NODELAY?) to ensure that the data +has been received in the slave! */ + + pthread_mutex_lock(&innobase_repl_cond_mutex); +try_again: + if (innobase_repl_state == 0) { + + pthread_mutex_unlock(&innobase_repl_cond_mutex); + + return(0); + } + + cmp = strcmp(innobase_repl_file_name, + trx->repl_wait_binlog_name); + if (cmp > 0 + || (cmp == 0 && innobase_repl_pos + >= (my_off_t)trx->repl_wait_binlog_pos)) { + /* We have already sent the relevant binlog to the + slave: no need to wait here */ + + pthread_mutex_unlock(&innobase_repl_cond_mutex); + +/* printf("Binlog now sent\n"); */ + + return(0); + } + + /* Let us update the info about the minimum binlog position + of waiting threads in the innobase_repl_... variables */ + + if (innobase_repl_wait_file_name_inited != 0) { + cmp = strcmp(trx->repl_wait_binlog_name, + innobase_repl_wait_file_name); + if (cmp < 0 + || (cmp == 0 && (my_off_t)trx->repl_wait_binlog_pos + <= innobase_repl_wait_pos)) { + /* This thd has an even lower position, let + us update the minimum info */ + + strcpy(innobase_repl_wait_file_name, + trx->repl_wait_binlog_name); + + innobase_repl_wait_pos = + trx->repl_wait_binlog_pos; + } + } else { + strcpy(innobase_repl_wait_file_name, + trx->repl_wait_binlog_name); + + innobase_repl_wait_pos = trx->repl_wait_binlog_pos; + + innobase_repl_wait_file_name_inited = 1; + } + set_timespec(abstime, thd->variables.sync_replication_timeout); + + /* Let us suspend this thread to wait on the condition; + when replication has progressed far enough, we will release + these waiting threads. The following call + pthread_cond_timedwait also atomically unlocks + innobase_repl_cond_mutex. */ + + innobase_repl_n_wait_threads++; + +/* printf("Waiting for binlog to be sent\n"); */ + + ret = pthread_cond_timedwait(&innobase_repl_cond, + &innobase_repl_cond_mutex, &abstime); + innobase_repl_n_wait_threads--; + + if (ret != 0) { + ut_print_timestamp(stderr); + + fprintf(stderr, +" InnoDB: Error: MySQL synchronous replication\n" +"InnoDB: was not able to send the binlog to the slave within the\n" +"InnoDB: timeout %lu. We assume that the slave has become inaccessible,\n" +"InnoDB: and switch off synchronous replication until the communication.\n" +"InnoDB: to the slave works again.\n", + thd->variables.sync_replication_timeout); + fprintf(stderr, +"InnoDB: MySQL synchronous replication has sent binlog\n" +"InnoDB: to the slave up to file %s, position %lu\n", innobase_repl_file_name, + (ulong)innobase_repl_pos); + fprintf(stderr, +"InnoDB: This transaction needs it to be sent up to\n" +"InnoDB: file %s, position %lu\n", trx->repl_wait_binlog_name, + (uint)trx->repl_wait_binlog_pos); + + innobase_repl_state = 0; + + pthread_mutex_unlock(&innobase_repl_cond_mutex); + + return(0); + } + + goto try_again; + } + return(0); } +/********************************************************************* +In synchronous replication, reports to InnoDB up to which binlog position +we have sent the binlog to the slave. Note that replication is synchronous +for one slave only. For other slaves, we do nothing in this function. This +function is used in a replication master. */ + +int +innobase_repl_report_sent_binlog( +/*=============================*/ + /* out: 0 */ + THD* thd, /* in: thread doing the binlog communication to + the slave */ + char* log_file_name, /* in: binlog file name */ + my_off_t end_offset) /* in: the offset in the binlog file up to + which we sent the contents to the slave */ +{ + int cmp; + ibool can_release_threads = 0; + + /* If synchronous replication is not switched on, or this thd is + sending binlog to a slave where we do not need synchronous replication, + then return immediately */ + + if (thd->server_id != thd->variables.sync_replication_slave_id) { + + /* Do nothing */ + + return(0); + } + + pthread_mutex_lock(&innobase_repl_cond_mutex); + + if (innobase_repl_state == 0) { + + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: Switching MySQL synchronous replication on again at\n" +"InnoDB: binlog file %s, position %lu\n", log_file_name, (ulong)end_offset); + + innobase_repl_state = 1; + } + + /* The position should increase monotonically, since just one thread + is sending the binlog to the slave for which we want synchronous + replication. Let us check this, and print an error to the .err log + if that is not the case. */ + + if (innobase_repl_file_name_inited) { + cmp = strcmp(log_file_name, innobase_repl_file_name); + + if (cmp < 0 + || (cmp == 0 && end_offset < innobase_repl_pos)) { + + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: Error: MySQL synchronous replication has sent binlog\n" +"InnoDB: to the slave up to file %s, position %lu\n", innobase_repl_file_name, + (ulong)innobase_repl_pos); + fprintf(stderr, +"InnoDB: but now MySQL reports that it sent the binlog only up to\n" +"InnoDB: file %s, position %lu\n", log_file_name, (ulong)end_offset); + + } + } + + strcpy(innobase_repl_file_name, log_file_name); + innobase_repl_pos = end_offset; + innobase_repl_file_name_inited = 1; + + if (innobase_repl_n_wait_threads > 0) { + /* Let us check if some of the waiting threads doing a trx + commit can now proceed */ + + cmp = strcmp(innobase_repl_file_name, + innobase_repl_wait_file_name); + if (cmp > 0 + || (cmp == 0 && innobase_repl_pos + >= innobase_repl_wait_pos)) { + + /* Yes, at least one waiting thread can now proceed: + let us release all waiting threads with a broadcast */ + + can_release_threads = 1; + + innobase_repl_wait_file_name_inited = 0; + } + } + + pthread_mutex_unlock(&innobase_repl_cond_mutex); + + if (can_release_threads) { + + pthread_cond_broadcast(&innobase_repl_cond); + } +} + /********************************************************************* Rolls back a transaction or the latest SQL statement. */ diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 35f95ead757..6c412a889b2 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -321,3 +321,5 @@ int innobase_rollback_by_xid( int innobase_xa_end(THD *thd); +int innobase_repl_report_sent_binlog(THD *thd, char *log_file_name, + my_off_t end_offset); diff --git a/sql/handler.cc b/sql/handler.cc index 14b8974ece9..6ab4f7824ed 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2411,3 +2411,60 @@ TYPELIB *ha_known_exts(void) } return &known_extensions; } + +/* + Reports to table handlers up to which position we have sent the binlog + to a slave in replication + + SYNOPSIS + ha_repl_report_sent_binlog() + + NOTES + Only works for InnoDB at the moment + + RETURN VALUE + Always 0 (= success) + + PARAMETERS + THD *thd in: thread doing the binlog communication to + the slave + char *log_file_name in: binlog file name + my_off_t end_offset in: the offset in the binlog file up to + which we sent the contents to the slave +*/ + +int ha_repl_report_sent_binlog(THD *thd, char *log_file_name, + my_off_t end_offset) +{ +#ifdef HAVE_INNOBASE_DB + return innobase_repl_report_sent_binlog(thd,log_file_name,end_offset); +#else + /* remove warnings about unused parameters */ + thd=thd; log_file_name=log_file_name; end_offset=end_offset; + return 0; +#endif +} + +/* + Reports to table handlers that we stop replication to a specific slave + + SYNOPSIS + ha_repl_report_replication_stop() + + NOTES + Does nothing at the moment + + RETURN VALUE + Always 0 (= success) + + PARAMETERS + THD *thd in: thread doing the binlog communication to + the slave +*/ + +int ha_repl_report_replication_stop(THD *thd) +{ + thd = thd; + + return 0; +} diff --git a/sql/handler.h b/sql/handler.h index 4c06fe8299d..5e25f038c36 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -843,7 +843,7 @@ int ha_change_key_cache_param(KEY_CACHE *key_cache); int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache); int ha_end_key_cache(KEY_CACHE *key_cache); -/* weird stuff */ +/* report to InnoDB that control passes to the client */ int ha_release_temporary_latches(THD *thd); /* transactions: interface to handlerton functions */ @@ -875,3 +875,7 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht); #define trans_need_2pc(thd, all) ((total_ha_2pc > 1) && \ !((all ? &thd->transaction.all : &thd->transaction.stmt)->no_2pc)) +/* semi-synchronous replication */ +int ha_repl_report_sent_binlog(THD *thd, char *log_file_name, + my_off_t end_offset); +int ha_repl_report_replication_stop(THD *thd); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9c592d068ee..214915a3cb0 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5495,7 +5495,6 @@ The minimum value for this variable is 4096.", {"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default.", (gptr*) &opt_sync_frm, (gptr*) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, -#ifdef DOES_NOTHING_YET {"sync-replication", OPT_SYNC_REPLICATION, "Enable synchronous replication.", (gptr*) &global_system_variables.sync_replication, @@ -5511,7 +5510,6 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.sync_replication_timeout, (gptr*) &global_system_variables.sync_replication_timeout, 0, GET_ULONG, REQUIRED_ARG, 10, 0, ~0L, 0, 1, 0}, -#endif {"table_cache", OPT_TABLE_CACHE, "The number of open tables for all threads.", (gptr*) &table_cache_size, (gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, 64, 1, 512*1024L, diff --git a/sql/set_var.cc b/sql/set_var.cc index 70d64b5dac6..09fc7b20dad 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -957,11 +957,9 @@ struct show_var_st init_vars[]= { {"sql_warnings", (char*) &sys_sql_warnings, SHOW_BOOL}, #ifdef HAVE_REPLICATION {sys_sync_binlog_period.name,(char*) &sys_sync_binlog_period, SHOW_SYS}, -#ifdef DOES_NOTHING_YET {sys_sync_replication.name, (char*) &sys_sync_replication, SHOW_SYS}, {sys_sync_replication_slave_id.name, (char*) &sys_sync_replication_slave_id,SHOW_SYS}, {sys_sync_replication_timeout.name, (char*) &sys_sync_replication_timeout,SHOW_SYS}, -#endif #endif {sys_sync_frm.name, (char*) &sys_sync_frm, SHOW_SYS}, #ifdef HAVE_TZNAME diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 634b6ab0995..72470c487a3 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -385,6 +385,11 @@ impossible position"; goto err; } + printf("Binlog file name %s\n", log_file_name); + + if (thd->variables.sync_replication) + ha_repl_report_sent_binlog(thd, log_file_name, pos); + /* We need to start a packet with something other than 255 to distinguish it from error @@ -470,6 +475,10 @@ impossible position"; my_errno= ER_UNKNOWN_ERROR; goto err; } + + if (thd->variables.sync_replication) + ha_repl_report_sent_binlog(thd, log_file_name, my_b_tell(&log)); + /* No need to save this event. We are only doing simple reads (no real parsing of the events) so we don't need it. And so @@ -527,6 +536,13 @@ impossible position"; my_errno= ER_UNKNOWN_ERROR; goto err; } + + printf("Dump loop: %s: Current log position %lu\n", log_file_name, + (ulong)my_b_tell(&log)); + + if (thd->variables.sync_replication) + ha_repl_report_sent_binlog(thd, log_file_name, my_b_tell(&log)); + DBUG_PRINT("info", ("log event code %d", (*packet)[LOG_EVENT_OFFSET+1] )); if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT) @@ -640,6 +656,12 @@ impossible position"; goto err; } + printf("Second loop: %s: Current log position %lu\n", log_file_name, + (ulong)my_b_tell(&log)); + + if (thd->variables.sync_replication) + ha_repl_report_sent_binlog(thd, log_file_name, my_b_tell(&log)); + if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT) { if (send_file(thd)) @@ -704,12 +726,22 @@ impossible position"; my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; goto err; } + + if (thd->variables.sync_replication) + ha_repl_report_sent_binlog(thd, log_file_name, 0); + + printf("Binlog file name of a new binlog %s\n", log_file_name); + packet->length(0); packet->append('\0'); } } end: + printf("Ending replication\n"); + if (thd->variables.sync_replication) + ha_repl_report_replication_stop(thd); + end_io_cache(&log); (void)my_close(file, MYF(MY_WME)); @@ -721,6 +753,11 @@ end: DBUG_VOID_RETURN; err: + if (thd->variables.sync_replication) + ha_repl_report_replication_stop(thd); + + printf("Ending replication in error %s\n", errmsg); + thd->proc_info = "Waiting to finalize termination"; end_io_cache(&log); /* From 677fbc7d4e34dff14aaf49efa114bc85aa986da1 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Apr 2005 20:10:28 +0200 Subject: [PATCH 06/78] Step 1 of the switch to support configuration with NPTL: Rename 'IS_LINUX' configuration variable to 'TARGET_LINUX'. --- acinclude.m4 | 2 +- configure.in | 18 +++++++++--------- myisam/Makefile.am | 2 +- scripts/Makefile.am | 2 +- scripts/mysqld_safe.sh | 2 +- support-files/Makefile.am | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index 74426bc2061..a81a4fa5c3f 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -976,7 +976,7 @@ AC_DEFUN([MYSQL_FIND_OPENSSL], [ if test -z "$OPENSSL_LIB" -o -z "$OPENSSL_INCLUDE" ; then echo "Could not find an installation of OpenSSL" if test -n "$OPENSSL_LIB" ; then - if test "$IS_LINUX" = "true"; then + if test "$TARGET_LINUX" = "true"; then echo "Looks like you've forgotten to install OpenSSL development RPM" fi fi diff --git a/configure.in b/configure.in index d191463d0f9..6650c0fc64a 100644 --- a/configure.in +++ b/configure.in @@ -410,15 +410,15 @@ AC_MSG_CHECKING("if we should use 'skip-locking' as default for $target_os") if expr "$target_os" : "[[Ll]]inux.*" > /dev/null then MYSQLD_DEFAULT_SWITCHES="--skip-locking" - IS_LINUX="true" + TARGET_LINUX="true" AC_MSG_RESULT("yes"); else MYSQLD_DEFAULT_SWITCHES="" - IS_LINUX="false" + TARGET_LINUX="false" AC_MSG_RESULT("no"); fi AC_SUBST(MYSQLD_DEFAULT_SWITCHES) -AC_SUBST(IS_LINUX) +AC_SUBST(TARGET_LINUX) dnl Find paths to some shell programs AC_PATH_PROG(LN, ln, ln) @@ -607,7 +607,7 @@ AC_SUBST(NOINST_LDFLAGS) # (this is true on the MySQL build machines to avoid NSS problems) # -if test "$IS_LINUX" = "true" -a "$static_nss" = "" +if test "$TARGET_LINUX" = "true" -a "$static_nss" = "" then tmp=`nm /usr/lib/libc.a | grep _nss_files_getaliasent_r` if test -n "$tmp" @@ -841,7 +841,7 @@ struct request_info *req; ]) AC_SUBST(WRAPLIBS) -if test "$IS_LINUX" = "true"; then +if test "$TARGET_LINUX" = "true"; then AC_MSG_CHECKING([for atomic operations]) atom_ops= @@ -885,7 +885,7 @@ int main() [ USE_PSTACK=no ]) pstack_libs= pstack_dirs= - if test "$USE_PSTACK" = yes -a "$IS_LINUX" = "true" -a "$BASE_MACHINE_TYPE" = "i386" -a "$with_mit_threads" = "no" + if test "$USE_PSTACK" = yes -a "$TARGET_LINUX" = "true" -a "$BASE_MACHINE_TYPE" = "i386" -a "$with_mit_threads" = "no" then have_libiberty= have_libbfd= my_save_LIBS="$LIBS" @@ -1286,7 +1286,7 @@ then else AC_MSG_RESULT("Not found") # If this is a linux machine we should barf - if test "$IS_LINUX" = "true" + if test "$TARGET_LINUX" = "true" then AC_MSG_ERROR([This is a linux system and Linuxthreads was not found. On linux Linuxthreads should be used. Please install Linuxthreads @@ -1738,7 +1738,7 @@ fi AC_SUBST(COMPILATION_COMMENT) AC_MSG_CHECKING("need of special linking flags") -if test "$IS_LINUX" = "true" -a "$ac_cv_prog_gcc" = "yes" -a "$all_is_static" != "yes" +if test "$TARGET_LINUX" = "true" -a "$ac_cv_prog_gcc" = "yes" -a "$all_is_static" != "yes" then LDFLAGS="$LDFLAGS -rdynamic" AC_MSG_RESULT("-rdynamic") @@ -1955,7 +1955,7 @@ CFLAGS="$ORG_CFLAGS" # Sanity check: We chould not have any fseeko symbol unless # large_file_support=yes AC_CHECK_FUNC(fseeko, -[if test "$large_file_support" = no -a "$IS_LINUX" = "true"; +[if test "$large_file_support" = no -a "$TARGET_LINUX" = "true"; then AC_MSG_ERROR("Found fseeko symbol but large_file_support is not enabled!"); fi] diff --git a/myisam/Makefile.am b/myisam/Makefile.am index 378e8107814..0b8a25e3404 100644 --- a/myisam/Makefile.am +++ b/myisam/Makefile.am @@ -88,7 +88,7 @@ SUFFIXES = .sh -e 's!@''FIND_PROC''@!@FIND_PROC@!' \ -e 's!@''MYSQLD_DEFAULT_SWITCHES''@!@MYSQLD_DEFAULT_SWITCHES@!' \ -e 's!@''MYSQL_UNIX_ADDR''@!@MYSQL_UNIX_ADDR@!' \ - -e 's!@''IS_LINUX''@!@IS_LINUX@!' \ + -e 's!@''TARGET_LINUX''@!@TARGET_LINUX@!' \ -e "s!@""CONF_COMMAND""@!@CONF_COMMAND@!" \ -e 's!@''MYSQLD_USER''@!@MYSQLD_USER@!' \ -e 's!@''sysconfdir''@!@sysconfdir@!' \ diff --git a/scripts/Makefile.am b/scripts/Makefile.am index b170fa483b2..e2ef1bba97c 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -135,7 +135,7 @@ SUFFIXES = .sh -e 's!@''MYSQLD_DEFAULT_SWITCHES''@!@MYSQLD_DEFAULT_SWITCHES@!' \ -e 's!@''MYSQL_UNIX_ADDR''@!@MYSQL_UNIX_ADDR@!' \ -e 's!@''MYSQL_TCP_PORT''@!@MYSQL_TCP_PORT@!' \ - -e 's!@''IS_LINUX''@!@IS_LINUX@!' \ + -e 's!@''TARGET_LINUX''@!@TARGET_LINUX@!' \ -e "s!@""CONF_COMMAND""@!@CONF_COMMAND@!" \ -e 's!@''MYSQLD_USER''@!@MYSQLD_USER@!' \ -e 's!@''STATIC_NSS_FLAGS''@!@STATIC_NSS_FLAGS@!' \ diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 308db270828..8a232f4f7f9 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -324,7 +324,7 @@ do break fi - if @IS_LINUX@ && test $KILL_MYSQLD -eq 1 + if @TARGET_LINUX@ && test $KILL_MYSQLD -eq 1 then # Test if one process was hanging. # This is only a fix for Linux (running as base 3 mysqld processes) diff --git a/support-files/Makefile.am b/support-files/Makefile.am index 0a6077f0efc..5f5a10fc1fc 100644 --- a/support-files/Makefile.am +++ b/support-files/Makefile.am @@ -90,7 +90,7 @@ SUFFIXES = .sh -e 's!@''FIND_PROC''@!@FIND_PROC@!' \ -e 's!@''MYSQLD_DEFAULT_SWITCHES''@!@MYSQLD_DEFAULT_SWITCHES@!' \ -e 's!@''MYSQL_UNIX_ADDR''@!@MYSQL_UNIX_ADDR@!' \ - -e 's!@''IS_LINUX''@!@IS_LINUX@!' \ + -e 's!@''TARGET_LINUX''@!@TARGET_LINUX@!' \ -e "s!@""CONF_COMMAND""@!@CONF_COMMAND@!" \ -e 's!@''MYSQLD_USER''@!@MYSQLD_USER@!' \ -e 's!@''sysconfdir''@!@sysconfdir@!' \ From b6a4a2f41cb7aa04b59d8017070a69cd6f4c5082 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Apr 2005 20:38:57 +0200 Subject: [PATCH 07/78] Step 2 of the switch to support configuration with NPTL: Define a new CPP symbol that the target OS is Linux, and use it where only the OS matters and not the threads Library. Until now, 'HAVE_LINUXTHREADS' was used to indicate "Target is Linux" in many places. When we support configuration with NPTL but no Linuxthreads, this misuse must cease. configure.in: Step 2 of the switch to support configuration with NPTL: Define a new CPP symbol that the target OS is Linux. Until now, 'HAVE_LINUXTHREADS' was used to indicate "Target is Linux" in many places. When we support configuration with NPTL but no Linuxthreads, this misuse must cease. include/my_global.h: Step 2 of the switch to support configuration with NPTL: Use the new 'TARGET_OS_LINUX' where only the OS matters and not the threads Library. mysys/thr_mutex.c: Step 2 of the switch to support configuration with NPTL: Use the new 'TARGET_OS_LINUX' where only the OS matters and not the threads Library. sql/stacktrace.c: Step 2 of the switch to support configuration with NPTL: Use the new 'TARGET_OS_LINUX' where only the OS matters and not the threads Library. sql/stacktrace.h: Step 2 of the switch to support configuration with NPTL: Use the new 'TARGET_OS_LINUX' where only the OS matters and not the threads Library. tools/mysqlmanager.c: Step 2 of the switch to support configuration with NPTL: Use the new 'TARGET_OS_LINUX' where only the OS matters and not the threads Library. --- configure.in | 1 + include/my_global.h | 8 ++++---- mysys/thr_mutex.c | 2 +- sql/stacktrace.c | 4 ++-- sql/stacktrace.h | 4 ++-- tools/mysqlmanager.c | 2 +- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/configure.in b/configure.in index 6650c0fc64a..f7a266eebec 100644 --- a/configure.in +++ b/configure.in @@ -412,6 +412,7 @@ then MYSQLD_DEFAULT_SWITCHES="--skip-locking" TARGET_LINUX="true" AC_MSG_RESULT("yes"); + AC_DEFINE([TARGET_OS_LINUX], [1], [Whether we build for Linux]) else MYSQLD_DEFAULT_SWITCHES="" TARGET_LINUX="false" diff --git a/include/my_global.h b/include/my_global.h index 23cf0d54824..a027bf9d2bb 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -97,7 +97,7 @@ /* Fix problem with S_ISLNK() on Linux */ -#if defined(HAVE_LINUXTHREADS) +#if defined(TARGET_OS_LINUX) #undef _GNU_SOURCE #define _GNU_SOURCE 1 #endif @@ -214,13 +214,13 @@ C_MODE_START int __cxa_pure_virtual() {\ #endif /* In Linux-alpha we have atomic.h if we are using gcc */ -#if defined(HAVE_LINUXTHREADS) && defined(__GNUC__) && defined(__alpha__) && (__GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 95)) && !defined(HAVE_ATOMIC_ADD) +#if defined(TARGET_OS_LINUX) && defined(__GNUC__) && defined(__alpha__) && (__GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 95)) && !defined(HAVE_ATOMIC_ADD) #define HAVE_ATOMIC_ADD #define HAVE_ATOMIC_SUB #endif /* In Linux-ia64 including atomic.h will give us an error */ -#if (defined(HAVE_LINUXTHREADS) && defined(__GNUC__) && (defined(__ia64__)||defined(__powerpc64__))) || !defined(THREAD) +#if (defined(TARGET_OS_LINUX) && defined(__GNUC__) && (defined(__ia64__)||defined(__powerpc64__))) || !defined(THREAD) #undef HAVE_ATOMIC_ADD #undef HAVE_ATOMIC_SUB #endif @@ -755,7 +755,7 @@ typedef unsigned long uint32; /* Short for unsigned integer >= 32 bits */ error "Neither int or long is of 4 bytes width" #endif -#if !defined(HAVE_ULONG) && !defined(HAVE_LINUXTHREADS) && !defined(__USE_MISC) +#if !defined(HAVE_ULONG) && !defined(TARGET_OS_LINUX) && !defined(__USE_MISC) typedef unsigned long ulong; /* Short for unsigned long */ #endif #ifndef longlong_defined diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c index bbcfaa8bba6..2facb4e18cf 100644 --- a/mysys/thr_mutex.c +++ b/mysys/thr_mutex.c @@ -17,7 +17,7 @@ /* This makes a wrapper for mutex handling to make it easier to debug mutex */ #include -#if defined(HAVE_LINUXTHREADS) && !defined (__USE_UNIX98) +#if defined(TARGET_OS_LINUX) && !defined (__USE_UNIX98) #define __USE_UNIX98 /* To get rw locks under Linux */ #endif #if defined(THREAD) && defined(SAFE_MUTEX) diff --git a/sql/stacktrace.c b/sql/stacktrace.c index 322d647e741..838f547dc02 100644 --- a/sql/stacktrace.c +++ b/sql/stacktrace.c @@ -43,7 +43,7 @@ void safe_print_str(const char* name, const char* val, int max_len) fputc('\n', stderr); } -#ifdef HAVE_LINUXTHREADS +#ifdef TARGET_OS_LINUX #define SIGRETURN_FRAME_COUNT 2 #if defined(__alpha__) && defined(__GNUC__) @@ -201,7 +201,7 @@ end: stack trace is much more helpful in diagnosing the problem, so please do \n\ resolve it\n"); } -#endif /* HAVE_LINUXTHREADS */ +#endif /* TARGET_OS_LINUX */ #endif /* HAVE_STACKTRACE */ /* Produce a core for the thread */ diff --git a/sql/stacktrace.h b/sql/stacktrace.h index 980e1ea07eb..d5d1e05ef0e 100644 --- a/sql/stacktrace.h +++ b/sql/stacktrace.h @@ -18,7 +18,7 @@ extern "C" { #endif -#ifdef HAVE_LINUXTHREADS +#ifdef TARGET_OS_LINUX #if defined(HAVE_STACKTRACE) || (defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) #undef HAVE_STACKTRACE #define HAVE_STACKTRACE @@ -30,7 +30,7 @@ extern char* heap_start; void print_stacktrace(gptr stack_bottom, ulong thread_stack); void safe_print_str(const char* name, const char* val, int max_len); #endif /* (defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */ -#endif /* HAVE_LINUXTHREADS */ +#endif /* TARGET_OS_LINUX */ /* Define empty prototypes for functions that are not implemented */ #ifndef HAVE_STACKTRACE diff --git a/tools/mysqlmanager.c b/tools/mysqlmanager.c index bb0a76d6c49..27caa1e0255 100644 --- a/tools/mysqlmanager.c +++ b/tools/mysqlmanager.c @@ -101,7 +101,7 @@ static CHARSET_INFO *cs= &my_charset_latin1; set by the user */ -#if defined(__i386__) && defined(HAVE_LINUXTHREADS) +#if defined(__i386__) && defined(TARGET_OS_LINUX) #define DO_STACKTRACE 1 #endif From 948d88da935b4fac3ef8081488d40f44cf733be4 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 Apr 2005 12:06:46 +0200 Subject: [PATCH 08/78] Upgrade to libedit-2.9 BitKeeper/deleted/.del-readline.h~ac6080227e4b72fc: Delete: cmd-line-utils/libedit/readline/readline.h --- client/mysql.cc | 2 +- cmd-line-utils/libedit/Makefile.am | 2 +- cmd-line-utils/libedit/chared.c | 55 +- cmd-line-utils/libedit/chared.h | 12 +- cmd-line-utils/libedit/common.c | 96 +- .../libedit/{readline => editline}/readline.h | 83 +- cmd-line-utils/libedit/el.c | 85 +- cmd-line-utils/libedit/el.h | 18 +- cmd-line-utils/libedit/el_term.h | 131 ++ cmd-line-utils/libedit/emacs.c | 109 +- cmd-line-utils/libedit/fgetln.c | 169 +-- cmd-line-utils/libedit/hist.c | 28 +- cmd-line-utils/libedit/hist.h | 8 +- cmd-line-utils/libedit/histedit.h | 37 +- cmd-line-utils/libedit/history.c | 67 +- cmd-line-utils/libedit/key.c | 54 +- cmd-line-utils/libedit/key.h | 37 +- cmd-line-utils/libedit/map.c | 58 +- cmd-line-utils/libedit/map.h | 8 +- cmd-line-utils/libedit/parse.c | 34 +- cmd-line-utils/libedit/parse.h | 8 +- cmd-line-utils/libedit/prompt.c | 23 +- cmd-line-utils/libedit/prompt.h | 8 +- cmd-line-utils/libedit/read.c | 147 +- cmd-line-utils/libedit/read.h | 4 +- cmd-line-utils/libedit/readline.c | 1247 +++++++++++------ cmd-line-utils/libedit/refresh.c | 29 +- cmd-line-utils/libedit/refresh.h | 8 +- cmd-line-utils/libedit/search.c | 84 +- cmd-line-utils/libedit/search.h | 10 +- cmd-line-utils/libedit/sig.c | 17 +- cmd-line-utils/libedit/sig.h | 8 +- cmd-line-utils/libedit/strlcpy.c | 95 +- cmd-line-utils/libedit/sys.h | 34 +- cmd-line-utils/libedit/term.c | 143 +- cmd-line-utils/libedit/tokenizer.c | 98 +- cmd-line-utils/libedit/tty.c | 162 ++- cmd-line-utils/libedit/tty.h | 8 +- cmd-line-utils/libedit/unvis.c | 311 ++++ cmd-line-utils/libedit/vi.c | 149 +- cmd-line-utils/libedit/vis.c | 392 ++++++ cmd-line-utils/libedit/vis.h | 92 ++ 42 files changed, 2857 insertions(+), 1313 deletions(-) rename cmd-line-utils/libedit/{readline => editline}/readline.h (65%) create mode 100644 cmd-line-utils/libedit/el_term.h create mode 100644 cmd-line-utils/libedit/unvis.c create mode 100644 cmd-line-utils/libedit/vis.c create mode 100644 cmd-line-utils/libedit/vis.h diff --git a/client/mysql.cc b/client/mysql.cc index 0c229796c1e..49efe9cbcf2 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1306,7 +1306,7 @@ static void initialize_readline (char *name) setlocale(LC_ALL,""); /* so as libedit use isprint */ #endif rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion; - rl_completion_entry_function= (CPFunction*)&no_completion; + rl_completion_entry_function= (Function*)&no_completion; #else rl_attempted_completion_function= (CPPFunction*)&new_mysql_completion; rl_completion_entry_function= (Function*)&no_completion; diff --git a/cmd-line-utils/libedit/Makefile.am b/cmd-line-utils/libedit/Makefile.am index a3d73a7082a..0a8458e51f7 100644 --- a/cmd-line-utils/libedit/Makefile.am +++ b/cmd-line-utils/libedit/Makefile.am @@ -20,7 +20,7 @@ EXTRA_libedit_a_SOURCES = np/unvis.c np/strlcpy.c np/vis.c np/strlcat.c \ libedit_a_LIBADD = @LIBEDIT_LOBJECTS@ libedit_a_DEPENDENCIES = @LIBEDIT_LOBJECTS@ -pkginclude_HEADERS = readline/readline.h +pkginclude_HEADERS = editline/readline.h noinst_HEADERS = chared.h el.h histedit.h key.h parse.h refresh.h sig.h \ sys.h tokenizer.h config.h hist.h map.h prompt.h read.h \ diff --git a/cmd-line-utils/libedit/chared.c b/cmd-line-utils/libedit/chared.c index 62a407e66a8..21fc8bc2c1d 100644 --- a/cmd-line-utils/libedit/chared.c +++ b/cmd-line-utils/libedit/chared.c @@ -1,4 +1,4 @@ -/* $NetBSD: chared.c,v 1.18 2002/11/20 16:50:08 christos Exp $ */ +/* $NetBSD: chared.c,v 1.22 2004/08/13 12:10:38 mycroft Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)chared.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: chared.c,v 1.18 2002/11/20 16:50:08 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * chared.c: Character editor utilities @@ -62,13 +51,13 @@ cv_undo(EditLine *el) { c_undo_t *vu = &el->el_chared.c_undo; c_redo_t *r = &el->el_chared.c_redo; - int size; + uint size; /* Save entire line for undo */ size = el->el_line.lastchar - el->el_line.buffer; vu->len = size; vu->cursor = el->el_line.cursor - el->el_line.buffer; - memcpy(vu->buf, el->el_line.buffer, (size_t)size); + memcpy(vu->buf, el->el_line.buffer, size); /* save command info for redo */ r->count = el->el_state.doingarg ? el->el_state.argument : 0; @@ -139,6 +128,21 @@ c_delafter(EditLine *el, int num) } +/* c_delafter1(): + * Delete the character after the cursor, do not yank + */ +protected void +c_delafter1(EditLine *el) +{ + char *cp; + + for (cp = el->el_line.cursor; cp <= el->el_line.lastchar; cp++) + *cp = cp[1]; + + el->el_line.lastchar--; +} + + /* c_delbefore(): * Delete num characters before the cursor */ @@ -167,6 +171,21 @@ c_delbefore(EditLine *el, int num) } +/* c_delbefore1(): + * Delete the character before the cursor, do not yank + */ +protected void +c_delbefore1(EditLine *el) +{ + char *cp; + + for (cp = el->el_line.cursor - 1; cp <= el->el_line.lastchar; cp++) + *cp = cp[1]; + + el->el_line.lastchar--; +} + + /* ce__isword(): * Return if p is part of a word according to emacs */ @@ -460,8 +479,8 @@ ch_init(EditLine *el) el->el_state.argument = 1; el->el_state.lastcmd = ED_UNASSIGNED; - el->el_chared.c_macro.nline = NULL; el->el_chared.c_macro.level = -1; + el->el_chared.c_macro.offset = 0; el->el_chared.c_macro.macro = (char **) el_malloc(EL_MAXMACRO * sizeof(char *)); if (el->el_chared.c_macro.macro == NULL) @@ -582,7 +601,7 @@ ch_enlargebufs(el, addlen) return 0; /* Safe to set enlarged buffer size */ - el->el_line.limit = &newbuffer[newsz - EL_LEAVE]; + el->el_line.limit = &el->el_line.buffer[newsz - EL_LEAVE]; return 1; } diff --git a/cmd-line-utils/libedit/chared.h b/cmd-line-utils/libedit/chared.h index d2e6f742413..2dd0a5795c7 100644 --- a/cmd-line-utils/libedit/chared.h +++ b/cmd-line-utils/libedit/chared.h @@ -1,4 +1,4 @@ -/* $NetBSD: chared.h,v 1.11 2002/11/20 16:50:08 christos Exp $ */ +/* $NetBSD: chared.h,v 1.14 2004/08/13 12:10:39 mycroft Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -66,8 +62,8 @@ typedef struct c_macro_t { int level; + int offset; char **macro; - char *nline; } c_macro_t; /* @@ -158,7 +154,9 @@ protected char *c__next_word(char *, char *, int, int (*)(int)); protected char *c__prev_word(char *, char *, int, int (*)(int)); protected void c_insert(EditLine *, int); protected void c_delbefore(EditLine *, int); +protected void c_delbefore1(EditLine *); protected void c_delafter(EditLine *, int); +protected void c_delafter1(EditLine *); protected int c_gets(EditLine *, char *, const char *); protected int c_hpos(EditLine *); diff --git a/cmd-line-utils/libedit/common.c b/cmd-line-utils/libedit/common.c index f290057568a..81bf9bf29ff 100644 --- a/cmd-line-utils/libedit/common.c +++ b/cmd-line-utils/libedit/common.c @@ -1,4 +1,4 @@ -/* $NetBSD: common.c,v 1.14 2002/11/20 16:50:08 christos Exp $ */ +/* $NetBSD: common.c,v 1.16 2003/08/07 16:44:30 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)common.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: common.c,v 1.14 2002/11/20 16:50:08 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * common.c: Common Editor functions @@ -56,7 +45,7 @@ __RCSID("$NetBSD: common.c,v 1.14 2002/11/20 16:50:08 christos Exp $"); */ protected el_action_t /*ARGSUSED*/ -ed_end_of_file(EditLine *el, int c __attribute__((unused))) +ed_end_of_file(EditLine *el, int c __attribute__((__unused__))) { re_goto_bottom(el); @@ -113,7 +102,7 @@ ed_insert(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_delete_prev_word(EditLine *el, int c __attribute__((unused))) +ed_delete_prev_word(EditLine *el, int c __attribute__((__unused__))) { char *cp, *p, *kp; @@ -141,7 +130,7 @@ ed_delete_prev_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_delete_next_char(EditLine *el, int c __attribute__((unused))) +ed_delete_next_char(EditLine *el, int c __attribute__((__unused__))) { #ifdef notdef /* XXX */ #define EL el->el_line @@ -192,7 +181,7 @@ ed_delete_next_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_kill_line(EditLine *el, int c __attribute__((unused))) +ed_kill_line(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; @@ -213,7 +202,7 @@ ed_kill_line(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_move_to_end(EditLine *el, int c __attribute__((unused))) +ed_move_to_end(EditLine *el, int c __attribute__((__unused__))) { el->el_line.cursor = el->el_line.lastchar; @@ -236,7 +225,7 @@ ed_move_to_end(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_move_to_beg(EditLine *el, int c __attribute__((unused))) +ed_move_to_beg(EditLine *el, int c __attribute__((__unused__))) { el->el_line.cursor = el->el_line.buffer; @@ -285,7 +274,7 @@ ed_transpose_chars(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_next_char(EditLine *el, int c __attribute__((unused))) +ed_next_char(EditLine *el, int c __attribute__((__unused__))) { char *lim = el->el_line.lastchar; @@ -314,7 +303,7 @@ ed_next_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_prev_word(EditLine *el, int c __attribute__((unused))) +ed_prev_word(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.buffer) @@ -340,7 +329,7 @@ ed_prev_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_prev_char(EditLine *el, int c __attribute__((unused))) +ed_prev_char(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor > el->el_line.buffer) { @@ -437,8 +426,7 @@ ed_argument_digit(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -ed_unassigned(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_unassigned(EditLine *el, int c __attribute__((__unused__))) { return (CC_ERROR); @@ -455,8 +443,8 @@ ed_unassigned(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_tty_sigint(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_tty_sigint(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -469,8 +457,8 @@ ed_tty_sigint(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_tty_dsusp(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_tty_dsusp(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -483,8 +471,8 @@ ed_tty_dsusp(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_tty_flush_output(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_tty_flush_output(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -497,8 +485,8 @@ ed_tty_flush_output(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_tty_sigquit(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_tty_sigquit(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -511,8 +499,8 @@ ed_tty_sigquit(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_tty_sigtstp(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_tty_sigtstp(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -525,8 +513,8 @@ ed_tty_sigtstp(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_tty_stop_output(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_tty_stop_output(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -539,8 +527,8 @@ ed_tty_stop_output(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_tty_start_output(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_tty_start_output(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -553,7 +541,7 @@ ed_tty_start_output(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_newline(EditLine *el, int c __attribute__((unused))) +ed_newline(EditLine *el, int c __attribute__((__unused__))) { re_goto_bottom(el); @@ -569,7 +557,7 @@ ed_newline(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_delete_prev_char(EditLine *el, int c __attribute__((unused))) +ed_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor <= el->el_line.buffer) @@ -589,7 +577,7 @@ ed_delete_prev_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_clear_screen(EditLine *el, int c __attribute__((unused))) +ed_clear_screen(EditLine *el, int c __attribute__((__unused__))) { term_clear_screen(el); /* clear the whole real screen */ @@ -604,8 +592,8 @@ ed_clear_screen(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_redisplay(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_redisplay(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_REDISPLAY); @@ -618,7 +606,7 @@ ed_redisplay(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_start_over(EditLine *el, int c __attribute__((unused))) +ed_start_over(EditLine *el, int c __attribute__((__unused__))) { ch_reset(el); @@ -632,8 +620,8 @@ ed_start_over(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_sequence_lead_in(EditLine *el __attribute__((unused)), - int c __attribute__((unused))) +ed_sequence_lead_in(EditLine *el __attribute__((__unused__)), + int c __attribute__((__unused__))) { return (CC_NORM); @@ -646,7 +634,7 @@ ed_sequence_lead_in(EditLine *el __attribute__((unused)), */ protected el_action_t /*ARGSUSED*/ -ed_prev_history(EditLine *el, int c __attribute__((unused))) +ed_prev_history(EditLine *el, int c __attribute__((__unused__))) { char beep = 0; int sv_event = el->el_history.eventno; @@ -684,7 +672,7 @@ ed_prev_history(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_next_history(EditLine *el, int c __attribute__((unused))) +ed_next_history(EditLine *el, int c __attribute__((__unused__))) { el_action_t beep = CC_REFRESH, rval; @@ -711,7 +699,7 @@ ed_next_history(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_search_prev_history(EditLine *el, int c __attribute__((unused))) +ed_search_prev_history(EditLine *el, int c __attribute__((__unused__))) { const char *hp; int h; @@ -779,7 +767,7 @@ ed_search_prev_history(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_search_next_history(EditLine *el, int c __attribute__((unused))) +ed_search_next_history(EditLine *el, int c __attribute__((__unused__))) { const char *hp; int h; @@ -833,7 +821,7 @@ ed_search_next_history(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_prev_line(EditLine *el, int c __attribute__((unused))) +ed_prev_line(EditLine *el, int c __attribute__((__unused__))) { char *ptr; int nchars = c_hpos(el); @@ -876,7 +864,7 @@ ed_prev_line(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_next_line(EditLine *el, int c __attribute__((unused))) +ed_next_line(EditLine *el, int c __attribute__((__unused__))) { char *ptr; int nchars = c_hpos(el); @@ -910,7 +898,7 @@ ed_next_line(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -ed_command(EditLine *el, int c __attribute__((unused))) +ed_command(EditLine *el, int c __attribute__((__unused__))) { char tmpbuf[EL_BUFSIZ]; int tmplen; diff --git a/cmd-line-utils/libedit/readline/readline.h b/cmd-line-utils/libedit/editline/readline.h similarity index 65% rename from cmd-line-utils/libedit/readline/readline.h rename to cmd-line-utils/libedit/editline/readline.h index 7485dde4052..902179c208a 100644 --- a/cmd-line-utils/libedit/readline/readline.h +++ b/cmd-line-utils/libedit/editline/readline.h @@ -1,4 +1,4 @@ -/* $NetBSD: readline.h,v 1.1 2001/01/05 21:15:50 jdolecek Exp $ */ +/* $NetBSD: readline.h,v 1.12 2004/09/08 18:15:37 christos Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -36,7 +36,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ #ifndef _READLINE_H_ -#define _READLINE_H_ +#define _READLINE_H_ #include @@ -48,11 +48,45 @@ typedef void VFunction(void); typedef char *CPFunction(const char *, int); typedef char **CPPFunction(const char *, int, int); +typedef void *histdata_t; + typedef struct _hist_entry { const char *line; - const char *data; + histdata_t *data; } HIST_ENTRY; +typedef struct _keymap_entry { + char type; +#define ISFUNC 0 +#define ISKMAP 1 +#define ISMACR 2 + Function *function; +} KEYMAP_ENTRY; + +#define KEYMAP_SIZE 256 + +typedef KEYMAP_ENTRY KEYMAP_ENTRY_ARRAY[KEYMAP_SIZE]; +typedef KEYMAP_ENTRY *Keymap; + +#define control_character_threshold 0x20 +#define control_character_bit 0x40 + +#ifndef CTRL +#include +#ifdef __GLIBC__ +#include +#endif +#ifndef CTRL +#define CTRL(c) ((c) & 037) +#endif +#endif +#ifndef UNCTRL +#define UNCTRL(c) (((c) - 'a' + 'A')|control_character_bit) +#endif + +#define RUBOUT 0x7f +#define ABORT_CHAR CTRL('G') + /* global variables used by readline enabled applications */ #ifdef __cplusplus extern "C" { @@ -68,12 +102,31 @@ extern int max_input_history; extern char *rl_basic_word_break_characters; extern char *rl_completer_word_break_characters; extern char *rl_completer_quote_characters; -extern CPFunction *rl_completion_entry_function; +extern Function *rl_completion_entry_function; extern CPPFunction *rl_attempted_completion_function; extern int rl_completion_type; extern int rl_completion_query_items; extern char *rl_special_prefixes; extern int rl_completion_append_character; +extern int rl_inhibit_completion; +extern Function *rl_pre_input_hook; +extern Function *rl_startup_hook; +extern char *rl_terminal_name; +extern int rl_already_prompted; +extern char *rl_prompt; +/* + * The following is not implemented + */ +extern KEYMAP_ENTRY_ARRAY emacs_standard_keymap, + emacs_meta_keymap, + emacs_ctlx_keymap; +extern int rl_filename_completion_desired; +extern int rl_ignore_completion_duplicates; +extern Function *rl_getc_function; +extern VFunction *rl_redisplay_function; +extern VFunction *rl_completion_display_matches_hook; +extern VFunction *rl_prep_term_function; +extern VFunction *rl_deprep_term_function; /* supported functions */ char *readline(const char *); @@ -99,6 +152,8 @@ int read_history(const char *); int write_history(const char *); int history_expand(char *, char **); char **history_tokenize(const char *); +const char *get_history_event(const char *, int *, int); +char *history_arg_extract(int, int, const char *); char *tilde_expand(char *); char *filename_completion_function(const char *, int); @@ -111,6 +166,26 @@ void rl_display_match_list(char **, int, int); int rl_insert(int, int); void rl_reset_terminal(const char *); int rl_bind_key(int, int (*)(int, int)); +int rl_newline(int, int); +void rl_callback_read_char(void); +void rl_callback_handler_install(const char *, VFunction *); +void rl_callback_handler_remove(void); +void rl_redisplay(void); +int rl_get_previous_history(int, int); +void rl_prep_terminal(int); +void rl_deprep_terminal(void); +int rl_read_init_file(const char *); +int rl_parse_and_bind(const char *); +void rl_stuff_char(int); +int rl_add_defun(const char *, Function *, int); + +/* + * The following are not implemented + */ +Keymap rl_get_keymap(void); +Keymap rl_make_bare_keymap(void); +int rl_generic_bind(int, const char *, const char *, Keymap); +int rl_bind_key_in_map(int, Function *, Keymap); #ifdef __cplusplus } #endif diff --git a/cmd-line-utils/libedit/el.c b/cmd-line-utils/libedit/el.c index 1b445d40f1c..c32a01b2151 100644 --- a/cmd-line-utils/libedit/el.c +++ b/cmd-line-utils/libedit/el.c @@ -1,4 +1,4 @@ -/* $NetBSD: el.c,v 1.30 2002/11/12 00:00:23 thorpej Exp $ */ +/* $NetBSD: el.c,v 1.39 2004/07/08 00:51:36 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94"; -#else -__RCSID("$NetBSD: el.c,v 1.30 2002/11/12 00:00:23 thorpej Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * el.c: EditLine interface functions @@ -72,7 +61,10 @@ el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) el->el_infd = fileno(fin); el->el_outfile = fout; el->el_errfile = ferr; - el->el_prog = strdup(prog); + if ((el->el_prog = el_strdup(prog)) == NULL) { + el_free(el); + return NULL; + } /* * Initialize all the modules. Order is important!!! @@ -80,11 +72,11 @@ el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) el->el_flags = 0; if (term_init(el) == -1) { - free(el->el_prog); + el_free(el->el_prog); el_free(el); return NULL; } - (void) el_key_init(el); + (void) key_init(el); (void) map_init(el); if (tty_init(el) == -1) el->el_flags |= NO_TTY; @@ -112,7 +104,7 @@ el_end(EditLine *el) el_reset(el); term_end(el); - el_key_end(el); + key_end(el); map_end(el); tty_end(el); ch_end(el); @@ -257,6 +249,27 @@ el_set(EditLine *el, int op, ...) el->el_data = va_arg(va, void *); break; + case EL_UNBUFFERED: + rv = va_arg(va, int); + if (rv && !(el->el_flags & UNBUFFERED)) { + el->el_flags |= UNBUFFERED; + read_prepare(el); + } else if (!rv && (el->el_flags & UNBUFFERED)) { + el->el_flags &= ~UNBUFFERED; + read_finish(el); + } + rv = 0; + break; + + case EL_PREP_TERM: + rv = va_arg(va, int); + if (rv) + (void) tty_rawmode(el); + else + (void) tty_cookedmode(el); + rv = 0; + break; + default: rv = -1; break; @@ -297,21 +310,22 @@ el_get(EditLine *el, int op, void *ret) rv = 0; break; -#if 0 /* XXX */ case EL_TERMINAL: - rv = term_get(el, (const char *) &ret); + term_get(el, (const char **)ret); + rv = 0; break; +#if 0 /* XXX */ case EL_BIND: case EL_TELLTC: case EL_SETTC: case EL_ECHOTC: case EL_SETTY: { - char *argv[20]; + const char *argv[20]; int i; - for (i = 1; i < 20; i++) + for (i = 1; i < sizeof(argv) / sizeof(argv[0]); i++) if ((argv[i] = va_arg(va, char *)) == NULL) break; @@ -378,6 +392,11 @@ el_get(EditLine *el, int op, void *ret) rv = 0; break; + case EL_UNBUFFERED: + *((int *) ret) = (!(el->el_flags & UNBUFFERED)); + rv = 0; + break; + default: rv = -1; } @@ -409,12 +428,17 @@ el_source(EditLine *el, const char *fname) fp = NULL; if (fname == NULL) { -#ifdef HAVE_ISSETUGID static const char elpath[] = "/.editrc"; +#ifdef MAXPATHLEN char path[MAXPATHLEN]; +#else + char path[4096]; +#endif +#ifdef HAVE_ISSETUGID if (issetugid()) return (-1); +#endif if ((ptr = getenv("HOME")) == NULL) return (-1); if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path)) @@ -422,14 +446,6 @@ el_source(EditLine *el, const char *fname) if (strlcat(path, elpath, sizeof(path)) >= sizeof(path)) return (-1); fname = path; -#else - /* - * If issetugid() is missing, always return an error, in order - * to keep from inadvertently opening up the user to a security - * hole. - */ - return (-1); -#endif } if (fp == NULL) fp = fopen(fname, "r"); @@ -496,10 +512,13 @@ el_editmode(EditLine *el, int argc, const char **argv) return (-1); how = argv[1]; - if (strcmp(how, "on") == 0) + if (strcmp(how, "on") == 0) { el->el_flags &= ~EDIT_DISABLED; - else if (strcmp(how, "off") == 0) + tty_rawmode(el); + } else if (strcmp(how, "off") == 0) { + tty_cookedmode(el); el->el_flags |= EDIT_DISABLED; + } else { (void) fprintf(el->el_errfile, "edit: Bad value `%s'.\n", how); return (-1); diff --git a/cmd-line-utils/libedit/el.h b/cmd-line-utils/libedit/el.h index 49bd462ad3b..c4b6cff2186 100644 --- a/cmd-line-utils/libedit/el.h +++ b/cmd-line-utils/libedit/el.h @@ -1,4 +1,4 @@ -/* $NetBSD: el.h,v 1.13 2002/11/15 14:32:33 christos Exp $ */ +/* $NetBSD: el.h,v 1.16 2003/10/18 23:48:42 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -55,9 +51,10 @@ #define EL_BUFSIZ 1024 /* Maximum line size */ -#define HANDLE_SIGNALS 1<<0 -#define NO_TTY 1<<1 -#define EDIT_DISABLED 1<<2 +#define HANDLE_SIGNALS 0x01 +#define NO_TTY 0x02 +#define EDIT_DISABLED 0x04 +#define UNBUFFERED 0x08 typedef int bool_t; /* True or not */ @@ -91,6 +88,7 @@ typedef struct el_state_t { /* * Until we come up with something better... */ +#define el_strdup(a) strdup(a) #define el_malloc(a) malloc(a) #define el_realloc(a,b) realloc(a, b) #define el_free(a) free(a) @@ -98,7 +96,7 @@ typedef struct el_state_t { #include "tty.h" #include "prompt.h" #include "key.h" -#include "libedit_term.h" +#include "el_term.h" #include "refresh.h" #include "chared.h" #include "common.h" diff --git a/cmd-line-utils/libedit/el_term.h b/cmd-line-utils/libedit/el_term.h new file mode 100644 index 00000000000..9e5588ee96f --- /dev/null +++ b/cmd-line-utils/libedit/el_term.h @@ -0,0 +1,131 @@ +/* $NetBSD: term.h,v 1.15 2003/09/14 21:48:55 christos Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Christos Zoulas of Cornell University. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. + * + * @(#)term.h 8.1 (Berkeley) 6/4/93 + */ + +/* + * el.term.h: Termcap header + */ +#ifndef _h_el_term +#define _h_el_term + +#include "histedit.h" + +typedef struct { /* Symbolic function key bindings */ + const char *name; /* name of the key */ + int key; /* Index in termcap table */ + key_value_t fun; /* Function bound to it */ + int type; /* Type of function */ +} fkey_t; + +typedef struct { + const char *t_name; /* the terminal name */ + coord_t t_size; /* # lines and cols */ + int t_flags; +#define TERM_CAN_INSERT 0x001 /* Has insert cap */ +#define TERM_CAN_DELETE 0x002 /* Has delete cap */ +#define TERM_CAN_CEOL 0x004 /* Has CEOL cap */ +#define TERM_CAN_TAB 0x008 /* Can use tabs */ +#define TERM_CAN_ME 0x010 /* Can turn all attrs. */ +#define TERM_CAN_UP 0x020 /* Can move up */ +#define TERM_HAS_META 0x040 /* Has a meta key */ +#define TERM_HAS_AUTO_MARGINS 0x080 /* Has auto margins */ +#define TERM_HAS_MAGIC_MARGINS 0x100 /* Has magic margins */ + char *t_buf; /* Termcap buffer */ + int t_loc; /* location used */ + char **t_str; /* termcap strings */ + int *t_val; /* termcap values */ + char *t_cap; /* Termcap buffer */ + fkey_t *t_fkey; /* Array of keys */ +} el_term_t; + +/* + * fKey indexes + */ +#define A_K_DN 0 +#define A_K_UP 1 +#define A_K_LT 2 +#define A_K_RT 3 +#define A_K_HO 4 +#define A_K_EN 5 +#define A_K_NKEYS 6 + +#ifdef _SUNOS +extern int tgetent(char *, const char *); +extern int tgetflag(char *); +extern int tgetnum(char *); +extern int tputs(const char *, int, int (*)(int)); +extern char* tgoto(const char*, int, int); +extern char* tgetstr(char*, char**); +#endif + +protected void term_move_to_line(EditLine *, int); +protected void term_move_to_char(EditLine *, int); +protected void term_clear_EOL(EditLine *, int); +protected void term_overwrite(EditLine *, const char *, int); +protected void term_insertwrite(EditLine *, char *, int); +protected void term_deletechars(EditLine *, int); +protected void term_clear_screen(EditLine *); +protected void term_beep(EditLine *); +protected int term_change_size(EditLine *, int, int); +protected int term_get_size(EditLine *, int *, int *); +protected int term_init(EditLine *); +protected void term_bind_arrow(EditLine *); +protected void term_print_arrow(EditLine *, const char *); +protected int term_clear_arrow(EditLine *, const char *); +protected int term_set_arrow(EditLine *, const char *, key_value_t *, int); +protected void term_end(EditLine *); +protected void term_get(EditLine *, const char **); +protected int term_set(EditLine *, const char *); +protected int term_settc(EditLine *, int, const char **); +protected int term_telltc(EditLine *, int, const char **); +protected int term_echotc(EditLine *, int, const char **); +protected int term__putc(int); +protected void term__flush(void); + +/* + * Easy access macros + */ +#define EL_FLAGS (el)->el_term.t_flags + +#define EL_CAN_INSERT (EL_FLAGS & TERM_CAN_INSERT) +#define EL_CAN_DELETE (EL_FLAGS & TERM_CAN_DELETE) +#define EL_CAN_CEOL (EL_FLAGS & TERM_CAN_CEOL) +#define EL_CAN_TAB (EL_FLAGS & TERM_CAN_TAB) +#define EL_CAN_ME (EL_FLAGS & TERM_CAN_ME) +#define EL_HAS_META (EL_FLAGS & TERM_HAS_META) +#define EL_HAS_AUTO_MARGINS (EL_FLAGS & TERM_HAS_AUTO_MARGINS) +#define EL_HAS_MAGIC_MARGINS (EL_FLAGS & TERM_HAS_MAGIC_MARGINS) + +#endif /* _h_el_term */ diff --git a/cmd-line-utils/libedit/emacs.c b/cmd-line-utils/libedit/emacs.c index d58d1620693..79f2bf0c818 100644 --- a/cmd-line-utils/libedit/emacs.c +++ b/cmd-line-utils/libedit/emacs.c @@ -1,4 +1,4 @@ -/* $NetBSD: emacs.c,v 1.12 2002/11/15 14:32:33 christos Exp $ */ +/* $NetBSD: emacs.c,v 1.19 2004/10/28 21:14:52 dsl Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)emacs.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: emacs.c,v 1.12 2002/11/15 14:32:33 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * emacs.c: Emacs functions @@ -56,7 +45,7 @@ __RCSID("$NetBSD: emacs.c,v 1.12 2002/11/15 14:32:33 christos Exp $"); */ protected el_action_t /*ARGSUSED*/ -em_delete_or_list(EditLine *el, int c __attribute__((unused))) +em_delete_or_list(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.lastchar) { @@ -75,7 +64,10 @@ em_delete_or_list(EditLine *el, int c __attribute__((unused))) return (CC_ERROR); } } else { - c_delafter(el, el->el_state.argument); /* delete after dot */ + if (el->el_state.doingarg) + c_delafter(el, el->el_state.argument); + else + c_delafter1(el); if (el->el_line.cursor > el->el_line.lastchar) el->el_line.cursor = el->el_line.lastchar; /* bounds check */ @@ -90,7 +82,7 @@ em_delete_or_list(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_delete_next_word(EditLine *el, int c __attribute__((unused))) +em_delete_next_word(EditLine *el, int c __attribute__((__unused__))) { char *cp, *p, *kp; @@ -119,14 +111,12 @@ em_delete_next_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_yank(EditLine *el, int c __attribute__((unused))) +em_yank(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; - if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf) { - if (!ch_enlargebufs(el, 1)) - return (CC_ERROR); - } + if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf) + return (CC_NORM); if (el->el_line.lastchar + (el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >= @@ -156,7 +146,7 @@ em_yank(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_kill_line(EditLine *el, int c __attribute__((unused))) +em_kill_line(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; @@ -178,7 +168,7 @@ em_kill_line(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_kill_region(EditLine *el, int c __attribute__((unused))) +em_kill_region(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; @@ -211,7 +201,7 @@ em_kill_region(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_copy_region(EditLine *el, int c __attribute__((unused))) +em_copy_region(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; @@ -235,12 +225,12 @@ em_copy_region(EditLine *el, int c __attribute__((unused))) } -/* em_gosmacs_traspose(): +/* em_gosmacs_transpose(): * Exchange the two characters before the cursor * Gosling emacs transpose chars [^T] */ protected el_action_t -em_gosmacs_traspose(EditLine *el, int c) +em_gosmacs_transpose(EditLine *el, int c) { if (el->el_line.cursor > &el->el_line.buffer[1]) { @@ -260,7 +250,7 @@ em_gosmacs_traspose(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -em_next_word(EditLine *el, int c __attribute__((unused))) +em_next_word(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.lastchar) return (CC_ERROR); @@ -285,7 +275,7 @@ em_next_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_upper_case(EditLine *el, int c __attribute__((unused))) +em_upper_case(EditLine *el, int c __attribute__((__unused__))) { char *cp, *ep; @@ -293,8 +283,8 @@ em_upper_case(EditLine *el, int c __attribute__((unused))) el->el_state.argument, ce__isword); for (cp = el->el_line.cursor; cp < ep; cp++) - if (islower((unsigned char) *cp)) - *cp = toupper(*cp); + if (islower((unsigned char)*cp)) + *cp = toupper((unsigned char)*cp); el->el_line.cursor = ep; if (el->el_line.cursor > el->el_line.lastchar) @@ -309,7 +299,7 @@ em_upper_case(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_capitol_case(EditLine *el, int c __attribute__((unused))) +em_capitol_case(EditLine *el, int c __attribute__((__unused__))) { char *cp, *ep; @@ -317,16 +307,16 @@ em_capitol_case(EditLine *el, int c __attribute__((unused))) el->el_state.argument, ce__isword); for (cp = el->el_line.cursor; cp < ep; cp++) { - if (isalpha((unsigned char) *cp)) { - if (islower((unsigned char) *cp)) - *cp = toupper(*cp); + if (isalpha((unsigned char)*cp)) { + if (islower((unsigned char)*cp)) + *cp = toupper((unsigned char)*cp); cp++; break; } } for (; cp < ep; cp++) - if (isupper((unsigned char) *cp)) - *cp = tolower(*cp); + if (isupper((unsigned char)*cp)) + *cp = tolower((unsigned char)*cp); el->el_line.cursor = ep; if (el->el_line.cursor > el->el_line.lastchar) @@ -341,7 +331,7 @@ em_capitol_case(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_lower_case(EditLine *el, int c __attribute__((unused))) +em_lower_case(EditLine *el, int c __attribute__((__unused__))) { char *cp, *ep; @@ -349,8 +339,8 @@ em_lower_case(EditLine *el, int c __attribute__((unused))) el->el_state.argument, ce__isword); for (cp = el->el_line.cursor; cp < ep; cp++) - if (isupper((unsigned char) *cp)) - *cp = tolower(*cp); + if (isupper((unsigned char)*cp)) + *cp = tolower((unsigned char)*cp); el->el_line.cursor = ep; if (el->el_line.cursor > el->el_line.lastchar) @@ -365,7 +355,7 @@ em_lower_case(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_set_mark(EditLine *el, int c __attribute__((unused))) +em_set_mark(EditLine *el, int c __attribute__((__unused__))) { el->el_chared.c_kill.mark = el->el_line.cursor; @@ -379,7 +369,7 @@ em_set_mark(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_exchange_mark(EditLine *el, int c __attribute__((unused))) +em_exchange_mark(EditLine *el, int c __attribute__((__unused__))) { char *cp; @@ -396,7 +386,7 @@ em_exchange_mark(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_universal_argument(EditLine *el, int c __attribute__((unused))) +em_universal_argument(EditLine *el, int c __attribute__((__unused__))) { /* multiply current argument by 4 */ if (el->el_state.argument > 1000000) @@ -413,7 +403,7 @@ em_universal_argument(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_meta_next(EditLine *el, int c __attribute__((unused))) +em_meta_next(EditLine *el, int c __attribute__((__unused__))) { el->el_state.metanext = 1; @@ -426,7 +416,7 @@ em_meta_next(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_toggle_overwrite(EditLine *el, int c __attribute__((unused))) +em_toggle_overwrite(EditLine *el, int c __attribute__((__unused__))) { el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ? @@ -440,7 +430,7 @@ em_toggle_overwrite(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_copy_prev_word(EditLine *el, int c __attribute__((unused))) +em_copy_prev_word(EditLine *el, int c __attribute__((__unused__))) { char *cp, *oldc, *dp; @@ -467,7 +457,7 @@ em_copy_prev_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_inc_search_next(EditLine *el, int c __attribute__((unused))) +em_inc_search_next(EditLine *el, int c __attribute__((__unused__))) { el->el_search.patlen = 0; @@ -480,9 +470,32 @@ em_inc_search_next(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -em_inc_search_prev(EditLine *el, int c __attribute__((unused))) +em_inc_search_prev(EditLine *el, int c __attribute__((__unused__))) { el->el_search.patlen = 0; return (ce_inc_search(el, ED_SEARCH_PREV_HISTORY)); } + + +/* em_delete_prev_char(): + * Delete the character to the left of the cursor + * [^?] + */ +protected el_action_t +/*ARGSUSED*/ +em_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) +{ + + if (el->el_line.cursor <= el->el_line.buffer) + return (CC_ERROR); + + if (el->el_state.doingarg) + c_delbefore(el, el->el_state.argument); + else + c_delbefore1(el); + el->el_line.cursor -= el->el_state.argument; + if (el->el_line.cursor < el->el_line.buffer) + el->el_line.cursor = el->el_line.buffer; + return (CC_REFRESH); +} diff --git a/cmd-line-utils/libedit/fgetln.c b/cmd-line-utils/libedit/fgetln.c index 4f7416a4c8d..5b95b2f6584 100644 --- a/cmd-line-utils/libedit/fgetln.c +++ b/cmd-line-utils/libedit/fgetln.c @@ -1,109 +1,88 @@ +/* $NetBSD: fgetln.c,v 1.2 2003/12/10 01:30:27 lukem Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 THE FOUNDATION OR CONTRIBUTORS + * 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 #include -#include "compat.h" +#include +#include +#include +#include -#ifndef HAVE_FGETLN -#ifdef HAVE_GETLINE - -extern int getline (char **lineptr, size_t *n, FILE *stream); - -#else - -/* The interface here is that of GNU libc's getline */ -static int -getline (char **lineptr, size_t *n, FILE *stream) +char * +fgetln(FILE *fp, size_t *len) { -#define EXPAND_CHUNK 16 + static char *buf = NULL; + static size_t bufsiz = 0; + char *ptr; - int n_read = 0; - char *line = *lineptr; - if (lineptr == NULL) return -1; - if (n == NULL) return -1; - if (stream == NULL) return -1; - if (*lineptr == NULL || *n == 0) return -1; - -#ifdef HAVE_FLOCKFILE - flockfile (stream); -#endif - - while (1) - { - int c; - -#ifdef HAVE_FLOCKFILE - c = getc_unlocked (stream); -#else - c = getc (stream); -#endif + if (buf == NULL) { + bufsiz = BUFSIZ; + if ((buf = malloc(bufsiz)) == NULL) + return NULL; + } - if (c == EOF) - { - if (n_read > 0) - line[n_read] = '\0'; - break; - } + if (fgets(buf, bufsiz, fp) == NULL) + return NULL; + *len = 0; - if (n_read + 2 >= *n) - { - size_t new_size; + while ((ptr = strchr(&buf[*len], '\n')) == NULL) { + size_t nbufsiz = bufsiz + BUFSIZ; + char *nbuf = realloc(buf, nbufsiz); - if (*n == 0) - new_size = 16; - else - new_size = *n * 2; + if (nbuf == NULL) { + int oerrno = errno; + free(buf); + errno = oerrno; + buf = NULL; + return NULL; + } else + buf = nbuf; - if (*n >= new_size) /* Overflowed size_t */ - line = NULL; - else - line = (char *) (*lineptr ? (char*) realloc(*lineptr, new_size) : - (char*) malloc(new_size)); + *len = bufsiz; + if (fgets(&buf[bufsiz], BUFSIZ, fp) == NULL) + return buf; - if (line) - { - *lineptr = line; - *n = new_size; - } - else - { - if (*n > 0) - { - (*lineptr)[*n - 1] = '\0'; - n_read = *n - 2; - } - break; - } - } + bufsiz = nbufsiz; + } - line[n_read] = c; - n_read++; - - if (c == '\n') - { - line[n_read] = '\0'; - break; - } - } - -#ifdef HAVE_FLOCKFILE - funlockfile (stream); -#endif - - return n_read - 1; + *len = (ptr - buf) + 1; + return buf; } -#endif /* ! HAVE_GETLINE */ -char *fgetln(FILE *stream, size_t *len) -{ - char *ptr = NULL; - int sz; - size_t length= 0; - - sz = getline(&ptr, &length, stream); - if(len) { - *len = sz; - } - - return sz >= 0 ? ptr : NULL; -} -#endif diff --git a/cmd-line-utils/libedit/hist.c b/cmd-line-utils/libedit/hist.c index 59c2f39dd34..e8f5c0f39ba 100644 --- a/cmd-line-utils/libedit/hist.c +++ b/cmd-line-utils/libedit/hist.c @@ -1,4 +1,4 @@ -/* $NetBSD: hist.c,v 1.12 2003/01/21 18:40:23 christos Exp $ */ +/* $NetBSD: hist.c,v 1.15 2003/11/01 23:36:39 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)hist.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: hist.c,v 1.12 2003/01/21 18:40:23 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * hist.c: History access functions @@ -157,7 +146,6 @@ hist_get(EditLine *el) * process a history command */ protected int -/*ARGSUSED*/ hist_command(EditLine *el, int argc, const char **argv) { const char *str; @@ -167,7 +155,7 @@ hist_command(EditLine *el, int argc, const char **argv) if (el->el_history.ref == NULL) return (-1); - if (argc == 0 || strcmp(argv[0], "list") == 1) { + if (argc == 1 || strcmp(argv[1], "list") == 0) { /* List history entries */ for (str = HIST_LAST(el); str != NULL; str = HIST_PREV(el)) @@ -176,15 +164,15 @@ hist_command(EditLine *el, int argc, const char **argv) return (0); } - if (argc != 2) + if (argc != 3) return (-1); - num = (int)strtol(argv[1], NULL, 0); + num = (int)strtol(argv[2], NULL, 0); - if (strcmp(argv[0], "size") == 0) + if (strcmp(argv[1], "size") == 0) return history(el->el_history.ref, &ev, H_SETSIZE, num); - if (strcmp(argv[0], "unique") == 0) + if (strcmp(argv[1], "unique") == 0) return history(el->el_history.ref, &ev, H_SETUNIQUE, num); return -1; diff --git a/cmd-line-utils/libedit/hist.h b/cmd-line-utils/libedit/hist.h index b713281b382..46e14634adf 100644 --- a/cmd-line-utils/libedit/hist.h +++ b/cmd-line-utils/libedit/hist.h @@ -1,4 +1,4 @@ -/* $NetBSD: hist.h,v 1.9 2003/01/21 18:40:23 christos Exp $ */ +/* $NetBSD: hist.h,v 1.10 2003/08/07 16:44:31 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/cmd-line-utils/libedit/histedit.h b/cmd-line-utils/libedit/histedit.h index 3137bd680a7..c58eb62dcfa 100644 --- a/cmd-line-utils/libedit/histedit.h +++ b/cmd-line-utils/libedit/histedit.h @@ -1,4 +1,4 @@ -/* $NetBSD: histedit.h,v 1.21 2003/01/21 18:40:24 christos Exp $ */ +/* $NetBSD: histedit.h,v 1.25 2003/12/05 13:37:48 lukem Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -45,7 +41,7 @@ #define _HISTEDIT_H_ #define LIBEDIT_MAJOR 2 -#define LIBEDIT_MINOR 6 +#define LIBEDIT_MINOR 9 #include #include @@ -53,6 +49,7 @@ /* * ==== Editing ==== */ + typedef struct editline EditLine; /* @@ -64,7 +61,6 @@ typedef struct lineinfo { const char *lastchar; } LineInfo; - /* * EditLine editor function return codes. * For user-defined function interface @@ -84,9 +80,8 @@ typedef struct lineinfo { * Initialization, cleanup, and resetting */ EditLine *el_init(const char *, FILE *, FILE *, FILE *); -void el_reset(EditLine *); void el_end(EditLine *); - +void el_reset(EditLine *); /* * Get a line, a character or push a string back in the input queue @@ -131,6 +126,8 @@ int el_get(EditLine *, int, void *); #define EL_RPROMPT 12 /* , el_pfunc_t); */ #define EL_GETCFN 13 /* , el_rfunc_t); */ #define EL_CLIENTDATA 14 /* , void *); */ +#define EL_UNBUFFERED 15 /* , int); */ +#define EL_PREP_TERM 16 /* , int); */ #define EL_BUILTIN_GETCFN (NULL) @@ -146,7 +143,6 @@ int el_source(EditLine *, const char *); */ void el_resize(EditLine *); - /* * User-defined function interface. */ @@ -154,6 +150,7 @@ const LineInfo *el_line(EditLine *); int el_insertstr(EditLine *, const char *); void el_deletestr(EditLine *, int); + /* * ==== History ==== */ @@ -196,4 +193,22 @@ int history(History *, HistEvent *, int, ...); #define H_SETUNIQUE 20 /* , int); */ #define H_GETUNIQUE 21 /* , void); */ + +/* + * ==== Tokenization ==== + */ + +typedef struct tokenizer Tokenizer; + +/* + * String tokenization functions, using simplified sh(1) quoting rules + */ +Tokenizer *tok_init(const char *); +void tok_end(Tokenizer *); +void tok_reset(Tokenizer *); +int tok_line(Tokenizer *, const LineInfo *, + int *, const char ***, int *, int *); +int tok_str(Tokenizer *, const char *, + int *, const char ***); + #endif /* _HISTEDIT_H_ */ diff --git a/cmd-line-utils/libedit/history.c b/cmd-line-utils/libedit/history.c index 53648203bf0..1da6a864181 100644 --- a/cmd-line-utils/libedit/history.c +++ b/cmd-line-utils/libedit/history.c @@ -1,4 +1,4 @@ -/* $NetBSD: history.c,v 1.22 2003/01/21 18:40:24 christos Exp $ */ +/* $NetBSD: history.c,v 1.28 2004/11/27 18:31:45 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)history.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: history.c,v 1.22 2003/01/21 18:40:24 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * hist.c: History access functions @@ -51,11 +40,7 @@ __RCSID("$NetBSD: history.c,v 1.22 2003/01/21 18:40:24 christos Exp $"); #include #include #include -#ifdef HAVE_VIS_H #include -#else -#include "np/vis.h" -#endif #include static const char hist_cookie[] = "_HiStOrY_V2_\n"; @@ -91,6 +76,7 @@ struct history { #define HENTER(h, ev, str) (*(h)->h_enter)((h)->h_ref, ev, str) #define HADD(h, ev, str) (*(h)->h_add)((h)->h_ref, ev, str) +#define h_strdup(a) strdup(a) #define h_malloc(a) malloc(a) #define h_realloc(a, b) realloc((a), (b)) #define h_free(a) free(a) @@ -249,20 +235,19 @@ history_def_next(ptr_t p, HistEvent *ev) { history_t *h = (history_t *) p; - if (h->cursor != &h->list) - h->cursor = h->cursor->next; - else { + if (h->cursor == &h->list) { he_seterrev(ev, _HE_EMPTY_LIST); return (-1); } - if (h->cursor != &h->list) - *ev = h->cursor->ev; - else { + if (h->cursor->next == &h->list) { he_seterrev(ev, _HE_END_REACHED); return (-1); } + h->cursor = h->cursor->next; + *ev = h->cursor->ev; + return (0); } @@ -275,21 +260,20 @@ history_def_prev(ptr_t p, HistEvent *ev) { history_t *h = (history_t *) p; - if (h->cursor != &h->list) - h->cursor = h->cursor->prev; - else { + if (h->cursor == &h->list) { he_seterrev(ev, (h->cur > 0) ? _HE_END_REACHED : _HE_EMPTY_LIST); return (-1); } - if (h->cursor != &h->list) - *ev = h->cursor->ev; - else { + if (h->cursor->prev == &h->list) { he_seterrev(ev, _HE_START_REACHED); return (-1); } + h->cursor = h->cursor->prev; + *ev = h->cursor->ev; + return (0); } @@ -374,7 +358,8 @@ history_def_add(ptr_t p, HistEvent *ev, const char *str) */ /* ARGSUSED */ private void -history_def_delete(history_t *h, HistEvent *ev __attribute__((unused)), hentry_t *hp) +history_def_delete(history_t *h, + HistEvent *ev __attribute__((__unused__)), hentry_t *hp) { HistEventPrivate *evp = (void *)&hp->ev; if (hp == &h->list) @@ -397,7 +382,7 @@ history_def_insert(history_t *h, HistEvent *ev, const char *str) h->cursor = (hentry_t *) h_malloc(sizeof(hentry_t)); if (h->cursor == NULL) goto oomem; - if ((h->cursor->ev.str = strdup(str)) == NULL) { + if ((h->cursor->ev.str = h_strdup(str)) == NULL) { h_free((ptr_t)h->cursor); goto oomem; } @@ -447,7 +432,7 @@ history_def_enter(ptr_t p, HistEvent *ev, const char *str) */ /* ARGSUSED */ private int -history_def_init(ptr_t *p, HistEvent *ev __attribute__((unused)), int n) +history_def_init(ptr_t *p, HistEvent *ev __attribute__((__unused__)), int n) { history_t *h = (history_t *) h_malloc(sizeof(history_t)); if (h == NULL) @@ -661,6 +646,12 @@ history_load(History *h, const char *fname) if ((fp = fopen(fname, "r")) == NULL) return (i); + if ((line = fgetln(fp, &sz)) == NULL) + goto done; + + if (strncmp(line, hist_cookie, sz) != 0) + goto done; + ptr = h_malloc(max_size = 1024); if (ptr == NULL) goto done; @@ -674,7 +665,7 @@ history_load(History *h, const char *fname) if (max_size < sz) { char *nptr; - max_size = (sz + 1023) & ~1023; + max_size = (sz + 1024) & ~1023; nptr = h_realloc(ptr, max_size); if (nptr == NULL) { i = -1; @@ -714,16 +705,18 @@ history_save(History *h, const char *fname) if (fchmod(fileno(fp), S_IRUSR|S_IWUSR) == -1) goto done; + if (fputs(hist_cookie, fp) == EOF) + goto done; ptr = h_malloc(max_size = 1024); if (ptr == NULL) goto done; for (i = 0, retval = HLAST(h, &ev); retval != -1; retval = HPREV(h, &ev), i++) { - len = strlen(ev.str) * 4 + 1; + len = strlen(ev.str) * 4; if (len >= max_size) { char *nptr; - max_size = (len + 1023) & ~1023; + max_size = (len + 1024) & ~1023; nptr = h_realloc(ptr, max_size); if (nptr == NULL) { i = -1; @@ -732,7 +725,7 @@ history_save(History *h, const char *fname) ptr = nptr; } (void) strvis(ptr, ev.str, VIS_WHITE); - (void) fprintf(fp, "%s\n", ev.str); + (void) fprintf(fp, "%s\n", ptr); } oomem: h_free((ptr_t)ptr); diff --git a/cmd-line-utils/libedit/key.c b/cmd-line-utils/libedit/key.c index e75db00ce1b..090a2684e92 100644 --- a/cmd-line-utils/libedit/key.c +++ b/cmd-line-utils/libedit/key.c @@ -1,4 +1,4 @@ -/* $NetBSD: key.c,v 1.13 2002/03/18 16:00:55 christos Exp $ */ +/* $NetBSD: key.c,v 1.15 2003/10/18 23:48:42 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)key.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: key.c,v 1.13 2002/03/18 16:00:55 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * key.c: This module contains the procedures for maintaining @@ -103,14 +92,14 @@ private int key__decode_char(char *, int, int); * Initialize the key maps */ protected int -el_key_init(EditLine *el) +key_init(EditLine *el) { el->el_key.buf = (char *) el_malloc(KEY_BUFSIZ); if (el->el_key.buf == NULL) return (-1); el->el_key.map = NULL; - el_key_reset(el); + key_reset(el); return (0); } @@ -119,7 +108,7 @@ el_key_init(EditLine *el) * Free the key maps */ protected void -el_key_end(EditLine *el) +key_end(EditLine *el) { el_free((ptr_t) el->el_key.buf); @@ -133,7 +122,7 @@ el_key_end(EditLine *el) * Associate cmd with a key value */ protected key_value_t * -el_key_map_cmd(EditLine *el, int cmd) +key_map_cmd(EditLine *el, int cmd) { el->el_key.val.cmd = (el_action_t) cmd; @@ -145,7 +134,7 @@ el_key_map_cmd(EditLine *el, int cmd) * Associate str with a key value */ protected key_value_t * -el_key_map_str(EditLine *el, char *str) +key_map_str(EditLine *el, char *str) { el->el_key.val.str = str; @@ -159,7 +148,7 @@ el_key_map_str(EditLine *el, char *str) * [Always bind the ansi arrow keys?] */ protected void -el_key_reset(EditLine *el) +key_reset(EditLine *el) { node__put(el, el->el_key.map); @@ -177,7 +166,7 @@ el_key_reset(EditLine *el) * The last character read is returned in *ch. */ protected int -el_key_get(EditLine *el, char *ch, key_value_t *val) +key_get(EditLine *el, char *ch, key_value_t *val) { return (node_trav(el, el->el_key.map, ch, val)); @@ -191,7 +180,7 @@ el_key_get(EditLine *el, char *ch, key_value_t *val) * out str or a unix command. */ protected void -el_key_add(EditLine *el, const char *key, key_value_t *val, int ntype) +key_add(EditLine *el, const char *key, key_value_t *val, int ntype) { if (key[0] == '\0') { @@ -219,7 +208,7 @@ el_key_add(EditLine *el, const char *key, key_value_t *val, int ntype) * */ protected void -el_key_clear(EditLine *el, el_action_t *map, const char *in) +key_clear(EditLine *el, el_action_t *map, const char *in) { if ((map[(unsigned char)*in] == ED_SEQUENCE_LEAD_IN) && @@ -227,7 +216,7 @@ el_key_clear(EditLine *el, el_action_t *map, const char *in) el->el_map.alt[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN) || (map == el->el_map.alt && el->el_map.key[(unsigned char)*in] != ED_SEQUENCE_LEAD_IN))) - (void) el_key_delete(el, in); + (void) key_delete(el, in); } @@ -236,7 +225,7 @@ el_key_clear(EditLine *el, el_action_t *map, const char *in) * they exists. */ protected int -el_key_delete(EditLine *el, const char *key) +key_delete(EditLine *el, const char *key) { if (key[0] == '\0') { @@ -257,7 +246,7 @@ el_key_delete(EditLine *el, const char *key) * Print entire el->el_key.map if null */ protected void -el_key_print(EditLine *el, const char *key) +key_print(EditLine *el, const char *key) { /* do nothing if el->el_key.map is empty and null key specified */ @@ -356,7 +345,8 @@ node__try(EditLine *el, key_node_t *ptr, const char *str, key_value_t *val, int break; case XK_STR: case XK_EXE: - ptr->val.str = strdup(val->str); + if ((ptr->val.str = el_strdup(val->str)) == NULL) + return -1; break; default: EL_ABORT((el->el_errfile, "Bad XK_ type %d\n", ntype)); @@ -504,7 +494,7 @@ node_lookup(EditLine *el, const char *str, key_node_t *ptr, int cnt) if (str[1] == 0) { el->el_key.buf[ncnt + 1] = '"'; el->el_key.buf[ncnt + 2] = '\0'; - el_key_kprint(el, el->el_key.buf, + key_kprint(el, el->el_key.buf, &ptr->val, ptr->type); return (0); } else @@ -552,7 +542,7 @@ node_enum(EditLine *el, key_node_t *ptr, int cnt) /* print this key and function */ el->el_key.buf[ncnt + 1] = '"'; el->el_key.buf[ncnt + 2] = '\0'; - el_key_kprint(el, el->el_key.buf, &ptr->val, ptr->type); + key_kprint(el, el->el_key.buf, &ptr->val, ptr->type); } else (void) node_enum(el, ptr->next, ncnt + 1); @@ -568,7 +558,7 @@ node_enum(EditLine *el, key_node_t *ptr, int cnt) * function specified by val */ protected void -el_key_kprint(EditLine *el, const char *key, key_value_t *val, int ntype) +key_kprint(EditLine *el, const char *key, key_value_t *val, int ntype) { el_bindings_t *fp; char unparsbuf[EL_BUFSIZ]; @@ -579,7 +569,7 @@ el_key_kprint(EditLine *el, const char *key, key_value_t *val, int ntype) case XK_STR: case XK_EXE: (void) fprintf(el->el_outfile, fmt, key, - el_key__decode_str(val->str, unparsbuf, + key__decode_str(val->str, unparsbuf, ntype == XK_STR ? "\"\"" : "[]")); break; case XK_CMD: @@ -644,7 +634,7 @@ key__decode_char(char *buf, int cnt, int ch) * Make a printable version of the ey */ protected char * -el_key__decode_str(const char *str, char *buf, const char *sep) +key__decode_str(const char *str, char *buf, const char *sep) { char *b; const char *p; diff --git a/cmd-line-utils/libedit/key.h b/cmd-line-utils/libedit/key.h index 9d83d7c2521..39a075c504e 100644 --- a/cmd-line-utils/libedit/key.h +++ b/cmd-line-utils/libedit/key.h @@ -1,4 +1,4 @@ -/* $NetBSD: key.h,v 1.6 2002/03/18 16:00:55 christos Exp $ */ +/* $NetBSD: key.h,v 1.8 2003/08/07 16:44:32 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -62,19 +58,22 @@ typedef struct el_key_t { #define XK_NOD 2 #define XK_EXE 3 -protected int el_key_init(EditLine *); -protected void el_key_end(EditLine *); -protected key_value_t *el_key_map_cmd(EditLine *, int); -protected key_value_t *el_key_map_str(EditLine *, char *); -protected void el_key_reset(EditLine *); -protected int el_key_get(EditLine *, char *, key_value_t *); -protected void el_key_add(EditLine *, - const char *, key_value_t *, int); -protected void el_key_clear(EditLine *, el_action_t *, const char *); -protected int el_key_delete(EditLine *, const char *); -protected void el_key_print(EditLine *, const char *); -protected void el_key_kprint(EditLine *, const char *, key_value_t *, +#undef key_end +#undef key_clear +#undef key_print + +protected int key_init(EditLine *); +protected void key_end(EditLine *); +protected key_value_t *key_map_cmd(EditLine *, int); +protected key_value_t *key_map_str(EditLine *, char *); +protected void key_reset(EditLine *); +protected int key_get(EditLine *, char *, key_value_t *); +protected void key_add(EditLine *, const char *, key_value_t *, int); +protected void key_clear(EditLine *, el_action_t *, const char *); +protected int key_delete(EditLine *, const char *); +protected void key_print(EditLine *, const char *); +protected void key_kprint(EditLine *, const char *, key_value_t *, int); -protected char *el_key__decode_str(const char *, char *, const char *); +protected char *key__decode_str(const char *, char *, const char *); #endif /* _h_el_key */ diff --git a/cmd-line-utils/libedit/map.c b/cmd-line-utils/libedit/map.c index a16625311ae..d99c36ff665 100644 --- a/cmd-line-utils/libedit/map.c +++ b/cmd-line-utils/libedit/map.c @@ -1,4 +1,4 @@ -/* $NetBSD: map.c,v 1.18 2002/11/15 14:32:33 christos Exp $ */ +/* $NetBSD: map.c,v 1.20 2004/08/13 12:10:39 mycroft Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)map.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: map.c,v 1.18 2002/11/15 14:32:33 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * map.c: Editor function definitions @@ -71,7 +60,7 @@ private const el_action_t el_map_emacs[] = { /* 5 */ ED_MOVE_TO_END, /* ^E */ /* 6 */ ED_NEXT_CHAR, /* ^F */ /* 7 */ ED_UNASSIGNED, /* ^G */ - /* 8 */ ED_DELETE_PREV_CHAR, /* ^H */ + /* 8 */ EM_DELETE_PREV_CHAR, /* ^H */ /* 9 */ ED_UNASSIGNED, /* ^I */ /* 10 */ ED_NEWLINE, /* ^J */ /* 11 */ ED_KILL_LINE, /* ^K */ @@ -190,7 +179,7 @@ private const el_action_t el_map_emacs[] = { /* 124 */ ED_INSERT, /* | */ /* 125 */ ED_INSERT, /* } */ /* 126 */ ED_INSERT, /* ~ */ - /* 127 */ ED_DELETE_PREV_CHAR, /* ^? */ + /* 127 */ EM_DELETE_PREV_CHAR, /* ^? */ /* 128 */ ED_UNASSIGNED, /* M-^@ */ /* 129 */ ED_UNASSIGNED, /* M-^A */ /* 130 */ ED_UNASSIGNED, /* M-^B */ @@ -1011,8 +1000,7 @@ map_init_meta(EditLine *el) break; default: buf[1] = i & 0177; - el_key_add(el, buf, - el_key_map_cmd(el, (int) map[i]), XK_CMD); + key_add(el, buf, key_map_cmd(el, (int) map[i]), XK_CMD); break; } map[(int) buf[0]] = ED_SEQUENCE_LEAD_IN; @@ -1034,7 +1022,7 @@ map_init_vi(EditLine *el) el->el_map.type = MAP_VI; el->el_map.current = el->el_map.key; - el_key_reset(el); + key_reset(el); for (i = 0; i < N_KEYS; i++) { key[i] = vii[i]; @@ -1063,7 +1051,7 @@ map_init_emacs(EditLine *el) el->el_map.type = MAP_EMACS; el->el_map.current = el->el_map.key; - el_key_reset(el); + key_reset(el); for (i = 0; i < N_KEYS; i++) { key[i] = emacs[i]; @@ -1076,7 +1064,7 @@ map_init_emacs(EditLine *el) buf[0] = CONTROL('X'); buf[1] = CONTROL('X'); buf[2] = 0; - el_key_add(el, buf, el_key_map_cmd(el, EM_EXCHANGE_MARK), XK_CMD); + key_add(el, buf, key_map_cmd(el, EM_EXCHANGE_MARK), XK_CMD); tty_bind_char(el, 1); term_bind_arrow(el); @@ -1133,7 +1121,7 @@ map_print_key(EditLine *el, el_action_t *map, const char *in) el_bindings_t *bp; if (in[0] == '\0' || in[1] == '\0') { - (void) el_key__decode_str(in, outbuf, ""); + (void) key__decode_str(in, outbuf, ""); for (bp = el->el_map.help; bp->name != NULL; bp++) if (bp->func == map[(unsigned char) *in]) { (void) fprintf(el->el_outfile, @@ -1141,7 +1129,7 @@ map_print_key(EditLine *el, el_action_t *map, const char *in) return; } } else - el_key_print(el, in); + key_print(el, in); } @@ -1163,20 +1151,20 @@ map_print_some_keys(EditLine *el, el_action_t *map, int first, int last) if (first == last) (void) fprintf(el->el_outfile, "%-15s-> is undefined\n", - el_key__decode_str(firstbuf, unparsbuf, STRQQ)); + key__decode_str(firstbuf, unparsbuf, STRQQ)); return; } for (bp = el->el_map.help; bp->name != NULL; bp++) { if (bp->func == map[first]) { if (first == last) { (void) fprintf(el->el_outfile, "%-15s-> %s\n", - el_key__decode_str(firstbuf, unparsbuf, STRQQ), + key__decode_str(firstbuf, unparsbuf, STRQQ), bp->name); } else { (void) fprintf(el->el_outfile, "%-4s to %-7s-> %s\n", - el_key__decode_str(firstbuf, unparsbuf, STRQQ), - el_key__decode_str(lastbuf, extrabuf, STRQQ), + key__decode_str(firstbuf, unparsbuf, STRQQ), + key__decode_str(lastbuf, extrabuf, STRQQ), bp->name); } return; @@ -1230,7 +1218,7 @@ map_print_all_keys(EditLine *el) map_print_some_keys(el, el->el_map.alt, prev, i - 1); (void) fprintf(el->el_outfile, "Multi-character bindings\n"); - el_key_print(el, ""); + key_print(el, ""); (void) fprintf(el->el_outfile, "Arrow key bindings\n"); term_print_arrow(el, ""); } @@ -1323,9 +1311,9 @@ map_bind(EditLine *el, int argc, const char **argv) return (-1); } if (in[1]) - (void) el_key_delete(el, in); + (void) key_delete(el, in); else if (map[(unsigned char) *in] == ED_SEQUENCE_LEAD_IN) - (void) el_key_delete(el, in); + (void) key_delete(el, in); else map[(unsigned char) *in] = ED_UNASSIGNED; return (0); @@ -1353,9 +1341,9 @@ map_bind(EditLine *el, int argc, const char **argv) return (-1); } if (key) - term_set_arrow(el, in, el_key_map_str(el, out), ntype); + term_set_arrow(el, in, key_map_str(el, out), ntype); else - el_key_add(el, in, el_key_map_str(el, out), ntype); + key_add(el, in, key_map_str(el, out), ntype); map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN; break; @@ -1366,13 +1354,13 @@ map_bind(EditLine *el, int argc, const char **argv) return (-1); } if (key) - term_set_arrow(el, in, el_key_map_str(el, out), ntype); + term_set_arrow(el, in, key_map_str(el, out), ntype); else { if (in[1]) { - el_key_add(el, in, el_key_map_cmd(el, cmd), ntype); + key_add(el, in, key_map_cmd(el, cmd), ntype); map[(unsigned char) *in] = ED_SEQUENCE_LEAD_IN; } else { - el_key_clear(el, map, in); + key_clear(el, map, in); map[(unsigned char) *in] = cmd; } } diff --git a/cmd-line-utils/libedit/map.h b/cmd-line-utils/libedit/map.h index 3c9948ccf88..3b08f48be7a 100644 --- a/cmd-line-utils/libedit/map.h +++ b/cmd-line-utils/libedit/map.h @@ -1,4 +1,4 @@ -/* $NetBSD: map.h,v 1.7 2002/03/18 16:00:56 christos Exp $ */ +/* $NetBSD: map.h,v 1.8 2003/08/07 16:44:32 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/cmd-line-utils/libedit/parse.c b/cmd-line-utils/libedit/parse.c index d09b890c1ab..993cf5b752d 100644 --- a/cmd-line-utils/libedit/parse.c +++ b/cmd-line-utils/libedit/parse.c @@ -1,4 +1,4 @@ -/* $NetBSD: parse.c,v 1.16 2003/01/21 18:40:24 christos Exp $ */ +/* $NetBSD: parse.c,v 1.20 2003/12/05 13:37:48 lukem Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: parse.c,v 1.16 2003/01/21 18:40:24 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * parse.c: parse an editline extended command @@ -59,7 +48,6 @@ __RCSID("$NetBSD: parse.c,v 1.16 2003/01/21 18:40:24 christos Exp $"); * setty */ #include "el.h" -#include "tokenizer.h" #include private const struct { @@ -87,9 +75,8 @@ parse_line(EditLine *el, const char *line) int argc; Tokenizer *tok; - if (!(tok = tok_init(NULL))) - return -1; - tok_line(tok, line, &argc, &argv); + tok = tok_init(NULL); + tok_str(tok, line, &argc, &argv); argc = el_parse(el, argc, argv); tok_end(tok); return (argc); @@ -207,7 +194,7 @@ parse__escape(const char **const ptr) c = *p; break; } - } else if (*p == '^' && isalpha((unsigned char) p[1])) { + } else if (*p == '^') { p++; c = (*p == '?') ? '\177' : (*p & 0237); } else @@ -215,6 +202,7 @@ parse__escape(const char **const ptr) *ptr = ++p; return (c); } + /* parse__string(): * Parse the escapes from in and put the raw string out */ @@ -237,6 +225,14 @@ parse__string(char *out, const char *in) *out++ = n; break; + case 'M': + if (in[1] == '-' && in[2] != '\0') { + *out++ = '\033'; + in += 2; + break; + } + /*FALLTHROUGH*/ + default: *out++ = *in++; break; diff --git a/cmd-line-utils/libedit/parse.h b/cmd-line-utils/libedit/parse.h index 4aaef2f834a..4b796666b8e 100644 --- a/cmd-line-utils/libedit/parse.h +++ b/cmd-line-utils/libedit/parse.h @@ -1,4 +1,4 @@ -/* $NetBSD: parse.h,v 1.4 2000/09/04 22:06:31 lukem Exp $ */ +/* $NetBSD: parse.h,v 1.5 2003/08/07 16:44:32 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/cmd-line-utils/libedit/prompt.c b/cmd-line-utils/libedit/prompt.c index 03d8309a991..455dd60331b 100644 --- a/cmd-line-utils/libedit/prompt.c +++ b/cmd-line-utils/libedit/prompt.c @@ -1,4 +1,4 @@ -/* $NetBSD: prompt.c,v 1.9 2002/03/18 16:00:56 christos Exp $ */ +/* $NetBSD: prompt.c,v 1.11 2003/08/07 16:44:32 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)prompt.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: prompt.c,v 1.9 2002/03/18 16:00:56 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * prompt.c: Prompt printing functions @@ -59,7 +48,7 @@ private char *prompt_default_r(EditLine *); */ private char * /*ARGSUSED*/ -prompt_default(EditLine *el __attribute__((unused))) +prompt_default(EditLine *el __attribute__((__unused__))) { static char a[3] = {'?', ' ', '\0'}; @@ -72,7 +61,7 @@ prompt_default(EditLine *el __attribute__((unused))) */ private char * /*ARGSUSED*/ -prompt_default_r(EditLine *el __attribute__((unused))) +prompt_default_r(EditLine *el __attribute__((__unused__))) { static char a[1] = {'\0'}; @@ -127,7 +116,7 @@ prompt_init(EditLine *el) */ protected void /*ARGSUSED*/ -prompt_end(EditLine *el __attribute__((unused))) +prompt_end(EditLine *el __attribute__((__unused__))) { } diff --git a/cmd-line-utils/libedit/prompt.h b/cmd-line-utils/libedit/prompt.h index 08810e22a0c..d18110861f8 100644 --- a/cmd-line-utils/libedit/prompt.h +++ b/cmd-line-utils/libedit/prompt.h @@ -1,4 +1,4 @@ -/* $NetBSD: prompt.h,v 1.5 2000/09/04 22:06:31 lukem Exp $ */ +/* $NetBSD: prompt.h,v 1.6 2003/08/07 16:44:32 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/cmd-line-utils/libedit/read.c b/cmd-line-utils/libedit/read.c index 5eaa83bf482..40093d6647f 100644 --- a/cmd-line-utils/libedit/read.c +++ b/cmd-line-utils/libedit/read.c @@ -1,4 +1,4 @@ -/* $NetBSD: read.c,v 1.24 2002/11/20 16:50:08 christos Exp $ */ +/* $NetBSD: read.c,v 1.35 2005/03/09 23:55:02 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,20 +32,14 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: read.c,v 1.24 2002/11/20 16:50:08 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * read.c: Clean this junk up! This is horrible code. * Terminal read functions */ #include +#include #include #include #include "el.h" @@ -97,6 +87,10 @@ el_read_getfn(EditLine *el) } +#ifndef MIN +#define MIN(A,B) ((A) < (B) ? (A) : (B)) +#endif + #ifdef DEBUG_EDIT private void read_debug(EditLine *el) @@ -121,11 +115,7 @@ read_debug(EditLine *el) */ /* ARGSUSED */ private int -read__fixio(int fd -#if !(defined(TRY_AGAIN) && (defined(FIONBIO) || (defined(F_SETFL) && defined(O_NDELAY)))) - __attribute__((unused)) -#endif /* !(defined(TRY_AGAIN) && (defined(FIONBIO) || (defined(F_SETFL) && defined(O_NDELAY)))) */ -, int e) +read__fixio(int fd __attribute__((__unused__)), int e) { switch (e) { @@ -190,18 +180,10 @@ read_preread(EditLine *el) { int chrs = 0; - if (el->el_chared.c_macro.nline) { - el_free((ptr_t) el->el_chared.c_macro.nline); - el->el_chared.c_macro.nline = NULL; - } if (el->el_tty.t_mode == ED_IO) return (0); #ifdef FIONREAD - -#ifndef MIN // definition of MIN is lacking on hpux.. -#define MIN(x,y) (((x)<(y))?(x):(y)) -#endif (void) ioctl(el->el_infd, FIONREAD, (ioctl_t) & chrs); if (chrs > 0) { char buf[EL_BUFSIZ]; @@ -210,8 +192,7 @@ read_preread(EditLine *el) (size_t) MIN(chrs, EL_BUFSIZ - 1)); if (chrs > 0) { buf[chrs] = '\0'; - el->el_chared.c_macro.nline = strdup(buf); - el_push(el, el->el_chared.c_macro.nline); + el_push(el, buf); } } #endif /* FIONREAD */ @@ -230,11 +211,12 @@ el_push(EditLine *el, char *str) if (str != NULL && ma->level + 1 < EL_MAXMACRO) { ma->level++; - ma->macro[ma->level] = str; - } else { - term_beep(el); - term__flush(); + if ((ma->macro[ma->level] = el_strdup(str)) != NULL) + return; + ma->level--; } + term_beep(el); + term__flush(); } @@ -266,7 +248,7 @@ read_getcmd(EditLine *el, el_action_t *cmdnum, char *ch) cmd = el->el_map.current[(unsigned char) *ch]; if (cmd == ED_SEQUENCE_LEAD_IN) { key_value_t val; - switch (el_key_get(el, ch, &val)) { + switch (key_get(el, ch, &val)) { case XK_CMD: cmd = val.cmd; break; @@ -331,14 +313,16 @@ el_getc(EditLine *el, char *cp) if (ma->level < 0) break; - if (*ma->macro[ma->level] == 0) { - ma->level--; + if (ma->macro[ma->level][ma->offset] == '\0') { + el_free(ma->macro[ma->level--]); + ma->offset = 0; continue; } - *cp = *ma->macro[ma->level]++ & 0377; - if (*ma->macro[ma->level] == 0) { /* Needed for QuoteMode - * On */ - ma->level--; + *cp = ma->macro[ma->level][ma->offset++] & 0377; + if (ma->macro[ma->level][ma->offset] == '\0') { + /* Needed for QuoteMode On */ + el_free(ma->macro[ma->level--]); + ma->offset = 0; } return (1); } @@ -359,6 +343,35 @@ el_getc(EditLine *el, char *cp) return (num_read); } +protected void +read_prepare(EditLine *el) +{ + if (el->el_flags & HANDLE_SIGNALS) + sig_set(el); + if (el->el_flags & NO_TTY) + return; + if ((el->el_flags & (UNBUFFERED|EDIT_DISABLED)) == UNBUFFERED) + tty_rawmode(el); + + /* This is relatively cheap, and things go terribly wrong if + we have the wrong size. */ + el_resize(el); + re_clear_display(el); /* reset the display stuff */ + ch_reset(el); + re_refresh(el); /* print the prompt */ + + if (el->el_flags & UNBUFFERED) + term__flush(); +} + +protected void +read_finish(EditLine *el) +{ + if ((el->el_flags & UNBUFFERED) == 0) + (void) tty_cookedmode(el); + if (el->el_flags & HANDLE_SIGNALS) + sig_clr(el); +} public const char * el_gets(EditLine *el, int *nread) @@ -367,13 +380,11 @@ el_gets(EditLine *el, int *nread) el_action_t cmdnum = 0; int num; /* how many chars we have read at NL */ char ch; + int crlf = 0; #ifdef FIONREAD c_macro_t *ma = &el->el_chared.c_macro; #endif /* FIONREAD */ - if (el->el_flags & HANDLE_SIGNALS) - sig_set(el); - if (el->el_flags & NO_TTY) { char *cp = el->el_line.buffer; size_t idx; @@ -387,6 +398,8 @@ el_gets(EditLine *el, int *nread) cp = &el->el_line.buffer[idx]; } cp++; + if (el->el_flags & UNBUFFERED) + break; if (cp[-1] == '\r' || cp[-1] == '\n') break; } @@ -398,12 +411,6 @@ el_gets(EditLine *el, int *nread) return (el->el_line.buffer); } - /* This is relatively cheap, and things go terribly wrong if - we have the wrong size. */ - el_resize(el); - - re_clear_display(el); /* reset the display stuff */ - ch_reset(el); #ifdef FIONREAD if (el->el_tty.t_mode == EX_IO && ma->level < 0) { @@ -420,11 +427,16 @@ el_gets(EditLine *el, int *nread) } #endif /* FIONREAD */ - re_refresh(el); /* print the prompt */ + if ((el->el_flags & UNBUFFERED) == 0) + read_prepare(el); if (el->el_flags & EDIT_DISABLED) { - char *cp = el->el_line.buffer; + char *cp; size_t idx; + if ((el->el_flags & UNBUFFERED) == 0) + cp = el->el_line.buffer; + else + cp = el->el_line.lastchar; term__flush(); @@ -439,7 +451,10 @@ el_gets(EditLine *el, int *nread) if (*cp == 4) /* ought to be stty eof */ break; cp++; - if (cp[-1] == '\r' || cp[-1] == '\n') + crlf = cp[-1] == '\r' || cp[-1] == '\n'; + if (el->el_flags & UNBUFFERED) + break; + if (crlf) break; } @@ -463,8 +478,7 @@ el_gets(EditLine *el, int *nread) #endif /* DEBUG_READ */ break; } - if ((unsigned int)cmdnum >= (unsigned int)(el->el_map.nfunc)) - { /* BUG CHECK command */ + if ((uint)cmdnum >= el->el_map.nfunc) { /* BUG CHECK command */ #ifdef DEBUG_EDIT (void) fprintf(el->el_errfile, "ERROR: illegal command from key 0%o\r\n", ch); @@ -494,7 +508,7 @@ el_gets(EditLine *el, int *nread) el->el_chared.c_redo.pos < el->el_chared.c_redo.lim) { if (cmdnum == VI_DELETE_PREV_CHAR && el->el_chared.c_redo.pos != el->el_chared.c_redo.buf - && isprint(el->el_chared.c_redo.pos[-1])) + && isprint((unsigned char)el->el_chared.c_redo.pos[-1])) el->el_chared.c_redo.pos--; else *el->el_chared.c_redo.pos++ = ch; @@ -536,7 +550,13 @@ el_gets(EditLine *el, int *nread) continue; /* keep going... */ case CC_EOF: /* end of file typed */ - num = 0; + if ((el->el_flags & UNBUFFERED) == 0) + num = 0; + else if (num == -1) { + *el->el_line.lastchar++ = CONTROL('d'); + el->el_line.cursor = el->el_line.lastchar; + num = 1; + } break; case CC_NEWLINE: /* normal end of line */ @@ -567,14 +587,19 @@ el_gets(EditLine *el, int *nread) el->el_state.argument = 1; el->el_state.doingarg = 0; el->el_chared.c_vcmd.action = NOP; + if (el->el_flags & UNBUFFERED) + break; } term__flush(); /* flush any buffered output */ /* make sure the tty is set up correctly */ - (void) tty_cookedmode(el); - if (el->el_flags & HANDLE_SIGNALS) - sig_clr(el); - if (nread) - *nread = num; + if ((el->el_flags & UNBUFFERED) == 0) { + read_finish(el); + if (nread) + *nread = num; + } else { + if (nread) + *nread = el->el_line.lastchar - el->el_line.buffer; + } return (num ? el->el_line.buffer : NULL); } diff --git a/cmd-line-utils/libedit/read.h b/cmd-line-utils/libedit/read.h index b01e77db239..1982f47253b 100644 --- a/cmd-line-utils/libedit/read.h +++ b/cmd-line-utils/libedit/read.h @@ -1,4 +1,4 @@ -/* $NetBSD: read.h,v 1.1 2001/09/27 19:29:50 christos Exp $ */ +/* $NetBSD: read.h,v 1.4 2004/02/27 14:52:18 christos Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -49,6 +49,8 @@ typedef struct el_read_t { } el_read_t; protected int read_init(EditLine *); +protected void read_prepare(EditLine *); +protected void read_finish(EditLine *); protected int el_read_setfn(EditLine *, el_rfunc_t); protected el_rfunc_t el_read_getfn(EditLine *); diff --git a/cmd-line-utils/libedit/readline.c b/cmd-line-utils/libedit/readline.c index 5b40ade582c..761acffc13f 100644 --- a/cmd-line-utils/libedit/readline.c +++ b/cmd-line-utils/libedit/readline.c @@ -1,4 +1,4 @@ -/* $NetBSD: readline.c,v 1.28 2003/03/10 01:14:54 christos Exp $ */ +/* $NetBSD: readline.c,v 1.49 2005/03/10 19:34:46 christos Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -36,10 +36,25 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -__RCSID("$NetBSD: readline.c,v 1.28 2003/03/10 01:14:54 christos Exp $"); -#endif /* not lint && not SCCSID */ +/* AIX requires this to be the first thing in the file. */ +#if defined (_AIX) && !defined (__GNUC__) + #pragma alloca +#endif + +#include + +#ifdef __GNUC__ +# undef alloca +# define alloca(n) __builtin_alloca (n) +#else +# ifdef HAVE_ALLOCA_H +# include +# else +# ifndef _AIX +extern char *alloca (); +# endif +# endif +#endif #include #include @@ -51,19 +66,20 @@ __RCSID("$NetBSD: readline.c,v 1.28 2003/03/10 01:14:54 christos Exp $"); #include #include #include -#ifdef HAVE_ALLOCA_H -#include -#endif -#include "histedit.h" -#include "readline/readline.h" +#include +#include +#include + #include "el.h" #include "fcns.h" /* for EL_NUM_FCNS */ +#include "histedit.h" +#include "editline/readline.h" /* for rl_complete() */ -#define TAB '\r' +#define TAB '\r' /* see comment at the #ifdef for sense of this */ -#define GDB_411_HACK +/* #define GDB_411_HACK */ /* readline compatibility stuff - look at readline sources/documentation */ /* to see what these variables mean */ @@ -78,6 +94,9 @@ FILE *rl_outstream = NULL; int rl_point = 0; int rl_end = 0; char *rl_line_buffer = NULL; +VFunction *rl_linefunc = NULL; +int rl_done = 0; +VFunction *rl_event_hook = NULL; int history_base = 1; /* probably never subject to change */ int history_length = 0; @@ -86,15 +105,33 @@ char history_expansion_char = '!'; char history_subst_char = '^'; char *history_no_expand_chars = expand_chars; Function *history_inhibit_expansion_function = NULL; +char *history_arg_extract(int start, int end, const char *str); int rl_inhibit_completion = 0; int rl_attempted_completion_over = 0; char *rl_basic_word_break_characters = break_chars; char *rl_completer_word_break_characters = NULL; char *rl_completer_quote_characters = NULL; -CPFunction *rl_completion_entry_function = NULL; +Function *rl_completion_entry_function = NULL; CPPFunction *rl_attempted_completion_function = NULL; +Function *rl_pre_input_hook = NULL; +Function *rl_startup1_hook = NULL; +Function *rl_getc_function = NULL; +char *rl_terminal_name = NULL; +int rl_already_prompted = 0; +int rl_filename_completion_desired = 0; +int rl_ignore_completion_duplicates = 0; +int rl_catch_signals = 1; +VFunction *rl_redisplay_function = NULL; +Function *rl_startup_hook = NULL; +VFunction *rl_completion_display_matches_hook = NULL; +VFunction *rl_prep_term_function = NULL; +VFunction *rl_deprep_term_function = NULL; +/* + * The current prompt string. + */ +char *rl_prompt = NULL; /* * This is set to character indicating type of completion being done by * rl_complete_internal(); this is available for application completion @@ -128,30 +165,30 @@ static int _rl_complete_show_all = 0; static History *h = NULL; static EditLine *e = NULL; +static Function *map[256]; static int el_rl_complete_cmdnum = 0; /* internal functions */ static unsigned char _el_rl_complete(EditLine *, int); +static unsigned char _el_rl_tstp(EditLine *, int); static char *_get_prompt(EditLine *); static HIST_ENTRY *_move_history(int); -static int _history_search_gen(const char *, int, int); -static int _history_expand_command(const char *, size_t, char **); +static int _history_expand_command(const char *, size_t, size_t, + char **); static char *_rl_compat_sub(const char *, const char *, - const char *, int); -static int rl_complete_internal(int); + const char *, int); +static int _rl_complete_internal(int); static int _rl_qsort_string_compare(const void *, const void *); - -/* - * needed for prompt switching in readline() - */ -static char *el_rl_prompt = NULL; +static int _rl_event_read_char(EditLine *, char *); +static void _rl_update_pos(void); /* ARGSUSED */ static char * -_get_prompt(EditLine *el __attribute__((unused))) +_get_prompt(EditLine *el __attribute__((__unused__))) { - return (el_rl_prompt); + rl_already_prompted = 1; + return (rl_prompt); } @@ -168,7 +205,7 @@ _move_history(int op) return (HIST_ENTRY *) NULL; rl_he.line = ev.str; - rl_he.data = ""; + rl_he.data = (histdata_t) &(ev.num); return (&rl_he); } @@ -221,28 +258,40 @@ rl_initialize(void) el_set(e, EL_HIST, history, h); /* for proper prompt printing in readline() */ - el_rl_prompt = strdup(""); - if (el_rl_prompt == NULL) { + rl_prompt = strdup(""); + if (rl_prompt == NULL) { history_end(h); el_end(e); return -1; } el_set(e, EL_PROMPT, _get_prompt); - el_set(e, EL_SIGNAL, 1); + el_set(e, EL_SIGNAL, rl_catch_signals); /* set default mode to "emacs"-style and read setting afterwards */ /* so this can be overriden */ el_set(e, EL_EDITOR, "emacs"); + if (rl_terminal_name != NULL) + el_set(e, EL_TERMINAL, rl_terminal_name); + else + el_get(e, EL_TERMINAL, &rl_terminal_name); /* - * Word completition - this has to go AFTER rebinding keys + * Word completion - this has to go AFTER rebinding keys * to emacs-style. */ el_set(e, EL_ADDFN, "rl_complete", - "ReadLine compatible completition function", + "ReadLine compatible completion function", _el_rl_complete); el_set(e, EL_BIND, "^I", "rl_complete", NULL); + /* + * Send TSTP when ^Z is pressed. + */ + el_set(e, EL_ADDFN, "rl_tstp", + "ReadLine compatible suspend function", + _el_rl_tstp); + el_set(e, EL_BIND, "^Z", "rl_tstp", NULL); + /* * Find out where the rl_complete function was added; this is * used later to detect that lastcmd was also rl_complete. @@ -264,7 +313,10 @@ rl_initialize(void) li = el_line(e); /* a cheesy way to get rid of const cast. */ rl_line_buffer = memchr(li->buffer, *li->buffer, 1); - rl_point = rl_end = 0; + _rl_update_pos(); + + if (rl_startup_hook) + (*rl_startup_hook)(NULL, 0); return (0); } @@ -281,19 +333,38 @@ readline(const char *prompt) int count; const char *ret; char *buf; + static int used_event_hook; if (e == NULL || h == NULL) rl_initialize(); + rl_done = 0; + /* update prompt accordingly to what has been passed */ if (!prompt) prompt = ""; - if (strcmp(el_rl_prompt, prompt) != 0) { - free(el_rl_prompt); - el_rl_prompt = strdup(prompt); - if (el_rl_prompt == NULL) + if (strcmp(rl_prompt, prompt) != 0) { + free(rl_prompt); + rl_prompt = strdup(prompt); + if (rl_prompt == NULL) return NULL; } + + if (rl_pre_input_hook) + (*rl_pre_input_hook)(NULL, 0); + + if (rl_event_hook && !(e->el_flags&NO_TTY)) { + el_set(e, EL_GETCFN, _rl_event_read_char); + used_event_hook = 1; + } + + if (!rl_event_hook && used_event_hook) { + el_set(e, EL_GETCFN, EL_BUILTIN_GETCFN); + used_event_hook = 0; + } + + rl_already_prompted = 0; + /* get one line from input stream */ ret = el_gets(e, &count); @@ -333,73 +404,178 @@ using_history(void) /* * substitute ``what'' with ``with'', returning resulting string; if - * globally == 1, substitutes all occurences of what, otherwise only the + * globally == 1, substitutes all occurrences of what, otherwise only the * first one */ static char * _rl_compat_sub(const char *str, const char *what, const char *with, int globally) { - char *result; - const char *temp, *new; - unsigned int len, with_len, what_len, add; - size_t size, i; + const char *s; + char *r, *result; + size_t len, with_len, what_len; - result = malloc((size = 16)); - if (result == NULL) - return NULL; - temp = str; + len = strlen(str); with_len = strlen(with); what_len = strlen(what); - len = 0; - do { - new = strstr(temp, what); - if (new) { - i = new - temp; - add = i + with_len; - if (i + add + 1 >= size) { - char *nresult; - size += add + 1; - nresult = realloc(result, size); - if (nresult == NULL) { - free(result); - return NULL; - } - result = nresult; - } - (void) strncpy(&result[len], temp, i); - len += i; - (void) strcpy(&result[len], with); /* safe */ - len += with_len; - temp = new + what_len; - } else { - add = strlen(temp); - if (len + add + 1 >= size) { - char *nresult; - size += add + 1; - nresult = realloc(result, size); - if (nresult == NULL) { - free(result); - return NULL; - } - result = nresult; - } - (void) strcpy(&result[len], temp); /* safe */ - len += add; - temp = NULL; - } - } while (temp && globally); - result[len] = '\0'; - return (result); + /* calculate length we need for result */ + s = str; + while (*s) { + if (*s == *what && !strncmp(s, what, what_len)) { + len += with_len - what_len; + if (!globally) + break; + s += what_len; + } else + s++; + } + r = result = malloc(len + 1); + if (result == NULL) + return NULL; + s = str; + while (*s) { + if (*s == *what && !strncmp(s, what, what_len)) { + (void)strncpy(r, with, with_len); + r += with_len; + s += what_len; + if (!globally) { + (void)strcpy(r, s); + return(result); + } + } else + *r++ = *s++; + } + *r = 0; + return(result); } +static char *last_search_pat; /* last !?pat[?] search pattern */ +static char *last_search_match; /* last !?pat[?] that matched */ + +const char * +get_history_event(const char *cmd, int *cindex, int qchar) +{ + int idx, sign, sub, num, begin, ret; + size_t len; + char *pat; + const char *rptr; + HistEvent ev; + + idx = *cindex; + if (cmd[idx++] != history_expansion_char) + return(NULL); + + /* find out which event to take */ + if (cmd[idx] == history_expansion_char || cmd[idx] == 0) { + if (history(h, &ev, H_FIRST) != 0) + return(NULL); + *cindex = cmd[idx]? (idx + 1):idx; + return(ev.str); + } + sign = 0; + if (cmd[idx] == '-') { + sign = 1; + idx++; + } + + if ('0' <= cmd[idx] && cmd[idx] <= '9') { + HIST_ENTRY *rl_he; + + num = 0; + while (cmd[idx] && '0' <= cmd[idx] && cmd[idx] <= '9') { + num = num * 10 + cmd[idx] - '0'; + idx++; + } + if (sign) + num = history_length - num + 1; + + if (!(rl_he = history_get(num))) + return(NULL); + + *cindex = idx; + return(rl_he->line); + } + sub = 0; + if (cmd[idx] == '?') { + sub = 1; + idx++; + } + begin = idx; + while (cmd[idx]) { + if (cmd[idx] == '\n') + break; + if (sub && cmd[idx] == '?') + break; + if (!sub && (cmd[idx] == ':' || cmd[idx] == ' ' + || cmd[idx] == '\t' || cmd[idx] == qchar)) + break; + idx++; + } + len = idx - begin; + if (sub && cmd[idx] == '?') + idx++; + if (sub && len == 0 && last_search_pat && *last_search_pat) + pat = last_search_pat; + else if (len == 0) + return(NULL); + else { + if ((pat = malloc(len + 1)) == NULL) + return NULL; + (void)strncpy(pat, cmd + begin, len); + pat[len] = '\0'; + } + + if (history(h, &ev, H_CURR) != 0) { + if (pat != last_search_pat) + free(pat); + return (NULL); + } + num = ev.num; + + if (sub) { + if (pat != last_search_pat) { + if (last_search_pat) + free(last_search_pat); + last_search_pat = pat; + } + ret = history_search(pat, -1); + } else + ret = history_search_prefix(pat, -1); + + if (ret == -1) { + /* restore to end of list on failed search */ + history(h, &ev, H_FIRST); + (void)fprintf(rl_outstream, "%s: Event not found\n", pat); + if (pat != last_search_pat) + free(pat); + return(NULL); + } + + if (sub && len) { + if (last_search_match && last_search_match != pat) + free(last_search_match); + last_search_match = pat; + } + + if (pat != last_search_pat) + free(pat); + + if (history(h, &ev, H_CURR) != 0) + return(NULL); + *cindex = idx; + rptr = ev.str; + + /* roll back to original position */ + (void)history(h, &ev, H_SET, num); + + return rptr; +} /* * the real function doing history expansion - takes as argument command * to do and data upon which the command should be executed * does expansion the way I've understood readline documentation - * word designator ``%'' isn't supported (yet ?) * * returns 0 if data was not modified, 1 if it was and 2 if the string * should be only printed and not executed; in case of error, @@ -407,144 +583,145 @@ _rl_compat_sub(const char *str, const char *what, const char *with, * it's callers responsibility to free() string returned in *result */ static int -_history_expand_command(const char *command, size_t cmdlen, char **result) +_history_expand_command(const char *command, size_t offs, size_t cmdlen, + char **result) { - char **arr, *tempcmd, *line, *search = NULL, *cmd; - const char *event_data = NULL; + char *tmp, *search = NULL, *aptr; + const char *ptr, *cmd; static char *from = NULL, *to = NULL; - int start = -1, end = -1, max, i, idx; - int h_on = 0, t_on = 0, r_on = 0, e_on = 0, p_on = 0, g_on = 0; - int event_num = 0, retval; - size_t cmdsize; + int start, end, idx, has_mods = 0; + int p_on = 0, g_on = 0; *result = NULL; + aptr = NULL; + ptr = NULL; - cmd = alloca(cmdlen + 1); - (void) strncpy(cmd, command, cmdlen); - cmd[cmdlen] = 0; + /* First get event specifier */ + idx = 0; - idx = 1; - /* find out which event to take */ - if (cmd[idx] == history_expansion_char) { - event_num = history_length; - idx++; + if (strchr(":^*$", command[offs + 1])) { + char str[4]; + /* + * "!:" is shorthand for "!!:". + * "!^", "!*" and "!$" are shorthand for + * "!!:^", "!!:*" and "!!:$" respectively. + */ + str[0] = str[1] = '!'; + str[2] = '0'; + ptr = get_history_event(str, &idx, 0); + idx = (command[offs + 1] == ':')? 1:0; + has_mods = 1; } else { - int off, num; - size_t len; - off = idx; - while (cmd[off] && !strchr(":^$*-%", cmd[off])) - off++; - num = atoi(&cmd[idx]); - if (num != 0) { - event_num = num; - if (num < 0) - event_num += history_length + 1; + if (command[offs + 1] == '#') { + /* use command so far */ + if ((aptr = malloc(offs + 1)) == NULL) + return -1; + (void)strncpy(aptr, command, offs); + aptr[offs] = '\0'; + idx = 1; } else { - int prefix = 1, curr_num; - HistEvent ev; + int qchar; - len = off - idx; - if (cmd[idx] == '?') { - idx++, len--; - if (cmd[off - 1] == '?') - len--; - else if (cmd[off] != '\n' && cmd[off] != '\0') - return (-1); - prefix = 0; - } - search = alloca(len + 1); - (void) strncpy(search, &cmd[idx], len); - search[len] = '\0'; - - if (history(h, &ev, H_CURR) != 0) - return (-1); - curr_num = ev.num; - - if (prefix) - retval = history_search_prefix(search, -1); - else - retval = history_search(search, -1); - - if (retval == -1) { - fprintf(rl_outstream, "%s: Event not found\n", - search); - return (-1); - } - if (history(h, &ev, H_CURR) != 0) - return (-1); - event_data = ev.str; - - /* roll back to original position */ - history(h, &ev, H_NEXT_EVENT, curr_num); + qchar = (offs > 0 && command[offs - 1] == '"')? '"':0; + ptr = get_history_event(command + offs, &idx, qchar); } - idx = off; + has_mods = command[offs + idx] == ':'; } - if (!event_data && event_num >= 0) { - HIST_ENTRY *rl_he; - rl_he = history_get(event_num); - if (!rl_he) - return (0); - event_data = rl_he->line; + if (ptr == NULL && aptr == NULL) + return(-1); + + if (!has_mods) { + *result = strdup(aptr? aptr : ptr); + if (aptr) + free(aptr); + return(1); + } + + cmd = command + offs + idx + 1; + + /* Now parse any word designators */ + + if (*cmd == '%') /* last word matched by ?pat? */ + tmp = strdup(last_search_match? last_search_match:""); + else if (strchr("^*$-0123456789", *cmd)) { + start = end = -1; + if (*cmd == '^') + start = end = 1, cmd++; + else if (*cmd == '$') + start = -1, cmd++; + else if (*cmd == '*') + start = 1, cmd++; + else if (*cmd == '-' || isdigit((unsigned char) *cmd)) { + start = 0; + while (*cmd && '0' <= *cmd && *cmd <= '9') + start = start * 10 + *cmd++ - '0'; + + if (*cmd == '-') { + if (isdigit((unsigned char) cmd[1])) { + cmd++; + end = 0; + while (*cmd && '0' <= *cmd && *cmd <= '9') + end = end * 10 + *cmd++ - '0'; + } else if (cmd[1] == '$') { + cmd += 2; + end = -1; + } else { + cmd++; + end = -2; + } + } else if (*cmd == '*') + end = -1, cmd++; + else + end = start; + } + tmp = history_arg_extract(start, end, aptr? aptr:ptr); + if (tmp == NULL) { + (void)fprintf(rl_outstream, "%s: Bad word specifier", + command + offs + idx); + if (aptr) + free(aptr); + return(-1); + } } else - return (-1); + tmp = strdup(aptr? aptr:ptr); - if (cmd[idx] != ':') - return (-1); - cmd += idx + 1; + if (aptr) + free(aptr); - /* recognize cmd */ - if (*cmd == '^') - start = end = 1, cmd++; - else if (*cmd == '$') - start = end = -1, cmd++; - else if (*cmd == '*') - start = 1, end = -1, cmd++; - else if (isdigit((unsigned char) *cmd)) { - const char *temp; - int shifted = 0; - - start = atoi(cmd); - temp = cmd; - for (; isdigit((unsigned char) *cmd); cmd++); - if (temp != cmd) - shifted = 1; - if (shifted && *cmd == '-') { - if (!isdigit((unsigned char) *(cmd + 1))) - end = -2; - else { - end = atoi(cmd + 1); - for (; isdigit((unsigned char) *cmd); cmd++); - } - } else if (shifted && *cmd == '*') - end = -1, cmd++; - else if (shifted) - end = start; + if (*cmd == 0 || (cmd - (command + offs) >= cmdlen)) { + *result = tmp; + return(1); } - if (*cmd == ':') - cmd++; - line = strdup(event_data); - if (line == NULL) - return 0; for (; *cmd; cmd++) { if (*cmd == ':') continue; - else if (*cmd == 'h') - h_on = 1 | g_on, g_on = 0; - else if (*cmd == 't') - t_on = 1 | g_on, g_on = 0; - else if (*cmd == 'r') - r_on = 1 | g_on, g_on = 0; - else if (*cmd == 'e') - e_on = 1 | g_on, g_on = 0; - else if (*cmd == 'p') - p_on = 1 | g_on, g_on = 0; + else if (*cmd == 'h') { /* remove trailing path */ + if ((aptr = strrchr(tmp, '/')) != NULL) + *aptr = 0; + } else if (*cmd == 't') { /* remove leading path */ + if ((aptr = strrchr(tmp, '/')) != NULL) { + aptr = strdup(aptr + 1); + free(tmp); + tmp = aptr; + } + } else if (*cmd == 'r') { /* remove trailing suffix */ + if ((aptr = strrchr(tmp, '.')) != NULL) + *aptr = 0; + } else if (*cmd == 'e') { /* remove all but suffix */ + if ((aptr = strrchr(tmp, '.')) != NULL) { + aptr = strdup(aptr); + free(tmp); + tmp = aptr; + } + } else if (*cmd == 'p') /* print only */ + p_on = 1; else if (*cmd == 'g') g_on = 2; else if (*cmd == 's' || *cmd == '&') { char *what, *with, delim; - unsigned int len, from_len; + size_t len, from_len; size_t size; if (*cmd == '&' && (from == NULL || to == NULL)) @@ -559,13 +736,12 @@ _history_expand_command(const char *command, size_t cmdlen, char **result) } len = 0; for (; *cmd && *cmd != delim; cmd++) { - if (*cmd == '\\' - && *(cmd + 1) == delim) + if (*cmd == '\\' && cmd[1] == delim) cmd++; if (len >= size) { char *nwhat; nwhat = realloc(what, - (size <<= 1)); + (size <<= 1)); if (nwhat == NULL) { free(what); return 0; @@ -612,7 +788,7 @@ _history_expand_command(const char *command, size_t cmdlen, char **result) } if (*cmd == '&') { /* safe */ - (void) strcpy(&with[len], from); + (void)strcpy(&with[len], from); len += from_len; continue; } @@ -624,88 +800,18 @@ _history_expand_command(const char *command, size_t cmdlen, char **result) } with[len] = '\0'; to = with; - - tempcmd = _rl_compat_sub(line, from, to, - (g_on) ? 1 : 0); - if (tempcmd) { - free(line); - line = tempcmd; - } - g_on = 0; } + + aptr = _rl_compat_sub(tmp, from, to, g_on); + if (aptr) { + free(tmp); + tmp = aptr; + } + g_on = 0; } } - - arr = history_tokenize(line); - free(line); /* no more needed */ - if (arr && *arr == NULL) - free(arr), arr = NULL; - if (!arr) - return (-1); - - /* find out max valid idx to array of array */ - max = 0; - for (i = 0; arr[i]; i++) - max++; - max--; - - /* set boundaries to something relevant */ - if (start < 0) - start = 1; - if (end < 0) - end = max - ((end < -1) ? 1 : 0); - - /* check boundaries ... */ - if (start > max || end > max || start > end) - return (-1); - - for (i = 0; i <= max; i++) { - char *temp; - if (h_on && (i == 1 || h_on > 1) && - (temp = strrchr(arr[i], '/'))) - *(temp + 1) = '\0'; - if (t_on && (i == 1 || t_on > 1) && - (temp = strrchr(arr[i], '/'))) - (void) strcpy(arr[i], temp + 1); - if (r_on && (i == 1 || r_on > 1) && - (temp = strrchr(arr[i], '.'))) - *temp = '\0'; - if (e_on && (i == 1 || e_on > 1) && - (temp = strrchr(arr[i], '.'))) - (void) strcpy(arr[i], temp); - } - - cmdsize = 1, cmdlen = 0; - if ((tempcmd = malloc(cmdsize)) == NULL) - return 0; - for (i = start; start <= i && i <= end; i++) { - int arr_len; - - arr_len = strlen(arr[i]); - if (cmdlen + arr_len + 1 >= cmdsize) { - char *ntempcmd; - cmdsize += arr_len + 1; - ntempcmd = realloc(tempcmd, cmdsize); - if (ntempcmd == NULL) { - free(tempcmd); - return 0; - } - tempcmd = ntempcmd; - } - (void) strcpy(&tempcmd[cmdlen], arr[i]); /* safe */ - cmdlen += arr_len; - tempcmd[cmdlen++] = ' '; /* add a space */ - } - while (cmdlen > 0 && isspace((unsigned char) tempcmd[cmdlen - 1])) - cmdlen--; - tempcmd[cmdlen] = '\0'; - - *result = tempcmd; - - for (i = 0; i <= max; i++) - free(arr[i]); - free(arr), arr = (char **) NULL; - return (p_on) ? 2 : 1; + *result = tmp; + return (p_on? 2:1); } @@ -715,27 +821,36 @@ _history_expand_command(const char *command, size_t cmdlen, char **result) int history_expand(char *str, char **output) { - int i, retval = 0, idx; - size_t size; - char *temp, *result; + int ret = 0; + size_t idx, i, size; + char *tmp, *result; if (h == NULL || e == NULL) rl_initialize(); - *output = strdup(str); /* do it early */ - if (*output == NULL) - return 0; + if (history_expansion_char == 0) { + *output = strdup(str); + return(0); + } + *output = NULL; if (str[0] == history_subst_char) { /* ^foo^foo2^ is equivalent to !!:s^foo^foo2^ */ - temp = alloca(4 + strlen(str) + 1); - temp[0] = temp[1] = history_expansion_char; - temp[2] = ':'; - temp[3] = 's'; - (void) strcpy(temp + 4, str); - str = temp; + *output = malloc(strlen(str) + 4 + 1); + if (*output == NULL) + return 0; + (*output)[0] = (*output)[1] = history_expansion_char; + (*output)[2] = ':'; + (*output)[3] = 's'; + (void)strcpy((*output) + 4, str); + str = *output; + } else { + *output = strdup(str); + if (*output == NULL) + return 0; } -#define ADD_STRING(what, len) \ + +#define ADD_STRING(what, len) \ { \ if (idx + len + 1 > size) { \ char *nresult = realloc(result, (size += len + 1));\ @@ -753,35 +868,35 @@ history_expand(char *str, char **output) result = NULL; size = idx = 0; for (i = 0; str[i];) { - int start, j, loop_again; - size_t len; + int qchar, loop_again; + size_t len, start, j; + qchar = 0; loop_again = 1; start = j = i; loop: for (; str[j]; j++) { if (str[j] == '\\' && str[j + 1] == history_expansion_char) { - (void) strcpy(&str[j], &str[j + 1]); + (void)strcpy(&str[j], &str[j + 1]); continue; } if (!loop_again) { - if (str[j] == '?') { - while (str[j] && str[++j] != '?'); - if (str[j] == '?') - j++; - } else if (isspace((unsigned char) str[j])) + if (isspace((unsigned char) str[j]) + || str[j] == qchar) break; } if (str[j] == history_expansion_char && !strchr(history_no_expand_chars, str[j + 1]) && (!history_inhibit_expansion_function || - (*history_inhibit_expansion_function)(str, j) == 0)) + (*history_inhibit_expansion_function)(str, + (int)j) == 0)) break; } - if (str[j] && str[j + 1] != '#' && loop_again) { + if (str[j] && loop_again) { i = j; + qchar = (j > 0 && str[j - 1] == '"' )? '"':0; j++; if (str[j] == history_expansion_char) j++; @@ -789,61 +904,116 @@ loop: goto loop; } len = i - start; - temp = &str[start]; - ADD_STRING(temp, len); + tmp = &str[start]; + ADD_STRING(tmp, len); - if (str[i] == '\0' || str[i] != history_expansion_char - || str[i + 1] == '#') { + if (str[i] == '\0' || str[i] != history_expansion_char) { len = j - i; - temp = &str[i]; - ADD_STRING(temp, len); + tmp = &str[i]; + ADD_STRING(tmp, len); if (start == 0) - retval = 0; + ret = 0; else - retval = 1; + ret = 1; break; } - retval = _history_expand_command(&str[i], (size_t) (j - i), - &temp); - if (retval != -1) { - len = strlen(temp); - ADD_STRING(temp, len); + ret = _history_expand_command (str, i, (j - i), &tmp); + if (ret > 0 && tmp) { + len = strlen(tmp); + ADD_STRING(tmp, len); + free(tmp); } i = j; - } /* for(i ...) */ + } - if (retval == 2) { - add_history(temp); + /* ret is 2 for "print only" option */ + if (ret == 2) { + add_history(result); #ifdef GDB_411_HACK /* gdb 4.11 has been shipped with readline, where */ /* history_expand() returned -1 when the line */ /* should not be executed; in readline 2.1+ */ /* it should return 2 in such a case */ - retval = -1; + ret = -1; #endif } free(*output); *output = result; - return (retval); + return (ret); } +/* +* Return a string consisting of arguments of "str" from "start" to "end". +*/ +char * +history_arg_extract(int start, int end, const char *str) +{ + size_t i, len, max; + char **arr, *result; + + arr = history_tokenize(str); + if (!arr) + return(NULL); + if (arr && *arr == NULL) { + free(arr); + return(NULL); + } + + for (max = 0; arr[max]; max++) + continue; + max--; + + if (start == '$') + start = max; + if (end == '$') + end = max; + if (end < 0) + end = max + end + 1; + if (start < 0) + start = end; + + if (start < 0 || end < 0 || start > max || end > max || start > end) + return(NULL); + + for (i = start, len = 0; i <= end; i++) + len += strlen(arr[i]) + 1; + len++; + result = malloc(len); + if (result == NULL) + return NULL; + + for (i = start, len = 0; i <= end; i++) { + (void)strcpy(result + len, arr[i]); + len += strlen(arr[i]); + if (i < end) + result[len++] = ' '; + } + result[len] = 0; + + for (i = 0; arr[i]; i++) + free(arr[i]); + free(arr); + + return(result); +} /* - * Parse the string into individual tokens, similarily to how shell would do it. + * Parse the string into individual tokens, + * similar to how shell would do it. */ char ** history_tokenize(const char *str) { - int size = 1, result_idx = 0, i, start; + int size = 1, idx = 0, i, start; size_t len; char **result = NULL, *temp, delim = '\0'; - for (i = 0; str[i]; i++) { + for (i = 0; str[i];) { while (isspace((unsigned char) str[i])) i++; start = i; - for (; str[i]; i++) { + for (; str[i];) { if (str[i] == '\\') { if (str[i+1] != '\0') i++; @@ -855,9 +1025,11 @@ history_tokenize(const char *str) break; else if (!delim && strchr("'`\"", str[i])) delim = str[i]; + if (str[i]) + i++; } - if (result_idx + 2 >= size) { + if (idx + 2 >= size) { char **nresult; size <<= 1; nresult = realloc(result, size * sizeof(char *)); @@ -870,15 +1042,18 @@ history_tokenize(const char *str) len = i - start; temp = malloc(len + 1); if (temp == NULL) { + for (i = 0; i < idx; i++) + free(result[i]); free(result); return NULL; } - (void) strncpy(temp, &str[start], len); + (void)strncpy(temp, &str[start], len); temp[len] = '\0'; - result[result_idx++] = temp; - result[result_idx] = NULL; + result[idx++] = temp; + result[idx] = NULL; + if (str[i]) + i++; } - return (result); } @@ -962,28 +1137,29 @@ history_get(int num) { static HIST_ENTRY she; HistEvent ev; - int i = 1, curr_num; + int curr_num; if (h == NULL || e == NULL) rl_initialize(); - /* rewind to beginning */ + /* save current position */ if (history(h, &ev, H_CURR) != 0) return (NULL); curr_num = ev.num; - if (history(h, &ev, H_LAST) != 0) + + /* start from most recent */ + if (history(h, &ev, H_FIRST) != 0) return (NULL); /* error */ - while (i < num && history(h, &ev, H_PREV) == 0) - i++; - if (i != num) - return (NULL); /* not so many entries */ + + /* look backwards for event matching specified offset */ + if (history(h, &ev, H_NEXT_EVENT, num)) + return (NULL); she.line = ev.str; she.data = NULL; - /* rewind history to the same event it was before */ - (void) history(h, &ev, H_FIRST); - (void) history(h, &ev, H_NEXT_EVENT, curr_num); + /* restore pointer to where it was */ + (void)history(h, &ev, H_SET, curr_num); return (&she); } @@ -1000,11 +1176,11 @@ add_history(const char *line) if (h == NULL || e == NULL) rl_initialize(); - (void) history(h, &ev, H_ENTER, line); + (void)history(h, &ev, H_ENTER, line); if (history(h, &ev, H_GETSIZE) == 0) history_length = ev.num; - return (!(history_length > 0)); /* return 0 if all is okay */ + return (!(history_length > 0)); /* return 0 if all is okay */ } @@ -1086,22 +1262,17 @@ int history_set_pos(int pos) { HistEvent ev; - int off, curr_num; + int curr_num; if (pos > history_length || pos < 0) return (-1); history(h, &ev, H_CURR); curr_num = ev.num; - history(h, &ev, H_FIRST); - off = 0; - while (off < pos && history(h, &ev, H_NEXT) == 0) - off++; - if (off != pos) { /* do a rollback in case of error */ - history(h, &ev, H_FIRST); - history(h, &ev, H_NEXT_EVENT, curr_num); - return (-1); + if (history(h, &ev, H_SET, pos)) { + history(h, &ev, H_SET, curr_num); + return(-1); } return (0); } @@ -1130,10 +1301,10 @@ next_history(void) /* - * generic history search function + * searches for first history event containing the str */ -static int -_history_search_gen(const char *str, int direction, int pos) +int +history_search(const char *str, int direction) { HistEvent ev; const char *strp; @@ -1144,38 +1315,25 @@ _history_search_gen(const char *str, int direction, int pos) curr_num = ev.num; for (;;) { - strp = strstr(ev.str, str); - if (strp && (pos < 0 || &ev.str[pos] == strp)) + if ((strp = strstr(ev.str, str)) != NULL) return (int) (strp - ev.str); - if (history(h, &ev, direction < 0 ? H_PREV : H_NEXT) != 0) + if (history(h, &ev, direction < 0 ? H_NEXT:H_PREV) != 0) break; } - - history(h, &ev, direction < 0 ? H_NEXT_EVENT : H_PREV_EVENT, curr_num); - + history(h, &ev, H_SET, curr_num); return (-1); } -/* - * searches for first history event containing the str - */ -int -history_search(const char *str, int direction) -{ - - return (_history_search_gen(str, direction, -1)); -} - - /* * searches for first history event beginning with str */ int history_search_prefix(const char *str, int direction) { + HistEvent ev; - return (_history_search_gen(str, direction, 0)); + return (history(h, &ev, direction < 0? H_PREV_STR:H_NEXT_STR, str)); } @@ -1185,8 +1343,8 @@ history_search_prefix(const char *str, int direction) */ /* ARGSUSED */ int -history_search_pos(const char *str, - int direction __attribute__((unused)), int pos) +history_search_pos(const char *str, + int direction __attribute__((__unused__)), int pos) { HistEvent ev; int curr_num, off; @@ -1217,7 +1375,7 @@ history_search_pos(const char *str, /********************************/ -/* completition functions */ +/* completion functions */ /* * does tilde expansion of strings of type ``~user/foo'' @@ -1246,7 +1404,7 @@ tilde_expand(char *txt) temp = malloc(len); if (temp == NULL) return NULL; - (void) strncpy(temp, txt + 1, len - 2); + (void)strncpy(temp, txt + 1, len - 2); temp[len - 2] = '\0'; } pass = getpwnam(temp); @@ -1261,7 +1419,7 @@ tilde_expand(char *txt) temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); if (temp == NULL) return NULL; - (void) sprintf(temp, "%s/%s", pass->pw_dir, txt); + (void)sprintf(temp, "%s/%s", pass->pw_dir, txt); return (temp); } @@ -1295,7 +1453,7 @@ filename_completion_function(const char *text, int state) return NULL; } filename = nptr; - (void) strcpy(filename, temp); + (void)strcpy(filename, temp); len = temp - text; /* including last slash */ nptr = realloc(dirname, len + 1); if (nptr == NULL) { @@ -1303,12 +1461,16 @@ filename_completion_function(const char *text, int state) return NULL; } dirname = nptr; - (void) strncpy(dirname, text, len); + (void)strncpy(dirname, text, len); dirname[len] = '\0'; } else { - filename = strdup(text); - if (filename == NULL) - return NULL; + if (*text == 0) + filename = NULL; + else { + filename = strdup(text); + if (filename == NULL) + return NULL; + } dirname = NULL; } @@ -1324,13 +1486,11 @@ filename_completion_function(const char *text, int state) return NULL; } dirname = nptr; - (void) strcpy(dirname, temp); /* safe */ + (void)strcpy(dirname, temp); /* safe */ free(temp); /* no longer needed */ } /* will be used in cycle */ - filename_len = strlen(filename); - if (filename_len == 0) - return (NULL); /* no expansion possible */ + filename_len = filename ? strlen(filename) : 0; if (dir != NULL) { (void)closedir(dir); @@ -1342,14 +1502,17 @@ filename_completion_function(const char *text, int state) } /* find the match */ while ((entry = readdir(dir)) != NULL) { + /* skip . and .. */ + if (entry->d_name[0] == '.' && (!entry->d_name[1] + || (entry->d_name[1] == '.' && !entry->d_name[2]))) + continue; + if (filename_len == 0) + break; /* otherwise, get first entry where first */ /* filename_len characters are equal */ if (entry->d_name[0] == filename[0] -#ifndef STRUCT_DIRENT_HAS_D_NAMLEN + /* Some dirents have d_namlen, but it is not portable. */ && strlen(entry->d_name) >= filename_len -#else - && entry->d_namlen >= filename_len -#endif && strncmp(entry->d_name, filename, filename_len) == 0) break; @@ -1358,16 +1521,13 @@ filename_completion_function(const char *text, int state) if (entry) { /* match found */ struct stat stbuf; -#ifndef STRUCT_DIRENT_HAS_D_NAMLEN + /* Some dirents have d_namlen, but it is not portable. */ len = strlen(entry->d_name) + -#else - len = entry->d_namlen + -#endif ((dirname) ? strlen(dirname) : 0) + 1 + 1; temp = malloc(len); if (temp == NULL) return NULL; - (void) sprintf(temp, "%s%s", + (void)sprintf(temp, "%s%s", dirname ? dirname : "", entry->d_name); /* safe */ /* test, if it's directory */ @@ -1420,32 +1580,43 @@ username_completion_function(const char *text, int state) */ /* ARGSUSED */ static unsigned char -_el_rl_complete(EditLine *el __attribute__((unused)), int ch) +_el_rl_complete(EditLine *el __attribute__((__unused__)), int ch) { return (unsigned char) rl_complete(0, ch); } +/* + * el-compatible wrapper to send TSTP on ^Z + */ +/* ARGSUSED */ +static unsigned char +_el_rl_tstp(EditLine *el __attribute__((__unused__)), int ch __attribute__((__unused__))) +{ + (void)kill(0, SIGTSTP); + return CC_NORM; +} /* - * returns list of completitions for text given + * returns list of completions for text given */ char ** completion_matches(const char *text, CPFunction *genfunc) { char **match_list = NULL, *retstr, *prevstr; size_t match_list_len, max_equal, which, i; - unsigned int matches; + size_t matches; if (h == NULL || e == NULL) rl_initialize(); matches = 0; match_list_len = 1; - while ((retstr = (*genfunc) (text, matches)) != NULL) { + while ((retstr = (*genfunc) (text, (int)matches)) != NULL) { /* allow for list terminator here */ - if (matches + 2 >= match_list_len) { + if (matches + 3 >= match_list_len) { char **nmatch_list; - match_list_len <<= 1; + while (matches + 3 >= match_list_len) + match_list_len <<= 1; nmatch_list = realloc(match_list, match_list_len * sizeof(char *)); if (nmatch_list == NULL) { @@ -1477,7 +1648,7 @@ completion_matches(const char *text, CPFunction *genfunc) free(match_list); return NULL; } - (void) strncpy(retstr, match_list[1], max_equal); + (void)strncpy(retstr, match_list[1], max_equal); retstr[max_equal] = '\0'; match_list[0] = retstr; @@ -1532,9 +1703,10 @@ rl_display_match_list (matches, len, max) idx = 1; for(; count > 0; count--) { - for(i=0; i < limit && matches[idx]; i++, idx++) - fprintf(e->el_outfile, "%-*s ", max, matches[idx]); - fprintf(e->el_outfile, "\n"); + for(i = 0; i < limit && matches[idx]; i++, idx++) + (void)fprintf(e->el_outfile, "%-*s ", max, + matches[idx]); + (void)fprintf(e->el_outfile, "\n"); } } @@ -1550,9 +1722,9 @@ rl_display_match_list (matches, len, max) * Note: '*' support is not implemented */ static int -rl_complete_internal(int what_to_do) +_rl_complete_internal(int what_to_do) { - CPFunction *complet_func; + Function *complet_func; const LineInfo *li; char *temp, **matches; const char *ctemp; @@ -1565,7 +1737,7 @@ rl_complete_internal(int what_to_do) complet_func = rl_completion_entry_function; if (!complet_func) - complet_func = filename_completion_function; + complet_func = (Function *)(void *)filename_completion_function; /* We now look backwards for the start of a filename/variable word */ li = el_line(e); @@ -1573,26 +1745,26 @@ rl_complete_internal(int what_to_do) while (ctemp > li->buffer && !strchr(rl_basic_word_break_characters, ctemp[-1]) && (!rl_special_prefixes - || !strchr(rl_special_prefixes, ctemp[-1]) ) ) + || !strchr(rl_special_prefixes, ctemp[-1]) ) ) ctemp--; len = li->cursor - ctemp; temp = alloca(len + 1); - (void) strncpy(temp, ctemp, len); + (void)strncpy(temp, ctemp, len); temp[len] = '\0'; /* these can be used by function called in completion_matches() */ /* or (*rl_attempted_completion_function)() */ - rl_point = li->cursor - li->buffer; - rl_end = li->lastchar - li->buffer; + _rl_update_pos(); - if (!rl_attempted_completion_function) - matches = completion_matches(temp, complet_func); - else { + if (rl_attempted_completion_function) { int end = li->cursor - li->buffer; matches = (*rl_attempted_completion_function) (temp, (int) (end - len), end); - } + } else + matches = 0; + if (!rl_attempted_completion_function || !matches) + matches = completion_matches(temp, (CPFunction *)complet_func); if (matches) { int i, retval = CC_REFRESH; @@ -1613,11 +1785,12 @@ rl_complete_internal(int what_to_do) if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { /* * We found exact match. Add a space after - * it, unless we do filename completition and the + * it, unless we do filename completion and the * object is a directory. */ size_t alen = strlen(matches[0]); - if ((complet_func != filename_completion_function + if ((complet_func != + (Function *)filename_completion_function || (alen > 0 && (matches[0])[alen - 1] != '/')) && rl_completion_append_character) { char buf[2]; @@ -1640,20 +1813,20 @@ rl_complete_internal(int what_to_do) matches_num = i - 1; /* newline to get on next line from command line */ - fprintf(e->el_outfile, "\n"); + (void)fprintf(e->el_outfile, "\n"); /* * If there are too many items, ask user for display * confirmation. */ if (matches_num > rl_completion_query_items) { - fprintf(e->el_outfile, - "Display all %d possibilities? (y or n) ", - matches_num); - fflush(e->el_outfile); + (void)fprintf(e->el_outfile, + "Display all %d possibilities? (y or n) ", + matches_num); + (void)fflush(e->el_outfile); if (getc(stdin) != 'y') match_display = 0; - fprintf(e->el_outfile, "\n"); + (void)fprintf(e->el_outfile, "\n"); } if (match_display) @@ -1689,20 +1862,24 @@ rl_complete_internal(int what_to_do) * complete word at current point */ int +/*ARGSUSED*/ rl_complete(int ignore, int invoking_key) { if (h == NULL || e == NULL) rl_initialize(); if (rl_inhibit_completion) { - rl_insert(ignore, invoking_key); + char arr[2]; + arr[0] = (char)invoking_key; + arr[1] = '\0'; + el_insertstr(e, arr); return (CC_REFRESH); } else if (e->el_state.lastcmd == el_rl_complete_cmdnum) - return rl_complete_internal('?'); + return _rl_complete_internal('?'); else if (_rl_complete_show_all) - return rl_complete_internal('!'); + return _rl_complete_internal('!'); else - return (rl_complete_internal(TAB)); + return _rl_complete_internal(TAB); } @@ -1751,7 +1928,7 @@ rl_read_key(void) */ /* ARGSUSED */ void -rl_reset_terminal(const char *p __attribute__((unused))) +rl_reset_terminal(const char *p __attribute__((__unused__))) { if (h == NULL || e == NULL) @@ -1780,3 +1957,211 @@ rl_insert(int count, int c) return (0); } + +/*ARGSUSED*/ +int +rl_newline(int count, int c) +{ + /* + * Readline-4.0 appears to ignore the args. + */ + return rl_insert(1, '\n'); +} + +/*ARGSUSED*/ +static unsigned char +rl_bind_wrapper(EditLine *el, unsigned char c) +{ + if (map[c] == NULL) + return CC_ERROR; + + _rl_update_pos(); + + (*map[c])(NULL, c); + + /* If rl_done was set by the above call, deal with it here */ + if (rl_done) + return CC_EOF; + + return CC_NORM; +} + +int +rl_add_defun(const char *name, Function *fun, int c) +{ + char dest[8]; + if (c >= sizeof(map) / sizeof(map[0]) || c < 0) + return -1; + map[(unsigned char)c] = fun; + el_set(e, EL_ADDFN, name, name, rl_bind_wrapper); + vis(dest, c, VIS_WHITE|VIS_NOSLASH, 0); + el_set(e, EL_BIND, dest, name); + return 0; +} + +void +rl_callback_read_char() +{ + int count = 0, done = 0; + const char *buf = el_gets(e, &count); + char *wbuf; + + if (buf == NULL || count-- <= 0) + return; +#ifdef CTRL2 /* _AIX */ + if (count == 0 && buf[0] == CTRL2('d')) +#else + if (count == 0 && buf[0] == CTRL('d')) +#endif + done = 1; + if (buf[count] == '\n' || buf[count] == '\r') + done = 2; + + if (done && rl_linefunc != NULL) { + el_set(e, EL_UNBUFFERED, 0); + if (done == 2) { + if ((wbuf = strdup(buf)) != NULL) + wbuf[count] = '\0'; + } else + wbuf = NULL; + (*(void (*)(const char *))rl_linefunc)(wbuf); + el_set(e, EL_UNBUFFERED, 1); + } +} + +void +rl_callback_handler_install (const char *prompt, VFunction *linefunc) +{ + if (e == NULL) { + rl_initialize(); + } + if (rl_prompt) + free(rl_prompt); + rl_prompt = prompt ? strdup(strchr(prompt, *prompt)) : NULL; + rl_linefunc = linefunc; + el_set(e, EL_UNBUFFERED, 1); +} + +void +rl_callback_handler_remove(void) +{ + el_set(e, EL_UNBUFFERED, 0); +} + +void +rl_redisplay(void) +{ + char a[2]; +#ifdef CTRL2 /* _AIX */ + a[0] = CTRL2('r'); +#else + a[0] = CTRL('r'); +#endif + a[1] = '\0'; + el_push(e, a); +} + +int +rl_get_previous_history(int count, int key) +{ + char a[2]; + a[0] = key; + a[1] = '\0'; + while (count--) + el_push(e, a); + return 0; +} + +void +/*ARGSUSED*/ +rl_prep_terminal(int meta_flag) +{ + el_set(e, EL_PREP_TERM, 1); +} + +void +rl_deprep_terminal() +{ + el_set(e, EL_PREP_TERM, 0); +} + +int +rl_read_init_file(const char *s) +{ + return(el_source(e, s)); +} + +int +rl_parse_and_bind(const char *line) +{ + const char **argv; + int argc; + Tokenizer *tok; + + tok = tok_init(NULL); + tok_str(tok, line, &argc, &argv); + argc = el_parse(e, argc, argv); + tok_end(tok); + return (argc ? 1 : 0); +} + +void +rl_stuff_char(int c) +{ + char buf[2]; + + buf[0] = c; + buf[1] = '\0'; + el_insertstr(e, buf); +} + +static int +_rl_event_read_char(EditLine *el, char *cp) +{ + int n, num_read = 0; + + *cp = 0; + while (rl_event_hook) { + + (*rl_event_hook)(); + +#if defined(FIONREAD) + if (ioctl(el->el_infd, FIONREAD, &n) < 0) + return(-1); + if (n) + num_read = read(el->el_infd, cp, 1); + else + num_read = 0; +#elif defined(F_SETFL) && defined(O_NDELAY) + if ((n = fcntl(el->el_infd, F_GETFL, 0)) < 0) + return(-1); + if (fcntl(el->el_infd, F_SETFL, n|O_NDELAY) < 0) + return(-1); + num_read = read(el->el_infd, cp, 1); + if (fcntl(el->el_infd, F_SETFL, n)) + return(-1); +#else + /* not non-blocking, but what you gonna do? */ + num_read = read(el->el_infd, cp, 1); + return(-1); +#endif + + if (num_read < 0 && errno == EAGAIN) + continue; + if (num_read == 0) + continue; + break; + } + if (!rl_event_hook) + el_set(el, EL_GETCFN, EL_BUILTIN_GETCFN); + return(num_read); +} + +static void +_rl_update_pos(void) +{ + const LineInfo *li = el_line(e); + + rl_point = li->cursor - li->buffer; + rl_end = li->lastchar - li->buffer; +} diff --git a/cmd-line-utils/libedit/refresh.c b/cmd-line-utils/libedit/refresh.c index e71bdba2b61..b2833d215c5 100644 --- a/cmd-line-utils/libedit/refresh.c +++ b/cmd-line-utils/libedit/refresh.c @@ -1,4 +1,4 @@ -/* $NetBSD: refresh.c,v 1.24 2003/03/10 21:18:49 christos Exp $ */ +/* $NetBSD: refresh.c,v 1.26 2003/08/07 16:44:33 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: refresh.c,v 1.24 2003/03/10 21:18:49 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * refresh.c: Lower level screen refreshing functions @@ -57,8 +46,8 @@ __RCSID("$NetBSD: refresh.c,v 1.24 2003/03/10 21:18:49 christos Exp $"); private void re_addc(EditLine *, int); private void re_update_line(EditLine *, char *, char *, int); -private void re_insert (EditLine *el, char *, int, int, char *, int); -private void re_delete(EditLine *el, char *, int, int, int); +private void re_insert (EditLine *, char *, int, int, char *, int); +private void re_delete(EditLine *, char *, int, int, int); private void re_fastputc(EditLine *, int); private void re__strncopy(char *, char *, size_t); private void re__copy_and_pad(char *, const char *, size_t); @@ -338,8 +327,8 @@ re_goto_bottom(EditLine *el) */ private void /*ARGSUSED*/ -re_insert(EditLine *el __attribute__((unused)), - char *d, int dat, int dlen, char *s, int num) +re_insert(EditLine *el __attribute__((__unused__)), + char *d, int dat, int dlen, char *s, int num) { char *a, *b; @@ -382,8 +371,8 @@ re_insert(EditLine *el __attribute__((unused)), */ private void /*ARGSUSED*/ -re_delete(EditLine *el __attribute__((unused)), - char *d, int dat, int dlen, int num) +re_delete(EditLine *el __attribute__((__unused__)), + char *d, int dat, int dlen, int num) { char *a, *b; diff --git a/cmd-line-utils/libedit/refresh.h b/cmd-line-utils/libedit/refresh.h index 33c0887c1b3..dd2bd02094b 100644 --- a/cmd-line-utils/libedit/refresh.h +++ b/cmd-line-utils/libedit/refresh.h @@ -1,4 +1,4 @@ -/* $NetBSD: refresh.h,v 1.4 2001/01/10 07:45:42 jdolecek Exp $ */ +/* $NetBSD: refresh.h,v 1.5 2003/08/07 16:44:33 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/cmd-line-utils/libedit/search.c b/cmd-line-utils/libedit/search.c index 0957529485c..848429e091b 100644 --- a/cmd-line-utils/libedit/search.c +++ b/cmd-line-utils/libedit/search.c @@ -1,4 +1,4 @@ -/* $NetBSD: search.c,v 1.14 2002/11/20 16:50:08 christos Exp $ */ +/* $NetBSD: search.c,v 1.20 2004/11/04 01:16:03 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,21 +32,13 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)search.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: search.c,v 1.14 2002/11/20 16:50:08 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * search.c: History and character search functions */ #include #if defined(REGEX) -#include #include #elif defined(REGEXP) #include @@ -227,8 +215,11 @@ ce_inc_search(EditLine *el, int dir) if (el->el_search.patlen == 0) { /* first round */ pchar = ':'; #ifdef ANCHOR +#define LEN 2 el->el_search.patbuf[el->el_search.patlen++] = '.'; el->el_search.patbuf[el->el_search.patlen++] = '*'; +#else +#define LEN 0 #endif } done = redo = 0; @@ -237,7 +228,7 @@ ce_inc_search(EditLine *el, int dir) *cp; *el->el_line.lastchar++ = *cp++) continue; *el->el_line.lastchar++ = pchar; - for (cp = &el->el_search.patbuf[1]; + for (cp = &el->el_search.patbuf[LEN]; cp < &el->el_search.patbuf[el->el_search.patlen]; *el->el_line.lastchar++ = *cp++) continue; @@ -250,7 +241,7 @@ ce_inc_search(EditLine *el, int dir) switch (el->el_map.current[(unsigned char) ch]) { case ED_INSERT: case ED_DIGIT: - if (el->el_search.patlen > EL_BUFSIZ - 3) + if (el->el_search.patlen >= EL_BUFSIZ - LEN) term_beep(el); else { el->el_search.patbuf[el->el_search.patlen++] = @@ -271,8 +262,9 @@ ce_inc_search(EditLine *el, int dir) redo++; break; + case EM_DELETE_PREV_CHAR: case ED_DELETE_PREV_CHAR: - if (el->el_search.patlen > 1) + if (el->el_search.patlen > LEN) done++; else term_beep(el); @@ -287,17 +279,18 @@ ce_inc_search(EditLine *el, int dir) case 0027: /* ^W: Append word */ /* No can do if globbing characters in pattern */ - for (cp = &el->el_search.patbuf[1];; cp++) - if (cp >= &el->el_search.patbuf[el->el_search.patlen]) { + for (cp = &el->el_search.patbuf[LEN];; cp++) + if (cp >= &el->el_search.patbuf[ + el->el_search.patlen]) { el->el_line.cursor += - el->el_search.patlen - 1; + el->el_search.patlen - LEN - 1; cp = c__next_word(el->el_line.cursor, el->el_line.lastchar, 1, ce__isword); while (el->el_line.cursor < cp && *el->el_line.cursor != '\n') { - if (el->el_search.patlen > - EL_BUFSIZ - 3) { + if (el->el_search.patlen >= + EL_BUFSIZ - LEN) { term_beep(el); break; } @@ -339,13 +332,13 @@ ce_inc_search(EditLine *el, int dir) /* Can't search if unmatched '[' */ for (cp = &el->el_search.patbuf[el->el_search.patlen-1], ch = ']'; - cp > el->el_search.patbuf; + cp >= &el->el_search.patbuf[LEN]; cp--) if (*cp == '[' || *cp == ']') { ch = *cp; break; } - if (el->el_search.patlen > 1 && ch != '[') { + if (el->el_search.patlen > LEN && ch != '[') { if (redo && newdir == dir) { if (pchar == '?') { /* wrap around */ el->el_history.eventno = @@ -375,9 +368,8 @@ ce_inc_search(EditLine *el, int dir) '\0'; if (el->el_line.cursor < el->el_line.buffer || el->el_line.cursor > el->el_line.lastchar || - (ret = ce_search_line(el, - &el->el_search.patbuf[1], - newdir)) == CC_ERROR) { + (ret = ce_search_line(el, newdir)) + == CC_ERROR) { /* avoid c_setpat */ el->el_state.lastcmd = (el_action_t) newdir; @@ -390,11 +382,11 @@ ce_inc_search(EditLine *el, int dir) el->el_line.lastchar : el->el_line.buffer; (void) ce_search_line(el, - &el->el_search.patbuf[1], newdir); } } - el->el_search.patbuf[--el->el_search.patlen] = + el->el_search.patlen -= LEN; + el->el_search.patbuf[el->el_search.patlen] = '\0'; if (ret == CC_ERROR) { term_beep(el); @@ -453,9 +445,6 @@ cv_search(EditLine *el, int dir) #ifdef ANCHOR tmpbuf[0] = '.'; tmpbuf[1] = '*'; -#define LEN 2 -#else -#define LEN 0 #endif tmplen = LEN; @@ -521,24 +510,39 @@ cv_search(EditLine *el, int dir) * Look for a pattern inside a line */ protected el_action_t -ce_search_line(EditLine *el, char *pattern, int dir) +ce_search_line(EditLine *el, int dir) { - char *cp; + char *cp = el->el_line.cursor; + char *pattern = el->el_search.patbuf; + char oc, *ocp; +#ifdef ANCHOR + ocp = &pattern[1]; + oc = *ocp; + *ocp = '^'; +#else + ocp = pattern; + oc = *ocp; +#endif if (dir == ED_SEARCH_PREV_HISTORY) { - for (cp = el->el_line.cursor; cp >= el->el_line.buffer; cp--) - if (el_match(cp, pattern)) { + for (; cp >= el->el_line.buffer; cp--) { + if (el_match(cp, ocp)) { + *ocp = oc; el->el_line.cursor = cp; return (CC_NORM); } + } + *ocp = oc; return (CC_ERROR); } else { - for (cp = el->el_line.cursor; *cp != '\0' && - cp < el->el_line.limit; cp++) - if (el_match(cp, pattern)) { + for (; *cp != '\0' && cp < el->el_line.limit; cp++) { + if (el_match(cp, ocp)) { + *ocp = oc; el->el_line.cursor = cp; return (CC_NORM); } + } + *ocp = oc; return (CC_ERROR); } } diff --git a/cmd-line-utils/libedit/search.h b/cmd-line-utils/libedit/search.h index a7363072a4c..2aa8f985013 100644 --- a/cmd-line-utils/libedit/search.h +++ b/cmd-line-utils/libedit/search.h @@ -1,4 +1,4 @@ -/* $NetBSD: search.h,v 1.6 2002/11/15 14:32:34 christos Exp $ */ +/* $NetBSD: search.h,v 1.8 2003/10/18 23:27:36 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -63,7 +59,7 @@ protected int c_hmatch(EditLine *, const char *); protected void c_setpat(EditLine *); protected el_action_t ce_inc_search(EditLine *, int); protected el_action_t cv_search(EditLine *, int); -protected el_action_t ce_search_line(EditLine *, char *, int); +protected el_action_t ce_search_line(EditLine *, int); protected el_action_t cv_repeat_srch(EditLine *, int); protected el_action_t cv_csearch(EditLine *, int, int, int, int); diff --git a/cmd-line-utils/libedit/sig.c b/cmd-line-utils/libedit/sig.c index 3730067ed5f..8e70933d606 100644 --- a/cmd-line-utils/libedit/sig.c +++ b/cmd-line-utils/libedit/sig.c @@ -1,4 +1,4 @@ -/* $NetBSD: sig.c,v 1.10 2003/03/10 00:58:05 christos Exp $ */ +/* $NetBSD: sig.c,v 1.11 2003/08/07 16:44:33 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)sig.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: sig.c,v 1.10 2003/03/10 00:58:05 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * sig.c: Signal handling stuff. diff --git a/cmd-line-utils/libedit/sig.h b/cmd-line-utils/libedit/sig.h index 8effea8e121..0bf1fc37e39 100644 --- a/cmd-line-utils/libedit/sig.h +++ b/cmd-line-utils/libedit/sig.h @@ -1,4 +1,4 @@ -/* $NetBSD: sig.h,v 1.4 2003/03/10 00:58:05 christos Exp $ */ +/* $NetBSD: sig.h,v 1.5 2003/08/07 16:44:33 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/cmd-line-utils/libedit/strlcpy.c b/cmd-line-utils/libedit/strlcpy.c index 74317d99cd2..e38d6cf1c4b 100644 --- a/cmd-line-utils/libedit/strlcpy.c +++ b/cmd-line-utils/libedit/strlcpy.c @@ -1,28 +1,73 @@ +/* $NetBSD: strlcpy.c,v 1.14 2003/10/27 00:12:42 lukem Exp $ */ +/* $OpenBSD: strlcpy.c,v 1.7 2003/04/12 21:56:39 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include #include -#ifndef HAVE_STRLCPY -size_t strlcpy(char *dst, const char *src, size_t size) -{ - if(size) { - strncpy(dst, src, size-1); - dst[size-1] = '\0'; - } else { - dst[0] = '\0'; - } - return strlen(src); -} - -size_t strlcat(char *dst, const char *src, size_t size) -{ - int dl = strlen(dst); - int sz = size-dl-1; - - if(sz >= 0) { - strncat(dst, src, sz); - dst[sz] = '\0'; - } - - return dl+strlen(src); -} - +#ifdef _LIBC +# ifdef __weak_alias +__weak_alias(strlcpy, _strlcpy) +# endif +#endif + +#if !HAVE_STRLCPY +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +#ifdef _LIBC +_strlcpy(dst, src, siz) +#else +strlcpy(dst, src, siz) +#endif + char *dst; + const char *src; + size_t siz; +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + _DIAGASSERT(dst != NULL); + _DIAGASSERT(src != NULL); + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} #endif diff --git a/cmd-line-utils/libedit/sys.h b/cmd-line-utils/libedit/sys.h index a7477d2c5ba..c8a29dbfb05 100644 --- a/cmd-line-utils/libedit/sys.h +++ b/cmd-line-utils/libedit/sys.h @@ -1,4 +1,4 @@ -/* $NetBSD: sys.h,v 1.6 2003/03/10 00:57:38 christos Exp $ */ +/* $NetBSD: sys.h,v 1.9 2004/01/17 17:57:40 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -48,6 +44,28 @@ #include #endif +#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ < 8) +# define __attribute__(A) +#endif + +#ifndef __P +# define __P(x) x +#endif + +#ifndef _DIAGASSERT +# define _DIAGASSERT(x) +#endif + +#ifndef __BEGIN_DECLS +# ifdef __cplusplus +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +#endif + #ifndef public # define public /* Externally visible functions/variables */ #endif @@ -61,6 +79,10 @@ /* When we want to hide everything */ #endif +#ifndef HAVE_U_INT32_T +typedef unsigned int u_int32_t; +#endif + #ifndef _PTR_T # define _PTR_T typedef void *ptr_t; diff --git a/cmd-line-utils/libedit/term.c b/cmd-line-utils/libedit/term.c index c4ee0d30aab..b516d6753c3 100644 --- a/cmd-line-utils/libedit/term.c +++ b/cmd-line-utils/libedit/term.c @@ -1,4 +1,4 @@ -/* $NetBSD: term.c,v 1.35 2002/03/18 16:00:59 christos Exp $ */ +/* $NetBSD: term.c,v 1.40 2004/05/22 23:21:28 christos Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,14 +32,7 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)term.c 8.2 (Berkeley) 4/30/95"; -#else -__RCSID("$NetBSD: term.c,v 1.35 2002/03/18 16:00:59 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * term.c: Editor/termcap-curses interface @@ -55,24 +44,23 @@ __RCSID("$NetBSD: term.c,v 1.35 2002/03/18 16:00:59 christos Exp $"); #include #include #include -#ifdef HAVE_TERMCAP_H -#include -#endif + #ifdef HAVE_CURSES_H -#include -#endif -#ifdef HAVE_NCURSES_H -#include +# include +#elif HAVE_NCURSES_H +# include #endif -#include "el.h" - -#if !defined(HAVE_TERMCAP_H) && defined(HAVE_TERM_H) -#include +/* Solaris's term.h does horrid things. */ +#if (defined(HAVE_TERM_H) && !defined(_SUNOS)) +# include #endif + #include #include +#include "el.h" + /* * IMPORTANT NOTE: these routines are allowed to look at the current screen * and the current possition assuming that it is correct. If this is not @@ -356,6 +344,7 @@ term_init(EditLine *el) term_init_arrow(el); return (0); } + /* term_end(): * Clean up the terminal stuff */ @@ -372,6 +361,8 @@ term_end(EditLine *el) el->el_term.t_str = NULL; el_free((ptr_t) el->el_term.t_val); el->el_term.t_val = NULL; + el_free((ptr_t) el->el_term.t_fkey); + el->el_term.t_fkey = NULL; term_free_display(el); } @@ -648,7 +639,8 @@ mc_again: * from col 0 */ if (EL_CAN_TAB ? - (((unsigned int)-del) > (((unsigned int) where >> 3) + + ((unsigned int)-del > + (((unsigned int) where >> 3) + (where & 07))) : (-del > where)) { term__putc('\r'); /* do a CR */ @@ -876,6 +868,12 @@ term_clear_to_bottom(EditLine *el) } #endif +protected void +term_get(EditLine *el, const char **term) +{ + *term = el->el_term.t_name; +} + /* term_set(): * Read in the terminal capabilities from the requested terminal @@ -937,8 +935,11 @@ term_set(EditLine *el, const char *term) /* Get the size */ Val(T_co) = tgetnum("co"); Val(T_li) = tgetnum("li"); - for (t = tstr; t->name != NULL; t++) - term_alloc(el, t, tgetstr(t->name, &area)); + for (t = tstr; t->name != NULL; t++) { + /* XXX: some systems tgetstr needs non const */ + term_alloc(el, t, tgetstr(strchr(t->name, *t->name), + &area)); + } } if (Val(T_co) < 2) @@ -957,6 +958,7 @@ term_set(EditLine *el, const char *term) return (-1); (void) sigprocmask(SIG_SETMASK, &oset, NULL); term_bind_arrow(el); + el->el_term.t_name = term; return (i <= 0 ? -1 : 0); } @@ -1078,32 +1080,32 @@ term_reset_arrow(EditLine *el) static const char stOH[] = {033, 'O', 'H', '\0'}; static const char stOF[] = {033, 'O', 'F', '\0'}; - el_key_add(el, strA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); - el_key_add(el, strB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); - el_key_add(el, strC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); - el_key_add(el, strD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); - el_key_add(el, strH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); - el_key_add(el, strF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); - el_key_add(el, stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); - el_key_add(el, stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); - el_key_add(el, stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); - el_key_add(el, stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); - el_key_add(el, stOH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); - el_key_add(el, stOF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); + key_add(el, strA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); + key_add(el, strB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); + key_add(el, strC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); + key_add(el, strD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); + key_add(el, strH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); + key_add(el, strF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); + key_add(el, stOA, &arrow[A_K_UP].fun, arrow[A_K_UP].type); + key_add(el, stOB, &arrow[A_K_DN].fun, arrow[A_K_DN].type); + key_add(el, stOC, &arrow[A_K_RT].fun, arrow[A_K_RT].type); + key_add(el, stOD, &arrow[A_K_LT].fun, arrow[A_K_LT].type); + key_add(el, stOH, &arrow[A_K_HO].fun, arrow[A_K_HO].type); + key_add(el, stOF, &arrow[A_K_EN].fun, arrow[A_K_EN].type); if (el->el_map.type == MAP_VI) { - el_key_add(el, &strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); - el_key_add(el, &strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); - el_key_add(el, &strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); - el_key_add(el, &strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); - el_key_add(el, &strH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); - el_key_add(el, &strF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); - el_key_add(el, &stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); - el_key_add(el, &stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); - el_key_add(el, &stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); - el_key_add(el, &stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); - el_key_add(el, &stOH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); - el_key_add(el, &stOF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); + key_add(el, &strA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); + key_add(el, &strB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); + key_add(el, &strC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); + key_add(el, &strD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); + key_add(el, &strH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); + key_add(el, &strF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); + key_add(el, &stOA[1], &arrow[A_K_UP].fun, arrow[A_K_UP].type); + key_add(el, &stOB[1], &arrow[A_K_DN].fun, arrow[A_K_DN].type); + key_add(el, &stOC[1], &arrow[A_K_RT].fun, arrow[A_K_RT].type); + key_add(el, &stOD[1], &arrow[A_K_LT].fun, arrow[A_K_LT].type); + key_add(el, &stOH[1], &arrow[A_K_HO].fun, arrow[A_K_HO].type); + key_add(el, &stOF[1], &arrow[A_K_EN].fun, arrow[A_K_EN].type); } } @@ -1157,7 +1159,7 @@ term_print_arrow(EditLine *el, const char *name) for (i = 0; i < A_K_NKEYS; i++) if (*name == '\0' || strcmp(name, arrow[i].name) == 0) if (arrow[i].type != XK_NOD) - el_key_kprint(el, arrow[i].name, &arrow[i].fun, + key_kprint(el, arrow[i].name, &arrow[i].fun, arrow[i].type); } @@ -1198,20 +1200,20 @@ term_bind_arrow(EditLine *el) * unassigned key. */ if (arrow[i].type == XK_NOD) - el_key_clear(el, map, p); + key_clear(el, map, p); else { if (p[1] && (dmap[j] == map[j] || map[j] == ED_SEQUENCE_LEAD_IN)) { - el_key_add(el, p, &arrow[i].fun, + key_add(el, p, &arrow[i].fun, arrow[i].type); map[j] = ED_SEQUENCE_LEAD_IN; } else if (map[j] == ED_UNASSIGNED) { - el_key_clear(el, map, p); + key_clear(el, map, p); if (arrow[i].type == XK_CMD) map[j] = arrow[i].fun.cmd; else - el_key_add(el, p, &arrow[i].fun, - arrow[i].type); + key_add(el, p, &arrow[i].fun, + arrow[i].type); } } } @@ -1244,12 +1246,10 @@ term__flush(void) /* term_telltc(): * Print the current termcap characteristics */ -char *el_key__decode_str(const char *, char *, const char *); - protected int /*ARGSUSED*/ -term_telltc(EditLine *el, int argc __attribute__((unused)), - const char **argv __attribute__((unused))) +term_telltc(EditLine *el, int argc __attribute__((__unused__)), + const char **argv __attribute__((__unused__))) { const struct termcapstr *t; char **ts; @@ -1273,7 +1273,7 @@ term_telltc(EditLine *el, int argc __attribute__((unused)), (void) fprintf(el->el_outfile, "\t%25s (%s) == %s\n", t->long_name, t->name, *ts && **ts ? - el_key__decode_str(*ts, upbuf, "") : "(empty)"); + key__decode_str(*ts, upbuf, "") : "(empty)"); (void) fputc('\n', el->el_outfile); return (0); } @@ -1284,8 +1284,8 @@ term_telltc(EditLine *el, int argc __attribute__((unused)), */ protected int /*ARGSUSED*/ -term_settc(EditLine *el, int argc __attribute__((unused)), - const char **argv __attribute__((unused))) +term_settc(EditLine *el, int argc __attribute__((__unused__)), + const char **argv) { const struct termcapstr *ts; const struct termcapval *tv; @@ -1361,9 +1361,8 @@ term_settc(EditLine *el, int argc __attribute__((unused)), */ protected int /*ARGSUSED*/ -term_echotc(EditLine *el __attribute__((unused)), - int argc __attribute__((unused)), - const char **argv __attribute__((unused))) +term_echotc(EditLine *el, int argc __attribute__((__unused__)), + const char **argv) { char *cap, *scap, *ep; int arg_need, arg_cols, arg_rows; @@ -1422,7 +1421,7 @@ term_echotc(EditLine *el __attribute__((unused)), } (void) fprintf(el->el_outfile, fmtd, 0); #else - (void) fprintf(el->el_outfile, fmtd, el->el_tty.t_speed); + (void) fprintf(el->el_outfile, fmtd, (int)el->el_tty.t_speed); #endif return (0); } else if (strcmp(*argv, "rows") == 0 || strcmp(*argv, "lines") == 0) { @@ -1441,8 +1440,10 @@ term_echotc(EditLine *el __attribute__((unused)), scap = el->el_term.t_str[t - tstr]; break; } - if (t->name == NULL) - scap = tgetstr(*argv, &area); + if (t->name == NULL) { + /* XXX: some systems tgetstr needs non const */ + scap = tgetstr(strchr(*argv, **argv), &area); + } if (!scap || scap[0] == '\0') { if (!silent) (void) fprintf(el->el_errfile, diff --git a/cmd-line-utils/libedit/tokenizer.c b/cmd-line-utils/libedit/tokenizer.c index f6892d9954c..561b41740f8 100644 --- a/cmd-line-utils/libedit/tokenizer.c +++ b/cmd-line-utils/libedit/tokenizer.c @@ -1,4 +1,4 @@ -/* $NetBSD: tokenizer.c,v 1.11 2002/10/27 20:24:29 christos Exp $ */ +/* $NetBSD: tokenizer.c,v 1.14 2003/12/05 13:37:48 lukem Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,21 +32,14 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)tokenizer.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: tokenizer.c,v 1.11 2002/10/27 20:24:29 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * tokenize.c: Bourne shell like tokenizer */ #include #include -#include "tokenizer.h" +#include "histedit.h" typedef enum { Q_none, Q_single, Q_double, Q_one, Q_doubleone @@ -64,6 +53,7 @@ typedef enum { #define WINCR 20 #define AINCR 10 +#define tok_strdup(a) strdup(a) #define tok_malloc(a) malloc(a) #define tok_free(a) free(a) #define tok_realloc(a, b) realloc(a, b) @@ -111,7 +101,7 @@ tok_init(const char *ifs) if (tok == NULL) return NULL; - tok->ifs = strdup(ifs ? ifs : IFS); + tok->ifs = tok_strdup(ifs ? ifs : IFS); if (tok->ifs == NULL) { tok_free((ptr_t)tok); return NULL; @@ -173,21 +163,39 @@ tok_end(Tokenizer *tok) /* tok_line(): - * Bourne shell like tokenizing - * Return: - * -1: Internal error - * 3: Quoted return - * 2: Unmatched double quote - * 1: Unmatched single quote - * 0: Ok + * Bourne shell (sh(1)) like tokenizing + * Arguments: + * tok current tokenizer state (setup with tok_init()) + * line line to parse + * Returns: + * -1 Internal error + * 3 Quoted return + * 2 Unmatched double quote + * 1 Unmatched single quote + * 0 Ok + * Modifies (if return value is 0): + * argc number of arguments + * argv argument array + * cursorc if !NULL, argv element containing cursor + * cursorv if !NULL, offset in argv[cursorc] of cursor */ public int -tok_line(Tokenizer *tok, const char *line, int *argc, const char ***argv) +tok_line(Tokenizer *tok, const LineInfo *line, + int *argc, const char ***argv, int *cursorc, int *cursoro) { const char *ptr; + int cc, co; - for (;;) { - switch (*(ptr = line++)) { + cc = co = -1; + ptr = line->buffer; + for (ptr = line->buffer; ;ptr++) { + if (ptr >= line->lastchar) + ptr = ""; + if (ptr == line->cursor) { + cc = tok->argc; + co = tok->wptr - tok->wstart; + } + switch (*ptr) { case '\'': tok->flags |= TOK_KEEP; tok->flags &= ~TOK_EAT; @@ -286,10 +294,7 @@ tok_line(Tokenizer *tok, const char *line, int *argc, const char ***argv) tok->flags &= ~TOK_EAT; switch (tok->quote) { case Q_none: - tok_finish(tok); - *argv = (const char **)tok->argv; - *argc = tok->argc; - return (0); + goto tok_line_outok; case Q_single: case Q_double: @@ -319,10 +324,7 @@ tok_line(Tokenizer *tok, const char *line, int *argc, const char ***argv) tok->flags &= ~TOK_EAT; return (3); } - tok_finish(tok); - *argv = (const char **)tok->argv; - *argc = tok->argc; - return (0); + goto tok_line_outok; case Q_single: return (1); @@ -407,4 +409,32 @@ tok_line(Tokenizer *tok, const char *line, int *argc, const char ***argv) tok->argv = p; } } + tok_line_outok: + if (cc == -1 && co == -1) { + cc = tok->argc; + co = tok->wptr - tok->wstart; + } + if (cursorc != NULL) + *cursorc = cc; + if (cursoro != NULL) + *cursoro = co; + tok_finish(tok); + *argv = (const char **)tok->argv; + *argc = tok->argc; + return (0); +} + +/* tok_str(): + * Simpler version of tok_line, taking a NUL terminated line + * and splitting into words, ignoring cursor state. + */ +public int +tok_str(Tokenizer *tok, const char *line, int *argc, const char ***argv) +{ + LineInfo li; + + memset(&li, 0, sizeof(li)); + li.buffer = line; + li.cursor = li.lastchar = strchr(line, '\0'); + return (tok_line(tok, &li, argc, argv, NULL, NULL)); } diff --git a/cmd-line-utils/libedit/tty.c b/cmd-line-utils/libedit/tty.c index fe81762fb82..6f73fb4f9e7 100644 --- a/cmd-line-utils/libedit/tty.c +++ b/cmd-line-utils/libedit/tty.c @@ -1,4 +1,4 @@ -/* $NetBSD: tty.c,v 1.16 2002/03/18 16:01:01 christos Exp $ */ +/* $NetBSD: tty.c,v 1.21 2004/08/13 12:10:39 mycroft Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,18 +32,12 @@ * SUCH DAMAGE. */ -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: tty.c,v 1.16 2002/03/18 16:01:01 christos Exp $"); -#endif -#endif /* not lint && not SCCSID */ +#include /* * tty.c: tty interface stuff */ +#include #include "tty.h" #include "el.h" @@ -124,11 +114,11 @@ private const ttychar_t ttychar = { private const ttymap_t tty_map[] = { #ifdef VERASE {C_ERASE, VERASE, - {ED_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, + {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, #endif /* VERASE */ #ifdef VERASE2 {C_ERASE2, VERASE2, - {ED_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, + {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, #endif /* VERASE2 */ #ifdef VKILL {C_KILL, VKILL, @@ -455,6 +445,7 @@ private const ttymodes_t ttymodes[] = { #define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8) #define tty__cooked_mode(td) ((td)->c_lflag & ICANON) +private int tty__getcharindex(int); private void tty__getchar(struct termios *, unsigned char *); private void tty__setchar(struct termios *, unsigned char *); private speed_t tty__getspeed(struct termios *); @@ -568,7 +559,7 @@ tty_init(EditLine *el) */ protected void /*ARGSUSED*/ -tty_end(EditLine *el __attribute__((unused))) +tty_end(EditLine *el __attribute__((__unused__))) { /* XXX: Maybe reset to an initial state? */ @@ -588,6 +579,113 @@ tty__getspeed(struct termios *td) return (spd); } +/* tty__getspeed(): + * Return the index of the asked char in the c_cc array + */ +private int +tty__getcharindex(int i) +{ + switch (i) { +#ifdef VINTR + case C_INTR: + return VINTR; +#endif /* VINTR */ +#ifdef VQUIT + case C_QUIT: + return VQUIT; +#endif /* VQUIT */ +#ifdef VERASE + case C_ERASE: + return VERASE; +#endif /* VERASE */ +#ifdef VKILL + case C_KILL: + return VKILL; +#endif /* VKILL */ +#ifdef VEOF + case C_EOF: + return VEOF; +#endif /* VEOF */ +#ifdef VEOL + case C_EOL: + return VEOL; +#endif /* VEOL */ +#ifdef VEOL2 + case C_EOL2: + return VEOL2; +#endif /* VEOL2 */ +#ifdef VSWTCH + case C_SWTCH: + return VSWTCH; +#endif /* VSWTCH */ +#ifdef VDSWTCH + case C_DSWTCH: + return VDSWTCH; +#endif /* VDSWTCH */ +#ifdef VERASE2 + case C_ERASE2: + return VERASE2; +#endif /* VERASE2 */ +#ifdef VSTART + case C_START: + return VSTART; +#endif /* VSTART */ +#ifdef VSTOP + case C_STOP: + return VSTOP; +#endif /* VSTOP */ +#ifdef VWERASE + case C_WERASE: + return VWERASE; +#endif /* VWERASE */ +#ifdef VSUSP + case C_SUSP: + return VSUSP; +#endif /* VSUSP */ +#ifdef VDSUSP + case C_DSUSP: + return VDSUSP; +#endif /* VDSUSP */ +#ifdef VREPRINT + case C_REPRINT: + return VREPRINT; +#endif /* VREPRINT */ +#ifdef VDISCARD + case C_DISCARD: + return VDISCARD; +#endif /* VDISCARD */ +#ifdef VLNEXT + case C_LNEXT: + return VLNEXT; +#endif /* VLNEXT */ +#ifdef VSTATUS + case C_STATUS: + return VSTATUS; +#endif /* VSTATUS */ +#ifdef VPAGE + case C_PAGE: + return VPAGE; +#endif /* VPAGE */ +#ifdef VPGOFF + case C_PGOFF: + return VPGOFF; +#endif /* VPGOFF */ +#ifdef VKILL2 + case C_KILL2: + return VKILL2; +#endif /* KILL2 */ +#ifdef VMIN + case C_MIN: + return VMIN; +#endif /* VMIN */ +#ifdef VTIME + case C_TIME: + return VTIME; +#endif /* VTIME */ + default: + return -1; + } +} /* tty__getchar(): * Get the tty characters @@ -784,15 +882,15 @@ tty_bind_char(EditLine *el, int force) if (new[0] == old[0] && !force) continue; /* Put the old default binding back, and set the new binding */ - el_key_clear(el, map, (char *)old); + key_clear(el, map, (char *)old); map[old[0]] = dmap[old[0]]; - el_key_clear(el, map, (char *)new); + key_clear(el, map, (char *)new); /* MAP_VI == 1, MAP_EMACS == 0... */ map[new[0]] = tp->bind[el->el_map.type]; if (dalt) { - el_key_clear(el, alt, (char *)old); + key_clear(el, alt, (char *)old); alt[old[0]] = dalt[old[0]]; - el_key_clear(el, alt, (char *)new); + key_clear(el, alt, (char *)new); alt[new[0]] = tp->bind[el->el_map.type + 1]; } } @@ -1041,13 +1139,14 @@ tty_noquotemode(EditLine *el) */ protected int /*ARGSUSED*/ -tty_stty(EditLine *el, int argc __attribute__((unused)), const char **argv) +tty_stty(EditLine *el, int argc __attribute__((__unused__)), const char **argv) { const ttymodes_t *m; char x; int aflag = 0; const char *s, *d; const char *name; + struct termios *tios = &el->el_tty.t_ex; int z = EX_IO; if (argv == NULL) @@ -1062,14 +1161,17 @@ tty_stty(EditLine *el, int argc __attribute__((unused)), const char **argv) break; case 'd': argv++; + tios = &el->el_tty.t_ed; z = ED_IO; break; case 'x': argv++; + tios = &el->el_tty.t_ex; z = EX_IO; break; case 'q': argv++; + tios = &el->el_tty.t_ts; z = QU_IO; break; default: @@ -1119,6 +1221,7 @@ tty_stty(EditLine *el, int argc __attribute__((unused)), const char **argv) return (0); } while (argv && (s = *argv++)) { + char *p; switch (*s) { case '+': case '-': @@ -1129,8 +1232,11 @@ tty_stty(EditLine *el, int argc __attribute__((unused)), const char **argv) break; } d = s; + if ((p = strchr(s, '=')) != NULL) + *p++ = '\0'; for (m = ttymodes; m->m_name; m++) - if (strcmp(m->m_name, d) == 0) + if (strcmp(m->m_name, d) == 0 && + (p == NULL || m->m_type == MD_CHAR)) break; if (!m->m_name) { @@ -1138,6 +1244,16 @@ tty_stty(EditLine *el, int argc __attribute__((unused)), const char **argv) "%s: Invalid argument `%s'.\n", name, d); return (-1); } + if (p) { + int c = ffs((int)m->m_value); + int v = *p ? parse__escape((const char **const) &p) : + el->el_tty.t_vdisable; + assert(c-- != 0); + c = tty__getcharindex(c); + assert(c != -1); + tios->c_cc[c] = v; + continue; + } switch (x) { case '+': el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value; diff --git a/cmd-line-utils/libedit/tty.h b/cmd-line-utils/libedit/tty.h index e9597fceb2b..cc7c4ad8c66 100644 --- a/cmd-line-utils/libedit/tty.h +++ b/cmd-line-utils/libedit/tty.h @@ -1,4 +1,4 @@ -/* $NetBSD: tty.h,v 1.9 2002/03/18 16:01:01 christos Exp $ */ +/* $NetBSD: tty.h,v 1.10 2003/08/07 16:44:34 agc Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * diff --git a/cmd-line-utils/libedit/unvis.c b/cmd-line-utils/libedit/unvis.c new file mode 100644 index 00000000000..ffa8ac4251c --- /dev/null +++ b/cmd-line-utils/libedit/unvis.c @@ -0,0 +1,311 @@ +/* $NetBSD: unvis.c,v 1.24 2003/08/07 16:42:59 agc Exp $ */ + +/*- + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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 + +#define __LIBC12_SOURCE__ + +#include + +#include +#include +#include +#include + +#ifdef __weak_alias +__weak_alias(strunvis,_strunvis) +__weak_alias(unvis,_unvis) +#endif + +#ifdef __warn_references +__warn_references(unvis, + "warning: reference to compatibility unvis(); include for correct reference") +#endif + +#if !HAVE_VIS +/* + * decode driven by state machine + */ +#define S_GROUND 0 /* haven't seen escape char */ +#define S_START 1 /* start decoding special sequence */ +#define S_META 2 /* metachar started (M) */ +#define S_META1 3 /* metachar more, regular char (-) */ +#define S_CTRL 4 /* control char started (^) */ +#define S_OCTAL2 5 /* octal digit 2 */ +#define S_OCTAL3 6 /* octal digit 3 */ +#define S_HEX1 7 /* hex digit */ +#define S_HEX2 8 /* hex digit 2 */ + +#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') +#define xtod(c) (isdigit(c) ? (c - '0') : ((tolower(c) - 'a') + 10)) + +int +unvis(cp, c, astate, flag) + char *cp; + int c; + int *astate, flag; +{ + return __unvis13(cp, (int)c, astate, flag); +} + +/* + * unvis - decode characters previously encoded by vis + */ +int +__unvis13(cp, c, astate, flag) + char *cp; + int c; + int *astate, flag; +{ + + _DIAGASSERT(cp != NULL); + _DIAGASSERT(astate != NULL); + + if (flag & UNVIS_END) { + if (*astate == S_OCTAL2 || *astate == S_OCTAL3 + || *astate == S_HEX2) { + *astate = S_GROUND; + return (UNVIS_VALID); + } + return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD); + } + + switch (*astate) { + + case S_GROUND: + *cp = 0; + if (c == '\\') { + *astate = S_START; + return (0); + } + if ((flag & VIS_HTTPSTYLE) && c == '%') { + *astate = S_HEX1; + return (0); + } + *cp = c; + return (UNVIS_VALID); + + case S_START: + switch(c) { + case '\\': + *cp = c; + *astate = S_GROUND; + return (UNVIS_VALID); + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + *cp = (c - '0'); + *astate = S_OCTAL2; + return (0); + case 'M': + *cp = (char)0200; + *astate = S_META; + return (0); + case '^': + *astate = S_CTRL; + return (0); + case 'n': + *cp = '\n'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'r': + *cp = '\r'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'b': + *cp = '\b'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'a': + *cp = '\007'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'v': + *cp = '\v'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 't': + *cp = '\t'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'f': + *cp = '\f'; + *astate = S_GROUND; + return (UNVIS_VALID); + case 's': + *cp = ' '; + *astate = S_GROUND; + return (UNVIS_VALID); + case 'E': + *cp = '\033'; + *astate = S_GROUND; + return (UNVIS_VALID); + case '\n': + /* + * hidden newline + */ + *astate = S_GROUND; + return (UNVIS_NOCHAR); + case '$': + /* + * hidden marker + */ + *astate = S_GROUND; + return (UNVIS_NOCHAR); + } + *astate = S_GROUND; + return (UNVIS_SYNBAD); + + case S_META: + if (c == '-') + *astate = S_META1; + else if (c == '^') + *astate = S_CTRL; + else { + *astate = S_GROUND; + return (UNVIS_SYNBAD); + } + return (0); + + case S_META1: + *astate = S_GROUND; + *cp |= c; + return (UNVIS_VALID); + + case S_CTRL: + if (c == '?') + *cp |= 0177; + else + *cp |= c & 037; + *astate = S_GROUND; + return (UNVIS_VALID); + + case S_OCTAL2: /* second possible octal digit */ + if (isoctal(c)) { + /* + * yes - and maybe a third + */ + *cp = (*cp << 3) + (c - '0'); + *astate = S_OCTAL3; + return (0); + } + /* + * no - done with current sequence, push back passed char + */ + *astate = S_GROUND; + return (UNVIS_VALIDPUSH); + + case S_OCTAL3: /* third possible octal digit */ + *astate = S_GROUND; + if (isoctal(c)) { + *cp = (*cp << 3) + (c - '0'); + return (UNVIS_VALID); + } + /* + * we were done, push back passed char + */ + return (UNVIS_VALIDPUSH); + case S_HEX1: + if (isxdigit(c)) { + *cp = xtod(c); + *astate = S_HEX2; + return (0); + } + /* + * no - done with current sequence, push back passed char + */ + *astate = S_GROUND; + return (UNVIS_VALIDPUSH); + case S_HEX2: + *astate = S_GROUND; + if (isxdigit(c)) { + *cp = xtod(c) | (*cp << 4); + return (UNVIS_VALID); + } + return (UNVIS_VALIDPUSH); + default: + /* + * decoder in unknown state - (probably uninitialized) + */ + *astate = S_GROUND; + return (UNVIS_SYNBAD); + } +} + +/* + * strunvis - decode src into dst + * + * Number of chars decoded into dst is returned, -1 on error. + * Dst is null terminated. + */ + +int +strunvisx(dst, src, flag) + char *dst; + const char *src; + int flag; +{ + char c; + char *start = dst; + int state = 0; + + _DIAGASSERT(src != NULL); + _DIAGASSERT(dst != NULL); + + while ((c = *src++) != '\0') { + again: + switch (__unvis13(dst, c, &state, flag)) { + case UNVIS_VALID: + dst++; + break; + case UNVIS_VALIDPUSH: + dst++; + goto again; + case 0: + case UNVIS_NOCHAR: + break; + default: + return (-1); + } + } + if (__unvis13(dst, c, &state, UNVIS_END) == UNVIS_VALID) + dst++; + *dst = '\0'; + return (dst - start); +} + +int +strunvis(dst, src) + char *dst; + const char *src; +{ + return strunvisx(dst, src, 0); +} +#endif diff --git a/cmd-line-utils/libedit/vi.c b/cmd-line-utils/libedit/vi.c index 5380872cf65..4a0352859dd 100644 --- a/cmd-line-utils/libedit/vi.c +++ b/cmd-line-utils/libedit/vi.c @@ -1,4 +1,4 @@ -/* $NetBSD: vi.c,v 1.16 2003/03/10 11:09:25 dsl Exp $ */ +/* $NetBSD: vi.c,v 1.20 2004/08/13 12:10:39 mycroft Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -15,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -36,18 +32,11 @@ * SUCH DAMAGE. */ -#include "config.h" +#include #include #include #include -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)vi.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: vi.c,v 1.16 2003/03/10 11:09:25 dsl Exp $"); -#endif -#endif /* not lint && not SCCSID */ /* * vi.c: Vi mode commands. @@ -123,7 +112,7 @@ cv_paste(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_paste_next(EditLine *el, int c __attribute__((unused))) +vi_paste_next(EditLine *el, int c __attribute__((__unused__))) { return (cv_paste(el, 0)); @@ -136,7 +125,7 @@ vi_paste_next(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_paste_prev(EditLine *el, int c __attribute__((unused))) +vi_paste_prev(EditLine *el, int c __attribute__((__unused__))) { return (cv_paste(el, 1)); @@ -149,7 +138,7 @@ vi_paste_prev(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_prev_big_word(EditLine *el, int c __attribute__((unused))) +vi_prev_big_word(EditLine *el, int c) { if (el->el_line.cursor == el->el_line.buffer) @@ -174,7 +163,7 @@ vi_prev_big_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_prev_word(EditLine *el, int c __attribute__((unused))) +vi_prev_word(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.buffer) @@ -199,7 +188,7 @@ vi_prev_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_next_big_word(EditLine *el, int c __attribute__((unused))) +vi_next_big_word(EditLine *el, int c) { if (el->el_line.cursor >= el->el_line.lastchar - 1) @@ -223,7 +212,7 @@ vi_next_big_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_next_word(EditLine *el, int c __attribute__((unused))) +vi_next_word(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor >= el->el_line.lastchar - 1) @@ -278,7 +267,7 @@ vi_change_case(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_change_meta(EditLine *el, int c __attribute__((unused))) +vi_change_meta(EditLine *el, int c __attribute__((__unused__))) { /* @@ -295,7 +284,7 @@ vi_change_meta(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_insert_at_bol(EditLine *el, int c __attribute__((unused))) +vi_insert_at_bol(EditLine *el, int c __attribute__((__unused__))) { el->el_line.cursor = el->el_line.buffer; @@ -311,7 +300,7 @@ vi_insert_at_bol(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_replace_char(EditLine *el, int c __attribute__((unused))) +vi_replace_char(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor >= el->el_line.lastchar) @@ -330,7 +319,7 @@ vi_replace_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_replace_mode(EditLine *el, int c __attribute__((unused))) +vi_replace_mode(EditLine *el, int c __attribute__((__unused__))) { el->el_map.current = el->el_map.key; @@ -346,7 +335,7 @@ vi_replace_mode(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_substitute_char(EditLine *el, int c __attribute__((unused))) +vi_substitute_char(EditLine *el, int c __attribute__((__unused__))) { c_delafter(el, el->el_state.argument); @@ -361,7 +350,7 @@ vi_substitute_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_substitute_line(EditLine *el, int c __attribute__((unused))) +vi_substitute_line(EditLine *el, int c __attribute__((__unused__))) { cv_undo(el); @@ -379,7 +368,7 @@ vi_substitute_line(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_change_to_eol(EditLine *el, int c __attribute__((unused))) +vi_change_to_eol(EditLine *el, int c __attribute__((__unused__))) { cv_undo(el); @@ -397,7 +386,7 @@ vi_change_to_eol(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_insert(EditLine *el, int c __attribute__((unused))) +vi_insert(EditLine *el, int c __attribute__((__unused__))) { el->el_map.current = el->el_map.key; @@ -412,7 +401,7 @@ vi_insert(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_add(EditLine *el, int c __attribute__((unused))) +vi_add(EditLine *el, int c __attribute__((__unused__))) { int ret; @@ -437,7 +426,7 @@ vi_add(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_add_at_eol(EditLine *el, int c __attribute__((unused))) +vi_add_at_eol(EditLine *el, int c __attribute__((__unused__))) { el->el_map.current = el->el_map.key; @@ -453,7 +442,7 @@ vi_add_at_eol(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_delete_meta(EditLine *el, int c __attribute__((unused))) +vi_delete_meta(EditLine *el, int c __attribute__((__unused__))) { return (cv_action(el, DELETE)); @@ -466,7 +455,7 @@ vi_delete_meta(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_end_big_word(EditLine *el, int c __attribute__((unused))) +vi_end_big_word(EditLine *el, int c) { if (el->el_line.cursor == el->el_line.lastchar) @@ -490,7 +479,7 @@ vi_end_big_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_end_word(EditLine *el, int c __attribute__((unused))) +vi_end_word(EditLine *el, int c __attribute__((__unused__))) { if (el->el_line.cursor == el->el_line.lastchar) @@ -514,7 +503,7 @@ vi_end_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_undo(EditLine *el, int c __attribute__((unused))) +vi_undo(EditLine *el, int c __attribute__((__unused__))) { c_undo_t un = el->el_chared.c_undo; @@ -540,7 +529,7 @@ vi_undo(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_command_mode(EditLine *el, int c __attribute__((unused))) +vi_command_mode(EditLine *el, int c __attribute__((__unused__))) { /* [Esc] cancels pending action */ @@ -585,20 +574,14 @@ vi_zero(EditLine *el, int c) */ protected el_action_t /*ARGSUSED*/ -vi_delete_prev_char(EditLine *el, int c __attribute__((unused))) +vi_delete_prev_char(EditLine *el, int c __attribute__((__unused__))) { - char *cp; - cp = el->el_line.cursor; - if (cp <= el->el_line.buffer) + if (el->el_line.cursor <= el->el_line.buffer) return (CC_ERROR); - /* do the delete here so we dont mess up the undo and paste buffers */ - el->el_line.cursor = --cp; - for (; cp < el->el_line.lastchar; cp++) - cp[0] = cp[1]; - el->el_line.lastchar = cp - 1; - + c_delbefore1(el); + el->el_line.cursor--; return (CC_REFRESH); } @@ -609,23 +592,35 @@ vi_delete_prev_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_list_or_eof(EditLine *el, int c __attribute__((unused))) +vi_list_or_eof(EditLine *el, int c __attribute__((__unused__))) { -#ifdef notyet - if (el->el_line.cursor == el->el_line.lastchar && - el->el_line.cursor == el->el_line.buffer) { -#endif - term_overwrite(el, STReof, 4); /* then do a EOF */ - term__flush(); - return (CC_EOF); -#ifdef notyet + if (el->el_line.cursor == el->el_line.lastchar) { + if (el->el_line.cursor == el->el_line.buffer) { + term_overwrite(el, STReof, 4); /* then do a EOF */ + term__flush(); + return (CC_EOF); + } else { + /* + * Here we could list completions, but it is an + * error right now + */ + term_beep(el); + return (CC_ERROR); + } } else { +#ifdef notyet re_goto_bottom(el); *el->el_line.lastchar = '\0'; /* just in case */ return (CC_LIST_CHOICES); - } +#else + /* + * Just complain for now. + */ + term_beep(el); + return (CC_ERROR); #endif + } } @@ -635,7 +630,7 @@ vi_list_or_eof(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_kill_line_prev(EditLine *el, int c __attribute__((unused))) +vi_kill_line_prev(EditLine *el, int c __attribute__((__unused__))) { char *kp, *cp; @@ -656,7 +651,7 @@ vi_kill_line_prev(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_search_prev(EditLine *el, int c __attribute__((unused))) +vi_search_prev(EditLine *el, int c __attribute__((__unused__))) { return (cv_search(el, ED_SEARCH_PREV_HISTORY)); @@ -669,7 +664,7 @@ vi_search_prev(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_search_next(EditLine *el, int c __attribute__((unused))) +vi_search_next(EditLine *el, int c __attribute__((__unused__))) { return (cv_search(el, ED_SEARCH_NEXT_HISTORY)); @@ -682,7 +677,7 @@ vi_search_next(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_repeat_search_next(EditLine *el, int c __attribute__((unused))) +vi_repeat_search_next(EditLine *el, int c __attribute__((__unused__))) { if (el->el_search.patlen == 0) @@ -698,7 +693,7 @@ vi_repeat_search_next(EditLine *el, int c __attribute__((unused))) */ /*ARGSUSED*/ protected el_action_t -vi_repeat_search_prev(EditLine *el, int c __attribute__((unused))) +vi_repeat_search_prev(EditLine *el, int c __attribute__((__unused__))) { if (el->el_search.patlen == 0) @@ -716,7 +711,7 @@ vi_repeat_search_prev(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_next_char(EditLine *el, int c __attribute__((unused))) +vi_next_char(EditLine *el, int c __attribute__((__unused__))) { return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 0); } @@ -728,7 +723,7 @@ vi_next_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_prev_char(EditLine *el, int c __attribute__((unused))) +vi_prev_char(EditLine *el, int c __attribute__((__unused__))) { return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 0); } @@ -740,7 +735,7 @@ vi_prev_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_to_next_char(EditLine *el, int c __attribute__((unused))) +vi_to_next_char(EditLine *el, int c __attribute__((__unused__))) { return cv_csearch(el, CHAR_FWD, -1, el->el_state.argument, 1); } @@ -752,7 +747,7 @@ vi_to_next_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_to_prev_char(EditLine *el, int c __attribute__((unused))) +vi_to_prev_char(EditLine *el, int c __attribute__((__unused__))) { return cv_csearch(el, CHAR_BACK, -1, el->el_state.argument, 1); } @@ -764,7 +759,7 @@ vi_to_prev_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_repeat_next_char(EditLine *el, int c __attribute__((unused))) +vi_repeat_next_char(EditLine *el, int c __attribute__((__unused__))) { return cv_csearch(el, el->el_search.chadir, el->el_search.chacha, @@ -778,7 +773,7 @@ vi_repeat_next_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_repeat_prev_char(EditLine *el, int c __attribute__((unused))) +vi_repeat_prev_char(EditLine *el, int c __attribute__((__unused__))) { el_action_t r; int dir = el->el_search.chadir; @@ -796,7 +791,7 @@ vi_repeat_prev_char(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_match(EditLine *el, int c __attribute__((unused))) +vi_match(EditLine *el, int c) { const char match_chars[] = "()[]{}"; char *cp; @@ -843,7 +838,7 @@ vi_match(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_undo_line(EditLine *el, int c __attribute__((unused))) +vi_undo_line(EditLine *el, int c) { cv_undo(el); @@ -857,7 +852,7 @@ vi_undo_line(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_to_column(EditLine *el, int c __attribute__((unused))) +vi_to_column(EditLine *el, int c) { el->el_line.cursor = el->el_line.buffer; @@ -871,7 +866,7 @@ vi_to_column(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_yank_end(EditLine *el, int c __attribute__((unused))) +vi_yank_end(EditLine *el, int c) { cv_yank(el, el->el_line.cursor, @@ -885,7 +880,7 @@ vi_yank_end(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_yank(EditLine *el, int c __attribute__((unused))) +vi_yank(EditLine *el, int c) { return cv_action(el, YANK); @@ -897,7 +892,7 @@ vi_yank(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_comment_out(EditLine *el, int c __attribute__((unused))) +vi_comment_out(EditLine *el, int c) { el->el_line.cursor = el->el_line.buffer; @@ -915,7 +910,7 @@ vi_comment_out(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_alias(EditLine *el __attribute__((unused)), int c __attribute__((unused))) +vi_alias(EditLine *el, int c) { #ifdef __weak_extern char alias_name[3]; @@ -947,7 +942,7 @@ vi_alias(EditLine *el __attribute__((unused)), int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_to_history_line(EditLine *el, int c __attribute__((unused))) +vi_to_history_line(EditLine *el, int c) { int sv_event_no = el->el_history.eventno; el_action_t rval; @@ -992,7 +987,7 @@ vi_to_history_line(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_histedit(EditLine *el, int c __attribute__((unused))) +vi_histedit(EditLine *el, int c) { int fd; pid_t pid; @@ -1048,7 +1043,7 @@ vi_histedit(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_history_word(EditLine *el, int c __attribute__((unused))) +vi_history_word(EditLine *el, int c) { const char *wp = HIST_FIRST(el); const char *wep, *wsp; @@ -1097,7 +1092,7 @@ vi_history_word(EditLine *el, int c __attribute__((unused))) */ protected el_action_t /*ARGSUSED*/ -vi_redo(EditLine *el, int c __attribute__((unused))) +vi_redo(EditLine *el, int c) { c_redo_t *r = &el->el_chared.c_redo; diff --git a/cmd-line-utils/libedit/vis.c b/cmd-line-utils/libedit/vis.c new file mode 100644 index 00000000000..127d28733a8 --- /dev/null +++ b/cmd-line-utils/libedit/vis.c @@ -0,0 +1,392 @@ +/* $NetBSD: vis.c,v 1.27 2004/02/26 23:01:15 enami Exp $ */ + +/*- + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. + */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. + */ + +/* AIX requires this to be the first thing in the file. */ +#if defined (_AIX) && !defined (__GNUC__) + #pragma alloca +#endif + +#include + +#ifdef __GNUC__ +# undef alloca +# define alloca(n) __builtin_alloca (n) +#else +# ifdef HAVE_ALLOCA_H +# include +# else +# ifndef _AIX +extern char *alloca (); +# endif +# endif +#endif + +#include + +#include +#include +#include + +#ifdef __weak_alias +__weak_alias(strsvis,_strsvis) +__weak_alias(strsvisx,_strsvisx) +__weak_alias(strvis,_strvis) +__weak_alias(strvisx,_strvisx) +__weak_alias(svis,_svis) +__weak_alias(vis,_vis) +#endif + +#if !HAVE_VIS || !HAVE_SVIS +#include +#include +#include +#include + +#undef BELL +#define BELL '\a' + +#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7') +#define iswhite(c) (c == ' ' || c == '\t' || c == '\n') +#define issafe(c) (c == '\b' || c == BELL || c == '\r') +#define xtoa(c) "0123456789abcdef"[c] + +#define MAXEXTRAS 5 + + +#define MAKEEXTRALIST(flag, extra, orig) \ +do { \ + const char *o = orig; \ + char *e; \ + while (*o++) \ + continue; \ + extra = alloca((size_t)((o - orig) + MAXEXTRAS)); \ + for (o = orig, e = extra; (*e++ = *o++) != '\0';) \ + continue; \ + e--; \ + if (flag & VIS_SP) *e++ = ' '; \ + if (flag & VIS_TAB) *e++ = '\t'; \ + if (flag & VIS_NL) *e++ = '\n'; \ + if ((flag & VIS_NOSLASH) == 0) *e++ = '\\'; \ + *e = '\0'; \ +} while (/*CONSTCOND*/0) + + +/* + * This is HVIS, the macro of vis used to HTTP style (RFC 1808) + */ +#define HVIS(dst, c, flag, nextc, extra) \ +do \ + if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL) { \ + *dst++ = '%'; \ + *dst++ = xtoa(((unsigned int)c >> 4) & 0xf); \ + *dst++ = xtoa((unsigned int)c & 0xf); \ + } else { \ + SVIS(dst, c, flag, nextc, extra); \ + } \ +while (/*CONSTCOND*/0) + +/* + * This is SVIS, the central macro of vis. + * dst: Pointer to the destination buffer + * c: Character to encode + * flag: Flag word + * nextc: The character following 'c' + * extra: Pointer to the list of extra characters to be + * backslash-protected. + */ +#define SVIS(dst, c, flag, nextc, extra) \ +do { \ + int isextra; \ + isextra = strchr(extra, c) != NULL; \ + if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) || \ + ((flag & VIS_SAFE) && issafe(c)))) { \ + *dst++ = c; \ + break; \ + } \ + if (flag & VIS_CSTYLE) { \ + switch (c) { \ + case '\n': \ + *dst++ = '\\'; *dst++ = 'n'; \ + continue; \ + case '\r': \ + *dst++ = '\\'; *dst++ = 'r'; \ + continue; \ + case '\b': \ + *dst++ = '\\'; *dst++ = 'b'; \ + continue; \ + case BELL: \ + *dst++ = '\\'; *dst++ = 'a'; \ + continue; \ + case '\v': \ + *dst++ = '\\'; *dst++ = 'v'; \ + continue; \ + case '\t': \ + *dst++ = '\\'; *dst++ = 't'; \ + continue; \ + case '\f': \ + *dst++ = '\\'; *dst++ = 'f'; \ + continue; \ + case ' ': \ + *dst++ = '\\'; *dst++ = 's'; \ + continue; \ + case '\0': \ + *dst++ = '\\'; *dst++ = '0'; \ + if (isoctal(nextc)) { \ + *dst++ = '0'; \ + *dst++ = '0'; \ + } \ + continue; \ + default: \ + if (isgraph(c)) { \ + *dst++ = '\\'; *dst++ = c; \ + continue; \ + } \ + } \ + } \ + if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) { \ + *dst++ = '\\'; \ + *dst++ = (u_char)(((u_int32_t)(u_char)c >> 6) & 03) + '0'; \ + *dst++ = (u_char)(((u_int32_t)(u_char)c >> 3) & 07) + '0'; \ + *dst++ = (c & 07) + '0'; \ + } else { \ + if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\'; \ + if (c & 0200) { \ + c &= 0177; *dst++ = 'M'; \ + } \ + if (iscntrl(c)) { \ + *dst++ = '^'; \ + if (c == 0177) \ + *dst++ = '?'; \ + else \ + *dst++ = c + '@'; \ + } else { \ + *dst++ = '-'; *dst++ = c; \ + } \ + } \ +} while (/*CONSTCOND*/0) + + +/* + * svis - visually encode characters, also encoding the characters + * pointed to by `extra' + */ +char * +svis(dst, c, flag, nextc, extra) + char *dst; + int c, flag, nextc; + const char *extra; +{ + char *nextra; + _DIAGASSERT(dst != NULL); + _DIAGASSERT(extra != NULL); + MAKEEXTRALIST(flag, nextra, extra); + if (flag & VIS_HTTPSTYLE) + HVIS(dst, c, flag, nextc, nextra); + else + SVIS(dst, c, flag, nextc, nextra); + *dst = '\0'; + return(dst); +} + + +/* + * strsvis, strsvisx - visually encode characters from src into dst + * + * Extra is a pointer to a \0-terminated list of characters to + * be encoded, too. These functions are useful e. g. to + * encode strings in such a way so that they are not interpreted + * by a shell. + * + * Dst must be 4 times the size of src to account for possible + * expansion. The length of dst, not including the trailing NULL, + * is returned. + * + * Strsvisx encodes exactly len bytes from src into dst. + * This is useful for encoding a block of data. + */ +int +strsvis(dst, csrc, flag, extra) + char *dst; + const char *csrc; + int flag; + const char *extra; +{ + int c; + char *start; + char *nextra; + const unsigned char *src = (const unsigned char *)csrc; + + _DIAGASSERT(dst != NULL); + _DIAGASSERT(src != NULL); + _DIAGASSERT(extra != NULL); + MAKEEXTRALIST(flag, nextra, extra); + if (flag & VIS_HTTPSTYLE) { + for (start = dst; (c = *src++) != '\0'; /* empty */) + HVIS(dst, c, flag, *src, nextra); + } else { + for (start = dst; (c = *src++) != '\0'; /* empty */) + SVIS(dst, c, flag, *src, nextra); + } + *dst = '\0'; + return (dst - start); +} + + +int +strsvisx(dst, csrc, len, flag, extra) + char *dst; + const char *csrc; + size_t len; + int flag; + const char *extra; +{ + int c; + char *start; + char *nextra; + const unsigned char *src = (const unsigned char *)csrc; + + _DIAGASSERT(dst != NULL); + _DIAGASSERT(src != NULL); + _DIAGASSERT(extra != NULL); + MAKEEXTRALIST(flag, nextra, extra); + + if (flag & VIS_HTTPSTYLE) { + for (start = dst; len > 0; len--) { + c = *src++; + HVIS(dst, c, flag, len ? *src : '\0', nextra); + } + } else { + for (start = dst; len > 0; len--) { + c = *src++; + SVIS(dst, c, flag, len ? *src : '\0', nextra); + } + } + *dst = '\0'; + return (dst - start); +} +#endif + +#if !HAVE_VIS +/* + * vis - visually encode characters + */ +char * +vis(dst, c, flag, nextc) + char *dst; + int c, flag, nextc; + +{ + char *extra; + + _DIAGASSERT(dst != NULL); + + MAKEEXTRALIST(flag, extra, ""); + if (flag & VIS_HTTPSTYLE) + HVIS(dst, c, flag, nextc, extra); + else + SVIS(dst, c, flag, nextc, extra); + *dst = '\0'; + return (dst); +} + + +/* + * strvis, strvisx - visually encode characters from src into dst + * + * Dst must be 4 times the size of src to account for possible + * expansion. The length of dst, not including the trailing NULL, + * is returned. + * + * Strvisx encodes exactly len bytes from src into dst. + * This is useful for encoding a block of data. + */ +int +strvis(dst, src, flag) + char *dst; + const char *src; + int flag; +{ + char *extra; + + MAKEEXTRALIST(flag, extra, ""); + return (strsvis(dst, src, flag, extra)); +} + + +int +strvisx(dst, src, len, flag) + char *dst; + const char *src; + size_t len; + int flag; +{ + char *extra; + + MAKEEXTRALIST(flag, extra, ""); + return (strsvisx(dst, src, len, flag, extra)); +} +#endif diff --git a/cmd-line-utils/libedit/vis.h b/cmd-line-utils/libedit/vis.h new file mode 100644 index 00000000000..44f6fc7d785 --- /dev/null +++ b/cmd-line-utils/libedit/vis.h @@ -0,0 +1,92 @@ +/* $NetBSD: vis.h,v 1.15 2005/02/03 04:39:32 perry Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. + * + * @(#)vis.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _VIS_H_ +#define _VIS_H_ + +#include + +/* + * to select alternate encoding format + */ +#define VIS_OCTAL 0x01 /* use octal \ddd format */ +#define VIS_CSTYLE 0x02 /* use \[nrft0..] where appropiate */ + +/* + * to alter set of characters encoded (default is to encode all + * non-graphic except space, tab, and newline). + */ +#define VIS_SP 0x04 /* also encode space */ +#define VIS_TAB 0x08 /* also encode tab */ +#define VIS_NL 0x10 /* also encode newline */ +#define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL) +#define VIS_SAFE 0x20 /* only encode "unsafe" characters */ + +/* + * other + */ +#define VIS_NOSLASH 0x40 /* inhibit printing '\' */ +#define VIS_HTTPSTYLE 0x80 /* http-style escape % HEX HEX */ + +/* + * unvis return codes + */ +#define UNVIS_VALID 1 /* character valid */ +#define UNVIS_VALIDPUSH 2 /* character valid, push back passed char */ +#define UNVIS_NOCHAR 3 /* valid sequence, no character produced */ +#define UNVIS_SYNBAD -1 /* unrecognized escape sequence */ +#define UNVIS_ERROR -2 /* decoder in unknown state (unrecoverable) */ + +/* + * unvis flags + */ +#define UNVIS_END 1 /* no more characters */ + +__BEGIN_DECLS +char *vis(char *, int, int, int); +char *svis(char *, int, int, int, const char *); +int strvis(char *, const char *, int); +int strsvis(char *, const char *, int, const char *); +int strvisx(char *, const char *, size_t, int); +int strsvisx(char *, const char *, size_t, int, const char *); +int strunvis(char *, const char *); +int strunvisx(char *, const char *, int); +#ifdef __LIBC12_SOURCE__ +int unvis(char *, int, int *, int); +int __unvis13(char *, int, int *, int); +#else +int unvis(char *, int, int *, int); +#endif +__END_DECLS + +#endif /* !_VIS_H_ */ From 6905af20b80c38e3d9e869f0af45dc9e5b930d53 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 Apr 2005 12:36:23 +0200 Subject: [PATCH 09/78] Reverting back to original path of readline.h cmd-line-utils/libedit/readline/readline.h: mvdir --- cmd-line-utils/libedit/Makefile.am | 2 +- cmd-line-utils/libedit/readline.c | 2 +- cmd-line-utils/libedit/{editline => readline}/readline.h | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename cmd-line-utils/libedit/{editline => readline}/readline.h (100%) diff --git a/cmd-line-utils/libedit/Makefile.am b/cmd-line-utils/libedit/Makefile.am index 0a8458e51f7..a3d73a7082a 100644 --- a/cmd-line-utils/libedit/Makefile.am +++ b/cmd-line-utils/libedit/Makefile.am @@ -20,7 +20,7 @@ EXTRA_libedit_a_SOURCES = np/unvis.c np/strlcpy.c np/vis.c np/strlcat.c \ libedit_a_LIBADD = @LIBEDIT_LOBJECTS@ libedit_a_DEPENDENCIES = @LIBEDIT_LOBJECTS@ -pkginclude_HEADERS = editline/readline.h +pkginclude_HEADERS = readline/readline.h noinst_HEADERS = chared.h el.h histedit.h key.h parse.h refresh.h sig.h \ sys.h tokenizer.h config.h hist.h map.h prompt.h read.h \ diff --git a/cmd-line-utils/libedit/readline.c b/cmd-line-utils/libedit/readline.c index 761acffc13f..3a38e8a99ab 100644 --- a/cmd-line-utils/libedit/readline.c +++ b/cmd-line-utils/libedit/readline.c @@ -73,7 +73,7 @@ extern char *alloca (); #include "el.h" #include "fcns.h" /* for EL_NUM_FCNS */ #include "histedit.h" -#include "editline/readline.h" +#include "readline/readline.h" /* for rl_complete() */ #define TAB '\r' diff --git a/cmd-line-utils/libedit/editline/readline.h b/cmd-line-utils/libedit/readline/readline.h similarity index 100% rename from cmd-line-utils/libedit/editline/readline.h rename to cmd-line-utils/libedit/readline/readline.h From c8683be463c0618e9d42fe964b1c4e8831fec0e4 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 Apr 2005 21:06:08 +0500 Subject: [PATCH 10/78] A fix (Bug #9489: Problem with BIT_OR and MySQL 5.0.3) heap/hp_hash.c: A fix (Bug #9489: Problem with BIT_OR and MySQL 5.0.3). Should take into account key pack length. --- heap/hp_hash.c | 11 +++++++++++ mysql-test/r/type_varchar.result | 11 ++++++++++- mysql-test/t/type_varchar.test | 14 +++++++++++++- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/heap/hp_hash.c b/heap/hp_hash.c index 3121ef71fb0..52a250bd7af 100644 --- a/heap/hp_hash.c +++ b/heap/hp_hash.c @@ -255,6 +255,9 @@ ulong hp_hashnr(register HP_KEYDEF *keydef, register const byte *key) if (*pos) /* Found null */ { nr^= (nr << 1) | 1; + /* Add key pack length (2) to key for VARCHAR segments */ + if (seg->type == HA_KEYTYPE_VARTEXT1) + key+= 2; continue; } pos++; @@ -390,6 +393,9 @@ ulong hp_hashnr(register HP_KEYDEF *keydef, register const byte *key) if (*pos) { nr^= (nr << 1) | 1; + /* Add key pack length (2) to key for VARCHAR segments */ + if (seg->type == HA_KEYTYPE_VARTEXT1) + key+= 2; continue; } pos++; @@ -584,7 +590,12 @@ int hp_key_cmp(HP_KEYDEF *keydef, const byte *rec, const byte *key) if (found_null != (int) *key++) return 1; if (found_null) + { + /* Add key pack length (2) to key for VARCHAR segments */ + if (seg->type == HA_KEYTYPE_VARTEXT1) + key+= 2; continue; + } } if (seg->type == HA_KEYTYPE_TEXT) { diff --git a/mysql-test/r/type_varchar.result b/mysql-test/r/type_varchar.result index d2fe843a68b..3bd7fe6b175 100644 --- a/mysql-test/r/type_varchar.result +++ b/mysql-test/r/type_varchar.result @@ -1,4 +1,4 @@ -drop table if exists t1; +drop table if exists t1, t2; create table t1 (v varchar(30), c char(3), e enum('abc','def','ghi'), t text); truncate table vchar; show create table t1; @@ -383,3 +383,12 @@ select * from t1; pkcol othercol test somethingelse drop table t1; +create table t1 (a int, b varchar(12)); +insert into t1 values (1, 'A'), (22, NULL); +create table t2 (a int); +insert into t2 values (22), (22); +select t1.a, t1.b, min(t1.b) from t1 inner join t2 ON t2.a = t1.a +group by t1.b, t1.a; +a b min(t1.b) +22 NULL NULL +drop table t1, t2; diff --git a/mysql-test/t/type_varchar.test b/mysql-test/t/type_varchar.test index 9867cf4c057..2bffca6b889 100644 --- a/mysql-test/t/type_varchar.test +++ b/mysql-test/t/type_varchar.test @@ -1,5 +1,5 @@ --disable_warnings -drop table if exists t1; +drop table if exists t1, t2; --enable_warnings create table t1 (v varchar(30), c char(3), e enum('abc','def','ghi'), t text); @@ -106,3 +106,15 @@ insert into t1 values ('test', 'something'); update t1 set othercol='somethingelse' where pkcol='test'; select * from t1; drop table t1; + +# +# Bug #9489: problems with key handling +# + +create table t1 (a int, b varchar(12)); +insert into t1 values (1, 'A'), (22, NULL); +create table t2 (a int); +insert into t2 values (22), (22); +select t1.a, t1.b, min(t1.b) from t1 inner join t2 ON t2.a = t1.a + group by t1.b, t1.a; +drop table t1, t2; From 8a9c988122135441d35bbab1b70c3e0ccb88b7a4 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Apr 2005 20:49:05 +0200 Subject: [PATCH 11/78] Step 3 of the switch to support configuration with NPTL: Change "configure.in". The branches for Tru64 (ex: OSF/1) and Linux are separated, and for Linux 'getconf GNU_LIBPTHREAD_VERSION' is used to tell between Linuxthreads and NPTL. configure.in: Step 3 of the switch to support configuration with NPTL: Change "configure.in". 1) Separate the branches checking for thread libraries on OSF/1 (now: Tru64) and on Linux, as these are different things. In the Tru64 branch, remove the obsolete part for OSF/1 3.2, because that is gone since long (about a decade?); we are at 5 now. Adapt the comment. 2) For Linux, the thread libraries are "Linuxthreads" (older) and "NPTL" (newer). Until now, we cared only about "Linuxthreads", and we did so by checking a comment in the header file '/usr/include/pthread.h'. With NPTL as an alternative or only thread package, this is not secure any more, there are distributions where the header file still contains that comment but the lib is NPTL. For all current distributions, the way to check is the 'getconf' command. On old distributions, 'getconf' exists but does not understand the 'GNU_LIBPTHREAD_VERSION' parameter. It is unlikely that such an old system should have NPTL, so the header file check is sufficient if the getconf inquiry fails. For both Linuxthreads and NPTL, '-lpthread' is the linker option to use. 3) To detect problems as early as possible, on Linux a link test using '-lpthread' is done. The code is copied from a later check where the thread functions are searched in '-lc', '-lpthread', and '-lpthreads', but this later search would not be executed after the lib was already determined. So if the test is not done here, it will be detected only during the real build. This is too late. --- configure.in | 138 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 85 insertions(+), 53 deletions(-) diff --git a/configure.in b/configure.in index f7a266eebec..dfffecdff08 100644 --- a/configure.in +++ b/configure.in @@ -411,12 +411,12 @@ if expr "$target_os" : "[[Ll]]inux.*" > /dev/null then MYSQLD_DEFAULT_SWITCHES="--skip-locking" TARGET_LINUX="true" - AC_MSG_RESULT("yes"); + AC_MSG_RESULT("yes") AC_DEFINE([TARGET_OS_LINUX], [1], [Whether we build for Linux]) else MYSQLD_DEFAULT_SWITCHES="" TARGET_LINUX="false" - AC_MSG_RESULT("no"); + AC_MSG_RESULT("no") fi AC_SUBST(MYSQLD_DEFAULT_SWITCHES) AC_SUBST(TARGET_LINUX) @@ -1267,61 +1267,93 @@ esac # We have to check libc last because else it fails on Solaris 2.6 with_posix_threads="no" -# Hack for DEC-UNIX (OSF1) +# Search thread lib on Linux if test "$with_named_thread" = "no" -a "$with_mit_threads" = "no" then - # Look for LinuxThreads. - AC_MSG_CHECKING("LinuxThreads") - res=`grep Linuxthreads /usr/include/pthread.h 2>/dev/null | wc -l` - if test "$res" -gt 0 + AC_MSG_CHECKING("Linux threads") + if test "$TARGET_LINUX" = "true" then - AC_MSG_RESULT("Found") - AC_DEFINE([HAVE_LINUXTHREADS], [1], - [Whether we are using Xavier Leroy's LinuxThreads]) - # Linux 2.0 sanity check - AC_TRY_COMPILE([#include ], [int a = sched_get_priority_min(1);], , - AC_MSG_ERROR([Syntax error in sched.h. Change _P to __P in the /usr/include/sched.h file. See the Installation chapter in the Reference Manual])) - # RedHat 5.0 does not work with dynamic linking of this. -static also - # gives a speed increase in linux so it does not hurt on other systems. - with_named_thread="-lpthread" - else - AC_MSG_RESULT("Not found") - # If this is a linux machine we should barf - if test "$TARGET_LINUX" = "true" - then - AC_MSG_ERROR([This is a linux system and Linuxthreads was not -found. On linux Linuxthreads should be used. Please install Linuxthreads -(or a new glibc) and try again. See the Installation chapter in the -Reference Manual for more information.]) - else - AC_MSG_CHECKING("DEC threads") - if test -f /usr/shlib/libpthread.so -a -f /usr/lib/libmach.a -a -f /usr/ccs/lib/cmplrs/cc/libexc.a - then - with_named_thread="-lpthread -lmach -lexc" - CFLAGS="$CFLAGS -D_REENTRANT" - CXXFLAGS="$CXXFLAGS -D_REENTRANT" - AC_DEFINE(HAVE_DEC_THREADS, [1], - [Whether we are using DEC threads]) - AC_MSG_RESULT("yes") - else - AC_MSG_RESULT("no") - AC_MSG_CHECKING("DEC 3.2 threads") - if test -f /usr/shlib/libpthreads.so -a -f /usr/lib/libmach.a -a -f /usr/ccs/lib/cmplrs/cc/libexc.a - then - with_named_thread="-lpthreads -lmach -lc_r" - AC_DEFINE(HAVE_DEC_THREADS, [1]) - AC_DEFINE([HAVE_DEC_3_2_THREADS], [1], - [Whether we are using OSF1 DEC threads on 3.2]) - with_osf32_threads="yes" - MYSQLD_DEFAULT_SWITCHES="--skip-thread-priority" - AC_MSG_RESULT("yes") - else - AC_MSG_RESULT("no") + AC_MSG_RESULT("starting") + # use getconf to check glibc contents + AC_MSG_CHECKING("getconf GNU_LIBPTHREAD_VERSION") + case `getconf GNU_LIBPTHREAD_VERSION | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ` in + NPTL* ) + AC_MSG_RESULT("NPTL") + AC_DEFINE([HAVE_NPTL], [1], [NPTL threads implementation]) + with_named_thread="-lpthread" + ;; + LINUXTHREADS* ) + AC_MSG_RESULT("Linuxthreads") + AC_DEFINE([HAVE_LINUXTHREADS], [1], + [Whether we are using Xavier Leroy's LinuxThreads]) + with_named_thread="-lpthread" + ;; + * ) + AC_MSG_RESULT("unknown") + ;; + esac + if test "$with_named_thread" = "no" + then + # old method, check headers + # Look for LinuxThreads. + AC_MSG_CHECKING("LinuxThreads in header file comment") + res=`grep Linuxthreads /usr/include/pthread.h 2>/dev/null | wc -l` + if test "$res" -gt 0 + then + AC_MSG_RESULT("Found") + AC_DEFINE([HAVE_LINUXTHREADS], [1], + [Whether we are using Xavier Leroy's LinuxThreads]) + # Linux 2.0 sanity check + AC_TRY_COMPILE([#include ], [int a = sched_get_priority_min(1);], , + AC_MSG_ERROR([Syntax error in sched.h. Change _P to __P in the /usr/include/sched.h file. See the Installation chapter in the Reference Manual])) + # RedHat 5.0 does not work with dynamic linking of this. -static also + # gives a speed increase in linux so it does not hurt on other systems. + with_named_thread="-lpthread" + else + AC_MSG_RESULT("Not found") + # If this is a linux machine we should barf + AC_MSG_ERROR([This is a Linux system without a working getconf, +and Linuxthreads was not found. Please install it (or a new glibc) and try again. +See the Installation chapter in the Reference Manual for more information.]) fi - fi - fi - fi -fi + else + AC_MSG_RESULT("no need to check headers") + fi + + AC_MSG_CHECKING("for pthread_create in -lpthread"); + ac_save_LIBS="$LIBS" + LIBS="$LIBS -lpthread" + AC_TRY_LINK( [#include ], + [ (void) pthread_create((pthread_t*) 0,(pthread_attr_t*) 0, 0, 0); ], + AC_MSG_RESULT("yes"), + [ AC_MSG_RESULT("no") + AC_MSG_ERROR([ +This is a Linux system claiming to support threads, either Linuxthreads or NPTL, but linking a test program failed. +Please install one of these (or a new glibc) and try again. +See the Installation chapter in the Reference Manual for more information.]) ] + ) + LIBS="$ac_save_LIBS" + else + AC_MSG_RESULT("no") + fi # "$TARGET_LINUX" +fi # "$with_named_thread" = "no" -a "$with_mit_threads" = "no" + + +# Hack for DEC-UNIX (OSF1 -> Tru64) +if test "$with_named_thread" = "no" -a "$with_mit_threads" = "no" +then + AC_MSG_CHECKING("DEC threads post OSF/1 3.2") + if test -f /usr/shlib/libpthread.so -a -f /usr/lib/libmach.a -a -f /usr/ccs/lib/cmplrs/cc/libexc.a + then + with_named_thread="-lpthread -lmach -lexc" + CFLAGS="$CFLAGS -D_REENTRANT" + CXXFLAGS="$CXXFLAGS -D_REENTRANT" + AC_DEFINE(HAVE_DEC_THREADS, [1], [Whether we are using DEC threads]) + AC_MSG_RESULT("yes") + else + AC_MSG_RESULT("no") + fi # DEC threads +fi # "$with_named_thread" = "no" -a "$with_mit_threads" = "no" dnl This is needed because -lsocket has to come after the thread From 85ef43b4d09ca3899f379868dfbc414e84fc700b Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 25 Apr 2005 04:00:35 +0400 Subject: [PATCH 12/78] Fix for BUG#8921: Make SHOW CREATE VIEW ignore temporary tables. mysql-test/r/temp_table.result: Testcase for BUG#8921 mysql-test/t/temp_table.test: Testcase for BUG#8921 --- mysql-test/r/temp_table.result | 26 ++++++++++++++++++++++++++ mysql-test/t/temp_table.test | 15 +++++++++++++++ sql/sql_parse.cc | 4 ++++ 3 files changed, 45 insertions(+) diff --git a/mysql-test/r/temp_table.result b/mysql-test/r/temp_table.result index 2dd58f54327..f43fd09982a 100644 --- a/mysql-test/r/temp_table.result +++ b/mysql-test/r/temp_table.result @@ -97,3 +97,29 @@ Variable_name Value Created_tmp_disk_tables 0 Created_tmp_tables 2 drop table t1; +create temporary table t1 as select 'This is temp. table' A; +create view t1 as select 'This is view' A; +select * from t1; +A +This is temp. table +show create table t1; +Table Create Table +t1 CREATE TEMPORARY TABLE `t1` ( + `A` varchar(19) NOT NULL default '' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show create view t1; +View Create View +t1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`t1` AS select _latin1'This is view' AS `A` +drop view t1; +select * from t1; +A +This is temp. table +create view t1 as select 'This is view again' A; +select * from t1; +A +This is temp. table +drop table t1; +select * from t1; +A +This is view again +drop view t1; diff --git a/mysql-test/t/temp_table.test b/mysql-test/t/temp_table.test index 74276c7668c..eeb33515570 100644 --- a/mysql-test/t/temp_table.test +++ b/mysql-test/t/temp_table.test @@ -89,3 +89,18 @@ flush status; select * from t1 group by d; show status like "created_tmp%tables"; drop table t1; + +# Fix for BUG#8921: Check that temporary table is ingored by view commands. +create temporary table t1 as select 'This is temp. table' A; +create view t1 as select 'This is view' A; +select * from t1; +show create table t1; +show create view t1; +drop view t1; +select * from t1; +create view t1 as select 'This is view again' A; +select * from t1; +drop table t1; +select * from t1; +drop view t1; + diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c5ef9f4e713..6453c726ee0 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3010,6 +3010,10 @@ unsent_create_error: goto error; #else { + /* Ignore temporary tables if this is "SHOW CREATE VIEW" */ + if (lex->only_view) + first_table->skip_temporary= 1; + if (check_db_used(thd, all_tables) || check_access(thd, SELECT_ACL | EXTRA_ACL, first_table->db, &first_table->grant.privilege, 0, 0)) From f65f279944a3388b567743f27f5db8e47ae44d95 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 25 Apr 2005 12:05:13 +0200 Subject: [PATCH 13/78] BUG#2596 MySQL Client Segmentation Fault on Solaris 9 - Print readline or libedit version client/mysql.cc: Print the version of readline or libedit library used. --- client/mysql.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 49efe9cbcf2..f27db0de8d8 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -691,8 +691,16 @@ static void usage(int version) #ifdef __NETWARE__ #define printf consoleprintf #endif - printf("%s Ver %s Distrib %s, for %s (%s)\n", - my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); + +#if defined(USE_LIBEDIT_INTERFACE) + const char* readline= ""; +#else + const char* readline= "readline"; +#endif + + printf("%s Ver %s Distrib %s, for %s (%s) using %s %s\n", + my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE, + readline, rl_library_version); if (version) return; printf("\ From ee5d8be5c07542a2b9e6b4fde9e17d3d4e426791 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 25 Apr 2005 13:28:07 +0200 Subject: [PATCH 14/78] - fixed NDB_VERSION_BUILD in configure.in to have the correct number (4->5) configure.in: - fixed NDB_VERSION_BUILD to have the correct number (4->5) --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index f4ced66a06d..d3e0bf6cefe 100644 --- a/configure.in +++ b/configure.in @@ -17,7 +17,7 @@ SHARED_LIB_VERSION=14:0:0 # ndb version NDB_VERSION_MAJOR=5 NDB_VERSION_MINOR=0 -NDB_VERSION_BUILD=4 +NDB_VERSION_BUILD=5 NDB_VERSION_STATUS="beta" # Set all version vars based on $VERSION. How do we do this more elegant ? From c6c0665a1f87e62c34975153769d73edbe252703 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 25 Apr 2005 16:53:47 -0500 Subject: [PATCH 15/78] regerror.c: Changed function signature to fix compile errors with Whidbey regex/regerror.c: Changed function signature to fix compile errors with Whidbey --- regex/regerror.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/regex/regerror.c b/regex/regerror.c index 0a7b7c8da2c..9caa5b95a4c 100644 --- a/regex/regerror.c +++ b/regex/regerror.c @@ -56,11 +56,7 @@ static struct rerr { */ /* ARGSUSED */ size_t -regerror(errcode, preg, errbuf, errbuf_size) -int errcode; -const regex_t *preg; -char *errbuf; -size_t errbuf_size; +regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) { register struct rerr *r; register size_t len; From 09c3e18f245e4401034740c07625b9c10624601f Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 01:56:10 +0400 Subject: [PATCH 16/78] BUG#10037: A proper fix: Add 0.01 to cost of 'range' scans, don't add 0.01 to cost of the 'index' scan. --- sql/opt_range.cc | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/sql/opt_range.cc b/sql/opt_range.cc index ac25f15d460..95fe003770b 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2257,8 +2257,7 @@ inline double get_index_only_read_time(const PARAM* param, ha_rows records, param->table->file->ref_length) + 1); read_time=((double) (records+keys_per_block-1)/ (double) keys_per_block); - /* Add 0.01 to avoid cost races between 'range' and 'index' */ - return read_time + 0.01; + return read_time; } @@ -3150,10 +3149,16 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, (param->table->file->index_flags(keynr, param->max_key_part,1) & HA_KEYREAD_ONLY) && !(pk_is_clustered && keynr == param->table->s->primary_key)) - /* We can resolve this by only reading through this key. */ + { + /* + We can resolve this by only reading through this key. + 0.01 is added to avoid races between range and 'index' scan. + */ found_read_time= get_index_only_read_time(param,found_records,keynr) + - cpu_cost; + cpu_cost + 0.01; + } else + { /* cost(read_through_index) = cost(disk_io) + cost(row_in_range_checks) The row_in_range check is in QUICK_RANGE_SELECT::cmp_next function. @@ -3161,8 +3166,8 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, found_read_time= param->table->file->read_time(keynr, param->range_count, found_records) + - cpu_cost; - + cpu_cost + 0.01; + } DBUG_PRINT("info",("key %s: found_read_time: %g (cur. read_time: %g)", param->table->key_info[keynr].name, found_read_time, read_time)); From ccfcfce6dbd897928954adbe74e474e8c1ac3e44 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 25 Apr 2005 18:02:03 -0700 Subject: [PATCH 17/78] Fix compile issues in Intel C/C++ compiler (Bug #9063) acinclude.m4: Use AC_LANG_PUSH/POP instead of _SAVE/RESTORE Add test to get type of 'struct rlimit' Switch order of including stdlib.h and declaration being tested to match how it will be used in regular code. configure.in: Call MYSQL_TYPE_STRUCT_RLIMIT macro sql/mysqld.cc: Use STRUCT_RLIMIT for getting type of struct rlimit. --- acinclude.m4 | 39 ++++++++++++++++++++++++++++++++++----- configure.in | 2 ++ sql/mysqld.cc | 2 +- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index 74426bc2061..904493a2e09 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -97,10 +97,10 @@ undefine([AC_CV_NAME])dnl AC_DEFUN([MYSQL_TYPE_ACCEPT], [ac_save_CXXFLAGS="$CXXFLAGS" AC_CACHE_CHECK([base type of last arg to accept], mysql_cv_btype_last_arg_accept, -AC_LANG_SAVE -AC_LANG_CPLUSPLUS +AC_LANG_PUSH(C++) if test "$ac_cv_prog_gxx" = "yes" then + # Add -Werror, remove -fbranch-probabilities (Bug #268) CXXFLAGS=`echo $CXXFLAGS -Werror | sed 's/-fbranch-probabilities//'` fi mysql_cv_btype_last_arg_accept=none @@ -127,7 +127,7 @@ fi if test "$mysql_cv_btype_last_arg_accept" = "none"; then mysql_cv_btype_last_arg_accept=int fi) -AC_LANG_RESTORE +AC_LANG_POP(C++) AC_DEFINE_UNQUOTED([SOCKET_SIZE_TYPE], [$mysql_cv_btype_last_arg_accept], [The base type of the last arg to accept]) CXXFLAGS="$ac_save_CXXFLAGS" @@ -153,6 +153,35 @@ then fi ]) +#---START: Figure out whether to use 'struct rlimit' or 'struct rlimit64' +AC_DEFUN([MYSQL_TYPE_STRUCT_RLIMIT], +[ac_save_CXXFLAGS="$CXXFLAGS" +AC_CACHE_CHECK([struct type to use with setrlimit], mysql_cv_btype_struct_rlimit, +AC_LANG_PUSH(C++) +if test "$ac_cv_prog_gxx" = "yes" +then + # Add -Werror, remove -fbranch-probabilities (Bug #268) + CXXFLAGS=`echo $CXXFLAGS -Werror | sed 's/-fbranch-probabilities//'` +fi +mysql_cv_btype_struct_rlimit=none +[AC_TRY_COMPILE([#if defined(inline) +#undef inline +#endif +#include +#include +], +[struct rlimit64 rl; setrlimit(RLIMIT_CORE, &rl);], +mysql_cv_btype_struct_rlimit="struct rlimit64")] +if test "$mysql_cv_btype_struct_rlimit" = "none"; then +mysql_cv_btype_struct_rlimit="struct rlimit" +fi) +AC_LANG_POP(C++) +AC_DEFINE_UNQUOTED([STRUCT_RLIMIT], [$mysql_cv_btype_struct_rlimit], + [The struct rlimit type to use with setrlimit]) +CXXFLAGS="$ac_save_CXXFLAGS" +]) +#---END: + AC_DEFUN([MYSQL_TIMESPEC_TS], [AC_CACHE_CHECK([if struct timespec has a ts_sec member], mysql_cv_timespec_ts, [AC_TRY_COMPILE([#include @@ -1940,8 +1969,8 @@ m4_define([_AC_PROG_CXX_EXIT_DECLARATION], 'void exit (int);' \ '#include ' do - _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([@%:@include -$ac_declaration], + _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$ac_declaration +@%:@include ], [exit (42);])], [], [continue]) diff --git a/configure.in b/configure.in index d191463d0f9..8191d46c0e6 100644 --- a/configure.in +++ b/configure.in @@ -1795,6 +1795,8 @@ AC_C_BIGENDIAN MYSQL_TYPE_ACCEPT #---END: +# Figure out what type of struct rlimit to use with setrlimit +MYSQL_TYPE_STRUCT_RLIMIT # Find where the stack goes MYSQL_STACK_DIRECTION # We want to skip alloca on irix unconditionally. It may work on some version.. diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 056c2a7ad7f..43bed35621b 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2000,7 +2000,7 @@ static void init_signals(void) if (test_flags & TEST_CORE_ON_SIGNAL) { /* Change limits so that we will get a core file */ - struct rlimit rl; + STRUCT_RLIMIT rl; rl.rlim_cur = rl.rlim_max = RLIM_INFINITY; if (setrlimit(RLIMIT_CORE, &rl) && global_system_variables.log_warnings) sql_print_warning("setrlimit could not change the size of core files to 'infinity'; We may not be able to generate a core file on signals"); From 5444ad94009330a1db7f978290e998fafd23d501 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 11:35:52 +0200 Subject: [PATCH 18/78] BUG#9911 RENAME TABLE of type ARCHIVE fails with .ARN file error - Implemented ha_archive::rename_table - Added testcases for rename mysql-test/r/archive.result: Addd testcase for rename of archive table mysql-test/t/archive.test: Addd testcase for rename of archive table sql/examples/ha_archive.cc: Implement special version of rename table that does not care it the .arn file is missing sql/examples/ha_archive.h: Implement special version of rename table that does not care it the .arn file is missing --- mysql-test/r/archive.result | 16 +++++++++++++++- mysql-test/t/archive.test | 13 ++++++++++++- sql/examples/ha_archive.cc | 24 ++++++++++++++++++++++++ sql/examples/ha_archive.h | 1 + 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index 4adb8a5410e..993fe7e4213 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -2601,4 +2601,18 @@ auto fld1 companynr fld3 fld4 fld5 fld6 2 011401 37 breaking dreaded Steinberg W 3 011402 37 Romans scholastics jarring 4 011403 37 intercepted audiology tinily -drop table t1, t2; +create table t3 engine=archive select * from t2; +select * from t3 where fld3='bonfire'; +auto fld1 companynr fld3 fld4 fld5 fld6 +1191 068504 00 bonfire corresponds positively +select count(*) from t3; +count(*) +1203 +rename table t3 to t4; +select * from t4 where fld3='bonfire'; +auto fld1 companynr fld3 fld4 fld5 fld6 +1191 068504 00 bonfire corresponds positively +select count(*) from t4; +count(*) +1203 +drop table t1, t2, t4; diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index ee78b53f9c8..b9e392870dc 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1299,4 +1299,15 @@ INSERT INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); SELECT * FROM t2; OPTIMIZE TABLE t2; SELECT * FROM t2; -drop table t1, t2; + +# +# Test rename of table +# +create table t3 engine=archive select * from t2; +select * from t3 where fld3='bonfire'; +select count(*) from t3; +rename table t3 to t4; +select * from t4 where fld3='bonfire'; +select count(*) from t4; + +drop table t1, t2, t4; diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index bc4af0c7dc7..0e1df45a70b 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -427,6 +427,30 @@ const char **ha_archive::bas_ext() const { static const char *ext[]= { ARZ, ARN, ARM, NullS }; return ext; } +/* + Rename all files that this handler defines in bas_ext list + + NOTE Don't care if the .arn file is missing +*/ +int ha_archive::rename_table(const char * from, const char * to) +{ + DBUG_ENTER("ha_archive::rename_table"); + for (const char **ext=bas_ext(); *ext ; ext++) + { + if (rename_file_ext(from,to,*ext)) + { + if (my_errno == ENOENT && + !my_strcasecmp(system_charset_info, *ext, ARN)) + continue; + + DBUG_RETURN(my_errno); + } + + } + DBUG_RETURN(0); +} + + /* When opening a file we: Create/get our shared structure. diff --git a/sql/examples/ha_archive.h b/sql/examples/ha_archive.h index 855d756368d..1d3365aca67 100644 --- a/sql/examples/ha_archive.h +++ b/sql/examples/ha_archive.h @@ -124,6 +124,7 @@ public: int optimize(THD* thd, HA_CHECK_OPT* check_opt); THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type); + int rename_table(const char * from, const char * to); }; bool archive_db_init(void); From 545063c30f6ff502bcd8c1414ab7bbcffe0a6656 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 12:16:12 +0200 Subject: [PATCH 19/78] Post-merge fix of the fixes for NPTL configuration (bug#2173, bug#5871, and bug#9497). config/ac-macros/openssl.m4: "Configure" variable 'IS_LINUX' renamed to 'TARGET_LINUX'. Manual merge: In 4.1, this was in 'acinclude.m4'. include/my_global.h: As we have a new CPP symbol, this should be "undef"ed explicitly. --- config/ac-macros/openssl.m4 | 2 +- include/my_global.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config/ac-macros/openssl.m4 b/config/ac-macros/openssl.m4 index 6541a492247..aa46dd45360 100644 --- a/config/ac-macros/openssl.m4 +++ b/config/ac-macros/openssl.m4 @@ -44,7 +44,7 @@ AC_DEFUN([MYSQL_FIND_OPENSSL], [ if test -z "$OPENSSL_LIB" -o -z "$OPENSSL_INCLUDE" ; then echo "Could not find an installation of OpenSSL" if test -n "$OPENSSL_LIB" ; then - if test "$IS_LINUX" = "true"; then + if test "$TARGET_LINUX" = "true"; then echo "Looks like you've forgotten to install OpenSSL development RPM" fi fi diff --git a/include/my_global.h b/include/my_global.h index 6cd1277d358..74846fe1762 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -107,6 +107,7 @@ #undef THREAD #undef HAVE_mit_thread #undef HAVE_LINUXTHREADS +#undef HAVE_NPTL #undef HAVE_UNIXWARE7_THREADS #endif From 38360ef37538a8bc112a4d0f2c2e8a05ea01ffad Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 15:43:20 +0500 Subject: [PATCH 20/78] A fix (bug #9756: mysql client failing on dumps containing certain \ sequences). mysys/charset.c: A fix (bug #9756: mysql client failing on dumps containing certain \ sequences). As 'to_end' points to the last position we should use '>' comparison instead of '>=' there. 'l' replaced with 'tmp_length' (in order not to mix 'l' with '1'). --- mysys/charset.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mysys/charset.c b/mysys/charset.c index a4a8205a3f9..534a6aa998e 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -581,15 +581,15 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info, { char escape=0; #ifdef USE_MB - int l; - if (use_mb_flag && (l= my_ismbchar(charset_info, from, end))) + int tmp_length; + if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end))) { - if (to + l >= to_end) + if (to + tmp_length > to_end) { overflow=1; break; } - while (l--) + while (tmp_length--) *to++= *from++; from--; continue; @@ -605,7 +605,7 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info, multi-byte character into a valid one. For example, 0xbf27 is not a valid GBK character, but 0xbf5c is. (0x27 = ', 0x5c = \) */ - if (use_mb_flag && (l= my_mbcharlen(charset_info, *from)) > 1) + if (use_mb_flag && (tmp_length= my_mbcharlen(charset_info, *from)) > 1) escape= *from; else #endif @@ -634,7 +634,7 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info, } if (escape) { - if (to + 2 >= to_end) + if (to + 2 > to_end) { overflow=1; break; @@ -644,7 +644,7 @@ ulong escape_string_for_mysql(CHARSET_INFO *charset_info, } else { - if (to + 1 >= to_end) + if (to + 1 > to_end) { overflow=1; break; From 2929f984d719eb2b94c8b37ec44847b7cc6b70e7 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 15:48:16 +0500 Subject: [PATCH 21/78] Test case (bug #9756: mysql client failing on dumps containing certain \ sequences). --- mysql-test/r/mysqldump.result | 32 ++++++++++++++++++++++++++++++++ mysql-test/t/mysqldump.test | 8 ++++++++ 2 files changed, 40 insertions(+) diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 130bda3e5bb..fdbdd26b00c 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -599,3 +599,35 @@ UNLOCK TABLES; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; DROP TABLE t1; +CREATE TABLE t1 (a char(10)); +INSERT INTO t1 VALUES ('\''); + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` char(10) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES ('\''); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +DROP TABLE t1; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index ca883f5c4d2..949c62ef288 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -196,3 +196,11 @@ INSERT INTO `t1` VALUES (0x602010000280100005E71A); --exec $MYSQL_DUMP --skip-extended-insert --hex-blob test --skip-comments t1 DROP TABLE t1; +# +# Bug #9756 +# + +CREATE TABLE t1 (a char(10)); +INSERT INTO t1 VALUES ('\''); +--exec $MYSQL_DUMP --skip-comments test t1 +DROP TABLE t1; From e6675ed3ac79b53d9732d26a1e472bf128a4ccc5 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 14:02:16 +0300 Subject: [PATCH 22/78] Improved client internal help. Doc fix for Bug#9870. --- client/mysql.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 8d5117a29e0..4eed4349b45 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -44,7 +44,7 @@ #include #endif -const char *VER= "14.9"; +const char *VER= "14.10"; /* Don't try to make a nice table if the data is too big */ #define MAX_COLUMN_LENGTH 1024 @@ -235,7 +235,7 @@ static COMMANDS commands[] = { { "connect",'r', com_connect,1, "Reconnect to the server. Optional arguments are db and host." }, { "delimiter", 'd', com_delimiter, 1, - "Set query delimiter. " }, + "Set statement delimiter. NOTE: Takes the rest of the line as new delimiter." }, #ifdef USE_POPEN { "edit", 'e', com_edit, 0, "Edit command with $EDITOR."}, #endif From 910c30586773c57f70ed5e12a3795de5b890071d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 13:15:20 +0200 Subject: [PATCH 23/78] Final fix for NPTL configuration (bug#2173, bug#5871, and bug#9497). include/my_global.h: As we have a new CPP symbol, this should be "undef"ed explicitly. --- include/my_global.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/my_global.h b/include/my_global.h index a027bf9d2bb..745179e8a06 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -107,6 +107,7 @@ #undef THREAD #undef HAVE_mit_thread #undef HAVE_LINUXTHREADS +#undef HAVE_NPTL #undef HAVE_UNIXWARE7_THREADS #endif From 2f24a41c30300fe19fbe098ebf0eec5bfb9b7043 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 14:28:22 +0300 Subject: [PATCH 24/78] Fixed Bug#9835: mysqld_multi --help won't output help if there are parameter problems. --- scripts/mysqld_multi.sh | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index ee873a86c8d..e4895ae4bef 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -4,7 +4,7 @@ use Getopt::Long; use POSIX qw(strftime); $|=1; -$VER="2.12"; +$VER="2.13"; $opt_config_file = undef(); $opt_example = 0; @@ -37,13 +37,13 @@ main(); sub main { - my ($flag_exit); + my $flag_exit= 0; if (!defined(my_which(my_print_defaults))) { # We can't throw out yet, since --version, --help, or --example may # have been given - print "WARNING! my_print_defaults command not found!\n"; + print "WARNING: my_print_defaults command not found.\n"; print "Please make sure you have this command available and\n"; print "in your path. The command is available from the latest\n"; print "MySQL distribution.\n"; @@ -76,10 +76,14 @@ sub main chop @defops; splice @ARGV, 0, 0, @defops; } - GetOptions("help","example","version","mysqld=s","mysqladmin=s", - "config-file=s","user=s","password=s","log=s","no-log","tcp-ip", - "silent","verbose") - || die "Wrong option! See $my_progname --help for detailed information!\n"; + if (!GetOptions("help","example","version","mysqld=s","mysqladmin=s", + "config-file=s","user=s","password=s","log=s","no-log", + "tcp-ip", "silent","verbose")) + { + $flag_exit= 1; + } + + usage() if ($opt_help); if ($opt_verbose && $opt_silent) { @@ -95,15 +99,14 @@ sub main exit(0); } example() if ($opt_example); - usage() if ($opt_help); if ($flag_exit) { - print "Error with an option, see $my_progname --help for more info!\n"; + print "Error with an option, see $my_progname --help for more info.\n"; exit(1); } if (!defined(my_which(my_print_defaults))) { - print "ABORT: Can't find command 'my_print_defaults'!\n"; + print "ABORT: Can't find command 'my_print_defaults'.\n"; print "This command is available from the latest MySQL\n"; print "distribution. Please make sure you have the command\n"; print "in your PATH.\n"; From 5ac5febb1d0c4e311c6abb46ec06645ef91885d0 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 16:16:38 +0300 Subject: [PATCH 25/78] Fixed Bug#6221, "mysqld_multi doesn't read the init_connect option in my.cnf correctly" --- scripts/mysqld_multi.sh | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index e4895ae4bef..8c363836a25 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -4,7 +4,7 @@ use Getopt::Long; use POSIX qw(strftime); $|=1; -$VER="2.13"; +$VER="2.14"; $opt_config_file = undef(); $opt_example = 0; @@ -159,6 +159,31 @@ sub main } } +#### +#### Quote option argument. Add double quotes around the argument +#### and escape the following: $, \, " +#### This function is needed, because my_print_defaults drops possible +#### quotes, single or double, from in front of an argument and from +#### the end. +#### + +sub quote_opt_arg +{ + my ($option)= @_; + + if ($option =~ m/(\-\-[a-zA-Z0-9\_\-]+)=(.*)/) + { + $option= $1; + $arg= $2; + $arg=~ s/\\/\\\\/g; # Escape escape character first to avoid doubling. + $arg=~ s/\$/\\\$/g; + $arg=~ s/\"/\\\"/g; + $arg= "\"" . $arg . "\""; + $option= $option . "=" . $arg; + } + return $option; +} + #### #### Init log file. Check for appropriate place for log file, in the following #### order my_print_defaults mysqld datadir, @datadir@, /var/log, /tmp @@ -293,6 +318,7 @@ sub start_mysqlds() else { $options[$j]=~ s/;/\\;/g; + $options[$j]= quote_opt_arg($options[$j]); $tmp.= " $options[$j]"; } } From 24caf249d32281259625ca3fd754805be0fbc307 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 15:52:04 +0200 Subject: [PATCH 26/78] checking that statements get into binlog even when they were affecting no rows of the blackhold engine (for this engine to be a binlog propagator). NOTE: blackhole.test currently hangs in 5.0 BUG#10175 so I'll merge without running this test; the person who fixes the hang will correct the merged blackhole.result or ask me to). mysql-test/r/blackhole.result: result update mysql-test/t/blackhole.test: checking that statements get into binlog even when they were affecting no rows of the blackhold engine. So that this engine can serve as a binlog propagator (A->B->C replication where B has only blackhole tables, B receives binlog from A, applies it to blackhole tables, writes statements to its binlog which it sends to C; both A and C have non-blackhole tables). B is just a proxy. --- mysql-test/r/blackhole.result | 41 ++++++++++++++++++++++++++++++++++- mysql-test/t/blackhole.test | 30 ++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/blackhole.result b/mysql-test/r/blackhole.result index 20018dcb089..4b779094376 100644 --- a/mysql-test/r/blackhole.result +++ b/mysql-test/r/blackhole.result @@ -83,4 +83,43 @@ Full-text indexes are called collections Only MyISAM tables support collections select * from t1 where MATCH(a,b) AGAINST ("only"); a b -drop table if exists t1,t2; +reset master; +drop table t1,t2; +create table t1 (a int) engine=blackhole; +delete from t1 where a=10; +update t1 set a=11 where a=15; +insert into t1 values(1); +insert ignore into t1 values(1); +replace into t1 values(100); +create table t2 (a varchar(200)) engine=blackhole; +load data infile '../../std_data/words.dat' into table t2; +alter table t1 add b int; +alter table t1 drop b; +create table t3 like t1; +insert into t1 select * from t3; +replace into t1 select * from t3; +select * from t1; +a +select * from t2; +a +select * from t3; +a +show binlog events; +Log_name Pos Event_type Server_id Orig_log_pos Info +master-bin.000001 # Start 1 # Server ver: VERSION, Binlog ver: 3 +master-bin.000001 # Query 1 # use `test`; drop table t1,t2 +master-bin.000001 # Query 1 # use `test`; create table t1 (a int) engine=blackhole +master-bin.000001 # Query 1 # use `test`; delete from t1 where a=10 +master-bin.000001 # Query 1 # use `test`; update t1 set a=11 where a=15 +master-bin.000001 # Query 1 # use `test`; insert into t1 values(1) +master-bin.000001 # Query 1 # use `test`; insert ignore into t1 values(1) +master-bin.000001 # Query 1 # use `test`; replace into t1 values(100) +master-bin.000001 # Query 1 # use `test`; create table t2 (a varchar(200)) engine=blackhole +master-bin.000001 # Create_file 1 # db=test;table=t2;file_id=1;block_len=581 +master-bin.000001 # Exec_load 1 # ;file_id=1 +master-bin.000001 # Query 1 # use `test`; alter table t1 add b int +master-bin.000001 # Query 1 # use `test`; alter table t1 drop b +master-bin.000001 # Query 1 # use `test`; create table t3 like t1 +master-bin.000001 # Query 1 # use `test`; insert into t1 select * from t3 +master-bin.000001 # Query 1 # use `test`; replace into t1 select * from t3 +drop table t1,t2,t3; diff --git a/mysql-test/t/blackhole.test b/mysql-test/t/blackhole.test index 052574d6921..d1fcfc971a9 100644 --- a/mysql-test/t/blackhole.test +++ b/mysql-test/t/blackhole.test @@ -96,4 +96,32 @@ select * from t1 where MATCH(a,b) AGAINST ("indexes"); select * from t1 where MATCH(a,b) AGAINST ("indexes collections"); select * from t1 where MATCH(a,b) AGAINST ("only"); -drop table if exists t1,t2; +# Test that every DML (except SELECT) and DDL gets into binlog +# so that blackhole can be used as "binlog propagator" + +reset master; +drop table t1,t2; +create table t1 (a int) engine=blackhole; +delete from t1 where a=10; +update t1 set a=11 where a=15; +insert into t1 values(1); +insert ignore into t1 values(1); +replace into t1 values(100); +create table t2 (a varchar(200)) engine=blackhole; +load data infile '../../std_data/words.dat' into table t2; +alter table t1 add b int; +alter table t1 drop b; +create table t3 like t1; +insert into t1 select * from t3; +replace into t1 select * from t3; +# Just to verify +select * from t1; +select * from t2; +select * from t3; + +let $VERSION=`select version()`; +--replace_result $VERSION VERSION +--replace_column 2 # 5 # +show binlog events; + +drop table t1,t2,t3; From 7226989dc92f969c0dd993296451393d47fe5ca4 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 17:46:43 +0300 Subject: [PATCH 27/78] Fixed Bug#9834, "mysqld_multi --config-file parameter requires absolute path". --- scripts/mysqld_multi.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index 8c363836a25..19434c3dc27 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -66,6 +66,11 @@ sub main else { $opt_config_file= $1; + if (!($opt_config_file =~ m/\//)) + { + # No path. Use current working directory + $opt_config_file= "./" . $opt_config_file; + } } } } @@ -82,7 +87,11 @@ sub main { $flag_exit= 1; } - + if (!($opt_config_file =~ m/\//)) + { + # No path. Use current working directory + $opt_config_file= "./" . $opt_config_file; + } usage() if ($opt_help); if ($opt_verbose && $opt_silent) From 86d285197ab517ccd16a2175881ee51b5e0dde40 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 19:46:52 +0500 Subject: [PATCH 28/78] A fix (bug #10176: problem with varchar keys). myisam/mi_key.c: A fix (bug #10176: problem with varchar keys). Should skip key pack length for 'old' too. --- myisam/mi_key.c | 3 +++ mysql-test/include/varchar.inc | 10 ++++++++++ mysql-test/r/bdb.result | 9 +++++++++ mysql-test/r/innodb.result | 9 +++++++++ mysql-test/r/myisam.result | 9 +++++++++ 5 files changed, 40 insertions(+) diff --git a/myisam/mi_key.c b/myisam/mi_key.c index ab5ddd3a378..d7d10e116aa 100644 --- a/myisam/mi_key.c +++ b/myisam/mi_key.c @@ -242,7 +242,10 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, { k_length-=length; if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) + { k_length-=2; /* Skip length */ + old+= 2; + } continue; /* Found NULL */ } } diff --git a/mysql-test/include/varchar.inc b/mysql-test/include/varchar.inc index 3ec9d00d05d..13b4315f2b8 100644 --- a/mysql-test/include/varchar.inc +++ b/mysql-test/include/varchar.inc @@ -226,3 +226,13 @@ create table t1 (v varchar(65530), key(v(10))); insert into t1 values(repeat('a',65530)); select length(v) from t1 where v=repeat('a',65530); drop table t1; + +# +# Bug #9489: problem with hash indexes +# + +create table t1(a int, b varchar(12), key ba(b, a)); +insert into t1 values (1, 'A'), (20, NULL); +explain select * from t1 where a=20 and b is null; +select * from t1 where a=20 and b is null; +drop table t1; diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result index d743bc03675..876da3cb964 100644 --- a/mysql-test/r/bdb.result +++ b/mysql-test/r/bdb.result @@ -1858,6 +1858,15 @@ select length(v) from t1 where v=repeat('a',65530); length(v) 65530 drop table t1; +create table t1(a int, b varchar(12), key ba(b, a)); +insert into t1 values (1, 'A'), (20, NULL); +explain select * from t1 where a=20 and b is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref ba ba 20 const,const 1 Using where +select * from t1 where a=20 and b is null; +a b +20 NULL +drop table t1; create table t1 (v varchar(65530), key(v)); Warnings: Warning 1071 Specified key was too long; max key length is 255 bytes diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index ccd8601ace0..d6cfefff9e6 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -2359,6 +2359,15 @@ select length(v) from t1 where v=repeat('a',65530); length(v) 65530 drop table t1; +create table t1(a int, b varchar(12), key ba(b, a)); +insert into t1 values (1, 'A'), (20, NULL); +explain select * from t1 where a=20 and b is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref ba ba 20 const,const 1 Using where; Using index +select * from t1 where a=20 and b is null; +a b +20 NULL +drop table t1; create table t1 (v varchar(65530), key(v)); ERROR HY000: Can't create table './test/t1' (errno: 139) create table t1 (v varchar(65536)); diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 539df03e6f9..1a8ace98d05 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -1157,6 +1157,15 @@ select length(v) from t1 where v=repeat('a',65530); length(v) 65530 drop table t1; +create table t1(a int, b varchar(12), key ba(b, a)); +insert into t1 values (1, 'A'), (20, NULL); +explain select * from t1 where a=20 and b is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref ba ba 20 const,const 1 Using where; Using index +select * from t1 where a=20 and b is null; +a b +20 NULL +drop table t1; create table t1 (v varchar(65530), key(v)); Warnings: Warning 1071 Specified key was too long; max key length is 1000 bytes From 0cb38f647aad045e6f22f6a9960e314741c58b5a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 17:57:14 +0300 Subject: [PATCH 29/78] Added a check for config-file. --- scripts/mysqld_multi.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index 19434c3dc27..642772bca44 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -87,7 +87,7 @@ sub main { $flag_exit= 1; } - if (!($opt_config_file =~ m/\//)) + if (defined($opt_config_file) && !($opt_config_file =~ m/\//)) { # No path. Use current working directory $opt_config_file= "./" . $opt_config_file; From cff8039064ca2f04c6ab77ed7a5ae672388e30fe Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 08:20:00 -0700 Subject: [PATCH 30/78] Fix typo in include file name (Bug #9063) acinclude.m4: Fix typo --- acinclude.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acinclude.m4 b/acinclude.m4 index 904493a2e09..61b37294377 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -168,7 +168,7 @@ mysql_cv_btype_struct_rlimit=none #undef inline #endif #include -#include +#include ], [struct rlimit64 rl; setrlimit(RLIMIT_CORE, &rl);], mysql_cv_btype_struct_rlimit="struct rlimit64")] From 79953d9c655b1d384c66afcc686f4dea30b7d41c Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 08:23:42 -0700 Subject: [PATCH 31/78] Merge changes to acinclude.m4 that are now in config/ac-macros/misc.m4 config/ac-macros/misc.m4: Add detection of struct rlimit --- config/ac-macros/misc.m4 | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/config/ac-macros/misc.m4 b/config/ac-macros/misc.m4 index 186a069ac61..201702e5379 100644 --- a/config/ac-macros/misc.m4 +++ b/config/ac-macros/misc.m4 @@ -34,10 +34,10 @@ undefine([AC_CV_NAME])dnl AC_DEFUN([MYSQL_TYPE_ACCEPT], [ac_save_CXXFLAGS="$CXXFLAGS" AC_CACHE_CHECK([base type of last arg to accept], mysql_cv_btype_last_arg_accept, -AC_LANG_SAVE -AC_LANG_CPLUSPLUS +AC_LANG_PUSH(C++) if test "$ac_cv_prog_gxx" = "yes" then + # Add -Werror, remove -fbranch-probabilities (Bug #268) CXXFLAGS=`echo $CXXFLAGS -Werror | sed 's/-fbranch-probabilities//'` fi mysql_cv_btype_last_arg_accept=none @@ -64,7 +64,7 @@ fi if test "$mysql_cv_btype_last_arg_accept" = "none"; then mysql_cv_btype_last_arg_accept=int fi) -AC_LANG_RESTORE +AC_LANG_POP(C++) AC_DEFINE_UNQUOTED([SOCKET_SIZE_TYPE], [$mysql_cv_btype_last_arg_accept], [The base type of the last arg to accept]) CXXFLAGS="$ac_save_CXXFLAGS" @@ -90,6 +90,35 @@ then fi ]) +#---START: Figure out whether to use 'struct rlimit' or 'struct rlimit64' +AC_DEFUN([MYSQL_TYPE_STRUCT_RLIMIT], +[ac_save_CXXFLAGS="$CXXFLAGS" +AC_CACHE_CHECK([struct type to use with setrlimit], mysql_cv_btype_struct_rlimit, +AC_LANG_PUSH(C++) +if test "$ac_cv_prog_gxx" = "yes" +then + # Add -Werror, remove -fbranch-probabilities (Bug #268) + CXXFLAGS=`echo $CXXFLAGS -Werror | sed 's/-fbranch-probabilities//'` +fi +mysql_cv_btype_struct_rlimit=none +[AC_TRY_COMPILE([#if defined(inline) +#undef inline +#endif +#include +#include +], +[struct rlimit64 rl; setrlimit(RLIMIT_CORE, &rl);], +mysql_cv_btype_struct_rlimit="struct rlimit64")] +if test "$mysql_cv_btype_struct_rlimit" = "none"; then +mysql_cv_btype_struct_rlimit="struct rlimit" +fi) +AC_LANG_POP(C++) +AC_DEFINE_UNQUOTED([STRUCT_RLIMIT], [$mysql_cv_btype_struct_rlimit], + [The struct rlimit type to use with setrlimit]) +CXXFLAGS="$ac_save_CXXFLAGS" +]) +#---END: + AC_DEFUN([MYSQL_TIMESPEC_TS], [AC_CACHE_CHECK([if struct timespec has a ts_sec member], mysql_cv_timespec_ts, [AC_TRY_COMPILE([#include From ede526167987b1b35da39a37091a27e6c8f8c6d2 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 17:31:59 +0200 Subject: [PATCH 32/78] Fixed BUG#8408: Stored procedure crash if function contains SHOW We simply have to disallow any kind of result set being sent back from a function. Can't see any way to make that to work. mysql-test/r/sp-error.result: New test case for BUG#8408. mysql-test/t/sp-error.test: New test case for BUG#8408. sql/item_func.cc: Disable result sets from functions but temporarily turning CLIENT_MULTI_RESULTS off. sql/share/errmsg.txt: Added error message for statements not allowed in functions (detected during parsing). sql/sql_yacc.yy: Don't allow result sets in functions. --- mysql-test/r/sp-error.result | 48 ++++++++++++++++++++++++++++ mysql-test/t/sp-error.test | 61 ++++++++++++++++++++++++++++++++++++ sql/item_func.cc | 10 ++++++ sql/share/errmsg.txt | 2 ++ sql/sql_yacc.yy | 6 ++++ 5 files changed, 127 insertions(+) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 5ee1d46f3c9..a2478343806 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -594,4 +594,52 @@ alter function bug7047; return 0; end| ERROR HY000: Can't drop or alter a FUNCTION from within another stored routine +drop function if exists bug8408| +drop procedure if exists bug8408| +create function bug8408() returns int +begin +select * from t1; +return 0; +end| +ERROR 0A000: Not allowed to return a result set from a function +create function bug8408() returns int +begin +show warnings; +return 0; +end| +ERROR 0A000: Not allowed to return a result set from a function +create function bug8408(a int) returns int +begin +declare b int; +select b; +return b; +end| +ERROR 0A000: Not allowed to return a result set from a function +create function bug8408() returns int +begin +call bug8408(); +return 0; +end| +create procedure bug8408() +select * from t1| +call bug8408()| +val x +select bug8408()| +ERROR 0A000: SELECT in a stored procedure must have INTO +drop procedure bug8408| +drop function bug8408| +create function bug8408() returns int +begin +declare n int default 0; +select count(*) into n from t1; +return n; +end| +insert into t1 value (2, 2.7), (3, 3.14), (7, 7.0)| +select *,bug8408() from t1| +val x bug8408() +2 2.7 3 +3 3.14 3 +7 7 3 +drop function bug8408| +delete from t1| drop table t1| diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index cb4ebf080f4..b2d24167e49 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -831,6 +831,67 @@ begin end| +# +# BUG#8408: Stored procedure crash if function contains SHOW +# BUG#9058: Stored Procedures: Crash if function included SELECT +# +--disable_warnings +drop function if exists bug8408| +drop procedure if exists bug8408| +--enable_warnings + +# Some things are caught when parsing +--error ER_SP_NO_RETSET_IN_FUNC +create function bug8408() returns int +begin + select * from t1; + return 0; +end| +--error ER_SP_NO_RETSET_IN_FUNC +create function bug8408() returns int +begin + show warnings; + return 0; +end| +--error ER_SP_NO_RETSET_IN_FUNC +create function bug8408(a int) returns int +begin + declare b int; + select b; + return b; +end| + +# Some things must be caught at invokation time +create function bug8408() returns int +begin + call bug8408(); + return 0; +end| +create procedure bug8408() + select * from t1| + +call bug8408()| +--error ER_SP_BADSELECT +select bug8408()| + +drop procedure bug8408| +drop function bug8408| + +# But this is ok +create function bug8408() returns int +begin + declare n int default 0; + select count(*) into n from t1; + return n; +end| + +insert into t1 value (2, 2.7), (3, 3.14), (7, 7.0)| +select *,bug8408() from t1| + +drop function bug8408| +delete from t1| + + # # BUG#NNNN: New bug synopsis # diff --git a/sql/item_func.cc b/sql/item_func.cc index fb21551e22f..3472c0ab786 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4554,6 +4554,7 @@ Item_func_sp::execute(Item **itp) { DBUG_ENTER("Item_func_sp::execute"); THD *thd= current_thd; + bool clcap_mr; int res; #ifndef NO_EMBEDDED_ACCESS_CHECKS st_sp_security_context save_ctx; @@ -4567,6 +4568,9 @@ Item_func_sp::execute(Item **itp) DBUG_RETURN(-1); } + clcap_mr= (thd->client_capabilities & CLIENT_MULTI_RESULTS); + thd->client_capabilities &= ~CLIENT_MULTI_RESULTS; + #ifndef EMBEDDED_LIBRARY my_bool nsok= thd->net.no_send_ok; thd->net.no_send_ok= TRUE; @@ -4582,6 +4586,8 @@ Item_func_sp::execute(Item **itp) m_sp->m_db.str, m_sp->m_name.str, 0)) { sp_restore_security_context(thd, m_sp, &save_ctx); + if (clcap_mr) + thd->client_capabilities |= CLIENT_MULTI_RESULTS; DBUG_RETURN(-1); } #endif @@ -4595,6 +4601,10 @@ Item_func_sp::execute(Item **itp) #ifndef EMBEDDED_LIBRARY thd->net.no_send_ok= nsok; #endif + + if (clcap_mr) + thd->client_capabilities |= CLIENT_MULTI_RESULTS; + DBUG_RETURN(res); } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 8d7a1fe0093..66986a884b3 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5342,3 +5342,5 @@ ER_SP_DUP_HANDLER 42000 eng "Duplicate handler declared in the same block" ER_SP_NOT_VAR_ARG 42000 eng "OUT or INOUT argument %d for routine %s is not a variable" +ER_SP_NO_RETSET_IN_FUNC 0A000 + eng "Not allowed to return a result set from a function" diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 27e75fd9940..80bf409f7a4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1442,6 +1442,12 @@ create_function_tail: LEX *lex= Lex; sp_head *sp= lex->sphead; + if (sp->m_multi_results) + { + my_message(ER_SP_NO_RETSET_IN_FUNC, ER(ER_SP_NO_RETSET_IN_FUNC), + MYF(0)); + YYABORT; + } if (sp->check_backpatch(YYTHD)) YYABORT; lex->sql_command= SQLCOM_CREATE_SPFUNCTION; From 31b3ecaf862cacbfe43731c07e8abf1180165b24 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 18:18:41 +0200 Subject: [PATCH 33/78] Fixed memory leak in Item_func_sp::cleanup(). --- sql/item_func.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/item_func.h b/sql/item_func.h index ba5a6101e4c..1182379ba05 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1301,6 +1301,8 @@ public: void cleanup() { + if (result_field) + delete result_field; Item_func::cleanup(); result_field= NULL; } From bf17c826deb66a82fe528e4a95edb4caee0ff652 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Apr 2005 23:24:59 +0300 Subject: [PATCH 34/78] Cleanups during review mysys/default.c: Cleanup: - Just test once for recursion level - Don't test explicitely for \r or \n as my_isspace() already does that sql/sql_insert.cc: Fix argument sql/sql_select.cc: Fixed indentation added comment --- mysys/default.c | 62 ++++++++++++++++++++++++++--------------------- sql/sql_insert.cc | 4 +-- sql/sql_select.cc | 12 +++++---- 3 files changed, 44 insertions(+), 34 deletions(-) diff --git a/mysys/default.c b/mysys/default.c index 63323f15fd5..4ee2041bc39 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -402,33 +402,48 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, continue; /* Configuration File Directives */ - if ((*ptr == '!') && (recursion_level < max_recursion_level)) + if ((*ptr == '!')) { + if (recursion_level >= max_recursion_level) + { + for (end= ptr + strlen(ptr) - 1; + my_isspace(&my_charset_latin1, *(end - 1)); + end--) + {} + end[0]= 0; + fprintf(stderr, + "Warning: skipping '%s' directive as maximum include" + "recursion level was reached in file %s at line %d\n", + ptr, name, line); + continue; + } + /* skip over `!' and following whitespace */ for (++ptr; my_isspace(&my_charset_latin1, ptr[0]); ptr++) {} - if ((!strncmp(ptr, includedir_keyword, sizeof(includedir_keyword) - 1)) - && my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1])) + if ((!strncmp(ptr, includedir_keyword, + sizeof(includedir_keyword) - 1)) && + my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1])) { /* skip over "includedir" and following whitespace */ for (ptr+= sizeof(includedir_keyword) - 1; my_isspace(&my_charset_latin1, ptr[0]); ptr++) {} - /* trim trailing whitespace from directory name */ - end= ptr + strlen(ptr) - 1; - /* fgets() stores the newline character in the buffer */ - if ((end[0] == '\n') || (end[0] == '\r') || - my_isspace(&my_charset_latin1, end[0])) - { - for (; my_isspace(&my_charset_latin1, *(end - 1)); end--) - {} - end[0]= 0; - } + /* + trim trailing whitespace from directory name + The -1 below is for the newline added by fgets() + Note that my_isspace() is true for \r and \n + */ + for (end= ptr + strlen(ptr) - 1; + my_isspace(&my_charset_latin1, *(end - 1)); + end--) + {} + end[0]= 0; /* print error msg if there is nothing after !includedir directive */ - if (end == ptr) + if (end <= ptr) { fprintf(stderr, "error: Wrong !includedir directive in config " @@ -468,8 +483,8 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, my_dirend(search_dir); } - else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) - && my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword) - 1])) + else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) && + my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword)-1])) { /* skip over `include' and following whitespace */ for (ptr+= sizeof(include_keyword) - 1; @@ -477,12 +492,13 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, {} /* trim trailing whitespace from filename */ - end= ptr + strlen(ptr) - 1; - for (; my_isspace(&my_charset_latin1, *(end - 1)) ; end--) + for (end= ptr + strlen(ptr) - 1; + my_isspace(&my_charset_latin1, *(end - 1)); + end--) {} end[0]= 0; - if (end == ptr) + if (end <= ptr) { fprintf(stderr, "error: Wrong !include directive in config " @@ -497,14 +513,6 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, continue; } - else - if (recursion_level >= max_recursion_level) - { - fprintf(stderr, - "warning: skipping !include directive as maximum include" - "recursion level was reached in file %s at line %d\n", - name, line); - } if (*ptr == '[') /* Group name */ { diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 7f890a583c6..f46c40f686a 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -72,7 +72,7 @@ static int check_insert_fields(THD *thd, TABLE *table, List &fields, { my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, ER(ER_WRONG_VALUE_COUNT_ON_ROW), - MYF(0), 1); + MYF(0), 1L); return -1; } #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -89,7 +89,7 @@ static int check_insert_fields(THD *thd, TABLE *table, List &fields, { my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, ER(ER_WRONG_VALUE_COUNT_ON_ROW), - MYF(0), 1); + MYF(0), 1L); return -1; } TABLE_LIST table_list; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 36efe26dff9..e7f968df396 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2055,8 +2055,8 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, KEY_OPTIMIZE_EXISTS) | ((old->optimize | new_fields->optimize) & KEY_OPTIMIZE_REF_OR_NULL)); - old->null_rejecting= old->null_rejecting && - new_fields->null_rejecting; + old->null_rejecting= (old->null_rejecting && + new_fields->null_rejecting); } } else if (old->eq_func && new_fields->eq_func && @@ -2068,8 +2068,8 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, KEY_OPTIMIZE_EXISTS) | ((old->optimize | new_fields->optimize) & KEY_OPTIMIZE_REF_OR_NULL)); - old->null_rejecting= old->null_rejecting && - new_fields->null_rejecting; + old->null_rejecting= (old->null_rejecting && + new_fields->null_rejecting); } else if (old->eq_func && new_fields->eq_func && (old->val->is_null() || new_fields->val->is_null())) @@ -2081,7 +2081,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, if (old->val->is_null()) old->val= new_fields->val; /* The referred expression can be NULL: */ - old->null_rejecting= false; + old->null_rejecting= 0; } else { @@ -2242,6 +2242,8 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, Item_func *cond, If the condition has form "tbl.keypart = othertbl.field" and othertbl.field can be NULL, there will be no matches if othertbl.field has NULL value. + We use null_rejecting in add_not_null_conds() to add + 'othertbl.field IS NOT NULL' to tab->select_cond. */ (*key_fields)->null_rejecting= (cond->functype() == Item_func::EQ_FUNC) && ((*value)->type() == Item::FIELD_ITEM) && From 705d1631248a0b3159b58572a0b8c9e35e0598cc Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 02:57:19 +0300 Subject: [PATCH 35/78] dict0dict.c, dict0dict.h, fil0fil.c: Fix a problem in crash recovery of .ibd files on Windows if the user used lower_case_table_names=0 or 2; the directory scan in crash recovery forgot to put all paths to lower case, so that the tablespace name would be consistent with the internal data dictionary of InnoDB; remember that InnoDB puts internally all database names and table names to lower case on Windows, regardless of the value of lower_case_table_names innobase/fil/fil0fil.c: Fix a problem in crash recovery of .ibd files on Windows if the user used lower_case_table_names=0 or 2; the directory scan in crash recovery forgot to put all paths to lower case, so that the tablespace name would be consistent with the internal data dictionary of InnoDB; remember that InnoDB puts internally all database names and table names to lower case on Windows, regardless of the value of lower_case_table_names innobase/include/dict0dict.h: Fix a problem in crash recovery of .ibd files on Windows if the user used lower_case_table_names=0 or 2; the directory scan in crash recovery forgot to put all paths to lower case, so that the tablespace name would be consistent with the internal data dictionary of InnoDB; remember that InnoDB puts internally all database names and table names to lower case on Windows, regardless of the value of lower_case_table_names innobase/dict/dict0dict.c: Fix a problem in crash recovery of .ibd files on Windows if the user used lower_case_table_names=0 or 2; the directory scan in crash recovery forgot to put all paths to lower case, so that the tablespace name would be consistent with the internal data dictionary of InnoDB; remember that InnoDB puts internally all database names and table names to lower case on Windows, regardless of the value of lower_case_table_names --- innobase/dict/dict0dict.c | 12 +++++++++++- innobase/fil/fil0fil.c | 9 +++++++++ innobase/include/dict0dict.h | 7 +++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index bbc47fe9c2b..b0327f77fd3 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -197,7 +197,17 @@ FILE* dict_foreign_err_file = NULL; mutex_t dict_foreign_err_mutex; /* mutex protecting the foreign and unique error buffers */ - +/********************************************************************** +Makes all characters in a NUL-terminated UTF-8 string lower case. */ + +void +dict_casedn_str( +/*============*/ + char* a) /* in/out: string to put in lower case */ +{ + innobase_casedn_str(a); +} + /************************************************************************ Checks if the database name in two table names is the same. */ diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index 773bd709fb7..9d5def718a6 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -25,6 +25,7 @@ Created 10/25/1995 Heikki Tuuri #include "srv0start.h" #include "mtr0mtr.h" #include "mtr0log.h" +#include "dict0dict.h" /* @@ -2732,7 +2733,15 @@ fil_load_single_table_tablespace( sprintf(filepath, "%s/%s/%s", fil_path_to_mysql_datadir, dbname, filename); srv_normalize_path_for_win(filepath); +#ifdef __WIN__ + /* If lower_case_table_names is 0 or 2, then MySQL allows database + directory names with upper case letters. On Windows, all table and + database names in InnoDB are internally always in lower case. Put the + file path to lower case, so that we are consistent with InnoDB's + internal data dictionary. */ + dict_casedn_str(filepath); +#endif file = os_file_create_simple_no_error_handling(filepath, OS_FILE_OPEN, OS_FILE_READ_ONLY, &success); if (!success) { diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index 745a776bda1..3333385ec56 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -26,6 +26,13 @@ Created 1/8/1996 Heikki Tuuri #include "ut0byte.h" #include "trx0types.h" +/********************************************************************** +Makes all characters in a NUL-terminated UTF-8 string lower case. */ + +void +dict_casedn_str( +/*============*/ + char* a); /* in/out: string to put in lower case */ /************************************************************************ Get the database name length in a table name. */ From 2821fa611b435abea0c7445a73376c400917e87e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 03:18:54 +0300 Subject: [PATCH 36/78] sql_repl.cc: Remove printf's from semi-sync code in sql_repl.cc sql/sql_repl.cc: Remove printf's from semi-sync code in sql_repl.cc --- sql/sql_repl.cc | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 72470c487a3..0dcfd985f88 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -385,8 +385,6 @@ impossible position"; goto err; } - printf("Binlog file name %s\n", log_file_name); - if (thd->variables.sync_replication) ha_repl_report_sent_binlog(thd, log_file_name, pos); @@ -537,9 +535,6 @@ impossible position"; goto err; } - printf("Dump loop: %s: Current log position %lu\n", log_file_name, - (ulong)my_b_tell(&log)); - if (thd->variables.sync_replication) ha_repl_report_sent_binlog(thd, log_file_name, my_b_tell(&log)); @@ -656,9 +651,6 @@ impossible position"; goto err; } - printf("Second loop: %s: Current log position %lu\n", log_file_name, - (ulong)my_b_tell(&log)); - if (thd->variables.sync_replication) ha_repl_report_sent_binlog(thd, log_file_name, my_b_tell(&log)); @@ -730,15 +722,12 @@ impossible position"; if (thd->variables.sync_replication) ha_repl_report_sent_binlog(thd, log_file_name, 0); - printf("Binlog file name of a new binlog %s\n", log_file_name); - packet->length(0); packet->append('\0'); } } end: - printf("Ending replication\n"); if (thd->variables.sync_replication) ha_repl_report_replication_stop(thd); @@ -756,8 +745,6 @@ err: if (thd->variables.sync_replication) ha_repl_report_replication_stop(thd); - printf("Ending replication in error %s\n", errmsg); - thd->proc_info = "Waiting to finalize termination"; end_io_cache(&log); /* From 7e04d257eb2f0cf89f07a161e7ac3762366c5da2 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 09:59:12 +0200 Subject: [PATCH 37/78] Bug #9954 mysql-4.1.11/cmd-line-utils/libedit/makelist.sh is not portable - Changed makelist.sh - Bump up required version of autoconf - Use new style to init mutex in my_thr_init cmd-line-utils/libedit/makelist.sh: Changed file so it works also on windows cr/lf files. configure.in: Bump up required AC version number so that correct version of aclocal and autoconf is selected. include/my_pthread.h: Use PTHREAD_MUTEX_ADAPTIVE_NP to see if "fast" mutexes are available Remove "errorcheck" mutexes, since they are never used. mysys/my_thr_init.c: Use new style functions to init mutex if PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP is defined Add comment what mutex "kind" means --- cmd-line-utils/libedit/makelist.sh | 7 ++++--- configure.in | 2 +- include/my_pthread.h | 12 +++--------- mysys/my_thr_init.c | 28 ++++++++++++---------------- 4 files changed, 20 insertions(+), 29 deletions(-) diff --git a/cmd-line-utils/libedit/makelist.sh b/cmd-line-utils/libedit/makelist.sh index b2502d16ed1..502604791f5 100644 --- a/cmd-line-utils/libedit/makelist.sh +++ b/cmd-line-utils/libedit/makelist.sh @@ -68,7 +68,7 @@ case $FLAG in /\(\):/ { pr = substr($2, 1, 2); if (pr == "vi" || pr == "em" || pr == "ed") { - name = substr($2, 1, length($2) - 3); + name = substr($2, 1, index($2,"(") - 1); # # XXX: need a space between name and prototype so that -fc and -fh # parsing is much easier @@ -97,7 +97,7 @@ case $FLAG in /\(\):/ { pr = substr($2, 1, 2); if (pr == "vi" || pr == "em" || pr == "ed") { - name = substr($2, 1, length($2) - 3); + name = substr($2, 1, index($2,"(") - 1); uname = ""; fname = ""; for (i = 1; i <= length(name); i++) { @@ -117,6 +117,7 @@ case $FLAG in printf(" \""); for (i = 2; i < NF; i++) printf("%s ", $i); + sub("\r", "", $i); printf("%s\" },\n", $i); ok = 0; } @@ -219,7 +220,7 @@ case $FLAG in /\(\):/ { pr = substr($2, 1, 2); if (pr == "vi" || pr == "em" || pr == "ed") { - name = substr($2, 1, length($2) - 3); + name = substr($2, 1, index($2, "(") - 1); fname = ""; for (i = 1; i <= length(name); i++) { s = substr(name, i, 1); diff --git a/configure.in b/configure.in index d191463d0f9..87f7033309e 100644 --- a/configure.in +++ b/configure.in @@ -118,7 +118,7 @@ AC_SUBST(SAVE_LDFLAGS) AC_SUBST(SAVE_CXXLDFLAGS) AC_SUBST(CXXLDFLAGS) -AC_PREREQ(2.12)dnl Minimum Autoconf version required. +AC_PREREQ(2.58)dnl Minimum Autoconf version required. #AC_ARG_PROGRAM # Automaticly invoked by AM_INIT_AUTOMAKE AM_SANITY_CHECK diff --git a/include/my_pthread.h b/include/my_pthread.h index f8cd3e0de71..b5b282238ba 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -604,19 +604,13 @@ extern int my_rw_trywrlock(my_rw_lock_t *); #define pthread_attr_setstacksize(A,B) pthread_dummy(0) #endif -/* Define mutex types */ +/* Define mutex types, see my_thr_init.c */ #define MY_MUTEX_INIT_SLOW NULL -#define MY_MUTEX_INIT_FAST NULL -#define MY_MUTEX_INIT_ERRCHK NULL #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP extern pthread_mutexattr_t my_fast_mutexattr; -#undef MY_MUTEX_INIT_FAST #define MY_MUTEX_INIT_FAST &my_fast_mutexattr -#endif -#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP -extern pthread_mutexattr_t my_errchk_mutexattr; -#undef MY_INIT_MUTEX_ERRCHK -#define MY_INIT_MUTEX_ERRCHK &my_errchk_mutexattr +#else +#define MY_MUTEX_INIT_FAST NULL #endif extern my_bool my_thread_global_init(void); diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index 36b37f68b46..93ba34ea5b4 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -40,9 +40,6 @@ pthread_mutex_t LOCK_gethostbyname_r; #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP pthread_mutexattr_t my_fast_mutexattr; #endif -#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP -pthread_mutexattr_t my_errchk_mutexattr; -#endif /* initialize thread environment @@ -62,19 +59,21 @@ my_bool my_thread_global_init(void) fprintf(stderr,"Can't initialize threads: error %d\n",errno); return 1; } + #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP - pthread_mutexattr_init(&my_fast_mutexattr); /* - Note that the following statement may give a compiler warning under - some configurations, but there isn't anything we can do about this as - this is a bug in the header files for the thread implementation + Set mutex type to "fast" a.k.a "adaptive" + + The mutex kind determines what happens if a thread attempts to lock + a mutex it already owns with pthread_mutex_lock(3). If the mutex + is of the ``fast'' kind, pthread_mutex_lock(3) simply suspends + the calling thread forever. If the mutex is of the ``error checking'' + kind, pthread_mutex_lock(3) returns immediately with the error + code EDEADLK. */ - pthread_mutexattr_setkind_np(&my_fast_mutexattr,PTHREAD_MUTEX_ADAPTIVE_NP); -#endif -#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP - pthread_mutexattr_init(&my_errchk_mutexattr); - pthread_mutexattr_setkind_np(&my_errchk_mutexattr, - PTHREAD_MUTEX_ERRORCHECK_NP); + pthread_mutexattr_init(&my_fast_mutexattr); + pthread_mutexattr_settype(&my_fast_mutexattr, + PTHREAD_MUTEX_ADAPTIVE_NP); #endif pthread_mutex_init(&THR_LOCK_malloc,MY_MUTEX_INIT_FAST); @@ -108,9 +107,6 @@ void my_thread_global_end(void) pthread_key_delete(THR_KEY_mysys); #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP pthread_mutexattr_destroy(&my_fast_mutexattr); -#endif -#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP - pthread_mutexattr_destroy(&my_errchk_mutexattr); #endif pthread_mutex_destroy(&THR_LOCK_malloc); pthread_mutex_destroy(&THR_LOCK_open); From ecfae64d65c54004b2330669f141d44e48d4742c Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 11:19:00 +0200 Subject: [PATCH 38/78] Bug #8162 MySQL cannot be compiled without readline - Display error if system readline or libedit can't be found configure.in: Display an error if user has selected not to use the bundled libedit or readline, AND the system readline or libedit can't be found --- configure.in | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index d191463d0f9..7ef68e2098d 100644 --- a/configure.in +++ b/configure.in @@ -2405,17 +2405,24 @@ then compile_readline=yes AC_DEFINE_UNQUOTED(USE_NEW_READLINE_INTERFACE, 1) else + # Use system readline library AC_LANG_SAVE AC_LANG_CPLUSPLUS MYSQL_CHECK_LIBEDIT_INTERFACE MYSQL_CHECK_NEW_RL_INTERFACE MYSQL_CHECK_READLINE_DECLARES_HIST_ENTRY AC_LANG_RESTORE - if [test "$mysql_cv_new_rl_interface" = "yes"] || [test "$mysql_cv_libedit_interface" = "no"] + if [test "$mysql_cv_new_rl_interface" = "yes"] then + # Use the new readline interface readline_link="-lreadline" - else + elif [test "$mysql_cv_libedit_interface" = "yes"]; then + # Use libedit readline_link="-ledit" + else + AC_MSG_ERROR([Could not find system readline or libedit libraries + Use --with-readline or --with-libedit to use the bundled + versions of libedit or readline]) fi fi fi From 072fa90d9e7f5ac4df1fb42054b906b872497113 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 11:25:08 +0200 Subject: [PATCH 39/78] BUG#9714 libsupc++ problem - Remove linking of libsupc++ - Move all local static variables to filescope configure.in: Remove linking with libsupc++ sql/examples/ha_archive.cc: Move local static variables to file scope sql/examples/ha_example.cc: Move local static variables to file scope sql/examples/ha_tina.cc: Move local static variables to file scope sql/ha_berkeley.cc: Move local static variables to file scope sql/ha_blackhole.cc: Move local static variables to file scope sql/ha_federated.cc: Move local static variables to file scope sql/ha_heap.cc: Move local static variables to file scope sql/ha_innodb.cc: Move local static variables to file scope sql/ha_myisam.cc: Move local static variables to file scope sql/ha_myisammrg.cc: Move local static variables to file scope sql/ha_ndbcluster.cc: Move local static variables to file scope sql/item.cc: Move local static instance variables to file scope sql/item_sum.cc: Move local static variables to file scope --- configure.in | 38 +++++++++----------------------------- sql/examples/ha_archive.cc | 13 +++++++++++-- sql/examples/ha_example.cc | 8 +++++++- sql/examples/ha_tina.cc | 9 ++++++++- sql/ha_berkeley.cc | 9 +++++++-- sql/ha_blackhole.cc | 9 ++++++--- sql/ha_federated.cc | 9 ++++----- sql/ha_heap.cc | 7 ++++++- sql/ha_innodb.cc | 9 ++++++--- sql/ha_myisam.cc | 10 +++++++++- sql/ha_myisammrg.cc | 10 +++++++++- sql/ha_ndbcluster.cc | 9 +++++++-- sql/item.cc | 12 ++++++------ sql/item_sum.cc | 14 ++++++++------ 14 files changed, 103 insertions(+), 63 deletions(-) diff --git a/configure.in b/configure.in index ff4527ee09f..a5b9edae877 100644 --- a/configure.in +++ b/configure.in @@ -336,7 +336,7 @@ AC_SUBST(LD) AC_SUBST(INSTALL_SCRIPT) export CC CXX CFLAGS LD LDFLAGS AR - +echo "GXX: $GXX" if test "$GXX" = "yes" then # mysqld requires -fno-implicit-templates. @@ -344,36 +344,16 @@ then # mysqld doesn't use run-time-type-checking, so we disable it. CXXFLAGS="$CXXFLAGS -fno-implicit-templates -fno-exceptions -fno-rtti" - # If you are using 'gcc' 3.0 (not g++) to compile C++ programs on Linux, - # we will gets some problems when linking static programs. - # The following code is used to fix this problem. - + #CXX_VERNO=`echo $CXX_VERSION | sed -e 's/[[^0-9. ]]//g; s/^ *//g; s/ .*//g'` + echo "CXX: $CXX" if echo $CXX | grep gcc > /dev/null 2>&1 then - GCC_VERSION=`gcc -v 2>&1 | grep version | sed -e 's/[[^0-9. ]]//g; s/^ *//g; s/ .*//g'` - case $SYSTEM_TYPE in - *freebsd*) - # The libsupc++ library on freebsd with gcc 3.4.2 is dependent on - # libstdc++, disable it since other solution works fine - GCC_VERSION="NOSUPCPP_$GCC_VERSION" - ;; - *) - ;; - esac - echo "Using gcc version '$GCC_VERSION'" - case "$GCC_VERSION" in - 3.4.*|3.5.*) - # Statically link the language support function's found in libsupc++.a - LIBS="$LIBS -lsupc++" - echo "Using -libsupc++ for static linking with gcc" - ;; - *) - # Using -lsupc++ doesn't work in gcc 3.3 on SuSE 9.2 - # (causes link failures when linking things staticly) - CXXFLAGS="$CXXFLAGS -DUSE_MYSYS_NEW -DDEFINE_CXA_PURE_VIRTUAL" - echo "Using MYSYS_NEW for static linking with gcc" - ;; - esac + echo "Setting CXXFLAGS" + # If you are using 'gcc' 3.0 (not g++) to compile C++ programs on Linux, + # we will gets some problems when linking static programs. + # The following code is used to fix this problem. + CXXFLAGS="$CXXFLAGS -DUSE_MYSYS_NEW -DDEFINE_CXA_PURE_VIRTUAL" + echo "Using MYSYS_NEW for static linking with gcc" fi fi diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index a88bfc0391b..231031c9834 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -431,11 +431,20 @@ int ha_archive::free_share(ARCHIVE_SHARE *share) } -/* +/* We just implement one additional file extension. */ +static const char *ha_archive_exts[] = { + ARZ, + ARN, + ARM, + NullS +}; + const char **ha_archive::bas_ext() const -{ static const char *ext[]= { ARZ, ARN, ARM, NullS }; return ext; } +{ + return ha_archive_exts; +} /* diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc index d043a66e71a..562b51878bf 100644 --- a/sql/examples/ha_example.cc +++ b/sql/examples/ha_example.cc @@ -186,8 +186,14 @@ static int free_share(EXAMPLE_SHARE *share) exist for the storage engine. This is also used by the default rename_table and delete_table method in handler.cc. */ +static const char *ha_example_exts[] = { + NullS +}; + const char **ha_example::bas_ext() const -{ static const char *ext[]= { NullS }; return ext; } +{ + return ha_example_exts; +} /* diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index b515932d25f..9ac446587ec 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -384,8 +384,15 @@ int ha_tina::find_current_row(byte *buf) If frm_error() is called in table.cc this is called to find out what file extensions exist for this handler. */ +static const char *ha_tina_exts[] = { + ".CSV", + NullS +}; + const char **ha_tina::bas_ext() const -{ static const char *ext[]= { ".CSV", NullS }; return ext; } +{ + return ha_tina_exts; +} /* diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 54d9865ddd5..04d81b2f95a 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -371,10 +371,15 @@ void berkeley_cleanup_log_files(void) /***************************************************************************** ** Berkeley DB tables *****************************************************************************/ +static const char *ha_berkeley_exts[] = { + ha_berkeley_ext, + NullS +}; const char **ha_berkeley::bas_ext() const -{ static const char *ext[]= { ha_berkeley_ext, NullS }; return ext; } - +{ + return ha_berkeley_exts; +} ulong ha_berkeley::index_flags(uint idx, uint part, bool all_parts) const { diff --git a/sql/ha_blackhole.cc b/sql/ha_blackhole.cc index e34d5d723a4..d9aedbe751d 100644 --- a/sql/ha_blackhole.cc +++ b/sql/ha_blackhole.cc @@ -25,10 +25,13 @@ #include "ha_blackhole.h" +static const char *ha_black_hole_exts[] = { + NullS +}; + const char **ha_blackhole::bas_ext() const -{ - static const char *ext[]= { NullS }; - return ext; +{ + return ha_blackhole_exts; } int ha_blackhole::open(const char *name, int mode, uint test_if_locked) diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 33acc9cad0b..0ac209d82e0 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -941,14 +941,13 @@ static int free_share(FEDERATED_SHARE *share) also used by the default rename_table and delete_table method in handler.cc. */ +static const char *ha_federated_exts[] = { + NullS +}; const char **ha_federated::bas_ext() const { - static const char *ext[]= - { - NullS - }; - return ext; + return ha_federated_exts; } diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index 0d700f6c9a5..52ff776c5d6 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -26,9 +26,14 @@ /***************************************************************************** ** HEAP tables *****************************************************************************/ +static const char *ha_heap_exts[] = { + NullS +}; const char **ha_heap::bas_ext() const -{ static const char *ext[1]= { NullS }; return ext; } +{ + return ha_heap_exts; +} /* Hash index statistics is updated (copied from HP_KEYDEF::hash_buckets to diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 3f592e36219..4d334c24107 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1863,17 +1863,20 @@ ha_innobase::get_row_type() const /******************************************************************** Gives the file extension of an InnoDB single-table tablespace. */ +static const char* ha_innobase_exts[] = { + ".ibd", + NullS +}; const char** ha_innobase::bas_ext() const /*========================*/ /* out: file extension string */ { - static const char* ext[] = {".ibd", NullS}; - - return(ext); + return ha_innobase_exts; } + /********************************************************************* Normalizes a table name string. A normalized name consists of the database name catenated to '/' and table name. An example: diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 2179eaa7f8f..2049efb73db 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -123,8 +123,16 @@ void mi_check_print_warning(MI_CHECK *param, const char *fmt,...) } +static const char *ha_myisam_exts[] = { + ".MYI", + ".MYD", + NullS +}; + const char **ha_myisam::bas_ext() const -{ static const char *ext[]= { ".MYI",".MYD", NullS }; return ext; } +{ + return ha_myisam_exts; +} const char *ha_myisam::index_type(uint key_number) diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 4cd39660728..5add9478bf4 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -32,8 +32,16 @@ ** MyISAM MERGE tables *****************************************************************************/ +static const char *ha_myisammrg_exts[] = { + ".MRG", + NullS +}; + const char **ha_myisammrg::bas_ext() const -{ static const char *ext[]= { ".MRG", NullS }; return ext; } +{ + return ha_myisammrg_exts; +} + const char *ha_myisammrg::index_type(uint key_number) { diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 020a76b667e..ea73ad224af 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -3062,10 +3062,15 @@ int ha_ndbcluster::extra_opt(enum ha_extra_function operation, ulong cache_size) DBUG_RETURN(extra(operation)); } +static const char *ha_ndbcluster_exts[] = { + ha_ndb_ext, + NullS +}; const char** ha_ndbcluster::bas_ext() const -{ static const char *ext[]= { ha_ndb_ext, NullS }; return ext; } - +{ + return ha_ndbcluster_exts; +} /* How many seeks it will take to read through the table diff --git a/sql/item.cc b/sql/item.cc index 73c8e80228b..57055a9745a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -43,11 +43,11 @@ void Hybrid_type_traits::fix_length_and_dec(Item *item, Item *arg) const item->max_length= item->float_length(arg->decimals); } +static const Hybrid_type_traits real_traits_instance; const Hybrid_type_traits *Hybrid_type_traits::instance() { - static const Hybrid_type_traits real_traits; - return &real_traits; + return &real_traits_instance; } @@ -67,11 +67,11 @@ Hybrid_type_traits::val_str(Hybrid_type *val, String *to, uint8 decimals) const } /* Hybrid_type_traits_decimal */ +static const Hybrid_type_traits_decimal decimal_traits_instance; const Hybrid_type_traits_decimal *Hybrid_type_traits_decimal::instance() { - static const Hybrid_type_traits_decimal decimal_traits; - return &decimal_traits; + return &decimal_traits_instance; } @@ -143,11 +143,11 @@ Hybrid_type_traits_decimal::val_str(Hybrid_type *val, String *to, } /* Hybrid_type_traits_integer */ +static const Hybrid_type_traits_integer integer_traits_instance; const Hybrid_type_traits_integer *Hybrid_type_traits_integer::instance() { - static const Hybrid_type_traits_integer integer_traits; - return &integer_traits; + return &integer_traits_instance; } void diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 64f23c3fc08..3dd4b6618a2 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -506,7 +506,6 @@ Item_sum_distinct::Item_sum_distinct(THD *thd, Item_sum_distinct *original) This is to speedup SUM/AVG(DISTINCT) evaluation for 8-32 bit integer values. */ - struct Hybrid_type_traits_fast_decimal: public Hybrid_type_traits_integer { @@ -521,13 +520,16 @@ struct Hybrid_type_traits_fast_decimal: public val->traits= Hybrid_type_traits_decimal::instance(); val->traits->div(val, u); } - static const Hybrid_type_traits_fast_decimal *instance() - { - static const Hybrid_type_traits_fast_decimal fast_decimal_traits; - return &fast_decimal_traits; - } + static const Hybrid_type_traits_fast_decimal *instance(); }; +static const Hybrid_type_traits_fast_decimal fast_decimal_traits_instance; + +const Hybrid_type_traits_fast_decimal + *Hybrid_type_traits_fast_decimal::instance() +{ + return &fast_decimal_traits_instance; +} void Item_sum_distinct::fix_length_and_dec() { From 2ea24da8497cf433ba2c7685e4e39dc4c713c682 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 13:19:40 +0300 Subject: [PATCH 40/78] ha_innodb.cc: Fix linking and compilation errors sql/ha_innodb.cc: Fix linking and compilation errors --- sql/ha_innodb.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index e68a85bdac9..3aed42f9c38 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1619,7 +1619,7 @@ innobase_report_binlog_offset_and_commit( if (trx->repl_wait_binlog_name == NULL) { trx->repl_wait_binlog_name = - (char*)mem_alloc(FN_REFLEN + 100); + (char*)mem_alloc_noninline(FN_REFLEN + 100); } ut_a(strlen(log_file_name) <= FN_REFLEN + 100); From 3296a12151454e7671bf4288248f551b2082a4ed Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 13:36:58 +0300 Subject: [PATCH 41/78] ha_innodb.cc, mysqld.cc: Fix compilation error if HAVE_REPLICATION is not defined sql/mysqld.cc: Fix compilation error if HAVE_REPLICATION is not defined sql/ha_innodb.cc: Fix compilation error if HAVE_REPLICATION is not defined --- sql/ha_innodb.cc | 22 ++++++++++------------ sql/mysqld.cc | 2 ++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 3aed42f9c38..7d77ae809b1 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1611,6 +1611,7 @@ innobase_report_binlog_offset_and_commit( trx->mysql_log_file_name = log_file_name; trx->mysql_log_offset = (ib_longlong)end_offset; +#ifdef HAVE_REPLICATION if (thd->variables.sync_replication) { /* Let us store the binlog file name and the position, so that we know how long to wait for the binlog to the replicated to @@ -1628,7 +1629,7 @@ innobase_report_binlog_offset_and_commit( trx->repl_wait_binlog_pos = (ib_longlong)end_offset; } - +#endif /* HAVE_REPLICATION */ trx->flush_log_later = TRUE; innobase_commit(thd, trx_handle); @@ -1681,10 +1682,7 @@ innobase_commit_complete( /* out: 0 */ THD* thd) /* in: user thread */ { - struct timespec abstime; trx_t* trx; - int cmp; - int ret; trx = (trx_t*) thd->ha_data[innobase_hton.slot]; @@ -1700,21 +1698,19 @@ innobase_commit_complete( trx_commit_complete_for_mysql(trx); } - printf("Wait binlog name %s, repl state %lu\n", - trx->repl_wait_binlog_name, - (uint)innobase_repl_state); - +#ifdef HAVE_REPLICATION if (thd->variables.sync_replication && trx->repl_wait_binlog_name && innobase_repl_state != 0) { + struct timespec abstime; + int cmp; + int ret; + /* In synchronous replication, let us wait until the MySQL replication has sent the relevant binlog segment to the replication slave. */ -/* TODO: Make sure MySQL uses some way (TCP_NODELAY?) to ensure that the data -has been received in the slave! */ - pthread_mutex_lock(&innobase_repl_cond_mutex); try_again: if (innobase_repl_state == 0) { @@ -1809,10 +1805,11 @@ try_again: goto try_again; } - +#endif HAVE_REPLICATION return(0); } +#ifdef HAVE_REPLICATION /********************************************************************* In synchronous replication, reports to InnoDB up to which binlog position we have sent the binlog to the slave. Note that replication is synchronous @@ -1908,6 +1905,7 @@ innobase_repl_report_sent_binlog( pthread_cond_broadcast(&innobase_repl_cond); } } +#endif /* HAVE_REPLICATION */ /********************************************************************* Rolls back a transaction or the latest SQL statement. */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f1efe0330db..169c9e057b5 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5495,6 +5495,7 @@ The minimum value for this variable is 4096.", {"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default.", (gptr*) &opt_sync_frm, (gptr*) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, +#ifdef HAVE_REPLICATION {"sync-replication", OPT_SYNC_REPLICATION, "Enable synchronous replication.", (gptr*) &global_system_variables.sync_replication, @@ -5510,6 +5511,7 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.sync_replication_timeout, (gptr*) &global_system_variables.sync_replication_timeout, 0, GET_ULONG, REQUIRED_ARG, 10, 0, ~0L, 0, 1, 0}, +#endif /* HAVE_REPLICATION */ {"table_cache", OPT_TABLE_CACHE, "The number of open tables for all threads.", (gptr*) &table_cache_size, (gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, 64, 1, 512*1024L, From f63c8f53b050016c6be6a152ea01b4e17e9ee071 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 12:40:37 +0200 Subject: [PATCH 42/78] Bug#7823 - FLUSH TABLES WITH READ LOCK + INSERT DELAYED = deadlock Added protection against global read lock while creating and initializing a delayed insert handler. Allowed to ignore a global read lock when locking the table inside the delayed insert handler. Added some minor improvements. sql/lock.cc: Bug#7823 - FLUSH TABLES WITH READ LOCK + INSERT DELAYED = deadlock Changed mysql_lock_tables() to allow for ignoring global read lock. Added functions to set/unset protection against global read lock. sql/mysql_priv.h: Bug#7823 - FLUSH TABLES WITH READ LOCK + INSERT DELAYED = deadlock Changed existing and added new function declarations. sql/sql_insert.cc: Bug#7823 - FLUSH TABLES WITH READ LOCK + INSERT DELAYED = deadlock Added and extended some comments. Added a protection against global read lock while a handler is created and initialized. Moved the unlock of the delayed insert object past its last usage in delayed_get_table(). Changed the table locking in handle_delayed_insert() so that it does not wait for global read lock. --- sql/lock.cc | 51 ++++++++++++++++++++++++++++++-- sql/mysql_priv.h | 5 +++- sql/sql_insert.cc | 75 ++++++++++++++++++++++++++++++++++------------- 3 files changed, 108 insertions(+), 23 deletions(-) diff --git a/sql/lock.cc b/sql/lock.cc index c7e6ebfda83..951b0e2ff6a 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -79,7 +79,8 @@ static int unlock_external(THD *thd, TABLE **table,uint count); static void print_lock_error(int error); -MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count) +MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, + bool ignore_global_read_lock) { MYSQL_LOCK *sql_lock; TABLE *write_lock_used; @@ -90,7 +91,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count) if (!(sql_lock = get_lock_data(thd,tables,count, 0,&write_lock_used))) break; - if (global_read_lock && write_lock_used) + if (global_read_lock && write_lock_used && ! ignore_global_read_lock) { /* Someone has issued LOCK ALL TABLES FOR READ and we want a write lock @@ -865,3 +866,49 @@ void make_global_read_lock_block_commit(THD *thd) pthread_mutex_unlock(&LOCK_open); thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT; } + + +/* + Set protection against global read lock. + + SYNOPSIS + set_protect_against_global_read_lock() + void + + RETURN + FALSE OK, no global read lock exists. + TRUE Error, global read lock exists already. +*/ + +my_bool set_protect_against_global_read_lock(void) +{ + my_bool global_read_lock_exists; + + pthread_mutex_lock(&LOCK_open); + if (! (global_read_lock_exists= test(global_read_lock))) + protect_against_global_read_lock++; + pthread_mutex_unlock(&LOCK_open); + return global_read_lock_exists; +} + + +/* + Unset protection against global read lock. + + SYNOPSIS + unset_protect_against_global_read_lock() + void + + RETURN + void +*/ + +void unset_protect_against_global_read_lock(void) +{ + pthread_mutex_lock(&LOCK_open); + protect_against_global_read_lock--; + pthread_mutex_unlock(&LOCK_open); + pthread_cond_broadcast(&COND_refresh); +} + + diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 6281b64bc5e..6a25536b3f1 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -766,7 +766,8 @@ extern pthread_t signal_thread; extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd; #endif /* HAVE_OPENSSL */ -MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **table,uint count); +MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, + bool ignore_global_read_lock= FALSE); void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count); @@ -779,6 +780,8 @@ void unlock_global_read_lock(THD *thd); bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, bool is_not_commit); void start_waiting_global_read_lock(THD *thd); void make_global_read_lock_block_commit(THD *thd); +my_bool set_protect_against_global_read_lock(void); +void unset_protect_against_global_read_lock(void); /* Lock based on name */ int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 0c62a9af7ba..c6b7b1d6c15 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -647,27 +647,42 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) { int error; delayed_insert *tmp; + TABLE *table; DBUG_ENTER("delayed_get_table"); if (!table_list->db) table_list->db=thd->db; - /* no match; create a new thread to handle the table */ + /* Find the thread which handles this table. */ if (!(tmp=find_handler(thd,table_list))) { - /* Don't create more than max_insert_delayed_threads */ + /* + No match. Create a new thread to handle the table, but + no more than max_insert_delayed_threads. + */ if (delayed_insert_threads >= thd->variables.max_insert_delayed_threads) DBUG_RETURN(0); thd->proc_info="Creating delayed handler"; pthread_mutex_lock(&LOCK_delayed_create); - if (!(tmp=find_handler(thd,table_list))) // Was just created + /* + The first search above was done without LOCK_delayed_create. + Another thread might have created the handler in between. Search again. + */ + if (! (tmp= find_handler(thd, table_list))) { + /* + Avoid that a global read lock steps in while we are creating the + new thread. It would block trying to open the table. Hence, the + DI thread and this thread would wait until after the global + readlock is gone. If the read lock exists already, we leave with + no table and then switch to non-delayed insert. + */ + if (set_protect_against_global_read_lock()) + goto err; if (!(tmp=new delayed_insert())) { - thd->fatal_error=1; my_error(ER_OUTOFMEMORY,MYF(0),sizeof(delayed_insert)); - pthread_mutex_unlock(&LOCK_delayed_create); - DBUG_RETURN(0); + goto err1; } pthread_mutex_lock(&LOCK_thread_count); thread_count++; @@ -676,10 +691,8 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) !(tmp->thd.query=my_strdup(table_list->real_name,MYF(MY_WME)))) { delete tmp; - thd->fatal_error=1; my_error(ER_OUT_OF_RESOURCES,MYF(0)); - pthread_mutex_unlock(&LOCK_delayed_create); - DBUG_RETURN(0); + goto err1; } tmp->table_list= *table_list; // Needed to open table tmp->table_list.db= tmp->thd.db; @@ -695,10 +708,8 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) pthread_mutex_unlock(&tmp->mutex); tmp->unlock(); delete tmp; - thd->fatal_error=1; - pthread_mutex_unlock(&LOCK_delayed_create); net_printf(&thd->net,ER_CANT_CREATE_THREAD,error); - DBUG_RETURN(0); + goto err1; } /* Wait until table is open */ @@ -708,6 +719,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) pthread_cond_wait(&tmp->cond_client,&tmp->mutex); } pthread_mutex_unlock(&tmp->mutex); + unset_protect_against_global_read_lock(); thd->proc_info="got old table"; if (tmp->thd.killed) { @@ -719,28 +731,34 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) thd->net.last_errno=tmp->thd.net.last_errno; } tmp->unlock(); - pthread_mutex_unlock(&LOCK_delayed_create); - DBUG_RETURN(0); // Continue with normal insert + goto err; } if (thd->killed) { tmp->unlock(); - pthread_mutex_unlock(&LOCK_delayed_create); - DBUG_RETURN(0); + goto err; } } pthread_mutex_unlock(&LOCK_delayed_create); } pthread_mutex_lock(&tmp->mutex); - TABLE *table=tmp->get_local_table(thd); + table= tmp->get_local_table(thd); pthread_mutex_unlock(&tmp->mutex); - tmp->unlock(); if (table) thd->di=tmp; else if (tmp->thd.fatal_error) thd->fatal_error=1; + /* Unlock the delayed insert object after its last access. */ + tmp->unlock(); DBUG_RETURN((table_list->table=table)); + + err1: + thd->fatal_error= 1; + unset_protect_against_global_read_lock(); + err: + pthread_mutex_unlock(&LOCK_delayed_create); + DBUG_RETURN(0); // Continue with normal insert } @@ -955,6 +973,14 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg) thd->killed=abort_loop; pthread_mutex_unlock(&LOCK_thread_count); + /* + Wait until the client runs into pthread_cond_wait(), + where we free it after the table is opened and di linked in the list. + If we did not wait here, the client might detect the opened table + before it is linked to the list. It would release LOCK_delayed_create + and allow another thread to create another handler for the same table, + since it does not find one in the list. + */ pthread_mutex_lock(&di->mutex); #if !defined( __WIN__) && !defined(OS2) /* Win32 calls this in pthread_create */ if (my_thread_init()) @@ -1069,8 +1095,17 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg) if (di->tables_in_use && ! thd->lock) { - /* request for new delayed insert */ - if (!(thd->lock=mysql_lock_tables(thd,&di->table,1))) + /* + Request for new delayed insert. + Lock the table, but avoid to be blocked by a global read lock. + If we got here while a global read lock exists, then one or more + inserts started before the lock was requested. These are allowed + to complete their work before the server returns control to the + client which requested the global read lock. The delayed insert + handler will close the table and finish when the outstanding + inserts are done. + */ + if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1, TRUE))) { di->dead=thd->killed=1; // Fatal error } From 136839824ef23957418915ea0a96815cc4c20ed9 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 13:43:02 +0300 Subject: [PATCH 43/78] ha_innodb.cc: Correct an assertion sql/ha_innodb.cc: Correct an assertion --- sql/ha_innodb.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 7d77ae809b1..4052ed14259 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1623,7 +1623,7 @@ innobase_report_binlog_offset_and_commit( (char*)mem_alloc_noninline(FN_REFLEN + 100); } - ut_a(strlen(log_file_name) <= FN_REFLEN + 100); + ut_a(strlen(log_file_name) < FN_REFLEN + 100); strcpy(trx->repl_wait_binlog_name, log_file_name); From 78f89a729a962f7a88869a3d5e50ca493391b2a4 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 12:50:37 +0200 Subject: [PATCH 44/78] Bug#9263 GCC4: -mcpu is depricated, use -mtune or -march instead - Made a script that selects the best compiler optimizations for the current cpu. - Use the script from BUILD/SETUP.sh BUILD/SETUP.sh: Run check-cpu and use the compiler optimization flags it outputs --- BUILD/SETUP.sh | 13 +++++---- BUILD/check-cpu | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 5 deletions(-) create mode 100755 BUILD/check-cpu diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index e048ad723ab..8bb281f20e9 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -53,11 +53,14 @@ max_leave_isam_configs="--with-innodb --with-bdb --with-ndbcluster --with-archiv max_no_es_configs="$max_leave_isam_configs --without-isam" max_configs="$max_no_es_configs --with-embedded-server" -alpha_cflags="-mcpu=ev6 -Wa,-mev6" # Not used yet -amd64_cflags="-DBIG_TABLES" -pentium_cflags="-mcpu=pentiumpro" -pentium64_cflags="-mcpu=nocona -m64" -ppc_cflags="-mpowerpc -mcpu=powerpc" +path=`dirname $0` +. "$path/check-cpu" + +alpha_cflags="$check_cpu_cflags -Wa,-m$cpu_flag" +amd64_cflags="$check_cpu_cflags -DBIG_TABLES" +pentium_cflags="$check_cpu_cflags" +pentium64_cflags="$check_cpu_cflags -m64" +ppc_cflags="$check_cpu_cflags" sparc_cflags="" # be as fast as we can be without losing our ability to backtrace diff --git a/BUILD/check-cpu b/BUILD/check-cpu new file mode 100755 index 00000000000..633aa9e8a00 --- /dev/null +++ b/BUILD/check-cpu @@ -0,0 +1,77 @@ +#!/bin/sh +# +# Check cpu of current machine and find the +# best compiler optimization flags for gcc +# +# + +if test -r /proc/cpuinfo ; then + cpuinfo="cat /proc/cpuinfo" + cpu_family=`$cpuinfo | grep 'family' | cut -d ':' -f 2 | cut -d ' ' -f 2 | head -1` + if test -z "$cpu_family" ; then + cpu_family=`$cpuinfo | grep 'cpu' | cut -d ':' -f 2 | cut -d ' ' -f 2 | head -1` + fi + cpu_vendor=`$cpuinfo | grep 'vendor_id' | cut -d ':' -f 2 | cut -d ' ' -f 2 | head -1` + model_name=`$cpuinfo | grep 'model name' | cut -d ':' -f 2 | head -1` + if test -z "$model_name" ; then + model_name=`$cpuinfo | grep 'cpu model' | cut -d ':' -f 2 | head -1` + fi + if test -z "$model_name" ; then + model_name=`uname -m` + fi +else + exit 0 +fi + +case "$cpu_family--$model_name" in + Alpha*EV6*) + cpu_flag="ev6"; + ;; + *Xeon*) + cpu_flag="nocona"; + ;; + *Pentium*4*CPU*) + cpu_flag="pentium4"; + ;; + *Athlon*64*) + cpu_flag="athlon64"; + ;; + *Athlon*) + cpu_flag="athlon"; + ;; + *Itanium*) + # Don't need to set any flags for itanium(at the moment) + cpu_flag=""; + ;; + *ppc) + cpu_flag="powerpc"; + ;; + *) + cpu_flag="i386"; + ;; +esac + +echo "cpu_flag: $cpu_flag" + +if test -z "$CC" ; then + cc="gcc"; +else + cc=$CC + +fi + +cc_ver=`$cc --version | sed 1q` +cc_verno=`echo $cc_ver | sed -e 's/[^0-9. ]//g; s/^ *//g; s/ .*//g'` + +case "$cc_ver--$cc_verno" in + *GCC*--3.4*|*GCC*--3.5*|*GCC*--4.*) + check_cpu_cflags="-mtune=$cpu_flag -march=$cpu_flag" + ;; + *GCC*) + check_cpu_cflags="-mcpu=$cpu_flag -march=$cpu_flag" + ;; + *) + check_cpu_cflags="" + ;; +esac +echo $check_cpu_cflags From ffb4ff245446616f425023256e9fd07204bef000 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 13:29:37 +0200 Subject: [PATCH 45/78] Bug #9954 mysql-4.1.11/cmd-line-utils/libedit/makelist.sh is not portable - Reverted removal of errorcheck mutex initialise, used in safe_mutex_init. include/my_pthread.h: Reverted the removal of errorcheck mutex initializer mysys/my_thr_init.c: Reverted the removal of errorcheck mutex initializer Add destruction of mutex initializer --- include/my_pthread.h | 6 ++++++ mysys/my_thr_init.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/include/my_pthread.h b/include/my_pthread.h index b5b282238ba..fde62655c5f 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -612,6 +612,12 @@ extern pthread_mutexattr_t my_fast_mutexattr; #else #define MY_MUTEX_INIT_FAST NULL #endif +#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP +extern pthread_mutexattr_t my_errorcheck_mutexattr; +#define MY_MUTEX_INIT_ERRCHK &my_errorcheck_mutexattr +#else +#define MY_MUTEX_INIT_ERRCHK NULL +#endif extern my_bool my_thread_global_init(void); extern void my_thread_global_end(void); diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index 93ba34ea5b4..878e1f6bfc6 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -40,6 +40,9 @@ pthread_mutex_t LOCK_gethostbyname_r; #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP pthread_mutexattr_t my_fast_mutexattr; #endif +#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP +pthread_mutexattr_t my_errorcheck_mutexattr; +#endif /* initialize thread environment @@ -75,6 +78,14 @@ my_bool my_thread_global_init(void) pthread_mutexattr_settype(&my_fast_mutexattr, PTHREAD_MUTEX_ADAPTIVE_NP); #endif +#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP + /* + Set mutex type to "errorcheck" a.k.a "adaptive" + */ + pthread_mutexattr_init(&my_errorcheck_mutexattr); + pthread_mutexattr_settype(&my_errorcheck_mutexattr, + PTHREAD_MUTEX_ERRORCHECK); +#endif pthread_mutex_init(&THR_LOCK_malloc,MY_MUTEX_INIT_FAST); pthread_mutex_init(&THR_LOCK_open,MY_MUTEX_INIT_FAST); @@ -107,6 +118,9 @@ void my_thread_global_end(void) pthread_key_delete(THR_KEY_mysys); #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP pthread_mutexattr_destroy(&my_fast_mutexattr); +#endif +#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP + pthread_mutexattr_destroy(&my_errorcheck_mutexattr); #endif pthread_mutex_destroy(&THR_LOCK_malloc); pthread_mutex_destroy(&THR_LOCK_open); From b00b2126de29598aa059a1c4a839f7c7f9ed1011 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 14:31:04 +0300 Subject: [PATCH 46/78] Fixed core dump bug when hot link list in key cache was empty. Bug #10167 mysql-test/r/drop.result: Fixed result --- mysql-test/r/drop.result | 4 +- mysys/mf_keycache.c | 11 +- tests/index_corrupt.pl | 212 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 221 insertions(+), 6 deletions(-) create mode 100755 tests/index_corrupt.pl diff --git a/mysql-test/r/drop.result b/mysql-test/r/drop.result index 40dda86b729..b07cf16aa64 100644 --- a/mysql-test/r/drop.result +++ b/mysql-test/r/drop.result @@ -30,13 +30,13 @@ table7, table8, table9, table10, table11, table12, table13, table14, table15, table16, table17, table18, table19, table20, table21, table22, table23, table24, table25, table26, table27, table28; -ERROR 42S02: Unknown table 'table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table14,table15,table16,table17,table18,table19,table20,table21,table22,table23,table' +ERROR 42S02: Unknown table 'table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table' drop table table1, table2, table3, table4, table5, table6, table7, table8, table9, table10, table11, table12, table13, table14, table15, table16, table17, table18, table19, table20, table21, table22, table23, table24, table25, table26, table27, table28, table29, table30; -ERROR 42S02: Unknown table 'table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table14,table15,table16,table17,table18,table19,table20,table21,table22,table23,table' +ERROR 42S02: Unknown table 'table1,table2,table3,table4,table5,table6,table7,table8,table9,table10,table11,table12,table13,table' use test; drop database mysqltest; flush tables with read lock; diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index 9feaf8dcd57..cee1b7eb4e9 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -1025,8 +1025,8 @@ static void reg_requests(KEY_CACHE *keycache, BLOCK_LINK *block, int count) for a too long time (this time is determined by parameter age_threshold). */ -static inline void unreg_request(KEY_CACHE *keycache, - BLOCK_LINK *block, int at_end) +static void unreg_request(KEY_CACHE *keycache, + BLOCK_LINK *block, int at_end) { if (! --block->requests) { @@ -1045,10 +1045,13 @@ static inline void unreg_request(KEY_CACHE *keycache, } link_block(keycache, block, hot, (my_bool)at_end); block->last_hit_time= keycache->keycache_time; - if (++keycache->keycache_time - keycache->used_ins->last_hit_time > + keycache->keycache_time++; + + block= keycache->used_ins; + /* Check if we should link a hot block to the warm block */ + if (block && keycache->keycache_time - block->last_hit_time > keycache->age_threshold) { - block= keycache->used_ins; unlink_block(keycache, block); link_block(keycache, block, 0, 0); if (block->temperature != BLOCK_WARM) diff --git a/tests/index_corrupt.pl b/tests/index_corrupt.pl new file mode 100755 index 00000000000..19bf54f5d11 --- /dev/null +++ b/tests/index_corrupt.pl @@ -0,0 +1,212 @@ +#!/usr/bin/perl -w +# +# This is a test for a key cache bug (bug #10167) +# To expose the bug mysqld should be started with --key-buffer-size=64K +# + +$opt_loop_count=100000; # Change this to make test harder/easier + +##################### Standard benchmark inits ############################## + +use DBI; +use Getopt::Long; +use Benchmark; + +package main; + +$opt_skip_create=$opt_skip_in=$opt_verbose=$opt_fast_insert= + $opt_lock_tables=$opt_debug=$opt_skip_delete=$opt_fast=$opt_force=0; +$opt_host=$opt_user=$opt_password=""; $opt_db="test"; + +GetOptions("host=s","db=s","loop-count=i","skip-create","skip-in", + "skip-delete","verbose","fast-insert","lock-tables","debug","fast", + "force","user=s","password=s") || die "Aborted"; +$opt_verbose=$opt_debug=$opt_lock_tables=$opt_fast_insert=$opt_fast=$opt_skip_in=$opt_force=undef; # Ignore warnings from these + +$firsttable = "bench_f1"; +$secondtable = "bench_f2"; +$kill_file= "/tmp/mysqltest_index_corrupt.$$"; + +#### +#### Start timeing and start test +#### + +$start_time=new Benchmark; +if (!$opt_skip_create) +{ + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + $dbh->do("drop table if exists $firsttable, $secondtable"); + + print "Creating tables in $opt_db\n"; + $dbh->do("create table $firsttable ( +c_pollid INTEGER NOT NULL, +c_time BIGINT NOT NULL, +c_data DOUBLE NOT NULL, +c_error INTEGER NOT NULL, +c_warning INTEGER NOT NULL, +c_okay INTEGER NOT NULL, +c_unknown INTEGER NOT NULL, +c_rolled_up BIT NOT NULL, +INDEX t_mgmt_hist_r_i1 (c_pollid), +INDEX t_mgmt_hist_r_i2 (c_time), +INDEX t_mgmt_hist_r_i3 (c_rolled_up))") or die $DBI::errstr; + + $dbh->do("create table $secondtable ( +c_pollid INTEGER NOT NULL, +c_min_time BIGINT NOT NULL, +c_max_time BIGINT NOT NULL, +c_min_data DOUBLE NOT NULL, +c_max_data DOUBLE NOT NULL, +c_avg_data DOUBLE NOT NULL, +c_error INTEGER NOT NULL, +c_warning INTEGER NOT NULL, +c_okay INTEGER NOT NULL, +c_unknown INTEGER NOT NULL, +c_rolled_up BIT NOT NULL, +INDEX t_mgmt_hist_d_i1 (c_pollid), +INDEX t_mgmt_hist_d_i2 (c_min_time), +INDEX t_mgmt_hist_d_i3 (c_max_time), +INDEX t_mgmt_hist_d_i4 (c_rolled_up))") or die $DBI::errstr; + + + $dbh->disconnect; $dbh=0; # Close handler +} +$|= 1; # Autoflush + +#### +#### Start the tests +#### + +print "Running tests\n"; +insert_in_bench() if (($pid=fork()) == 0); $work{$pid}="insert"; +select_from_bench() if (($pid=fork()) == 0); $work{$pid}="insert-select; +delete_from_bench() if (($pid=fork()) == 0); $work{$pid}="delete"; + +$errors=0; +while (($pid=wait()) != -1) +{ + $ret=$?/256; + print "thread '" . $work{$pid} . "' finished with exit code $ret\n"; + $errors++ if ($ret != 0); +} + +if (!$opt_skip_delete && !$errors) +{ + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + $dbh->do("drop table $firsttable, $secondtable"); +} +print ($errors ? "Test failed\n" :"Test ok\n"); + +$end_time=new Benchmark; +print "Total time: " . + timestr(timediff($end_time, $start_time),"noc") . "\n"; + +unlink $kill_file; + +exit(0); + +# +# Insert records in the two tables +# + +sub insert_in_bench +{ + my ($dbh,$rows,$found,$i); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + for ($rows= 1; $rows <= $opt_loop_count ; $rows++) + { + $c_pollid = sprintf("%d",rand 1000); + $c_time = sprintf("%d",rand 100000); + $c_data = rand 1000000; + $test = rand 1; + $c_error=0; + $c_warning=0; + $c_okay=0; + $c_unknown=0; + if ($test < .8) { + $c_okay=1; + } elsif ($test <.9) { + $c_error=1; + } elsif ($test <.95) { + $c_warning=1; + } else { + $c_unknown=1; + } + $statement = "INSERT INTO $firsttable (c_pollid, c_time, c_data, c_error +, c_warning, c_okay, c_unknown, c_rolled_up) ". + "VALUES ($c_pollid,$c_time,$c_data,$c_error,$c_warning,$c_okay,$c_unknown,0)"; + $cursor = $dbh->prepare($statement); + $cursor->execute(); + $cursor->finish(); + } + + $dbh->disconnect; $dbh=0; + print "insert_in_bench: Inserted $rows rows\n"; + + # Kill other threads + open(KILLFILE, "> $kill_file"); + close(KILLFILE); + + exit(0); +} + + +sub select_from_bench +{ + my ($dbh,$rows,$cursor); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + for ($rows= 1; $rows < $opt_loop_count ; $rows++) + { + $t_value = rand 100000; + $t_value2 = $t_value+10000; + $statement = "INSERT INTO $secondtable (c_pollid, c_min_time, c_max_time +, c_min_data, c_max_data, c_avg_data, c_error, c_warning, c_okay, c_unknown, c_rolled_up) SELECT c_pollid, MIN(c_time), MAX(c_time), MIN(c_data), MAX(c_data), AVG(c_data), SUM(c_error), SUM(c_warning), SUM(c_okay), SUM(c_unknown), 0 FROM $firsttable WHERE (c_time>=$t_value) AND (c_time<$t_value2) AND (c_rolled_up=0) GROUP BY c_pollid"; + $cursor = $dbh->prepare($statement); + $cursor->execute(); + $cursor->finish(); + sleep 1; + if (-e $kill_file) + { + last; + } + } + print "select_from_bench: insert-select executed $rows times\n"; + exit(0); +} + + +sub delete_from_bench +{ + my ($dbh,$row, $t_value, $t2_value, $statement, $cursor); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + for ($rows= 1; $rows < $opt_loop_count ; $rows++) + { + $t_value = rand 50000; + $t2_value = $t_value + 50001; + $statement = "DELETE FROM $firsttable WHERE (c_time>$t_value) AND (c_time<$t2_value)"; + $cursor = $dbh->prepare($statement); + $cursor->execute(); + $cursor->finish(); + sleep 10; + if (-e $kill_file) + { + last; + } + } + print "delete: delete executed $rows times\n"; + exit(0); +} From 5a720d4e6841b8a03c95a2d251b206cb6e78ac42 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 13:54:42 +0200 Subject: [PATCH 47/78] fix for compile error (Windows) --- sql/item_func.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_func.h b/sql/item_func.h index ba5a6101e4c..77b977fe778 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1318,7 +1318,7 @@ public: longlong val_int() { if (execute(&result_field)) - return 0LL; + return (longlong) 0; return result_field->val_int(); } From 05bfcf65a5b93ec8de46c224c1240695b3bf8165 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 15:09:41 +0300 Subject: [PATCH 48/78] handler.cc: Fix compilation error if HAVE_REPLICATION is not defined sql/handler.cc: Fix compilation error if HAVE_REPLICATION is not defined --- sql/handler.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/handler.cc b/sql/handler.cc index 95fd4d97616..3095aeb9476 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2412,6 +2412,7 @@ TYPELIB *ha_known_exts(void) return &known_extensions; } +#ifdef HAVE_REPLICATION /* Reports to table handlers up to which position we have sent the binlog to a slave in replication @@ -2468,3 +2469,4 @@ int ha_repl_report_replication_stop(THD *thd) return 0; } +#endif /* HAVE_REPLICATION */ From a082303fe147a4d456e845d1c7f901f15cefabc8 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 19:06:47 +0500 Subject: [PATCH 49/78] after-merge fix mysql-test/r/func_math.result: after merge fix: the test should be added after we have new hf's pm code pushed. mysql-test/t/func_math.test: after merge fix: the test should be added after we have new hf's pm code pushed. --- mysql-test/r/func_math.result | 10 ---------- mysql-test/t/func_math.test | 9 --------- 2 files changed, 19 deletions(-) diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index 9cb1e4a56d6..005f41f7063 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -127,13 +127,3 @@ Warnings: Note 1003 select degrees(pi()) AS `degrees(pi())`,radians(360) AS `radians(360)` select rand(rand); ERROR 42S22: Unknown column 'rand' in 'field list' -create table t1 select round(1, 6); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `round(1, 6)` double(7,6) NOT NULL default '0.000000' -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -select * from t1; -round(1, 6) -1.000000 -drop table t1; diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index 4c24dae8c5d..33b672e42b5 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -62,12 +62,3 @@ explain extended select degrees(pi()),radians(360); --error 1054 select rand(rand); - -# -# Bug #9837: problem with round() -# - -create table t1 select round(1, 6); -show create table t1; -select * from t1; -drop table t1; From 0e1e0ddf23a9aa89ee89022bd018f3eb47e84d86 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 17:16:08 +0300 Subject: [PATCH 50/78] mysqladmin extended-status now displays global status Fixed problem with NULL in VARCHAR/BLOB keys for multi-part keys where VARCHAR/BLOB is first part client/mysqladmin.cc: Show GLOBAL status myisam/mi_key.c: Fixed problem with NULL in VARCHAR/BLOB keys for multi-part keys where VARCHAR/BLOB is first part (Ramil will soon push test cases) sql/handler.cc: Indentation fix tests/mysql_client_test.c: Portability fixes --- client/mysqladmin.cc | 2 +- myisam/mi_key.c | 3 +++ sql/handler.cc | 7 ++++--- tests/mysql_client_test.c | 7 ++++--- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc index 24fe14b6675..c6274e499ab 100644 --- a/client/mysqladmin.cc +++ b/client/mysqladmin.cc @@ -727,7 +727,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) void (*func) (MYSQL_RES*, MYSQL_ROW, uint); new_line = 1; - if (mysql_query(mysql, "show status") || + if (mysql_query(mysql, "show /*!50002 GLOBAL */ status") || !(res = mysql_store_result(mysql))) { my_printf_error(0, "unable to show status; error: '%s'", MYF(ME_BELL), diff --git a/myisam/mi_key.c b/myisam/mi_key.c index ab5ddd3a378..d7d10e116aa 100644 --- a/myisam/mi_key.c +++ b/myisam/mi_key.c @@ -242,7 +242,10 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old, { k_length-=length; if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) + { k_length-=2; /* Skip length */ + old+= 2; + } continue; /* Found NULL */ } } diff --git a/sql/handler.cc b/sql/handler.cc index dc63b4b038f..50f82eb5753 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -175,9 +175,10 @@ enum db_type ha_checktype(enum db_type database_type) return ((enum db_type) thd->variables.table_type != DB_TYPE_UNKNOWN ? (enum db_type) thd->variables.table_type : - (enum db_type) global_system_variables.table_type != - DB_TYPE_UNKNOWN ? - (enum db_type) global_system_variables.table_type : DB_TYPE_MYISAM); + ((enum db_type) global_system_variables.table_type != + DB_TYPE_UNKNOWN ? + (enum db_type) global_system_variables.table_type : DB_TYPE_MYISAM) + ); } /* ha_checktype */ diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 2dd5fda6f05..ae000a4273d 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -7046,6 +7046,7 @@ static void test_set_option() bug #89 (reported by mark@mysql.com) */ +#ifndef EMBEDDED_LIBRARY static void test_prepare_grant() { int rc; @@ -7138,7 +7139,7 @@ static void test_prepare_grant() } } - +#endif /* Test a crash when invalid/corrupted .frm is used in the @@ -12598,7 +12599,7 @@ static void test_bug8330() const char *stmt_text; MYSQL_STMT *stmt[2]; int i, rc; - char *query= "select a,b from t1 where a=?"; + const char *query= "select a,b from t1 where a=?"; MYSQL_BIND bind[2]; long lval[2]; @@ -12789,7 +12790,7 @@ static void test_bug8722() } -MYSQL_STMT *open_cursor(char *query) +MYSQL_STMT *open_cursor(const char *query) { int rc; const ulong type= (ulong)CURSOR_TYPE_READ_ONLY; From 5c44e1acfeebe5e49b32add9a4a19aaf33892455 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 16:35:49 +0200 Subject: [PATCH 51/78] Post-review fixes of the patch for BUG#8408: Stored procedure crash if function contains SHOW (Review on irc by monty) mysql-test/r/sp-error.result: Renamed a procedure and function to avoid confusion mysql-test/t/sp-error.test: Renamed a procedure and function to avoid confusion sql/item_func.cc: Corrected (and better) way to set/reset the client cap. flag in Item_func_sp::execute() sql/share/errmsg.txt: Changed the ER_SP_BADSELECT error; more accurate, and includes the procedure name. sql/sql_parse.cc: Include the procedure name in the new error message. --- mysql-test/r/sp-error.result | 20 ++++++++++---------- mysql-test/t/sp-error.test | 23 ++++++++++++----------- sql/item_func.cc | 10 ++++------ sql/share/errmsg.txt | 2 +- sql/sql_parse.cc | 2 +- 5 files changed, 28 insertions(+), 29 deletions(-) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index a2478343806..683f3e12091 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -594,8 +594,6 @@ alter function bug7047; return 0; end| ERROR HY000: Can't drop or alter a FUNCTION from within another stored routine -drop function if exists bug8408| -drop procedure if exists bug8408| create function bug8408() returns int begin select * from t1; @@ -615,19 +613,21 @@ select b; return b; end| ERROR 0A000: Not allowed to return a result set from a function -create function bug8408() returns int +drop function if exists bug8408_f| +drop procedure if exists bug8408_p| +create function bug8408_f() returns int begin -call bug8408(); +call bug8408_p(); return 0; end| -create procedure bug8408() +create procedure bug8408_p() select * from t1| -call bug8408()| +call bug8408_p()| val x -select bug8408()| -ERROR 0A000: SELECT in a stored procedure must have INTO -drop procedure bug8408| -drop function bug8408| +select bug8408_f()| +ERROR 0A000: PROCEDURE test.bug8408_p can't return a result set in the given context +drop procedure bug8408_p| +drop function bug8408_f| create function bug8408() returns int begin declare n int default 0; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index b2d24167e49..ff317b4ac28 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -835,10 +835,6 @@ end| # BUG#8408: Stored procedure crash if function contains SHOW # BUG#9058: Stored Procedures: Crash if function included SELECT # ---disable_warnings -drop function if exists bug8408| -drop procedure if exists bug8408| ---enable_warnings # Some things are caught when parsing --error ER_SP_NO_RETSET_IN_FUNC @@ -861,21 +857,26 @@ begin return b; end| +--disable_warnings +drop function if exists bug8408_f| +drop procedure if exists bug8408_p| +--enable_warnings + # Some things must be caught at invokation time -create function bug8408() returns int +create function bug8408_f() returns int begin - call bug8408(); + call bug8408_p(); return 0; end| -create procedure bug8408() +create procedure bug8408_p() select * from t1| -call bug8408()| +call bug8408_p()| --error ER_SP_BADSELECT -select bug8408()| +select bug8408_f()| -drop procedure bug8408| -drop function bug8408| +drop procedure bug8408_p| +drop function bug8408_f| # But this is ok create function bug8408() returns int diff --git a/sql/item_func.cc b/sql/item_func.cc index 3472c0ab786..24a3f7927ae 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4554,7 +4554,7 @@ Item_func_sp::execute(Item **itp) { DBUG_ENTER("Item_func_sp::execute"); THD *thd= current_thd; - bool clcap_mr; + ulong old_client_capabilites; int res; #ifndef NO_EMBEDDED_ACCESS_CHECKS st_sp_security_context save_ctx; @@ -4568,7 +4568,7 @@ Item_func_sp::execute(Item **itp) DBUG_RETURN(-1); } - clcap_mr= (thd->client_capabilities & CLIENT_MULTI_RESULTS); + old_client_capabilites= thd->client_capabilities; thd->client_capabilities &= ~CLIENT_MULTI_RESULTS; #ifndef EMBEDDED_LIBRARY @@ -4586,8 +4586,7 @@ Item_func_sp::execute(Item **itp) m_sp->m_db.str, m_sp->m_name.str, 0)) { sp_restore_security_context(thd, m_sp, &save_ctx); - if (clcap_mr) - thd->client_capabilities |= CLIENT_MULTI_RESULTS; + thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS; DBUG_RETURN(-1); } #endif @@ -4602,8 +4601,7 @@ Item_func_sp::execute(Item **itp) thd->net.no_send_ok= nsok; #endif - if (clcap_mr) - thd->client_capabilities |= CLIENT_MULTI_RESULTS; + thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS; DBUG_RETURN(res); } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 66986a884b3..3a311ff7917 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5090,7 +5090,7 @@ ER_SP_LABEL_MISMATCH 42000 ER_SP_UNINIT_VAR 01000 eng "Referring to uninitialized variable %s" ER_SP_BADSELECT 0A000 - eng "SELECT in a stored procedure must have INTO" + eng "PROCEDURE %s can't return a result set in the given context" ER_SP_BADRETURN 42000 eng "RETURN is only allowed in a FUNCTION" ER_SP_BADSTATEMENT 0A000 diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c5ef9f4e713..ccba268e18e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4052,7 +4052,7 @@ unsent_create_error: { if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS)) { - my_message(ER_SP_BADSELECT, ER(ER_SP_BADSELECT), MYF(0)); + my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str); #ifndef EMBEDDED_LIBRARY thd->net.no_send_ok= nsok; #endif From cd50bf9ae4407e856a5cb4263512013a24cff5b7 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 17:52:14 +0200 Subject: [PATCH 52/78] After review fix BUILD/check-cpu: Remove defaul flag i386 and add a check to see wheter to set check_cpu_cflags or not. --- BUILD/check-cpu | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/BUILD/check-cpu b/BUILD/check-cpu index 633aa9e8a00..b5c14e38403 100755 --- a/BUILD/check-cpu +++ b/BUILD/check-cpu @@ -47,10 +47,16 @@ case "$cpu_family--$model_name" in cpu_flag="powerpc"; ;; *) - cpu_flag="i386"; + cpu_flag=""; ;; esac +if test -z "$cpu_flag"; then + echo "BUILD/check-cpu: Oops, could not findout what kind of cpu this machine is using." + check_cpu_flags="" + return +fi + echo "cpu_flag: $cpu_flag" if test -z "$CC" ; then From 27a6a8146417829d9edfcb8fb86306f985e03bd2 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 18:17:41 +0200 Subject: [PATCH 53/78] Fix for avoiding gettin Invalid schema object version when doing local changes --- mysql-test/r/ndb_multi.result | 22 +++++++++++- mysql-test/t/ndb_multi.test | 24 +++++++++++++ ndb/include/ndbapi/NdbDictionary.hpp | 5 ++- ndb/src/ndbapi/NdbDictionaryImpl.cpp | 11 +++--- sql/ha_ndbcluster.cc | 54 +++++++++++++++++++++------- sql/ha_ndbcluster.h | 4 +-- 6 files changed, 99 insertions(+), 21 deletions(-) diff --git a/mysql-test/r/ndb_multi.result b/mysql-test/r/ndb_multi.result index 5696fda1c07..2080be241e8 100644 --- a/mysql-test/r/ndb_multi.result +++ b/mysql-test/r/ndb_multi.result @@ -13,6 +13,26 @@ a show status like 'handler_discover%'; Variable_name Value Handler_discover 0 +select * from t1; +a +2 +drop table t1; +create table t1 (a int) engine=ndbcluster; +insert into t1 value (2); +select * from t1; +a +2 +show status like 'handler_discover%'; +Variable_name Value +Handler_discover 0 +drop table t1; +create table t1 (a int) engine=ndbcluster; +insert into t1 value (2); +select * from t1; +ERROR HY000: Got error 241 'Invalid schema object version' from ndbcluster +select * from t1; +a +2 flush status; select * from t1; a @@ -20,7 +40,7 @@ a update t1 set a=3 where a=2; show status like 'handler_discover%'; Variable_name Value -Handler_discover 1 +Handler_discover 0 create table t3 (a int not null primary key, b varchar(22), c int, last_col text) engine=ndb; insert into t3 values(1, 'Hi!', 89, 'Longtext column'); diff --git a/mysql-test/t/ndb_multi.test b/mysql-test/t/ndb_multi.test index 24651913a79..85950c72cf9 100644 --- a/mysql-test/t/ndb_multi.test +++ b/mysql-test/t/ndb_multi.test @@ -18,6 +18,30 @@ select * from t1; select * from t2; show status like 'handler_discover%'; +# Check dropping and recreating table on same server +connect (con1,localhost,,,test); +connect (con2,localhost,,,test); +connection con1; +select * from t1; +connection con2; +drop table t1; +create table t1 (a int) engine=ndbcluster; +insert into t1 value (2); +connection con1; +select * from t1; + +# Check dropping and recreating table on different server +connection server2; +show status like 'handler_discover%'; +drop table t1; +create table t1 (a int) engine=ndbcluster; +insert into t1 value (2); +connection server1; +# Currently a retry is required remotely +--error 1296 +select * from t1; +select * from t1; + # Connect to server2 and use the tables from there connection server2; flush status; diff --git a/ndb/include/ndbapi/NdbDictionary.hpp b/ndb/include/ndbapi/NdbDictionary.hpp index 6aa675a2319..0e4f506c604 100644 --- a/ndb/include/ndbapi/NdbDictionary.hpp +++ b/ndb/include/ndbapi/NdbDictionary.hpp @@ -75,8 +75,11 @@ public: Changed, ///< The object has been modified in memory ///< and has to be commited in NDB Kernel for ///< changes to take effect - Retrieved ///< The object exist and has been read + Retrieved, ///< The object exist and has been read ///< into main memory from NDB Kernel + Invalid ///< The object has been invalidated + ///< and should not be used + }; /** diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index fb2e0d673cd..4523ae2c261 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -1448,6 +1448,7 @@ int NdbDictionaryImpl::alterTable(NdbTableImpl &impl) // If in local cache it must be in global if (!cachedImpl) abort(); + cachedImpl->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(cachedImpl); m_globalHash->unlock(); } @@ -1747,8 +1748,8 @@ NdbDictionaryImpl::dropTable(const char * name) DBUG_PRINT("info",("INCOMPATIBLE_VERSION internal_name: %s", internalTableName)); m_localHash.drop(internalTableName); - m_globalHash->lock(); + tab->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(tab); m_globalHash->unlock(); DBUG_RETURN(dropTable(name)); @@ -1792,10 +1793,11 @@ NdbDictionaryImpl::dropTable(NdbTableImpl & impl) int ret = m_receiver.dropTable(impl); if(ret == 0 || m_error.code == 709){ const char * internalTableName = impl.m_internalName.c_str(); + m_localHash.drop(internalTableName); - m_globalHash->lock(); + impl.m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(&impl); m_globalHash->unlock(); @@ -1889,6 +1891,7 @@ NdbDictionaryImpl::invalidateObject(NdbTableImpl & impl) m_localHash.drop(internalTableName); m_globalHash->lock(); + impl.m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(&impl); m_globalHash->unlock(); return 0; @@ -2152,8 +2155,8 @@ NdbDictionaryImpl::dropIndex(const char * indexName, m_ndb.internalizeTableName(indexName); // Index is also a table m_localHash.drop(internalIndexName); - m_globalHash->lock(); + idx->m_table->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(idx->m_table); m_globalHash->unlock(); return dropIndex(indexName, tableName); @@ -2187,8 +2190,8 @@ NdbDictionaryImpl::dropIndex(NdbIndexImpl & impl, const char * tableName) int ret = m_receiver.dropIndex(impl, *timpl); if(ret == 0){ m_localHash.drop(internalIndexName); - m_globalHash->lock(); + impl.m_table->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(impl.m_table); m_globalHash->unlock(); } diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 8c12cccf5ee..0d6bfcb9d0d 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -331,11 +331,14 @@ void ha_ndbcluster::no_uncommitted_rows_reset(THD *thd) # The mapped error code */ -void ha_ndbcluster::invalidateDictionaryCache() +void ha_ndbcluster::invalidate_dictionary_cache(bool global) { NDBDICT *dict= get_ndb()->getDictionary(); DBUG_PRINT("info", ("invalidating %s", m_tabname)); - dict->invalidateTable(m_tabname); + if (global) + dict->invalidateTable(m_tabname); + else + dict->removeCachedTable(m_tabname); table->version=0L; /* Free when thread is ready */ /* Invalidate indexes */ for (uint i= 0; i < table->keys; i++) @@ -347,12 +350,21 @@ void ha_ndbcluster::invalidateDictionaryCache() switch(idx_type) { case(PRIMARY_KEY_ORDERED_INDEX): case(ORDERED_INDEX): - dict->invalidateIndex(index->getName(), m_tabname); + if (global) + dict->invalidateIndex(index->getName(), m_tabname); + else + dict->removeCachedIndex(index->getName(), m_tabname); break; case(UNIQUE_ORDERED_INDEX): - dict->invalidateIndex(index->getName(), m_tabname); + if (global) + dict->invalidateIndex(index->getName(), m_tabname); + else + dict->removeCachedIndex(index->getName(), m_tabname); case(UNIQUE_INDEX): - dict->invalidateIndex(unique_index->getName(), m_tabname); + if (global) + dict->invalidateIndex(unique_index->getName(), m_tabname); + else + dict->removeCachedIndex(unique_index->getName(), m_tabname); break; case(PRIMARY_KEY_INDEX): case(UNDEFINED_INDEX): @@ -371,7 +383,7 @@ int ha_ndbcluster::ndb_err(NdbConnection *trans) switch (err.classification) { case NdbError::SchemaError: { - invalidateDictionaryCache(); + invalidate_dictionary_cache(TRUE); if (err.code==284) { @@ -767,7 +779,13 @@ int ha_ndbcluster::get_metadata(const char *path) if (!(tab= dict->getTable(m_tabname))) ERR_RETURN(dict->getNdbError()); - DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); + if (tab->getObjectStatus() == NdbDictionary::Object::Invalid) + { + invalidate_dictionary_cache(FALSE); + if (!(tab= dict->getTable(m_tabname))) + ERR_RETURN(dict->getNdbError()); + DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); + } /* Compare FrmData in NDB with frm file from disk. */ @@ -786,7 +804,7 @@ int ha_ndbcluster::get_metadata(const char *path) if (!invalidating_ndb_table) { DBUG_PRINT("info", ("Invalidating table")); - invalidateDictionaryCache(); + invalidate_dictionary_cache(TRUE); invalidating_ndb_table= TRUE; } else @@ -812,7 +830,7 @@ int ha_ndbcluster::get_metadata(const char *path) if (error) DBUG_RETURN(error); - m_tableVersion= tab->getObjectVersion(); + m_table_version= tab->getObjectVersion(); m_table= (void *)tab; m_table_info= NULL; // Set in external lock @@ -3226,15 +3244,25 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) void *tab_info; if (!(tab= dict->getTable(m_tabname, &tab_info))) ERR_RETURN(dict->getNdbError()); - DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); - if (m_table != (void *)tab || m_tableVersion != tab->getObjectVersion()) + DBUG_PRINT("info", ("Table schema version: %d", + tab->getObjectVersion())); + // Check if thread has stale local cache + if (tab->getObjectStatus() == NdbDictionary::Object::Invalid) + { + invalidate_dictionary_cache(FALSE); + if (!(tab= dict->getTable(m_tabname))) + ERR_RETURN(dict->getNdbError()); + DBUG_PRINT("info", ("Table schema version: %d", + tab->getObjectVersion())); + } + if (m_table != (void *)tab || m_table_version < tab->getObjectVersion()) { /* The table has been altered, refresh the index list */ build_index_list(ndb, table, ILBP_OPEN); m_table= (void *)tab; - m_tableVersion = tab->getObjectVersion(); + m_table_version = tab->getObjectVersion(); } m_table_info= tab_info; } @@ -4006,7 +4034,7 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg): m_active_trans(NULL), m_active_cursor(NULL), m_table(NULL), - m_tableVersion(-1), + m_table_version(-1), m_table_info(NULL), m_table_flags(HA_REC_NOT_IN_SEQ | HA_NULL_IN_KEY | diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index ac2d27b9ec7..7de5dd503e7 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -203,7 +203,7 @@ class ha_ndbcluster: public handler void print_results(); longlong get_auto_increment(); - void invalidateDictionaryCache(); + void invalidate_dictionary_cache(bool global); int ndb_err(NdbConnection*); bool uses_blob_value(bool all_fields); @@ -215,7 +215,7 @@ class ha_ndbcluster: public handler NdbConnection *m_active_trans; NdbResultSet *m_active_cursor; void *m_table; - int m_tableVersion; + int m_table_version; void *m_table_info; char m_dbname[FN_HEADLEN]; //char m_schemaname[FN_HEADLEN]; From 4bbbba02c21020a3daae71f81dd990de639175cf Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 10:01:41 -0700 Subject: [PATCH 54/78] Carry over change to fix build on ICC that was lost in merge from 4.1. config/ac-macros/misc.m4: Try exit-related declarations before including stdlib.h, as this is how the actual code is structured. --- config/ac-macros/misc.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/ac-macros/misc.m4 b/config/ac-macros/misc.m4 index 201702e5379..d75dedafa2a 100644 --- a/config/ac-macros/misc.m4 +++ b/config/ac-macros/misc.m4 @@ -646,8 +646,8 @@ m4_define([_AC_PROG_CXX_EXIT_DECLARATION], 'void exit (int);' \ '#include ' do - _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([@%:@include -$ac_declaration], + _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([$ac_declaration +@%:@include ], [exit (42);])], [], [continue]) From 3238612840467f6edc8aab676f31940fc731bff7 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 20:54:19 +0200 Subject: [PATCH 55/78] Bug#7823 - FLUSH TABLES WITH READ LOCK + INSERT DELAYED = deadlock After merge fix. --- sql/sql_insert.cc | 75 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 20 deletions(-) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 7f890a583c6..31393b2173a 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -851,27 +851,42 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) { int error; delayed_insert *tmp; + TABLE *table; DBUG_ENTER("delayed_get_table"); if (!table_list->db) table_list->db=thd->db; - /* no match; create a new thread to handle the table */ + /* Find the thread which handles this table. */ if (!(tmp=find_handler(thd,table_list))) { - /* Don't create more than max_insert_delayed_threads */ + /* + No match. Create a new thread to handle the table, but + no more than max_insert_delayed_threads. + */ if (delayed_insert_threads >= thd->variables.max_insert_delayed_threads) DBUG_RETURN(0); thd->proc_info="Creating delayed handler"; pthread_mutex_lock(&LOCK_delayed_create); - if (!(tmp=find_handler(thd,table_list))) // Was just created + /* + The first search above was done without LOCK_delayed_create. + Another thread might have created the handler in between. Search again. + */ + if (! (tmp= find_handler(thd, table_list))) { + /* + Avoid that a global read lock steps in while we are creating the + new thread. It would block trying to open the table. Hence, the + DI thread and this thread would wait until after the global + readlock is gone. If the read lock exists already, we leave with + no table and then switch to non-delayed insert. + */ + if (set_protect_against_global_read_lock()) + goto err; if (!(tmp=new delayed_insert())) { - thd->fatal_error(); my_error(ER_OUTOFMEMORY,MYF(0),sizeof(delayed_insert)); - pthread_mutex_unlock(&LOCK_delayed_create); - DBUG_RETURN(0); + goto err1; } pthread_mutex_lock(&LOCK_thread_count); thread_count++; @@ -880,10 +895,8 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) !(tmp->thd.query=my_strdup(table_list->real_name,MYF(MY_WME)))) { delete tmp; - thd->fatal_error(); my_error(ER_OUT_OF_RESOURCES,MYF(0)); - pthread_mutex_unlock(&LOCK_delayed_create); - DBUG_RETURN(0); + goto err1; } tmp->table_list= *table_list; // Needed to open table tmp->table_list.db= tmp->thd.db; @@ -899,10 +912,8 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) pthread_mutex_unlock(&tmp->mutex); tmp->unlock(); delete tmp; - thd->fatal_error(); - pthread_mutex_unlock(&LOCK_delayed_create); net_printf(thd,ER_CANT_CREATE_THREAD,error); - DBUG_RETURN(0); + goto err1; } /* Wait until table is open */ @@ -912,6 +923,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) pthread_cond_wait(&tmp->cond_client,&tmp->mutex); } pthread_mutex_unlock(&tmp->mutex); + unset_protect_against_global_read_lock(); thd->proc_info="got old table"; if (tmp->thd.killed) { @@ -923,28 +935,34 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) thd->net.last_errno=tmp->thd.net.last_errno; } tmp->unlock(); - pthread_mutex_unlock(&LOCK_delayed_create); - DBUG_RETURN(0); // Continue with normal insert + goto err; } if (thd->killed) { tmp->unlock(); - pthread_mutex_unlock(&LOCK_delayed_create); - DBUG_RETURN(0); + goto err; } } pthread_mutex_unlock(&LOCK_delayed_create); } pthread_mutex_lock(&tmp->mutex); - TABLE *table=tmp->get_local_table(thd); + table=tmp->get_local_table(thd); pthread_mutex_unlock(&tmp->mutex); - tmp->unlock(); if (table) thd->di=tmp; else if (tmp->thd.is_fatal_error) thd->fatal_error(); + /* Unlock the delayed insert object after its last access. */ + tmp->unlock(); DBUG_RETURN((table_list->table=table)); + + err1: + thd->fatal_error(); + unset_protect_against_global_read_lock(); + err: + pthread_mutex_unlock(&LOCK_delayed_create); + DBUG_RETURN(0); // Continue with normal insert } @@ -1165,6 +1183,14 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg) thd->killed=abort_loop; pthread_mutex_unlock(&LOCK_thread_count); + /* + Wait until the client runs into pthread_cond_wait(), + where we free it after the table is opened and di linked in the list. + If we did not wait here, the client might detect the opened table + before it is linked to the list. It would release LOCK_delayed_create + and allow another thread to create another handler for the same table, + since it does not find one in the list. + */ pthread_mutex_lock(&di->mutex); #if !defined( __WIN__) && !defined(OS2) /* Win32 calls this in pthread_create */ if (my_thread_init()) @@ -1279,8 +1305,17 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg) if (di->tables_in_use && ! thd->lock) { - /* request for new delayed insert */ - if (!(thd->lock=mysql_lock_tables(thd,&di->table,1))) + /* + Request for new delayed insert. + Lock the table, but avoid to be blocked by a global read lock. + If we got here while a global read lock exists, then one or more + inserts started before the lock was requested. These are allowed + to complete their work before the server returns control to the + client which requested the global read lock. The delayed insert + handler will close the table and finish when the outstanding + inserts are done. + */ + if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1, TRUE))) { di->dead= 1; // Some fatal error thd->killed= 1; From cde34dfbf3721769894f60eb430bdf6034ebc3b9 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 22:02:26 +0200 Subject: [PATCH 56/78] Little different behaviour in 5.0 and merge with new tests required these changes mysql-test/r/archive.result: Changed order of tests so that the are before the unpredictable INSERT DELAYED Warning is produced during the rename mysql-test/t/archive.test: Changed order of tests so that the are before the unpredictable INSERT DELAYED Warning is produced during the rename --- mysql-test/r/archive.result | 30 ++++++++++++++++-------------- mysql-test/t/archive.test | 24 +++++++++++++----------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index c05f7a60e99..793e50cf653 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -184,6 +184,22 @@ fld1 fld3 250503 heaving 250504 population 250505 bomb +create table t3 engine=archive select * from t2; +select * from t3 where fld3='bonfire'; +auto fld1 companynr fld3 fld4 fld5 fld6 +1191 068504 00 bonfire corresponds positively +select count(*) from t3; +count(*) +1199 +rename table t3 to t4; +Warnings: +Error 7 Error on rename of './test/t3.ARN' to './test/t4.ARN' (Errcode: 2) +select * from t4 where fld3='bonfire'; +auto fld1 companynr fld3 fld4 fld5 fld6 +1191 068504 00 bonfire corresponds positively +select count(*) from t4; +count(*) +1199 INSERT INTO t2 VALUES (1,000001,00,'Omaha','teethe','neat',''); INSERT INTO t2 VALUES (2,011401,37,'breaking','dreaded','Steinberg','W'); INSERT INTO t2 VALUES (3,011402,37,'Romans','scholastics','jarring',''); @@ -5020,18 +5036,4 @@ auto fld1 companynr fld3 fld4 fld5 fld6 3 011402 37 Romans scholastics jarring 4 011403 37 intercepted audiology tinily INSERT DELAYED INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); -create table t3 engine=archive select * from t2; -select * from t3 where fld3='bonfire'; -auto fld1 companynr fld3 fld4 fld5 fld6 -1191 068504 00 bonfire corresponds positively -select count(*) from t3; -count(*) -1203 -rename table t3 to t4; -select * from t4 where fld3='bonfire'; -auto fld1 companynr fld3 fld4 fld5 fld6 -1191 068504 00 bonfire corresponds positively -select count(*) from t4; -count(*) -1203 drop table t1, t2, t4; diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index 9d027e65c49..9d25524da5f 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1289,6 +1289,18 @@ select fld3 from t2 where (fld3 like "C%" and fld3 = "Chantilly"); select fld1,fld3 from t2 where fld1 like "25050%"; select fld1,fld3 from t2 where fld1 like "25050_"; + +# +# Test rename of table +# +create table t3 engine=archive select * from t2; +select * from t3 where fld3='bonfire'; +select count(*) from t3; +rename table t3 to t4; +select * from t4 where fld3='bonfire'; +select count(*) from t4; + + # # Test for insert after select # @@ -1308,19 +1320,9 @@ INSERT INTO t2 VALUES (1,000001,00,'Omaha','teethe','neat','') , (2,011401,37,'b SELECT * FROM t2; # Just test syntax, we will never know if the out put is right or wrong +# Must be the last test INSERT DELAYED INTO t2 VALUES (4,011403,37,'intercepted','audiology','tinily',''); # # Cleanup, test is over # - -# -# Test rename of table -# -create table t3 engine=archive select * from t2; -select * from t3 where fld3='bonfire'; -select count(*) from t3; -rename table t3 to t4; -select * from t4 where fld3='bonfire'; -select count(*) from t4; - drop table t1, t2, t4; From a1b0139fe7bfcd65312b07d267d40761eac1ca67 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 22:20:58 +0200 Subject: [PATCH 57/78] BUG#9911 RENAME TABLE of type ARCHIVE fails with .ARN file error - Different behaviuor in 5.0 pushes a warning when renaming a non existent file. Avoid that by checking that the file exists before renaming. mysql-test/r/archive.result: Warning is not produced anymore sql/examples/ha_archive.cc: Change ha_archive::rename_table to avoid warning when trying to rename non existent file. --- mysql-test/r/archive.result | 2 -- sql/examples/ha_archive.cc | 17 +++++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index 793e50cf653..9cd5bba267f 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -192,8 +192,6 @@ select count(*) from t3; count(*) 1199 rename table t3 to t4; -Warnings: -Error 7 Error on rename of './test/t3.ARN' to './test/t4.ARN' (Errcode: 2) select * from t4 where fld3='bonfire'; auto fld1 companynr fld3 fld4 fld5 fld6 1191 068504 00 bonfire corresponds positively diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index e3ad677714f..58f8580e724 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -455,17 +455,22 @@ const char **ha_archive::bas_ext() const int ha_archive::rename_table(const char * from, const char * to) { DBUG_ENTER("ha_archive::rename_table"); + DBUG_PRINT("enter", ("from: %s, to: %s", from, to)); for (const char **ext=bas_ext(); *ext ; ext++) { - if (rename_file_ext(from,to,*ext)) + // Check if the .arn file exists before rename + if (!my_strcasecmp(system_charset_info, *ext, ARN)) { - if (my_errno == ENOENT && - !my_strcasecmp(system_charset_info, *ext, ARN)) + char name[FN_REFLEN]; + (void)strxnmov(name, FN_REFLEN, from, ARN, NullS); + if (access(name, F_OK)) + { + DBUG_PRINT("info", ("%s does not exist on disk, skipping it", name)); continue; - - DBUG_RETURN(my_errno); + } } - + if (rename_file_ext(from,to,*ext)) + DBUG_RETURN(my_errno); } DBUG_RETURN(0); } From 2cd93843bfbbf5e437f89ca76069a37393b712ed Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Apr 2005 22:58:11 +0200 Subject: [PATCH 58/78] Bug#7823 - FLUSH TABLES WITH READ LOCK + INSERT DELAYED = deadlock After merge fix. --- sql/lock.cc | 51 +++++++++++++++++++++++++++++++++++++++++++++-- sql/mysql_priv.h | 5 ++++- sql/sql_insert.cc | 2 +- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/sql/lock.cc b/sql/lock.cc index a8ccba32d4f..83a39005cd8 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -82,7 +82,8 @@ static int unlock_external(THD *thd, TABLE **table,uint count); static void print_lock_error(int error, const char *); -MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count) +MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, + bool ignore_global_read_lock) { MYSQL_LOCK *sql_lock; TABLE *write_lock_used; @@ -93,7 +94,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count) if (!(sql_lock = get_lock_data(thd,tables,count, 0,&write_lock_used))) break; - if (global_read_lock && write_lock_used) + if (global_read_lock && write_lock_used && ! ignore_global_read_lock) { /* Someone has issued LOCK ALL TABLES FOR READ and we want a write lock @@ -949,3 +950,49 @@ bool make_global_read_lock_block_commit(THD *thd) DBUG_RETURN(error); } + + +/* + Set protection against global read lock. + + SYNOPSIS + set_protect_against_global_read_lock() + void + + RETURN + FALSE OK, no global read lock exists. + TRUE Error, global read lock exists already. +*/ + +bool set_protect_against_global_read_lock(void) +{ + bool global_read_lock_exists; + + pthread_mutex_lock(&LOCK_open); + if (! (global_read_lock_exists= test(global_read_lock))) + protect_against_global_read_lock++; + pthread_mutex_unlock(&LOCK_open); + return global_read_lock_exists; +} + + +/* + Unset protection against global read lock. + + SYNOPSIS + unset_protect_against_global_read_lock() + void + + RETURN + void +*/ + +void unset_protect_against_global_read_lock(void) +{ + pthread_mutex_lock(&LOCK_open); + protect_against_global_read_lock--; + pthread_mutex_unlock(&LOCK_open); + pthread_cond_broadcast(&COND_refresh); +} + + diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 56fbd993aed..06c946114eb 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1151,7 +1151,8 @@ extern pthread_t signal_thread; extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd; #endif /* HAVE_OPENSSL */ -MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **table,uint count); +MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, + bool ignore_global_read_lock= FALSE); void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count); @@ -1165,6 +1166,8 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, bool is_not_commit); void start_waiting_global_read_lock(THD *thd); bool make_global_read_lock_block_commit(THD *thd); +bool set_protect_against_global_read_lock(void); +void unset_protect_against_global_read_lock(void); /* Lock based on name */ int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 56b6ab1aeed..ac8f5a06745 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1213,7 +1213,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) } pthread_mutex_lock(&tmp->mutex); - table=tmp->get_local_table(thd); + table= tmp->get_local_table(thd); pthread_mutex_unlock(&tmp->mutex); if (table) thd->di=tmp; From 2ef10765dc6ccfba55c65df3ec19313b23d7be5e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Apr 2005 09:39:29 +0200 Subject: [PATCH 59/78] Fix for avoiding gettin Invalid schema object version when doing local changes, post review fixes --- sql/ha_ndbcluster.cc | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 0d6bfcb9d0d..306d3224930 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -336,7 +336,17 @@ void ha_ndbcluster::invalidate_dictionary_cache(bool global) NDBDICT *dict= get_ndb()->getDictionary(); DBUG_PRINT("info", ("invalidating %s", m_tabname)); if (global) - dict->invalidateTable(m_tabname); + { + if (((const NDBTAB *)m_table)->getObjectStatus() + == NdbDictionary::Object::Invalid) + { + // Global cache has already been invalidated + dict->removeCachedTable(m_tabname); + global= FALSE; + } + else + dict->invalidateTable(m_tabname); + } else dict->removeCachedTable(m_tabname); table->version=0L; /* Free when thread is ready */ @@ -779,6 +789,7 @@ int ha_ndbcluster::get_metadata(const char *path) if (!(tab= dict->getTable(m_tabname))) ERR_RETURN(dict->getNdbError()); + // Check if thread has stale local cache if (tab->getObjectStatus() == NdbDictionary::Object::Invalid) { invalidate_dictionary_cache(FALSE); @@ -804,6 +815,7 @@ int ha_ndbcluster::get_metadata(const char *path) if (!invalidating_ndb_table) { DBUG_PRINT("info", ("Invalidating table")); + m_table= (void *) tab; invalidate_dictionary_cache(TRUE); invalidating_ndb_table= TRUE; } @@ -3288,7 +3300,6 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) thd->transaction.stmt.ndb_tid= 0; } } - m_table= NULL; m_table_info= NULL; /* This is the place to make sure this handler instance @@ -3910,7 +3921,13 @@ int ha_ndbcluster::rename_table(const char *from, const char *to) dict= ndb->getDictionary(); if (!(orig_tab= dict->getTable(m_tabname))) ERR_RETURN(dict->getNdbError()); - + // Check if thread has stale local cache + if (orig_tab->getObjectStatus() == NdbDictionary::Object::Invalid) + { + dict->removeCachedTable(m_tabname); + if (!(orig_tab= dict->getTable(m_tabname))) + ERR_RETURN(dict->getNdbError()); + } m_table= (void *)orig_tab; // Change current database to that of target table set_dbname(to); @@ -4278,7 +4295,6 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name, DBUG_RETURN(1); ERR_RETURN(err); } - DBUG_PRINT("info", ("Found table %s", tab->getName())); len= tab->getFrmLength(); From c97859b300ce982cedebc5f527fb7acbaa28712a Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Apr 2005 10:46:39 +0200 Subject: [PATCH 60/78] Fix for avoiding gettin Invalid schema object version when doing local changes, more post review fixes --- sql/ha_ndbcluster.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 306d3224930..181ae5e5b54 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -334,11 +334,15 @@ void ha_ndbcluster::no_uncommitted_rows_reset(THD *thd) void ha_ndbcluster::invalidate_dictionary_cache(bool global) { NDBDICT *dict= get_ndb()->getDictionary(); + DBUG_ENTER("invalidate_dictionary_cache"); DBUG_PRINT("info", ("invalidating %s", m_tabname)); + if (global) { - if (((const NDBTAB *)m_table)->getObjectStatus() - == NdbDictionary::Object::Invalid) + const NDBTAB *tab= dict->getTable(m_tabname); + if (!tab) + DBUG_VOID_RETURN; + if (tab->getObjectStatus() == NdbDictionary::Object::Invalid) { // Global cache has already been invalidated dict->removeCachedTable(m_tabname); @@ -381,6 +385,7 @@ void ha_ndbcluster::invalidate_dictionary_cache(bool global) break; } } + DBUG_VOID_RETURN; } int ha_ndbcluster::ndb_err(NdbConnection *trans) @@ -815,7 +820,6 @@ int ha_ndbcluster::get_metadata(const char *path) if (!invalidating_ndb_table) { DBUG_PRINT("info", ("Invalidating table")); - m_table= (void *) tab; invalidate_dictionary_cache(TRUE); invalidating_ndb_table= TRUE; } From 2c8e261725b4a7d57ee56058090b14f106d41c5b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Apr 2005 10:49:18 +0200 Subject: [PATCH 61/78] BUG#9911 After review fixes - Remove ha_archive::rename_table and move the fix to handler::rename_table sql/examples/ha_archive.cc: Remove ha_archive::rename_table sql/examples/ha_archive.h: Remove ha_archive::rename_table sql/handler.cc: Fix handler::rename_table so it does not care about if the file to rename is missing --- sql/examples/ha_archive.cc | 24 ------------------------ sql/examples/ha_archive.h | 1 - sql/handler.cc | 14 +++++++++----- 3 files changed, 9 insertions(+), 30 deletions(-) diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index 0e1df45a70b..bc4af0c7dc7 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -427,30 +427,6 @@ const char **ha_archive::bas_ext() const { static const char *ext[]= { ARZ, ARN, ARM, NullS }; return ext; } -/* - Rename all files that this handler defines in bas_ext list - - NOTE Don't care if the .arn file is missing -*/ -int ha_archive::rename_table(const char * from, const char * to) -{ - DBUG_ENTER("ha_archive::rename_table"); - for (const char **ext=bas_ext(); *ext ; ext++) - { - if (rename_file_ext(from,to,*ext)) - { - if (my_errno == ENOENT && - !my_strcasecmp(system_charset_info, *ext, ARN)) - continue; - - DBUG_RETURN(my_errno); - } - - } - DBUG_RETURN(0); -} - - /* When opening a file we: Create/get our shared structure. diff --git a/sql/examples/ha_archive.h b/sql/examples/ha_archive.h index 1d3365aca67..855d756368d 100644 --- a/sql/examples/ha_archive.h +++ b/sql/examples/ha_archive.h @@ -124,7 +124,6 @@ public: int optimize(THD* thd, HA_CHECK_OPT* check_opt); THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type); - int rename_table(const char * from, const char * to); }; bool archive_db_init(void); diff --git a/sql/handler.cc b/sql/handler.cc index 7c369a72392..f174f51514e 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1255,13 +1255,17 @@ int handler::delete_table(const char *name) int handler::rename_table(const char * from, const char * to) { - DBUG_ENTER("handler::rename_table"); - for (const char **ext=bas_ext(); *ext ; ext++) + int error= 0; + for (const char **ext= bas_ext(); *ext ; ext++) { - if (rename_file_ext(from,to,*ext)) - DBUG_RETURN(my_errno); + if (rename_file_ext(from, to, *ext)) + { + if ((error=my_errno) != ENOENT) + break; + error= 0; + } } - DBUG_RETURN(0); + return error; } /* From 56b8c9061c3d118f61b572e2299f351b179c9385 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Apr 2005 11:05:44 +0200 Subject: [PATCH 62/78] Merge bug9911 with 5.0 mysql-test/r/archive.result: Warning will be pushed when renaming table with "optional" files. --- mysql-test/r/archive.result | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index 9cd5bba267f..793e50cf653 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -192,6 +192,8 @@ select count(*) from t3; count(*) 1199 rename table t3 to t4; +Warnings: +Error 7 Error on rename of './test/t3.ARN' to './test/t4.ARN' (Errcode: 2) select * from t4 where fld3='bonfire'; auto fld1 companynr fld3 fld4 fld5 fld6 1191 068504 00 bonfire corresponds positively From c3e1ccada25654d527e6d04b891b668843944f1d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Apr 2005 13:06:36 +0400 Subject: [PATCH 63/78] A test case for Bug#5673 "Rounding problem in 4.0.21 inserting decimal value into a char field": the patch submitted for the bug a while ago has never been reviewed or approved to push into 4.0. Decimal support in 5.0 resolves the issue. Adding the test case and closing the bug report. mysql-test/r/type_decimal.result: Bug#5673: test results fixed. mysql-test/t/type_decimal.test: A test case for Bug#5673 "Rounding problem in 4.0.21 inserting decimal value into a char field" --- mysql-test/r/type_decimal.result | 20 ++++++++++++++++++++ mysql-test/t/type_decimal.test | 28 ++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index a01f8ee08a1..a7b6fa1b376 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -764,3 +764,23 @@ non PS, 1.0 in parameter 1.0 PS, 1.0 in parameter 1.0 deallocate prepare stmt; drop table t1; +create table t1 ( +strippedproductid char(15) not null default '', +zlevelprice decimal(10,2) default null, +primary key (strippedproductid) +); +create table t2 ( +productid char(15) not null default '', +zlevelprice char(21) default null, +primary key (productid) +); +insert into t1 values ('002trans','49.99'); +insert into t1 values ('003trans','39.98'); +insert into t1 values ('004trans','31.18'); +insert INTO t2 SELECT * FROM t1; +select * from t2; +productid zlevelprice +002trans 49.99 +003trans 39.98 +004trans 31.18 +drop table t1, t2; diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 107f4a06ec5..f86113ac66b 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -343,3 +343,31 @@ execute stmt using @a; select * from t1; deallocate prepare stmt; drop table t1; + +# +# A test case for Bug#5673 "Rounding problem in 4.0.21 inserting decimal +# value into a char field": this is a regression bug in 4.0 tree caused by +# a fix for some other decimal conversion issue. The patch never was +# approved to get into 4.0 (maybe because it was considered too intrusive) +# + +create table t1 ( + strippedproductid char(15) not null default '', + zlevelprice decimal(10,2) default null, + primary key (strippedproductid) +); + +create table t2 ( + productid char(15) not null default '', + zlevelprice char(21) default null, + primary key (productid) +); + +insert into t1 values ('002trans','49.99'); +insert into t1 values ('003trans','39.98'); +insert into t1 values ('004trans','31.18'); + +insert INTO t2 SELECT * FROM t1; + +select * from t2; +drop table t1, t2; From b411128fa541123f5a2663448c9c6ce6b6091df1 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Apr 2005 13:30:45 +0200 Subject: [PATCH 64/78] After review fixes to check-cpu BUILD/check-cpu: Remove the exit 0 from check-cpu --- BUILD/check-cpu | 2 -- 1 file changed, 2 deletions(-) diff --git a/BUILD/check-cpu b/BUILD/check-cpu index b5c14e38403..553df39191f 100755 --- a/BUILD/check-cpu +++ b/BUILD/check-cpu @@ -19,8 +19,6 @@ if test -r /proc/cpuinfo ; then if test -z "$model_name" ; then model_name=`uname -m` fi -else - exit 0 fi case "$cpu_family--$model_name" in From ea2eb32bf022f0f41d3a8de2d7a8031c179714e1 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Apr 2005 13:48:51 +0200 Subject: [PATCH 65/78] Removing duplicate AC_PREREQ macros Setting AC_PREREQ required version to 2.50 until we have sorted out what is required. The manual says 2.58. configure.in: Removing duplicate AC_PREREQ macros --- configure.in | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/configure.in b/configure.in index 07ce041b283..f6a50dcb46f 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -dnl -*- ksh -*- +bdnl -*- ksh -*- dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.50)dnl Minimum Autoconf version required. @@ -116,8 +116,6 @@ AC_SUBST(SAVE_LDFLAGS) AC_SUBST(SAVE_CXXLDFLAGS) AC_SUBST(CXXLDFLAGS) -AC_PREREQ(2.58)dnl Minimum Autoconf version required. - #AC_ARG_PROGRAM # Automaticly invoked by AM_INIT_AUTOMAKE AM_SANITY_CHECK From 994674c09b112745fd03355a0972fbf3f4b0295c Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Apr 2005 15:27:42 +0200 Subject: [PATCH 66/78] Bug#8321 - myisampack bug in compression algorithm This is the second of three changesets. It contains the pure bug fix. It also contains the second after-review fixes. The problem was that with gcc on x86, shifts are done modulo word size. 'value' is 32 bits wide and shifting it by 32 bits is a no-op. This was triggered by an evil distribution of character incidences. A distribution of 2917027827 characters made of 202 distinct values led to 34 occurrences of 32-bit Huffman codes. This might have been the first time ever that write_bits() had to write 32-bit values. Since it can be expected that one day even 32 bits might be insufficient, the third changeset suggests to enlarge some variables to 64 bits. --- myisam/myisampack.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/myisam/myisampack.c b/myisam/myisampack.c index 9f4e3bde65a..90689b08476 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -31,6 +31,7 @@ #define __GNU_LIBRARY__ /* Skip warnings in getopt.h */ #endif #include +#include #if INT_MAX > 32767 #define BITS_SAVED 32 @@ -1975,7 +1976,9 @@ static void write_bits (register ulong value, register uint bits) { reg3 uint byte_buff; bits= (uint) -file_buffer.bits; - byte_buff=file_buffer.byte | (uint) (value >> bits); + DBUG_ASSERT(bits <= 8 * sizeof(value)); + byte_buff= (file_buffer.byte | + ((bits != 8 * sizeof(value)) ? (uint) (value >> bits) : 0)); #if BITS_SAVED == 32 *file_buffer.pos++= (byte) (byte_buff >> 24) ; *file_buffer.pos++= (byte) (byte_buff >> 16) ; @@ -1983,7 +1986,9 @@ static void write_bits (register ulong value, register uint bits) *file_buffer.pos++= (byte) (byte_buff >> 8) ; *file_buffer.pos++= (byte) byte_buff; - value&=(1 << bits)-1; + DBUG_ASSERT(bits <= 8 * sizeof(ulong)); + if (bits != 8 * sizeof(value)) + value&= (((ulong) 1) << bits) - 1; #if BITS_SAVED == 16 if (bits >= sizeof(uint)) { From 745d52bb3da3afb018061b4e3ec34420a8475389 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Apr 2005 07:47:59 -0700 Subject: [PATCH 67/78] Fix tiny typo in configure.in configure.in: Fix typo --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index f6a50dcb46f..da707080006 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -bdnl -*- ksh -*- +dnl -*- ksh -*- dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.50)dnl Minimum Autoconf version required. From f0e256efe4a569788908d4ff9d672010b878449b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Apr 2005 18:28:50 +0200 Subject: [PATCH 68/78] BUG#5964 - 4.1 MERGE tables regression from 4.0 Changed the creation of the .MRG file so that only the table name is written when the MyISAM table is in the same database as the MERGE table, a relative path is used in other cases in mysqld, and possibly an absolute path is used in an embedded server. No test case is added as the external behaviour is unchanged. Only the file names within the .MRG file are changed. include/my_sys.h: BUG#5964 - 4.1 MERGE tables regression from 4.0 Added declaration for a new function. myisammrg/myrg_open.c: BUG#5964 - 4.1 MERGE tables regression from 4.0 Changed check for absolute path to check for any path. mysys/my_getwd.c: BUG#5964 - 4.1 MERGE tables regression from 4.0 Added a new functions which checks for absolute _or_ relative paths. sql/ha_myisammrg.cc: BUG#5964 - 4.1 MERGE tables regression from 4.0 Changed the creation of the .MRG file so that only the table name is written when the MyISAM table is in the same database as the MERGE table, a relative path is used in other cases in mysqld, and possibly an absolute path is used in an embedded server. --- include/my_sys.h | 1 + myisammrg/myrg_open.c | 2 +- mysys/my_getwd.c | 22 ++++++++++++++++++++++ sql/ha_myisammrg.cc | 28 ++++++++++++++++++++++++---- 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index b54e2581bd4..7ead643a9c6 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -609,6 +609,7 @@ extern uint dirname_part(my_string to,const char *name); extern uint dirname_length(const char *name); #define base_name(A) (A+dirname_length(A)) extern int test_if_hard_path(const char *dir_name); +extern my_bool has_path(const char *name); extern char *convert_dirname(char *to, const char *from, const char *from_end); extern void to_unix_path(my_string name); extern my_string fn_ext(const char *name); diff --git a/myisammrg/myrg_open.c b/myisammrg/myrg_open.c index a59ccb7d966..0dc2f4f9768 100644 --- a/myisammrg/myrg_open.c +++ b/myisammrg/myrg_open.c @@ -80,7 +80,7 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) continue; /* Skip comments */ } - if (!test_if_hard_path(buff)) + if (!has_path(buff)) { VOID(strmake(name_buff+dir_length,buff, sizeof(name_buff)-1-dir_length)); diff --git a/mysys/my_getwd.c b/mysys/my_getwd.c index d6f647254e8..89f949eca27 100644 --- a/mysys/my_getwd.c +++ b/mysys/my_getwd.c @@ -192,3 +192,25 @@ int test_if_hard_path(register const char *dir_name) return FALSE; #endif } /* test_if_hard_path */ + + +/* + Test if a name contains an (absolute or relative) path. + + SYNOPSIS + has_path() + name The name to test. + + RETURN + TRUE name contains a path. + FALSE name does not contain a path. +*/ + +my_bool has_path(const char *name) +{ + return test(strchr(name, FN_LIBCHAR)) +#ifdef FN_DEVCHAR + || test(strchr(name, FN_DEVCHAR)) +#endif + ; +} diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index bf47b4625e0..7a5d4fcf0a1 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -381,6 +381,7 @@ int ha_myisammrg::create(const char *name, register TABLE *form, char buff[FN_REFLEN],**table_names,**pos; TABLE_LIST *tables= (TABLE_LIST*) create_info->merge_list.first; THD *thd= current_thd; + uint dirlgt= dirname_length(name); DBUG_ENTER("ha_myisammrg::create"); if (!(table_names= (char**) thd->alloc((create_info->merge_list.elements+1)* @@ -394,11 +395,30 @@ int ha_myisammrg::create(const char *name, register TABLE *form, tbl= find_temporary_table(thd, tables->db, tables->real_name); if (!tbl) { - uint length= my_snprintf(buff,FN_REFLEN,"%s%s/%s", - mysql_real_data_home, + /* + Construct the path to the MyISAM table. Try to meet two conditions: + 1.) Allow to include MyISAM tables from different databases, and + 2.) allow for moving DATADIR around in the file system. + The first means that we need paths in the .MRG file. The second + means that we should not have absolute paths in the .MRG file. + The best, we can do, is to use 'mysql_data_home', which is '.' + in mysqld and may be an absolute path in an embedded server. + This means that it might not be possible to move the DATADIR of + an embedded server without changing the paths in the .MRG file. + */ + uint length= my_snprintf(buff, FN_REFLEN, "%s/%s/%s", mysql_data_home, tables->db, tables->real_name); - if (!(table_name= thd->strmake(buff, length))) - DBUG_RETURN(HA_ERR_OUT_OF_MEM); + /* + If a MyISAM table is in the same directory as the MERGE table, + we use the table name without a path. This means that the + DATADIR can easily be moved even for an embedded server as long + as the MyISAM tables are from the same database as the MERGE table. + */ + if ((dirname_length(buff) == dirlgt) && ! memcmp(buff, name, dirlgt)) + table_name= tables->real_name; + else + if (! (table_name= thd->strmake(buff, length))) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); } else table_name=(*tbl)->path; From c481eb3997555c0d2a01e80d3f4bfa28667a4b18 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Apr 2005 10:59:34 +0200 Subject: [PATCH 69/78] BUG#5964 - 4.1 MERGE tables regression from 4.0 After merge fix. --- sql/ha_myisammrg.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 20b5ad44629..f7c0abf9810 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -434,7 +434,7 @@ int ha_myisammrg::create(const char *name, register TABLE *form, as the MyISAM tables are from the same database as the MERGE table. */ if ((dirname_length(buff) == dirlgt) && ! memcmp(buff, name, dirlgt)) - table_name= tables->real_name; + table_name= tables->table_name; else if (! (table_name= thd->strmake(buff, length))) DBUG_RETURN(HA_ERR_OUT_OF_MEM); From b84dc09914b0bb7f943ff4c4b2e00648dc57520c Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Apr 2005 12:11:04 +0300 Subject: [PATCH 70/78] ha_innodb.cc: Fix compilation error on Windows in innobase_report_binlog_offset_and_commit() sql/ha_innodb.cc: Fix compilation error on Windows in innobase_report_binlog_offset_and_commit() --- sql/ha_innodb.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index f6398b8423e..4217b694f06 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1632,7 +1632,7 @@ innobase_report_binlog_offset_and_commit( #endif /* HAVE_REPLICATION */ trx->flush_log_later = TRUE; - innobase_commit(thd, trx_handle); + innobase_commit(thd, TRUE); trx->flush_log_later = FALSE; From b6ad57e0a37b43d20a58f9dc74258f2dc7544ea2 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Apr 2005 11:37:47 +0200 Subject: [PATCH 71/78] Fix for avoiding gettin Invalid schema object version when doing local changes, fixed found bug --- sql/ha_ndbcluster.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 181ae5e5b54..a1166641f7d 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -3266,7 +3266,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) if (tab->getObjectStatus() == NdbDictionary::Object::Invalid) { invalidate_dictionary_cache(FALSE); - if (!(tab= dict->getTable(m_tabname))) + if (!(tab= dict->getTable(m_tabname, &tab_info))) ERR_RETURN(dict->getNdbError()); DBUG_PRINT("info", ("Table schema version: %d", tab->getObjectVersion())); From 97b0821462cd21d5051b3264f072ea3d4a7a8d7f Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Apr 2005 17:03:34 +0300 Subject: [PATCH 72/78] CAST(string_argument AS UNSIGNED) didn't work for big integers above the signed range. (Bug #7036) Produce warnings of wrong cast of strings to signed/unsigned. Don't block not resolved IP's if DNS server is down (Bug #8467) Fix compiler problems with MinGW (Bug #8872) configure.in: Fix compiler problems with MinGW (Bug #8872) include/config-win.h: Fix compiler problems with MinGW (Bug #8872) include/my_global.h: Fix compiler problems with MinGW (Bug #8872) mysql-test/r/cast.result: Test for cast to signed/unsigned outside of range (Bug #7036) mysql-test/t/cast.test: Test for cast to signed/unsigned outside of range (Bug #7036) mysys/default.c: Cleanup (combine identical code). Done mainly by Jani sql/field.h: Added cast_to_int_type() to ensure that enums are casted as numbers sql/hostname.cc: Don't block not resolved IP's if DNS server is down (Bug #8467) sql/item.h: Added cast_to_int_type() to ensure that enums are casted as numbers sql/item_func.cc: CAST(string_argument AS UNSIGNED) didn't work for big integers above the signed range. (Bug #7036) Produce warnings of wrong cast of strings to signed/unsigned sql/item_func.h: CAST(string_argument AS UNSIGNED) didn't work for big integers above the signed range. (Bug #7036) --- configure.in | 3 ++ include/config-win.h | 17 ++++++- include/my_global.h | 2 + mysql-test/r/cast.result | 71 +++++++++++++++++++++++++-- mysql-test/t/cast.test | 26 +++++++++- mysys/default.c | 103 ++++++++++++++++++++++----------------- sql/field.h | 2 + sql/hostname.cc | 9 +++- sql/item.h | 7 ++- sql/item_func.cc | 73 +++++++++++++++++++++++++++ sql/item_func.h | 9 ++-- 11 files changed, 263 insertions(+), 59 deletions(-) diff --git a/configure.in b/configure.in index e90bea90dad..6efdc56d450 100644 --- a/configure.in +++ b/configure.in @@ -1860,6 +1860,9 @@ If you are using gcc 2.8.# you should upgrade to egcs 1.0.3 or newer and try again]); fi fi +AC_CHECK_TYPES([sigset_t, off_t], [], [], [#include ]) +AC_CHECK_TYPES([size_t], [], [], [#include ]) + MYSQL_PTHREAD_YIELD ###################################################################### diff --git a/include/config-win.h b/include/config-win.h index 472190e53ca..b3865c1fda7 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -106,20 +106,33 @@ functions */ /* Type information */ +#if defined(__EMX__) || !defined(HAVE_UINT) +#undef HAVE_UINT +#define HAVE_UINT typedef unsigned short ushort; typedef unsigned int uint; +#endif /* defined(__EMX__) || !defined(HAVE_UINT) */ + typedef unsigned __int64 ulonglong; /* Microsofts 64 bit types */ typedef __int64 longlong; +#ifndef HAVE_SIGSET_T typedef int sigset_t; +#endif #define longlong_defined -/* off_t should not be __int64 because of conflicts in header files; - Use my_off_t or os_off_t instead */ +/* + off_t should not be __int64 because of conflicts in header files; + Use my_off_t or os_off_t instead +*/ +#ifndef HAVE_OFF_T typedef long off_t; +#endif typedef __int64 os_off_t; #ifdef _WIN64 typedef UINT_PTR rf_SetTimer; #else +#ifndef HAVE_SIZE_T typedef unsigned int size_t; +#endif typedef uint rf_SetTimer; #endif diff --git a/include/my_global.h b/include/my_global.h index 745179e8a06..bf6f3b52c4b 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -393,6 +393,8 @@ int __void__; #endif #if defined(__EMX__) || !defined(HAVE_UINT) +#undef HAVE_UINT +#define HAVE_UINT typedef unsigned int uint; typedef unsigned short ushort; #endif diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index 636e2603f9b..7cd0934f7a3 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -4,9 +4,6 @@ CAST(1-2 AS UNSIGNED) select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER); CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER) -1 -select CONVERT('-1',UNSIGNED); -CONVERT('-1',UNSIGNED) -18446744073709551615 select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1; cast(-5 as unsigned) | 1 cast(-5 as unsigned) & -1 18446744073709551611 18446744073709551611 @@ -57,6 +54,41 @@ CONVERT(DATE "2004-01-22 21:45:33",BINARY(4)) select CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)); CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)) 2004 +select cast('18446744073709551616' as unsigned); +cast('18446744073709551616' as unsigned) +18446744073709551615 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '18446744073709551616' +select cast('18446744073709551616' as signed); +cast('18446744073709551616' as signed) +-1 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '18446744073709551616' +select cast('9223372036854775809' as signed); +cast('9223372036854775809' as signed) +-9223372036854775807 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement +select cast('-1' as unsigned); +cast('-1' as unsigned) +18446744073709551615 +Warnings: +Warning 1105 Cast to unsigned converted negative integer to it's positive complement +select cast('abc' as signed); +cast('abc' as signed) +0 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'abc' +select cast('1a' as signed); +cast('1a' as signed) +1 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '1a' +select cast('' as signed); +cast('' as signed) +0 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '' set names binary; select cast(_latin1'test' as char character set latin2); cast(_latin1'test' as char character set latin2) @@ -187,3 +219,36 @@ timediff(cast('2004-12-30 12:00:00' as time), '12:00:00') select timediff(cast('1 12:00:00' as time), '12:00:00'); timediff(cast('1 12:00:00' as time), '12:00:00') 24:00:00 +select cast(18446744073709551615 as unsigned); +cast(18446744073709551615 as unsigned) +18446744073709551615 +select cast(18446744073709551615 as signed); +cast(18446744073709551615 as signed) +-1 +select cast('18446744073709551615' as unsigned); +cast('18446744073709551615' as unsigned) +18446744073709551615 +select cast('18446744073709551615' as signed); +cast('18446744073709551615' as signed) +-1 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement +select cast('9223372036854775807' as signed); +cast('9223372036854775807' as signed) +9223372036854775807 +select cast(concat('184467440','73709551615') as unsigned); +cast(concat('184467440','73709551615') as unsigned) +18446744073709551615 +select cast(concat('184467440','73709551615') as signed); +cast(concat('184467440','73709551615') as signed) +-1 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement +select cast(repeat('1',20) as unsigned); +cast(repeat('1',20) as unsigned) +11111111111111111111 +select cast(repeat('1',20) as signed); +cast(repeat('1',20) as signed) +-7335632962598440505 +Warnings: +Warning 1105 Cast to signed converted positive out-of-range integer to it's negative complement diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test index 23bba7d5aff..aeab81585f0 100644 --- a/mysql-test/t/cast.test +++ b/mysql-test/t/cast.test @@ -4,7 +4,6 @@ select CAST(1-2 AS UNSIGNED); select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER); -select CONVERT('-1',UNSIGNED); select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1; select cast(-5 as unsigned) -1, cast(-5 as unsigned) + 1; select ~5, cast(~5 as signed); @@ -22,6 +21,15 @@ select CONVERT(DATE "2004-01-22 21:45:33",CHAR(4)); select CONVERT(DATE "2004-01-22 21:45:33",BINARY(4)); select CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)); +# out-of-range cases +select cast('18446744073709551616' as unsigned); +select cast('18446744073709551616' as signed); +select cast('9223372036854775809' as signed); +select cast('-1' as unsigned); +select cast('abc' as signed); +select cast('1a' as signed); +select cast('' as signed); + # # Character set convertion # @@ -118,3 +126,19 @@ select date_add(cast('2004-12-30 12:00:00' as date), interval 0 hour); select timediff(cast('2004-12-30 12:00:00' as time), '12:00:00'); # Still we should not throw away "days" part of time value select timediff(cast('1 12:00:00' as time), '12:00:00'); + +# +# Bug #7036: Casting from string to unsigned would cap value of result at +# maximum signed value instead of maximum unsigned value +# +select cast(18446744073709551615 as unsigned); +select cast(18446744073709551615 as signed); +select cast('18446744073709551615' as unsigned); +select cast('18446744073709551615' as signed); +select cast('9223372036854775807' as signed); + +select cast(concat('184467440','73709551615') as unsigned); +select cast(concat('184467440','73709551615') as signed); + +select cast(repeat('1',20) as unsigned); +select cast(repeat('1',20) as signed); diff --git a/mysys/default.c b/mysys/default.c index 4ee2041bc39..bf23502389d 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -318,6 +318,56 @@ static int search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, } +/* + Skip over keyword and get argument after keyword + + SYNOPSIS + get_argument() + keyword Include directive keyword + kwlen Length of keyword + ptr Pointer to the keword in the line under process + line line number + + RETURN + 0 error + # Returns pointer to the argument after the keyword. +*/ + +static char *get_argument(const char *keyword, uint kwlen, + char *ptr, char *name, uint line) +{ + char *end; + + /* Skip over "include / includedir keyword" and following whitespace */ + + for (ptr+= kwlen - 1; + my_isspace(&my_charset_latin1, ptr[0]); + ptr++) + {} + + /* + Trim trailing whitespace from directory name + The -1 below is for the newline added by fgets() + Note that my_isspace() is true for \r and \n + */ + for (end= ptr + strlen(ptr) - 1; + my_isspace(&my_charset_latin1, *(end - 1)); + end--) + {} + end[0]= 0; /* Cut off end space */ + + /* Print error msg if there is nothing after !include* directive */ + if (end <= ptr) + { + fprintf(stderr, + "error: Wrong '!%s' directive in config file: %s at line %d\n", + keyword, name, line); + return 0; + } + return ptr; +} + + /* Open a configuration file (if exists) and read given options from it @@ -426,31 +476,10 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, sizeof(includedir_keyword) - 1)) && my_isspace(&my_charset_latin1, ptr[sizeof(includedir_keyword) - 1])) { - /* skip over "includedir" and following whitespace */ - for (ptr+= sizeof(includedir_keyword) - 1; - my_isspace(&my_charset_latin1, ptr[0]); ptr++) - {} - - /* - trim trailing whitespace from directory name - The -1 below is for the newline added by fgets() - Note that my_isspace() is true for \r and \n - */ - for (end= ptr + strlen(ptr) - 1; - my_isspace(&my_charset_latin1, *(end - 1)); - end--) - {} - end[0]= 0; - - /* print error msg if there is nothing after !includedir directive */ - if (end <= ptr) - { - fprintf(stderr, - "error: Wrong !includedir directive in config " - "file: %s at line %d\n", - name,line); - goto err; - } + if (!(ptr= get_argument(includedir_keyword, + sizeof(includedir_keyword), + ptr, name, line))) + goto err; if (!(search_dir= my_dir(ptr, MYF(MY_WME)))) goto err; @@ -486,26 +515,10 @@ static int search_default_file_with_ext(DYNAMIC_ARRAY *args, MEM_ROOT *alloc, else if ((!strncmp(ptr, include_keyword, sizeof(include_keyword) - 1)) && my_isspace(&my_charset_latin1, ptr[sizeof(include_keyword)-1])) { - /* skip over `include' and following whitespace */ - for (ptr+= sizeof(include_keyword) - 1; - my_isspace(&my_charset_latin1, ptr[0]); ptr++) - {} - - /* trim trailing whitespace from filename */ - for (end= ptr + strlen(ptr) - 1; - my_isspace(&my_charset_latin1, *(end - 1)); - end--) - {} - end[0]= 0; - - if (end <= ptr) - { - fprintf(stderr, - "error: Wrong !include directive in config " - "file: %s at line %d\n", - name,line); - goto err; - } + if (!(ptr= get_argument(include_keyword, + sizeof(include_keyword), ptr, + name, line))) + goto err; search_default_file_with_ext(args, alloc, "", "", ptr, group, recursion_level + 1); diff --git a/sql/field.h b/sql/field.h index 5dc124aba35..f19771c3f9c 100644 --- a/sql/field.h +++ b/sql/field.h @@ -119,6 +119,7 @@ public: virtual String *val_str(String*,String *)=0; virtual Item_result result_type () const=0; virtual Item_result cmp_type () const { return result_type(); } + virtual Item_result cast_to_int_type () const { return result_type(); } static enum_field_types field_type_merge(enum_field_types, enum_field_types); static Item_result result_merge_type(enum_field_types); bool eq(Field *field) { return ptr == field->ptr && null_ptr == field->null_ptr; } @@ -1115,6 +1116,7 @@ public: } enum_field_types type() const { return FIELD_TYPE_STRING; } enum Item_result cmp_type () const { return INT_RESULT; } + enum Item_result cast_to_int_type () const { return INT_RESULT; } enum ha_base_keytype key_type() const; int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); diff --git a/sql/hostname.cc b/sql/hostname.cc index c74d230bbcb..fe2fad6f3b2 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -177,7 +177,14 @@ my_string ip_to_hostname(struct in_addr *in, uint *errors) &tmp_errno))) { DBUG_PRINT("error",("gethostbyname_r returned %d",tmp_errno)); - add_wrong_ip(in); + /* + Don't cache responses when the DSN server is down, as otherwise + transient DNS failure may leave any number of clients (those + that attempted to connect during the outage) unable to connect + indefinitely. + */ + if (tmp_errno == HOST_NOT_FOUND || tmp_error == NO_DATA) + add_wrong_ip(in); my_gethostbyname_r_free(); DBUG_RETURN(0); } diff --git a/sql/item.h b/sql/item.h index d949095b455..d576fbbc60a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -180,7 +180,8 @@ public: { return save_in_field(field, 1); } virtual bool send(Protocol *protocol, String *str); virtual bool eq(const Item *, bool binary_cmp) const; - virtual Item_result result_type () const { return REAL_RESULT; } + virtual Item_result result_type() const { return REAL_RESULT; } + virtual Item_result cast_to_int_type() const { return result_type(); } virtual enum_field_types field_type() const; virtual enum Type type() const =0; /* valXXX methods must return NULL or 0 or 0.0 if null_value is set. */ @@ -422,6 +423,10 @@ public: { return field->result_type(); } + Item_result cast_to_int_type() const + { + return field->cast_to_int_type(); + } enum_field_types field_type() const { return field->type(); diff --git a/sql/item_func.cc b/sql/item_func.cc index 2b38584fe23..1b80ef06251 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -582,6 +582,58 @@ void Item_func_signed::print(String *str) } +longlong Item_func_signed::val_int_from_str(int *error) +{ + char buff[MAX_FIELD_WIDTH], *end; + String tmp(buff,sizeof(buff), &my_charset_bin), *res; + longlong value; + + /* + For a string result, we must first get the string and then convert it + to a longlong + */ + + if (!(res= args[0]->val_str(&tmp))) + { + null_value= 1; + *error= 0; + return 0; + } + null_value= 0; + end= (char*) res->ptr()+ res->length(); + value= my_strtoll10(res->ptr(), &end, error); + if (*error > 0 || end != res->ptr()+ res->length()) + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE, + ER(ER_TRUNCATED_WRONG_VALUE), "INTEGER", + res->c_ptr()); + return value; +} + + +longlong Item_func_signed::val_int() +{ + longlong value; + int error; + + if (args[0]->cast_to_int_type() != STRING_RESULT) + { + value= args[0]->val_int(); + null_value= args[0]->null_value; + return value; + } + + value= val_int_from_str(&error); + if (value < 0 && error == 0) + { + push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, + "Cast to signed converted positive out-of-range integer to " + "it's negative complement"); + } + return value; +} + + void Item_func_unsigned::print(String *str) { str->append("cast(", 5); @@ -591,6 +643,27 @@ void Item_func_unsigned::print(String *str) } +longlong Item_func_unsigned::val_int() +{ + longlong value; + int error; + + if (args[0]->cast_to_int_type() != STRING_RESULT) + { + value= args[0]->val_int(); + null_value= args[0]->null_value; + return value; + } + + value= val_int_from_str(&error); + if (error < 0) + push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, + "Cast to unsigned converted negative integer to it's " + "positive complement"); + return value; +} + + double Item_func_plus::val() { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_func.h b/sql/item_func.h index 3a309f4ae99..288db3a148c 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -226,12 +226,8 @@ public: null_value= args[0]->null_value; return tmp; } - longlong val_int() - { - longlong tmp= args[0]->val_int(); - null_value= args[0]->null_value; - return tmp; - } + longlong val_int(); + longlong val_int_from_str(int *error); void fix_length_and_dec() { max_length=args[0]->max_length; unsigned_flag=0; } void print(String *str); @@ -245,6 +241,7 @@ public: const char *func_name() const { return "cast_as_unsigned"; } void fix_length_and_dec() { max_length=args[0]->max_length; unsigned_flag=1; } + longlong val_int(); void print(String *str); }; From 1df25ccdac1855e82fc04b2055c193864f8b33b9 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Apr 2005 20:23:02 +0500 Subject: [PATCH 73/78] Fix for #6553 and #8776 (no errors on bad spatial data) mysql-test/r/gis-rtree.result: test result fixed mysql-test/r/gis.result: test result fixed mysql-test/t/gis-rtree.test: test case fixed mysql-test/t/gis.test: test case added sql/field.cc: error messages launched now when we try to put bad spatial data in the GEOMETRY field sql/field.h: interface fixed sql/item_geofunc.cc: bad_data sign now instead of NULL now returned from Item_geometry_from_text::val_str sql/share/errmsg.txt: error message added sql/spatial.cc: bad_geometry data instance sql/spatial.h: bad_geometry_data declaration sql/sql_base.cc: messages now created in store_* function --- mysql-test/r/gis-rtree.result | 2 +- mysql-test/r/gis.result | 14 ++++++++++++-- mysql-test/t/gis-rtree.test | 2 +- mysql-test/t/gis.test | 16 ++++++++++++++-- sql/field.cc | 30 +++++++++++++++++++++++++++++- sql/field.h | 6 +++--- sql/item_geofunc.cc | 7 +++++-- sql/share/errmsg.txt | 2 ++ sql/spatial.cc | 2 ++ sql/spatial.h | 2 ++ sql/sql_base.cc | 5 +---- 11 files changed, 72 insertions(+), 16 deletions(-) diff --git a/mysql-test/r/gis-rtree.result b/mysql-test/r/gis-rtree.result index 0e558e47594..73cde35993e 100644 --- a/mysql-test/r/gis-rtree.result +++ b/mysql-test/r/gis-rtree.result @@ -801,5 +801,5 @@ CREATE TABLE t1 (st varchar(100)); INSERT INTO t1 VALUES ("Fake string"); CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom)); INSERT INTO t2 SELECT GeomFromText(st) FROM t1; -ERROR HY000: Unknown error +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field drop table t1, t2; diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result index 3b196a60d68..93216fe2003 100644 --- a/mysql-test/r/gis.result +++ b/mysql-test/r/gis.result @@ -461,9 +461,9 @@ Note 1003 select issimple(multipoint(point(3,6),point(4,10))) AS `issimple(Multi create table t1 (a geometry not null); insert into t1 values (GeomFromText('Point(1 2)')); insert into t1 values ('Garbage'); -ERROR HY000: Unknown error +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field insert IGNORE into t1 values ('Garbage'); -ERROR HY000: Unknown error +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field alter table t1 add spatial index(a); drop table t1; create table t1(a geometry not null, spatial index(a)); @@ -655,3 +655,13 @@ t1 where object_id=85984; object_id geometrytype(geo) ISSIMPLE(GEO) ASTEXT(centroid(geo)) 85984 MULTIPOLYGON 0 POINT(-114.87787186923 36.33101763469) drop table t1; +create table t1 (fl geometry); +insert into t1 values (1); +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field +insert into t1 values (1.11); +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field +insert into t1 values ("qwerty"); +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field +insert into t1 values (pointfromtext('point(1,1)')); +ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field +drop table t1; diff --git a/mysql-test/t/gis-rtree.test b/mysql-test/t/gis-rtree.test index da59c6ae5e4..522f7a6f637 100644 --- a/mysql-test/t/gis-rtree.test +++ b/mysql-test/t/gis-rtree.test @@ -168,6 +168,6 @@ drop table t1; CREATE TABLE t1 (st varchar(100)); INSERT INTO t1 VALUES ("Fake string"); CREATE TABLE t2 (geom GEOMETRY NOT NULL, SPATIAL KEY gk(geom)); ---error 1105 +--error 1416 INSERT INTO t2 SELECT GeomFromText(st) FROM t1; drop table t1, t2; diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test index 86c34eacbc5..b7071019e9d 100644 --- a/mysql-test/t/gis.test +++ b/mysql-test/t/gis.test @@ -165,9 +165,9 @@ explain extended select issimple(MultiPoint(Point(3, 6), Point(4, 10))), issimpl create table t1 (a geometry not null); insert into t1 values (GeomFromText('Point(1 2)')); --- error 1105 +-- error 1416 insert into t1 values ('Garbage'); --- error 1105 +-- error 1416 insert IGNORE into t1 values ('Garbage'); alter table t1 add spatial index(a); @@ -359,3 +359,15 @@ select object_id, geometrytype(geo), ISSIMPLE(GEO), ASTEXT(centroid(geo)) from t1 where object_id=85984; drop table t1; + +create table t1 (fl geometry); +--error 1416 +insert into t1 values (1); +--error 1416 +insert into t1 values (1.11); +--error 1416 +insert into t1 values ("qwerty"); +--error 1416 +insert into t1 values (pointfromtext('point(1,1)')); + +drop table t1; diff --git a/sql/field.cc b/sql/field.cc index 00f729d5b07..c59d9b63fca 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7267,12 +7267,38 @@ void Field_geom::sql_type(String &res) const } +int Field_geom::store(double nr) +{ + my_message(ER_CANT_CREATE_GEOMETRY_OBJECT, + ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0)); + return -1; +} + + +int Field_geom::store(longlong nr) +{ + my_message(ER_CANT_CREATE_GEOMETRY_OBJECT, + ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0)); + return -1; +} + + +int Field_geom::store_decimal(const my_decimal *) +{ + my_message(ER_CANT_CREATE_GEOMETRY_OBJECT, + ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0)); + return -1; +} + + int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs) { if (!length) bzero(ptr, Field_blob::pack_length()); else { + if (from == Geometry::bad_geometry_data.ptr()) + goto err; // Check given WKB uint32 wkb_type; if (length < SRID_SIZE + WKB_HEADER_SIZE + SIZEOF_STORED_DOUBLE*2) @@ -7280,7 +7306,7 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs) wkb_type= uint4korr(from + WKB_HEADER_SIZE); if (wkb_type < (uint32) Geometry::wkb_point || wkb_type > (uint32) Geometry::wkb_end) - return -1; + goto err; Field_blob::store_length(length); if (table->copy_blobs || length <= MAX_FIELD_WIDTH) { // Must make a copy @@ -7293,6 +7319,8 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs) err: bzero(ptr, Field_blob::pack_length()); + my_message(ER_CANT_CREATE_GEOMETRY_OBJECT, + ER(ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0)); return -1; } diff --git a/sql/field.h b/sql/field.h index 22787850442..0f1cc0b95aa 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1189,9 +1189,9 @@ public: enum_field_types type() const { return FIELD_TYPE_GEOMETRY; } void sql_type(String &str) const; int store(const char *to, uint length, CHARSET_INFO *charset); - int store(double nr) { return 1; } - int store(longlong nr) { return 1; } - int store_decimal(const my_decimal *) { return 1; } + int store(double nr); + int store(longlong nr); + int store_decimal(const my_decimal *); void get_key_image(char *buff,uint length,imagetype type); }; #endif /*HAVE_SPATIAL*/ diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 1a8cb50081b..b9f2ec8a6ca 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -55,8 +55,11 @@ String *Item_func_geometry_from_text::val_str(String *str) return 0; str->length(0); str->q_append(srid); - if ((null_value= !Geometry::create_from_wkt(&buffer, &trs, str, 0))) - return 0; + if (!Geometry::create_from_wkt(&buffer, &trs, str, 0)) + /* We shouldn't return NULL here as NULL is a legal spatial object */ + /* Geometry::bad_spatial_data will produce error message beeing stored*/ + /* in GEOMETRY field */ + return &Geometry::bad_geometry_data; return str; } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 3a311ff7917..050bbe86948 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5344,3 +5344,5 @@ ER_SP_NOT_VAR_ARG 42000 eng "OUT or INOUT argument %d for routine %s is not a variable" ER_SP_NO_RETSET_IN_FUNC 0A000 eng "Not allowed to return a result set from a function" +ER_CANT_CREATE_GEOMETRY_OBJECT 22003 + eng "Cannot get geometry object from data you send to the GEOMETRY field" diff --git a/sql/spatial.cc b/sql/spatial.cc index bcfefd9dde8..427648850e4 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -22,6 +22,8 @@ /***************************** Gis_class_info *******************************/ +String Geometry::bad_geometry_data("Bad object", &my_charset_bin); + Geometry::Class_info *Geometry::ci_collection[Geometry::wkb_end+1]= { NULL, NULL, NULL, NULL, NULL, NULL, NULL diff --git a/sql/spatial.h b/sql/spatial.h index b96434831a1..438ec171a72 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -173,6 +173,8 @@ public: static void operator delete(void *ptr, void *buffer) {} + static String bad_geometry_data; + enum wkbType { wkb_point= 1, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d79811aa4e2..ade1fb96b96 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3858,11 +3858,8 @@ fill_record(THD *thd, Field **ptr, List &values, bool ignore_errors) TABLE *table= field->table; if (field == table->next_number_field) table->auto_increment_field_not_null= TRUE; - if ((value->save_in_field(field, 0) < 0) && !ignore_errors) - { - my_message(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR), MYF(0)); + if (value->save_in_field(field, 0) == -1) DBUG_RETURN(TRUE); - } } DBUG_RETURN(thd->net.report_error); } From 27fa1254dcbfd0df2d2b7429956fcc39fc4602cd Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Apr 2005 21:19:39 +0400 Subject: [PATCH 74/78] Fix bug #9703 "Error 1032 with GROUP BY query and large tables" Reset old error if tmp table was successfully created. Test data is large and can be found in bug report along with test query. sql/sql_select.cc: Fix bug #9703 BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted --- BitKeeper/etc/logging_ok | 2 ++ sql/sql_select.cc | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index e4de8c6ebf2..330d28daf52 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -45,6 +45,8 @@ dlenev@build.mysql.com dlenev@jabberwock.localdomain dlenev@mysql.com ejonore@mc03.ndb.mysql.com +evgen@moonbone.(none) +evgen@moonbone.local gbichot@quadita2.mysql.com gbichot@quadxeon.mysql.com georg@beethoven.local diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 36efe26dff9..96958db2cce 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6891,6 +6891,11 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), &join->tmp_table_param, error, 0)) DBUG_RETURN(-1); + /* + If table->file->write_row() was failed because of 'out of memory' + and tmp table succesfully created, reset error. + */ + error=0; } if (join->rollup.state != ROLLUP::STATE_NONE && error <= 0) { From 9319613191a8acf8d1f65c1517cdca96bff07ec9 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 30 Apr 2005 01:05:15 +0400 Subject: [PATCH 75/78] Fix for BUG#10274: In Protocol_simple::store_long don't make any assumptions about relative sizes of int/long/longlong. --- sql/protocol.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/protocol.cc b/sql/protocol.cc index 485605ce8cd..91061426f04 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -810,7 +810,7 @@ bool Protocol_simple::store_long(longlong from) #endif char buff[20]; return net_store_data((char*) buff, - (uint) (int10_to_str((int)from,buff, (from <0)?-10:10)-buff)); + (uint) (int10_to_str((long int)from,buff, (from <0)?-10:10)-buff)); } From ac82a2d5eb0f183b27ddc3417b3b33899ef17bf5 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 30 Apr 2005 03:14:42 +0300 Subject: [PATCH 76/78] Setting a variable to CAST(NULL as X) set the result type of the variable to X. (Bug #6598) mysql-test/r/bigint.result: Test to show show that the parser threats big longlong values as unsigned mysql-test/r/user_var.result: Test of CAST(NULL as SIGNED/UNSIGNED) mysql-test/t/bigint.test: Test to show show that the parser threats big longlong values as unsigned mysql-test/t/user_var.test: Test of CAST(NULL as SIGNED/UNSIGNED) sql/item_func.cc: Setting a variable to CAST(NULL as X) set the result type of the variable to X. (Bug #6598) Setting a variable to NULL doesn't change the old result type. sql/item_func.h: Detect setting a variable to NULL sql/unireg.cc: Safety fix --- mysql-test/r/bigint.result | 17 +++++++++++++++ mysql-test/r/user_var.result | 41 ++++++++++++++++++++++++++++++++++++ mysql-test/t/bigint.test | 10 +++++++++ mysql-test/t/user_var.test | 26 +++++++++++++++++++++++ sql/item_func.cc | 15 +++++++++---- sql/item_func.h | 1 + sql/unireg.cc | 7 ++++-- 7 files changed, 111 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index e372c307ba7..a0c8f317db2 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -128,3 +128,20 @@ t2.value64=t1.value64; value64 value32 value64 value32 9223372036854775807 2 9223372036854775807 4 drop table t1, t2; +create table t1 select 1 as 'a'; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(1) NOT NULL default '0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 select 9223372036854775809 as 'a'; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` bigint(19) unsigned NOT NULL default '0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +select * from t1; +a +9223372036854775809 +drop table t1; diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 68eae111111..d9a647ce2c3 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -182,3 +182,44 @@ coercibility(@v1) coercibility(@v2) coercibility(@v3) coercibility(@v4) set session @honk=99; set one_shot @honk=99; ERROR HY000: The 'SET ONE_SHOT' syntax is reserved for purposes internal to the MySQL server +set @first_var= NULL; +create table t1 select @first_var; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `@first_var` longblob +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +set @first_var= cast(NULL as signed integer); +create table t1 select @first_var; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `@first_var` bigint(20) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +set @first_var= NULL; +create table t1 select @first_var; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `@first_var` bigint(20) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +set @first_var= concat(NULL); +create table t1 select @first_var; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `@first_var` longblob +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +set @first_var=1; +set @first_var= cast(NULL as CHAR); +create table t1 select @first_var; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `@first_var` longtext +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test index a26b78254e7..99c8a13d0b5 100644 --- a/mysql-test/t/bigint.test +++ b/mysql-test/t/bigint.test @@ -104,3 +104,13 @@ t2.value64=t1.value64; drop table t1, t2; +# +# Test of CREATE ... SELECT and unsigned integers +# +create table t1 select 1 as 'a'; +show create table t1; +drop table t1; +create table t1 select 9223372036854775809 as 'a'; +show create table t1; +select * from t1; +drop table t1; diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index ef360f2231d..b9d06558f34 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -119,3 +119,29 @@ select coercibility(@v1),coercibility(@v2),coercibility(@v3),coercibility(@v4); set session @honk=99; --error 1382 set one_shot @honk=99; + +# +# Bug #6598: problem with cast(NULL as signed integer); +# + +set @first_var= NULL; +create table t1 select @first_var; +show create table t1; +drop table t1; +set @first_var= cast(NULL as signed integer); +create table t1 select @first_var; +show create table t1; +drop table t1; +set @first_var= NULL; +create table t1 select @first_var; +show create table t1; +drop table t1; +set @first_var= concat(NULL); +create table t1 select @first_var; +show create table t1; +drop table t1; +set @first_var=1; +set @first_var= cast(NULL as CHAR); +create table t1 select @first_var; +show create table t1; +drop table t1; diff --git a/sql/item_func.cc b/sql/item_func.cc index fb21551e22f..6075f1f6bc3 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3271,7 +3271,8 @@ bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables, from the argument if the argument is NULL and the variable has previously been initialized. */ - if (!entry->collation.collation || !args[0]->null_value) + null_item= (args[0]->type() == NULL_ITEM); + if (!entry->collation.collation || !null_item) entry->collation.set(args[0]->collation.collation, DERIVATION_IMPLICIT); collation.set(entry->collation.collation, DERIVATION_IMPLICIT); cached_result_type= args[0]->result_type(); @@ -3315,8 +3316,8 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length, char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry)); if (entry->value && entry->value != pos) my_free(entry->value,MYF(0)); - entry->value=0; - entry->length=0; + entry->value= 0; + entry->length= 0; } else { @@ -3355,9 +3356,9 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length, if (type == DECIMAL_RESULT) ((my_decimal*)entry->value)->fix_buffer_pointer(); entry->length= length; - entry->type=type; entry->collation.set(cs, dv); } + entry->type=type; return 0; } @@ -3366,6 +3367,12 @@ bool Item_func_set_user_var::update_hash(void *ptr, uint length, Item_result type, CHARSET_INFO *cs, Derivation dv) { + /* + If we set a variable explicitely to NULL then keep the old + result type of the variable + */ + if ((null_value= args[0]->null_value) && null_item) + type= entry->type; // Don't change type of item if (::update_hash(entry, (null_value= args[0]->null_value), ptr, length, type, cs, dv)) { diff --git a/sql/item_func.h b/sql/item_func.h index 77b977fe778..3f45cad7dc3 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1071,6 +1071,7 @@ class Item_func_set_user_var :public Item_func char buffer[MAX_FIELD_WIDTH]; String value; my_decimal decimal_buff; + bool null_item; union { longlong vint; diff --git a/sql/unireg.cc b/sql/unireg.cc index 929ca5c672e..95a383e0f01 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -685,6 +685,9 @@ static bool make_empty_rec(THD *thd, File file,enum db_type table_type, thd->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong default values while ((field=it++)) { + /* + regfield don't have to be deleted as it's allocated with sql_alloc() + */ Field *regfield=make_field((char*) buff+field->offset,field->length, null_pos, null_count & 7, @@ -696,7 +699,8 @@ static bool make_empty_rec(THD *thd, File file,enum db_type table_type, field->interval, field->field_name, &table); - DBUG_ASSERT(regfield); + if (!regfield) + goto err; // End of memory if (!(field->flags & NOT_NULL_FLAG)) null_count++; @@ -730,7 +734,6 @@ static bool make_empty_rec(THD *thd, File file,enum db_type table_type, regfield->store(ER(ER_NO), (uint) strlen(ER(ER_NO)),system_charset_info); else regfield->reset(); - delete regfield; } /* Fill not used startpos */ From 963e94ce4978f546ae5059631bf279eb0fc6e1ab Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 30 Apr 2005 09:54:35 +0400 Subject: [PATCH 77/78] A fix and a test case for Bug#9520 "SELECT DISTINCT crashes server with cursor". The patch refactors do_select/sub_select functions, which implement the nested loop algorithm, and reuses them to fetch rows for cursors as well. Pushing with view.test failing (--ps-protocol). sql/sql_prepare.cc: Cursor::fetch() now returns void sql/sql_select.cc: A fix for Bug#9520 "SELECT DISTINCT crashes server with cursor": * rename sub_select returns codes to be able to track down what's going on in which case. * move record processing and outer join record processing to a separate function, out of sub_select read-record loop. * use generalized sub_select() nested loop function for cursors instead of own loop implementation used in Cursor::fetch() before sql/sql_select.h: Replace all return values of sub_select family with enum. Add JOIN::resume_nested_loop flag to indicate we are restarting the nested loop for execution of next chunk of cursor's rows. tests/mysql_client_test.c: A test case for Bug#9520 "SELECT DISTINCT crashes server with cursor" --- sql/sql_prepare.cc | 2 +- sql/sql_select.cc | 742 ++++++++++++++++++++------------------ sql/sql_select.h | 18 +- tests/mysql_client_test.c | 54 +++ 4 files changed, 456 insertions(+), 360 deletions(-) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 56d09d7c563..17c5f51f1e1 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2223,7 +2223,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) my_pthread_setprio(pthread_self(), QUERY_PRIOR); thd->protocol= &thd->protocol_prep; // Switch to binary protocol - (void) stmt->cursor->fetch(num_rows); + stmt->cursor->fetch(num_rows); thd->protocol= &thd->protocol_simple; // Use normal protocol if (!(specialflag & SPECIAL_NO_PRIOR)) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9b93a92c6aa..49e77e1c2dd 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -114,17 +114,31 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, static Next_select_func setup_end_select_func(JOIN *join); static int do_select(JOIN *join,List *fields,TABLE *tmp_table, Procedure *proc); -static int sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records); -static int sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records); -static int flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last); -static int end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); -static int end_send_group(JOIN *join, JOIN_TAB *join_tab,bool end_of_records); -static int end_write(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); -static int end_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); -static int end_unique_update(JOIN *join,JOIN_TAB *join_tab, - bool end_of_records); -static int end_write_group(JOIN *join, JOIN_TAB *join_tab, - bool end_of_records); + +static enum_nested_loop_state +sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); +static enum_nested_loop_state +evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, + int error, my_bool *report_error); +static enum_nested_loop_state +evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab); +static enum_nested_loop_state +sub_select(JOIN *join,JOIN_TAB *join_tab, bool end_of_records); +static enum_nested_loop_state +flush_cached_records(JOIN *join, JOIN_TAB *join_tab, bool skip_last); +static enum_nested_loop_state +end_send(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); +static enum_nested_loop_state +end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); +static enum_nested_loop_state +end_write(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); +static enum_nested_loop_state +end_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); +static enum_nested_loop_state +end_unique_update(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); +static enum_nested_loop_state +end_write_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records); + static int test_if_group_changed(List &list); static int join_read_const_table(JOIN_TAB *tab, POSITION *pos); static int join_read_system(JOIN_TAB *tab); @@ -1800,13 +1814,7 @@ Cursor::open(JOIN *join_arg) happen for the first table in join_tab list */ DBUG_ASSERT(join_tab->table->null_row == 0); - - /* - There is always at least one record in the table, as otherwise we - wouldn't have opened the cursor. Therefore a failure is the only - reason read_first_record can return not 0. - */ - DBUG_RETURN(join_tab->read_first_record(join_tab)); + DBUG_RETURN(0); } @@ -1816,97 +1824,36 @@ Cursor::open(JOIN *join_arg) PRECONDITION: Cursor is open RETURN VALUES: - -4 there are more rows, send_eof sent to the client - 0 no more rows, send_eof was sent to the client, cursor is closed - other fatal fetch error, cursor is closed (error is not reported) + none, this function will send error or OK to network if necessary. */ -int +void Cursor::fetch(ulong num_rows) { THD *thd= join->thd; JOIN_TAB *join_tab= join->join_tab + join->const_tables; - COND *on_expr= *join_tab->on_expr_ref; - COND *select_cond= join_tab->select_cond; - READ_RECORD *info= &join_tab->read_record; - int error= 0; + enum_nested_loop_state error= NESTED_LOOP_OK; /* save references to memory, allocated during fetch */ thd->set_n_backup_item_arena(this, &thd->stmt_backup); join->fetch_limit+= num_rows; - /* - Run while there are new rows in the first table; - For each row, satisfying ON and WHERE clauses (those parts of them which - can be evaluated early), call next_select. - */ - do - { - int no_more_rows; - join->examined_rows++; - - if (thd->killed) /* Aborted by user */ - { - my_message(ER_SERVER_SHUTDOWN, ER(ER_SERVER_SHUTDOWN), MYF(0)); - return -1; - } - - if (on_expr == 0 || on_expr->val_int()) - { - if (select_cond == 0 || select_cond->val_int()) - { - /* - TODO: call table->unlock_row() to unlock row failed selection, - when this feature will be used. - */ - error= join_tab->next_select(join, join_tab + 1, 0); - DBUG_ASSERT(error <= 0); - if (error) - { - /* real error or LIMIT/FETCH LIMIT worked */ - if (error == -4) - { - /* - FETCH LIMIT, read ahead one row, and close cursor - if there is no more rows XXX: to be fixed to support - non-equi-joins! - */ - if ((no_more_rows= info->read_record(info))) - error= no_more_rows > 0 ? -1: 0; - } - break; - } - } - } - /* read next row; break loop if there was an error */ - if ((no_more_rows= info->read_record(info))) - { - if (no_more_rows > 0) - error= -1; - else - { - enum { END_OF_RECORDS= 1 }; - error= join_tab->next_select(join, join_tab+1, (int) END_OF_RECORDS); - } - break; - } - } - while (thd->net.report_error == 0); - - if (thd->net.report_error) - error= -1; - - if (error == -3) /* LIMIT clause worked */ - error= 0; + error= sub_select(join, join_tab, 0); + if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS) + error= sub_select(join,join_tab,1); + if (error == NESTED_LOOP_QUERY_LIMIT) + error= NESTED_LOOP_OK; /* select_limit used */ + if (error == NESTED_LOOP_CURSOR_LIMIT) + join->resume_nested_loop= TRUE; #ifdef USING_TRANSACTIONS ha_release_temporary_latches(thd); #endif thd->restore_backup_item_arena(this, &thd->stmt_backup); - if (error == -4) + if (error == NESTED_LOOP_CURSOR_LIMIT) { /* Fetch limit worked, possibly more rows are there */ thd->server_status|= SERVER_STATUS_CURSOR_EXISTS; @@ -1916,20 +1863,19 @@ Cursor::fetch(ulong num_rows) else { close(); - if (error == 0) + if (error == NESTED_LOOP_OK) { thd->server_status|= SERVER_STATUS_LAST_ROW_SENT; ::send_eof(thd); thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT; } - else + else if (error != NESTED_LOOP_KILLED) my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); /* free cursor memory */ free_items(free_list); free_list= 0; free_root(&main_mem_root, MYF(0)); } - return error; } @@ -8948,7 +8894,8 @@ static Next_select_func setup_end_select_func(JOIN *join) static int do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) { - int error= 0; + int rc= 0; + enum_nested_loop_state error= NESTED_LOOP_OK; JOIN_TAB *join_tab; DBUG_ENTER("do_select"); @@ -8978,24 +8925,30 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) if (!join->conds || join->conds->val_int()) { Next_select_func end_select= join->join_tab[join->tables-1].next_select; - if (!(error=(*end_select)(join,join_tab,0)) || error == -3) - error=(*end_select)(join,join_tab,1); + error= (*end_select)(join,join_tab,0); + if (error == NESTED_LOOP_OK || error == NESTED_LOOP_QUERY_LIMIT) + error= (*end_select)(join,join_tab,1); } else if (join->send_row_on_empty_set()) - error= join->result->send_data(*join->fields); + rc= join->result->send_data(*join->fields); } else { error= sub_select(join,join_tab,0); - if (error >= 0) + if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS) error= sub_select(join,join_tab,1); - if (error == -3) - error= 0; /* select_limit used */ + if (error == NESTED_LOOP_QUERY_LIMIT) + error= NESTED_LOOP_OK; /* select_limit used */ } + if (error == NESTED_LOOP_NO_MORE_ROWS) + error= NESTED_LOOP_OK; - if (error >= 0) + if (error == NESTED_LOOP_OK) { - error=0; + /* + Sic: this branch works even if rc != 0, e.g. when + send_data above returns an error. + */ if (!table) // If sending data to client { /* @@ -9004,10 +8957,12 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) */ join->join_free(0); // Unlock all cursors if (join->result->send_eof()) - error= 1; // Don't send error + rc= 1; // Don't send error } DBUG_PRINT("info",("%ld records output",join->send_records)); } + else + rc= -1; if (table) { int tmp, new_errno= 0; @@ -9025,40 +8980,42 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) table->file->print_error(new_errno,MYF(0)); } #ifndef DBUG_OFF - if (error) + if (rc) { DBUG_PRINT("error",("Error: do_select() failed")); } #endif - DBUG_RETURN(join->thd->net.report_error ? -1 : error); + DBUG_RETURN(join->thd->net.report_error ? -1 : rc); } -static int +static enum_nested_loop_state sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) { - int error; + enum_nested_loop_state rc; if (end_of_records) { - if ((error=flush_cached_records(join,join_tab,FALSE)) < 0) - return error; /* purecov: inspected */ - return sub_select(join,join_tab,end_of_records); + rc= flush_cached_records(join,join_tab,FALSE); + if (rc == NESTED_LOOP_OK || rc == NESTED_LOOP_NO_MORE_ROWS) + rc= sub_select(join,join_tab,end_of_records); + return rc; } if (join->thd->killed) // If aborted by user { join->thd->send_kill_message(); - return -2; /* purecov: inspected */ + return NESTED_LOOP_KILLED; /* purecov: inspected */ } if (join_tab->use_quick != 2 || test_if_quick_select(join_tab) <= 0) { if (!store_record_in_cache(&join_tab->cache)) - return 0; // There is more room in cache + return NESTED_LOOP_OK; // There is more room in cache return flush_cached_records(join,join_tab,FALSE); } - if ((error=flush_cached_records(join,join_tab,TRUE)) < 0) - return error; /* purecov: inspected */ - return sub_select(join,join_tab,end_of_records); /* Use ordinary select */ + rc= flush_cached_records(join, join_tab, TRUE); + if (rc == NESTED_LOOP_OK || rc == NESTED_LOOP_NO_MORE_ROWS) + rc= sub_select(join, join_tab, end_of_records); + return rc; } /* @@ -9170,11 +9127,10 @@ sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) table of the embedding nested join, if any. RETURN - 0, if success - # of the error, otherwise + return one of enum_nested_loop_state, except NESTED_LOOP_NO_MORE_ROWS. */ -static int +static enum_nested_loop_state sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) { join_tab->table->null_row=0; @@ -9182,206 +9138,258 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) return (*join_tab->next_select)(join,join_tab+1,end_of_records); int error; - JOIN_TAB *first_unmatched; - JOIN_TAB *tab; - /* Cache variables for faster loop */ - COND *select_cond= join_tab->select_cond; + enum_nested_loop_state rc; my_bool *report_error= &(join->thd->net.report_error); + READ_RECORD *info= &join_tab->read_record; - join->return_tab= join_tab; - - if (join_tab->last_inner) + if (join->resume_nested_loop) { - /* join_tab is the first inner table for an outer join operation. */ - - /* Set initial state of guard variables for this table.*/ - join_tab->found=0; - join_tab->not_null_compl= 1; - - /* Set first_unmatched for the last inner table of this group */ - join_tab->last_inner->first_unmatched= join_tab; + /* If not the last table, plunge down the nested loop */ + if (join_tab < join->join_tab + join->tables - 1) + rc= (*join_tab->next_select)(join, join_tab + 1, 0); + else + { + join->resume_nested_loop= FALSE; + rc= NESTED_LOOP_OK; + } } - - if (!(error=(*join_tab->read_first_record)(join_tab))) + else { - bool not_exists_optimize= join_tab->table->reginfo.not_exists_optimize; - bool not_used_in_distinct=join_tab->not_used_in_distinct; - ha_rows found_records=join->found_records; - READ_RECORD *info= &join_tab->read_record; + join->return_tab= join_tab; + if (join_tab->last_inner) + { + /* join_tab is the first inner table for an outer join operation. */ + + /* Set initial state of guard variables for this table.*/ + join_tab->found=0; + join_tab->not_null_compl= 1; + + /* Set first_unmatched for the last inner table of this group */ + join_tab->last_inner->first_unmatched= join_tab; + } join->thd->row_count= 0; - do - { - if (join->thd->killed) // Aborted by user - { - join->thd->send_kill_message(); - return -2; /* purecov: inspected */ - } - DBUG_PRINT("info", ("select cond 0x%lx", (ulong)select_cond)); - if (!select_cond || select_cond->val_int()) - { - /* - There is no select condition or the attached pushed down - condition is true => a match is found. - */ - bool found= 1; - while (join_tab->first_unmatched && found) - { - /* - The while condition is always false if join_tab is not - the last inner join table of an outer join operation. - */ - first_unmatched= join_tab->first_unmatched; - /* - Mark that a match for current outer table is found. - This activates push down conditional predicates attached - to the all inner tables of the outer join. - */ - first_unmatched->found= 1; - for (tab= first_unmatched; tab <= join_tab; tab++) - { - /* Check all predicates that has just been activated. */ - /* - Actually all predicates non-guarded by first_unmatched->found - will be re-evaluated again. It could be fixed, but, probably, - it's not worth doing now. - */ - if (tab->select_cond && !tab->select_cond->val_int()) - { - /* The condition attached to table tab is false */ - if (tab == join_tab) - found= 0; - else - { - /* - Set a return point if rejected predicate is attached - not to the last table of the current nest level. - */ - join->return_tab= tab; - return 0; - } - } - } - /* - Check whether join_tab is not the last inner table - for another embedding outer join. - */ - if ((first_unmatched= first_unmatched->first_upper) && - first_unmatched->last_inner != join_tab) - first_unmatched= 0; - join_tab->first_unmatched= first_unmatched; - } - - /* - It was not just a return to lower loop level when one - of the newly activated predicates is evaluated as false - (See above join->return_tab= tab). - */ - join->examined_rows++; - join->thd->row_count++; - - if (found) - { - if (not_exists_optimize) - break; - /* A match from join_tab is found for the current partial join. */ - if ((error=(*join_tab->next_select)(join, join_tab+1, 0)) < 0) - return error; - if (join->return_tab < join_tab) - return 0; - /* - Test if this was a SELECT DISTINCT query on a table that - was not in the field list; In this case we can abort if - we found a row, as no new rows can be added to the result. - */ - if (not_used_in_distinct && found_records != join->found_records) - return 0; - } - else - info->file->unlock_row(); - } - else - { - /* - The condition pushed down to the table join_tab rejects all rows - with the beginning coinciding with the current partial join. - */ - join->examined_rows++; - join->thd->row_count++; - } - } while (!(error=info->read_record(info)) && !(*report_error)); + error= (*join_tab->read_first_record)(join_tab); + rc= evaluate_join_record(join, join_tab, error, report_error); } - if (error > 0 || (*report_error)) // Fatal error - return -1; - if (join_tab->last_inner && !join_tab->found) - { - /* - The table join_tab is the first inner table of a outer join operation - and no matches has been found for the current outer row. + while (rc == NESTED_LOOP_OK) + { + error= info->read_record(info); + rc= evaluate_join_record(join, join_tab, error, report_error); + } + + if (rc == NESTED_LOOP_NO_MORE_ROWS && + join_tab->last_inner && !join_tab->found) + rc= evaluate_null_complemented_join_record(join, join_tab); + + if (rc == NESTED_LOOP_NO_MORE_ROWS) + rc= NESTED_LOOP_OK; + return rc; +} + + +/* + Process one record of the nested loop join. + + DESCRIPTION + This function will evaluate parts of WHERE/ON clauses that are + applicable to the partial record on hand and in case of success + submit this record to the next level of the nested loop. +*/ + +static enum_nested_loop_state +evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, + int error, my_bool *report_error) +{ + bool not_exists_optimize= join_tab->table->reginfo.not_exists_optimize; + bool not_used_in_distinct=join_tab->not_used_in_distinct; + ha_rows found_records=join->found_records; + COND *select_cond= join_tab->select_cond; + + if (error > 0 || (*report_error)) // Fatal error + return NESTED_LOOP_ERROR; + if (error < 0) + return NESTED_LOOP_NO_MORE_ROWS; + if (join->thd->killed) // Aborted by user + { + join->thd->send_kill_message(); + return NESTED_LOOP_KILLED; /* purecov: inspected */ + } + DBUG_PRINT("info", ("select cond 0x%lx", (ulong)select_cond)); + if (!select_cond || select_cond->val_int()) + { + /* + There is no select condition or the attached pushed down + condition is true => a match is found. */ - JOIN_TAB *last_inner_tab= join_tab->last_inner; - for ( ; join_tab <= last_inner_tab ; join_tab++) - { - /* Change the the values of guard predicate variables. */ - join_tab->found= 1; - join_tab->not_null_compl= 0; - /* The outer row is complemented by nulls for each inner tables */ - restore_record(join_tab->table,s->default_values); // Make empty record - mark_as_null_row(join_tab->table); // For group by without error - select_cond= join_tab->select_cond; - /* Check all attached conditions for inner table rows. */ - if (select_cond && !select_cond->val_int()) - return 0; - } - join_tab--; - /* - The row complemented by nulls might be the first row - of embedding outer joins. - If so, perform the same actions as in the code - for the first regular outer join row above. - */ - for ( ; ; ) + bool found= 1; + while (join_tab->first_unmatched && found) { - first_unmatched= join_tab->first_unmatched; + /* + The while condition is always false if join_tab is not + the last inner join table of an outer join operation. + */ + JOIN_TAB *first_unmatched= join_tab->first_unmatched; + /* + Mark that a match for current outer table is found. + This activates push down conditional predicates attached + to the all inner tables of the outer join. + */ + first_unmatched->found= 1; + for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++) + { + /* Check all predicates that has just been activated. */ + /* + Actually all predicates non-guarded by first_unmatched->found + will be re-evaluated again. It could be fixed, but, probably, + it's not worth doing now. + */ + if (tab->select_cond && !tab->select_cond->val_int()) + { + /* The condition attached to table tab is false */ + if (tab == join_tab) + found= 0; + else + { + /* + Set a return point if rejected predicate is attached + not to the last table of the current nest level. + */ + join->return_tab= tab; + return NESTED_LOOP_OK; + } + } + } + /* + Check whether join_tab is not the last inner table + for another embedding outer join. + */ if ((first_unmatched= first_unmatched->first_upper) && first_unmatched->last_inner != join_tab) first_unmatched= 0; join_tab->first_unmatched= first_unmatched; - if (!first_unmatched) - break; - first_unmatched->found= 1; - for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++) - { - if (tab->select_cond && !tab->select_cond->val_int()) - { - join->return_tab= tab; - return 0; - } - } } + /* - The row complemented by nulls satisfies all conditions - attached to inner tables. - Send the row complemented by nulls to be joined with the - remaining tables. - */ - if ((error=(*join_tab->next_select)(join, join_tab+1 ,0)) < 0) - return error; + It was not just a return to lower loop level when one + of the newly activated predicates is evaluated as false + (See above join->return_tab= tab). + */ + join->examined_rows++; + join->thd->row_count++; + + if (found) + { + enum enum_nested_loop_state rc; + if (not_exists_optimize) + return NESTED_LOOP_NO_MORE_ROWS; + /* A match from join_tab is found for the current partial join. */ + rc= (*join_tab->next_select)(join, join_tab+1, 0); + if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS) + return rc; + if (join->return_tab < join_tab) + return NESTED_LOOP_OK; + /* + Test if this was a SELECT DISTINCT query on a table that + was not in the field list; In this case we can abort if + we found a row, as no new rows can be added to the result. + */ + if (not_used_in_distinct && found_records != join->found_records) + return NESTED_LOOP_OK; + } + else + join_tab->read_record.file->unlock_row(); } - return 0; + else + { + /* + The condition pushed down to the table join_tab rejects all rows + with the beginning coinciding with the current partial join. + */ + join->examined_rows++; + join->thd->row_count++; + } + return NESTED_LOOP_OK; } -static int +/* + DESCRIPTION + Construct a NULL complimented partial join record and feed it to the next + level of the nested loop. This function is used in case we have + an OUTER join and no matching record was found. +*/ + +static enum_nested_loop_state +evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab) +{ + /* + The table join_tab is the first inner table of a outer join operation + and no matches has been found for the current outer row. + */ + JOIN_TAB *last_inner_tab= join_tab->last_inner; + /* Cache variables for faster loop */ + COND *select_cond; + for ( ; join_tab <= last_inner_tab ; join_tab++) + { + /* Change the the values of guard predicate variables. */ + join_tab->found= 1; + join_tab->not_null_compl= 0; + /* The outer row is complemented by nulls for each inner tables */ + restore_record(join_tab->table,s->default_values); // Make empty record + mark_as_null_row(join_tab->table); // For group by without error + select_cond= join_tab->select_cond; + /* Check all attached conditions for inner table rows. */ + if (select_cond && !select_cond->val_int()) + return NESTED_LOOP_OK; + } + join_tab--; + /* + The row complemented by nulls might be the first row + of embedding outer joins. + If so, perform the same actions as in the code + for the first regular outer join row above. + */ + for ( ; ; ) + { + JOIN_TAB *first_unmatched= join_tab->first_unmatched; + if ((first_unmatched= first_unmatched->first_upper) && + first_unmatched->last_inner != join_tab) + first_unmatched= 0; + join_tab->first_unmatched= first_unmatched; + if (!first_unmatched) + break; + first_unmatched->found= 1; + for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++) + { + if (tab->select_cond && !tab->select_cond->val_int()) + { + join->return_tab= tab; + return NESTED_LOOP_OK; + } + } + } + /* + The row complemented by nulls satisfies all conditions + attached to inner tables. + Send the row complemented by nulls to be joined with the + remaining tables. + */ + return (*join_tab->next_select)(join, join_tab+1, 0); +} + + +static enum_nested_loop_state flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) { + enum_nested_loop_state rc= NESTED_LOOP_OK; int error; READ_RECORD *info; if (!join_tab->cache.records) - return 0; /* Nothing to do */ + return NESTED_LOOP_OK; /* Nothing to do */ if (skip_last) (void) store_record_in_cache(&join_tab->cache); // Must save this for later if (join_tab->use_quick == 2) @@ -9396,7 +9404,7 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) if ((error=join_init_read_record(join_tab))) { reset_cache_write(&join_tab->cache); - return -error; /* No records or error */ + return error < 0 ? NESTED_LOOP_NO_MORE_ROWS: NESTED_LOOP_ERROR; } for (JOIN_TAB *tmp=join->join_tab; tmp != join_tab ; tmp++) @@ -9411,11 +9419,11 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) if (join->thd->killed) { join->thd->send_kill_message(); - return -2; // Aborted by user /* purecov: inspected */ + return NESTED_LOOP_KILLED; // Aborted by user /* purecov: inspected */ } SQL_SELECT *select=join_tab->select; - if (!error && (!join_tab->cache.select || - !join_tab->cache.select->skip_record())) + if (rc == NESTED_LOOP_OK && + (!join_tab->cache.select || !join_tab->cache.select->skip_record())) { uint i; reset_cache_read(&join_tab->cache); @@ -9423,11 +9431,14 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) { read_cached_record(join_tab); if (!select || !select->skip_record()) - if ((error=(join_tab->next_select)(join,join_tab+1,0)) < 0) + { + rc= (join_tab->next_select)(join,join_tab+1,0); + if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS) { reset_cache_write(&join_tab->cache); - return error; /* purecov: inspected */ + return rc; } + } } } } while (!(error=info->read_record(info))); @@ -9436,10 +9447,10 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) read_cached_record(join_tab); // Restore current record reset_cache_write(&join_tab->cache); if (error > 0) // Fatal error - return -1; /* purecov: inspected */ + return NESTED_LOOP_ERROR; /* purecov: inspected */ for (JOIN_TAB *tmp2=join->join_tab; tmp2 != join_tab ; tmp2++) tmp2->table->status=tmp2->status; - return 0; + return NESTED_LOOP_OK; } @@ -9905,13 +9916,32 @@ join_read_next_same_or_null(READ_RECORD *info) /***************************************************************************** - The different end of select functions - These functions returns < 0 when end is reached, 0 on ok and > 0 if a - fatal error (like table corruption) was detected + DESCRIPTION + Functions that end one nested loop iteration. Different functions + are used to support GROUP BY clause and to redirect records + to a table (e.g. in case of SELECT into a temporary table) or to the + network client. + + RETURN VALUES + NESTED_LOOP_OK - the record has been successfully handled + NESTED_LOOP_ERROR - a fatal error (like table corruption) + was detected + NESTED_LOOP_KILLED - thread shutdown was requested while processing + the record + NESTED_LOOP_QUERY_LIMIT - the record has been successfully handled; + additionally, the nested loop produced the + number of rows specified in the LIMIT clause + for the query + NESTED_LOOP_CURSOR_LIMIT - the record has been successfully handled; + additionally, there is a cursor and the nested + loop algorithm produced the number of rows + that is specified for current cursor fetch + operation. + All return values except NESTED_LOOP_OK abort the nested loop. *****************************************************************************/ /* ARGSUSED */ -static int +static enum_nested_loop_state end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records) { @@ -9920,14 +9950,14 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { int error; if (join->having && join->having->val_int() == 0) - DBUG_RETURN(0); // Didn't match having + DBUG_RETURN(NESTED_LOOP_OK); // Didn't match having error=0; if (join->procedure) error=join->procedure->send_row(*join->fields); else if (join->do_send_rows) error=join->result->send_data(*join->fields); if (error) - DBUG_RETURN(-1); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ if (++join->send_records >= join->unit->select_limit_cnt && join->do_send_rows) { @@ -9961,10 +9991,10 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), join->do_send_rows= 0; if (join->unit->fake_select_lex) join->unit->fake_select_lex->select_limit= HA_POS_ERROR; - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } } - DBUG_RETURN(-3); // Abort nicely + DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT); // Abort nicely } else if (join->send_records >= join->fetch_limit) { @@ -9972,20 +10002,20 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), There is a server side cursor and all rows for this fetch request are sent. */ - DBUG_RETURN(-4); + DBUG_RETURN(NESTED_LOOP_CURSOR_LIMIT); } } else { if (join->procedure && join->procedure->end_of_records()) - DBUG_RETURN(-1); + DBUG_RETURN(NESTED_LOOP_ERROR); } - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } /* ARGSUSED */ -static int +static enum_nested_loop_state end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records) { @@ -10037,14 +10067,14 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), } } if (error > 0) - DBUG_RETURN(-1); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ if (end_of_records) - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); if (join->send_records >= join->unit->select_limit_cnt && join->do_send_rows) { if (!(join->select_options & OPTION_FOUND_ROWS)) - DBUG_RETURN(-3); // Abort nicely + DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT); // Abort nicely join->do_send_rows=0; join->unit->select_limit_cnt = HA_POS_ERROR; } @@ -10054,14 +10084,14 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), There is a server side cursor and all rows for this fetch request are sent. */ - DBUG_RETURN(-4); + DBUG_RETURN(NESTED_LOOP_CURSOR_LIMIT); } } } else { if (end_of_records) - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); join->first_record=1; VOID(test_if_group_changed(join->group_fields)); } @@ -10069,33 +10099,32 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { copy_fields(&join->tmp_table_param); if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1])) - DBUG_RETURN(-1); + DBUG_RETURN(NESTED_LOOP_ERROR); if (join->procedure) join->procedure->add(); - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } } if (update_sum_func(join->sum_funcs)) - DBUG_RETURN(-1); + DBUG_RETURN(NESTED_LOOP_ERROR); if (join->procedure) join->procedure->add(); - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } /* ARGSUSED */ -static int +static enum_nested_loop_state end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records) { TABLE *table=join->tmp_table; - int error; DBUG_ENTER("end_write"); if (join->thd->killed) // Aborted by user { join->thd->send_kill_message(); - DBUG_RETURN(-2); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ } if (!end_of_records) { @@ -10120,6 +10149,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), #endif if (!join->having || join->having->val_int()) { + int error; join->found_records++; if ((error=table->file->write_row(table->record[0]))) { @@ -10128,28 +10158,28 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), goto end; if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param, error,1)) - DBUG_RETURN(-1); // Not a table_is_full error + DBUG_RETURN(NESTED_LOOP_ERROR); // Not a table_is_full error table->s->uniques=0; // To ensure rows are the same } if (++join->send_records >= join->tmp_table_param.end_write_records && join->do_send_rows) { if (!(join->select_options & OPTION_FOUND_ROWS)) - DBUG_RETURN(-3); + DBUG_RETURN(NESTED_LOOP_QUERY_LIMIT); join->do_send_rows=0; join->unit->select_limit_cnt = HA_POS_ERROR; - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } } } end: - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } /* Group by searching after group record and updating it if possible */ /* ARGSUSED */ -static int +static enum_nested_loop_state end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records) { @@ -10159,11 +10189,11 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), DBUG_ENTER("end_update"); if (end_of_records) - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); if (join->thd->killed) // Aborted by user { join->thd->send_kill_message(); - DBUG_RETURN(-2); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ } join->found_records++; @@ -10187,9 +10217,9 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), table->record[0]))) { table->file->print_error(error,MYF(0)); /* purecov: inspected */ - DBUG_RETURN(-1); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ } - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } /* @@ -10211,19 +10241,19 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param, error, 0)) - DBUG_RETURN(-1); // Not a table_is_full error + DBUG_RETURN(NESTED_LOOP_ERROR); // Not a table_is_full error /* Change method to update rows */ table->file->ha_index_init(0); join->join_tab[join->tables-1].next_select=end_unique_update; } join->send_records++; - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } /* Like end_update, but this is done with unique constraints instead of keys */ -static int +static enum_nested_loop_state end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records) { @@ -10232,11 +10262,11 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), DBUG_ENTER("end_unique_update"); if (end_of_records) - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); if (join->thd->killed) // Aborted by user { join->thd->send_kill_message(); - DBUG_RETURN(-2); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ } init_tmptable_sum_functions(join->sum_funcs); @@ -10250,12 +10280,12 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if ((int) table->file->get_dup_key(error) < 0) { table->file->print_error(error,MYF(0)); /* purecov: inspected */ - DBUG_RETURN(-1); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ } if (table->file->rnd_pos(table->record[1],table->file->dupp_ref)) { table->file->print_error(error,MYF(0)); /* purecov: inspected */ - DBUG_RETURN(-1); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ } restore_record(table,record[1]); update_tmptable_sum_func(join->sum_funcs,table); @@ -10263,27 +10293,26 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), table->record[0]))) { table->file->print_error(error,MYF(0)); /* purecov: inspected */ - DBUG_RETURN(-1); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */ } } - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } /* ARGSUSED */ -static int +static enum_nested_loop_state end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), bool end_of_records) { TABLE *table=join->tmp_table; - int error; int idx= -1; DBUG_ENTER("end_write_group"); if (join->thd->killed) { // Aborted by user join->thd->send_kill_message(); - DBUG_RETURN(-2); /* purecov: inspected */ + DBUG_RETURN(NESTED_LOOP_KILLED); /* purecov: inspected */ } if (!join->first_record || end_of_records || (idx=test_if_group_changed(join->group_fields)) >= 0) @@ -10302,28 +10331,27 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), } copy_sum_funcs(join->sum_funcs, join->sum_funcs_end[send_group_parts]); - if (join->having && join->having->val_int() == 0) - error= -1; - else if ((error= table->file->write_row(table->record[0]))) + if (!join->having || join->having->val_int()) { - if (create_myisam_from_heap(join->thd, table, - &join->tmp_table_param, - error, 0)) - DBUG_RETURN(-1); + int error= table->file->write_row(table->record[0]); + if (error && create_myisam_from_heap(join->thd, table, + &join->tmp_table_param, + error, 0)) + DBUG_RETURN(NESTED_LOOP_ERROR); } if (join->rollup.state != ROLLUP::STATE_NONE) { if (join->rollup_write_data((uint) (idx+1), table)) - DBUG_RETURN(-1); + DBUG_RETURN(NESTED_LOOP_ERROR); } if (end_of_records) - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } } else { if (end_of_records) - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); join->first_record=1; VOID(test_if_group_changed(join->group_fields)); } @@ -10332,17 +10360,17 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), copy_fields(&join->tmp_table_param); copy_funcs(join->tmp_table_param.items_to_copy); if (init_sum_functions(join->sum_funcs, join->sum_funcs_end[idx+1])) - DBUG_RETURN(-1); + DBUG_RETURN(NESTED_LOOP_ERROR); if (join->procedure) join->procedure->add(); - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } } if (update_sum_func(join->sum_funcs)) - DBUG_RETURN(-1); + DBUG_RETURN(NESTED_LOOP_ERROR); if (join->procedure) join->procedure->add(); - DBUG_RETURN(0); + DBUG_RETURN(NESTED_LOOP_OK); } diff --git a/sql/sql_select.h b/sql/sql_select.h index c9a9b26d1b4..82efb62f7a3 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -91,7 +91,15 @@ enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF, class JOIN; -typedef int (*Next_select_func)(JOIN *,struct st_join_table *,bool); +enum enum_nested_loop_state +{ + NESTED_LOOP_KILLED= -2, NESTED_LOOP_ERROR= -1, + NESTED_LOOP_OK= 0, NESTED_LOOP_NO_MORE_ROWS= 1, + NESTED_LOOP_QUERY_LIMIT= 3, NESTED_LOOP_CURSOR_LIMIT= 4 +}; + +typedef enum_nested_loop_state +(*Next_select_func)(JOIN *, struct st_join_table *, bool); typedef int (*Read_record_func)(struct st_join_table *tab); @@ -162,6 +170,11 @@ class JOIN :public Sql_alloc uint send_group_parts; bool sort_and_group,first_record,full_join,group, no_field_update; bool do_send_rows; + /* + TRUE when we want to resume nested loop iterations when + fetching data from a cursor + */ + bool resume_nested_loop; table_map const_table_map,found_const_table_map,outer_join; ha_rows send_records,found_records,examined_rows,row_limit, select_limit; /* @@ -263,6 +276,7 @@ class JOIN :public Sql_alloc sort_and_group= 0; first_record= 0; do_send_rows= 1; + resume_nested_loop= FALSE; send_records= 0; found_records= 0; fetch_limit= HA_POS_ERROR; @@ -374,7 +388,7 @@ public: void reset_thd(THD *thd); int open(JOIN *join); - int fetch(ulong num_rows); + void fetch(ulong num_rows); void reset() { join= 0; } bool is_open() const { return join != 0; } void close(); diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 9b7c8281043..e5818449fcb 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -12854,6 +12854,59 @@ static void test_bug9159() myquery(rc); } + +/* Crash when opening a cursor to a query with DISTICNT and no key */ + +static void test_bug9520() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + char a[6]; + ulong a_len; + int rc, row_count= 0; + + myheader("test_bug9520"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (a char(5), b char(5), c char(5)," + " primary key (a, b, c))"); + rc= mysql_query(mysql, "insert into t1 values ('x', 'y', 'z'), " + " ('a', 'b', 'c'), ('k', 'l', 'm')"); + myquery(rc); + + stmt= open_cursor("select distinct b from t1"); + + /* + Not crashes with: + stmt= open_cursor("select distinct a from t1"); + */ + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + bzero(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (char*) a; + bind[0].buffer_length= sizeof(a); + bind[0].length= &a_len; + + mysql_stmt_bind_result(stmt, bind); + + while (!(rc= mysql_stmt_fetch(stmt))) + row_count++; + + DIE_UNLESS(rc == MYSQL_NO_DATA); + + printf("Fetched %d rows\n", row_count); + DBUG_ASSERT(row_count == 3); + + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -13079,6 +13132,7 @@ static struct my_tests_st my_tests[]= { { "test_bug8722", test_bug8722 }, { "test_bug8880", test_bug8880 }, { "test_bug9159", test_bug9159 }, + { "test_bug9520", test_bug9520 }, { 0, 0 } }; From d1d474c812a1020af48bebe6ecc68bdc51d0674c Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 30 Apr 2005 18:40:08 +0300 Subject: [PATCH 78/78] After merge fixes Makefile.am: Added target test-force mysql-test/r/cast.result: Updated results after merge --- Makefile.am | 5 +++++ mysql-test/r/cast.result | 2 ++ 2 files changed, 7 insertions(+) diff --git a/Makefile.am b/Makefile.am index 78efd47b762..7905869f833 100644 --- a/Makefile.am +++ b/Makefile.am @@ -102,5 +102,10 @@ tags: test: cd mysql-test; ./mysql-test-run && ./mysql-test-run --ps-protocol +test-force: + cd mysql-test; \ + mysql-test-run --force ;\ + mysql-test-run --ps-protocol --force + # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index c5fa5d076cc..6dc608a9289 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -7,6 +7,8 @@ CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER) select CAST('10 ' as unsigned integer); CAST('10 ' as unsigned integer) 10 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: '10 ' select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1; cast(-5 as unsigned) | 1 cast(-5 as unsigned) & -1 18446744073709551611 18446744073709551611