summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <monty@hundin.mysql.fi>2002-01-02 21:29:41 +0200
committerunknown <monty@hundin.mysql.fi>2002-01-02 21:29:41 +0200
commitf4fee3d90e8456cfd2a4e2f395bd270d0a12c70d (patch)
treeef8afaf7a0fed42b30ef0d9d38acccc992b5f87d /sql
parent27f652efefba29bf58f45cbfe21a4228ec6fdb34 (diff)
downloadmariadb-git-f4fee3d90e8456cfd2a4e2f395bd270d0a12c70d.tar.gz
Added macros for nice TIMESPEC usage.
Fixes for building MySQL with gcc 3.0 Added SIGNED / UNSIGNED casts Fixed core dump bug in net_clear() with libmysqld. Back to using semaphores in query cache. Added 'Null' and 'Index_type' to SHOW INDEX. BUILD/FINISH.sh: Fixes for gcc 3.0 BUILD/SETUP.sh: Fixes for gcc 3.0 Docs/manual.texi: Changelog + SIGNED/UNSIGNED casts. Makefile.am: include BUILD scripts in source distribution. client/Makefile.am: Fixes for gcc 3.0 client/mysql.cc: Cleanup client/mysqldump.c: Changed 'K' to mean 'disable-keys' instead of 'no-disabled-keys' client/readline.cc: Cleanup configure.in: Include BUILD in source distrbution extra/my_print_defaults.c: Cleanup include/my_global.h: Fix for HPUX and setrlimit. Portability fix. Added macros for nice TIMESPEC usage. innobase/include/dyn0dyn.h: Fix for AIX libmysql/Makefile.shared: Added strxmov to libmysqld libmysqld/examples/Makefile.am: Fixes for gcc 3.0 libmysqld/lib_vio.c: Cleanup myisam/ft_dump.c: Portability fixes myisam/ftdefs.h: Portability fixes mysql-test/r/bdb.result: Cleanup results after adding 2 columns to SHOW KEYS mysql-test/r/bigint.result: New test for SIGNED/UNSIGNED mysql-test/r/fulltext.result: Cleanup results after adding 2 columns to SHOW KEYS mysql-test/r/heap.result: Cleanup results after adding 2 columns to SHOW KEYS mysql-test/r/innodb.result: Cleanup results after adding 2 columns to SHOW KEYS mysql-test/r/isam.result: Cleanup results after adding 2 columns to SHOW KEYS mysql-test/r/key.result: Cleanup results after adding 2 columns to SHOW KEYS mysql-test/r/myisam.result: Cleanup results after adding 2 columns to SHOW KEYS mysql-test/r/query_cache.result: Cleanup results after adding 2 columns to SHOW KEYS mysql-test/r/select.result: Cleanup results after adding 2 columns to SHOW KEYS mysql-test/r/show_check.result: Cleanup results after adding 2 columns to SHOW KEYS mysql-test/r/type_ranges.result: Cleanup results after adding 2 columns to SHOW KEYS mysql-test/t/bigint.test: New test for SIGNED/UNSIGNED mysql-test/t/key.test: New test for SIGNED/UNSIGNED mysql-test/t/query_cache.test: Test for FOUND_ROWS() sql-bench/crash-me.sh: Safety fixes sql/derror.cc: Cleanup sql/ha_berkeley.h: New test for SIGNED/UNSIGNED sql/ha_heap.h: New test for SIGNED/UNSIGNED sql/ha_innobase.cc: New test for SIGNED/UNSIGNED sql/ha_innobase.h: New test for SIGNED/UNSIGNED sql/ha_isam.h: New test for SIGNED/UNSIGNED sql/ha_myisam.cc: New test for SIGNED/UNSIGNED sql/ha_myisam.h: New test for SIGNED/UNSIGNED sql/handler.h: New test for SIGNED/UNSIGNED sql/item_func.cc: Cleanup TIMESPEC usage sql/item_func.h: Added SIGNED / UNSIGNED casts sql/lex.h: Added SIGNED / UNSIGNED casts sql/mysqld.cc: Cleanup TIMESPEC usage sql/net_pkg.cc: Cleanup sql/net_serv.cc: Fixed core dump bug in net_clear() sql/slave.cc: Cleanup sql/sql_cache.cc: Back to using semaphores sql/sql_cache.h: Back to using semaphores sql/sql_insert.cc: Cleanup TIMESPEC usage sql/sql_manager.cc: Cleanup TIMESPEC usage sql/sql_parse.cc: Cleanup sql/sql_repl.cc: Cleanup TIMESPEC usage sql/sql_show.cc: Added 'Null' and 'Index_type' to SHOW INDEX. sql/sql_table.cc: Sort keys in table in a more logical order. sql/sql_yacc.yy: Support for SIGNED/UNSIGNED casts.
Diffstat (limited to 'sql')
-rw-r--r--sql/derror.cc34
-rw-r--r--sql/ha_berkeley.h1
-rw-r--r--sql/ha_heap.h1
-rw-r--r--sql/ha_innobase.cc21
-rw-r--r--sql/ha_innobase.h1
-rw-r--r--sql/ha_isam.h1
-rw-r--r--sql/ha_myisam.cc14
-rw-r--r--sql/ha_myisam.h3
-rw-r--r--sql/handler.h1
-rw-r--r--sql/item_func.cc18
-rw-r--r--sql/item_func.h21
-rw-r--r--sql/lex.h1
-rw-r--r--sql/mysqld.cc10
-rw-r--r--sql/net_pkg.cc2
-rw-r--r--sql/net_serv.cc2
-rw-r--r--sql/slave.cc62
-rw-r--r--sql/sql_cache.cc60
-rw-r--r--sql/sql_cache.h7
-rw-r--r--sql/sql_insert.cc16
-rw-r--r--sql/sql_manager.cc8
-rw-r--r--sql/sql_parse.cc4
-rw-r--r--sql/sql_repl.cc25
-rw-r--r--sql/sql_show.cc14
-rw-r--r--sql/sql_table.cc105
-rw-r--r--sql/sql_yacc.yy8
25 files changed, 242 insertions, 198 deletions
diff --git a/sql/derror.cc b/sql/derror.cc
index d0519c37dca..7ebe6e4b3c5 100644
--- a/sql/derror.cc
+++ b/sql/derror.cc
@@ -44,7 +44,7 @@ static void read_texts(const char *file_name,const char ***point,
uint error_messages)
{
register uint i;
- uint ant,funktpos,length,textant;
+ uint count,funktpos,length,textcount;
File file;
char name[FN_REFLEN];
const char *buff;
@@ -64,36 +64,38 @@ static void read_texts(const char *file_name,const char ***point,
if (head[0] != (uchar) 254 || head[1] != (uchar) 254 ||
head[2] != 2 || head[3] != 1)
goto err; /* purecov: inspected */
- textant=head[4];
- length=uint2korr(head+6); ant=uint2korr(head+8);
+ textcount=head[4];
+ length=uint2korr(head+6); count=uint2korr(head+8);
- if (ant < error_messages)
+ if (count < error_messages)
{
- fprintf(stderr,"\n%s: Fatal error: Error message file '%s' had only %d error messages, but it should have at least %d error messages.\n\
-Check that the above file is the right version for this program!\n\n",
- my_progname,name,ant,error_messages);
+ sql_print_error("\
+Error message file '%s' had only %d error messages,\n\
+but it should contain at least %d error messages.\n\
+Check that the above file is the right version for this program!",
+ name,count,error_messages);
VOID(my_close(file,MYF(MY_WME)));
unireg_abort(1);
}
x_free((gptr) *point); /* Free old language */
if (!(*point= (const char**)
- my_malloc((uint) (length+ant*sizeof(char*)),MYF(0))))
+ my_malloc((uint) (length+count*sizeof(char*)),MYF(0))))
{
funktpos=2; /* purecov: inspected */
goto err; /* purecov: inspected */
}
- buff= (char*) (*point + ant);
+ buff= (char*) (*point + count);
- if (my_read(file,(byte*) buff,(uint) ant*2,MYF(MY_NABP))) goto err;
- for (i=0, pos= (uchar*) buff ; i< ant ; i++)
+ if (my_read(file,(byte*) buff,(uint) count*2,MYF(MY_NABP))) goto err;
+ for (i=0, pos= (uchar*) buff ; i< count ; i++)
{
(*point)[i]=buff+uint2korr(pos);
pos+=2;
}
if (my_read(file,(byte*) buff,(uint) length,MYF(MY_NABP))) goto err;
- for (i=1 ; i < textant ; i++)
+ for (i=1 ; i < textcount ; i++)
{
point[i]= *point +uint2korr(head+10+i+i);
}
@@ -103,18 +105,18 @@ Check that the above file is the right version for this program!\n\n",
err:
switch (funktpos) {
case 2:
- buff="\n%s: Fatal error: Not enough memory for messagefile '%s'\n\n";
+ buff="Not enough memory for messagefile '%s'";
break;
case 1:
- buff="\n%s: Fatal error: Can't read from messagefile '%s'\n\n";
+ buff="Can't read from messagefile '%s'";
break;
default:
- buff="\n%s: Fatal error: Can't find messagefile '%s'\n\n";
+ buff="Can't find messagefile '%s'";
break;
}
if (file != FERR)
VOID(my_close(file,MYF(MY_WME)));
- fprintf(stderr,buff,my_progname,name);
+ sql_print_error(buff,name);
unireg_abort(1);
} /* read_texts */
diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h
index 65116f908ac..fbc858b5996 100644
--- a/sql/ha_berkeley.h
+++ b/sql/ha_berkeley.h
@@ -98,6 +98,7 @@ class ha_berkeley: public handler
}
~ha_berkeley() {}
const char *table_type() const { return "BerkeleyDB"; }
+ const char *index_type(uint key_number) { return "BTREE"; }
const char **bas_ext() const;
ulong option_flag() const { return int_option_flag; }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
diff --git a/sql/ha_heap.h b/sql/ha_heap.h
index 9b041411012..fa077cef60a 100644
--- a/sql/ha_heap.h
+++ b/sql/ha_heap.h
@@ -31,6 +31,7 @@ class ha_heap: public handler
ha_heap(TABLE *table): handler(table), file(0) {}
~ha_heap() {}
const char *table_type() const { return "HEAP"; }
+ const char *index_type(uint key_number) { return "HASH"; }
const char **bas_ext() const;
ulong option_flag() const
{ return (HA_READ_RND_SAME | HA_NO_INDEX | HA_ONLY_WHOLE_INDEX |
diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc
index 836a1a4331e..3b6b15d1e79 100644
--- a/sql/ha_innobase.cc
+++ b/sql/ha_innobase.cc
@@ -580,7 +580,7 @@ innobase_init(void)
ret = innobase_parse_data_file_paths_and_sizes();
if (ret == FALSE) {
- fprintf(stderr, "InnoDB: syntax error in innodb_data_file_path\n");
+ sql_print_error("InnoDB: syntax error in innodb_data_file_path");
DBUG_RETURN(TRUE);
}
@@ -928,13 +928,13 @@ ha_innobase::open(
if (NULL == (ib_table = dict_table_get(norm_name, NULL))) {
- fprintf(stderr,
-"InnoDB: Error: cannot find table %s from the internal data dictionary\n"
-"InnoDB: of InnoDB though the .frm file for the table exists. Maybe you\n"
-"InnoDB: have deleted and recreated InnoDB data files but have forgotten\n"
-"InnoDB: to delete the corresponding .frm files of InnoDB tables, or you\n"
-"InnoDB: have moved .frm files to another database?\n",
- norm_name);
+ sql_print_error("InnoDB error:\n\
+Cannot find table %s from the internal data dictionary\n\
+of InnoDB though the .frm file for the table exists. Maybe you\n\
+have deleted and recreated InnoDB data files but have forgotten\n\
+to delete the corresponding .frm files of InnoDB tables, or you\n\
+have moved .frm files to another database?",
+ norm_name);
free_share(share);
my_free((char*) upd_buff, MYF(0));
@@ -2034,10 +2034,7 @@ ha_innobase::change_active_index(
prebuilt->index=dict_table_get_index_noninline(prebuilt->table, key->name);
if (!prebuilt->index)
{
- fprintf(stderr,
- "InnoDB: Could not find key n:o %u with name %s from dict cache\n"
- "InnoDB: for table %s\n", keynr, key->name,
- prebuilt->table->name);
+ sql_print_error("Innodb could not find key n:o %u with name %s from dict cache for table %s", keynr, key->name, prebuilt->table->name);
return(1);
}
}
diff --git a/sql/ha_innobase.h b/sql/ha_innobase.h
index b1613c2503c..bcd11b8a96e 100644
--- a/sql/ha_innobase.h
+++ b/sql/ha_innobase.h
@@ -91,6 +91,7 @@ class ha_innobase: public handler
~ha_innobase() {}
const char* table_type() const { return("InnoDB");}
+ const char *index_type(uint key_number) { return "BTREE"; }
const char** bas_ext() const;
ulong option_flag() const { return int_option_flag; }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
diff --git a/sql/ha_isam.h b/sql/ha_isam.h
index 33ca99b5063..e878f0fe697 100644
--- a/sql/ha_isam.h
+++ b/sql/ha_isam.h
@@ -38,6 +38,7 @@ class ha_isam: public handler
{}
~ha_isam() {}
const char *table_type() const { return "ISAM"; }
+ const char *index_type(uint key_number) { return "BTREE"; }
const char **bas_ext() const;
ulong option_flag() const { return int_option_flag; }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 0378ff7ba6f..77d541bfdfb 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -80,9 +80,8 @@ static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
net_store_data(packet, msgbuf);
if (my_net_write(&thd->net, (char*)thd->packet.ptr(), thd->packet.length()))
- fprintf(stderr,
- "Failed on my_net_write, writing to stderr instead: %s\n",
- msgbuf);
+ sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n",
+ msgbuf);
return;
}
@@ -122,6 +121,13 @@ const char **ha_myisam::bas_ext() const
{ static const char *ext[]= { ".MYD",".MYI", NullS }; return ext; }
+const char *ha_myisam::index_type(uint key_number)
+{
+ return ((table->key_info[key_number].flags & HA_FULLTEXT) ?
+ "FULLTEXT" :
+ "BTREE");
+}
+
int ha_myisam::net_read_dump(NET* net)
{
int data_fd = file->dfile;
@@ -1170,7 +1176,7 @@ longlong ha_myisam::get_auto_increment()
longlong nr;
int error;
- byte key[MAX_KEY_LENGTH];
+ byte key[MI_MAX_KEY_LENGTH];
(void) extra(HA_EXTRA_KEYREAD);
key_copy(key,table,table->next_number_index,
table->next_number_key_offset);
diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h
index 7b5c959ccfa..e2044dfe1e2 100644
--- a/sql/ha_myisam.h
+++ b/sql/ha_myisam.h
@@ -54,12 +54,13 @@ class ha_myisam: public handler
{}
~ha_myisam() {}
const char *table_type() const { return "MyISAM"; }
+ const char *index_type(uint key_number);
const char **bas_ext() const;
ulong option_flag() const { return int_option_flag; }
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_keys() const { return MI_MAX_KEY; }
uint max_key_parts() const { return MAX_REF_PARTS; }
- uint max_key_length() const { return MAX_KEY_LENGTH; }
+ uint max_key_length() const { return MI_MAX_KEY_LENGTH; }
int open(const char *name, int mode, uint test_if_locked);
int close(void);
diff --git a/sql/handler.h b/sql/handler.h
index 1e2c0074475..33cfa965363 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -236,6 +236,7 @@ public:
virtual bool has_transactions(){ return 0;}
virtual uint extra_rec_buf_length() { return 0; }
virtual ha_rows estimate_number_of_rows() { return records+EXTRA_RECORDS; }
+ virtual const char *index_type(uint key_number) { return "";}
virtual int index_init(uint idx) { active_index=idx; return 0;}
virtual int index_end() {return 0; }
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 4caa959bce8..93edcc64146 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1496,14 +1496,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout)
thd->mysys_var->current_mutex= &LOCK_user_locks;
thd->mysys_var->current_cond= &ull->cond;
-#ifdef HAVE_TIMESPEC_TS_SEC
- abstime.ts_sec=time((time_t*) 0)+(time_t) lock_timeout;
- abstime.ts_nsec=0;
-#else
- abstime.tv_sec=time((time_t*) 0)+(time_t) lock_timeout;
- abstime.tv_nsec=0;
-#endif
-
+ set_timespec(abstime,lock_timeout);
while (!thd->killed &&
(error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime))
!= ETIME && error != ETIMEDOUT && ull->locked) ;
@@ -1591,14 +1584,7 @@ longlong Item_func_get_lock::val_int()
thd->mysys_var->current_mutex= &LOCK_user_locks;
thd->mysys_var->current_cond= &ull->cond;
-#ifdef HAVE_TIMESPEC_TS_SEC
- abstime.ts_sec=time((time_t*) 0)+(time_t) timeout;
- abstime.ts_nsec=0;
-#else
- abstime.tv_sec=time((time_t*) 0)+(time_t) timeout;
- abstime.tv_nsec=0;
-#endif
-
+ set_timespec(abstime,timeout);
while (!thd->killed &&
(error=pthread_cond_timedwait(&ull->cond,&LOCK_user_locks,&abstime))
!= ETIME && error != ETIMEDOUT && ull->locked) ;
diff --git a/sql/item_func.h b/sql/item_func.h
index 23cdf7082cf..648ca6d0743 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -181,6 +181,27 @@ public:
void fix_length_and_dec() { decimals=0; max_length=21; }
};
+class Item_func_signed :public Item_int_func
+{
+public:
+ Item_func_signed(Item *a) :Item_int_func(a) {}
+ double val() { return args[0]->val(); }
+ longlong val_int() { return args[0]->val_int(); }
+ void fix_length_and_dec()
+ { decimals=0; max_length=args[0]->max_length; unsigned_flag=0; }
+};
+
+class Item_func_unsigned :public Item_int_func
+{
+public:
+ Item_func_unsigned(Item *a) :Item_int_func(a) {}
+ double val() { return args[0]->val(); }
+ longlong val_int() { return args[0]->val_int(); }
+ void fix_length_and_dec()
+ { decimals=0; max_length=args[0]->max_length; unsigned_flag=1; }
+};
+
+
class Item_func_plus :public Item_num_op
{
public:
diff --git a/sql/lex.h b/sql/lex.h
index 59c71f20cd7..baabe2d16f0 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -301,6 +301,7 @@ static SYMBOL symbols[] = {
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM),0,0},
{ "SESSION", SYM(SESSION_SYM),0,0},
{ "SET", SYM(SET),0,0},
+ { "SIGNED", SYM(SIGNED),0,0},
{ "SHARE", SYM(SHARE_SYM),0,0},
{ "SHOW", SYM(SHOW),0,0},
{ "SHUTDOWN", SYM(SHUTDOWN),0,0},
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index e4e24c5ce53..a6eb447f1a1 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -447,15 +447,7 @@ static void close_connections(void)
if (pthread_kill(select_thread,THR_CLIENT_ALARM))
break; // allready dead
#endif
-#ifdef HAVE_TIMESPEC_TS_SEC
- abstime.ts_sec=time(NULL)+2; // Bsd 2.1
- abstime.ts_nsec=0;
-#else
- struct timeval tv;
- gettimeofday(&tv,0);
- abstime.tv_sec=tv.tv_sec+2;
- abstime.tv_nsec=tv.tv_usec*1000;
-#endif
+ set_timespec(abstime, 2);
for (uint tmp=0 ; tmp < 10 ; tmp++)
{
error=pthread_cond_timedwait(&COND_thread_count,&LOCK_thread_count,
diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc
index 2f26ad81bd5..64c1b07a493 100644
--- a/sql/net_pkg.cc
+++ b/sql/net_pkg.cc
@@ -52,6 +52,7 @@ void send_error(NET *net, uint sql_errno, const char *err)
{
if (thd && thd->bootstrap)
{
+ /* In bootstrap it's ok to print on stderr */
fprintf(stderr,"ERROR: %d %s\n",sql_errno,err);
}
DBUG_VOID_RETURN;
@@ -120,6 +121,7 @@ net_printf(NET *net, uint errcode, ...)
{
if (thd && thd->bootstrap)
{
+ /* In bootstrap it's ok to print on stderr */
fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos);
thd->fatal_error=1;
}
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 3e4dcb75ebb..9a8d6b5e967 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -167,7 +167,7 @@ static my_bool net_realloc(NET *net, ulong length)
void net_clear(NET *net)
{
-#ifndef EXTRA_DEBUG
+#if !defined(EXTRA_DEBUG) && !defined(EMBEDDED_LIBRARY)
int count; /* One may get 'unused' warn */
bool is_blocking=vio_is_blocking(net->vio);
if (is_blocking)
diff --git a/sql/slave.cc b/sql/slave.cc
index 33c4273bcb0..f2c29146308 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -285,11 +285,11 @@ char* rewrite_db(char* db)
I_List_iterator<i_string_pair> it(replicate_rewrite_db);
i_string_pair* tmp;
- while((tmp=it++))
- {
- if (!strcmp(tmp->key, db))
- return tmp->val;
- }
+ while ((tmp=it++))
+ {
+ if (!strcmp(tmp->key, db))
+ return tmp->val;
+ }
return db;
}
@@ -310,7 +310,7 @@ int db_ok(const char* db, I_List<i_string> &do_list,
I_List_iterator<i_string> it(do_list);
i_string* tmp;
- while((tmp=it++))
+ while ((tmp=it++))
{
if (!strcmp(tmp->ptr, db))
return 1; // match
@@ -322,7 +322,7 @@ int db_ok(const char* db, I_List<i_string> &do_list,
I_List_iterator<i_string> it(ignore_list);
i_string* tmp;
- while((tmp=it++))
+ while ((tmp=it++))
{
if (!strcmp(tmp->ptr, db))
return 0; // match
@@ -346,7 +346,7 @@ static int init_strvar_from_file(char* var, int max_size, IO_CACHE* f,
// if we truncated a line or stopped on last char, remove all chars
// up to and including newline
int c;
- while( ((c=my_b_get(f)) != '\n' && c != my_b_EOF));
+ while (((c=my_b_get(f)) != '\n' && c != my_b_EOF));
}
return 0;
}
@@ -803,7 +803,7 @@ int st_master_info::wait_for_pos(THD* thd, String* log_name, ulonglong log_pos)
bool pos_reached;
int event_count = 0;
pthread_mutex_lock(&lock);
- while(!thd->killed)
+ while (!thd->killed)
{
int cmp_result;
if (*log_file_name)
@@ -1002,8 +1002,8 @@ server_errno=%d)",
if (len == 1)
{
- sql_print_error("Slave: received 0 length packet from server, apparent\
- master shutdown: %s (%d)",
+ sql_print_error("Slave: received 0 length packet from server, apparent \
+master shutdown: %s (%d)",
mc_mysql_error(mysql), read_errno);
return packet_error;
}
@@ -1015,24 +1015,23 @@ server_errno=%d)",
int check_expected_error(THD* thd, int expected_error)
{
- switch(expected_error)
- {
- case ER_NET_READ_ERROR:
- case ER_NET_ERROR_ON_WRITE:
- case ER_SERVER_SHUTDOWN:
- case ER_NEW_ABORTING_CONNECTION:
- my_snprintf(last_slave_error, sizeof(last_slave_error),
- "Slave: query '%s' partially completed on the master \
+ switch (expected_error) {
+ case ER_NET_READ_ERROR:
+ case ER_NET_ERROR_ON_WRITE:
+ case ER_SERVER_SHUTDOWN:
+ case ER_NEW_ABORTING_CONNECTION:
+ my_snprintf(last_slave_error, sizeof(last_slave_error),"\
+Slave: query '%s' partially completed on the master \
and was aborted. There is a chance that your master is inconsistent at this \
-point. If you are sure that your master is ok, run this query manually on the\
- slave and then restart the slave with SET SQL_SLAVE_SKIP_COUNTER=1;\
- SLAVE START;", thd->query);
- last_slave_errno = expected_error;
- sql_print_error("%s",last_slave_error);
- return 1;
- default:
- return 0;
- }
+point. If you are sure that your master is ok, run this query manually on the \
+slave and then restart the slave with SET SQL_SLAVE_SKIP_COUNTER=1;\
+SLAVE START;", thd->query);
+ last_slave_errno = expected_error;
+ sql_print_error("%s",last_slave_error);
+ return 1;
+ default:
+ return 0;
+ }
}
@@ -1230,8 +1229,7 @@ try again, log '%s' at postion %s", RPL_LOG_NAME,
goto connected;
}
-
- while(!slave_killed(thd))
+ while (!slave_killed(thd))
{
thd->proc_info = "Reading master update";
ulong event_len = read_event(mysql, &glob_mi);
@@ -1323,8 +1321,8 @@ the slave thread with \"mysqladmin start-slave\". We stopped at log \
events_till_disconnect++;
}
#endif
- } // while(!slave_killed(thd)) - read/exec loop
- } // while(!slave_killed(thd)) - slave loop
+ } // while (!slave_killed(thd)) - read/exec loop
+ } // while (!slave_killed(thd)) - slave loop
// error = 0;
err:
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 523e835f472..388abd99bd5 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -288,6 +288,11 @@ If join_results allocated new block(s) then we need call pack_cache again.
pthread_mutex_lock(M);}
#define MUTEX_UNLOCK(M) {DBUG_PRINT("lock", ("mutex unlock 0x%lx",\
(ulong)(M))); pthread_mutex_unlock(M);}
+#define SEM_LOCK(M) { int val = 0; sem_getvalue (M, &val); \
+ DBUG_PRINT("lock", ("sem lock 0x%lx (%d)", (ulong)(M), val)); \
+ sem_wait(M); DBUG_PRINT("lock", ("sem lock ok")); }
+#define SEM_UNLOCK(M) {DBUG_PRINT("info", ("sem unlock 0x%lx", (ulong)(M))); \
+ sem_post(M); DBUG_PRINT("info", ("sem unlock ok")); }
#define STRUCT_LOCK(M) {DBUG_PRINT("lock", ("%d struct lock...",__LINE__)); \
pthread_mutex_lock(M);DBUG_PRINT("lock", ("struct lock OK"));}
#define STRUCT_UNLOCK(M) { \
@@ -310,6 +315,8 @@ If join_results allocated new block(s) then we need call pack_cache again.
#else
#define MUTEX_LOCK(M) pthread_mutex_lock(M)
#define MUTEX_UNLOCK(M) pthread_mutex_unlock(M)
+#define SEM_LOCK(M) sem_wait(M)
+#define SEM_UNLOCK(M) sem_post(M)
#define STRUCT_LOCK(M) pthread_mutex_lock(M)
#define STRUCT_UNLOCK(M) pthread_mutex_unlock(M)
#define BLOCK_LOCK_WR(B) B->query()->lock_writing()
@@ -426,7 +433,7 @@ void Query_cache_query::init_n_lock()
{
DBUG_ENTER("Query_cache_query::init_n_lock");
res=0; wri = 0; len = 0;
- pthread_cond_init(&lock, NULL);
+ sem_init(&lock, 0, 1);
pthread_mutex_init(&clients_guard,MY_MUTEX_INIT_FAST);
clients = 0;
lock_writing();
@@ -446,7 +453,7 @@ void Query_cache_query::unlock_n_destroy()
active semaphore
*/
this->unlock_writing();
- pthread_cond_destroy(&lock);
+ sem_destroy(&lock);
pthread_mutex_destroy(&clients_guard);
DBUG_VOID_RETURN;
}
@@ -462,9 +469,7 @@ void Query_cache_query::unlock_n_destroy()
void Query_cache_query::lock_writing()
{
- MUTEX_LOCK(&clients_guard);
- while (clients != 0)
- pthread_cond_wait(&lock,&clients_guard);
+ SEM_LOCK(&lock);
}
@@ -478,18 +483,12 @@ void Query_cache_query::lock_writing()
my_bool Query_cache_query::try_lock_writing()
{
DBUG_ENTER("Query_cache_block::try_lock_writing");
- if (pthread_mutex_trylock(&clients_guard))
- {
- DBUG_PRINT("qcache", ("can't lock mutex"));
- DBUG_RETURN(0);
- }
- if (clients != 0)
+ if (sem_trywait(&lock)!=0 || clients != 0)
{
- DBUG_PRINT("info", ("already locked (r)"));
- MUTEX_UNLOCK(&clients_guard);
+ DBUG_PRINT("info", ("can't lock semaphore"));
DBUG_RETURN(0);
}
- DBUG_PRINT("qcache", ("mutex 'lock' 0x%lx locked", (ulong) &lock));
+ DBUG_PRINT("info", ("mutex 'lock' 0x%lx locked", (ulong) &lock));
DBUG_RETURN(1);
}
@@ -497,23 +496,28 @@ my_bool Query_cache_query::try_lock_writing()
void Query_cache_query::lock_reading()
{
MUTEX_LOCK(&clients_guard);
- clients++;
+ if ( ++clients == 1 )
+ SEM_LOCK(&lock);
MUTEX_UNLOCK(&clients_guard);
}
void Query_cache_query::unlock_writing()
{
- MUTEX_UNLOCK(&clients_guard);
+ SEM_UNLOCK(&lock);
}
void Query_cache_query::unlock_reading()
{
+ /*
+ To avoid unlocking semaphore before unlocking mutex (that may cause
+ destroying locked mutex), we use temporary boolean variable 'unlock'.
+ */
MUTEX_LOCK(&clients_guard);
- if (--clients == 0)
- pthread_cond_broadcast(&lock);
+ bool ulock = ((--clients) == 0);
MUTEX_UNLOCK(&clients_guard);
+ if (ulock) SEM_UNLOCK(&lock);
}
extern "C"
@@ -1377,8 +1381,11 @@ void Query_cache::free_cache(my_bool destruction)
/* Becasue we did a flush, all cache memory must be in one this block */
bins[0].free_blocks->destroy();
total_blocks--;
- DBUG_PRINT("qcache", ("free memory %lu (should be %lu)",
- free_memory , query_cache_size));
+#ifndef DBUG_OFF
+ if (free_memory != query_cache_size)
+ DBUG_PRINT("qcache", ("free memory %lu (should be %lu)",
+ free_memory , query_cache_size));
+#endif
my_free((gptr) cache, MYF(MY_ALLOW_ZERO_PTR));
make_disabled();
hash_free(&queries);
@@ -2573,7 +2580,7 @@ my_bool Query_cache::move_by_type(byte **border,
} while ( result_block != first_result_block );
}
Query_cache_query *new_query= ((Query_cache_query *) new_block->data());
- pthread_cond_init(&new_query->lock, NULL);
+ sem_init(&new_query->lock, 0, 1);
pthread_mutex_init(&new_query->clients_guard,MY_MUTEX_INIT_FAST);
/*
@@ -2948,6 +2955,7 @@ my_bool Query_cache::check_integrity()
my_bool result = 0;
uint i;
STRUCT_LOCK(&structure_guard_mutex);
+ DBUG_ENTER("check_integrity");
if (hash_check(&queries))
{
@@ -3030,6 +3038,8 @@ my_bool Query_cache::check_integrity()
result = 1;
break;
case Query_cache_block::RES_INCOMPLETE:
+ // This type of block can be not lincked yet (in multithread environment)
+ break;
case Query_cache_block::RES_BEG:
case Query_cache_block::RES_CONT:
case Query_cache_block::RESULT:
@@ -3048,11 +3058,13 @@ my_bool Query_cache::check_integrity()
}
else
{
+ BLOCK_LOCK_RD(query_block);
if (in_list(queries_blocks, query_block, "query from results"))
result = 1;
if (in_list(query_block->query()->result(), block,
"results"))
result = 1;
+ BLOCK_UNLOCK_RD(query_block);
}
break;
}
@@ -3160,15 +3172,15 @@ my_bool Query_cache::check_integrity()
} while (block != bins[i].free_blocks);
if (count != bins[i].number)
{
- DBUG_PRINT("qcache", ("bin[%d].number is %d, but bin have %d blocks",
- bins[i].number, count));
+ DBUG_PRINT("error", ("bin[%d].number is %d, but bin have %d blocks",
+ bins[i].number, count));
result = 1;
}
}
}
DBUG_ASSERT(result == 0);
STRUCT_UNLOCK(&structure_guard_mutex);
- return result;
+ DBUG_RETURN(result);
}
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index 50ae765e446..bde11d2dbb6 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -55,6 +55,8 @@
#define TABLE_COUNTER_TYPE uint8
+#include <my_semaphore.h>
+
struct Query_cache_block;
struct Query_cache_block_table;
struct Query_cache_table;
@@ -107,7 +109,7 @@ struct Query_cache_query
Query_cache_block *res;
NET *wri;
ulong len;
- pthread_cond_t lock; // R/W lock of block
+ sem_t lock; // R/W lock of block
pthread_mutex_t clients_guard;
uint clients;
@@ -396,5 +398,8 @@ protected:
};
extern Query_cache query_cache;
+void query_cache_insert(NET *net, const char *packet, ulong length);
+void query_cache_end_of_result(NET *net);
+void query_cache_abort(NET *net);
#endif
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 06a1818b50d..75feca8d759 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -988,23 +988,12 @@ static pthread_handler_decl(handle_delayed_insert,arg)
if (!di->status && !di->stacked_inserts)
{
struct timespec abstime;
-#if defined(HAVE_TIMESPEC_TS_SEC)
- abstime.ts_sec=time((time_t*) 0)+(time_t) delayed_insert_timeout;
- abstime.ts_nsec=0;
-#elif defined(__WIN__)
- abstime.tv_sec=time((time_t*) 0)+(time_t) delayed_insert_timeout;
- abstime.tv_nsec=0;
-#else
- struct timeval tv;
- gettimeofday(&tv,0);
- abstime.tv_sec=tv.tv_sec+(time_t) delayed_insert_timeout;
- abstime.tv_nsec=tv.tv_usec*1000;
-#endif
+ set_timespec(abstime, delayed_insert_timeout);
/* Information for pthread_kill */
di->thd.mysys_var->current_mutex= &di->mutex;
di->thd.mysys_var->current_cond= &di->cond;
- di->thd.proc_info=0;
+ di->thd.proc_info="Waiting for INSERT";
DBUG_PRINT("info",("Waiting for someone to insert rows"));
while (!thd->killed)
@@ -1039,6 +1028,7 @@ static pthread_handler_decl(handle_delayed_insert,arg)
pthread_mutex_unlock(&di->thd.mysys_var->mutex);
pthread_mutex_lock(&di->mutex);
}
+ di->thd.proc_info=0;
if (di->tables_in_use && ! thd->lock)
{
diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc
index 53953c96d0b..13cac83fc3f 100644
--- a/sql/sql_manager.cc
+++ b/sql/sql_manager.cc
@@ -55,13 +55,7 @@ pthread_handler_decl(handle_manager,arg __attribute__((unused)))
{
if (reset_flush_time)
{
-#ifdef HAVE_TIMESPEC_TS_SEC
- abstime.ts_sec = time(NULL)+flush_time; // Bsd 2.1
- abstime.ts_nsec = 0;
-#else
- abstime.tv_sec = time(NULL)+flush_time; // Linux or Solairs
- abstime.tv_nsec = 0;
-#endif
+ set_timespec(abstime, flush_time);
reset_flush_time = FALSE;
}
while (!manager_status && !error && !abort_loop)
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 3662aa301e2..f61624dbe52 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -89,8 +89,8 @@ static void test_signal(int sig_ptr)
MessageBox(NULL,"Test signal","DBUG",MB_OK);
#endif
#if defined(OS2)
- fprintf( stderr, "Test signal %d\n", sig_ptr);
- fflush( stderr);
+ fprintf(stderr, "Test signal %d\n", sig_ptr);
+ fflush(stderr);
#endif
}
static void init_signals(void)
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index bfee5f9235b..c65654faefb 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -607,25 +607,14 @@ int stop_slave(THD* thd, bool net_report )
// do not abort the slave in the middle of a query, so we do not set
// thd->killed for the slave thread
thd->proc_info = "waiting for slave to die";
- while(slave_running)
+ while (slave_running)
{
- /* there is a small chance that slave thread might miss the first
- alarm. To protect againts it, resend the signal until it reacts
+ /*
+ There is a small chance that slave thread might miss the first
+ alarm. To protect againts it, resend the signal until it reacts
*/
-
struct timespec abstime;
-#ifdef HAVE_TIMESPEC_TS_SEC
- abstime.ts_sec=time(NULL)+2;
- abstime.ts_nsec=0;
-#elif defined(__WIN__)
- abstime.tv_sec=time((time_t*) 0)+2;
- abstime.tv_nsec=0;
-#else
- struct timeval tv;
- gettimeofday(&tv,0);
- abstime.tv_sec=tv.tv_sec+2;
- abstime.tv_nsec=tv.tv_usec*1000;
-#endif
+ set_timespec(abstime, 2);
pthread_cond_timedwait(&COND_slave_stopped, &LOCK_slave, &abstime);
if (slave_running)
KICK_SLAVE;
@@ -659,8 +648,8 @@ void reset_slave()
pthread_mutex_lock(&LOCK_slave);
if ((slave_was_running = slave_running))
{
- pthread_mutex_unlock(&LOCK_slave);
- stop_slave(0,0);
+ pthread_mutex_unlock(&LOCK_slave);
+ stop_slave(0,0);
}
else
pthread_mutex_unlock(&LOCK_slave);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 821ec3fe972..8ffeb70e912 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -652,6 +652,8 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
item->maybe_null=1;
field_list.push_back(item=new Item_empty_string("Packed",10));
item->maybe_null=1;
+ field_list.push_back(new Item_empty_string("Null",3));
+ field_list.push_back(new Item_empty_string("Index_type",16));
field_list.push_back(new Item_empty_string("Comment",255));
item->maybe_null=1;
@@ -691,6 +693,8 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
}
else
net_store_null(packet);
+
+ /* Check if we have a key part that only uses part of the field */
if (!key_part->field ||
key_part->length !=
table->field[key_part->fieldnr-1]->key_length())
@@ -701,8 +705,14 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
else
net_store_null(packet);
net_store_null(packet); // No pack_information yet
- net_store_data(packet,convert,
- key_info->flags & HA_FULLTEXT ? "FULLTEXT":"");
+
+ /* Null flag */
+ uint flags= key_part->field ? key_part->field->flags : 0;
+ char *pos=(byte*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
+ net_store_data(packet,convert,(const char*) pos);
+ net_store_data(packet,convert,table->file->index_type(i));
+ /* Comment */
+ net_store_data(packet,convert,"");
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
DBUG_RETURN(1); /* purecov: inspected */
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 6ded046ccbf..ac0748d1497 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -26,6 +26,7 @@
#endif
extern HASH open_cache;
+static const char *primary_key_name="PRIMARY";
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
@@ -196,6 +197,48 @@ int quick_rm_table(enum db_type base,const char *db,
return ha_delete_table(base,path) || error;
}
+/*
+ Sort keys in the following order:
+ - PRIMARY KEY
+ - UNIQUE keyws where all column are NOT NULL
+ - Other UNIQUE keys
+ - Normal keys
+ - Fulltext keys
+
+ This will make checking for duplicated keys faster and ensure that
+ PRIMARY keys are prioritized.
+*/
+
+
+static int sort_keys(KEY *a, KEY *b)
+{
+ if (a == b) // Safety
+ return 0;
+ if (a->flags & HA_NOSAME)
+ {
+ if (!(b->flags & HA_NOSAME))
+ return -1;
+ if ((a->flags ^ b->flags) & HA_NULL_PART_KEY)
+ {
+ /* Sort NOT NULL keys before other keys */
+ return (a->flags & HA_NULL_PART_KEY) ? 1 : -1;
+ }
+ if (a->name == primary_key_name)
+ return -1;
+ if (b->name == primary_key_name)
+ return 1;
+ }
+ else if (b->flags & HA_NOSAME)
+ return 1; // Prefer b
+
+ if ((a->flags ^ b->flags) & HA_FULLTEXT)
+ {
+ return (a->flags & HA_FULLTEXT) ? 1 : -1;
+ }
+ return a < b ? -1 : 1; // Prefer original key order
+}
+
+
/*****************************************************************************
* Create a table.
* If one creates a temporary table, this is automaticly opened
@@ -351,8 +394,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
List_iterator<Key> key_iterator(keys);
uint key_parts=0,key_count=keys.elements;
List<Key> keys_in_order; // Add new keys here
- Key *primary_key=0;
- bool unique_key=0;
+ bool primary_key=0,unique_key=0;
Key *key;
uint tmp;
tmp=min(file->max_keys(), MAX_KEY);
@@ -362,12 +404,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_RETURN(-1);
}
- /*
- Check keys;
- Put PRIMARY KEY first, then UNIQUE keys and other keys last
- This will make checking for duplicated keys faster and ensure that
- primary keys are prioritized.
- */
+ /* Calculate number of key segements */
while ((key=key_iterator++))
{
@@ -383,33 +420,6 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_RETURN(-1);
}
key_parts+=key->columns.elements;
- if (key->type == Key::PRIMARY)
- {
- if (primary_key)
- {
- my_error(ER_MULTIPLE_PRI_KEY,MYF(0));
- DBUG_RETURN(-1);
- }
- primary_key=key;
- }
- else if (key->type == Key::UNIQUE)
- {
- unique_key=1;
- if (keys_in_order.push_front(key))
- DBUG_RETURN(-1);
- }
- else if (keys_in_order.push_back(key))
- DBUG_RETURN(-1);
- }
- if (primary_key)
- {
- if (keys_in_order.push_front(primary_key))
- DBUG_RETURN(-1);
- }
- else if (!unique_key && (file->option_flag() & HA_REQUIRE_PRIMARY_KEY))
- {
- my_error(ER_REQUIRES_PRIMARY_KEY,MYF(0));
- DBUG_RETURN(-1);
}
key_info_buffer=key_info=(KEY*) sql_calloc(sizeof(KEY)*key_count);
@@ -417,8 +427,8 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
if (!key_info_buffer || ! key_part_info)
DBUG_RETURN(-1); // Out of memory
- List_iterator<Key> key_iterator_in_order(keys_in_order);
- for (; (key=key_iterator_in_order++) ; key_info++)
+ key_iterator.rewind();
+ for (; (key=key_iterator++) ; key_info++)
{
uint key_length=0;
key_part_spec *column;
@@ -486,6 +496,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
MYF(0),column->field_name);
DBUG_RETURN(-1);
}
+ key_info->flags|= HA_NULL_PART_KEY;
}
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
{
@@ -545,7 +556,15 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
if (column_nr == 0)
{
if (key->type == Key::PRIMARY)
- key_name="PRIMARY";
+ {
+ if (primary_key)
+ {
+ my_error(ER_MULTIPLE_PRI_KEY,MYF(0));
+ DBUG_RETURN(-1);
+ }
+ key_name=primary_key_name;
+ primary_key=1;
+ }
else if (!(key_name = key->name()))
key_name=make_unique_key_name(sql_field->field_name,
key_info_buffer,key_info);
@@ -557,6 +576,8 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
key_info->name=(char*) key_name;
}
}
+ if (!(key_info->flags & HA_NULL_PART_KEY))
+ unique_key=1;
key_info->key_length=(uint16) key_length;
uint max_key_length= max(file->max_key_length(), MAX_KEY_LENGTH);
if (key_length > max_key_length && key->type != Key::FULLTEXT)
@@ -565,11 +586,19 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_RETURN(-1);
}
}
+ if (!unique_key && !primary_key &&
+ (file->option_flag() & HA_REQUIRE_PRIMARY_KEY))
+ {
+ my_error(ER_REQUIRES_PRIMARY_KEY,MYF(0));
+ DBUG_RETURN(-1);
+ }
if (auto_increment > 0)
{
my_error(ER_WRONG_AUTO_KEY,MYF(0));
DBUG_RETURN(-1);
}
+ /* Sort keys in optimized order */
+ qsort((gptr) key_info_buffer, key_count, sizeof(KEY), (qsort_cmp) sort_keys);
/* Check if table exists */
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 5282fb157e6..382e007447d 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -351,6 +351,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token PRECISION
%token QUICK
%token REAL
+%token SIGNED
%token SMALLINT
%token STRING_SYM
%token TEXT_SYM
@@ -1009,7 +1010,8 @@ field_opt_list:
| field_option {}
field_option:
- UNSIGNED { Lex->type|= UNSIGNED_FLAG;}
+ SIGNED {}
+ | UNSIGNED { Lex->type|= UNSIGNED_FLAG;}
| ZEROFILL { Lex->type|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
opt_len:
@@ -1595,7 +1597,9 @@ simple_expr:
| MATCH ident_list_arg AGAINST '(' expr IN_SYM BOOLEAN_SYM MODE_SYM ')'
{ Select->ftfunc_list.push_back((Item_func_match *)
($$=new Item_func_match_bool(*$2,$5))); }
- | BINARY expr %prec NEG { $$= new Item_func_binary($2); }
+ | BINARY expr %prec NEG { $$= new Item_func_binary($2); }
+ | SIGNED expr %prec NEG { $$= new Item_func_signed($2); }
+ | UNSIGNED expr %prec NEG { $$= new Item_func_unsigned($2); }
| CASE_SYM opt_expr WHEN_SYM when_list opt_else END
{ $$= new Item_func_case(* $4, $2, $5 ) }
| FUNC_ARG0 '(' ')'