summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <malff/marcsql@weblab.(none)>2007-02-16 09:02:02 -0700
committerunknown <malff/marcsql@weblab.(none)>2007-02-16 09:02:02 -0700
commita858d8e84afe238789092a0d4d585ec5243f9fed (patch)
tree3a04d97790571390b5233a060198c29b27273c1a /sql
parent9d66be72b0ee079cecc39e09d4f4c0f7e1849dbc (diff)
parenta475ed7c6b6607272afb87517ae6ab1f3a397f41 (diff)
downloadmariadb-git-a858d8e84afe238789092a0d4d585ec5243f9fed.tar.gz
Merge weblab.(none):/home/marcsql/TREE/mysql-5.0-base
into weblab.(none):/home/marcsql/TREE/mysql-5.0-rt-merge sql/item_cmpfunc.cc: Auto merged sql/item_cmpfunc.h: Auto merged sql/item_subselect.cc: Auto merged sql/item_subselect.h: Auto merged sql/sql_lex.cc: Auto merged sql/sql_lex.h: Auto merged sql/sql_yacc.yy: Auto merged
Diffstat (limited to 'sql')
-rw-r--r--sql/item_cmpfunc.cc74
-rw-r--r--sql/item_cmpfunc.h86
-rw-r--r--sql/item_subselect.cc30
-rw-r--r--sql/item_subselect.h20
-rw-r--r--sql/sp_head.cc2
-rw-r--r--sql/sql_cache.cc18
-rw-r--r--sql/sql_lex.cc11
-rw-r--r--sql/sql_lex.h6
-rw-r--r--sql/sql_yacc.yy143
9 files changed, 346 insertions, 44 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 9ca010e7cf5..faf6ebc1e23 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -792,6 +792,59 @@ int Arg_comparator::compare_e_row()
}
+void Item_func_truth::fix_length_and_dec()
+{
+ maybe_null= 0;
+ null_value= 0;
+ decimals= 0;
+ max_length= 1;
+}
+
+
+void Item_func_truth::print(String *str)
+{
+ str->append('(');
+ args[0]->print(str);
+ str->append(STRING_WITH_LEN(" is "));
+ if (! affirmative)
+ str->append(STRING_WITH_LEN("not "));
+ if (value)
+ str->append(STRING_WITH_LEN("true"));
+ else
+ str->append(STRING_WITH_LEN("false"));
+ str->append(')');
+}
+
+
+bool Item_func_truth::val_bool()
+{
+ bool val= args[0]->val_bool();
+ if (args[0]->null_value)
+ {
+ /*
+ NULL val IS {TRUE, FALSE} --> FALSE
+ NULL val IS NOT {TRUE, FALSE} --> TRUE
+ */
+ return (! affirmative);
+ }
+
+ if (affirmative)
+ {
+ /* {TRUE, FALSE} val IS {TRUE, FALSE} value */
+ return (val == value);
+ }
+
+ /* {TRUE, FALSE} val IS NOT {TRUE, FALSE} value */
+ return (val != value);
+}
+
+
+longlong Item_func_truth::val_int()
+{
+ return (val_bool() ? 1 : 0);
+}
+
+
bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
{
if (!args[0]->fixed && args[0]->fix_fields(thd, args) ||
@@ -1527,6 +1580,7 @@ Item_func_if::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null || args[2]->maybe_null;
decimals= max(args[1]->decimals, args[2]->decimals);
+ unsigned_flag=args[1]->unsigned_flag && args[2]->unsigned_flag;
enum Item_result arg1_type=args[1]->result_type();
enum Item_result arg2_type=args[2]->result_type();
@@ -1556,12 +1610,20 @@ Item_func_if::fix_length_and_dec()
collation.set(&my_charset_bin); // Number
}
}
- max_length=
- (cached_result_type == DECIMAL_RESULT || cached_result_type == INT_RESULT) ?
- (max(args[1]->max_length - args[1]->decimals,
- args[2]->max_length - args[2]->decimals) + decimals +
- (unsigned_flag ? 0 : 1) ) :
- max(args[1]->max_length, args[2]->max_length);
+
+ if ((cached_result_type == DECIMAL_RESULT )
+ || (cached_result_type == INT_RESULT))
+ {
+ int len1= args[1]->max_length - args[1]->decimals
+ - (args[1]->unsigned_flag ? 0 : 1);
+
+ int len2= args[2]->max_length - args[2]->decimals
+ - (args[2]->unsigned_flag ? 0 : 1);
+
+ max_length=max(len1, len2) + decimals + (unsigned_flag ? 0 : 1);
+ }
+ else
+ max_length= max(args[1]->max_length, args[2]->max_length);
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index d7db928e281..c81a4fc5ca1 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -101,6 +101,92 @@ public:
uint decimal_precision() const { return 1; }
};
+
+/**
+ Abstract Item class, to represent <code>X IS [NOT] (TRUE | FALSE)</code>
+ boolean predicates.
+*/
+
+class Item_func_truth : public Item_bool_func
+{
+public:
+ virtual bool val_bool();
+ virtual longlong val_int();
+ virtual void fix_length_and_dec();
+ virtual void print(String *str);
+
+protected:
+ Item_func_truth(Item *a, bool a_value, bool a_affirmative)
+ : Item_bool_func(a), value(a_value), affirmative(a_affirmative)
+ {}
+
+ ~Item_func_truth()
+ {}
+private:
+ /**
+ True for <code>X IS [NOT] TRUE</code>,
+ false for <code>X IS [NOT] FALSE</code> predicates.
+ */
+ const bool value;
+ /**
+ True for <code>X IS Y</code>, false for <code>X IS NOT Y</code> predicates.
+ */
+ const bool affirmative;
+};
+
+
+/**
+ This Item represents a <code>X IS TRUE</code> boolean predicate.
+*/
+
+class Item_func_istrue : public Item_func_truth
+{
+public:
+ Item_func_istrue(Item *a) : Item_func_truth(a, true, true) {}
+ ~Item_func_istrue() {}
+ virtual const char* func_name() const { return "istrue"; }
+};
+
+
+/**
+ This Item represents a <code>X IS NOT TRUE</code> boolean predicate.
+*/
+
+class Item_func_isnottrue : public Item_func_truth
+{
+public:
+ Item_func_isnottrue(Item *a) : Item_func_truth(a, true, false) {}
+ ~Item_func_isnottrue() {}
+ virtual const char* func_name() const { return "isnottrue"; }
+};
+
+
+/**
+ This Item represents a <code>X IS FALSE</code> boolean predicate.
+*/
+
+class Item_func_isfalse : public Item_func_truth
+{
+public:
+ Item_func_isfalse(Item *a) : Item_func_truth(a, false, true) {}
+ ~Item_func_isfalse() {}
+ virtual const char* func_name() const { return "isfalse"; }
+};
+
+
+/**
+ This Item represents a <code>X IS NOT FALSE</code> boolean predicate.
+*/
+
+class Item_func_isnotfalse : public Item_func_truth
+{
+public:
+ Item_func_isnotfalse(Item *a) : Item_func_truth(a, false, false) {}
+ ~Item_func_isnotfalse() {}
+ virtual const char* func_name() const { return "isnotfalse"; }
+};
+
+
class Item_cache;
#define UNKNOWN ((my_bool)-1)
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index d61bb25e9b7..a83b68f9945 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -51,6 +51,10 @@ Item_subselect::Item_subselect():
void Item_subselect::init(st_select_lex *select_lex,
select_subselect *result)
{
+ /*
+ Please see Item_singlerow_subselect::invalidate_and_restore_select_lex(),
+ which depends on alterations to the parse tree implemented here.
+ */
DBUG_ENTER("Item_subselect::init");
DBUG_PRINT("enter", ("select_lex: 0x%lx", (long) select_lex));
@@ -91,6 +95,12 @@ void Item_subselect::init(st_select_lex *select_lex,
DBUG_VOID_RETURN;
}
+st_select_lex *
+Item_subselect::get_select_lex()
+{
+ return unit->first_select();
+}
+
void Item_subselect::cleanup()
{
DBUG_ENTER("Item_subselect::cleanup");
@@ -268,6 +278,26 @@ Item_singlerow_subselect::Item_singlerow_subselect(st_select_lex *select_lex)
DBUG_VOID_RETURN;
}
+st_select_lex *
+Item_singlerow_subselect::invalidate_and_restore_select_lex()
+{
+ DBUG_ENTER("Item_singlerow_subselect::invalidate_and_restore_select_lex");
+ st_select_lex *result= get_select_lex();
+
+ DBUG_ASSERT(result);
+
+ /*
+ This code restore the parse tree in it's state before the execution of
+ Item_singlerow_subselect::Item_singlerow_subselect(),
+ and in particular decouples this object from the SELECT_LEX,
+ so that the SELECT_LEX can be used with a different flavor
+ or Item_subselect instead, as part of query rewriting.
+ */
+ unit->item= NULL;
+
+ DBUG_RETURN(result);
+}
+
Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param,
Item_subselect *parent,
st_select_lex *select_lex,
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 25a0326f8b6..4853d635657 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -126,6 +126,12 @@ public:
virtual void reset_value_registration() {}
enum_parsing_place place() { return parsing_place; }
+ /**
+ Get the SELECT_LEX structure associated with this Item.
+ @return the SELECT_LEX structure associated with this Item
+ */
+ st_select_lex* get_select_lex();
+
friend class select_subselect;
friend class Item_in_optimizer;
friend bool Item_field::fix_fields(THD *, Item **);
@@ -169,6 +175,20 @@ public:
bool null_inside();
void bring_value();
+ /**
+ This method is used to implement a special case of semantic tree
+ rewriting, mandated by a SQL:2003 exception in the specification.
+ The only caller of this method is handle_sql2003_note184_exception(),
+ see the code there for more details.
+ Note that this method breaks the object internal integrity, by
+ removing it's association with the corresponding SELECT_LEX,
+ making this object orphan from the parse tree.
+ No other method, beside the destructor, should be called on this
+ object, as it is now invalid.
+ @return the SELECT_LEX structure that was given in the constructor.
+ */
+ st_select_lex* invalidate_and_restore_select_lex();
+
friend class select_singlerow_subselect;
};
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index de0edabda3e..2e8ecd20000 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -36,6 +36,7 @@ Item_result
sp_map_result_type(enum enum_field_types type)
{
switch (type) {
+ case MYSQL_TYPE_BIT:
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
@@ -58,6 +59,7 @@ Item::Type
sp_map_item_type(enum enum_field_types type)
{
switch (type) {
+ case MYSQL_TYPE_BIT:
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 8e6846fdcd2..d06ac7824fd 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1765,8 +1765,18 @@ void Query_cache::free_cache()
{
DBUG_ENTER("Query_cache::free_cache");
if (query_cache_size > 0)
- {
flush_cache();
+ /*
+ There may be two free_cache() calls in progress, because we
+ release 'structure_guard_mutex' in flush_cache(). When the second
+ flush_cache() wakes up from the wait on 'COND_flush_finished', the
+ first call to free_cache() has done its job. So we have to test
+ 'query_cache_size > 0' the second time to see if the cache wasn't
+ reset by other thread, or if it was reset and was re-enabled then.
+ If the cache was reset, then we have nothing to do here.
+ */
+ if (query_cache_size > 0)
+ {
#ifndef DBUG_OFF
if (bins[0].free_blocks == 0)
{
@@ -1808,6 +1818,12 @@ void Query_cache::free_cache()
flush_in_progress flag and releases the lock, so other threads may
proceed skipping the cache as if it is disabled. Concurrent
flushes are performed in turn.
+
+ After flush_cache() call, the cache is flushed, all the freed
+ memory is accumulated in bin[0], and the 'structure_guard_mutex'
+ is locked. However, since we could release the mutex during
+ execution, the rest of the cache state could have been changed,
+ and should not be relied on.
*/
void Query_cache::flush_cache()
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index ce76c35b33c..d837f494c90 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -99,6 +99,16 @@ void lex_free(void)
}
+void
+st_parsing_options::reset()
+{
+ allows_variable= TRUE;
+ allows_select_into= TRUE;
+ allows_select_procedure= TRUE;
+ allows_derived= TRUE;
+}
+
+
/*
This is called before every query that is to be parsed.
Because of this, it's critical to not do too much things here.
@@ -149,6 +159,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->safe_to_cache_query= 1;
lex->time_zone_tables_used= 0;
lex->leaf_tables_insert= 0;
+ lex->parsing_options.reset();
lex->empty_field_list_on_rset= 0;
lex->select_lex.select_number= 1;
lex->next_state=MY_LEX_START;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index ae2b0d30a9c..5c16c4d06b2 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -884,10 +884,8 @@ struct st_parsing_options
bool allows_select_procedure;
bool allows_derived;
- st_parsing_options()
- : allows_variable(TRUE), allows_select_into(TRUE),
- allows_select_procedure(TRUE), allows_derived(TRUE)
- {}
+ st_parsing_options() { reset(); }
+ void reset();
};
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index b4147d2905c..b430831b98e 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -58,15 +58,6 @@ const LEX_STRING null_lex_str={0,0};
YYABORT; \
}
-/* Helper for parsing "IS [NOT] truth_value" */
-inline Item *is_truth_value(Item *A, bool v1, bool v2)
-{
- return new Item_func_if(create_func_ifnull(A,
- new Item_int((char *) (v2 ? "TRUE" : "FALSE"), v2, 1)),
- new Item_int((char *) (v1 ? "TRUE" : "FALSE"), v1, 1),
- new Item_int((char *) (v1 ? "FALSE" : "TRUE"),!v1, 1));
-}
-
#ifndef DBUG_OFF
#define YYDEBUG 1
#else
@@ -276,6 +267,81 @@ void case_stmt_action_end_case(LEX *lex, bool simple)
lex->sphead->do_cont_backpatch();
}
+/**
+ Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>.
+ See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383.
+ This function returns the proper item for the SQL expression
+ <code>left [NOT] IN ( expr )</code>
+ @param thd the current thread
+ @param left the in predicand
+ @param equal true for IN predicates, false for NOT IN predicates
+ @param expr first and only expression of the in value list
+ @return an expression representing the IN predicate.
+*/
+Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
+ Item *expr)
+{
+ /*
+ Relevant references for this issue:
+ - SQL:2003, Part 2, section 8.4 <in predicate>, page 383,
+ - SQL:2003, Part 2, section 7.2 <row value expression>, page 296,
+ - SQL:2003, Part 2, section 6.3 <value expression primary>, page 174,
+ - SQL:2003, Part 2, section 7.15 <subquery>, page 370,
+ - SQL:2003 Feature F561, "Full value expressions".
+
+ The exception in SQL:2003 Note 184 means:
+ Item_singlerow_subselect, which corresponds to a <scalar subquery>,
+ should be re-interpreted as an Item_in_subselect, which corresponds
+ to a <table subquery> when used inside an <in predicate>.
+
+ Our reading of Note 184 is reccursive, so that all:
+ - IN (( <subquery> ))
+ - IN ((( <subquery> )))
+ - IN '('^N <subquery> ')'^N
+ - etc
+ should be interpreted as a <table subquery>, no matter how deep in the
+ expression the <subquery> is.
+ */
+
+ Item *result;
+
+ DBUG_ENTER("handle_sql2003_note184_exception");
+
+ if (expr->type() == Item::SUBSELECT_ITEM)
+ {
+ Item_subselect *expr2 = (Item_subselect*) expr;
+
+ if (expr2->substype() == Item_subselect::SINGLEROW_SUBS)
+ {
+ Item_singlerow_subselect *expr3 = (Item_singlerow_subselect*) expr2;
+ st_select_lex *subselect;
+
+ /*
+ Implement the mandated change, by altering the semantic tree:
+ left IN Item_singlerow_subselect(subselect)
+ is modified to
+ left IN (subselect)
+ which is represented as
+ Item_in_subselect(left, subselect)
+ */
+ subselect= expr3->invalidate_and_restore_select_lex();
+ result= new (thd->mem_root) Item_in_subselect(left, subselect);
+
+ if (! equal)
+ result = negate_expression(thd, result);
+
+ DBUG_RETURN(result);
+ }
+ }
+
+ if (equal)
+ result= new (thd->mem_root) Item_func_eq(left, expr);
+ else
+ result= new (thd->mem_root) Item_func_ne(left, expr);
+
+ DBUG_RETURN(result);
+}
+
%}
%union {
int num;
@@ -4382,13 +4448,18 @@ bool_factor:
| bool_test ;
bool_test:
- bool_pri IS TRUE_SYM { $$= is_truth_value($1,1,0); }
- | bool_pri IS not TRUE_SYM { $$= is_truth_value($1,0,0); }
- | bool_pri IS FALSE_SYM { $$= is_truth_value($1,0,1); }
- | bool_pri IS not FALSE_SYM { $$= is_truth_value($1,1,1); }
- | bool_pri IS UNKNOWN_SYM { $$= new Item_func_isnull($1); }
- | bool_pri IS not UNKNOWN_SYM { $$= new Item_func_isnotnull($1); }
- | bool_pri ;
+ bool_pri IS TRUE_SYM
+ { $$= new (YYTHD->mem_root) Item_func_istrue($1); }
+ | bool_pri IS not TRUE_SYM
+ { $$= new (YYTHD->mem_root) Item_func_isnottrue($1); }
+ | bool_pri IS FALSE_SYM
+ { $$= new (YYTHD->mem_root) Item_func_isfalse($1); }
+ | bool_pri IS not FALSE_SYM
+ { $$= new (YYTHD->mem_root) Item_func_isnotfalse($1); }
+ | bool_pri IS UNKNOWN_SYM { $$= new Item_func_isnull($1); }
+ | bool_pri IS not UNKNOWN_SYM { $$= new Item_func_isnotnull($1); }
+ | bool_pri
+ ;
bool_pri:
bool_pri IS NULL_SYM { $$= new Item_func_isnull($1); }
@@ -4401,31 +4472,37 @@ bool_pri:
| predicate ;
predicate:
- bit_expr IN_SYM '(' subselect ')'
- { $$= new Item_in_subselect($1, $4); }
- | bit_expr not IN_SYM '(' subselect ')'
- { $$= negate_expression(YYTHD, new Item_in_subselect($1, $5)); }
+ bit_expr IN_SYM '(' subselect ')'
+ {
+ $$= new (YYTHD->mem_root) Item_in_subselect($1, $4);
+ }
+ | bit_expr not IN_SYM '(' subselect ')'
+ {
+ THD *thd= YYTHD;
+ Item *item= new (thd->mem_root) Item_in_subselect($1, $5);
+ $$= negate_expression(thd, item);
+ }
| bit_expr IN_SYM '(' expr ')'
{
- $$= new Item_func_eq($1, $4);
+ $$= handle_sql2003_note184_exception(YYTHD, $1, true, $4);
}
- | bit_expr IN_SYM '(' expr ',' expr_list ')'
- {
- $6->push_front($4);
- $6->push_front($1);
- $$= new Item_func_in(*$6);
+ | bit_expr IN_SYM '(' expr ',' expr_list ')'
+ {
+ $6->push_front($4);
+ $6->push_front($1);
+ $$= new (YYTHD->mem_root) Item_func_in(*$6);
}
| bit_expr not IN_SYM '(' expr ')'
{
- $$= new Item_func_ne($1, $5);
+ $$= handle_sql2003_note184_exception(YYTHD, $1, false, $5);
}
- | bit_expr not IN_SYM '(' expr ',' expr_list ')'
+ | bit_expr not IN_SYM '(' expr ',' expr_list ')'
{
- $7->push_front($5);
- $7->push_front($1);
- Item_func_in *item = new Item_func_in(*$7);
- item->negate();
- $$= item;
+ $7->push_front($5);
+ $7->push_front($1);
+ Item_func_in *item = new (YYTHD->mem_root) Item_func_in(*$7);
+ item->negate();
+ $$= item;
}
| bit_expr BETWEEN_SYM bit_expr AND_SYM predicate
{ $$= new Item_func_between($1,$3,$5); }