diff options
Diffstat (limited to 'sql')
65 files changed, 2314 insertions, 1569 deletions
diff --git a/sql/field.cc b/sql/field.cc index fb244de4275..925fca8ac43 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1444,6 +1444,7 @@ my_decimal *Field_str::val_decimal(my_decimal *decimal_value) uint Field::fill_cache_field(CACHE_FIELD *copy) { + uint store_length; copy->str=ptr; copy->length=pack_length(); copy->blob_field=0; @@ -1457,10 +1458,16 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) else if (!zero_pack() && (type() == MYSQL_TYPE_STRING && copy->length >= 4 && copy->length < 256)) + { copy->strip=1; /* Remove end space */ + store_length= 2; + } else + { copy->strip=0; - return copy->length+(int) copy->strip; + store_length= 0; + } + return copy->length+ store_length; } @@ -2479,7 +2486,7 @@ int Field_new_decimal::store(longlong nr) int err; if ((err= int2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, - nr, false, &decimal_value))) + nr, FALSE, &decimal_value))) { if (check_overflow(err)) set_value_on_overflow(&decimal_value, decimal_value.sign()); @@ -6822,7 +6829,12 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) ¬_used))) { uint conv_errors; - tmpstr.copy(from, length, cs, field_charset, &conv_errors); + if (tmpstr.copy(from, length, cs, field_charset, &conv_errors)) + { + /* Fatal OOM error */ + bzero(ptr,Field_blob::pack_length()); + return -1; + } from= tmpstr.ptr(); length= tmpstr.length(); if (conv_errors) diff --git a/sql/field.h b/sql/field.h index ebf48568c04..523cf444c30 100644 --- a/sql/field.h +++ b/sql/field.h @@ -86,6 +86,7 @@ public: utype unireg_check; uint32 field_length; // Length of field + uint field_index; // field number in fields array uint16 flags; uchar null_bit; // Bit used to test null bit @@ -1288,7 +1289,7 @@ public: enum_field_types type() const { return FIELD_TYPE_BIT; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; } uint32 key_length() const { return (uint32) field_length + (bit_len > 0); } - uint32 max_length() { return (uint32) field_length + (bit_len > 0); } + uint32 max_length() { return (uint32) field_length * 8 + bit_len; } uint size_of() const { return sizeof(*this); } Item_result result_type () const { return INT_RESULT; } void reset(void) { bzero(ptr, field_length); } @@ -1320,6 +1321,11 @@ public: Field *new_key_field(MEM_ROOT *root, struct st_table *new_table, char *new_ptr, uchar *new_null_ptr, uint new_null_bit); + void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg) + { + bit_ptr= bit_ptr_arg; + bit_ofs= bit_ofs_arg; + } }; @@ -1331,6 +1337,7 @@ public: enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg); enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + uint32 max_length() { return (uint32) create_length; } uint size_of() const { return sizeof(*this); } int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr) { return Field_bit::store(nr); } diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 77db17608bc..6754a1a8707 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -1399,27 +1399,25 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) int ha_federated::delete_row(const byte *buf) { - uint x= 0; char delete_buffer[IO_SIZE]; char data_buffer[IO_SIZE]; - String delete_string(delete_buffer, sizeof(delete_buffer), &my_charset_bin); - delete_string.length(0); String data_string(data_buffer, sizeof(data_buffer), &my_charset_bin); - data_string.length(0); - DBUG_ENTER("ha_federated::delete_row"); + delete_string.length(0); delete_string.append("DELETE FROM `"); delete_string.append(share->table_base_name); delete_string.append("`"); delete_string.append(" WHERE "); - for (Field **field= table->field; *field; field++, x++) + for (Field **field= table->field; *field; field++) { - delete_string.append((*field)->field_name); + Field *cur_field= *field; + data_string.length(0); + delete_string.append(cur_field->field_name); - if ((*field)->is_null()) + if (cur_field->is_null_in_record((const uchar*) buf)) { delete_string.append(" IS "); data_string.append("NULL"); @@ -1427,17 +1425,15 @@ int ha_federated::delete_row(const byte *buf) else { delete_string.append("="); - (*field)->val_str(&data_string); - (*field)->quote_data(&data_string); + cur_field->val_str(&data_string, (char*) buf+ cur_field->offset()); + cur_field->quote_data(&data_string); } delete_string.append(data_string); - data_string.length(0); - - if (x + 1 < table->s->fields) - delete_string.append(" AND "); + delete_string.append(" AND "); } + delete_string.length(delete_string.length()-5); // Remove AND delete_string.append(" LIMIT 1"); DBUG_PRINT("info", ("Delete sql: %s", delete_string.c_ptr_quick())); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 162e3184713..8218e4fecc0 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1496,8 +1496,8 @@ innobase_start_trx_and_assign_read_view( /********************************************************************* Commits a transaction in an InnoDB database or marks an SQL statement ended. */ - -static int +static +int innobase_commit( /*============*/ /* out: 0 */ @@ -3561,7 +3561,9 @@ ha_innobase::delete_row( } /************************************************************************** -Deletes a lock set to a row */ +Removes a new lock set on a row. This can be called after a row has been read +in the processing of an UPDATE or a DELETE query, if the option +innodb_locks_unsafe_for_binlog is set. */ void ha_innobase::unlock_row(void) @@ -3579,8 +3581,10 @@ ha_innobase::unlock_row(void) mem_analyze_corruption((byte *) prebuilt->trx); ut_error; } - - row_unlock_for_mysql(prebuilt); + + if (srv_locks_unsafe_for_binlog) { + row_unlock_for_mysql(prebuilt, FALSE); + } } /********************************************************************** @@ -6014,6 +6018,7 @@ ha_innobase::external_lock( reads. */ prebuilt->select_lock_type = LOCK_S; + prebuilt->stored_select_lock_type = LOCK_S; } /* Starting from 4.1.9, no InnoDB table lock is taken in LOCK @@ -6053,7 +6058,6 @@ ha_innobase::external_lock( trx->n_mysql_tables_in_use--; prebuilt->mysql_has_locked = FALSE; - /* If the MySQL lock count drops to zero we know that the current SQL statement has ended */ @@ -6586,12 +6590,14 @@ the value of the auto-inc counter. */ int ha_innobase::innobase_read_and_init_auto_inc( /*=========================================*/ - /* out: 0 or error code: deadlock or - lock wait timeout */ + /* out: 0 or error code: deadlock or lock wait + timeout */ longlong* ret) /* out: auto-inc value */ { row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; longlong auto_inc; + ulint old_select_lock_type; + ibool trx_was_not_started = FALSE; int error; ut_a(prebuilt); @@ -6599,6 +6605,10 @@ ha_innobase::innobase_read_and_init_auto_inc( (trx_t*) current_thd->ha_data[innobase_hton.slot]); ut_a(prebuilt->table); + if (prebuilt->trx->conc_state == TRX_NOT_STARTED) { + trx_was_not_started = TRUE; + } + /* In case MySQL calls this in the middle of a SELECT query, release possible adaptive hash latch to avoid deadlocks of threads */ @@ -6610,7 +6620,9 @@ ha_innobase::innobase_read_and_init_auto_inc( /* Already initialized */ *ret = auto_inc; - return(0); + error = 0; + + goto func_exit_early; } error = row_lock_table_autoinc_for_mysql(prebuilt); @@ -6618,7 +6630,7 @@ ha_innobase::innobase_read_and_init_auto_inc( if (error != DB_SUCCESS) { error = convert_error_code_to_mysql(error, user_thd); - goto func_exit; + goto func_exit_early; } /* Check again if someone has initialized the counter meanwhile */ @@ -6627,30 +6639,37 @@ ha_innobase::innobase_read_and_init_auto_inc( if (auto_inc != 0) { *ret = auto_inc; - return(0); + error = 0; + + goto func_exit_early; } (void) extra(HA_EXTRA_KEYREAD); index_init(table->s->next_number_index); - /* We use an exclusive lock when we read the max key value from the - auto-increment column index. This is because then build_template will - advise InnoDB to fetch all columns. In SHOW TABLE STATUS the query - id of the auto-increment column is not changed, and previously InnoDB - did not fetch it, causing SHOW TABLE STATUS to show wrong values - for the autoinc column. */ - - prebuilt->select_lock_type = LOCK_X; + /* Starting from 5.0.9, we use a consistent read to read the auto-inc + column maximum value. This eliminates the spurious deadlocks caused + by the row X-lock that we previously used. Note the following flaw + in our algorithm: if some other user meanwhile UPDATEs the auto-inc + column, our consistent read will not return the largest value. We + accept this flaw, since the deadlocks were a bigger trouble. */ - /* Play safe and also give in another way the hint to fetch - all columns in the key: */ + /* Fetch all the columns in the key */ prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS; - prebuilt->trx->mysql_n_tables_locked += 1; - + old_select_lock_type = prebuilt->select_lock_type; + prebuilt->select_lock_type = LOCK_NONE; + + /* Eliminate an InnoDB error print that happens when we try to SELECT + from a table when no table has been locked in ::external_lock(). */ + prebuilt->trx->n_mysql_tables_in_use++; + error = index_last(table->record[1]); + prebuilt->trx->n_mysql_tables_in_use--; + prebuilt->select_lock_type = old_select_lock_type; + if (error) { if (error == HA_ERR_END_OF_FILE) { /* The table was empty, initialize to 1 */ @@ -6658,7 +6677,10 @@ ha_innobase::innobase_read_and_init_auto_inc( error = 0; } else { - /* Deadlock or a lock wait timeout */ + /* This should not happen in a consistent read */ + fprintf(stderr, +"InnoDB: Error: consistent read of auto-inc column returned %lu\n", + (ulong)error); auto_inc = -1; goto func_exit; @@ -6678,7 +6700,18 @@ func_exit: *ret = auto_inc; - return(error); +func_exit_early: + /* Since MySQL does not seem to call autocommit after SHOW TABLE + STATUS (even if we would register the trx here), we must commit our + transaction here if it was started here. This is to eliminate a + dangling transaction. */ + + if (trx_was_not_started) { + + innobase_commit_low(prebuilt->trx); + } + + return(error); } /*********************************************************************** diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 00623251c29..def99b51f95 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -41,7 +41,7 @@ static const int parallelism= 0; // Default value for max number of transactions // createable against NDB from this handler -static const int max_transactions= 256; +static const int max_transactions= 2; static const char *ha_ndb_ext=".ndb"; @@ -341,7 +341,7 @@ void ha_ndbcluster::records_update() { Ndb *ndb= get_ndb(); struct Ndb_statistics stat; - if(ndb_get_table_statistics(ndb, m_tabname, &stat) == 0){ + if (ndb_get_table_statistics(ndb, m_tabname, &stat) == 0){ mean_rec_length= stat.row_size; data_file_length= stat.fragment_memory; info->records= stat.row_count; @@ -448,27 +448,27 @@ void ha_ndbcluster::invalidate_dictionary_cache(bool global) NDBINDEX *unique_index = (NDBINDEX *) m_index[i].unique_index; NDB_INDEX_TYPE idx_type= m_index[i].type; - switch(idx_type) { - case(PRIMARY_KEY_ORDERED_INDEX): - case(ORDERED_INDEX): + switch (idx_type) { + case PRIMARY_KEY_ORDERED_INDEX: + case ORDERED_INDEX: if (global) dict->invalidateIndex(index->getName(), m_tabname); else dict->removeCachedIndex(index->getName(), m_tabname); break; - case(UNIQUE_ORDERED_INDEX): + case UNIQUE_ORDERED_INDEX: if (global) dict->invalidateIndex(index->getName(), m_tabname); else dict->removeCachedIndex(index->getName(), m_tabname); - case(UNIQUE_INDEX): + case UNIQUE_INDEX: 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): + case PRIMARY_KEY_INDEX: + case UNDEFINED_INDEX: break; } } @@ -515,8 +515,10 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans) if (m_rows_to_insert == 1) m_dupkey= table->s->primary_key; else - // We are batching inserts, offending key is not available + { + /* We are batching inserts, offending key is not available */ m_dupkey= (uint) -1; + } } DBUG_RETURN(res); } @@ -1385,7 +1387,7 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf) return res; } - if((res= define_read_attrs(buf, op))) + if ((res= define_read_attrs(buf, op))) DBUG_RETURN(res); if (execute_no_commit_ie(this,trans) != 0) @@ -1515,10 +1517,10 @@ int ha_ndbcluster::unique_index_read(const byte *key, ERR_RETURN(trans->getNdbError()); // Set secondary index key(s) - if((res= set_index_key(op, table->key_info + active_index, key))) + if ((res= set_index_key(op, table->key_info + active_index, key))) DBUG_RETURN(res); - if((res= define_read_attrs(buf, op))) + if ((res= define_read_attrs(buf, op))) DBUG_RETURN(res); if (execute_no_commit_ie(this,trans) != 0) @@ -1578,7 +1580,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) { if (execute_commit(this,trans) != 0) DBUG_RETURN(-1); - if(trans->restart() != 0) + if (trans->restart() != 0) { DBUG_ASSERT(0); DBUG_RETURN(-1); @@ -1616,7 +1618,7 @@ inline int ha_ndbcluster::next_result(byte *buf) if (!m_active_cursor) DBUG_RETURN(HA_ERR_END_OF_FILE); - if((res= fetch_next(m_active_cursor)) == 0) + if ((res= fetch_next(m_active_cursor)) == 0) { DBUG_PRINT("info", ("One more record found")); @@ -1624,7 +1626,7 @@ inline int ha_ndbcluster::next_result(byte *buf) table->status= 0; DBUG_RETURN(0); } - else if(res == 1) + else if (res == 1) { // No more records table->status= STATUS_NOT_FOUND; @@ -1855,7 +1857,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key, DBUG_ASSERT(op->getSorted() == sorted); DBUG_ASSERT(op->getLockMode() == (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type)); - if(op->reset_bounds(m_force_send)) + if (op->reset_bounds(m_force_send)) DBUG_RETURN(ndb_err(m_active_trans)); } @@ -1901,7 +1903,7 @@ int ha_ndbcluster::full_table_scan(byte *buf) m_active_cursor= op; if (generate_scan_filter(m_cond_stack, op)) DBUG_RETURN(ndb_err(trans)); - if((res= define_read_attrs(buf, op))) + if ((res= define_read_attrs(buf, op))) DBUG_RETURN(res); if (execute_no_commit(this,trans) != 0) @@ -2039,7 +2041,7 @@ int ha_ndbcluster::write_row(byte *record) no_uncommitted_rows_execute_failure(); DBUG_RETURN(ndb_err(trans)); } - if(trans->restart() != 0) + if (trans->restart() != 0) { DBUG_ASSERT(0); DBUG_RETURN(-1); @@ -2418,7 +2420,7 @@ void ha_ndbcluster::print_results() field= table->field[f]; if (!(value= m_value[f]).ptr) { - my_snprintf(buf, sizeof(buf), "not read"); + strmov(buf, "not read"); goto print_value; } @@ -2428,7 +2430,7 @@ void ha_ndbcluster::print_results() { if (value.rec->isNULL()) { - my_snprintf(buf, sizeof(buf), "NULL"); + strmov(buf, "NULL"); goto print_value; } type.length(0); @@ -2442,10 +2444,8 @@ void ha_ndbcluster::print_results() NdbBlob *ndb_blob= value.blob; bool isNull= TRUE; ndb_blob->getNull(isNull); - if (isNull) { - my_snprintf(buf, sizeof(buf), "NULL"); - goto print_value; - } + if (isNull) + strmov(buf, "NULL"); } print_value: @@ -2485,7 +2485,7 @@ check_null_in_key(const KEY* key_info, const byte *key, uint key_len) for (; curr_part != end_part && key < end_ptr; curr_part++) { - if(curr_part->null_bit && *key) + if (curr_part->null_bit && *key) return 1; key += curr_part->store_length; @@ -2509,7 +2509,7 @@ int ha_ndbcluster::index_read(byte *buf, case PRIMARY_KEY_INDEX: if (find_flag == HA_READ_KEY_EXACT && key_info->key_length == key_len) { - if(m_active_cursor && (error= close_scan())) + if (m_active_cursor && (error= close_scan())) DBUG_RETURN(error); DBUG_RETURN(pk_read(key, key_len, buf)); } @@ -2523,7 +2523,7 @@ int ha_ndbcluster::index_read(byte *buf, if (find_flag == HA_READ_KEY_EXACT && key_info->key_length == key_len && !check_null_in_key(key_info, key, key_len)) { - if(m_active_cursor && (error= close_scan())) + if (m_active_cursor && (error= close_scan())) DBUG_RETURN(error); DBUG_RETURN(unique_index_read(key, key_len, buf)); } @@ -2635,7 +2635,7 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key, start_key->length == key_info->key_length && start_key->flag == HA_READ_KEY_EXACT) { - if(m_active_cursor && (error= close_scan())) + if (m_active_cursor && (error= close_scan())) DBUG_RETURN(error); error= pk_read(start_key->key, start_key->length, buf); DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error); @@ -2648,7 +2648,7 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key, start_key->flag == HA_READ_KEY_EXACT && !check_null_in_key(key_info, start_key->key, start_key->length)) { - if(m_active_cursor && (error= close_scan())) + if (m_active_cursor && (error= close_scan())) DBUG_RETURN(error); error= unique_index_read(start_key->key, start_key->length, buf); DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error); @@ -2695,7 +2695,7 @@ int ha_ndbcluster::rnd_init(bool scan) { if (!scan) DBUG_RETURN(1); - if(cursor->restart(m_force_send) != 0) + if (cursor->restart(m_force_send) != 0) { DBUG_ASSERT(0); DBUG_RETURN(-1); @@ -3465,7 +3465,7 @@ int ndbcluster_commit(THD *thd, bool all) } ndb->closeTransaction(trans); - if(all) + if (all) thd_ndb->all= NULL; else thd_ndb->stmt= NULL; @@ -3515,7 +3515,7 @@ int ndbcluster_rollback(THD *thd, bool all) } ndb->closeTransaction(trans); - if(all) + if (all) thd_ndb->all= NULL; else thd_ndb->stmt= NULL; @@ -3771,7 +3771,8 @@ static int create_ndb_column(NDBCOL &col, col.setType(NDBCOL::Char); col.setLength(field->pack_length()); break; - case MYSQL_TYPE_BIT: { + case MYSQL_TYPE_BIT: + { int no_of_bits= field->field_length*8 + ((Field_bit *) field)->bit_len; col.setType(NDBCOL::Bit); if (!no_of_bits) @@ -3906,7 +3907,7 @@ int ha_ndbcluster::create(const char *name, if ((my_errno= create_ndb_column(col, field, info))) DBUG_RETURN(my_errno); tab.addColumn(col); - if(col.getPrimaryKey()) + if (col.getPrimaryKey()) pk_length += (field->pack_length() + 3) / 4; } @@ -3939,7 +3940,7 @@ int ha_ndbcluster::create(const char *name, { NdbDictionary::Column * col= tab.getColumn(i); int size= pk_length + (col->getPartSize()+3)/4 + 7; - if(size > NDB_MAX_TUPLE_SIZE_IN_WORDS && + if (size > NDB_MAX_TUPLE_SIZE_IN_WORDS && (pk_length+7) < NDB_MAX_TUPLE_SIZE_IN_WORDS) { size= NDB_MAX_TUPLE_SIZE_IN_WORDS - pk_length - 7; @@ -4167,12 +4168,10 @@ ulonglong ha_ndbcluster::get_auto_increment() m_rows_to_insert+= m_autoincrement_prefetch; } cache_size= - (int) - (m_rows_to_insert - m_rows_inserted < m_autoincrement_prefetch) ? - m_rows_to_insert - m_rows_inserted - : (m_rows_to_insert > m_autoincrement_prefetch) ? - m_rows_to_insert - : m_autoincrement_prefetch; + (int) ((m_rows_to_insert - m_rows_inserted < m_autoincrement_prefetch) ? + m_rows_to_insert - m_rows_inserted : + ((m_rows_to_insert > m_autoincrement_prefetch) ? + m_rows_to_insert : m_autoincrement_prefetch)); auto_value= NDB_FAILED_AUTO_INCREMENT; uint retries= NDB_AUTO_INCREMENT_RETRIES; do { @@ -4710,7 +4709,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path, List_iterator_fast<char> it2(create_list); while ((file_name=it2++)) { - DBUG_PRINT("info", ("Table %s need discovery", name)); + DBUG_PRINT("info", ("Table %s need discovery", file_name)); if (ha_create_table_from_engine(thd, db, file_name) == 0) files->push_back(thd->strdup(file_name)); } @@ -4776,7 +4775,7 @@ ndbcluster_init() g_ndb_cluster_connection->get_connected_port())); g_ndb_cluster_connection->wait_until_ready(10,3); } - else if(res == 1) + else if (res == 1) { if (g_ndb_cluster_connection->start_connect_thread(connect_callback)) { @@ -4824,7 +4823,7 @@ ndbcluster_init() DBUG_RETURN(&ndbcluster_hton); ndbcluster_init_error: - if(g_ndb) + if (g_ndb) delete g_ndb; g_ndb= NULL; if (g_ndb_cluster_connection) @@ -4853,7 +4852,7 @@ bool ndbcluster_end() (void) pthread_cond_signal(&COND_ndb_util_thread); (void) pthread_mutex_unlock(&LOCK_ndb_util_thread); - if(g_ndb) + if (g_ndb) delete g_ndb; g_ndb= NULL; if (g_ndb_cluster_connection) @@ -5103,7 +5102,7 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname, } pthread_mutex_lock(&share->mutex); - if(share->commit_count_lock == lock) + if (share->commit_count_lock == lock) { DBUG_PRINT("info", ("Setting commit_count to %llu", stat.commit_count)); share->commit_count= stat.commit_count; @@ -5594,9 +5593,13 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, for (; multi_range_curr<multi_range_end && curr+reclength <= end_of_buffer; multi_range_curr++) { - switch(index_type){ + switch (index_type){ + case PRIMARY_KEY_ORDERED_INDEX: + if (!(multi_range_curr->start_key.length == key_info->key_length && + multi_range_curr->start_key.flag == HA_READ_KEY_EXACT)) + goto range; + /* fall through */ case PRIMARY_KEY_INDEX: - pk: { multi_range_curr->range_flag |= UNIQUE_RANGE; if ((op= m_active_trans->getNdbOperation(tab)) && @@ -5610,8 +5613,14 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, break; } break; + case UNIQUE_ORDERED_INDEX: + if (!(multi_range_curr->start_key.length == key_info->key_length && + multi_range_curr->start_key.flag == HA_READ_KEY_EXACT && + !check_null_in_key(key_info, multi_range_curr->start_key.key, + multi_range_curr->start_key.length))) + goto range; + /* fall through */ case UNIQUE_INDEX: - sk: { multi_range_curr->range_flag |= UNIQUE_RANGE; if ((op= m_active_trans->getNdbIndexOperation(unique_idx, tab)) && @@ -5624,19 +5633,8 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, ERR_RETURN(op ? op->getNdbError() : m_active_trans->getNdbError()); break; } - case PRIMARY_KEY_ORDERED_INDEX: - if (multi_range_curr->start_key.length == key_info->key_length && - multi_range_curr->start_key.flag == HA_READ_KEY_EXACT) - goto pk; - goto range; - case UNIQUE_ORDERED_INDEX: - if (multi_range_curr->start_key.length == key_info->key_length && - multi_range_curr->start_key.flag == HA_READ_KEY_EXACT && - !check_null_in_key(key_info, multi_range_curr->start_key.key, - multi_range_curr->start_key.length)) - goto sk; - goto range; - case ORDERED_INDEX: { + case ORDERED_INDEX: + { range: multi_range_curr->range_flag &= ~(uint)UNIQUE_RANGE; if (scanOp == 0) @@ -5647,7 +5645,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, DBUG_ASSERT(scanOp->getSorted() == sorted); DBUG_ASSERT(scanOp->getLockMode() == (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type)); - if(scanOp->reset_bounds(m_force_send)) + if (scanOp->reset_bounds(m_force_send)) DBUG_RETURN(ndb_err(m_active_trans)); end_of_buffer -= reclength; @@ -5673,7 +5671,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, DBUG_RETURN(res); break; } - case(UNDEFINED_INDEX): + case UNDEFINED_INDEX: DBUG_ASSERT(FALSE); DBUG_RETURN(1); break; @@ -5782,7 +5780,7 @@ ha_ndbcluster::read_multi_range_next(KEY_MULTI_RANGE ** multi_range_found_p) DBUG_MULTI_RANGE(6); // First fetch from cursor DBUG_ASSERT(range_no == -1); - if((res= m_multi_cursor->nextResult(true))) + if ((res= m_multi_cursor->nextResult(true))) { goto close_scan; } @@ -5885,7 +5883,7 @@ ha_ndbcluster::update_table_comment( const char* comment)/* in: table comment defined by user */ { uint length= strlen(comment); - if(length > 64000 - 3) + if (length > 64000 - 3) { return((char*)comment); /* string too long */ } @@ -5912,9 +5910,9 @@ ha_ndbcluster::update_table_comment( return (char*)comment; } - snprintf(str,fmt_len_plus_extra,fmt,comment, - length > 0 ? " ":"", - tab->getReplicaCount()); + my_snprintf(str,fmt_len_plus_extra,fmt,comment, + length > 0 ? " ":"", + tab->getReplicaCount()); return str; } @@ -6013,7 +6011,7 @@ extern "C" pthread_handler_decl(ndb_util_thread_func, lock= share->commit_count_lock; pthread_mutex_unlock(&share->mutex); - if(ndb_get_table_statistics(ndb, tabname, &stat) == 0) + if (ndb_get_table_statistics(ndb, tabname, &stat) == 0) { DBUG_PRINT("ndb_util_thread", ("Table: %s, commit_count: %llu, rows: %llu", @@ -6048,7 +6046,7 @@ extern "C" pthread_handler_decl(ndb_util_thread_func, abstime.tv_sec= tick_time.tv_sec; abstime.tv_nsec= tick_time.tv_usec * 1000; - if(msecs >= 1000){ + if (msecs >= 1000){ secs= msecs / 1000; msecs= msecs % 1000; } @@ -6157,17 +6155,18 @@ void ndb_serialize_cond(const Item *item, void *arg) { DBUG_PRINT("info", ("Skiping argument %d", context->skip)); context->skip--; - switch(item->type()) { - case (Item::FUNC_ITEM): { + switch (item->type()) { + case Item::FUNC_ITEM: + { Item_func *func_item= (Item_func *) item; context->skip+= func_item->argument_count(); break; } - case(Item::INT_ITEM): - case(Item::REAL_ITEM): - case(Item::STRING_ITEM): - case(Item::VARBIN_ITEM): - case(Item::DECIMAL_ITEM): + case Item::INT_ITEM: + case Item::REAL_ITEM: + case Item::STRING_ITEM: + case Item::VARBIN_ITEM: + case Item::DECIMAL_ITEM: break; default: context->supported= FALSE; @@ -6186,8 +6185,8 @@ void ndb_serialize_cond(const Item *item, void *arg) (func_item= rewrite_context->func_item) && rewrite_context->count++ == 0) { - switch(func_item->functype()) { - case(Item_func::BETWEEN): + switch (func_item->functype()) { + case Item_func::BETWEEN: /* Rewrite <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2> @@ -6197,7 +6196,8 @@ void ndb_serialize_cond(const Item *item, void *arg) BEGIN(AND) GT(<field>|<const>, <const1>|<field1>), LT(<field>|<const>, <const2>|<field2>), END() */ - case(Item_func::IN_FUNC): { + case Item_func::IN_FUNC: + { /* Rewrite <field>|<const> IN(<const1>|<field1>, <const2>|<field2>,..) to <field>|<const> = <const1>|<field1> OR @@ -6262,17 +6262,18 @@ void ndb_serialize_cond(const Item *item, void *arg) { Ndb_rewrite_context *rewrite_context= context->rewrite_stack; const Item_func *func_item= rewrite_context->func_item; - switch(func_item->functype()) { - case(Item_func::BETWEEN): { - /* - Rewrite - <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2> - to <field>|<const> > <const1>|<field1> AND - <field>|<const> < <const2>|<field2> - or actually in prefix format - BEGIN(AND) GT(<field>|<const>, <const1>|<field1>), - LT(<field>|<const>, <const2>|<field2>), END() - */ + switch (func_item->functype()) { + case Item_func::BETWEEN: + { + /* + Rewrite + <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2> + to <field>|<const> > <const1>|<field1> AND + <field>|<const> < <const2>|<field2> + or actually in prefix format + BEGIN(AND) GT(<field>|<const>, <const1>|<field1>), + LT(<field>|<const>, <const2>|<field2>), END() + */ if (rewrite_context->count == 2) { // Lower limit of BETWEEN @@ -6294,7 +6295,8 @@ void ndb_serialize_cond(const Item *item, void *arg) } break; } - case(Item_func::IN_FUNC): { + case Item_func::IN_FUNC: + { /* Rewrite <field>|<const> IN(<const1>|<field1>, <const2>|<field2>,..) to <field>|<const> = <const1>|<field1> OR @@ -6343,8 +6345,10 @@ void ndb_serialize_cond(const Item *item, void *arg) curr_cond->ndb_item= new Ndb_item(NDB_END_COND); } else - switch(item->type()) { - case(Item::FIELD_ITEM): { + { + switch (item->type()) { + case Item::FIELD_ITEM: + { Item_field *field_item= (Item_field *) item; Field *field= field_item->field; enum_field_types type= field->type(); @@ -6390,23 +6394,23 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect(Item::INT_ITEM); } else - switch(field->result_type()) { - case(STRING_RESULT): + switch (field->result_type()) { + case STRING_RESULT: // Expect char string or binary string context->expect_only(Item::STRING_ITEM); context->expect(Item::VARBIN_ITEM); context->expect_collation(field_item->collation.collation); break; - case(REAL_RESULT): + case REAL_RESULT: context->expect_only(Item::REAL_ITEM); context->expect(Item::DECIMAL_ITEM); context->expect(Item::INT_ITEM); break; - case(INT_RESULT): + case INT_RESULT: context->expect_only(Item::INT_ITEM); context->expect(Item::VARBIN_ITEM); break; - case(DECIMAL_RESULT): + case DECIMAL_RESULT: context->expect_only(Item::DECIMAL_ITEM); context->expect(Item::REAL_ITEM); context->expect(Item::INT_ITEM); @@ -6451,7 +6455,8 @@ void ndb_serialize_cond(const Item *item, void *arg) } break; } - case(Item::FUNC_ITEM): { + case Item::FUNC_ITEM: + { Item_func *func_item= (Item_func *) item; // Check that we expect a function or functional expression here if (context->expecting(Item::FUNC_ITEM) || @@ -6464,8 +6469,9 @@ void ndb_serialize_cond(const Item *item, void *arg) break; } - switch(func_item->functype()) { - case(Item_func::EQ_FUNC): { + switch (func_item->functype()) { + case Item_func::EQ_FUNC: + { DBUG_PRINT("info", ("EQ_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6481,7 +6487,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::NE_FUNC): { + case Item_func::NE_FUNC: + { DBUG_PRINT("info", ("NE_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6497,7 +6504,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::LT_FUNC): { + case Item_func::LT_FUNC: + { DBUG_PRINT("info", ("LT_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6513,7 +6521,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::LE_FUNC): { + case Item_func::LE_FUNC: + { DBUG_PRINT("info", ("LE_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6529,7 +6538,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::GE_FUNC): { + case Item_func::GE_FUNC: + { DBUG_PRINT("info", ("GE_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6545,7 +6555,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::GT_FUNC): { + case Item_func::GT_FUNC: + { DBUG_PRINT("info", ("GT_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6561,7 +6572,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::LIKE_FUNC): { + case Item_func::LIKE_FUNC: + { DBUG_PRINT("info", ("LIKE_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6571,7 +6583,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect(Item::FUNC_ITEM); break; } - case(Item_func::NOTLIKE_FUNC): { + case Item_func::NOTLIKE_FUNC: + { DBUG_PRINT("info", ("NOTLIKE_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6581,7 +6594,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect(Item::FUNC_ITEM); break; } - case(Item_func::ISNULL_FUNC): { + case Item_func::ISNULL_FUNC: + { DBUG_PRINT("info", ("ISNULL_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6592,7 +6606,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::ISNOTNULL_FUNC): { + case Item_func::ISNOTNULL_FUNC: + { DBUG_PRINT("info", ("ISNOTNULL_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6603,7 +6618,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(DECIMAL_RESULT); break; } - case(Item_func::NOT_FUNC): { + case Item_func::NOT_FUNC: + { DBUG_PRINT("info", ("NOT_FUNC")); curr_cond->ndb_item= new Ndb_item(func_item->functype(), func_item); @@ -6611,7 +6627,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect(Item::COND_ITEM); break; } - case(Item_func::BETWEEN) : { + case Item_func::BETWEEN: + { DBUG_PRINT("info", ("BETWEEN, rewriting using AND")); Ndb_rewrite_context *rewrite_context= new Ndb_rewrite_context(func_item); @@ -6627,7 +6644,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect(Item::FUNC_ITEM); break; } - case(Item_func::IN_FUNC) : { + case Item_func::IN_FUNC: + { DBUG_PRINT("info", ("IN_FUNC, rewriting using OR")); Ndb_rewrite_context *rewrite_context= new Ndb_rewrite_context(func_item); @@ -6643,13 +6661,16 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect(Item::FUNC_ITEM); break; } - case(Item_func::UNKNOWN_FUNC): { + case Item_func::UNKNOWN_FUNC: + { DBUG_PRINT("info", ("UNKNOWN_FUNC %s", func_item->const_item()?"const":"")); DBUG_PRINT("info", ("result type %d", func_item->result_type())); if (func_item->const_item()) - switch(func_item->result_type()) { - case(STRING_RESULT): { + { + switch (func_item->result_type()) { + case STRING_RESULT: + { NDB_ITEM_QUALIFICATION q; q.value_type= Item::STRING_ITEM; curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); @@ -6678,7 +6699,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->skip= func_item->argument_count(); break; } - case(REAL_RESULT): { + case REAL_RESULT: + { NDB_ITEM_QUALIFICATION q; q.value_type= Item::REAL_ITEM; curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); @@ -6700,7 +6722,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->skip= func_item->argument_count(); break; } - case(INT_RESULT): { + case INT_RESULT: + { NDB_ITEM_QUALIFICATION q; q.value_type= Item::INT_ITEM; curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); @@ -6722,7 +6745,8 @@ void ndb_serialize_cond(const Item *item, void *arg) context->skip= func_item->argument_count(); break; } - case(DECIMAL_RESULT): { + case DECIMAL_RESULT: + { NDB_ITEM_QUALIFICATION q; q.value_type= Item::DECIMAL_ITEM; curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); @@ -6746,12 +6770,14 @@ void ndb_serialize_cond(const Item *item, void *arg) default: break; } + } else // Function does not return constant expression context->supported= FALSE; break; } - default: { + default: + { DBUG_PRINT("info", ("Found func_item of type %d", func_item->functype())); context->supported= FALSE; @@ -6759,7 +6785,7 @@ void ndb_serialize_cond(const Item *item, void *arg) } break; } - case(Item::STRING_ITEM): + case Item::STRING_ITEM: DBUG_PRINT("info", ("STRING_ITEM")); if (context->expecting(Item::STRING_ITEM)) { @@ -6798,7 +6824,7 @@ void ndb_serialize_cond(const Item *item, void *arg) else context->supported= FALSE; break; - case(Item::INT_ITEM): + case Item::INT_ITEM: DBUG_PRINT("info", ("INT_ITEM")); if (context->expecting(Item::INT_ITEM)) { @@ -6825,7 +6851,7 @@ void ndb_serialize_cond(const Item *item, void *arg) else context->supported= FALSE; break; - case(Item::REAL_ITEM): + case Item::REAL_ITEM: DBUG_PRINT("info", ("REAL_ITEM %s")); if (context->expecting(Item::REAL_ITEM)) { @@ -6850,7 +6876,7 @@ void ndb_serialize_cond(const Item *item, void *arg) else context->supported= FALSE; break; - case(Item::VARBIN_ITEM): + case Item::VARBIN_ITEM: DBUG_PRINT("info", ("VARBIN_ITEM")); if (context->expecting(Item::VARBIN_ITEM)) { @@ -6873,7 +6899,7 @@ void ndb_serialize_cond(const Item *item, void *arg) else context->supported= FALSE; break; - case(Item::DECIMAL_ITEM): + case Item::DECIMAL_ITEM: DBUG_PRINT("info", ("DECIMAL_ITEM %s")); if (context->expecting(Item::DECIMAL_ITEM)) { @@ -6899,17 +6925,19 @@ void ndb_serialize_cond(const Item *item, void *arg) else context->supported= FALSE; break; - case(Item::COND_ITEM): { + case Item::COND_ITEM: + { Item_cond *cond_item= (Item_cond *) item; if (context->expecting(Item::COND_ITEM)) - switch(cond_item->functype()) { - case(Item_func::COND_AND_FUNC): + { + switch (cond_item->functype()) { + case Item_func::COND_AND_FUNC: DBUG_PRINT("info", ("COND_AND_FUNC")); curr_cond->ndb_item= new Ndb_item(cond_item->functype(), cond_item); break; - case(Item_func::COND_OR_FUNC): + case Item_func::COND_OR_FUNC: DBUG_PRINT("info", ("COND_OR_FUNC")); curr_cond->ndb_item= new Ndb_item(cond_item->functype(), cond_item); @@ -6919,17 +6947,21 @@ void ndb_serialize_cond(const Item *item, void *arg) context->supported= FALSE; break; } + } else - // Did not expect condition + { + /* Did not expect condition */ context->supported= FALSE; + } break; } - default: { + default: + { DBUG_PRINT("info", ("Found item of type %d", item->type())); context->supported= FALSE; } } - + } if (context->supported && context->rewrite_stack) { Ndb_rewrite_context *rewrite_context= context->rewrite_stack; @@ -6973,18 +7005,19 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, bool negated) { DBUG_ENTER("build_scan_filter_predicate"); - switch(cond->ndb_item->type) { - case(NDB_FUNCTION): { + switch (cond->ndb_item->type) { + case NDB_FUNCTION: + { if (!cond->next) break; Ndb_item *a= cond->next->ndb_item; Ndb_item *b, *field, *value= NULL; - switch(cond->ndb_item->argument_count()) { - case(1): + switch (cond->ndb_item->argument_count()) { + case 1: field= (a->type == NDB_FIELD)? a : NULL; break; - case(2): + case 2: if (!cond->next->next) break; b= cond->next->next->ndb_item; @@ -7000,11 +7033,11 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, default: break; } - switch((negated) ? - Ndb_item::negate(cond->ndb_item->qualification.function_type) - : cond->ndb_item->qualification.function_type) + switch ((negated) ? + Ndb_item::negate(cond->ndb_item->qualification.function_type) + : cond->ndb_item->qualification.function_type) { + case Item_func::EQ_FUNC: { - case(Item_func::EQ_FUNC): { if (!value || !field) break; // Save value in right format for the field type value->save_in_field(field); @@ -7017,7 +7050,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::NE_FUNC): { + case Item_func::NE_FUNC: + { if (!value || !field) break; // Save value in right format for the field type value->save_in_field(field); @@ -7030,7 +7064,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::LT_FUNC): { + case Item_func::LT_FUNC: + { if (!value || !field) break; // Save value in right format for the field type value->save_in_field(field); @@ -7055,7 +7090,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::LE_FUNC): { + case Item_func::LE_FUNC: + { if (!value || !field) break; // Save value in right format for the field type value->save_in_field(field); @@ -7080,7 +7116,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::GE_FUNC): { + case Item_func::GE_FUNC: + { if (!value || !field) break; // Save value in right format for the field type value->save_in_field(field); @@ -7105,7 +7142,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::GT_FUNC): { + case Item_func::GT_FUNC: + { if (!value || !field) break; // Save value in right format for the field type value->save_in_field(field); @@ -7130,7 +7168,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::LIKE_FUNC): { + case Item_func::LIKE_FUNC: + { if (!value || !field) break; if ((value->qualification.value_type != Item::STRING_ITEM) && (value->qualification.value_type != Item::VARBIN_ITEM)) @@ -7148,7 +7187,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::NOTLIKE_FUNC): { + case Item_func::NOTLIKE_FUNC: + { if (!value || !field) break; if ((value->qualification.value_type != Item::STRING_ITEM) && (value->qualification.value_type != Item::VARBIN_ITEM)) @@ -7166,7 +7206,7 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, cond= cond->next->next->next; DBUG_RETURN(0); } - case(Item_func::ISNULL_FUNC): + case Item_func::ISNULL_FUNC: if (!field) break; DBUG_PRINT("info", ("Generating ISNULL filter")); @@ -7174,7 +7214,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, DBUG_RETURN(1); cond= cond->next->next; DBUG_RETURN(0); - case(Item_func::ISNOTNULL_FUNC): { + case Item_func::ISNOTNULL_FUNC: + { if (!field) break; DBUG_PRINT("info", ("Generating ISNOTNULL filter")); @@ -7200,15 +7241,18 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter) { uint level=0; bool negated= FALSE; - DBUG_ENTER("build_scan_filter_group"); + do { - if (!cond) DBUG_RETURN(1); - switch(cond->ndb_item->type) { - case(NDB_FUNCTION): - switch(cond->ndb_item->qualification.function_type) { - case(Item_func::COND_AND_FUNC): { + if (!cond) + DBUG_RETURN(1); + switch (cond->ndb_item->type) { + case NDB_FUNCTION: + { + switch (cond->ndb_item->qualification.function_type) { + case Item_func::COND_AND_FUNC: + { level++; DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NAND":"AND", level)); @@ -7219,7 +7263,8 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter) cond= cond->next; break; } - case(Item_func::COND_OR_FUNC): { + case Item_func::COND_OR_FUNC: + { level++; DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NOR":"OR", level)); @@ -7230,11 +7275,11 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter) cond= cond->next; break; } - case(Item_func::NOT_FUNC): { + case Item_func::NOT_FUNC: + { DBUG_PRINT("info", ("Generating negated query")); cond= cond->next; negated= TRUE; - break; } default: @@ -7244,7 +7289,8 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter) break; } break; - case(NDB_END_COND): + } + case NDB_END_COND: DBUG_PRINT("info", ("End of group %u", level)); level--; if (cond) cond= cond->next; @@ -7253,7 +7299,8 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter) if (!negated) break; // else fall through (NOT END is an illegal condition) - default: { + default: + { DBUG_PRINT("info", ("Illegal scan filter")); } } @@ -7268,11 +7315,11 @@ ha_ndbcluster::build_scan_filter(Ndb_cond * &cond, NdbScanFilter *filter) bool simple_cond= TRUE; DBUG_ENTER("build_scan_filter"); - switch(cond->ndb_item->type) { - case(NDB_FUNCTION): - switch(cond->ndb_item->qualification.function_type) { - case(Item_func::COND_AND_FUNC): - case(Item_func::COND_OR_FUNC): + switch (cond->ndb_item->type) { + case NDB_FUNCTION: + switch (cond->ndb_item->qualification.function_type) { + case Item_func::COND_AND_FUNC: + case Item_func::COND_OR_FUNC: simple_cond= FALSE; break; default: diff --git a/sql/handler.cc b/sql/handler.cc index 46a80770024..a61dce35501 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1949,14 +1949,12 @@ int ha_create_table_from_engine(THD* thd, HA_CREATE_INFO create_info; TABLE table; DBUG_ENTER("ha_create_table_from_engine"); - DBUG_PRINT("enter", ("name '%s'.'%s'", - db, name)); + DBUG_PRINT("enter", ("name '%s'.'%s'", db, name)); bzero((char*) &create_info,sizeof(create_info)); - - if(error= ha_discover(thd, db, name, &frmblob, &frmlen)) + if ((error= ha_discover(thd, db, name, &frmblob, &frmlen))) { - // Table could not be discovered and thus not created + /* Table could not be discovered and thus not created */ DBUG_RETURN(error); } @@ -1967,11 +1965,10 @@ int ha_create_table_from_engine(THD* thd, (void)strxnmov(path,FN_REFLEN,mysql_data_home,"/",db,"/",name,NullS); // Save the frm file - if (writefrm(path, frmblob, frmlen)) - { - my_free((char*) frmblob, MYF(MY_ALLOW_ZERO_PTR)); + error= writefrm(path, frmblob, frmlen); + my_free((char*) frmblob, MYF(0)); + if (error) DBUG_RETURN(2); - } if (openfrm(thd, path,"",0,(uint) READ_ALL, 0, &table)) DBUG_RETURN(3); @@ -1987,7 +1984,6 @@ int ha_create_table_from_engine(THD* thd, } error=table.file->create(path,&table,&create_info); VOID(closefrm(&table)); - my_free((char*) frmblob, MYF(MY_ALLOW_ZERO_PTR)); DBUG_RETURN(error != 0); } diff --git a/sql/item.cc b/sql/item.cc index 82edc05c721..e53c1ebf734 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -338,7 +338,6 @@ Item::Item(): place == IN_HAVING) thd->lex->current_select->select_n_having_items++; } - item_flags= 0; } /* @@ -359,8 +358,7 @@ Item::Item(THD *thd, Item *item): unsigned_flag(item->unsigned_flag), with_sum_func(item->with_sum_func), fixed(item->fixed), - collation(item->collation), - item_flags(item->item_flags) + collation(item->collation) { next= thd->free_list; // Put in free list thd->free_list= this; @@ -440,16 +438,17 @@ void Item::rename(char *new_name) } -Item_ident::Item_ident(const char *db_name_par,const char *table_name_par, - const char *field_name_par) - :orig_db_name(db_name_par), orig_table_name(table_name_par), - orig_field_name(field_name_par), - db_name(db_name_par), table_name(table_name_par), - field_name(field_name_par), +Item_ident::Item_ident(Name_resolution_context *context_arg, + const char *db_name_arg,const char *table_name_arg, + const char *field_name_arg) + :orig_db_name(db_name_arg), orig_table_name(table_name_arg), + orig_field_name(field_name_arg), context(context_arg), + db_name(db_name_arg), table_name(table_name_arg), + field_name(field_name_arg), alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX), cached_table(0), depended_from(0) { - name = (char*) field_name_par; + name = (char*) field_name_arg; } @@ -460,6 +459,7 @@ Item_ident::Item_ident(THD *thd, Item_ident *item) orig_db_name(item->orig_db_name), orig_table_name(item->orig_table_name), orig_field_name(item->orig_field_name), + context(item->context), db_name(item->db_name), table_name(item->table_name), field_name(item->field_name), @@ -785,7 +785,7 @@ Item_splocal::type() const } -bool Item_splocal::fix_fields(THD *, struct st_table_list *, Item **) +bool Item_splocal::fix_fields(THD *, Item **) { Item *it= this_item(); DBUG_ASSERT(it->fixed); @@ -855,7 +855,8 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, uint el= fields.elements; Item *new_item; ref_pointer_array[el]= this; - if (!(new_item= new Item_ref(ref_pointer_array + el, 0, name))) + if (!(new_item= new Item_ref(&thd->lex->current_select->context, + ref_pointer_array + el, 0, name))) return; // fatal_error is set fields.push_front(this); ref_pointer_array[el]= this; @@ -995,7 +996,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags) } Item_field::Item_field(Field *f) - :Item_ident(NullS, *f->table_name, f->field_name), + :Item_ident(0, NullS, *f->table_name, f->field_name), item_equal(0), no_const_subst(0), have_privileges(0), any_privileges(0) { @@ -1007,8 +1008,9 @@ Item_field::Item_field(Field *f) orig_table_name= orig_field_name= ""; } -Item_field::Item_field(THD *thd, Field *f) - :Item_ident(f->table->s->db, *f->table_name, f->field_name), +Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, + Field *f) + :Item_ident(context_arg, f->table->s->db, *f->table_name, f->field_name), item_equal(0), no_const_subst(0), have_privileges(0), any_privileges(0) { @@ -1043,6 +1045,17 @@ Item_field::Item_field(THD *thd, Field *f) set_field(f); } + +Item_field::Item_field(Name_resolution_context *context_arg, + const char *db_arg,const char *table_name_arg, + const char *field_name_arg) + :Item_ident(context_arg, db_arg,table_name_arg,field_name_arg), + field(0), result_field(0), item_equal(0), no_const_subst(0), + have_privileges(0), any_privileges(0) +{ + collation.set(DERIVATION_IMPLICIT); +} + // Constructor need to process subselect with temporary tables (see Item) Item_field::Item_field(THD *thd, Item_field *item) :Item_ident(thd, item), @@ -2233,7 +2246,7 @@ bool Item_param::convert_str_value(THD *thd) return rc; } -bool Item_param::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +bool Item_param::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); SELECT_LEX *cursel= (SELECT_LEX *) thd->lex->current_select; @@ -2393,9 +2406,7 @@ int Item_copy_string::save_in_field(Field *field, bool no_conversions) */ /* ARGSUSED */ -bool Item::fix_fields(THD *thd, - struct st_table_list *list, - Item ** ref) +bool Item::fix_fields(THD *thd, Item ** ref) { // We do not check fields which are fixed during construction @@ -2762,7 +2773,6 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) SYNOPSIS Item_field::fix_fields() thd [in] current thread - tables [in] the tables in a FROM clause reference [in/out] view column if this item was resolved to a view column DESCRIPTION @@ -2808,7 +2818,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) FALSE on success */ -bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) +bool Item_field::fix_fields(THD *thd, Item **reference) { enum_parsing_place place= NO_MATTER; DBUG_ASSERT(fixed == 0); @@ -2821,135 +2831,131 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) expression to 'reference', i.e. it substitute that expression instead of this Item_field */ - if ((from_field= find_field_in_tables(thd, this, tables, reference, - IGNORE_EXCEPT_NON_UNIQUE, - !any_privileges)) == + if ((from_field= find_field_in_tables(thd, this, context->table_list, + reference, + IGNORE_EXCEPT_NON_UNIQUE, + !any_privileges && + context->check_privileges, + TRUE)) == not_found_field) { - SELECT_LEX *last= 0; - TABLE_LIST *table_list; - Item **ref= (Item **) not_found_item; - SELECT_LEX *current_sel= (SELECT_LEX *) thd->lex->current_select; /* - If there is an outer select, and it is not a derived table (which do - not support the use of outer fields for now), try to resolve this - reference in the outer select(s). - + If there is an outer contexts (outer selects, but current select is + not derived table or view) try to resolve this reference in the + outer contexts. + We treat each subselect as a separate namespace, so that different subselects may contain columns with the same names. The subselects are - searched starting from the innermost. + searched starting from the innermost. */ - if (current_sel->master_unit()->first_select()->linkage != - DERIVED_TABLE_TYPE) + Name_resolution_context *last_checked_context= context; + Item **ref= (Item **) not_found_item; + Name_resolution_context *outer_context= context->outer_context; + for (; + outer_context; + outer_context= outer_context->outer_context) { - SELECT_LEX_UNIT *prev_unit= current_sel->master_unit(); - SELECT_LEX *outer_sel= prev_unit->outer_select(); - for ( ; outer_sel ; - outer_sel= (prev_unit= outer_sel->master_unit())->outer_select()) - { - last= outer_sel; - Item_subselect *prev_subselect_item= prev_unit->item; - upward_lookup= TRUE; - - /* Search in the tables of the FROM clause of the outer select. */ - table_list= outer_sel->get_table_list(); - if (outer_sel->resolve_mode == SELECT_LEX::INSERT_MODE && table_list) - { - /* - It is a primary INSERT st_select_lex => do not resolve against the - first table. - */ - table_list= table_list->next_local; - } - place= prev_subselect_item->parsing_place; - /* - Check table fields only if the subquery is used somewhere out of - HAVING, or the outer SELECT does not use grouping (i.e. tables are - accessible). + SELECT_LEX *select= outer_context->select_lex; + Item_subselect *prev_subselect_item= + last_checked_context->select_lex->master_unit()->item; + last_checked_context= outer_context; + upward_lookup= TRUE; - In case of view, find_field_in_tables() write pointer to view - field expression to 'reference', i.e. it substitute that - expression instead of this Item_field - */ - if ((place != IN_HAVING || - (outer_sel->with_sum_func == 0 && - outer_sel->group_list.elements == 0)) && - (from_field= find_field_in_tables(thd, this, table_list, - reference, - IGNORE_EXCEPT_NON_UNIQUE, - TRUE)) != - not_found_field) - { - if (from_field) - { - if (from_field != view_ref_found) - { - prev_subselect_item->used_tables_cache|= from_field->table->map; - prev_subselect_item->const_item_cache= 0; - } - else - { - Item::Type type= (*reference)->type(); - prev_subselect_item->used_tables_cache|= - (*reference)->used_tables(); - prev_subselect_item->const_item_cache&= - (*reference)->const_item(); - mark_as_dependent(thd, last, current_sel, this, - ((type == REF_ITEM || type == FIELD_ITEM) ? - (Item_ident*) (*reference) : - 0)); - /* - view reference found, we substituted it instead of this - Item (find_field_in_tables do it by assigning new value to - *reference), so can quit - */ - return FALSE; - } - } - break; - } + place= prev_subselect_item->parsing_place; + /* + Check table fields only if the subquery is used somewhere out of + HAVING, or the outer SELECT does not use grouping (i.e. tables are + accessible). - /* Search in the SELECT and GROUP lists of the outer select. */ - if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE) + In case of a view, find_field_in_tables() writes the pointer to + the found view field into '*reference', in other words, it + substitutes this Item_field with the found expression. + */ + if ((place != IN_HAVING || + (!select->with_sum_func && + select->group_list.elements == 0)) && + (from_field= find_field_in_tables(thd, this, + outer_context->table_list, + reference, + IGNORE_EXCEPT_NON_UNIQUE, + outer_context-> + check_privileges, + TRUE)) != + not_found_field) + { + if (from_field) { - if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel))) - return TRUE; /* Some error occurred (e.g. ambiguous names). */ - if (ref != not_found_item) + if (from_field != view_ref_found) + { + prev_subselect_item->used_tables_cache|= from_field->table->map; + prev_subselect_item->const_item_cache= 0; + } + else { - DBUG_ASSERT(*ref && (*ref)->fixed); - prev_subselect_item->used_tables_cache|= (*ref)->used_tables(); - prev_subselect_item->const_item_cache&= (*ref)->const_item(); - break; + Item::Type type= (*reference)->type(); + prev_subselect_item->used_tables_cache|= + (*reference)->used_tables(); + prev_subselect_item->const_item_cache&= + (*reference)->const_item(); + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, this, + ((type == REF_ITEM || type == FIELD_ITEM) ? + (Item_ident*) (*reference) : + 0)); + /* + A reference to a view field had been found and we + substituted it instead of this Item (find_field_in_tables + does it by assigning the new value to *reference), so now + we can return from this function. + */ + return FALSE; } - } + } + break; + } - // Reference is not found => depend from outer (or just error) - prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; - prev_subselect_item->const_item_cache= 0; + /* Search in SELECT and GROUP lists of the outer select. */ + if (outer_context->resolve_in_select_list) + { + if (!(ref= resolve_ref_in_select_and_group(thd, this, select))) + goto error; /* Some error occurred (e.g. ambiguous names). */ + if (ref != not_found_item) + { + DBUG_ASSERT(*ref && (*ref)->fixed); + prev_subselect_item->used_tables_cache|= (*ref)->used_tables(); + prev_subselect_item->const_item_cache&= (*ref)->const_item(); + break; + } + } - if (outer_sel->master_unit()->first_select()->linkage == - DERIVED_TABLE_TYPE) - break; // do not look over derived table - } + /* + Reference is not found in this select => this subquery depend on + outer select (or we just trying to find wrong identifier, in this + case it does not matter which used tables bits we set) + */ + prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; + prev_subselect_item->const_item_cache= 0; } DBUG_ASSERT(ref != 0); if (!from_field) - return TRUE; + goto error; if (ref == not_found_item && from_field == not_found_field) { if (upward_lookup) { - // We can't say exactly what absent table or field + // We can't say exactly what absent table or field my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd->where); } else { - // Call to report error - find_field_in_tables(thd, this, tables, reference, REPORT_ALL_ERRORS, - TRUE); + /* Call find_field_in_tables only to report the error */ + find_field_in_tables(thd, this, context->table_list, + reference, REPORT_ALL_ERRORS, + !any_privileges && + context->check_privileges, TRUE); } - return TRUE; + goto error; } else if (ref != not_found_item) { @@ -2967,45 +2973,54 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) save= *ref; *ref= NULL; // Don't call set_properties() rf= (place == IN_HAVING ? - new Item_ref(ref, (char*) table_name, (char*) field_name) : - new Item_direct_ref(ref, (char*) table_name, (char*) field_name)); + new Item_ref(context, ref, (char*) table_name, + (char*) field_name) : + new Item_direct_ref(context, ref, (char*) table_name, + (char*) field_name)); *ref= save; if (!rf) - return TRUE; + goto error; thd->change_item_tree(reference, rf); /* rf is Item_ref => never substitute other items (in this case) during fix_fields() => we can use rf after fix_fields() */ DBUG_ASSERT(!rf->fixed); // Assured by Item_ref() - if (rf->fix_fields(thd, tables, reference) || rf->check_cols(1)) - return TRUE; + if (rf->fix_fields(thd, reference) || rf->check_cols(1)) + goto error; - mark_as_dependent(thd, last, current_sel, this, rf); + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, this, + rf); return FALSE; } else { - mark_as_dependent(thd, last, current_sel, this, this); - if (last->having_fix_field) + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, + this, this); + if (last_checked_context->select_lex->having_fix_field) { Item_ref *rf; - rf= new Item_ref((cached_table->db[0] ? cached_table->db : 0), + rf= new Item_ref(context, + (cached_table->db[0] ? cached_table->db : 0), (char*) cached_table->alias, (char*) field_name); if (!rf) - return TRUE; + goto error; thd->change_item_tree(reference, rf); /* rf is Item_ref => never substitute other items (in this case) during fix_fields() => we can use rf after fix_fields() */ DBUG_ASSERT(!rf->fixed); // Assured by Item_ref() - return (rf->fix_fields(thd, tables, reference) || rf->check_cols(1)); + if (rf->fix_fields(thd, reference) || rf->check_cols(1)) + goto error; + return FALSE; } } } else if (!from_field) - return TRUE; + goto error; /* if it is not expression from merged VIEW we will set this field. @@ -3053,12 +3068,16 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), "ANY", thd->priv_user, thd->host_or_ip, field_name, tab); - return TRUE; + goto error; } } #endif fixed= 1; return FALSE; + +error: + context->process_error(thd); + return TRUE; } @@ -3347,6 +3366,9 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) case MYSQL_TYPE_YEAR: return new Field_year((char*) 0, max_length, null_ptr, 0, Field::NONE, name, table); + case MYSQL_TYPE_BIT: + return new Field_bit_as_char(NULL, max_length, null_ptr, 0, NULL, 0, + Field::NONE, name, table); default: /* This case should never be chosen */ DBUG_ASSERT(0); @@ -3919,16 +3941,17 @@ bool Item_field::send(Protocol *protocol, String *buffer) } -Item_ref::Item_ref(Item **item, const char *table_name_par, - const char *field_name_par) - :Item_ident(NullS, table_name_par, field_name_par), result_field(0), - ref(item) +Item_ref::Item_ref(Name_resolution_context *context_arg, + Item **item, const char *table_name_arg, + const char *field_name_arg) + :Item_ident(context_arg, NullS, table_name_arg, field_name_arg), + result_field(0), ref(item) { /* This constructor used to create some internals references over fixed items */ DBUG_ASSERT(ref != 0); - if (*ref) + if (*ref && (*ref)->fixed) set_properties(); } @@ -3939,7 +3962,6 @@ Item_ref::Item_ref(Item **item, const char *table_name_par, SYNOPSIS Item_ref::fix_fields() thd [in] current thread - tables [in] the tables in a FROM clause reference [in/out] view column if this item was resolved to a view column DESCRIPTION @@ -3991,59 +4013,56 @@ Item_ref::Item_ref(Item **item, const char *table_name_par, FALSE on success */ -bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) +bool Item_ref::fix_fields(THD *thd, Item **reference) { - DBUG_ASSERT(fixed == 0); enum_parsing_place place= NO_MATTER; + DBUG_ASSERT(fixed == 0); SELECT_LEX *current_sel= thd->lex->current_select; if (!ref || ref == not_found_item) { - SELECT_LEX_UNIT *prev_unit= current_sel->master_unit(); - SELECT_LEX *outer_sel= prev_unit->outer_select(); - - if (!(ref= resolve_ref_in_select_and_group(thd, this, current_sel))) - return TRUE; /* Some error occurred (e.g. ambiguous names). */ + if (!(ref= resolve_ref_in_select_and_group(thd, this, + context->select_lex))) + goto error; /* Some error occurred (e.g. ambiguous names). */ if (ref == not_found_item) /* This reference was not resolved. */ { - TABLE_LIST *table_list; + Name_resolution_context *last_checked_context= context; + Name_resolution_context *outer_context= context->outer_context; Field *from_field; - SELECT_LEX *last; ref= 0; - if (!outer_sel || (current_sel->master_unit()->first_select()->linkage == - DERIVED_TABLE_TYPE)) + if (!outer_context) { /* The current reference cannot be resolved in this query. */ my_error(ER_BAD_FIELD_ERROR,MYF(0), this->full_name(), current_thd->where); - return TRUE; + goto error; } + /* - If there is an outer select, and it is not a derived table (which do - not support the use of outer fields for now), try to resolve this - reference in the outer select(s). + If there is an outer context (select), and it is not a derived table + (which do not support the use of outer fields for now), try to + resolve this reference in the outer select(s). We treat each subselect as a separate namespace, so that different subselects may contain columns with the same names. The subselects are searched starting from the innermost. */ from_field= (Field*) not_found_field; - last= 0; - /* The following loop will always be excuted at least once */ - for ( ; outer_sel ; - outer_sel= (prev_unit= outer_sel->master_unit())->outer_select()) + do { - last= outer_sel; - Item_subselect *prev_subselect_item= prev_unit->item; + SELECT_LEX *select= outer_context->select_lex; + Item_subselect *prev_subselect_item= + last_checked_context->select_lex->master_unit()->item; + last_checked_context= outer_context; /* Search in the SELECT and GROUP lists of the outer select. */ - if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE) + if (outer_context->resolve_in_select_list) { - if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel))) - return TRUE; /* Some error occurred (e.g. ambiguous names). */ + if (!(ref= resolve_ref_in_select_and_group(thd, this, select))) + goto error; /* Some error occurred (e.g. ambiguous names). */ if (ref != not_found_item) { DBUG_ASSERT(*ref && (*ref)->fixed); @@ -4059,43 +4078,34 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) ref= 0; } - /* Search in the tables of the FROM clause of the outer select. */ - table_list= outer_sel->get_table_list(); - if (outer_sel->resolve_mode == SELECT_LEX::INSERT_MODE && table_list) - { - /* - It is a primary INSERT st_select_lex => do not resolve against - the first table. - */ - table_list= table_list->next_local; - } - place= prev_subselect_item->parsing_place; /* Check table fields only if the subquery is used somewhere out of HAVING or the outer SELECT does not use grouping (i.e. tables are accessible). - TODO: + TODO: Here we could first find the field anyway, and then test this condition, so that we can give a better error message - ER_WRONG_FIELD_WITH_GROUP, instead of the less informative ER_BAD_FIELD_ERROR which we produce now. */ if ((place != IN_HAVING || - (!outer_sel->with_sum_func && - outer_sel->group_list.elements == 0))) + (!select->with_sum_func && + select->group_list.elements == 0))) { /* In case of view, find_field_in_tables() write pointer to view field expression to 'reference', i.e. it substitute that expression instead of this Item_ref */ - from_field= find_field_in_tables(thd, this, table_list, + from_field= find_field_in_tables(thd, this, + outer_context->table_list, reference, IGNORE_EXCEPT_NON_UNIQUE, + outer_context->check_privileges, TRUE); if (! from_field) - return TRUE; + goto error; if (from_field == view_ref_found) { Item::Type type= (*reference)->type(); @@ -4104,7 +4114,8 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) prev_subselect_item->const_item_cache&= (*reference)->const_item(); DBUG_ASSERT((*reference)->type() == REF_ITEM); - mark_as_dependent(thd, last, current_sel, this, + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, this, ((type == REF_ITEM || type == FIELD_ITEM) ? (Item_ident*) (*reference) : 0)); @@ -4127,19 +4138,18 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; prev_subselect_item->const_item_cache= 0; - if (outer_sel->master_unit()->first_select()->linkage == - DERIVED_TABLE_TYPE) - break; /* Do not consider derived tables. */ - } + outer_context= outer_context->outer_context; + } while (outer_context); DBUG_ASSERT(from_field != 0 && from_field != view_ref_found); if (from_field != not_found_field) { Item_field* fld; if (!(fld= new Item_field(from_field))) - return TRUE; + goto error; thd->change_item_tree(reference, fld); - mark_as_dependent(thd, last, thd->lex->current_select, this, fld); + mark_as_dependent(thd, last_checked_context->select_lex, + thd->lex->current_select, this, fld); return FALSE; } if (ref == 0) @@ -4147,11 +4157,12 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) /* The item was not a table field and not a reference */ my_error(ER_BAD_FIELD_ERROR, MYF(0), this->full_name(), current_thd->where); - return TRUE; + goto error; } /* Should be checked in resolve_ref_in_select_and_group(). */ DBUG_ASSERT(*ref && (*ref)->fixed); - mark_as_dependent(thd, last, current_sel, this, this); + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, this, this); } } @@ -4171,14 +4182,18 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) name, ((*ref)->with_sum_func? "reference to group function": "forward reference in item list")); - return TRUE; + goto error; } set_properties(); if ((*ref)->check_cols(1)) - return TRUE; + goto error; return FALSE; + +error: + context->process_error(thd); + return TRUE; } @@ -4366,18 +4381,16 @@ my_decimal *Item_ref::val_decimal(my_decimal *decimal_value) int Item_ref::save_in_field(Field *to, bool no_conversions) { int res; - if(result_field){ + if (result_field) + { if (result_field->is_null()) { null_value= 1; return set_field_to_null_with_conversions(to, no_conversions); } - else - { - to->set_notnull(); - field_conv(to, result_field); - null_value= 0; - } + to->set_notnull(); + field_conv(to, result_field); + null_value= 0; return 0; } res= (*ref)->save_in_field(to, no_conversions); @@ -4386,6 +4399,19 @@ int Item_ref::save_in_field(Field *to, bool no_conversions) } +void Item_ref::make_field(Send_field *field) +{ + (*ref)->make_field(field); + /* Non-zero in case of a view */ + if (name) + field->col_name= name; + if (table_name) + field->table_name= table_name; + if (db_name) + field->db_name= db_name; +} + + void Item_ref_null_helper::print(String *str) { str->append("<ref_null_helper>(", 18); @@ -4449,6 +4475,31 @@ bool Item_direct_ref::get_date(TIME *ltime,uint fuzzydate) } +/* + Prepare referenced view viewld then call usual Item_direct_ref::fix_fields + + SYNOPSIS + Item_direct_view_ref::fix_fields() + thd thread handler + reference reference on reference where this item stored + + RETURN + FALSE OK + TRUE Error +*/ + +bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference) +{ + /* view fild reference must be defined */ + DBUG_ASSERT(*ref); + /* (*ref)->check_cols() will be made in Item_direct_ref::fix_fields */ + if (!(*ref)->fixed && + ((*ref)->fix_fields(thd, ref))) + return TRUE; + return Item_direct_ref::fix_fields(thd, reference); +} + + void Item_null_helper::print(String *str) { str->append("<null_helper>(", 14); @@ -4464,9 +4515,7 @@ bool Item_default_value::eq(const Item *item, bool binary_cmp) const } -bool Item_default_value::fix_fields(THD *thd, - struct st_table_list *table_list, - Item **items) +bool Item_default_value::fix_fields(THD *thd, Item **items) { Item *real_arg; Item_field *field_arg; @@ -4478,29 +4527,34 @@ bool Item_default_value::fix_fields(THD *thd, fixed= 1; return FALSE; } - if (!arg->fixed && arg->fix_fields(thd, table_list, &arg)) - return TRUE; + if (!arg->fixed && arg->fix_fields(thd, &arg)) + goto error; + real_arg= arg->real_item(); if (real_arg->type() != FIELD_ITEM) { my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name); - return TRUE; + goto error; } field_arg= (Item_field *)real_arg; if (field_arg->field->flags & NO_DEFAULT_VALUE_FLAG) { my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), field_arg->field->field_name); - return TRUE; + goto error; } if (!(def_field= (Field*) sql_alloc(field_arg->field->size_of()))) - return TRUE; + goto error; memcpy(def_field, field_arg->field, field_arg->field->size_of()); def_field->move_field(def_field->table->s->default_values - def_field->table->record[0]); set_field(def_field); return FALSE; + +error: + context->process_error(thd); + return TRUE; } @@ -4523,11 +4577,27 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) { if (field_arg->flags & NO_DEFAULT_VALUE_FLAG) { - push_warning_printf(field_arg->table->in_use, - MYSQL_ERROR::WARN_LEVEL_WARN, - ER_NO_DEFAULT_FOR_FIELD, - ER(ER_NO_DEFAULT_FOR_FIELD), - field_arg->field_name); + if (context->error_processor == &view_error_processor) + { + TABLE_LIST *view= (cached_table->belong_to_view ? + cached_table->belong_to_view : + cached_table); + // TODO: make correct error message + push_warning_printf(field_arg->table->in_use, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_DEFAULT_FOR_VIEW_FIELD, + ER(ER_NO_DEFAULT_FOR_VIEW_FIELD), + view->view_db.str, + view->view_name.str); + } + else + { + push_warning_printf(field_arg->table->in_use, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_DEFAULT_FOR_FIELD, + ER(ER_NO_DEFAULT_FOR_FIELD), + field_arg->field_name); + } return 1; } field_arg->set_default(); @@ -4544,12 +4614,10 @@ bool Item_insert_value::eq(const Item *item, bool binary_cmp) const } -bool Item_insert_value::fix_fields(THD *thd, - struct st_table_list *table_list, - Item **items) +bool Item_insert_value::fix_fields(THD *thd, Item **items) { DBUG_ASSERT(fixed == 0); - if (!arg->fixed && arg->fix_fields(thd, table_list, &arg)) + if (!arg->fixed && arg->fix_fields(thd, &arg)) return TRUE; if (arg->type() == REF_ITEM) @@ -4638,9 +4706,7 @@ bool Item_trigger_field::eq(const Item *item, bool binary_cmp) const } -bool Item_trigger_field::fix_fields(THD *thd, - TABLE_LIST *table_list, - Item **items) +bool Item_trigger_field::fix_fields(THD *thd, Item **items) { /* Since trigger is object tightly associated with TABLE object most @@ -5153,8 +5219,7 @@ enum_field_types Item_type_holder::get_real_type(Item *item) acceptable information for client in send_field, so we make field type from expression type. */ - switch (item->result_type()) - { + switch (item->result_type()) { case STRING_RESULT: return MYSQL_TYPE_VAR_STRING; case INT_RESULT: @@ -5408,6 +5473,34 @@ void Item_result_field::cleanup() DBUG_VOID_RETURN; } +/* + Dummy error processor used by default by Name_resolution_context + + SYNOPSIS + dummy_error_processor() + + NOTE + do nothing +*/ + +void dummy_error_processor(THD *thd, void *data) +{} + +/* + Wrapper of hide_view_error call for Name_resolution_context error processor + + SYNOPSIS + view_error_processor() + + NOTE + hide view underlying tables details in error messages +*/ + +void view_error_processor(THD *thd, void *data) +{ + ((TABLE_LIST *)data)->hide_view_error(thd); +} + /***************************************************************************** ** Instantiate templates *****************************************************************************/ diff --git a/sql/item.h b/sql/item.h index c8180b4932a..560f1124fb4 100644 --- a/sql/item.h +++ b/sql/item.h @@ -24,7 +24,6 @@ struct st_table_list; void item_init(void); /* Init item functions */ class Item_field; - /* "Declared Type Collation" A combination of collation and its derivation. @@ -218,23 +217,110 @@ struct Hybrid_type_traits_integer: public Hybrid_type_traits static const Hybrid_type_traits_integer *instance(); }; + +void dummy_error_processor(THD *thd, void *data); + +void view_error_processor(THD *thd, void *data); + +/* + Instances of Name_resolution_context store the information necesary for + name resolution of Items and other context analysis of a query made in + fix_fields(). + + This structure is a part of SELECT_LEX, a pointer to this structure is + assigned when an item is created (which happens mostly during parsing + (sql_yacc.yy)), but the structure itself will be initialized after parsing + is complete + + TODO: move subquery of INSERT ... SELECT and CREATE ... SELECT to + separate SELECT_LEX which allow to remove tricks of changing this + structure before and after INSERT/CREATE and its SELECT to make correct + field name resolution. +*/ +struct Name_resolution_context +{ + /* + The name resolution context to search in when an Item cannot be + resolved in this context (the context of an outer select) + */ + Name_resolution_context *outer_context; + + /* + List of tables used to resolve the items of this context. Usually these + are tables from the FROM clause of SELECT statement. The exceptions are + INSERT ... SELECT and CREATE ... SELECT statements, where SELECT + subquery is not moved to a separate SELECT_LEX. For these types of + statements we have to change this member dynamically to ensure correct + name resolution of different parts of the statement. + */ + TABLE_LIST *table_list; + + /* + SELECT_LEX item belong to, in case of merged VIEW it can differ from + SELECT_LEX where item was created, so we can't use table_list/field_list + from there + */ + st_select_lex *select_lex; + + /* + Processor of errors caused during Item name resolving, now used only to + hide underlying tables in errors about views (i.e. it substitute some + errors for views) + */ + void (*error_processor)(THD *, void *); + void *error_processor_data; + + /* + When TRUE items are resolved in this context both against the + SELECT list and this->table_list. If FALSE, items are resolved + only against this->table_list. + */ + bool resolve_in_select_list; + + /* + When FALSE we do not check columns right of resolving items, used to + prevent rights check on underlying tables of view + */ + bool check_privileges; + + Name_resolution_context() + :outer_context(0), table_list(0), select_lex(0), + error_processor_data(0), + check_privileges(TRUE) + {} + + void init() + { + resolve_in_select_list= FALSE; + error_processor= &dummy_error_processor; + } + + void resolve_in_table_list_only(TABLE_LIST *tables) + { + table_list= tables; + resolve_in_select_list= FALSE; + } + + void process_error(THD *thd) + { + (*error_processor)(thd, error_processor_data); + } +}; + + /*************************************************************************/ typedef bool (Item::*Item_processor)(byte *arg); typedef Item* (Item::*Item_transformer) (byte *arg); - typedef void (*Cond_traverser) (const Item *item, void *arg); -/* - See comments for sql_yacc.yy: insert_update_elem rule - */ -#define MY_ITEM_PREFER_1ST_TABLE 1 class Item { Item(const Item &); /* Prevent use of these */ void operator=(Item &); public: - static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); } + static void *operator new(size_t size) + { return (void*) sql_alloc((uint) size); } static void *operator new(size_t size, MEM_ROOT *mem_root) { return (void*) alloc_root(mem_root, (uint) size); } /* Special for SP local variable assignment - reusing slots */ @@ -248,7 +334,8 @@ public: PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM, SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER, - PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM}; + PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM, + VIEW_FIXER_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; @@ -277,7 +364,6 @@ public: my_bool is_autogenerated_name; /* indicate was name of this Item autogenerated or set by user */ DTCollation collation; - uint8 item_flags; /* Flags on how item should be processed */ // alloc & destruct is done as start of select using sql_alloc Item(); @@ -302,7 +388,7 @@ public: virtual void cleanup(); virtual void make_field(Send_field *field); Field *make_string_field(TABLE *table); - virtual bool fix_fields(THD *, struct st_table_list *, Item **); + virtual bool fix_fields(THD *, Item **); /* should be used in case where we are sure that we do not need complete fix_fields() procedure. @@ -554,6 +640,8 @@ public: virtual bool remove_fixed(byte * arg) { fixed= 0; return 0; } virtual bool cleanup_processor(byte *arg); virtual bool collect_item_field_processor(byte * arg) { return 0; } + virtual bool change_context_processor(byte *context) { return 0; } + virtual Item *equal_fields_propagator(byte * arg) { return this; } virtual Item *set_no_const_sub(byte *arg) { return this; } virtual Item *replace_equal_field(byte * arg) { return this; } @@ -590,11 +678,6 @@ public: cleanup(); delete this; } - virtual bool set_flags_processor(byte *args) - { - this->item_flags|= *((uint8*)args); - return false; - } virtual bool is_splocal() { return 0; } /* Needed for error checking */ }; @@ -631,7 +714,7 @@ public: Item **this_item_addr(THD *thd, Item **); Item *this_const_item() const; - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void cleanup(); inline uint get_offset() @@ -704,7 +787,9 @@ protected: const char *orig_db_name; const char *orig_table_name; const char *orig_field_name; + public: + Name_resolution_context *context; const char *db_name; const char *table_name; const char *field_name; @@ -722,13 +807,16 @@ public: */ TABLE_LIST *cached_table; st_select_lex *depended_from; - Item_ident(const char *db_name_par,const char *table_name_par, - const char *field_name_par); + Item_ident(Name_resolution_context *context_arg, + const char *db_name_arg, const char *table_name_arg, + const char *field_name_arg); Item_ident(THD *thd, Item_ident *item); const char *full_name() const; void cleanup(); bool remove_dependence_processor(byte * arg); void print(String *str); + virtual bool change_context_processor(byte *cntx) + { context= (Name_resolution_context *)cntx; return FALSE; } }; class Item_equal; @@ -750,12 +838,9 @@ public: /* field need any privileges (for VIEW creation) */ bool any_privileges; - Item_field(const char *db_par,const char *table_name_par, - const char *field_name_par) - :Item_ident(db_par,table_name_par,field_name_par), - field(0), result_field(0), item_equal(0), no_const_subst(0), - have_privileges(0), any_privileges(0) - { collation.set(DERIVATION_IMPLICIT); } + Item_field(Name_resolution_context *context_arg, + const char *db_arg,const char *table_name_arg, + const char *field_name_arg); /* Constructor needed to process subselect with temporary tables (see Item) */ @@ -765,7 +850,7 @@ public: and database names will live as long as Item_field (this is important in prepared statements). */ - Item_field(THD *thd, Field *field); + Item_field(THD *thd, Name_resolution_context *context_arg, Field *field); /* If this constructor is used, fix_fields() won't work, because db_name, table_name and column_name are unknown. It's necessary to call @@ -785,7 +870,7 @@ public: bool val_bool_result(); bool send(Protocol *protocol, String *str_arg); void reset_field(Field *f); - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void make_field(Send_field *tmp_field); int save_in_field(Field *field,bool no_conversions); void save_org_in_field(Field *field); @@ -946,7 +1031,7 @@ public: bool get_time(TIME *tm); bool get_date(TIME *tm, uint fuzzydate); int save_in_field(Field *field, bool no_conversions); - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void set_null(); void set_int(longlong i, uint32 max_length_arg); @@ -1317,9 +1402,11 @@ protected: public: Field *result_field; /* Save result here */ Item **ref; - Item_ref(const char *db_par, const char *table_name_par, - const char *field_name_par) - :Item_ident(db_par, table_name_par, field_name_par), result_field(0), ref(0) {} + Item_ref(Name_resolution_context *context_arg, + const char *db_arg, const char *table_name_arg, + const char *field_name_arg) + :Item_ident(context_arg, db_arg, table_name_arg, field_name_arg), + result_field(0), ref(0) {} /* This constructor is used in two scenarios: A) *item = NULL @@ -1334,13 +1421,18 @@ public: TODO we probably fix a superset of problems like in BUG#6658. Check this with Bar, and if we have a more broader set of problems like this. */ - Item_ref(Item **item, const char *table_name_par, const char *field_name_par); + Item_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, const char *field_name_arg); /* Constructor need to process subselect with temporary tables (see Item) */ - Item_ref(THD *thd, Item_ref *item) :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {} + Item_ref(THD *thd, Item_ref *item) + :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {} enum Type type() const { return REF_ITEM; } bool eq(const Item *item, bool binary_cmp) const - { return ref && (*ref)->eq(item, binary_cmp); } + { + Item *it= ((Item *) item)->real_item(); + return ref && (*ref)->eq(it, binary_cmp); + } double val_real(); longlong val_int(); my_decimal *val_decimal(my_decimal *); @@ -1354,8 +1446,8 @@ public: my_decimal *val_decimal_result(my_decimal *); bool val_bool_result(); bool send(Protocol *prot, String *tmp); - void make_field(Send_field *field) { (*ref)->make_field(field); } - bool fix_fields(THD *, struct st_table_list *, Item **); + void make_field(Send_field *field); + bool fix_fields(THD *, Item **); int save_in_field(Field *field, bool no_conversions); void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); } enum Item_result result_type () const { return (*ref)->result_type(); } @@ -1380,6 +1472,8 @@ public: { return (*ref)->walk(processor, arg); } void print(String *str); void cleanup(); + Item_field *filed_for_view_update() + { return (*ref)->filed_for_view_update(); } }; @@ -1390,9 +1484,10 @@ public: class Item_direct_ref :public Item_ref { public: - Item_direct_ref(Item **item, const char *table_name_par, - const char *field_name_par) - :Item_ref(item, table_name_par, field_name_par) {} + Item_direct_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, + const char *field_name_arg) + :Item_ref(context_arg, item, table_name_arg, field_name_arg) {} /* Constructor need to process subselect with temporary tables (see Item) */ Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {} @@ -1405,6 +1500,24 @@ public: bool get_date(TIME *ltime,uint fuzzydate); }; +/* + Class for view fields, the same as Item_direct_ref, but call fix_fields + of reference if it is not called yet +*/ +class Item_direct_view_ref :public Item_direct_ref +{ +public: + Item_direct_view_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, + const char *field_name_arg) + :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg) {} + /* Constructor need to process subselect with temporary tables (see Item) */ + Item_direct_view_ref(THD *thd, Item_direct_ref *item) + :Item_direct_ref(thd, item) {} + + bool fix_fields(THD *, Item **); +}; + class Item_in_subselect; @@ -1413,9 +1526,11 @@ class Item_ref_null_helper: public Item_ref protected: Item_in_subselect* owner; public: - Item_ref_null_helper(Item_in_subselect* master, Item **item, - const char *table_name_par, const char *field_name_par): - Item_ref(item, table_name_par, field_name_par), owner(master) {} + Item_ref_null_helper(Name_resolution_context *context_arg, + Item_in_subselect* master, Item **item, + const char *table_name_arg, const char *field_name_arg) + :Item_ref(context_arg, item, table_name_arg, field_name_arg), + owner(master) {} double val_real(); longlong val_int(); String* val_str(String* s); @@ -1429,10 +1544,11 @@ class Item_null_helper :public Item_ref_null_helper { Item *store; public: - Item_null_helper(Item_in_subselect* master, Item *item, - const char *table_name_par, const char *field_name_par) - :Item_ref_null_helper(master, (store= 0, &store), table_name_par, - field_name_par), + Item_null_helper(Name_resolution_context *context_arg, + Item_in_subselect* master, Item *item, + const char *table_name_arg, const char *field_name_arg) + :Item_ref_null_helper(context_arg, master, (store= 0, &store), + table_name_arg, field_name_arg), store(item) { ref= &store; } void print(String *str); @@ -1583,13 +1699,17 @@ class Item_default_value : public Item_field { public: Item *arg; - Item_default_value() : - Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(NULL) {} - Item_default_value(Item *a) : - Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {} + Item_default_value(Name_resolution_context *context_arg) + :Item_field(context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(NULL) {} + Item_default_value(Name_resolution_context *context_arg, Item *a) + :Item_field(context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(a) {} enum Type type() const { return DEFAULT_VALUE_ITEM; } bool eq(const Item *item, bool binary_cmp) const; - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void print(String *str); int save_in_field(Field *field_arg, bool no_conversions); table_map used_tables() const { return (table_map)0L; } @@ -1618,10 +1738,12 @@ class Item_insert_value : public Item_field { public: Item *arg; - Item_insert_value(Item *a) : - Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {} + Item_insert_value(Name_resolution_context *context_arg, Item *a) + :Item_field(context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(a) {} bool eq(const Item *item, bool binary_cmp) const; - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void print(String *str); int save_in_field(Field *field_arg, bool no_conversions) { @@ -1683,15 +1805,17 @@ public: /* Pointer to Table_trigger_list object for table of this trigger */ Table_triggers_list *triggers; - Item_trigger_field(row_version_type row_ver_par, - const char *field_name_par): - Item_field((const char *)NULL, (const char *)NULL, field_name_par), - row_version(row_ver_par), field_idx((uint)-1) + Item_trigger_field(Name_resolution_context *context_arg, + row_version_type row_ver_arg, + const char *field_name_arg) + :Item_field(context_arg, + (const char *)NULL, (const char *)NULL, field_name_arg), + row_version(row_ver_arg), field_idx((uint)-1) {} void setup_field(THD *thd, TABLE *table); enum Type type() const { return TRIGGER_FIELD_ITEM; } bool eq(const Item *item, bool binary_cmp) const; - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void print(String *str); table_map used_tables() const { return (table_map)0L; } void cleanup(); @@ -1880,7 +2004,7 @@ public: Item_type_holder(THD*, Item*); Item_result result_type() const; - virtual enum_field_types field_type() const { return fld_type; }; + enum_field_types field_type() const { return fld_type; }; enum Type type() const { return TYPE_HOLDER; } double val_real(); longlong val_int(); @@ -1892,6 +2016,7 @@ public: static enum_field_types get_real_type(Item *); }; + class st_select_lex; void mark_select_range_as_dependent(THD *thd, st_select_lex *last_select, diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 58a7f3316d7..5ed857319be 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -275,7 +275,7 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) owner= item; func= comparator_matrix[type] [test(owner->functype() == Item_func::EQUAL_FUNC)]; - switch(type) { + switch (type) { case ROW_RESULT: { uint n= (*a)->cols(); @@ -638,11 +638,9 @@ int Arg_comparator::compare_e_row() } -bool Item_in_optimizer::fix_left(THD *thd, - struct st_table_list *tables, - Item **ref) +bool Item_in_optimizer::fix_left(THD *thd, Item **ref) { - if (!args[0]->fixed && args[0]->fix_fields(thd, tables, args) || + if (!args[0]->fixed && args[0]->fix_fields(thd, args) || !cache && !(cache= Item_cache::get_cache(args[0]->result_type()))) return 1; @@ -679,16 +677,15 @@ bool Item_in_optimizer::fix_left(THD *thd, } -bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, - Item ** ref) +bool Item_in_optimizer::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - if (fix_left(thd, tables, ref)) + if (fix_left(thd, ref)) return TRUE; if (args[0]->maybe_null) maybe_null=1; - if (!args[1]->fixed && args[1]->fix_fields(thd, tables, args+1)) + if (!args[1]->fixed && args[1]->fix_fields(thd, args+1)) return TRUE; Item_in_subselect * sub= (Item_in_subselect *)args[1]; if (args[0]->cols() != sub->engine->cols()) @@ -1581,6 +1578,25 @@ my_decimal *Item_func_case::val_decimal(my_decimal *decimal_value) } +bool Item_func_case::fix_fields(THD *thd, Item **ref) +{ + /* + buff should match stack usage from + Item_func_case::val_int() -> Item_func_case::find_item() + */ + char buff[MAX_FIELD_WIDTH*2+sizeof(String)*2+sizeof(String*)*2+sizeof(double)*2+sizeof(longlong)*2]; + bool res= Item_func::fix_fields(thd, ref); + /* + Call check_stack_overrun after fix_fields to be sure that stack variable + is not optimized away + */ + if (check_stack_overrun(thd, STACK_MIN_SIZE, buff)) + return TRUE; // Fatal error flag is set! + return res; +} + + + void Item_func_case::fix_length_and_dec() { Item **agg; @@ -2312,7 +2328,7 @@ void Item_cond::copy_andor_arguments(THD *thd, Item_cond *item) bool -Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_cond::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); List_iterator<Item> li(list); @@ -2360,7 +2376,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) // item can be substituted in fix_fields if ((!item->fixed && - item->fix_fields(thd, tables, li.ref())) || + item->fix_fields(thd, li.ref())) || (item= *li.ref())->check_cols(1)) return TRUE; /* purecov: inspected */ used_tables_cache|= item->used_tables(); @@ -2747,11 +2763,11 @@ Item_func::optimize_type Item_func_like::select_optimize() const } -bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) +bool Item_func_like::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - if (Item_bool_func2::fix_fields(thd, tlist, ref) || - escape_item->fix_fields(thd, tlist, &escape_item)) + if (Item_bool_func2::fix_fields(thd, ref) || + escape_item->fix_fields(thd, &escape_item)) return TRUE; if (!escape_item->const_during_execution()) @@ -2815,13 +2831,13 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) #ifdef USE_REGEX bool -Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_func_regex::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); if ((!args[0]->fixed && - args[0]->fix_fields(thd, tables, args)) || args[0]->check_cols(1) || + args[0]->fix_fields(thd, args)) || args[0]->check_cols(1) || (!args[1]->fixed && - args[1]->fix_fields(thd,tables, args + 1)) || args[1]->check_cols(1)) + args[1]->fix_fields(thd, args + 1)) || args[1]->check_cols(1)) return TRUE; /* purecov: inspected */ with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func; max_length= 1; @@ -3481,7 +3497,7 @@ void Item_equal::sort(Item_field_cmpfunc cmp, void *arg) } while (swap); } -bool Item_equal::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +bool Item_equal::fix_fields(THD *thd, Item **ref) { List_iterator_fast<Item_field> li(fields); Item *item; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 7a22e76b217..75c8411b844 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -108,8 +108,8 @@ public: Item_in_optimizer(Item *a, Item_in_subselect *b): Item_bool_func(a, my_reinterpret_cast(Item *)(b)), cache(0), save_cache(0) {} - bool fix_fields(THD *, struct st_table_list *, Item **); - bool fix_left(THD *thd, struct st_table_list *tables, Item **ref); + bool fix_fields(THD *, Item **); + bool fix_left(THD *thd, Item **ref); bool is_null(); /* Item_in_optimizer item is special boolean function. On value request @@ -502,11 +502,11 @@ public: String *val_str(String *str); my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return cached_result_type; } - bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); args[0]->top_level_item(); - return Item_func::fix_fields(thd, tlist, ref); + return Item_func::fix_fields(thd, ref); } void fix_length_and_dec(); uint decimal_precision() const; @@ -566,6 +566,7 @@ public: longlong val_int(); String *val_str(String *); my_decimal *val_decimal(my_decimal *); + bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); uint decimal_precision() const; table_map not_null_tables() const { return 0; } @@ -849,6 +850,12 @@ class Item_func_in :public Item_int_func bool nulls_in_row(); bool is_bool_func() { return 1; } CHARSET_INFO *compare_collation() { return cmp_collation.collation; } + /* + IN() protect from NULL only first argument, if construction like + "expression IN ()" will be allowed, we will need to check number of + argument here, because "NOT(NULL IN ())" is TRUE. + */ + table_map not_null_tables() const { return args[0]->not_null_tables(); } }; /* Functions used by where clause */ @@ -961,7 +968,7 @@ public: optimize_type select_optimize() const; cond_result eq_cmp_result() const { return COND_TRUE; } const char *func_name() const { return "like"; } - bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); + bool fix_fields(THD *thd, Item **ref); }; #ifdef USE_REGEX @@ -980,7 +987,7 @@ public: regex_compiled(0),regex_is_const(0) {} void cleanup(); longlong val_int(); - bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); + bool fix_fields(THD *thd, Item **ref); const char *func_name() const { return "regexp"; } void print(String *str) { print_op(str); } CHARSET_INFO *compare_collation() { return cmp_collation.collation; } @@ -1024,7 +1031,7 @@ public: :Item_bool_func(), list(nlist), abort_on_null(0) {} bool add(Item *item) { return list.push_back(item); } void add_at_head(List<Item> *nlist) { list.prepand(nlist); } - bool fix_fields(THD *, struct st_table_list *, Item **ref); + bool fix_fields(THD *, Item **ref); enum Type type() const { return COND_ITEM; } List<Item>* argument_list() { return &list; } @@ -1033,7 +1040,7 @@ public: void print(String *str); void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields); friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, - COND **conds); + COND **conds); void top_level_item() { abort_on_null=1; } void copy_andor_arguments(THD *thd, Item_cond *item); bool walk(Item_processor processor, byte *arg); @@ -1141,7 +1148,7 @@ public: void sort(Item_field_cmpfunc cmp, void *arg); friend class Item_equal_iterator; void fix_length_and_dec(); - bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); void update_used_tables(); bool walk(Item_processor processor, byte *arg); Item *transform(Item_transformer transformer, byte *arg); diff --git a/sql/item_func.cc b/sql/item_func.cc index 1dbf28b67cb..16296266234 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -194,11 +194,10 @@ bool Item_func::agg_arg_charsets(DTCollation &coll, ((Item_field *)(*arg))->no_const_subst= 1; /* We do not check conv->fixed, because Item_func_conv_charset which can - be return by safe_charset_converter can't be fixed at creation, also - it do not need tables (second argument) for name resolving + be return by safe_charset_converter can't be fixed at creation */ *arg= conv; - conv->fix_fields(thd, 0, arg); + conv->fix_fields(thd, arg); } if (arena) thd->restore_backup_item_arena(arena, &backup); @@ -261,7 +260,6 @@ Item_func::Item_func(THD *thd, Item_func *item) SYNOPSIS: fix_fields() thd Thread object - tables List of all open tables involved in the query ref Pointer to where this object is used. This reference is used if we want to replace this object with another one (for example in the summary functions). @@ -290,7 +288,7 @@ Item_func::Item_func(THD *thd, Item_func *item) */ bool -Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_func::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); Item **arg,**arg_end; @@ -312,7 +310,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) We can't yet set item to *arg as fix_fields may change *arg We shouldn't call fix_fields() twice, so check 'fixed' field first */ - if ((!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg))) + if ((!(*arg)->fixed && (*arg)->fix_fields(thd, arg))) return TRUE; /* purecov: inspected */ item= *arg; @@ -1882,8 +1880,7 @@ void Item_func_round::fix_length_and_dec() return; } - switch (args[0]->result_type()) - { + switch (args[0]->result_type()) { case REAL_RESULT: case STRING_RESULT: hybrid_type= REAL_RESULT; @@ -1891,16 +1888,17 @@ void Item_func_round::fix_length_and_dec() max_length= float_length(decimals); break; case INT_RESULT: - if ((decimals_to_set==0) && + if (!decimals_to_set && (truncate || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS))) { + int length_can_increase= test(!truncate && (args[1]->val_int() < 0)); + max_length= args[0]->max_length + length_can_increase; /* Here we can keep INT_RESULT */ hybrid_type= INT_RESULT; - int length_can_increase= !truncate && (args[1]->val_int() < 0); - max_length= args[0]->max_length + length_can_increase; decimals= 0; break; } + /* fall through */ case DECIMAL_RESULT: { hybrid_type= DECIMAL_RESULT; @@ -2010,10 +2008,9 @@ my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value) } -bool Item_func_rand::fix_fields(THD *thd, struct st_table_list *tables, - Item **ref) +bool Item_func_rand::fix_fields(THD *thd,Item **ref) { - if (Item_real_func::fix_fields(thd, tables, ref)) + if (Item_real_func::fix_fields(thd, ref)) return TRUE; used_tables_cache|= RAND_TABLE_BIT; if (arg_count) @@ -2604,7 +2601,7 @@ void udf_handler::cleanup() bool -udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, +udf_handler::fix_fields(THD *thd, Item_result_field *func, uint arg_count, Item **arguments) { #ifndef EMBEDDED_LIBRARY // Avoid compiler warning @@ -2646,7 +2643,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, arg++,i++) { if (!(*arg)->fixed && - (*arg)->fix_fields(thd, tables, arg)) + (*arg)->fix_fields(thd, arg)) DBUG_RETURN(1); // we can't assign 'item' before, because fix_fields() can change arg Item *item= *arg; @@ -3458,12 +3455,11 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, SELECT @a:= ). */ -bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables, - Item **ref) +bool Item_func_set_user_var::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); /* fix_fields will call Item_func_set_user_var::fix_length_and_dec */ - if (Item_func::fix_fields(thd, tables, ref) || + if (Item_func::fix_fields(thd, ref) || !(entry= get_variable(&thd->user_vars, name, 1))) return TRUE; /* @@ -4127,11 +4123,10 @@ bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const } -bool Item_user_var_as_out_param::fix_fields(THD *thd, TABLE_LIST *tables, - Item **ref) +bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - if (Item::fix_fields(thd, tables, ref) || + if (Item::fix_fields(thd, ref) || !(entry= get_variable(&thd->user_vars, name, 1))) return TRUE; entry->type= STRING_RESULT; @@ -4314,7 +4309,7 @@ void Item_func_match::init_search(bool no_order) } -bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) +bool Item_func_match::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); Item *item; @@ -4329,7 +4324,7 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) modifications to find_best and auto_close as complement to auto_init code above. */ - if (Item_func::fix_fields(thd, tlist, ref) || + if (Item_func::fix_fields(thd, ref) || !args[0]->const_during_execution()) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"AGAINST"); @@ -4451,7 +4446,8 @@ err: bool Item_func_match::eq(const Item *item, bool binary_cmp) const { - if (item->type() != FUNC_ITEM || ((Item_func*)item)->functype() != FT_FUNC || + if (item->type() != FUNC_ITEM || + ((Item_func*)item)->functype() != FT_FUNC || flags != ((Item_func_match*)item)->flags) return 0; @@ -4690,8 +4686,9 @@ longlong Item_func_row_count::val_int() } -Item_func_sp::Item_func_sp(sp_name *name) - :Item_func(), m_name(name), m_sp(NULL), result_field(NULL) +Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, sp_name *name) + :Item_func(), context(context_arg), m_name(name), m_sp(NULL), + result_field(NULL) { maybe_null= 1; m_name->init_qname(current_thd); @@ -4699,8 +4696,10 @@ Item_func_sp::Item_func_sp(sp_name *name) } -Item_func_sp::Item_func_sp(sp_name *name, List<Item> &list) - :Item_func(list), m_name(name), m_sp(NULL), result_field(NULL) +Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, + sp_name *name, List<Item> &list) + :Item_func(list), context(context_arg), m_name(name), m_sp(NULL), + result_field(NULL) { maybe_null= 1; m_name->init_qname(current_thd); @@ -4809,7 +4808,7 @@ Item_func_sp::execute(Item **itp) ulong old_client_capabilites; int res= -1; bool save_in_sub_stmt= thd->transaction.in_sub_stmt; - my_bool nsok; + my_bool save_no_send_ok; #ifndef NO_EMBEDDED_ACCESS_CHECKS st_sp_security_context save_ctx; #endif @@ -4824,7 +4823,7 @@ Item_func_sp::execute(Item **itp) thd->client_capabilities &= ~CLIENT_MULTI_RESULTS; #ifndef EMBEDDED_LIBRARY - nsok= thd->net.no_send_ok; + save_no_send_ok= thd->net.no_send_ok; thd->net.no_send_ok= TRUE; #endif @@ -4836,7 +4835,7 @@ Item_func_sp::execute(Item **itp) if (save_ctx.changed && check_routine_access(thd, EXECUTE_ACL, m_sp->m_db.str, m_sp->m_name.str, 0, 0)) - goto error_check; + goto error_check_ctx; #endif /* Like for SPs, we don't binlog the substatements. If the statement which @@ -4859,8 +4858,8 @@ Item_func_sp::execute(Item **itp) ER_FAILED_ROUTINE_BREAK_BINLOG, ER(ER_FAILED_ROUTINE_BREAK_BINLOG)); -error_check_ctx: #ifndef NO_EMBEDDED_ACCESS_CHECKS +error_check_ctx: sp_restore_security_context(thd, m_sp, &save_ctx); #endif @@ -4868,7 +4867,7 @@ error_check_ctx: error_check: #ifndef EMBEDDED_LIBRARY - thd->net.no_send_ok= nsok; + thd->net.no_send_ok= save_no_send_ok; #endif thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS; @@ -4944,7 +4943,10 @@ Item_func_sp::fix_length_and_dec() } if (!(field= sp_result_field())) + { + context->process_error(current_thd); DBUG_VOID_RETURN; + } decimals= field->decimals(); max_length= field->field_length; maybe_null= 1; diff --git a/sql/item_func.h b/sql/item_func.h index e0f14ceac75..f6bc35e1617 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -116,7 +116,7 @@ public: Item_func(List<Item> &list); // Constructor used for Item_cond_and/or (see Item comment) Item_func(THD *thd, Item_func *item); - bool fix_fields(THD *,struct st_table_list *, Item **ref); + bool fix_fields(THD *, Item **ref); table_map used_tables() const; table_map not_null_tables() const; void update_used_tables(); @@ -630,7 +630,7 @@ public: const char *func_name() const { return "rand"; } bool const_item() const { return 0; } void update_used_tables(); - bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); }; @@ -885,14 +885,15 @@ protected: udf_handler udf; public: - Item_udf_func(udf_func *udf_arg) :Item_func(), udf(udf_arg) {} + Item_udf_func(udf_func *udf_arg) + :Item_func(), udf(udf_arg) {} Item_udf_func(udf_func *udf_arg, List<Item> &list) :Item_func(list), udf(udf_arg) {} const char *func_name() const { return udf.name(); } - bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - bool res= udf.fix_fields(thd, tables, this, arg_count, args); + bool res= udf.fix_fields(thd, this, arg_count, args); used_tables_cache= udf.used_tables_cache; const_item_cache= udf.const_item_cache; fixed= 1; @@ -907,9 +908,11 @@ public: class Item_func_udf_float :public Item_udf_func { public: - Item_func_udf_float(udf_func *udf_arg) :Item_udf_func(udf_arg) {} - Item_func_udf_float(udf_func *udf_arg, List<Item> &list) - :Item_udf_func(udf_arg,list) {} + Item_func_udf_float(udf_func *udf_arg) + :Item_udf_func(udf_arg) {} + Item_func_udf_float(udf_func *udf_arg, + List<Item> &list) + :Item_udf_func(udf_arg, list) {} longlong val_int() { DBUG_ASSERT(fixed == 1); @@ -932,9 +935,11 @@ class Item_func_udf_float :public Item_udf_func class Item_func_udf_int :public Item_udf_func { public: - Item_func_udf_int(udf_func *udf_arg) :Item_udf_func(udf_arg) {} - Item_func_udf_int(udf_func *udf_arg, List<Item> &list) - :Item_udf_func(udf_arg,list) {} + Item_func_udf_int(udf_func *udf_arg) + :Item_udf_func(udf_arg) {} + Item_func_udf_int(udf_func *udf_arg, + List<Item> &list) + :Item_udf_func(udf_arg, list) {} longlong val_int(); double val_real() { return (double) Item_func_udf_int::val_int(); } String *val_str(String *str); @@ -946,9 +951,10 @@ public: class Item_func_udf_decimal :public Item_udf_func { public: - Item_func_udf_decimal(udf_func *udf_arg) :Item_udf_func(udf_arg) {} + Item_func_udf_decimal(udf_func *udf_arg) + :Item_udf_func(udf_arg) {} Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list) - :Item_udf_func(udf_arg,list) {} + :Item_udf_func(udf_arg, list) {} longlong val_int(); double val_real(); my_decimal *val_decimal(my_decimal *); @@ -961,9 +967,10 @@ public: class Item_func_udf_str :public Item_udf_func { public: - Item_func_udf_str(udf_func *udf_arg) :Item_udf_func(udf_arg) {} + Item_func_udf_str(udf_func *udf_arg) + :Item_udf_func(udf_arg) {} Item_func_udf_str(udf_func *udf_arg, List<Item> &list) - :Item_udf_func(udf_arg,list) {} + :Item_udf_func(udf_arg, list) {} String *val_str(String *); double val_real() { @@ -998,8 +1005,10 @@ public: class Item_func_udf_float :public Item_real_func { public: - Item_func_udf_float(udf_func *udf_arg) :Item_real_func() {} - Item_func_udf_float(udf_func *udf_arg, List<Item> &list) :Item_real_func(list) {} + Item_func_udf_float(udf_func *udf_arg) + :Item_real_func() {} + Item_func_udf_float(udf_func *udf_arg, List<Item> &list) + :Item_real_func(list) {} double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } }; @@ -1007,8 +1016,10 @@ class Item_func_udf_float :public Item_real_func class Item_func_udf_int :public Item_int_func { public: - Item_func_udf_int(udf_func *udf_arg) :Item_int_func() {} - Item_func_udf_int(udf_func *udf_arg, List<Item> &list) :Item_int_func(list) {} + Item_func_udf_int(udf_func *udf_arg) + :Item_int_func() {} + Item_func_udf_int(udf_func *udf_arg, List<Item> &list) + :Item_int_func(list) {} longlong val_int() { DBUG_ASSERT(fixed == 1); return 0; } }; @@ -1016,8 +1027,10 @@ public: class Item_func_udf_decimal :public Item_int_func { public: - Item_func_udf_decimal(udf_func *udf_arg) :Item_int_func() {} - Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list) :Item_int_func(list) {} + Item_func_udf_decimal(udf_func *udf_arg) + :Item_int_func() {} + Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list) + :Item_int_func(list) {} my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; } }; @@ -1025,8 +1038,10 @@ public: class Item_func_udf_str :public Item_func { public: - Item_func_udf_str(udf_func *udf_arg) :Item_func() {} - Item_func_udf_str(udf_func *udf_arg, List<Item> &list) :Item_func(list) {} + Item_func_udf_str(udf_func *udf_arg) + :Item_func() {} + Item_func_udf_str(udf_func *udf_arg, List<Item> &list) + :Item_func(list) {} String *val_str(String *) { DBUG_ASSERT(fixed == 1); null_value=1; return 0; } double val_real() { DBUG_ASSERT(fixed == 1); null_value= 1; return 0.0; } @@ -1116,7 +1131,7 @@ public: bool check(); bool update(); enum Item_result result_type () const { return cached_result_type; } - bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); void print(String *str); void print_as_stmt(String *str); @@ -1176,7 +1191,7 @@ public: String *val_str(String *str); my_decimal *val_decimal(my_decimal *decimal_buffer); /* fix_fields() binds variable name with its entry structure */ - bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); void print(String *str); void set_null_value(CHARSET_INFO* cs); void set_value(const char *str, uint length, CHARSET_INFO* cs); @@ -1230,7 +1245,7 @@ public: const char *func_name() const { return "match"; } void update_used_tables() {} table_map not_null_tables() const { return 0; } - bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); + bool fix_fields(THD *thd, Item **ref); bool eq(const Item *, bool binary_cmp) const; /* The following should be safe, even if we compare doubles */ longlong val_int() { DBUG_ASSERT(fixed == 1); return val_real() != 0.0; } @@ -1302,6 +1317,7 @@ class sp_name; class Item_func_sp :public Item_func { private: + Name_resolution_context *context; sp_name *m_name; mutable sp_head *m_sp; TABLE *dummy_table; @@ -1314,9 +1330,10 @@ private: public: - Item_func_sp(sp_name *name); + Item_func_sp(Name_resolution_context *context_arg, sp_name *name); - Item_func_sp(sp_name *name, List<Item> &list); + Item_func_sp(Name_resolution_context *context_arg, + sp_name *name, List<Item> &list); virtual ~Item_func_sp() {} @@ -1361,6 +1378,9 @@ public: return result_field->val_str(str); } + virtual bool change_context_processor(byte *cntx) + { context= (Name_resolution_context *)cntx; return FALSE; } + void fix_length_and_dec(); }; diff --git a/sql/item_row.cc b/sql/item_row.cc index 0c8baa332ca..9362518e6ef 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -53,7 +53,7 @@ void Item_row::illegal_method_call(const char *method) DBUG_VOID_RETURN; } -bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref) +bool Item_row::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); null_value= 0; @@ -61,7 +61,7 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref) Item **arg, **arg_end; for (arg= items, arg_end= items+arg_count; arg != arg_end ; arg++) { - if ((*arg)->fix_fields(thd, tabl, arg)) + if ((*arg)->fix_fields(thd, arg)) return TRUE; // we can't assign 'item' before, because fix_fields() can change arg Item *item= *arg; diff --git a/sql/item_row.h b/sql/item_row.h index e6b23eebb49..6fbe7436b72 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -61,7 +61,7 @@ public: illegal_method_call((const char*)"val_decimal"); return 0; }; - bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields); table_map used_tables() const { return used_tables_cache; }; bool const_item() const { return const_item_cache; }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 06239de1f99..1ad65fb6208 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -371,8 +371,8 @@ String *Item_func_des_encrypt::val_str(String *str) uint key_number, res_length, tail; String *res= args[0]->val_str(str); - if ((null_value=args[0]->null_value)) - goto error; + if ((null_value= args[0]->null_value)) + return 0; // ENCRYPT(NULL) == NULL if ((res_length=res->length()) == 0) return &my_empty_string; @@ -461,10 +461,10 @@ String *Item_func_des_decrypt::val_str(String *str) struct st_des_keyblock keyblock; struct st_des_keyschedule keyschedule; String *res= args[0]->val_str(str); - uint length=res->length(),tail; + uint length= 0, tail; if ((null_value=args[0]->null_value)) - goto error; + return 0; length=res->length(); if (length < 9 || (length % 8) != 1 || !((*res)[0] & 128)) return res; // Skip decryption if not encrypted diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index c4beb3b08cb..d85210984d9 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -95,6 +95,7 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "concat_ws"; } + table_map not_null_tables() const { return 0; } }; class Item_func_reverse :public Item_str_func @@ -415,12 +416,12 @@ class Item_func_make_set :public Item_str_func public: Item_func_make_set(Item *a,List<Item> &list) :Item_str_func(list),item(a) {} String *val_str(String *str); - bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - return ((!item->fixed && item->fix_fields(thd, tlist, &item)) || + return ((!item->fixed && item->fix_fields(thd, &item)) || item->check_cols(1) || - Item_func::fix_fields(thd, tlist, ref)); + Item_func::fix_fields(thd, ref)); } void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields); void fix_length_and_dec(); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index c7587686ecd..ad1c9977e5b 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -130,7 +130,7 @@ Item_subselect::select_transformer(JOIN *join) } -bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) +bool Item_subselect::fix_fields(THD *thd_param, Item **ref) { char const *save_where= thd_param->where; bool res; @@ -165,7 +165,7 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) substitution= 0; thd->where= "checking transformed subquery"; if (!(*ref)->fixed) - ret= (*ref)->fix_fields(thd, tables, ref); + ret= (*ref)->fix_fields(thd, ref); thd->where= save_where; return ret; } @@ -833,7 +833,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, reference, also Item_sum_(max|min) can't be fixed after creation, so we do not check item->fixed */ - if (item->fix_fields(thd, join->tables_list, 0)) + if (item->fix_fields(thd, 0)) DBUG_RETURN(RES_ERROR); /* we added aggregate function => we have to change statistic */ count_field_types(&join->tmp_table_param, join->all_fields, 0); @@ -862,7 +862,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, thd->lex->current_select= up= current->return_after_parsing(); //optimizer never use Item **ref => we can pass 0 as parameter - if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0)) + if (!optimizer || optimizer->fix_left(thd, 0)) { thd->lex->current_select= current; DBUG_RETURN(RES_ERROR); @@ -873,7 +873,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, As far as Item_ref_in_optimizer do not substitute itself on fix_fields we can use same item for all selects. */ - expr= new Item_direct_ref((Item**)optimizer->get_cache(), + expr= new Item_direct_ref(&select_lex->context, + (Item**)optimizer->get_cache(), (char *)"<no matter>", (char *)in_left_expr_name); @@ -893,7 +894,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, { bool tmp; Item *item= func->create(expr, - new Item_ref_null_helper(this, + new Item_ref_null_helper(&select_lex->context, + this, select_lex-> ref_pointer_array, (char *)"<ref>", @@ -913,7 +915,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, we do not check join->having->fixed, because Item_and (from and_items) or comparison function (from func->create) can't be fixed after creation */ - tmp= join->having->fix_fields(thd, join->tables_list, 0); + tmp= join->having->fix_fields(thd, 0); select_lex->having_fix_field= 0; if (tmp) DBUG_RETURN(RES_ERROR); @@ -949,7 +951,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, and_items) or comparison function (from func->create) can't be fixed after creation */ - tmp= join->having->fix_fields(thd, join->tables_list, 0); + tmp= join->having->fix_fields(thd, 0); select_lex->having_fix_field= 0; if (tmp) DBUG_RETURN(RES_ERROR); @@ -971,7 +973,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, we do not check join->conds->fixed, because Item_and can't be fixed after creation */ - if (join->conds->fix_fields(thd, join->tables_list, 0)) + if (join->conds->fix_fields(thd, 0)) DBUG_RETURN(RES_ERROR); } else @@ -983,22 +985,23 @@ Item_in_subselect::single_value_transformer(JOIN *join, comparison functions can't be changed during fix_fields() we can assign select_lex->having here, and pass 0 as last argument (reference) to fix_fields() - */ - item= func->create(expr, - new Item_null_helper(this, item, - (char *)"<no matter>", - (char *)"<result>")); + */ + item= func->create(expr, + new Item_null_helper(&select_lex->context, + this, item, + (char *)"<no matter>", + (char *)"<result>")); #ifdef CORRECT_BUT_TOO_SLOW_TO_BE_USABLE if (!abort_on_null && left_expr->maybe_null) item= new Item_cond_or(new Item_func_isnull(left_expr), item); #endif - select_lex->having= join->having= item; + select_lex->having= join->having= item; select_lex->having_fix_field= 1; /* we do not check join->having->fixed, because comparison function (from func->create) can't be fixed after creation */ - tmp= join->having->fix_fields(thd, join->tables_list, 0); + tmp= join->having->fix_fields(thd, 0); select_lex->having_fix_field= 0; if (tmp) DBUG_RETURN(RES_ERROR); @@ -1048,7 +1051,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) SELECT_LEX *current= thd->lex->current_select, *up; thd->lex->current_select= up= current->return_after_parsing(); //optimizer never use Item **ref => we can pass 0 as parameter - if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0)) + if (!optimizer || optimizer->fix_left(thd, 0)) { thd->lex->current_select= current; DBUG_RETURN(RES_ERROR); @@ -1071,12 +1074,14 @@ Item_in_subselect::row_value_transformer(JOIN *join) if (select_lex->ref_pointer_array[i]-> check_cols(left_expr->el(i)->cols())) DBUG_RETURN(RES_ERROR); - Item *func= new Item_ref_null_helper(this, + Item *func= new Item_ref_null_helper(&select_lex->context, + this, select_lex->ref_pointer_array+i, (char *) "<no matter>", (char *) "<list ref>"); func= - eq_creator.create(new Item_direct_ref((*optimizer->get_cache())-> + eq_creator.create(new Item_direct_ref(&select_lex->context, + (*optimizer->get_cache())-> addr(i), (char *)"<no matter>", (char *)in_left_expr_name), @@ -1099,7 +1104,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) join->having can't be fixed after creation, so we do not check join->having->fixed */ - if (join->having->fix_fields(thd, join->tables_list, 0)) + if (join->having->fix_fields(thd, 0)) { select_lex->having_fix_field= 0; DBUG_RETURN(RES_ERROR); @@ -1118,7 +1123,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) join->conds can't be fixed after creation, so we do not check join->conds->fixed */ - if (join->conds->fix_fields(thd, join->tables_list, 0)) + if (join->conds->fix_fields(thd, 0)) DBUG_RETURN(RES_ERROR); } @@ -1189,8 +1194,7 @@ Item_in_subselect::select_in_like_transformer(JOIN *join, Comp_creator *func) thd->lex->current_select= up= current->return_after_parsing(); result= (!left_expr->fixed && - left_expr->fix_fields(thd, up->get_table_list(), - optimizer->arguments())); + left_expr->fix_fields(thd, optimizer->arguments())); /* fix_fields can change reference to left_expr, we need reassign it */ left_expr= optimizer->arguments()[0]; diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 84935429353..e05db4a00cc 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -92,7 +92,7 @@ public: val_int(); return null_value; } - bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); virtual bool exec(); virtual void fix_length_and_dec(); table_map used_tables() const; @@ -119,9 +119,9 @@ public: friend class select_subselect; friend class Item_in_optimizer; - friend bool Item_field::fix_fields(THD *, TABLE_LIST *, Item **); - friend bool Item_ref::fix_fields(THD *, TABLE_LIST *, Item **); - friend bool Item_param::fix_fields(THD *, TABLE_LIST *, Item **); + friend bool Item_field::fix_fields(THD *, Item **); + friend bool Item_ref::fix_fields(THD *, Item **); + friend bool Item_param::fix_fields(THD *, Item **); friend void mark_select_range_as_dependent(THD*, st_select_lex*, st_select_lex*, Field*, Item*, Item_ident*); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 76f94801b49..d2f1016891b 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -193,7 +193,7 @@ my_decimal *Item_sum_int::val_decimal(my_decimal *decimal_value) bool -Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_sum_num::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); @@ -208,7 +208,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) maybe_null=0; for (uint i=0 ; i < arg_count ; i++) { - if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1)) + if (args[i]->fix_fields(thd, args + i) || args[i]->check_cols(1)) return TRUE; set_if_bigger(decimals, args[i]->decimals); maybe_null |= args[i]->maybe_null; @@ -253,7 +253,7 @@ Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) } bool -Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_sum_hybrid::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); @@ -268,7 +268,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) // 'item' can be changed during fix_fields if (!item->fixed && - item->fix_fields(thd, tables, args) || + item->fix_fields(thd, args) || (item= args[0])->check_cols(1)) return TRUE; decimals=item->decimals; @@ -2766,11 +2766,12 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)), */ Item_func_group_concat:: -Item_func_group_concat(bool distinct_arg, List<Item> *select_list, +Item_func_group_concat(Name_resolution_context *context_arg, + bool distinct_arg, List<Item> *select_list, SQL_LIST *order_list, String *separator_arg) :tmp_table_param(0), warning(0), separator(separator_arg), tree(0), table(0), - order(0), tables_list(0), + order(0), context(context_arg), arg_count_order(order_list ? order_list->elements : 0), arg_count_field(select_list->elements), count_cut_values(0), @@ -2826,7 +2827,7 @@ Item_func_group_concat::Item_func_group_concat(THD *thd, tree(item->tree), table(item->table), order(item->order), - tables_list(item->tables_list), + context(item->context), arg_count_order(item->arg_count_order), arg_count_field(item->arg_count_field), count_cut_values(item->count_cut_values), @@ -2946,7 +2947,7 @@ bool Item_func_group_concat::add() bool -Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_func_group_concat::fix_fields(THD *thd, Item **ref) { uint i; /* for loop variable */ DBUG_ASSERT(fixed == 0); @@ -2968,7 +2969,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) for (i=0 ; i < arg_count ; i++) { if ((!args[i]->fixed && - args[i]->fix_fields(thd, tables, args + i)) || + args[i]->fix_fields(thd, args + i)) || args[i]->check_cols(1)) return TRUE; if (i < arg_count_field) @@ -2979,7 +2980,6 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) null_value= 1; thd->allow_sum_func= 1; max_length= thd->variables.group_concat_max_len; - tables_list= tables; fixed= 1; return FALSE; } @@ -3029,7 +3029,7 @@ bool Item_func_group_concat::setup(THD *thd) tmp table columns. */ if (arg_count_order && - setup_order(thd, args, tables_list, list, all_fields, *order)) + setup_order(thd, args, context->table_list, list, all_fields, *order)) DBUG_RETURN(TRUE); count_field_types(tmp_table_param,all_fields,0); diff --git a/sql/item_sum.h b/sql/item_sum.h index b9a90ee5de5..b02d18e9a55 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -98,7 +98,7 @@ public: */ virtual const char *func_name() const= 0; virtual Item *result_item(Field *field) - { return new Item_field(field);} + { return new Item_field(field); } table_map used_tables() const { return ~(table_map) 0; } /* Not used */ bool const_item() const { return 0; } bool is_null() { return null_value; } @@ -124,7 +124,7 @@ public: Item_sum_num(Item *a, Item* b) :Item_sum(a,b) {} Item_sum_num(List<Item> &list) :Item_sum(list) {} Item_sum_num(THD *thd, Item_sum_num *item) :Item_sum(thd, item) {} - bool fix_fields(THD *, TABLE_LIST *, Item **); + bool fix_fields(THD *, Item **); longlong val_int() { DBUG_ASSERT(fixed == 1); @@ -543,7 +543,7 @@ protected: was_values(TRUE) { collation.set(&my_charset_bin); } Item_sum_hybrid(THD *thd, Item_sum_hybrid *item); - bool fix_fields(THD *, TABLE_LIST *, Item **); + bool fix_fields(THD *, Item **); table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } @@ -660,18 +660,21 @@ protected: udf_handler udf; public: - Item_udf_sum(udf_func *udf_arg) :Item_sum(), udf(udf_arg) { quick_group=0;} - Item_udf_sum( udf_func *udf_arg, List<Item> &list ) - :Item_sum( list ), udf(udf_arg) + Item_udf_sum(udf_func *udf_arg) + :Item_sum(), udf(udf_arg) + { quick_group=0; } + Item_udf_sum(udf_func *udf_arg, List<Item> &list) + :Item_sum(list), udf(udf_arg) { quick_group=0;} Item_udf_sum(THD *thd, Item_udf_sum *item) - :Item_sum(thd, item), udf(item->udf) { udf.not_original= TRUE; } + :Item_sum(thd, item), udf(item->udf) + { udf.not_original= TRUE; } const char *func_name() const { return udf.name(); } - bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); fixed= 1; - return udf.fix_fields(thd,tables,this,this->arg_count,this->args); + return udf.fix_fields(thd, this, this->arg_count, this->args); } enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } virtual bool have_field_update(void) const { return 0; } @@ -688,9 +691,10 @@ public: class Item_sum_udf_float :public Item_udf_sum { public: - Item_sum_udf_float(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_float(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_float(udf_func *udf_arg, List<Item> &list) - :Item_udf_sum(udf_arg,list) {} + :Item_udf_sum(udf_arg, list) {} Item_sum_udf_float(THD *thd, Item_sum_udf_float *item) :Item_udf_sum(thd, item) {} longlong val_int() @@ -709,9 +713,10 @@ class Item_sum_udf_float :public Item_udf_sum class Item_sum_udf_int :public Item_udf_sum { public: - Item_sum_udf_int(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_int(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_int(udf_func *udf_arg, List<Item> &list) - :Item_udf_sum(udf_arg,list) {} + :Item_udf_sum(udf_arg, list) {} Item_sum_udf_int(THD *thd, Item_sum_udf_int *item) :Item_udf_sum(thd, item) {} longlong val_int(); @@ -728,7 +733,8 @@ public: class Item_sum_udf_str :public Item_udf_sum { public: - Item_sum_udf_str(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_str(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_str(udf_func *udf_arg, List<Item> &list) :Item_udf_sum(udf_arg,list) {} Item_sum_udf_str(THD *thd, Item_sum_udf_str *item) @@ -766,9 +772,10 @@ public: class Item_sum_udf_decimal :public Item_udf_sum { public: - Item_sum_udf_decimal(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_decimal(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list) - :Item_udf_sum(udf_arg,list) {} + :Item_udf_sum(udf_arg, list) {} Item_sum_udf_decimal(THD *thd, Item_sum_udf_decimal *item) :Item_udf_sum(thd, item) {} String *val_str(String *); @@ -785,7 +792,8 @@ public: class Item_sum_udf_float :public Item_sum_num { public: - Item_sum_udf_float(udf_func *udf_arg) :Item_sum_num() {} + Item_sum_udf_float(udf_func *udf_arg) + :Item_sum_num() {} Item_sum_udf_float(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} Item_sum_udf_float(THD *thd, Item_sum_udf_float *item) :Item_sum_num(thd, item) {} @@ -800,7 +808,8 @@ class Item_sum_udf_float :public Item_sum_num class Item_sum_udf_int :public Item_sum_num { public: - Item_sum_udf_int(udf_func *udf_arg) :Item_sum_num() {} + Item_sum_udf_int(udf_func *udf_arg) + :Item_sum_num() {} Item_sum_udf_int(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} Item_sum_udf_int(THD *thd, Item_sum_udf_int *item) :Item_sum_num(thd, item) {} @@ -816,15 +825,17 @@ public: class Item_sum_udf_decimal :public Item_sum_num { public: - Item_sum_udf_decimal(udf_func *udf_arg) :Item_sum_num() {} - Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} + Item_sum_udf_decimal(udf_func *udf_arg) + :Item_sum_num() {} + Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list) + :Item_sum_num() {} Item_sum_udf_decimal(THD *thd, Item_sum_udf_float *item) :Item_sum_num(thd, item) {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; } void clear() {} - bool add() { return 0; } + bool add() { return 0; } void update_field() {} }; @@ -832,8 +843,10 @@ class Item_sum_udf_decimal :public Item_sum_num class Item_sum_udf_str :public Item_sum_num { public: - Item_sum_udf_str(udf_func *udf_arg) :Item_sum_num() {} - Item_sum_udf_str(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} + Item_sum_udf_str(udf_func *udf_arg) + :Item_sum_num() {} + Item_sum_udf_str(udf_func *udf_arg, List<Item> &list) + :Item_sum_num() {} Item_sum_udf_str(THD *thd, Item_sum_udf_str *item) :Item_sum_num(thd, item) {} String *val_str(String *) @@ -862,7 +875,7 @@ class Item_func_group_concat : public Item_sum TREE *tree; TABLE *table; ORDER **order; - TABLE_LIST *tables_list; + Name_resolution_context *context; uint arg_count_order; // total count of ORDER BY items uint arg_count_field; // count of arguments uint count_cut_values; @@ -887,8 +900,9 @@ class Item_func_group_concat : public Item_sum Item_func_group_concat *group_concat_item); public: - Item_func_group_concat(bool is_distinct,List<Item> *is_select, - SQL_LIST *is_order,String *is_separator); + Item_func_group_concat(Name_resolution_context *context_arg, + bool is_distinct, List<Item> *is_select, + SQL_LIST *is_order, String *is_separator); Item_func_group_concat(THD *thd, Item_func_group_concat *item); ~Item_func_group_concat() {} @@ -901,7 +915,7 @@ public: bool add(); void reset_field() {} // not used void update_field() {} // not used - bool fix_fields(THD *, TABLE_LIST *, Item **); + bool fix_fields(THD *,Item **); bool setup(THD *thd); void make_unique(); double val_real() @@ -927,4 +941,6 @@ public: Item *copy_or_same(THD* thd); void no_rows_in_result() {} void print(String *str); + virtual bool change_context_processor(byte *cntx) + { context= (Name_resolution_context *)cntx; return FALSE; } }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 19386c15835..cac9613f1ad 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1753,10 +1753,10 @@ void Item_func_convert_tz::fix_length_and_dec() bool -Item_func_convert_tz::fix_fields(THD *thd_arg, TABLE_LIST *tables_arg, Item **ref) +Item_func_convert_tz::fix_fields(THD *thd_arg, Item **ref) { String str; - if (Item_date_func::fix_fields(thd_arg, tables_arg, ref)) + if (Item_date_func::fix_fields(thd_arg, ref)) return TRUE; tz_tables= thd_arg->lex->time_zone_tables_used; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index a6dd9f7da91..107d12e6da2 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -561,7 +561,7 @@ class Item_func_convert_tz :public Item_date_func double val_real() { return (double) val_int(); } String *val_str(String *str); const char *func_name() const { return "convert_tz"; } - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void fix_length_and_dec(); bool get_date(TIME *res, uint fuzzy_date); void cleanup(); diff --git a/sql/item_uniq.h b/sql/item_uniq.h index e95aa35101e..c884c454dac 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -47,7 +47,7 @@ public: bool add() { return 0; } void reset_field() {} void update_field() {} - bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); fixed= 1; diff --git a/sql/lex.h b/sql/lex.h index d0dc287775e..aa10328ced0 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -214,7 +214,9 @@ static SYMBOL symbols[] = { { "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION)}, { "GET_FORMAT", SYM(GET_FORMAT)}, { "GLOBAL", SYM(GLOBAL_SYM)}, +#ifdef SP_GOTO { "GOTO", SYM(GOTO_SYM)}, +#endif { "GRANT", SYM(GRANT)}, { "GRANTS", SYM(GRANTS)}, { "GROUP", SYM(GROUP)}, @@ -262,7 +264,10 @@ static SYMBOL symbols[] = { { "KEY", SYM(KEY_SYM)}, { "KEYS", SYM(KEYS)}, { "KILL", SYM(KILL_SYM)}, +#ifdef SP_GOTO + /* QQ This will go away when the GOTO label syntax is fixed */ { "LABEL", SYM(LABEL_SYM)}, +#endif { "LANGUAGE", SYM(LANGUAGE_SYM)}, { "LAST", SYM(LAST_SYM)}, { "LEADING", SYM(LEADING)}, diff --git a/sql/log_event.cc b/sql/log_event.cc index 8f109f00c5f..5a612791cdd 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2618,13 +2618,15 @@ void Load_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_ev #ifndef MYSQL_CLIENT void Load_log_event::set_fields(const char* affected_db, - List<Item> &field_list) + List<Item> &field_list, + Name_resolution_context *context) { uint i; const char* field = fields; for (i= 0; i < num_fields; i++) { - field_list.push_back(new Item_field(affected_db, table_name, field)); + field_list.push_back(new Item_field(context, + affected_db, table_name, field)); field+= field_lens[i] + 1; } } @@ -2789,7 +2791,8 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, ex.skip_lines = skip_lines; List<Item> field_list; - set_fields(thd->db,field_list); + thd->main_lex.select_lex.context.resolve_in_table_list_only(&tables); + set_fields(thd->db, field_list, &thd->main_lex.select_lex.context); thd->variables.pseudo_thread_id= thread_id; List<Item> set_fields; if (net) @@ -3617,7 +3620,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli) Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) */ - e.fix_fields(thd, 0, 0); + e.fix_fields(thd, 0); /* A variable can just be considered as a table with a single record and with a single column. Thus, like diff --git a/sql/log_event.h b/sql/log_event.h index b163a37e7cc..9f4681ae2c5 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -877,7 +877,8 @@ public: const char* table_name_arg, List<Item>& fields_arg, enum enum_duplicates handle_dup, bool ignore, bool using_trans); - void set_fields(const char* db, List<Item> &fields_arg); + void set_fields(const char* db, List<Item> &fields_arg, + Name_resolution_context *context); const char* get_db() { return db; } #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2add9ac9269..9a3684c3865 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -667,6 +667,7 @@ int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t); Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Item ***copy_func, Field **from_field, bool group, bool modify_item, + bool table_cant_handle_bit_fields, uint convert_blob_length); void sp_prepare_create_field(THD *thd, create_field *sql_field); int prepare_create_field(create_field *sql_field, @@ -725,7 +726,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields, List<List_item> &values, List<Item> &update_fields, List<Item> &update_values, enum_duplicates flag, bool ignore); -int check_that_all_fields_are_given_values(THD *thd, TABLE *entry); +int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, + TABLE_LIST *table_list); bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds); bool mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, SQL_LIST *order, ha_rows rows, ulong options); @@ -756,7 +758,8 @@ enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND, Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, Item **ref, find_item_error_report_type report_error, - bool check_privileges); + bool check_privileges, + bool register_tree_change); Field * find_field_in_table(THD *thd, TABLE_LIST *table_list, const char *name, const char *item_name, @@ -892,16 +895,29 @@ Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter, bool *unaliased); bool get_key_map_from_key_list(key_map *map, TABLE *table, List<String> *index_list); -bool insert_fields(THD *thd,TABLE_LIST *tables, +bool insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, const char *table_name, - List_iterator<Item> *it, bool any_privileges); -bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, + List_iterator<Item> *it, bool any_privileges); +bool setup_tables(THD *thd, Name_resolution_context *context, + TABLE_LIST *tables, Item **conds, TABLE_LIST **leaves, bool select_insert); int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, List<Item> *sum_func_list, uint wild_num); -bool setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables, +bool setup_fields(THD *thd, Item** ref_pointer_array, List<Item> &item, bool set_query_id, List<Item> *sum_func_list, bool allow_sum_func); +inline bool setup_fields_with_no_wrap(THD *thd, Item **ref_pointer_array, + List<Item> &item, bool set_query_id, + List<Item> *sum_func_list, + bool allow_sum_func) +{ + bool res; + thd->lex->select_lex.no_wrap_view_item= TRUE; + res= setup_fields(thd, ref_pointer_array, item, set_query_id, sum_func_list, + allow_sum_func); + thd->lex->select_lex.no_wrap_view_item= FALSE; + return res; +} int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds); int setup_ftfuncs(SELECT_LEX* select); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index bc4cc81506e..78d9af387da 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2992,9 +2992,7 @@ int win_main(int argc, char **argv) int main(int argc, char **argv) #endif { - DEBUGGER_OFF; - MY_INIT(argv[0]); // init my_sys library & pthreads #ifdef _CUSTOMSTARTUPCONFIG_ @@ -3006,14 +3004,15 @@ int main(int argc, char **argv) #endif #ifdef __WIN__ -/* Before performing any socket operation (like retrieving hostname */ -/* in init_common_variables we have to call WSAStartup */ - if (!opt_disable_networking) + /* + Before performing any socket operation (like retrieving hostname + in init_common_variables we have to call WSAStartup + */ { WSADATA WsaData; if (SOCKET_ERROR == WSAStartup (0x0101, &WsaData)) { - /* errors are not read yet, so we use test here */ + /* errors are not read yet, so we use english text here */ my_message(ER_WSAS_FAILED, "WSAStartup Failed", MYF(0)); unireg_abort(1); } @@ -5388,7 +5387,7 @@ The minimum value for this variable is 4096.", "Default pointer size to be used for MyISAM tables.", (gptr*) &myisam_data_pointer_size, (gptr*) &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG, - 6, 2, 8, 0, 1, 0}, + 6, 2, 7, 0, 1, 0}, {"myisam_max_extra_sort_file_size", OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, "Deprecated option", (gptr*) &global_system_variables.myisam_max_extra_sort_file_size, @@ -6360,9 +6359,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case (int) OPT_SLOW_QUERY_LOG: opt_slow_log=1; break; - case (int) OPT_LOG_SLOW_ADMIN_STATEMENTS: - opt_log_slow_admin_statements= 1; - break; case (int) OPT_SKIP_NEW: opt_specialflag|= SPECIAL_NO_NEW_FUNC; delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 3226dc9607b..c2760b08b6e 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3528,15 +3528,12 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) { /* Optimize NOT BETWEEN and NOT IN */ Item *arg= cond_func->arguments()[0]; - if (arg->type() == Item::FUNC_ITEM) - { - cond_func= (Item_func*) arg; - if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE) - DBUG_RETURN(0); - inv= TRUE; - } - else + if (arg->type() != Item::FUNC_ITEM) + DBUG_RETURN(0); + cond_func= (Item_func*) arg; + if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE) DBUG_RETURN(0); + inv= TRUE; } else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE) DBUG_RETURN(0); @@ -8178,7 +8175,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next() (have_max && have_min && (max_res == 0))); } /* - If this is a just a GROUP BY or DISTINCT without MIN or MAX and there + If this is just a GROUP BY or DISTINCT without MIN or MAX and there are equality predicates for the key parts after the group, find the first sub-group with the extended prefix. */ @@ -8581,23 +8578,21 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range() if ((result == HA_ERR_KEY_NOT_FOUND) && (cur_range->flag & EQ_RANGE)) continue; /* Check the next range. */ - else if (result) + if (result) + { /* In no key was found with this upper bound, there certainly are no keys in the ranges to the left. */ return result; - + } /* A key was found. */ if (cur_range->flag & EQ_RANGE) - return result; /* No need to perform the checks below for equal keys. */ + return 0; /* No need to perform the checks below for equal keys. */ /* Check if record belongs to the current group. */ if (key_cmp(index_info->key_part, group_prefix, real_prefix_len)) - { - result = HA_ERR_KEY_NOT_FOUND; - continue; - } + continue; // Row not found /* If there is a lower limit, check if the found key is in the range. */ if ( !(cur_range->flag & NO_MIN_RANGE) ) diff --git a/sql/protocol.cc b/sql/protocol.cc index 1c399a89a99..ade94a483a8 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -28,6 +28,7 @@ #include <stdarg.h> static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024; +static void write_eof_packet(THD *thd, NET *net); #ifndef EMBEDDED_LIBRARY bool Protocol::net_store_data(const char *from, uint length) @@ -362,43 +363,52 @@ static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */ */ void -send_eof(THD *thd, bool no_flush) +send_eof(THD *thd) { NET *net= &thd->net; DBUG_ENTER("send_eof"); if (net->vio != 0 && !net->no_send_eof) { - if (thd->client_capabilities & CLIENT_PROTOCOL_41) - { - uchar buff[5]; - /* Don't send warn count during SP execution, as the warn_list - is cleared between substatements, and mysqltest gets confused */ - uint tmp= (thd->spcont ? 0 : min(thd->total_warn_count, 65535)); - buff[0]=254; - int2store(buff+1, tmp); - /* - The following test should never be true, but it's better to do it - because if 'is_fatal_error' is set the server is not going to execute - other queries (see the if test in dispatch_command / COM_QUERY) - */ - if (thd->is_fatal_error) - thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; - int2store(buff+3, thd->server_status); - VOID(my_net_write(net,(char*) buff,5)); - VOID(net_flush(net)); - } - else - { - VOID(my_net_write(net,eof_buff,1)); - if (!no_flush) - VOID(net_flush(net)); - } + write_eof_packet(thd, net); + VOID(net_flush(net)); thd->net.no_send_error= 1; DBUG_PRINT("info", ("EOF sent, so no more error sending allowed")); } DBUG_VOID_RETURN; } + +/* + Format EOF packet according to the current protocol and + write it to the network output buffer. +*/ + +static void write_eof_packet(THD *thd, NET *net) +{ + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + uchar buff[5]; + /* + Don't send warn count during SP execution, as the warn_list + is cleared between substatements, and mysqltest gets confused + */ + uint tmp= (thd->spcont ? 0 : min(thd->total_warn_count, 65535)); + buff[0]= 254; + int2store(buff+1, tmp); + /* + The following test should never be true, but it's better to do it + because if 'is_fatal_error' is set the server is not going to execute + other queries (see the if test in dispatch_command / COM_QUERY) + */ + if (thd->is_fatal_error) + thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; + int2store(buff+3, thd->server_status); + VOID(my_net_write(net, (char*) buff, 5)); + } + else + VOID(my_net_write(net, eof_buff, 1)); +} + /* Please client to send scrambled_password in old format. SYNOPSYS @@ -640,7 +650,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags) } if (flags & SEND_EOF) - my_net_write(&thd->net, eof_buff, 1); + write_eof_packet(thd, &thd->net); DBUG_RETURN(prepare_for_send(list)); err: diff --git a/sql/protocol.h b/sql/protocol.h index 5b402cb2669..2717d2258fa 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -179,7 +179,7 @@ void net_printf_error(THD *thd, uint sql_errno, ...); void net_send_error(THD *thd, uint sql_errno=0, const char *err=0); void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, const char *info=0); -void send_eof(THD *thd, bool no_flush=0); +void send_eof(THD *thd); bool send_old_password_request(THD *thd); char *net_store_length(char *packet,uint length); char *net_store_data(char *to,const char *from, uint length); diff --git a/sql/set_var.cc b/sql/set_var.cc index 1c0de702e4e..3f991713eb7 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1617,7 +1617,7 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) { if (!(res= var->value->val_str(&str))) { - strmake(buff, "NULL", 4); + strmov(buff, "NULL"); goto err; } var->save_result.ulong_value= ((ulong) @@ -2983,7 +2983,7 @@ int set_var::check(THD *thd) } if ((!value->fixed && - value->fix_fields(thd, 0, &value)) || value->check_cols(1)) + value->fix_fields(thd, &value)) || value->check_cols(1)) return -1; if (var->check_update_type(value->result_type())) { @@ -3017,7 +3017,7 @@ int set_var::light_check(THD *thd) if (type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL)) return 1; - if (value && ((!value->fixed && value->fix_fields(thd, 0, &value)) || + if (value && ((!value->fixed && value->fix_fields(thd, &value)) || value->check_cols(1))) return -1; return 0; @@ -3046,7 +3046,7 @@ int set_var_user::check(THD *thd) Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) */ - return (user_var_item->fix_fields(thd, 0, (Item**) 0) || + return (user_var_item->fix_fields(thd, (Item**) 0) || user_var_item->check()) ? -1 : 0; } @@ -3069,7 +3069,7 @@ int set_var_user::light_check(THD *thd) Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) */ - return (user_var_item->fix_fields(thd, 0, (Item**) 0)); + return (user_var_item->fix_fields(thd, (Item**) 0)); } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 7ae5130764f..747e7031530 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5358,3 +5358,5 @@ ER_STMT_HAS_NO_OPEN_CURSOR eng "The statement (%lu) has no open cursor." ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG eng "Explicit or implicit commit is not allowed in stored function or trigger." +ER_NO_DEFAULT_FOR_VIEW_FIELD + eng "Field of view '%-.64s.%-.64s' underlying table doesn't have a default value" diff --git a/sql/sp.cc b/sql/sp.cc index 4f89d6ba6da..456248db66b 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -676,15 +676,20 @@ db_show_routine_status(THD *thd, int type, const char *wild) tables is not VIEW for sure => we can pass 0 as condition */ - setup_tables(thd, &tables, 0, &leaves, FALSE); + thd->lex->select_lex.context.resolve_in_table_list_only(&tables); + setup_tables(thd, &thd->lex->select_lex.context, + &tables, 0, &leaves, FALSE); for (used_field= &used_fields[0]; used_field->field_name; used_field++) { - Item_field *field= new Item_field("mysql", "proc", + Item_field *field= new Item_field(&thd->lex->select_lex.context, + "mysql", "proc", used_field->field_name); - if (!(used_field->field= find_field_in_tables(thd, field, &tables, - 0, REPORT_ALL_ERRORS, 1))) + if (!field || + !(used_field->field= find_field_in_tables(thd, field, &tables, + 0, REPORT_ALL_ERRORS, 1, + TRUE))) { res= SP_INTERNAL_ERROR; goto err_case1; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index e4dc64c993d..6be80568186 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -117,7 +117,7 @@ sp_prepare_func_item(THD* thd, Item **it_addr) DBUG_ENTER("sp_prepare_func_item"); it_addr= it->this_item_addr(thd, it_addr); - if (!it->fixed && (*it_addr)->fix_fields(thd, 0, it_addr)) + if (!it->fixed && (*it_addr)->fix_fields(thd, it_addr)) { DBUG_PRINT("info", ("fix_fields() failed")); DBUG_RETURN(NULL); @@ -962,7 +962,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) we do not check suv->fixed, because it can't be fixed after creation */ - suv->fix_fields(thd, NULL, &item); + suv->fix_fields(thd, &item); suv->fix_length_and_dec(); suv->check(); suv->update(); @@ -1579,8 +1579,8 @@ sp_instr_set_trigger_field::execute(THD *thd, uint *nextp) DBUG_ENTER("sp_instr_set_trigger_field::execute"); /* QQ: Still unsure what should we return in case of error 1 or -1 ? */ - if (!value->fixed && value->fix_fields(thd, 0, &value) || - trigger_field->fix_fields(thd, 0, 0) || + if (!value->fixed && value->fix_fields(thd, &value) || + trigger_field->fix_fields(thd, 0) || (value->save_in_field(trigger_field->field, 0) < 0)) res= -1; *nextp= m_ip + 1; @@ -1935,7 +1935,7 @@ int sp_instr_cpush::execute(THD *thd, uint *nextp) { DBUG_ENTER("sp_instr_cpush::execute"); - thd->spcont->push_cursor(&m_lex_keeper); + thd->spcont->push_cursor(&m_lex_keeper, this); *nextp= m_ip+1; DBUG_RETURN(0); } @@ -1994,12 +1994,24 @@ sp_instr_copen::execute(THD *thd, uint *nextp) } else { + Query_arena *old_arena= thd->current_arena; + + /* + Get the Query_arena from the cpush instruction, which contains + the free_list of the query, so new items (if any) are stored in + the right free_list, and we can cleanup after each open. + */ + thd->current_arena= c->get_instr(); res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this); + /* Cleanup the query's items */ + if (thd->current_arena->free_list) + cleanup_items(thd->current_arena->free_list); + thd->current_arena= old_arena; /* Work around the fact that errors in selects are not returned properly (but instead converted into a warning), so if a condition handler caught, we have lost the result code. - */ + */ if (!res) { uint dummy1, dummy2; diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index aacb9254753..d0817e43790 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -148,9 +148,9 @@ sp_rcontext::restore_variables(uint fp) } void -sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper) +sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i) { - m_cstack[m_ccount++]= new sp_cursor(lex_keeper); + m_cstack[m_ccount++]= new sp_cursor(lex_keeper, i); } void @@ -169,8 +169,9 @@ sp_rcontext::pop_cursors(uint count) * */ -sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper) - :m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL) +sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i) + :m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL), + m_i(i) { /* currsor can't be stored in QC, so we should prevent opening QC for diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index b188805435f..856beb13f6d 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -26,6 +26,7 @@ struct sp_cond_type; class sp_cursor; struct sp_pvar; class sp_lex_keeper; +class sp_instr_cpush; #define SP_HANDLER_NONE 0 #define SP_HANDLER_EXIT 1 @@ -161,7 +162,7 @@ class sp_rcontext : public Sql_alloc restore_variables(uint fp); void - push_cursor(sp_lex_keeper *lex_keeper); + push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i); void pop_cursors(uint count); @@ -203,7 +204,7 @@ class sp_cursor : public Sql_alloc { public: - sp_cursor(sp_lex_keeper *lex_keeper); + sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i); virtual ~sp_cursor() { @@ -229,6 +230,12 @@ public: int fetch(THD *, List<struct sp_pvar> *vars); + inline sp_instr_cpush * + get_instr() + { + return m_i; + } + private: MEM_ROOT m_mem_root; // My own mem_root @@ -238,6 +245,7 @@ private: my_bool m_nseof; // Original no_send_eof Protocol *m_oprot; // Original protcol MYSQL_ROWS *m_current_row; + sp_instr_cpush *m_i; // My push instruction void destroy(); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d8bbb686ba2..383adcadc6a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2439,21 +2439,19 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, table_list->alias, name, item_name, (ulong) ref)); if (table_list->field_translation) { - uint num; - if (table_list->schema_table_reformed) + Field_iterator_view field_it; + field_it.set(table_list); + DBUG_ASSERT(table_list->schema_table_reformed || + (ref != 0 && table_list->view != 0)); + for (; !field_it.end_of_fields(); field_it.next()) { - num= thd->lex->current_select->item_list.elements; - } - else - { - DBUG_ASSERT(ref != 0 && table_list->view != 0); - num= table_list->view->select_lex.item_list.elements; - } - Field_translator *trans= table_list->field_translation; - for (uint i= 0; i < num; i ++) - { - if (!my_strcasecmp(system_charset_info, trans[i].name, name)) + if (!my_strcasecmp(system_charset_info, field_it.name(), name)) { + Item *item= field_it.create_item(thd); + if (!item) + { + DBUG_RETURN(0); + } if (table_list->schema_table_reformed) { /* @@ -2462,7 +2460,7 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, So we can return ->field. It is used only for 'show & where' commands. */ - DBUG_RETURN(((Item_field*) (trans[i].item))->field); + DBUG_RETURN(((Item_field*) (field_it.item()))->field); } #ifndef NO_EMBEDDED_ACCESS_CHECKS if (check_grants_view && @@ -2472,26 +2470,10 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, name, length)) DBUG_RETURN(WRONG_GRANT); #endif - if (thd->lex->current_select->no_wrap_view_item) - { - if (register_tree_change) - thd->change_item_tree(ref, trans[i].item); - else - *ref= trans[i].item; - } + if (register_tree_change) + thd->change_item_tree(ref, item); else - { - Item_ref *item_ref= new Item_ref(&trans[i].item, - table_list->view_name.str, - item_name); - /* as far as Item_ref have defined reference it do not need tables */ - if (register_tree_change && item_ref) - thd->change_item_tree(ref, item_ref); - else if (item_ref) - *ref= item_ref; - if (!(*ref)->fixed) - (*ref)->fix_fields(thd, 0, ref); - } + *ref= item; DBUG_RETURN((Field*) view_ref_found); } } @@ -2599,19 +2581,21 @@ Field *find_field_in_real_table(THD *thd, TABLE *table, SYNOPSIS find_field_in_tables() - thd Pointer to current thread structure - item Field item that should be found - tables Tables to be searched for item - ref If 'item' is resolved to a view field, ref is set to - point to the found view field - report_error Degree of error reporting: - - IGNORE_ERRORS then do not report any error - - IGNORE_EXCEPT_NON_UNIQUE report only non-unique - fields, suppress all other errors - - REPORT_EXCEPT_NON_UNIQUE report all other errors - except when non-unique fields were found - - REPORT_ALL_ERRORS - check_privileges need to check privileges + thd Pointer to current thread structure + item Field item that should be found + tables Tables to be searched for item + ref If 'item' is resolved to a view field, ref is set to + point to the found view field + report_error Degree of error reporting: + - IGNORE_ERRORS then do not report any error + - IGNORE_EXCEPT_NON_UNIQUE report only non-unique + fields, suppress all other errors + - REPORT_EXCEPT_NON_UNIQUE report all other errors + except when non-unique fields were found + - REPORT_ALL_ERRORS + check_privileges need to check privileges + register_tree_change TRUE if ref is not stack variable and we + need register changes in item tree RETURN VALUES 0 If error: the found field is not unique, or there are @@ -2627,7 +2611,7 @@ Field *find_field_in_real_table(THD *thd, TABLE *table, Field * find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, Item **ref, find_item_error_report_type report_error, - bool check_privileges) + bool check_privileges, bool register_tree_change) { Field *found=0; const char *db=item->db_name; @@ -2635,6 +2619,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, const char *name=item->field_name; uint length=(uint) strlen(name); char name_buff[NAME_LEN+1]; + bool allow_rowid; if (item->cached_table) { @@ -2669,7 +2654,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, (test(table->grant.want_privilege) && check_privileges), 1, &(item->cached_field_index), - TRUE); + register_tree_change); } if (found) { @@ -2702,13 +2687,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, db= name_buff; } - bool search_global= item->item_flags & MY_ITEM_PREFER_1ST_TABLE; if (table_name && table_name[0]) { /* Qualified field */ - bool found_table=0; - uint table_idx= 0; - for (; tables; tables= search_global?tables->next_global:tables->next_local, - table_idx++) + bool found_table= 0; + for (; tables; tables= tables->next_local) { /* TODO; Ensure that db and tables->db always points to something ! */ if (!my_strcasecmp(table_alias_charset, tables->alias, table_name) && @@ -2725,7 +2707,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, (test(tables->grant.want_privilege) && check_privileges), 1, &(item->cached_field_index), - TRUE); + register_tree_change); if (find) { item->cached_table= tables; @@ -2744,8 +2726,6 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) 0; } found=find; - if (table_idx == 0 && item->item_flags & MY_ITEM_PREFER_1ST_TABLE) - break; } } } @@ -2770,11 +2750,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) not_found_field; return (Field*) 0; } - bool allow_rowid= tables && !tables->next_local; // Only one table - uint table_idx= 0; - for (; tables ; tables= search_global?tables->next_global:tables->next_local, - table_idx++) + allow_rowid= tables && !tables->next_local; // Only one table + for (; tables ; tables= tables->next_local) { + Field *field; if (!tables->table && !tables->ancestor) { if (report_error == REPORT_ALL_ERRORS || @@ -2783,17 +2762,17 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) not_found_field; } - Field *field= find_field_in_table(thd, tables, name, item->name, - length, ref, - (tables->table && - test(tables->table->grant. - want_privilege) && - check_privileges), - (test(tables->grant.want_privilege) && - check_privileges), - allow_rowid, - &(item->cached_field_index), - TRUE); + field= find_field_in_table(thd, tables, name, item->name, + length, ref, + (tables->table && + test(tables->table->grant. + want_privilege) && + check_privileges), + (test(tables->grant.want_privilege) && + check_privileges), + allow_rowid, + &(item->cached_field_index), + register_tree_change); if (field) { if (field == WRONG_GRANT) @@ -2809,8 +2788,6 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) 0; } found= field; - if (table_idx == 0 && item->item_flags & MY_ITEM_PREFER_1ST_TABLE) - break; } } if (found) @@ -3066,7 +3043,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, */ it.replace(new Item_int("Not_used", (longlong) 1, 21)); } - else if (insert_fields(thd,tables,((Item_field*) item)->db_name, + else if (insert_fields(thd, ((Item_field*) item)->context, + ((Item_field*) item)->db_name, ((Item_field*) item)->table_name, &it, any_privileges)) { @@ -3102,7 +3080,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, ** Check that all given fields exists and fill struct with current data ****************************************************************************/ -bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, +bool setup_fields(THD *thd, Item **ref_pointer_array, List<Item> &fields, bool set_query_id, List<Item> *sum_func_list, bool allow_sum_func) { @@ -3131,7 +3109,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, Item **ref= ref_pointer_array; while ((item= it++)) { - if (!item->fixed && item->fix_fields(thd, tables, it.ref()) || + if (!item->fixed && item->fix_fields(thd, it.ref()) || (item= *(it.ref()))->check_cols(1)) { DBUG_RETURN(TRUE); /* purecov: inspected */ @@ -3181,6 +3159,7 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables) SYNOPSIS setup_tables() thd Thread handler + context name resolution contest to setup table list there tables Table list conds Condition of current SELECT (can be changed by VIEW) leaves List of join table leaves list @@ -3200,11 +3179,15 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables) TRUE error */ -bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, +bool setup_tables(THD *thd, Name_resolution_context *context, + TABLE_LIST *tables, Item **conds, TABLE_LIST **leaves, bool select_insert) { uint tablenr= 0; DBUG_ENTER("setup_tables"); + + context->table_list= tables; + /* this is used for INSERT ... SELECT. For select we setup tables except first (and its underlying tables) @@ -3259,10 +3242,21 @@ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, table_list; table_list= table_list->next_local) { - if (table_list->ancestor && - table_list->setup_ancestor(thd, conds, - table_list->effective_with_check)) - DBUG_RETURN(1); + if (table_list->ancestor) + { + DBUG_ASSERT(table_list->view); + Query_arena *arena= thd->current_arena, backup; + bool res; + if (arena->is_conventional()) + arena= 0; // For easier test + else + thd->set_n_backup_item_arena(arena, &backup); + res= table_list->setup_ancestor(thd); + if (arena) + thd->restore_backup_item_arena(arena, &backup); + if (res) + DBUG_RETURN(1); + } } DBUG_RETURN(0); } @@ -3314,7 +3308,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, SYNOPSIS insert_fields() thd Thread handler - tables List of tables + context Context for name resolution db_name Database name in case of 'database_name.table_name.*' table_name Table name in case of 'table_name.*' it Pointer to '*' @@ -3328,7 +3322,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, */ bool -insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, +insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, const char *table_name, List_iterator<Item> *it, bool any_privileges) { @@ -3352,7 +3346,9 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, } found= 0; - for (; tables; tables= tables->next_local) + for (TABLE_LIST *tables= context->table_list; + tables; + tables= tables->next_local) { Field_iterator *iterator; TABLE_LIST *natural_join_table; @@ -3361,7 +3357,6 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, TABLE_LIST *last; TABLE_LIST *embedding; TABLE *table= tables->table; - bool alias_used= 0; if (!table_name || (!my_strcasecmp(table_alias_charset, table_name, tables->alias) && @@ -3395,16 +3390,6 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, } } #endif - if (table) - thd->used_tables|= table->map; - else - { - view_iter.set(tables); - for (; !view_iter.end_of_fields(); view_iter.next()) - { - thd->used_tables|= view_iter.item(thd)->used_tables(); - } - } natural_join_table= 0; last= embedded= tables; @@ -3435,8 +3420,6 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, { iterator= &view_iter; view= 1; - alias_used= my_strcasecmp(table_alias_charset, - tables->table_name, tables->alias); } else { @@ -3445,6 +3428,10 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, } iterator->set(tables); + /* for view used tables will be collected in following loop */ + if (table) + thd->used_tables|= table->map; + for (; !iterator->end_of_fields(); iterator->next()) { Item *not_used_item; @@ -3457,16 +3444,10 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, strlen(field_name), ¬_used_item, 0, 0, 0, ¬_used_field_index, TRUE)) { - Item *item= iterator->item(thd); - if (view && !thd->lex->current_select->no_wrap_view_item) - { - /* - as far as we have view, then item point to view_iter, so we - can use it directly for this view specific operation - */ - item= new Item_ref(view_iter.item_ptr(), tables->view_name.str, - field_name); - } + Item *item= iterator->create_item(thd); + if (!item) + goto err; + thd->used_tables|= item->used_tables(); if (!found++) (void) it->replace(item); // Replace '*' else @@ -3537,9 +3518,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, my_message(ER_NO_TABLES_USED, ER(ER_NO_TABLES_USED), MYF(0)); else my_error(ER_BAD_TABLE_ERROR, MYF(0), table_name); -#ifndef NO_EMBEDDED_ACCESS_CHECKS err: -#endif DBUG_RETURN(1); } @@ -3550,16 +3529,25 @@ err: SYNOPSIS setup_conds() thd thread handler - tables list of tables for name resolving leaves list of leaves of join table tree */ -int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) +int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, + COND **conds) { SELECT_LEX *select_lex= thd->lex->current_select; Query_arena *arena= thd->current_arena, backup; - bool save_wrapper= thd->lex->current_select->no_wrap_view_item; TABLE_LIST *table= NULL; // For HP compilers + /* + it_is_update set to TRUE when tables of primary SELECT_LEX (SELECT_LEX + which belong to LEX, i.e. most up SELECT) will be updated by + INSERT/UPDATE/LOAD + NOTE: using this condition helps to prevent call of prepare_check_option() + from subquery of VIEW, because tables of subquery belongs to VIEW + (see condition before prepare_check_option() call) + */ + bool it_is_update= (select_lex == &thd->lex->select_lex) && + thd->lex->which_check_option_applicable(); DBUG_ENTER("setup_conds"); if (select_lex->conds_processed_with_permanent_arena || @@ -3568,12 +3556,17 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) thd->set_query_id=1; - thd->lex->current_select->no_wrap_view_item= 0; + for (table= tables; table; table= table->next_local) + { + if (table->prepare_where(thd, conds, FALSE)) + goto err_no_arena; + } + select_lex->cond_count= 0; if (*conds) { thd->where="where clause"; - if (!(*conds)->fixed && (*conds)->fix_fields(thd, tables, conds) || + if (!(*conds)->fixed && (*conds)->fix_fields(thd, conds) || (*conds)->check_cols(1)) goto err_no_arena; } @@ -3591,11 +3584,12 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) /* Make a join an a expression */ thd->where="on clause"; if (!embedded->on_expr->fixed && - embedded->on_expr->fix_fields(thd, tables, &embedded->on_expr) || + embedded->on_expr->fix_fields(thd, &embedded->on_expr) || embedded->on_expr->check_cols(1)) goto err_no_arena; select_lex->cond_count++; } + if (embedded->natural_join) { /* Make a join of all fields wich have the same name */ @@ -3675,7 +3669,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) { if (t2_field != view_ref_found) { - if (!(item_t2= new Item_field(thd, t2_field))) + if (!(item_t2= new Item_field(thd, &select_lex->context, + t2_field))) goto err; /* Mark field used for table cache */ t2_field->query_id= thd->query_id; @@ -3687,7 +3682,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) t1_field->query_id= thd->query_id; t1->used_keys.intersect(t1_field->part_of_key); } - Item_func_eq *tmp= new Item_func_eq(iterator->item(thd), + Item_func_eq *tmp= new Item_func_eq(iterator->create_item(thd), item_t2); if (!tmp) goto err; @@ -3703,7 +3698,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) { COND *on_expr= cond_and; if (!on_expr->fixed) - on_expr->fix_fields(thd, 0, &on_expr); + on_expr->fix_fields(thd, &on_expr); if (!embedded->outer_join) // Not left join { *conds= and_conds(*conds, cond_and); @@ -3712,7 +3707,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) thd->restore_backup_item_arena(arena, &backup); if (*conds && !(*conds)->fixed) { - if ((*conds)->fix_fields(thd, tables, conds)) + if ((*conds)->fix_fields(thd, conds)) goto err_no_arena; } } @@ -3724,8 +3719,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) thd->restore_backup_item_arena(arena, &backup); if (embedded->on_expr && !embedded->on_expr->fixed) { - if (embedded->on_expr->fix_fields(thd, tables, - &embedded->on_expr)) + if (embedded->on_expr->fix_fields(thd, &embedded->on_expr)) goto err_no_arena; } } @@ -3737,6 +3731,20 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) } while (embedding && embedding->nested_join->join_list.head() == embedded); + + /* process CHECK OPTION */ + if (it_is_update) + { + TABLE_LIST *view= table->belong_to_view; + if (!view) + view= table; + if (view->effective_with_check) + { + if (view->prepare_check_option(thd)) + goto err_no_arena; + thd->change_item_tree(&table->check_option, view->check_option); + } + } } if (!thd->current_arena->is_conventional()) @@ -3750,14 +3758,12 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) select_lex->where= *conds; select_lex->conds_processed_with_permanent_arena= 1; } - thd->lex->current_select->no_wrap_view_item= save_wrapper; DBUG_RETURN(test(thd->net.report_error)); err: if (arena) thd->restore_backup_item_arena(arena, &backup); err_no_arena: - thd->lex->current_select->no_wrap_view_item= save_wrapper; DBUG_RETURN(1); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 20f48da9283..a941ba11943 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -784,7 +784,10 @@ void THD::nocheck_register_item_tree_change(Item **place, Item *old_value, void *change_mem= alloc_root(runtime_memroot, sizeof(*change)); if (change_mem == 0) { - fatal_error(); + /* + OOM, thd->fatal_error() is called by the error handler of the + memroot. Just return. + */ return; } change= new (change_mem) Item_change_record; @@ -1451,17 +1454,16 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u) (void)local_vars.push_back(new Item_splocal(mv->s, mv->offset)); else { - Item_func_set_user_var *xx = new Item_func_set_user_var(mv->s, item); + Item_func_set_user_var *var= new Item_func_set_user_var(mv->s, item); /* Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) Item_func_set_user_var can't be fixed after creation, so we do not - check xx->fixed + check var->fixed */ - xx->fix_fields(thd, (TABLE_LIST*) thd->lex->select_lex.table_list.first, - 0); - xx->fix_length_and_dec(); - vars.push_back(xx); + var->fix_fields(thd, 0); + var->fix_length_and_dec(); + vars.push_back(var); } } return 0; @@ -1538,15 +1540,19 @@ void Statement::set_statement(Statement *stmt) void Statement::set_n_backup_statement(Statement *stmt, Statement *backup) { + DBUG_ENTER("Statement::set_n_backup_statement"); backup->set_statement(this); set_statement(stmt); + DBUG_VOID_RETURN; } void Statement::restore_backup_statement(Statement *stmt, Statement *backup) { + DBUG_ENTER("Statement::restore_backup_statement"); stmt->set_statement(this); set_statement(backup); + DBUG_VOID_RETURN; } @@ -1569,6 +1575,7 @@ void Query_arena::set_n_backup_item_arena(Query_arena *set, Query_arena *backup) { DBUG_ENTER("Query_arena::set_n_backup_item_arena"); DBUG_ASSERT(backup->is_backup_arena == FALSE); + backup->set_item_arena(this); set_item_arena(set); #ifndef DBUG_OFF diff --git a/sql/sql_class.h b/sql/sql_class.h index 1f232b9ca21..5642fa0d6af 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -653,6 +653,14 @@ typedef struct system_status_var void free_tmp_table(THD *thd, TABLE *entry); +/* The following macro is to make init of Query_arena simpler */ +#ifndef DBUG_OFF +#define INIT_ARENA_DBUG_INFO is_backup_arena= 0 +#else +#define INIT_ARENA_DBUG_INFO +#endif + + class Query_arena { public: @@ -664,9 +672,6 @@ public: MEM_ROOT *mem_root; // Pointer to current memroot #ifndef DBUG_OFF bool is_backup_arena; /* True if this arena is used for backup. */ -#define INIT_ARENA_DBUG_INFO is_backup_arena= 0 -#else -#define INIT_ARENA_DBUG_INFO #endif enum enum_state { @@ -691,7 +696,6 @@ public: */ Query_arena() { INIT_ARENA_DBUG_INFO; } -#undef INIT_ARENA_DBUG_INFO virtual Type type() const; virtual ~Query_arena() {}; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 25fef8b0ad6..d83937098e2 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -300,7 +300,9 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) SELECT_LEX *select_lex= &thd->lex->select_lex; DBUG_ENTER("mysql_prepare_delete"); - if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, FALSE) || + if (setup_tables(thd, &thd->lex->select_lex.context, + table_list, conds, &select_lex->leaf_tables, + FALSE) || setup_conds(thd, table_list, select_lex->leaf_tables, conds) || setup_ftfuncs(select_lex)) DBUG_RETURN(TRUE); @@ -356,7 +358,8 @@ bool mysql_multi_delete_prepare(THD *thd) lex->query_tables also point on local list of DELETE SELECT_LEX */ - if (setup_tables(thd, lex->query_tables, &lex->select_lex.where, + if (setup_tables(thd, &thd->lex->select_lex.context, + lex->query_tables, &lex->select_lex.where, &lex->select_lex.leaf_tables, FALSE)) DBUG_RETURN(TRUE); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index e1d701936cf..fc9d15e94c4 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -114,6 +114,10 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) bool is_union= first_select->next_select() && first_select->next_select()->linkage == UNION_TYPE; + /* prevent name resolving out of derived table */ + for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select()) + sl->context.outer_context= 0; + if (!(derived_result= new select_union(0))) DBUG_RETURN(1); // out of memory diff --git a/sql/sql_do.cc b/sql/sql_do.cc index e37f3e86dda..08388dee516 100644 --- a/sql/sql_do.cc +++ b/sql/sql_do.cc @@ -24,7 +24,7 @@ bool mysql_do(THD *thd, List<Item> &values) List_iterator<Item> li(values); Item *value; DBUG_ENTER("mysql_do"); - if (setup_fields(thd, 0, 0, values, 0, 0, 0)) + if (setup_fields(thd, 0, values, 0, 0, 0)) DBUG_RETURN(TRUE); while ((value = li++)) value->val_int(); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index e905f93b860..e109600bcd0 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -353,7 +353,9 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, LINT_INIT(key); LINT_INIT(key_len); - list.push_front(new Item_field(NULL,NULL,"*")); + thd->lex->select_lex.context.resolve_in_table_list_only(tables); + list.push_front(new Item_field(&thd->lex->select_lex.context, + NULL, NULL, "*")); List_iterator<Item> it(list); it++; @@ -410,7 +412,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, tables->table=table; if (cond && ((!cond->fixed && - cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1))) + cond->fix_fields(thd, &cond)) || cond->check_cols(1))) goto err0; if (keyname) @@ -422,7 +424,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } } - if (insert_fields(thd, tables, tables->db, tables->alias, &it, 0)) + if (insert_fields(thd, &thd->lex->select_lex.context, + tables->db, tables->alias, &it, 0)) goto err0; protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); @@ -505,7 +508,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, { // 'item' can be changed by fix_fields() call if ((!item->fixed && - item->fix_fields(thd, tables, it_ke.ref())) || + item->fix_fields(thd, it_ke.ref())) || (item= *it_ke.ref())->check_cols(1)) goto err; if (item->used_tables() & ~RAND_TABLE_BIT) diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 0cf8d1e93a7..6780beec258 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -81,14 +81,18 @@ enum enum_used_fields static bool init_fields(THD *thd, TABLE_LIST *tables, struct st_find_field *find_fields, uint count) { + Name_resolution_context *context= &thd->lex->select_lex.context; DBUG_ENTER("init_fields"); + context->resolve_in_table_list_only(tables); for (; count-- ; find_fields++) { /* We have to use 'new' here as field will be re_linked on free */ - Item_field *field= new Item_field("mysql", find_fields->table_name, + Item_field *field= new Item_field(context, + "mysql", find_fields->table_name, find_fields->field_name); if (!(find_fields->field= find_field_in_tables(thd, field, tables, - 0, REPORT_ALL_ERRORS, 1))) + 0, REPORT_ALL_ERRORS, 1, + TRUE))) DBUG_RETURN(1); } DBUG_RETURN(0); @@ -544,7 +548,6 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol, prepare_simple_select() thd Thread handler cond WHERE part of select - tables list of tables, used in WHERE table goal table error code of error (out) @@ -553,11 +556,11 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol, # created SQL_SELECT */ -SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, TABLE_LIST *tables, +SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, TABLE *table, int *error) { if (!cond->fixed) - cond->fix_fields(thd, tables, &cond); // can never fail + cond->fix_fields(thd, &cond); // can never fail /* Assume that no indexes cover all required fields */ table->used_keys.clear_all(); @@ -599,7 +602,7 @@ SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, uint mlen, new Item_string("\\",1,&my_charset_latin1)); if (thd->is_fatal_error) return 0; // OOM - return prepare_simple_select(thd,cond,tables,table,error); + return prepare_simple_select(thd, cond, table, error); } @@ -651,7 +654,8 @@ bool mysqld_help(THD *thd, const char *mask) tables do not contain VIEWs => we can pass 0 as conds */ - setup_tables(thd, tables, 0, &leaves, FALSE); + setup_tables(thd, &thd->lex->select_lex.context, + tables, 0, &leaves, FALSE); memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields)); if (init_fields(thd, tables, used_fields, array_elements(used_fields))) goto error; @@ -718,15 +722,15 @@ bool mysqld_help(THD *thd, const char *mask) Item *cond_cat_by_cat= new Item_func_equal(new Item_field(cat_cat_id), new Item_int((int32)category_id)); - if (!(select= prepare_simple_select(thd,cond_topic_by_cat, - tables,tables[0].table,&error))) + if (!(select= prepare_simple_select(thd, cond_topic_by_cat, + tables[0].table, &error))) goto error; get_all_items_for_category(thd,tables[0].table, used_fields[help_topic_name].field, select,&topics_list); delete select; - if (!(select= prepare_simple_select(thd,cond_cat_by_cat,tables, - tables[1].table,&error))) + if (!(select= prepare_simple_select(thd, cond_cat_by_cat, + tables[1].table, &error))) goto error; get_all_items_for_category(thd,tables[1].table, used_fields[help_category_name].field, diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 2ce81d8815e..576866cb17d 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -31,7 +31,7 @@ static void end_delayed_insert(THD *thd); extern "C" pthread_handler_decl(handle_delayed_insert,arg); static void unlink_blobs(register TABLE *table); #endif -static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id); +static bool check_view_insertability(THD *thd, TABLE_LIST *view); /* Define to force use of my_malloc() if the allocated memory block is big */ @@ -106,7 +106,11 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, } else { // Part field list - TABLE_LIST *save_next; + Name_resolution_context *context= &thd->lex->select_lex.context; + TABLE_LIST *save_next= table_list->next_local, + *save_context= context->table_list; + bool save_resolve_in_select_list= + thd->lex->select_lex.context.resolve_in_select_list; int res; if (fields.elements != values.elements) { @@ -115,12 +119,15 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, } thd->dupp_field=0; - thd->lex->select_lex.no_wrap_view_item= 1; - save_next= table_list->next_local; // fields only from first table + thd->lex->select_lex.no_wrap_view_item= TRUE; + /* fields only from first table */ table_list->next_local= 0; - res= setup_fields(thd, 0, table_list, fields, 1, 0, 0); + context->resolve_in_table_list_only(table_list); + res= setup_fields(thd, 0, fields, 1, 0, 0); table_list->next_local= save_next; - thd->lex->select_lex.no_wrap_view_item= 0; + thd->lex->select_lex.no_wrap_view_item= FALSE; + context->table_list= save_context; + context->resolve_in_select_list= save_resolve_in_select_list; if (res) return -1; if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE) @@ -159,7 +166,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, if (check_key_in_view(thd, table_list) || (table_list->view && - check_view_insertability(table_list, thd->query_id))) + check_view_insertability(thd, table_list))) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT"); return -1; @@ -209,7 +216,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, Check the fields we are going to modify. This will set the query_id of all used fields to the threads query_id. */ - if (setup_fields(thd, 0, insert_table_list, update_fields, 1, 0, 0)) + if (setup_fields(thd, 0, update_fields, 1, 0, 0)) return -1; if (table->timestamp_field) @@ -247,6 +254,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, ulonglong id; COPY_INFO info; TABLE *table= 0; + TABLE_LIST *next_local; List_iterator_fast<List_item> its(values_list); List_item *values; #ifndef EMBEDDED_LIBRARY @@ -327,7 +335,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, /* mysql_prepare_insert set table_list->table if it was not set */ table= table_list->table; - // is table which we are changing used somewhere in other parts of query + next_local= table_list->next_local; + table_list->next_local= 0; + thd->lex->select_lex.context.resolve_in_table_list_only(table_list); value_count= values->elements; while ((values= its++)) { @@ -337,10 +347,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter); goto abort; } - if (setup_fields(thd, 0, table_list, *values, 0, 0, 0)) + if (setup_fields(thd, 0, *values, 0, 0, 0)) goto abort; } its.rewind (); + table_list->next_local= next_local; /* Fill in the given fields and dump it to the table file */ @@ -387,12 +398,16 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, MODE_STRICT_ALL_TABLES))); if ((fields.elements || !value_count) && - check_that_all_fields_are_given_values(thd, table)) + check_that_all_fields_are_given_values(thd, table, table_list)) { /* thd->net.report_error is now set, which will abort the next loop */ error= 1; } + if (table_list->prepare_where(thd, 0, TRUE) || + table_list->prepare_check_option(thd)) + error= 1; + while ((values= its++)) { if (fields.elements || !value_count) @@ -596,6 +611,7 @@ abort: SYNOPSIS check_view_insertability() + thd - thread handler view - reference on VIEW IMPLEMENTATION @@ -612,7 +628,7 @@ abort: TRUE - can't be used for insert */ -static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) +static bool check_view_insertability(THD * thd, TABLE_LIST *view) { uint num= view->view->select_lex.item_list.elements; TABLE *table= view->table; @@ -620,15 +636,25 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) *trans_end= trans_start + num; Field_translator *trans; Field **field_ptr= table->field; - query_id_t other_query_id= query_id - 1; + uint used_fields_buff_size= (table->s->fields + 7) / 8; + uchar *used_fields_buff= (uchar*)thd->alloc(used_fields_buff_size); + MY_BITMAP used_fields; DBUG_ENTER("check_key_in_view"); + if (!used_fields_buff) + DBUG_RETURN(TRUE); // EOM + DBUG_ASSERT(view->table != 0 && view->field_translation != 0); + bitmap_init(&used_fields, used_fields_buff, used_fields_buff_size * 8, 0); + bitmap_clear_all(&used_fields); + view->contain_auto_increment= 0; /* check simplicity and prepare unique test of view */ for (trans= trans_start; trans != trans_end; trans++) { + if (!trans->item->fixed && trans->item->fix_fields(thd, &trans->item)) + return TRUE; Item_field *field; /* simple SELECT list entry (field without expression) */ if (!(field= trans->item->filed_for_view_update())) @@ -636,7 +662,6 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) if (field->field->unireg_check == Field::NEXT_NUMBER) view->contain_auto_increment= 1; /* prepare unique test */ - field->field->query_id= other_query_id; /* remove collation (or other transparent for update function) if we have it @@ -648,29 +673,12 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) { /* Thanks to test above, we know that all columns are of type Item_field */ Item_field *field= (Item_field *)trans->item; - if (field->field->query_id == query_id) + /* check fields belong to table in which we are inserting */ + if (field->field->table == table && + bitmap_fast_test_and_set(&used_fields, field->field->field_index)) DBUG_RETURN(TRUE); - field->field->query_id= query_id; } - /* VIEW contain all fields without default value */ - for (; *field_ptr; field_ptr++) - { - Field *field= *field_ptr; - /* field have not default value */ - if ((field->type() == FIELD_TYPE_BLOB) && - (table->timestamp_field != field || - field->unireg_check == Field::TIMESTAMP_UN_FIELD)) - { - for (trans= trans_start; ; trans++) - { - if (trans == trans_end) - DBUG_RETURN(TRUE); // Field was not part of view - if (((Item_field *)trans->item)->field == *field_ptr) - break; // ok - } - } - } DBUG_RETURN(FALSE); } @@ -698,7 +706,8 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, bool insert_into_view= (table_list->view != 0); DBUG_ENTER("mysql_prepare_insert_check_table"); - if (setup_tables(thd, table_list, where, &thd->lex->select_lex.leaf_tables, + if (setup_tables(thd, &thd->lex->select_lex.context, + table_list, where, &thd->lex->select_lex.leaf_tables, select_insert)) DBUG_RETURN(TRUE); @@ -711,7 +720,7 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(TRUE); } - DBUG_RETURN(insert_view_fields(&fields, table_list)); + DBUG_RETURN(insert_view_fields(thd, &fields, table_list)); } DBUG_RETURN(FALSE); @@ -725,31 +734,63 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, mysql_prepare_insert() thd Thread handler table_list Global/local table list - table Table to insert into (can be NULL if table should be taken from - table_list->table) + table Table to insert into (can be NULL if table should + be taken from table_list->table) where Where clause (for insert ... select) select_insert TRUE if INSERT ... SELECT statement + TODO (in far future) + In cases of: + INSERT INTO t1 SELECT a, sum(a) as sum1 from t2 GROUP BY a + ON DUPLICATE KEY ... + we should be able to refer to sum1 in the ON DUPLICATE KEY part + + WARNING + You MUST set table->insert_values to 0 after calling this function + before releasing the table object. + RETURN VALUE FALSE OK TRUE error */ -bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, - List<Item> &fields, List_item *values, +bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, + TABLE *table, List<Item> &fields, List_item *values, List<Item> &update_fields, List<Item> &update_values, enum_duplicates duplic, COND **where, bool select_insert) { + SELECT_LEX *select_lex= &thd->lex->select_lex; + TABLE_LIST *save_table_list; + TABLE_LIST *save_next_local; bool insert_into_view= (table_list->view != 0); - /* TODO: use this condition for 'WITH CHECK OPTION' */ - bool res; - TABLE_LIST *next_local; + bool save_resolve_in_select_list; + bool res= 0; DBUG_ENTER("mysql_prepare_insert"); DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d", (ulong)table_list, (ulong)table, (int)insert_into_view)); + /* + For subqueries in VALUES() we should not see the table in which we are + inserting (for INSERT ... SELECT this is done by changing table_list, + because INSERT ... SELECT share SELECT_LEX it with SELECT. + */ + if (!select_insert) + { + for (SELECT_LEX_UNIT *un= select_lex->first_inner_unit(); + un; + un= un->next_unit()) + { + for (SELECT_LEX *sl= un->first_select(); + sl; + sl= sl->next_select()) + { + sl->context.outer_context= 0; + } + } + } + if (duplic == DUP_UPDATE) { /* it should be allocated before Item::fix_fields() */ @@ -761,31 +802,54 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, select_insert)) DBUG_RETURN(TRUE); - next_local= table_list->next_local; + save_table_list= select_lex->context.table_list; + save_resolve_in_select_list= select_lex->context.resolve_in_select_list; + save_next_local= table_list->next_local; + table_list->next_local= 0; + select_lex->context.resolve_in_table_list_only(table_list); if ((values && check_insert_fields(thd, table_list, fields, *values, !insert_into_view)) || - (values && setup_fields(thd, 0, table_list, *values, 0, 0, 0)) || - (duplic == DUP_UPDATE && - ((thd->lex->select_lex.no_wrap_view_item= 1, - (res= check_update_fields(thd, table_list, update_fields)), - thd->lex->select_lex.no_wrap_view_item= 0, - res) || - setup_fields(thd, 0, table_list, update_values, 1, 0, 0)))) - DBUG_RETURN(TRUE); - table_list->next_local= next_local; + (values && setup_fields(thd, 0, *values, 0, 0, 0))) + res= TRUE; + else if (duplic == DUP_UPDATE) + { + select_lex->no_wrap_view_item= TRUE; + res= check_update_fields(thd, table_list, update_fields); + select_lex->no_wrap_view_item= FALSE; + if (select_lex->group_list.elements == 0) + { + /* + When we are not using GROUP BY we can refer to other tables in the + ON DUPLICATE KEY part + */ + table_list->next_local= save_next_local; + } + if (!res) + res= setup_fields(thd, 0, update_values, 1, 0, 0); + } + table_list->next_local= save_next_local; + select_lex->context.table_list= save_table_list; + select_lex->context.resolve_in_select_list= save_resolve_in_select_list; + if (res) + DBUG_RETURN(res); if (!table) table= table_list->table; - if (!select_insert && unique_table(table_list, table_list->next_global)) + if (!select_insert) { - my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); - DBUG_RETURN(TRUE); + Item *fake_conds= 0; + if (unique_table(table_list, table_list->next_global)) + { + my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); + DBUG_RETURN(TRUE); + } + select_lex->fix_prepare_information(thd, &fake_conds); + select_lex->first_execution= 0; } if (duplic == DUP_UPDATE || duplic == DUP_REPLACE) table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); - thd->lex->select_lex.first_execution= 0; DBUG_RETURN(FALSE); } @@ -1038,7 +1102,8 @@ before_trg_err: Check that all fields with arn't null_fields are used ******************************************************************************/ -int check_that_all_fields_are_given_values(THD *thd, TABLE *entry) +int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, + TABLE_LIST *table_list) { int err= 0; for (Field **field=entry->field ; *field ; field++) @@ -1047,10 +1112,29 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry) ((*field)->flags & NO_DEFAULT_VALUE_FLAG) && ((*field)->real_type() != FIELD_TYPE_ENUM)) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_NO_DEFAULT_FOR_FIELD, - ER(ER_NO_DEFAULT_FOR_FIELD), - (*field)->field_name); + bool view= FALSE; + if (table_list) + { + table_list= (table_list->belong_to_view ? + table_list->belong_to_view : + table_list); + view= (table_list->view); + } + if (view) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_DEFAULT_FOR_VIEW_FIELD, + ER(ER_NO_DEFAULT_FOR_VIEW_FIELD), + table_list->view_db.str, + table_list->view_name.str); + } + else + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_DEFAULT_FOR_FIELD, + ER(ER_NO_DEFAULT_FOR_FIELD), + (*field)->field_name); + } err= 1; } } @@ -1932,35 +2016,37 @@ bool delayed_insert::handle_inserts(void) bool mysql_insert_select_prepare(THD *thd) { LEX *lex= thd->lex; + SELECT_LEX *select_lex= &lex->select_lex; TABLE_LIST *first_select_leaf_table; DBUG_ENTER("mysql_insert_select_prepare"); + /* SELECT_LEX do not belong to INSERT statement, so we can't add WHERE clause if table is VIEW */ - lex->query_tables->no_where_clause= 1; + if (mysql_prepare_insert(thd, lex->query_tables, lex->query_tables->table, lex->field_list, 0, lex->update_list, lex->value_list, lex->duplicates, - &lex->select_lex.where, TRUE)) + &select_lex->where, TRUE)) DBUG_RETURN(TRUE); /* exclude first table from leaf tables list, because it belong to INSERT */ - DBUG_ASSERT(lex->select_lex.leaf_tables != 0); - lex->leaf_tables_insert= lex->select_lex.leaf_tables; + DBUG_ASSERT(select_lex->leaf_tables != 0); + lex->leaf_tables_insert= select_lex->leaf_tables; /* skip all leaf tables belonged to view where we are insert */ - for (first_select_leaf_table= lex->select_lex.leaf_tables->next_leaf; + for (first_select_leaf_table= select_lex->leaf_tables->next_leaf; first_select_leaf_table && first_select_leaf_table->belong_to_view && first_select_leaf_table->belong_to_view == lex->leaf_tables_insert->belong_to_view; first_select_leaf_table= first_select_leaf_table->next_leaf) {} - lex->select_lex.leaf_tables= first_select_leaf_table; + select_lex->leaf_tables= first_select_leaf_table; DBUG_RETURN(FALSE); } @@ -1988,8 +2074,8 @@ select_insert::select_insert(TABLE_LIST *table_list_par, TABLE *table_par, int select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) { - int res; LEX *lex= thd->lex; + int res; SELECT_LEX *lex_current_select_save= lex->current_select; DBUG_ENTER("select_insert::prepare"); @@ -2043,8 +2129,11 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))); - DBUG_RETURN(fields->elements && - check_that_all_fields_are_given_values(thd, table)); + res= ((fields->elements && + check_that_all_fields_are_given_values(thd, table, table_list)) || + table_list->prepare_where(thd, 0, TRUE) || + table_list->prepare_check_option(thd)); + DBUG_RETURN(res); } @@ -2290,7 +2379,8 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))); - DBUG_RETURN(check_that_all_fields_are_given_values(thd, table)); + DBUG_RETURN(check_that_all_fields_are_given_values(thd, table, + table_list)); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 08f0c3badf7..fe79b6dd035 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1104,7 +1104,8 @@ void st_select_lex::init_query() having= where= prep_where= 0; olap= UNSPECIFIED_OLAP_TYPE; having_fix_field= 0; - resolve_mode= NOMATTER_MODE; + context.select_lex= this; + context.init(); cond_count= with_wild= 0; conds_processed_with_permanent_arena= 0; ref_pointer_array= 0; @@ -1703,8 +1704,7 @@ bool st_lex::can_not_use_merged() bool st_lex::only_view_structure() { - switch(sql_command) - { + switch (sql_command) { case SQLCOM_SHOW_CREATE: case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_FIELDS: @@ -1744,6 +1744,31 @@ bool st_lex::need_correct_ident() } } +/* + Get effective type of CHECK OPTION for given view + + SYNOPSIS + get_effective_with_check() + view given view + + NOTE + It have not sense to set CHECK OPTION for SELECT satement or subqueries, + so we do not. + + RETURN + VIEW_CHECK_NONE no need CHECK OPTION + VIEW_CHECK_LOCAL CHECK OPTION LOCAL + VIEW_CHECK_CASCADED CHECK OPTION CASCADED +*/ + +uint8 st_lex::get_effective_with_check(st_table_list *view) +{ + if (view->select_lex->master_unit() == &unit && + which_check_option_applicable()) + return (uint8)view->with_check; + return VIEW_CHECK_NONE; +} + /* initialize limit counters @@ -1804,7 +1829,8 @@ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local) */ if ((*link_to_local= test(select_lex.table_list.first))) { - select_lex.table_list.first= (byte*) first->next_local; + select_lex.table_list.first= (byte*) (select_lex.context.table_list= + first->next_local); select_lex.table_list.elements--; //safety first->next_local= 0; /* @@ -1909,7 +1935,8 @@ void st_lex::link_first_table_back(TABLE_LIST *first, if (link_to_local) { first->next_local= (TABLE_LIST*) select_lex.table_list.first; - select_lex.table_list.first= (byte*) first; + select_lex.table_list.first= + (byte*) (select_lex.context.table_list= first); select_lex.table_list.elements++; //safety } } @@ -1930,7 +1957,21 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds) if (!thd->current_arena->is_conventional() && first_execution) { first_execution= 0; - prep_where= where; + if (*conds) + { + prep_where= *conds; + *conds= where= prep_where->copy_andor_structure(thd); + } + for (TABLE_LIST *tbl= (TABLE_LIST *)table_list.first; + tbl; + tbl= tbl->next_local) + { + if (tbl->on_expr) + { + tbl->prep_on_expr= tbl->on_expr; + tbl->on_expr= tbl->on_expr->copy_andor_structure(thd); + } + } } } @@ -1945,3 +1986,4 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds) st_select_lex_unit::change_result are in sql_union.cc */ + diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 5cf0b66598f..8fde37b0126 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -470,6 +470,7 @@ typedef class st_select_lex_unit SELECT_LEX_UNIT; class st_select_lex: public st_select_lex_node { public: + Name_resolution_context context; char *db, *db1, *table1, *db2, *table2; /* For outer join using .. */ Item *where, *having; /* WHERE & HAVING clauses */ Item *prep_where; /* saved WHERE clause for prepared statement processing */ @@ -549,27 +550,6 @@ public: /* exclude this select from check of unique_table() */ bool exclude_from_table_unique_test; - /* - SELECT for SELECT command st_select_lex. Used to privent scaning - item_list of non-SELECT st_select_lex (no sense find to finding - reference in it (all should be in tables, it is dangerouse due - to order of fix_fields calling for non-SELECTs commands (item list - can be not fix_fieldsd)). This value will be assigned for - primary select (sql_yac.yy) and for any subquery and - UNION SELECT (sql_parse.cc mysql_new_select()) - - - INSERT for primary st_select_lex structure of simple INSERT/REPLACE - (used for name resolution, see Item_fiels & Item_ref fix_fields, - FALSE for INSERT/REPLACE ... SELECT, because it's - st_select_lex->table_list will be preprocessed (first table removed) - before passing to handle_select) - - NOMATTER for other - */ - enum {NOMATTER_MODE, SELECT_MODE, INSERT_MODE} resolve_mode; - - void init_query(); void init_select(); st_select_lex_unit* master_unit(); @@ -903,7 +883,30 @@ typedef struct st_lex bool can_not_use_merged(); bool only_view_structure(); bool need_correct_ident(); + uint8 get_effective_with_check(st_table_list *view); + /* + Is this update command where 'WHITH CHECK OPTION' clause is important + SYNOPSIS + st_lex::which_check_option_applicable() + + RETURN + TRUE have to take 'WHITH CHECK OPTION' clause into account + FALSE 'WHITH CHECK OPTION' clause do not need + */ + inline bool which_check_option_applicable() + { + switch (sql_command) { + case SQLCOM_UPDATE: + case SQLCOM_UPDATE_MULTI: + case SQLCOM_INSERT: + case SQLCOM_INSERT_SELECT: + case SQLCOM_LOAD: + return TRUE; + default: + return FALSE; + } + } inline bool requires_prelocking() { return test(query_tables_own_last); diff --git a/sql/sql_load.cc b/sql/sql_load.cc index cc25839bcc9..1ec209aba85 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -149,7 +149,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } if (open_and_lock_tables(thd, table_list)) DBUG_RETURN(TRUE); - if (setup_tables(thd, table_list, &unused_conds, + if (setup_tables(thd, &thd->lex->select_lex.context, + table_list, &unused_conds, &thd->lex->select_lex.leaf_tables, FALSE)) DBUG_RETURN(-1); if (!table_list->table || // do not suport join view @@ -159,6 +160,11 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "LOAD"); DBUG_RETURN(TRUE); } + if (table_list->prepare_where(thd, 0, TRUE) || + table_list->prepare_check_option(thd)) + { + DBUG_RETURN(TRUE); + } /* Let us emit an error if we are loading data to table which is used in subselect in SET clause like we do it for INSERT. @@ -186,16 +192,16 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, Let us also prepare SET clause, altough it is probably empty in this case. */ - if (setup_fields(thd, 0, table_list, set_fields, 1, 0, 0) || - setup_fields(thd, 0, table_list, set_values, 1, 0, 0)) + if (setup_fields(thd, 0, set_fields, 1, 0, 0) || + setup_fields(thd, 0, set_values, 1, 0, 0)) DBUG_RETURN(TRUE); } else { // Part field list /* TODO: use this conds for 'WITH CHECK OPTIONS' */ - if (setup_fields(thd, 0, table_list, fields_vars, 1, 0, 0) || - setup_fields(thd, 0, table_list, set_fields, 1, 0, 0) || - check_that_all_fields_are_given_values(thd, table)) + if (setup_fields(thd, 0, fields_vars, 1, 0, 0) || + setup_fields(thd, 0, set_fields, 1, 0, 0) || + check_that_all_fields_are_given_values(thd, table, table_list)) DBUG_RETURN(TRUE); /* Check whenever TIMESTAMP field with auto-set feature specified @@ -209,7 +215,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, check_that_all_fields_are_given_values() and setting use_timestamp since it may update query_id for some fields. */ - if (setup_fields(thd, 0, table_list, set_values, 1, 0, 0)) + if (setup_fields(thd, 0, set_values, 1, 0, 0)) DBUG_RETURN(TRUE); } diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc index 831b15cf7ef..71e8fe4149f 100644 --- a/sql/sql_olap.cc +++ b/sql/sql_olap.cc @@ -77,7 +77,8 @@ static int make_new_olap_select(LEX *lex, SELECT_LEX *select_lex, List<Item> new { not_found= 0; ((Item_field*)new_item)->db_name=iif->db_name; - Item_field *new_one=new Item_field(iif->db_name, iif->table_name, iif->field_name); + Item_field *new_one=new Item_field(&select_lex->context, + iif->db_name, iif->table_name, iif->field_name); privlist.push_back(new_one); if (add_to_list(new_select->group_list,new_one,1)) return 1; @@ -152,12 +153,11 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex) List<Item> all_fields(select_lex->item_list); - if (setup_tables(lex->thd, (TABLE_LIST *)select_lex->table_list.first + if (setup_tables(lex->thd, &select_lex->context, + (TABLE_LIST *)select_lex->table_list.first &select_lex->where, &select_lex->leaf_tables, FALSE) || - setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first, - select_lex->item_list, 1, &all_fields,1) || - setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first, - item_list_copy, 1, &all_fields, 1)) + setup_fields(lex->thd, 0, select_lex->item_list, 1, &all_fields,1) || + setup_fields(lex->thd, 0, item_list_copy, 1, &all_fields, 1)) return -1; if (select_lex->olap == CUBE_TYPE) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d6a719e65f9..a57ad84da5b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2289,6 +2289,10 @@ mysql_execute_command(THD *thd) lex->first_lists_tables_same(); /* should be assigned after making first tables same */ all_tables= lex->query_tables; + /* set context for commands which do not use setup_tables */ + select_lex-> + context.resolve_in_table_list_only((TABLE_LIST*)select_lex-> + table_list.first); /* Reset warning count for each query that uses tables @@ -2351,10 +2355,6 @@ mysql_execute_command(THD *thd) } #endif /* !HAVE_REPLICATION */ - - - - /* When option readonly is set deny operations which change tables. Except for the replication thread and the 'super' users. @@ -2572,7 +2572,7 @@ mysql_execute_command(THD *thd) goto error; /* PURGE MASTER LOGS BEFORE 'data' */ it= (Item *)lex->value_list.head(); - if ((!it->fixed &&it->fix_fields(lex->thd, 0, &it)) || + if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) { my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE"); @@ -2881,9 +2881,7 @@ mysql_execute_command(THD *thd) CREATE from SELECT give its SELECT_LEX for SELECT, and item_list belong to SELECT */ - select_lex->resolve_mode= SELECT_LEX::SELECT_MODE; res= handle_select(thd, lex, result, 0); - select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE; delete result; } /* reset for PS */ @@ -3222,6 +3220,8 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if ((res= insert_precheck(thd, all_tables))) break; + /* Skip first table, which is the table we are inserting in */ + select_lex->context.table_list= first_table->next_local; res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values, lex->update_list, lex->value_list, lex->duplicates, lex->ignore); @@ -3232,6 +3232,7 @@ end_with_restore_list: case SQLCOM_REPLACE_SELECT: case SQLCOM_INSERT_SELECT: { + select_result *result; DBUG_ASSERT(first_table == all_tables && first_table != 0); if ((res= insert_precheck(thd, all_tables))) break; @@ -3243,27 +3244,24 @@ end_with_restore_list: /* Don't unlock tables until command is written to binary log */ select_lex->options|= SELECT_NO_UNLOCK; - select_result *result; unit->set_limit(select_lex); - if (!(res= open_and_lock_tables(thd, all_tables))) { /* Skip first table, which is the table we are inserting in */ select_lex->table_list.first= (byte*)first_table->next_local; res= mysql_insert_select_prepare(thd); + lex->select_lex.context.table_list= first_table->next_local; if (!res && (result= new select_insert(first_table, first_table->table, &lex->field_list, - &lex->update_list, &lex->value_list, + &lex->update_list, + &lex->value_list, lex->duplicates, lex->ignore))) { - /* - insert/replace from SELECT give its SELECT_LEX for SELECT, - and item_list belong to SELECT - */ - select_lex->resolve_mode= SELECT_LEX::SELECT_MODE; + /* Skip first table, which is the table we are inserting in */ + select_lex->context.table_list= first_table->next_local; + res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE); - select_lex->resolve_mode= SELECT_LEX::INSERT_MODE; delete result; } /* revert changes for SP */ @@ -3863,7 +3861,7 @@ end_with_restore_list: { Item *it= (Item *)lex->value_list.head(); - if ((!it->fixed && it->fix_fields(lex->thd, 0, &it)) || it->check_cols(1)) + if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) { my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY), MYF(0)); @@ -5230,16 +5228,27 @@ mysql_new_select(LEX *lex, bool move_down) unit->link_prev= 0; unit->return_to= lex->current_select; select_lex->include_down(unit); - /* TODO: assign resolve_mode for fake subquery after merging with new tree */ + /* + By default we assume that it is usual subselect and we have outer name + resolution context, if no we will assign it to 0 later + */ + select_lex->context.outer_context= &select_lex->outer_select()->context; } else { + Name_resolution_context *outer_context; if (lex->current_select->order_list.first && !lex->current_select->braces) { my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY"); DBUG_RETURN(1); } select_lex->include_neighbour(lex->current_select); + /* + we are not sure that we have one level of SELECTs above, so we take + outer_context address from first select of unit + */ + outer_context= + select_lex->master_unit()->first_select()->context.outer_context; SELECT_LEX_UNIT *unit= select_lex->master_unit(); SELECT_LEX *fake= unit->fake_select_lex; if (!fake) @@ -5256,13 +5265,23 @@ mysql_new_select(LEX *lex, bool move_down) fake->make_empty_select(); fake->linkage= GLOBAL_OPTIONS_TYPE; fake->select_limit= 0; + + fake->context.outer_context= outer_context; + /* allow item list resolving in fake select for ORDER BY */ + fake->context.resolve_in_select_list= TRUE; + fake->context.select_lex= fake; } + select_lex->context.outer_context= outer_context; } select_lex->master_unit()->global_parameters= select_lex; select_lex->include_global((st_select_lex_node**)&lex->all_selects_list); lex->current_select= select_lex; - select_lex->resolve_mode= SELECT_LEX::SELECT_MODE; + /* + in subquery is SELECT query and we allow resolution of names in SELECT + list + */ + select_lex->context.resolve_in_select_list= TRUE; DBUG_RETURN(0); } @@ -6381,9 +6400,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, */ /* - Writing this command to the binlog may result in infinite loops when doing - mysqlbinlog|mysql, and anyway it does not really make sense to log it - automatically (would cause more trouble to users than it would help them) + Writing this command to the binlog may result in infinite loops + when doing mysqlbinlog|mysql, and anyway it does not really make + sense to log it automatically (would cause more trouble to users + than it would help them) */ tmp_write_to_binlog= 0; mysql_log.new_file(1); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index c97cb037f15..53f706bd0f6 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -917,12 +917,12 @@ static bool mysql_test_insert(Prepared_statement *stmt, goto error; /* - open temporary memory pool for temporary data allocated by derived - tables & preparation procedure - Note that this is done without locks (should not be needed as we will not - access any data here) - If we would use locks, then we have to ensure we are not using - TL_WRITE_DELAYED as having two such locks can cause table corruption. + open temporary memory pool for temporary data allocated by derived + tables & preparation procedure + Note that this is done without locks (should not be needed as we will not + access any data here) + If we would use locks, then we have to ensure we are not using + TL_WRITE_DELAYED as having two such locks can cause table corruption. */ if (open_normal_and_derived_tables(thd, table_list)) goto error; @@ -939,9 +939,9 @@ static bool mysql_test_insert(Prepared_statement *stmt, table_list->table->insert_values=(byte *)1; } - if (mysql_prepare_insert(thd, table_list, table_list->table, fields, - values, update_fields, update_values, duplic, - &unused_conds, FALSE)) + if (mysql_prepare_insert(thd, table_list, table_list->table, + fields, values, update_fields, update_values, + duplic, &unused_conds, FALSE)) goto error; value_count= values->elements; @@ -963,7 +963,7 @@ static bool mysql_test_insert(Prepared_statement *stmt, my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter); goto error; } - if (setup_fields(thd, 0, table_list, *values, 0, 0, 0)) + if (setup_fields(thd, 0, *values, 0, 0, 0)) goto error; } } @@ -1039,9 +1039,9 @@ static int mysql_test_update(Prepared_statement *stmt, table_list->grant.want_privilege= want_privilege; table_list->table->grant.want_privilege= want_privilege; #endif - thd->lex->select_lex.no_wrap_view_item= 1; - res= setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0); - thd->lex->select_lex.no_wrap_view_item= 0; + thd->lex->select_lex.no_wrap_view_item= TRUE; + res= setup_fields(thd, 0, select->item_list, 1, 0, 0); + thd->lex->select_lex.no_wrap_view_item= FALSE; if (res) goto error; #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -1050,7 +1050,7 @@ static int mysql_test_update(Prepared_statement *stmt, table_list->table->grant.want_privilege= (SELECT_ACL & ~table_list->table->grant.privilege); #endif - if (setup_fields(thd, 0, table_list, stmt->lex->value_list, 0, 0, 0)) + if (setup_fields(thd, 0, stmt->lex->value_list, 0, 0, 0)) goto error; /* TODO: here we should send types of placeholders to the client. */ DBUG_RETURN(0); @@ -1119,6 +1119,8 @@ static bool mysql_test_select(Prepared_statement *stmt, SELECT_LEX_UNIT *unit= &lex->unit; DBUG_ENTER("mysql_test_select"); + lex->select_lex.context.resolve_in_select_list= TRUE; + #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL; if (tables) @@ -1207,7 +1209,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt, if (open_and_lock_tables(thd, tables)) DBUG_RETURN(TRUE); - DBUG_RETURN(setup_fields(thd, 0, 0, *values, 0, 0, 0)); + DBUG_RETURN(setup_fields(thd, 0, *values, 0, 0, 0)); } @@ -1277,6 +1279,8 @@ static bool select_like_stmt_test(Prepared_statement *stmt, THD *thd= stmt->thd; LEX *lex= stmt->lex; + lex->select_lex.context.resolve_in_select_list= TRUE; + if (specific_prepare && (*specific_prepare)(thd)) DBUG_RETURN(TRUE); @@ -1354,9 +1358,8 @@ static bool mysql_test_create_table(Prepared_statement *stmt) if (select_lex->item_list.elements) { - select_lex->resolve_mode= SELECT_LEX::SELECT_MODE; + select_lex->context.resolve_in_select_list= TRUE; res= select_like_stmt_test_with_open_n_lock(stmt, tables, 0, 0); - select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE; } /* put tables back for PS rexecuting */ @@ -1446,16 +1449,21 @@ error: static bool mysql_insert_select_prepare_tester(THD *thd) { + TABLE_LIST *first; + bool res; SELECT_LEX *first_select= &thd->lex->select_lex; /* Skip first table, which is the table we are inserting in */ - first_select->table_list.first= (byte*)((TABLE_LIST*)first_select-> - table_list.first)->next_local; + first_select->table_list.first= (byte*)(first= + ((TABLE_LIST*)first_select-> + table_list.first)->next_local); + res= mysql_insert_select_prepare(thd); /* insert/replace from SELECT give its SELECT_LEX for SELECT, and item_list belong to SELECT */ - first_select->resolve_mode= SELECT_LEX::SELECT_MODE; - return mysql_insert_select_prepare(thd); + thd->lex->select_lex.context.resolve_in_select_list= TRUE; + thd->lex->select_lex.context.table_list= first; + return res; } @@ -1493,12 +1501,12 @@ static int mysql_test_insert_select(Prepared_statement *stmt, first_local_table= (TABLE_LIST *)lex->select_lex.table_list.first; DBUG_ASSERT(first_local_table != 0); - res= select_like_stmt_test_with_open_n_lock(stmt, tables, - &mysql_insert_select_prepare_tester, - OPTION_SETUP_TABLES_DONE); + res= + select_like_stmt_test_with_open_n_lock(stmt, tables, + &mysql_insert_select_prepare_tester, + OPTION_SETUP_TABLES_DONE); /* revert changes made by mysql_insert_select_prepare_tester */ lex->select_lex.table_list.first= (byte*) first_local_table; - lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE; return res; } @@ -1538,6 +1546,10 @@ static bool check_prepared_statement(Prepared_statement *stmt, lex->first_lists_tables_same(); tables= lex->query_tables; + /* set context for commands which do not use setup_tables */ + lex->select_lex.context.resolve_in_table_list_only(select_lex-> + get_table_list()); + switch (sql_command) { case SQLCOM_REPLACE: case SQLCOM_INSERT: @@ -1813,18 +1825,9 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, void init_stmt_after_parse(THD *thd, LEX *lex) { SELECT_LEX *sl= lex->all_selects_list; - /* - Save WHERE clause pointers, because they may be changed during query - optimisation. - */ - for (; sl; sl= sl->next_select_in_list()) - { - sl->prep_where= sl->where; - sl->uncacheable&= ~UNCACHEABLE_PREPARE; - } - for (TABLE_LIST *table= lex->query_tables; table; table= table->next_global) - table->prep_on_expr= table->on_expr; + for (; sl; sl= sl->next_select_in_list()) + sl->uncacheable&= ~UNCACHEABLE_PREPARE; } @@ -2203,13 +2206,15 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) ulong num_rows= uint4korr(packet+4); Prepared_statement *stmt; Statement stmt_backup; + Cursor *cursor; DBUG_ENTER("mysql_stmt_fetch"); statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch"))) DBUG_VOID_RETURN; - if (!stmt->cursor || !stmt->cursor->is_open()) + cursor= stmt->cursor; + if (!cursor || !cursor->is_open()) { my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0), stmt_id); DBUG_VOID_RETURN; @@ -2222,22 +2227,27 @@ 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 - stmt->cursor->fetch(num_rows); + cursor->fetch(num_rows); thd->protocol= &thd->protocol_simple; // Use normal protocol if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); - thd->restore_backup_statement(stmt, &stmt_backup); - thd->current_arena= thd; - - if (!stmt->cursor->is_open()) + if (!cursor->is_open()) { /* We're done with the fetch: reset PS for next execution */ cleanup_stmt_and_thd_after_use(stmt, thd); reset_stmt_params(stmt); + /* + Must be the last, as some momory is still needed for + the previous calls. + */ + free_root(cursor->mem_root, MYF(0)); } + thd->restore_backup_statement(stmt, &stmt_backup); + thd->current_arena= thd; + DBUG_VOID_RETURN; } @@ -2264,14 +2274,21 @@ void mysql_stmt_reset(THD *thd, char *packet) /* There is always space for 4 bytes in buffer */ ulong stmt_id= uint4korr(packet); Prepared_statement *stmt; + Cursor *cursor; DBUG_ENTER("mysql_stmt_reset"); statistic_increment(thd->status_var.com_stmt_reset, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset"))) DBUG_VOID_RETURN; - if (stmt->cursor && stmt->cursor->is_open()) - stmt->cursor->close(); + cursor= stmt->cursor; + if (cursor && cursor->is_open()) + { + thd->change_list= cursor->change_list; + cursor->close(FALSE); + cleanup_stmt_and_thd_after_use(stmt, thd); + free_root(cursor->mem_root, MYF(0)); + } stmt->state= Query_arena::PREPARED; @@ -2430,6 +2447,8 @@ Prepared_statement::~Prepared_statement() if (cursor) cursor->Cursor::~Cursor(); free_items(); + if (cursor) + free_root(cursor->mem_root, MYF(0)); delete lex->result; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 13c5c7cd716..66e783a2103 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -28,8 +28,6 @@ #include <hash.h> #include <ft_global.h> -typedef uint32 cache_rec_length_type; - const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref", "MAYBE_REF","ALL","range","index","fulltext", "ref_or_null","unique_subquery","index_subquery", @@ -182,10 +180,10 @@ static void reset_cache_read(JOIN_CACHE *cache); static void reset_cache_write(JOIN_CACHE *cache); static void read_cached_record(JOIN_TAB *tab); static bool cmp_buffer_with_ref(JOIN_TAB *tab); -static bool setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, - List<Item> &all_fields,ORDER *new_order); -static ORDER *create_distinct_group(THD *thd, ORDER *order, - List<Item> &fields, +static bool setup_new_fields(THD *thd, List<Item> &fields, + List<Item> &all_fields, ORDER *new_order); +static ORDER *create_distinct_group(THD *thd, Item **ref_pointer_array, + ORDER *order, List<Item> &fields, bool *all_order_by_fields_used); static bool test_if_subpart(ORDER *a,ORDER *b); static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables); @@ -283,6 +281,7 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array, save_allow_sum_func= thd->allow_sum_func; thd->allow_sum_func= 0; res= setup_conds(thd, tables, leaves, conds); + thd->allow_sum_func= save_allow_sum_func; res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields, order); @@ -339,11 +338,12 @@ JOIN::prepare(Item ***rref_pointer_array, /* Check that all tables, fields, conds and order are ok */ if ((!(select_options & OPTION_SETUP_TABLES_DONE) && - setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables, + setup_tables(thd, &select_lex->context, + tables_list, &conds, &select_lex->leaf_tables, FALSE)) || setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) || select_lex->setup_ref_array(thd, og_num) || - setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1, + setup_fields(thd, (*rref_pointer_array), fields_list, 1, &all_fields, 1) || setup_without_group(thd, (*rref_pointer_array), tables_list, select_lex->leaf_tables, fields_list, @@ -359,7 +359,7 @@ JOIN::prepare(Item ***rref_pointer_array, thd->allow_sum_func=1; select_lex->having_fix_field= 1; bool having_fix_rc= (!having->fixed && - (having->fix_fields(thd, tables_list, &having) || + (having->fix_fields(thd, &having) || having->check_cols(1))); select_lex->having_fix_field= 0; if (having_fix_rc || thd->net.report_error) @@ -432,7 +432,7 @@ JOIN::prepare(Item ***rref_pointer_array, goto err; /* purecov: inspected */ if (procedure) { - if (setup_new_fields(thd, tables_list, fields_list, all_fields, + if (setup_new_fields(thd, fields_list, all_fields, procedure->param_fields)) goto err; /* purecov: inspected */ if (procedure->group) @@ -566,7 +566,7 @@ JOIN::optimize() Item_cond_and can't be fixed after creation, so we do not check conds->fixed */ - conds->fix_fields(thd, tables_list, &conds); + conds->fix_fields(thd, &conds); conds->change_ref_to_fields(thd, tables_list); conds->top_level_item(); having= 0; @@ -779,7 +779,8 @@ JOIN::optimize() bool all_order_fields_used; if (order) skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1); - if ((group_list=create_distinct_group(thd, order, fields_list, + if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array, + order, fields_list, &all_order_fields_used))) { bool skip_group= (skip_sort_order && @@ -1117,7 +1118,6 @@ int JOIN::reinit() { DBUG_ENTER("JOIN::reinit"); - first_record= 0; if (exec_tmp_table1) @@ -1737,6 +1737,7 @@ Cursor::init_from_thd(THD *thd) lock= thd->lock; query_id= thd->query_id; free_list= thd->free_list; + change_list= thd->change_list; reset_thd(thd); /* XXX: thd->locked_tables is not changed. @@ -1753,6 +1754,7 @@ Cursor::reset_thd(THD *thd) thd->open_tables= 0; thd->lock= 0; thd->free_list= 0; + thd->change_list.empty(); } @@ -1826,6 +1828,7 @@ Cursor::fetch(ulong num_rows) thd->open_tables= open_tables; thd->lock= lock; thd->query_id= query_id; + thd->change_list= change_list; /* save references to memory, allocated during fetch */ thd->set_n_backup_item_arena(this, &backup_arena); @@ -1842,10 +1845,8 @@ Cursor::fetch(ulong num_rows) #ifdef USING_TRANSACTIONS ha_release_temporary_latches(thd); #endif - + /* Grab free_list here to correctly free it in close */ thd->restore_backup_item_arena(this, &backup_arena); - DBUG_ASSERT(thd->free_list == 0); - reset_thd(thd); if (error == NESTED_LOOP_CURSOR_LIMIT) { @@ -1853,10 +1854,12 @@ Cursor::fetch(ulong num_rows) thd->server_status|= SERVER_STATUS_CURSOR_EXISTS; ::send_eof(thd); thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS; + change_list= thd->change_list; + reset_thd(thd); } else { - close(); + close(TRUE); if (error == NESTED_LOOP_OK) { thd->server_status|= SERVER_STATUS_LAST_ROW_SENT; @@ -1871,7 +1874,7 @@ Cursor::fetch(ulong num_rows) void -Cursor::close() +Cursor::close(bool is_active) { THD *thd= join->thd; DBUG_ENTER("Cursor::close"); @@ -1884,6 +1887,10 @@ Cursor::close() (void) unit->cleanup(); else (void) join->select_lex->cleanup(); + + if (is_active) + close_thread_tables(thd); + else { /* XXX: Another hack: closing tables used in the cursor */ DBUG_ASSERT(lock || open_tables || derived_tables); @@ -1903,11 +1910,7 @@ Cursor::close() join= 0; unit= 0; free_items(); - /* - Must be last, as some memory might be allocated for free purposes, - like in free_tmp_table() (TODO: fix this issue) - */ - free_root(mem_root, MYF(0)); + change_list.empty(); DBUG_VOID_RETURN; } @@ -1915,7 +1918,7 @@ Cursor::close() Cursor::~Cursor() { if (is_open()) - close(); + close(FALSE); } /*********************************************************************/ @@ -1977,6 +1980,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array, bool free_join= 1; DBUG_ENTER("mysql_select"); + select_lex->context.resolve_in_select_list= TRUE; JOIN *join; if (select_lex->join != 0) { @@ -7445,7 +7449,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top) conds->top_level_item(); /* conds is always a new item as both cond and on_expr existed */ DBUG_ASSERT(!conds->fixed); - conds->fix_fields(join->thd, 0, &conds); + conds->fix_fields(join->thd, &conds); } else conds= table->on_expr; @@ -7666,7 +7670,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) cond->fixed, also it do not need tables so we use 0 as second argument. */ - cond->fix_fields(thd, 0, &cond); + cond->fix_fields(thd, &cond); } thd->insert_id(0); // Clear for next request } @@ -7685,7 +7689,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) cond->fixed, also it do not need tables so we use 0 as second argument. */ - cond->fix_fields(thd, 0, &cond); + cond->fix_fields(thd, &cond); } } } @@ -7957,7 +7961,9 @@ Field *create_tmp_field_for_schema(THD *thd, Item *item, TABLE *table) Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Item ***copy_func, Field **from_field, - bool group, bool modify_item, uint convert_blob_length) + bool group, bool modify_item, + bool table_cant_handle_bit_fields, + uint convert_blob_length) { switch (type) { case Item::SUM_FUNC_ITEM: @@ -7972,15 +7978,20 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::DEFAULT_VALUE_ITEM: { Item_field *field= (Item_field*) item; + if (table_cant_handle_bit_fields && field->field->type() == FIELD_TYPE_BIT) + return create_tmp_field_from_item(thd, item, table, copy_func, + modify_item, convert_blob_length); return create_tmp_field_from_field(thd, (*from_field= field->field), item->name, table, modify_item ? (Item_field*) item : NULL, convert_blob_length); } case Item::REF_ITEM: - if ( item->real_item()->type() == Item::FIELD_ITEM) + { + Item *tmp_item; + if ((tmp_item= item->real_item())->type() == Item::FIELD_ITEM) { - Item_field *field= (Item_field*) *((Item_ref*)item)->ref; + Item_field *field= (Item_field*) tmp_item; Field *new_field= create_tmp_field_from_field(thd, (*from_field= field->field), item->name, table, @@ -7990,6 +8001,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, item->set_result_field(new_field); return new_field; } + } case Item::FUNC_ITEM: case Item::COND_ITEM: case Item::FIELD_AVG_ITEM: @@ -8192,6 +8204,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, Field *new_field= create_tmp_field(thd, table, arg, arg->type(), ©_func, tmp_from_field, group != 0,not_all_columns, + group || distinct, param->convert_blob_length); if (!new_field) goto err; // Should be OOM @@ -8202,6 +8215,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, *blob_field++= (uint) (reg_field - table->field); blob_count++; } + new_field->field_index= (uint) (reg_field - table->field); *(reg_field++)= new_field; if (new_field->real_type() == MYSQL_TYPE_STRING || new_field->real_type() == MYSQL_TYPE_VARCHAR) @@ -8239,7 +8253,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, create_tmp_field_for_schema(thd, item, table) : create_tmp_field(thd, table, item, type, ©_func, tmp_from_field, group != 0, - not_all_columns || group !=0, + not_all_columns || group != 0, 0, param->convert_blob_length); if (!new_field) @@ -8267,6 +8281,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, new_field->flags|= GROUP_FLAG; } new_field->query_id= thd->query_id; + new_field->field_index= (uint) (reg_field - table->field); *(reg_field++) =new_field; } if (!--hidden_field_count) @@ -8377,6 +8392,13 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, } else field->move_field((char*) pos,(uchar*) 0,0); + if (field->type() == FIELD_TYPE_BIT) + { + /* We have to reserve place for extra bits among null bits */ + ((Field_bit*) field)->set_bit_ptr(null_flags + null_count / 8, + null_count & 7); + null_count+= (field->field_length & 7); + } field->reset(); if (from_field[i]) { /* Not a table Item */ @@ -11168,8 +11190,7 @@ static bool fix_having(JOIN *join, Item **having) else // This should never happen if (!(table->select->cond= new Item_cond_and(table->select->cond, sort_table_cond)) || - table->select->cond->fix_fields(join->thd, join->tables_list, - &table->select->cond)) + table->select->cond->fix_fields(join->thd, &table->select->cond)) return 1; table->select_cond=table->select->cond; table->select_cond->top_level_item(); @@ -11619,7 +11640,7 @@ used_blob_length(CACHE_FIELD **ptr) static bool store_record_in_cache(JOIN_CACHE *cache) { - cache_rec_length_type length; + uint length; uchar *pos; CACHE_FIELD *copy,*end_field; bool last_record; @@ -11664,9 +11685,9 @@ store_record_in_cache(JOIN_CACHE *cache) end > str && end[-1] == ' ' ; end--) ; length=(uint) (end-str); - memcpy(pos+sizeof(length), str, length); - memcpy_fixed(pos, &length, sizeof(length)); - pos+= length+sizeof(length); + memcpy(pos+2, str, length); + int2store(pos, length); + pos+= length+2; } else { @@ -11700,7 +11721,7 @@ static void read_cached_record(JOIN_TAB *tab) { uchar *pos; - cache_rec_length_type length; + uint length; bool last_record; CACHE_FIELD *copy,*end_field; @@ -11729,10 +11750,10 @@ read_cached_record(JOIN_TAB *tab) { if (copy->strip) { - memcpy_fixed(&length, pos, sizeof(length)); - memcpy(copy->str, pos+sizeof(length), length); + length= uint2korr(pos); + memcpy(copy->str, pos+2, length); memset(copy->str+length, ' ', copy->length-length); - pos+= sizeof(length)+length; + pos+= 2 + length; } else { @@ -11769,12 +11790,10 @@ cp_buffer_from_ref(THD *thd, TABLE_REF *ref) thd->count_cuted_fields= CHECK_FIELD_IGNORE; for (store_key **copy=ref->key_copy ; *copy ; copy++) { - int res; - if ((res= (*copy)->copy())) + if ((*copy)->copy() & 1) { thd->count_cuted_fields= save_count_cuted_fields; - if ((res= res & 1)) - return res; // Something went wrong + return 1; // Something went wrong } } thd->count_cuted_fields= save_count_cuted_fields; @@ -11791,14 +11810,13 @@ cp_buffer_from_ref(THD *thd, TABLE_REF *ref) SYNOPSIS find_order_in_list() - thd [in] Pointer to current thread structure - ref_pointer_array [in/out] All select, group and order by fields - tables [in] List of tables to search in (usually FROM clause) - order [in] Column reference to be resolved - fields [in] List of fields to search in (usually SELECT list) - all_fields [in/out] All select, group and order by fields - is_group_field [in] True if order is a GROUP field, false if - ORDER by field + thd Pointer to current thread structure + ref_pointer_array All select, group and order by fields + tables List of tables to search in (usually FROM clause) + order Column reference to be resolved + fields List of fields to search in (usually SELECT list) + all_fields All select, group and order by fields + is_group_field True if order is a GROUP field, false if ORDER by field DESCRIPTION Given a column reference (represented by 'order') from a GROUP BY or ORDER @@ -11815,6 +11833,8 @@ cp_buffer_from_ref(THD *thd, TABLE_REF *ref) RETURN FALSE if OK TRUE if error occurred + + ref_pointer_array and all_fields are updated */ static bool @@ -11860,26 +11880,25 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, original field name, we should additionaly check if we have conflict for this name (in case if we would perform lookup in all tables). */ - if (unaliased && !order_item->fixed && order_item->fix_fields(thd, tables, - order->item)) + if (unaliased && !order_item->fixed && + order_item->fix_fields(thd, order->item)) return TRUE; /* Lookup the current GROUP field in the FROM clause. */ order_item_type= order_item->type(); + from_field= (Field*) not_found_field; if (is_group_field && order_item_type == Item::FIELD_ITEM || order_item_type == Item::REF_ITEM) { from_field= find_field_in_tables(thd, (Item_ident*) order_item, tables, - &view_ref, IGNORE_ERRORS, TRUE); - if(!from_field) - from_field= (Field*) not_found_field; + &view_ref, IGNORE_ERRORS, TRUE, + FALSE); + if (!from_field) + from_field= (Field*) not_found_field; } - else - from_field= (Field*) not_found_field; if (from_field == not_found_field || - from_field && (from_field != view_ref_found ? /* it is field of base table => check that fields are same */ ((*select_item)->type() == Item::FIELD_ITEM && @@ -11892,43 +11911,46 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, view_ref->type() == Item::REF_ITEM && ((Item_ref *) (*select_item))->ref == ((Item_ref *) view_ref)->ref))) + { /* - If there is no such field in the FROM clause, or it is the same field as - the one found in the SELECT clause, then use the Item created for the - SELECT field. As a result if there was a derived field that 'shadowed' - a table field with the same name, the table field will be chosen over - the derived field. + If there is no such field in the FROM clause, or it is the same field + as the one found in the SELECT clause, then use the Item created for + the SELECT field. As a result if there was a derived field that + 'shadowed' a table field with the same name, the table field will be + chosen over the derived field. */ - { order->item= ref_pointer_array + counter; order->in_field_list=1; return FALSE; } else + { /* - There is a field with the same name in the FROM clause. This is the field - that will be chosen. In this case we issue a warning so the user knows - that the field from the FROM clause overshadows the column reference from - the SELECT list. + There is a field with the same name in the FROM clause. This + is the field that will be chosen. In this case we issue a + warning so the user knows that the field from the FROM clause + overshadows the column reference from the SELECT list. */ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_NON_UNIQ_ERROR, ER(ER_NON_UNIQ_ERROR), from_field->field_name, current_thd->where); + } } order->in_field_list=0; /* - The call to order_item->fix_fields() means that here we resolve 'order_item' - to a column from a table in the list 'tables', or to a column in some outer - query. Exactly because of the second case we come to this point even if - (select_item == not_found_item), inspite of that fix_fields() calls - find_item_in_list() one more time. + The call to order_item->fix_fields() means that here we resolve + 'order_item' to a column from a table in the list 'tables', or to + a column in some outer query. Exactly because of the second case + we come to this point even if (select_item == not_found_item), + inspite of that fix_fields() calls find_item_in_list() one more + time. We check order_item->fixed because Item_func_group_concat can put arguments for which fix_fields already was called. */ if (!order_item->fixed && - (order_item->fix_fields(thd, tables, order->item) || + (order_item->fix_fields(thd, order->item) || (order_item= *order->item)->check_cols(1) || thd->is_fatal_error)) return TRUE; /* Wrong field. */ @@ -12040,7 +12062,7 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, */ static bool -setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, +setup_new_fields(THD *thd, List<Item> &fields, List<Item> &all_fields, ORDER *new_field) { Item **item; @@ -12057,7 +12079,7 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, else { thd->where="procedure list"; - if ((*new_field->item)->fix_fields(thd, tables, new_field->item)) + if ((*new_field->item)->fix_fields(thd, new_field->item)) DBUG_RETURN(1); /* purecov: inspected */ all_fields.push_front(*new_field->item); new_field->item=all_fields.head_ref(); @@ -12073,12 +12095,14 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, */ static ORDER * -create_distinct_group(THD *thd, ORDER *order_list, List<Item> &fields, +create_distinct_group(THD *thd, Item **ref_pointer_array, + ORDER *order_list, List<Item> &fields, bool *all_order_by_fields_used) { List_iterator<Item> li(fields); Item *item; ORDER *order,*group,**prev; + uint index= 0; *all_order_by_fields_used= 1; while ((item=li++)) @@ -12110,11 +12134,17 @@ create_distinct_group(THD *thd, ORDER *order_list, List<Item> &fields, ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER)); if (!ord) return 0; - ord->item=li.ref(); + /* + We have here only field_list (not all_field_list), so we can use + simple indexing of ref_pointer_array (order in the array and in the + list are same) + */ + ord->item= ref_pointer_array + index; ord->asc=1; *prev=ord; prev= &ord->next; } + index++; } *prev=0; return group; @@ -12137,7 +12167,7 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields, param->quick_group=1; while ((field=li++)) { - Item::Type type=field->type(); + Item::Type type=field->real_item()->type(); if (type == Item::FIELD_ITEM) param->field_count++; else if (type == Item::SUM_FUNC_ITEM) @@ -12151,7 +12181,7 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields, for (uint i=0 ; i < sum_item->arg_count ; i++) { - if (sum_item->args[0]->type() == Item::FIELD_ITEM) + if (sum_item->args[0]->real_item()->type() == Item::FIELD_ITEM) param->field_count++; else param->func_count++; @@ -12398,9 +12428,10 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, param->copy_funcs.empty(); for (i= 0; (pos= li++); i++) { - if (pos->type() == Item::FIELD_ITEM) + if (pos->real_item()->type() == Item::FIELD_ITEM) { Item_field *item; + pos= pos->real_item(); if (!(item= new Item_field(thd, ((Item_field*) pos)))) goto err; pos= item; @@ -12855,7 +12886,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) DBUG_RETURN(TRUE); if (!cond->fixed) - cond->fix_fields(thd,(TABLE_LIST *) 0, (Item**)&cond); + cond->fix_fields(thd, (Item**)&cond); if (join_tab->select) { error=(int) cond->add(join_tab->select->cond); @@ -12897,8 +12928,8 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) thd reference to the context expr expression to make replacement group_list list of references to group by items - changed out: returns 1 if item contains a replaced field item - + changed out: returns 1 if item contains a replaced field item + DESCRIPTION The function replaces occurrences of group by fields in expr by ref objects for these fields unless they are under aggregate @@ -12927,6 +12958,7 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, { if (expr->arg_count) { + Name_resolution_context *context= &thd->lex->current_select->context; Item **arg,**arg_end; for (arg= expr->arguments(), arg_end= expr->arguments()+expr->arg_count; @@ -12940,8 +12972,9 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, { if (item->eq(*group_tmp->item,0)) { - Item *new_item; - if(!(new_item= new Item_ref(group_tmp->item, 0, item->name))) + Item *new_item; + if(!(new_item= new Item_ref(context, group_tmp->item, 0, + item->name))) return 1; // fatal_error is set thd->change_item_tree(arg, new_item); *changed= TRUE; diff --git a/sql/sql_select.h b/sql/sql_select.h index 6d33ae2f978..ac3e8898cc6 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -390,6 +390,7 @@ class Cursor: public Sql_alloc, public Query_arena /* List of items created during execution */ query_id_t query_id; public: + Item_change_list change_list; select_send result; /* Temporary implementation as now we replace THD state by value */ @@ -402,7 +403,8 @@ public: void fetch(ulong num_rows); void reset() { join= 0; } bool is_open() const { return join != 0; } - void close(); + + void close(bool is_active); void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; } Cursor(THD *thd); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 12025c82da6..72092db400d 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3240,11 +3240,13 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) { ST_FIELD_INFO *field_info= schema_table->fields_info; + Name_resolution_context *context= &thd->lex->select_lex.context; for ( ; field_info->field_name; field_info++) { if (field_info->old_name) { - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (field) { field->set_name(field_info->old_name, @@ -3264,12 +3266,14 @@ int make_schemata_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) char tmp[128]; LEX *lex= thd->lex; SELECT_LEX *sel= lex->current_select; + Name_resolution_context *context= &sel->context; if (!sel->item_list.elements) { ST_FIELD_INFO *field_info= &schema_table->fields_info[1]; String buffer(tmp,sizeof(tmp), system_charset_info); - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (!field || add_item_to_list(thd, field)) return 1; buffer.length(0); @@ -3291,6 +3295,7 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) char tmp[128]; String buffer(tmp,sizeof(tmp), thd->charset()); LEX *lex= thd->lex; + Name_resolution_context *context= &lex->select_lex.context; ST_FIELD_INFO *field_info= &schema_table->fields_info[2]; buffer.length(0); @@ -3302,7 +3307,8 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) buffer.append(lex->wild->ptr()); buffer.append(")"); } - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (add_item_to_list(thd, field)) return 1; field->set_name(buffer.ptr(), buffer.length(), system_charset_info); @@ -3310,7 +3316,7 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) { field->set_name(buffer.ptr(), buffer.length(), system_charset_info); field_info= &schema_table->fields_info[3]; - field= new Item_field(NullS, NullS, field_info->field_name); + field= new Item_field(context, NullS, NullS, field_info->field_name); if (add_item_to_list(thd, field)) return 1; field->set_name(field_info->old_name, strlen(field_info->old_name), @@ -3325,6 +3331,8 @@ int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int fields_arr[]= {3, 14, 13, 6, 15, 5, 16, 17, 18, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; + Name_resolution_context *context= &thd->lex->select_lex.context; + for (; *field_num >= 0; field_num++) { field_info= &schema_table->fields_info[*field_num]; @@ -3332,7 +3340,8 @@ int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) *field_num == 17 || *field_num == 18)) continue; - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (field) { field->set_name(field_info->old_name, @@ -3351,10 +3360,13 @@ int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int fields_arr[]= {0, 2, 1, 3, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; + Name_resolution_context *context= &thd->lex->select_lex.context; + for (; *field_num >= 0; field_num++) { field_info= &schema_table->fields_info[*field_num]; - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (field) { field->set_name(field_info->old_name, @@ -3373,10 +3385,13 @@ int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int fields_arr[]= {2, 3, 4, 19, 16, 15, 14, 18, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; + Name_resolution_context *context= &thd->lex->select_lex.context; + for (; *field_num >= 0; field_num++) { field_info= &schema_table->fields_info[*field_num]; - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (field) { field->set_name(field_info->old_name, @@ -3442,12 +3457,11 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list) if (table_list->field_translation) { - Field_translator *end= table_list->field_translation + - sel->item_list.elements; + Field_translator *end= table_list->field_translation_end; for (transl= table_list->field_translation; transl < end; transl++) { if (!transl->item->fixed && - transl->item->fix_fields(thd, table_list, &transl->item)) + transl->item->fix_fields(thd, &transl->item)) DBUG_RETURN(1); } DBUG_RETURN(0); @@ -3464,11 +3478,12 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list) { char *name= item->name; transl[i].item= item; - if (!item->fixed && item->fix_fields(thd, table_list, &transl[i].item)) + if (!item->fixed && item->fix_fields(thd, &transl[i].item)) DBUG_RETURN(1); transl[i++].name= name; } table_list->field_translation= transl; + table_list->field_translation_end= transl + sel->item_list.elements; } DBUG_RETURN(0); @@ -3495,7 +3510,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, ST_SCHEMA_TABLE *schema_table= get_schema_table(schema_table_idx); LEX_STRING db, table; DBUG_ENTER("mysql_schema_select"); - /* + /* We have to make non const db_name & table_name because of lower_case_table_names */ @@ -3503,7 +3518,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, information_schema_name.length, 0); make_lex_string(thd, &table, schema_table->table_name, strlen(schema_table->table_name), 0); - if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */ + if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */ !sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0), 0, 0, TL_READ, (List<String> *) 0, (List<String> *) 0)) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e03a6c24d42..b050d46f358 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -267,7 +267,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, table->table_name); else error= 1; - } else { @@ -1734,7 +1733,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, field=item->tmp_table_field(&tmp_table); else field=create_tmp_field(thd, &tmp_table, item, item->type(), - (Item ***) 0, &tmp_field,0,0,0); + (Item ***) 0, &tmp_field, 0, 0, 0, 0); if (!field || !(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ? ((Item_field *)item)->field : @@ -3400,7 +3399,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, */ if (!Field::type_can_have_key_part(cfield->field->type()) || !Field::type_can_have_key_part(cfield->sql_type) || - cfield->field->field_length == key_part_length || + (cfield->field->field_length == key_part_length && + !f_is_blob(key_part->key_type)) || (cfield->length && (cfield->length < key_part_length / key_part->field->charset()->mbmaxlen))) key_part_length= 0; // Use whole field diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 95524a6dfbf..1272d38f729 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -201,7 +201,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables) { trg_field->setup_field(thd, table); if (!trg_field->fixed && - trg_field->fix_fields(thd, (TABLE_LIST *)0, (Item **)0)) + trg_field->fix_fields(thd, (Item **)0)) return 1; } diff --git a/sql/sql_udf.h b/sql/sql_udf.h index 4df3fe0949d..d588572a762 100644 --- a/sql/sql_udf.h +++ b/sql/sql_udf.h @@ -65,8 +65,8 @@ class udf_handler :public Sql_alloc Item_result result_type () const { return u_d ? u_d->returns : STRING_RESULT;} bool get_arguments(); - bool fix_fields(THD *thd,struct st_table_list *tlist,Item_result_field *item, - uint arg_count,Item **args); + bool fix_fields(THD *thd, Item_result_field *item, + uint arg_count, Item **args); void cleanup(); double val(my_bool *null_value) { diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 6e307dda5be..c23f14e980b 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -124,6 +124,13 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd) fake_select_lex->table_list.link_in_list((byte *)&result_table_list, (byte **) &result_table_list.next_local); + for (ORDER *order= (ORDER *)global_parameters->order_list.first; + order; + order=order->next) + { + (*order->item)->walk(&Item::change_context_processor, + (byte *) &fake_select_lex->context); + } } @@ -187,6 +194,8 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, else tmp_result= sel_result; + sl->context.resolve_in_select_list= TRUE; + for (;sl; sl= sl->next_select()) { bool can_skip_order_by; @@ -647,14 +656,14 @@ bool st_select_lex::cleanup() if (join) { DBUG_ASSERT((st_select_lex*)join->select_lex == this); - error|= join->destroy(); + error= join->destroy(); delete join; join= 0; } for (SELECT_LEX_UNIT *lex_unit= first_inner_unit(); lex_unit ; lex_unit= lex_unit->next_unit()) { - error|= lex_unit->cleanup(); + error= (bool) ((uint) error | (uint) lex_unit->cleanup()); } DBUG_RETURN(error); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 6b9a8ddfcb6..ce4a7d6394e 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -67,6 +67,8 @@ static bool check_fields(THD *thd, List<Item> &items) List_iterator<Item> it(items); Item *item; Item_field *field; + Name_resolution_context *context= &thd->lex->select_lex.context; + while ((item= it++)) { if (!(field= item->filed_for_view_update())) @@ -185,14 +187,8 @@ int mysql_update(THD *thd, #ifndef NO_EMBEDDED_ACCESS_CHECKS table_list->grant.want_privilege= table->grant.want_privilege= want_privilege; #endif - { - bool res; - select_lex->no_wrap_view_item= 1; - res= setup_fields(thd, 0, table_list, fields, 1, 0, 0); - select_lex->no_wrap_view_item= 0; - if (res) - DBUG_RETURN(1); /* purecov: inspected */ - } + if (setup_fields_with_no_wrap(thd, 0, fields, 1, 0, 0)) + DBUG_RETURN(1); /* purecov: inspected */ if (table_list->view && check_fields(thd, fields)) { DBUG_RETURN(1); @@ -216,7 +212,7 @@ int mysql_update(THD *thd, table_list->grant.want_privilege= table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); #endif - if (setup_fields(thd, 0, table_list, values, 1, 0, 0)) + if (setup_fields(thd, 0, values, 1, 0, 0)) { free_underlaid_joins(thd, select_lex); DBUG_RETURN(1); /* purecov: inspected */ @@ -557,7 +553,9 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, tables.table= table; tables.alias= table_list->alias; - if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, FALSE) || + if (setup_tables(thd, &select_lex->context, + table_list, conds, &select_lex->leaf_tables, + FALSE) || setup_conds(thd, table_list, select_lex->leaf_tables, conds) || select_lex->setup_ref_array(thd, order_num) || setup_order(thd, select_lex->ref_pointer_array, @@ -617,7 +615,6 @@ bool mysql_multi_update_prepare(THD *thd) TABLE_LIST *tl, *leaves; List<Item> *fields= &lex->select_lex.item_list; table_map tables_for_update; - int res; bool update_view= 0; /* if this multi-update was converted from usual update, here is table @@ -642,15 +639,12 @@ bool mysql_multi_update_prepare(THD *thd) call in setup_tables()). */ - if (setup_tables(thd, table_list, &lex->select_lex.where, + if (setup_tables(thd, &lex->select_lex.context, + table_list, &lex->select_lex.where, &lex->select_lex.leaf_tables, FALSE)) DBUG_RETURN(TRUE); - leaves= lex->select_lex.leaf_tables; - if ((lex->select_lex.no_wrap_view_item= 1, - res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0), - lex->select_lex.no_wrap_view_item= 0, - res)) + if (setup_fields_with_no_wrap(thd, 0, *fields, 1, 0, 0)) DBUG_RETURN(TRUE); for (tl= table_list; tl ; tl= tl->next_local) @@ -672,6 +666,7 @@ bool mysql_multi_update_prepare(THD *thd) /* Setup timestamp handling and locking mode */ + leaves= lex->select_lex.leaf_tables; for (tl= leaves; tl; tl= tl->next_leaf) { TABLE *table= tl->table; @@ -762,12 +757,10 @@ bool mysql_multi_update_prepare(THD *thd) for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global) tbl->cleanup_items(); - if (setup_tables(thd, table_list, &lex->select_lex.where, + if (setup_tables(thd, &lex->select_lex.context, + table_list, &lex->select_lex.where, &lex->select_lex.leaf_tables, FALSE) || - (lex->select_lex.no_wrap_view_item= 1, - res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0), - lex->select_lex.no_wrap_view_item= 0, - res)) + setup_fields_with_no_wrap(thd, 0, *fields, 1, 0, 0)) DBUG_RETURN(TRUE); } @@ -897,7 +890,7 @@ int multi_update::prepare(List<Item> ¬_used_values, reference tables */ - if (setup_fields(thd, 0, all_tables, *values, 1, 0, 0)) + if (setup_fields(thd, 0, *values, 1, 0, 0)) DBUG_RETURN(1); /* diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 0b351407c13..c8abee1e7dc 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -58,13 +58,13 @@ static void make_unique_view_field_name(Item *target, char *name= (target->orig_name ? target->orig_name : target->name); - uint name_len; - uint attempt= 0; + uint name_len, attempt; char buff[NAME_LEN+1]; - for (;; attempt++) + List_iterator_fast<Item> itc(item_list); + + for (attempt= 0;; attempt++) { Item *check; - List_iterator_fast<Item> itc(item_list); bool ok= TRUE; if (attempt) @@ -84,6 +84,7 @@ static void make_unique_view_field_name(Item *target, } while (check != last_element); if (ok) break; + itc.rewind(); } target->orig_name= target->name; @@ -305,13 +306,14 @@ bool mysql_create_view(THD *thd, { Item *item; List_iterator_fast<Item> it(select_lex->item_list); + List_iterator_fast<Item> itc(select_lex->item_list); while ((item= it++)) { Item *check; - List_iterator_fast<Item> itc(select_lex->item_list); /* treat underlying fields like set by user names */ if (item->real_item()->type() == Item::FIELD_ITEM) item->is_autogenerated_name= FALSE; + itc.rewind(); while ((check= itc++) && check != item) { if (my_strcasecmp(system_charset_info, item->name, check->name) == 0) @@ -822,16 +824,30 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) old_lex->can_use_merged()) && !old_lex->can_not_use_merged()) { + List_iterator_fast<TABLE_LIST> ti(view_select->top_join_list); /* lex should contain at least one table */ DBUG_ASSERT(view_tables != 0); table->effective_algorithm= VIEW_ALGORITHM_MERGE; DBUG_PRINT("info", ("algorithm: MERGE")); table->updatable= (table->updatable_view != 0); - table->effective_with_check= (uint8)table->with_check; - - table->ancestor= view_tables; - + table->effective_with_check= + old_lex->get_effective_with_check(table); + + /* prepare view context */ + lex->select_lex.context.resolve_in_table_list_only(table->ancestor= + view_tables); + lex->select_lex.context.outer_context= 0; + lex->select_lex.context.select_lex= table->select_lex; + /* do not check privileges & hide errors for view underlyings */ + for (SELECT_LEX *sl= lex->all_selects_list; + sl; + sl= sl->next_select_in_list()) + { + sl->context.check_privileges= FALSE; + sl->context.error_processor= &view_error_processor; + sl->context.error_processor_data= (void *)table; + } /* Tables of the main select of the view should be marked as belonging to the same select as original view (again we can use LEX::select_lex @@ -852,13 +868,11 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) nested_join->join_list= view_select->top_join_list; /* re-nest tables of VIEW */ + ti.rewind(); + while ((tbl= ti++)) { - List_iterator_fast<TABLE_LIST> ti(nested_join->join_list); - while ((tbl= ti++)) - { - tbl->join_list= &nested_join->join_list; - tbl->embedding= table; - } + tbl->join_list= &nested_join->join_list; + tbl->embedding= table; } } @@ -866,13 +880,12 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) table->where= view_select->where; /* Add subqueries units to SELECT into which we merging current view. - unit(->next)* chain starts with subqueries that are used by this view and continues with subqueries that are used by other views. We must not add any subquery twice (otherwise we'll form a loop), - to do this we remember in end_unit the first subquery that has + to do this we remember in end_unit the first subquery that has been already added. - + NOTE: we do not support UNION here, so we take only one select */ SELECT_LEX_NODE *end_unit= table->select_lex->slave; @@ -1058,9 +1071,9 @@ frm_type_enum mysql_frm_type(char *path) bool check_key_in_view(THD *thd, TABLE_LIST *view) { TABLE *table; - Field_translator *trans; + Field_translator *trans, *end_of_trans; KEY *key_info, *key_info_end; - uint i, elements_in_view; + uint i; DBUG_ENTER("check_key_in_view"); /* @@ -1077,9 +1090,24 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) trans= view->field_translation; key_info_end= (key_info= table->key_info)+ table->s->keys; - elements_in_view= view->view->select_lex.item_list.elements; + end_of_trans= view->field_translation_end; DBUG_ASSERT(table != 0 && view->field_translation != 0); + { + /* + We should be sure that all fields are ready to get keys from them, but + this operation should not have influence on Field::query_id, to avoid + marking as used fields which are not used + */ + bool save_set_query_id= thd->set_query_id; + thd->set_query_id= 0; + for (Field_translator *fld= trans; fld < end_of_trans; fld++) + { + if (!fld->item->fixed && fld->item->fix_fields(thd, &fld->item)) + return TRUE; + } + thd->set_query_id= save_set_query_id; + } /* Loop over all keys to see if a unique-not-null key is used */ for (;key_info != key_info_end ; key_info++) { @@ -1091,15 +1119,15 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) /* check that all key parts are used */ for (;;) { - uint k; - for (k= 0; k < elements_in_view; k++) + Field_translator *k; + for (k= trans; k < end_of_trans; k++) { Item_field *field; - if ((field= trans[k].item->filed_for_view_update()) && + if ((field= k->item->filed_for_view_update()) && field->field == key_part->field) break; } - if (k == elements_in_view) + if (k == end_of_trans) break; // Key is not possible if (++key_part == key_part_end) DBUG_RETURN(FALSE); // Found usable key @@ -1111,19 +1139,20 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) /* check all fields presence */ { Field **field_ptr; + Field_translator *fld; for (field_ptr= table->field; *field_ptr; field_ptr++) { - for (i= 0; i < elements_in_view; i++) + for (fld= trans; fld < end_of_trans; fld++) { Item_field *field; - if ((field= trans[i].item->filed_for_view_update()) && + if ((field= fld->item->filed_for_view_update()) && field->field == *field_ptr) break; } - if (i == elements_in_view) // If field didn't exists + if (fld == end_of_trans) // If field didn't exists { /* - Keys or all fields of underlying tables are not foud => we have + Keys or all fields of underlying tables are not found => we have to check variable updatable_views_with_limit to decide should we issue an error or just a warning */ @@ -1148,6 +1177,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) SYNOPSIS insert_view_fields() + thd thread handler list list for insertion view view for processing @@ -1156,19 +1186,20 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) TRUE error (is not sent to cliet) */ -bool insert_view_fields(List<Item> *list, TABLE_LIST *view) +bool insert_view_fields(THD *thd, List<Item> *list, TABLE_LIST *view) { - uint elements_in_view= view->view->select_lex.item_list.elements; + Field_translator *trans_end; Field_translator *trans; DBUG_ENTER("insert_view_fields"); if (!(trans= view->field_translation)) DBUG_RETURN(FALSE); + trans_end= view->field_translation_end; - for (uint i= 0; i < elements_in_view; i++) + for (Field_translator *entry= trans; entry < trans_end; entry++) { Item_field *fld; - if ((fld= trans[i].item->filed_for_view_update())) + if ((fld= entry->item->filed_for_view_update())) list->push_back(fld); else { diff --git a/sql/sql_view.h b/sql/sql_view.h index 4e6aaf7f477..3246dbae383 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -25,7 +25,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *view, enum_drop_mode drop_mode); bool check_key_in_view(THD *thd, TABLE_LIST * view); -bool insert_view_fields(List<Item> *list, TABLE_LIST *view); +bool insert_view_fields(THD *thd, List<Item> *list, TABLE_LIST *view); frm_type_enum mysql_frm_type(char *path); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 360bc421965..4fc9819d0e1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1259,7 +1259,6 @@ create: THD *thd= YYTHD; LEX *lex= thd->lex; lex->sql_command= SQLCOM_CREATE_VIEW; - lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE; /* first table in list is target VIEW name */ if (!lex->select_lex.add_table_to_list(thd, $5, NULL, 0)) YYABORT; @@ -2114,6 +2113,7 @@ sp_proc_stmt: } | LABEL_SYM IDENT { +#ifdef SP_GOTO LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *ctx= lex->spcont; @@ -2131,9 +2131,14 @@ sp_proc_stmt: lab->ctx= ctx; sp->backpatch(lab); } +#else + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; +#endif } | GOTO_SYM IDENT { +#ifdef SP_GOTO LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *ctx= lex->spcont; @@ -2186,6 +2191,10 @@ sp_proc_stmt: i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */ sp->add_instr(i); } +#else + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; +#endif } | OPEN_SYM ident { @@ -3383,7 +3392,6 @@ alter: LEX *lex= thd->lex; lex->sql_command= SQLCOM_CREATE_VIEW; lex->create_view_mode= VIEW_ALTER; - lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE; /* first table in list is target VIEW name */ lex->select_lex.add_table_to_list(thd, $4, NULL, 0); } @@ -3941,7 +3949,6 @@ select: { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; - lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE; } ; @@ -4095,7 +4102,10 @@ select_item_list: | '*' { THD *thd= YYTHD; - if (add_item_to_list(thd, new Item_field(NULL, NULL, "*"))) + if (add_item_to_list(thd, + new Item_field(&thd->lex->current_select-> + context, + NULL, NULL, "*"))) YYABORT; (thd->lex->current_select->with_wild)++; }; @@ -4393,10 +4403,10 @@ simple_expr: my_error(ER_WRONG_COLUMN_NAME, MYF(0), name->str); YYABORT; } - $$= new Item_default_value($3); + $$= new Item_default_value(&Select->context, $3); } | VALUES '(' simple_ident ')' - { $$= new Item_insert_value($3); } + { $$= new Item_insert_value(&Select->context, $3); } | FUNC_ARG0 '(' ')' { if (!$1.symbol->create_func) @@ -4687,15 +4697,16 @@ simple_expr: name->init_qname(YYTHD); sp_add_to_hash(&lex->spfuns, name); if ($5) - $$= new Item_func_sp(name, *$5); + $$= new Item_func_sp(&lex->current_select->context, name, *$5); else - $$= new Item_func_sp(name); + $$= new Item_func_sp(&lex->current_select->context, name); lex->safe_to_cache_query=0; } | IDENT_sys '(' udf_expr_list ')' { #ifdef HAVE_DLOPEN udf_func *udf; + SELECT_LEX *sel= Select; if (using_udf_functions && (udf=find_udf($1.str, $1.length))) { @@ -4776,9 +4787,9 @@ simple_expr: sp_add_to_hash(&lex->spfuns, name); if ($3) - $$= new Item_func_sp(name, *$3); + $$= new Item_func_sp(&lex->current_select->context, name, *$3); else - $$= new Item_func_sp(name); + $$= new Item_func_sp(&lex->current_select->context, name); lex->safe_to_cache_query=0; } } @@ -4980,8 +4991,10 @@ sum_expr: opt_gconcat_separator ')' { - Select->in_sum_expr--; - $$=new Item_func_group_concat($3,$5,Select->gorder_list,$7); + SELECT_LEX *sel= Select; + sel->in_sum_expr--; + $$=new Item_func_group_concat(&sel->context, $3, $5, + sel->gorder_list, $7); $5->empty(); }; @@ -5400,16 +5413,30 @@ using_list: ident { SELECT_LEX *sel= Select; - if (!($$= new Item_func_eq(new Item_field(sel->db1, sel->table1, + if (!($$= new Item_func_eq(new Item_field(&sel->context, + sel->db1, sel->table1, $1.str), - new Item_field(sel->db2, sel->table2, + new Item_field(&sel->context, + sel->db2, sel->table2, $1.str)))) YYABORT; } | using_list ',' ident { SELECT_LEX *sel= Select; - if (!($$= new Item_cond_and(new Item_func_eq(new Item_field(sel->db1,sel->table1,$3.str), new Item_field(sel->db2,sel->table2,$3.str)), $1))) + if (!($$= + new Item_cond_and(new + Item_func_eq(new + Item_field(&sel->context, + sel->db1, + sel->table1, + $3.str), + new + Item_field(&sel->context, + sel->db2, + sel->table2, + $3.str)), + $1))) YYABORT; }; @@ -5675,7 +5702,10 @@ procedure_clause: lex->proc_list.elements=0; lex->proc_list.first=0; lex->proc_list.next= (byte**) &lex->proc_list.first; - if (add_proc_to_list(lex->thd, new Item_field(NULL,NULL,$2.str))) + if (add_proc_to_list(lex->thd, new Item_field(&lex-> + current_select-> + context, + NULL,NULL,$2.str))) YYABORT; Lex->uncacheable(UNCACHEABLE_SIDEEFFECT); } @@ -5922,7 +5952,6 @@ insert: mysql_init_select(lex); /* for subselects */ lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ; - lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE; } insert_lock_option opt_ignore insert2 { @@ -5940,7 +5969,6 @@ replace: lex->sql_command = SQLCOM_REPLACE; lex->duplicates= DUP_REPLACE; mysql_init_select(lex); - lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE; } replace_lock_option insert2 { @@ -6058,7 +6086,7 @@ values: expr_or_default: expr { $$= $1;} - | DEFAULT {$$= new Item_default_value(); } + | DEFAULT {$$= new Item_default_value(&Select->context); } ; opt_insert_update: @@ -6120,24 +6148,9 @@ insert_update_elem: simple_ident_nospvar equal expr_or_default { LEX *lex= Lex; - uint8 tmp= MY_ITEM_PREFER_1ST_TABLE; if (lex->update_list.push_back($1) || lex->value_list.push_back($3)) YYABORT; - /* - INSERT INTO a1(a) SELECT b1.a FROM b1 ON DUPLICATE KEY - UPDATE a= a + b1.b - - Set MY_ITEM_PREFER_1ST_TABLE flag to $1 and $3 items - to prevent find_field_in_tables() doing further item searching - if it finds item occurence in first table in insert_table_list. - This allows to avoid ambiguity in resolving 'a' field in - example above. - */ - $1->walk(&Item::set_flags_processor, - (byte *) &tmp); - $3->walk(&Item::set_flags_processor, - (byte *) &tmp); }; opt_low_priority: @@ -7027,15 +7040,17 @@ insert_ident: table_wild: ident '.' '*' { - $$ = new Item_field(NullS,$1.str,"*"); - Lex->current_select->with_wild++; + SELECT_LEX *sel= Select; + $$ = new Item_field(&sel->context, NullS, $1.str, "*"); + sel->with_wild++; } | ident '.' ident '.' '*' { - $$ = new Item_field((YYTHD->client_capabilities & + SELECT_LEX *sel= Select; + $$ = new Item_field(&sel->context, (YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str), $3.str,"*"); - Lex->current_select->with_wild++; + sel->with_wild++; } ; @@ -7060,8 +7075,8 @@ simple_ident: SELECT_LEX *sel=Select; $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(NullS,NullS,$1.str) : - (Item*) new Item_ref(NullS,NullS,$1.str); + (Item*) new Item_field(&sel->context, NullS, NullS, $1.str) : + (Item*) new Item_ref(&sel->context, NullS, NullS, $1.str); } } | simple_ident_q { $$= $1; } @@ -7073,8 +7088,8 @@ simple_ident_nospvar: SELECT_LEX *sel=Select; $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(NullS,NullS,$1.str) : - (Item*) new Item_ref(NullS,NullS,$1.str); + (Item*) new Item_field(&sel->context, NullS, NullS, $1.str) : + (Item*) new Item_ref(&sel->context, NullS, NullS, $1.str); } | simple_ident_q { $$= $1; } ; @@ -7111,7 +7126,8 @@ simple_ident_q: YYABORT; } - if (!(trg_fld= new Item_trigger_field(new_row ? + if (!(trg_fld= new Item_trigger_field(&lex->current_select->context, + new_row ? Item_trigger_field::NEW_ROW: Item_trigger_field::OLD_ROW, $3.str))) @@ -7136,8 +7152,8 @@ simple_ident_q: } $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(NullS,$1.str,$3.str) : - (Item*) new Item_ref(NullS,$1.str,$3.str); + (Item*) new Item_field(&sel->context, NullS, $1.str, $3.str) : + (Item*) new Item_ref(&sel->context, NullS, $1.str, $3.str); } } | '.' ident '.' ident @@ -7152,8 +7168,8 @@ simple_ident_q: } $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(NullS,$2.str,$4.str) : - (Item*) new Item_ref(NullS, $2.str, $4.str); + (Item*) new Item_field(&sel->context, NullS, $2.str, $4.str) : + (Item*) new Item_ref(&sel->context, NullS, $2.str, $4.str); } | ident '.' ident '.' ident { @@ -7167,10 +7183,12 @@ simple_ident_q: } $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field((YYTHD->client_capabilities & + (Item*) new Item_field(&sel->context, + (YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str), $3.str, $5.str) : - (Item*) new Item_ref((YYTHD->client_capabilities & + (Item*) new Item_ref(&sel->context, + (YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str), $3.str, $5.str); }; @@ -7414,7 +7432,6 @@ keyword: | INNOBASE_SYM {} | INSERT_METHOD {} | RELAY_THREAD {} - | LABEL_SYM {} | LANGUAGE_SYM {} | LAST_SYM {} | LEAVES {} @@ -7720,11 +7737,13 @@ sys_option_value: it= new Item_null(); } - if (!(trg_fld= new Item_trigger_field(Item_trigger_field::NEW_ROW, + if (!(trg_fld= new Item_trigger_field(&lex->current_select-> + context, + Item_trigger_field::NEW_ROW, $2.base_name.str)) || - !(i= new sp_instr_set_trigger_field( - lex->sphead->instructions(), lex->spcont, - trg_fld, it))) + !(i= new sp_instr_set_trigger_field(lex->sphead-> + instructions(), + lex->spcont, trg_fld, it))) YYABORT; /* diff --git a/sql/table.cc b/sql/table.cc index 6677453969b..fec74c570f3 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -594,6 +594,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, goto err; /* purecov: inspected */ } + reg_field->field_index= i; reg_field->comment=comment; if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag)) { @@ -1713,8 +1714,6 @@ void st_table_list::set_ancestor() } if (tbl->multitable_view) multitable_view= TRUE; - if (tbl->table) - tbl->table->grant= grant; } while ((tbl= tbl->next_local)); if (!multitable_view) @@ -1727,68 +1726,18 @@ void st_table_list::set_ancestor() /* - Save old want_privilege and clear want_privilege - - SYNOPSIS - save_and_clear_want_privilege() -*/ - -void st_table_list::save_and_clear_want_privilege() -{ - for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) - { - if (tbl->table) - { - privilege_backup= tbl->table->grant.want_privilege; - tbl->table->grant.want_privilege= 0; - } - else - { - tbl->save_and_clear_want_privilege(); - } - } -} - - -/* - restore want_privilege saved by save_and_clear_want_privilege - - SYNOPSIS - restore_want_privilege() -*/ - -void st_table_list::restore_want_privilege() -{ - for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) - { - if (tbl->table) - tbl->table->grant.want_privilege= privilege_backup; - else - { - tbl->restore_want_privilege(); - } - } -} - - -/* setup fields of placeholder of merged VIEW SYNOPSIS st_table_list::setup_ancestor() thd - thread handler - conds - condition of this JOIN - check_opt_type - WHITH CHECK OPTION type (VIEW_CHECK_NONE, - VIEW_CHECK_LOCAL, VIEW_CHECK_CASCADED) + NOTES ancestor is list of tables and views used by view (underlying tables/views) DESCRIPTION It is: - - preparing translation table for view columns (fix_fields() for every - call and creation for first call) - - preparing WHERE, ON and CHECK OPTION condition (fix_fields() for every - call and merging for first call). + - preparing translation table for view columns If there are underlying view(s) procedure first will be called for them. RETURN @@ -1796,163 +1745,114 @@ void st_table_list::restore_want_privilege() TRUE - error */ -bool st_table_list::setup_ancestor(THD *thd, Item **conds, - uint8 check_opt_type) +bool st_table_list::setup_ancestor(THD *thd) { - Field_translator *transl; - SELECT_LEX *select= &view->select_lex; - SELECT_LEX *current_select_save= thd->lex->current_select; - byte *main_table_list_save= select_lex->table_list.first; - Item *item; - TABLE_LIST *tbl; - List_iterator_fast<Item> it(select->item_list); - uint i= 0; - enum sub_select_type linkage_save= - select_lex->master_unit()->first_select()->linkage; - bool save_set_query_id= thd->set_query_id; - bool save_wrapper= select_lex->no_wrap_view_item; - bool save_allow_sum_func= thd->allow_sum_func; - bool res= FALSE; DBUG_ENTER("st_table_list::setup_ancestor"); - - if (check_stack_overrun(thd, STACK_MIN_SIZE, (char *)&res)) - return TRUE; - - for (tbl= ancestor; tbl; tbl= tbl->next_local) + if (!field_translation) { - if (tbl->ancestor && - tbl->setup_ancestor(thd, conds, - (check_opt_type == VIEW_CHECK_CASCADED ? - VIEW_CHECK_CASCADED : - VIEW_CHECK_NONE))) + Field_translator *transl; + SELECT_LEX *select= &view->select_lex; + Item *item; + TABLE_LIST *tbl; + List_iterator_fast<Item> it(select->item_list); + uint field_count= 0; + + if (check_stack_overrun(thd, STACK_MIN_SIZE, (char *)&field_count)) + { DBUG_RETURN(TRUE); - } + } - /* - We have to ensure that inside the view we are not referring to any - table outside of the view. We do it by changing the pointers used - by fix_fields to look up tables so that only tables and views in - view are seen. We also set linkage to DERIVED_TABLE_TYPE as a barrier - so that we stop resolving fields as this level. - */ - thd->lex->current_select= select_lex; - select_lex->table_list.first= (byte *)ancestor; - select_lex->master_unit()->first_select()->linkage= DERIVED_TABLE_TYPE; + for (tbl= ancestor; tbl; tbl= tbl->next_local) + { + if (tbl->ancestor && + tbl->setup_ancestor(thd)) + { + DBUG_RETURN(TRUE); + } + } - if (field_translation) - { - DBUG_PRINT("info", ("there are already translation table")); - - select_lex->no_wrap_view_item= 1; - - thd->set_query_id= 1; - /* this view was prepared already on previous PS/SP execution */ - Field_translator *end= field_translation + select->item_list.elements; - /* real rights will be checked in VIEW field */ - save_and_clear_want_privilege(); - /* aggregate function are allowed */ - thd->allow_sum_func= 1; - for (transl= field_translation; transl < end; transl++) + /* Create view fields translation table */ + + if (!(transl= + (Field_translator*)(thd->current_arena-> + alloc(select->item_list.elements * + sizeof(Field_translator))))) { - if (!transl->item->fixed && - transl->item->fix_fields(thd, ancestor, &transl->item)) - goto err; + DBUG_RETURN(TRUE); } - for (tbl= ancestor; tbl; tbl= tbl->next_local) + + while ((item= it++)) { - if (tbl->on_expr && !tbl->on_expr->fixed && - tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr)) - goto err; + transl[field_count].name= item->name; + transl[field_count++].item= item; } - if (where && !where->fixed && where->fix_fields(thd, ancestor, &where)) - goto err; - if (check_option && !check_option->fixed && - check_option->fix_fields(thd, ancestor, &check_option)) - goto err; - restore_want_privilege(); + field_translation= transl; + field_translation_end= transl + field_count; + /* TODO: use hash for big number of fields */ - /* WHERE/ON resolved => we can rename fields */ - for (transl= field_translation; transl < end; transl++) + /* full text function moving to current select */ + if (view->select_lex.ftfunc_list->elements) { - transl->item->rename((char *)transl->name); + Item_func_match *ifm; + SELECT_LEX *current_select= thd->lex->current_select; + List_iterator_fast<Item_func_match> + li(*(view->select_lex.ftfunc_list)); + while ((ifm= li++)) + current_select->ftfunc_list->push_front(ifm); } - goto ok; } + DBUG_RETURN(FALSE); +} - /* Create view fields translation table */ - if (!(transl= - (Field_translator*)(thd->current_arena-> - alloc(select->item_list.elements * - sizeof(Field_translator))))) - { - res= TRUE; - goto ok; // Restore thd - } +/* + Prepare where expression of view - select_lex->no_wrap_view_item= 1; + SYNOPSIS + st_table_list::prep_where() + thd - thread handler + conds - condition of this JOIN + no_where_clause - do not build WHERE or ON outer qwery do not need it + (it is INSERT), we do not need conds if this flag is set - /* - Resolve all view items against ancestor table. + NOTE: have to be called befor CHECK OPTION preparation, because it makes + fix_fields for view WHERE clause - TODO: do it only for real used fields "on demand" to mark really - used fields correctly. - */ - thd->set_query_id= 1; - /* real rights will be checked in VIEW field */ - save_and_clear_want_privilege(); - /* aggregate function are allowed */ - thd->allow_sum_func= 1; - while ((item= it++)) - { - /* save original name of view column */ - char *name= item->name; - transl[i].item= item; - if (!item->fixed && item->fix_fields(thd, ancestor, &transl[i].item)) - goto err; - /* set new item get in fix fields and original column name */ - transl[i++].name= name; - } - field_translation= transl; - /* TODO: sort this list? Use hash for big number of fields */ + RETURN + FALSE - OK + TRUE - error +*/ - for (tbl= ancestor; tbl; tbl= tbl->next_local) +bool st_table_list::prep_where(THD *thd, Item **conds, + bool no_where_clause) +{ + DBUG_ENTER("st_table_list::prep_where"); + + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) { - if (tbl->on_expr && !tbl->on_expr->fixed && - tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr)) - goto err; + if (tbl->view && tbl->prep_where(thd, conds, no_where_clause)) + { + DBUG_RETURN(TRUE); + } } - if (where || - (check_opt_type == VIEW_CHECK_CASCADED && - ancestor->check_option)) - { - Query_arena *arena= thd->current_arena, backup; - TABLE_LIST *tbl= this; - if (arena->is_conventional()) - arena= 0; // For easier test - - if (where && !where->fixed && where->fix_fields(thd, ancestor, &where)) - goto err; - - if (arena) - thd->set_n_backup_item_arena(arena, &backup); - if (check_opt_type) + if (where) + { + if (!where->fixed && where->fix_fields(thd, &where)) { - if (where) - check_option= where->copy_andor_structure(thd); - if (check_opt_type == VIEW_CHECK_CASCADED) - { - check_option= and_conds(check_option, ancestor->check_option); - } + DBUG_RETURN(TRUE); } /* check that it is not VIEW in which we insert with INSERT SELECT (in this case we can't add view WHERE condition to main SELECT_LEX) */ - if (where && !no_where_clause) + if (!no_where_clause && !where_processed) { + TABLE_LIST *tbl= this; + Query_arena *arena= thd->current_arena, backup; + arena= thd->change_arena_if_needed(&backup); // For easier test + /* Go up to join tree and try to find left join */ for (; tbl; tbl= tbl->embedding) { @@ -1969,72 +1869,107 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds, } } if (tbl == 0) - { - if (outer_join) - { - /* - Store WHERE condition to ON expression for outer join, because - we can't use WHERE to correctly execute left joins on VIEWs and - this expression will not be moved to WHERE condition (i.e. will - be clean correctly for PS/SP) - */ - on_expr= and_conds(on_expr, where); - } - else - { - /* - It is conds of JOIN, but it will be stored in - st_select_lex::prep_where for next reexecution - */ - *conds= and_conds(*conds, where); - } - } + *conds= and_conds(*conds, where); + if (arena) + thd->restore_backup_item_arena(arena, &backup); + where_processed= TRUE; } - - if (arena) - thd->restore_backup_item_arena(arena, &backup); } - restore_want_privilege(); - /* - fix_fields do not need tables, because new are only AND operation and we - just need recollect statistics - */ - if (check_option && !check_option->fixed && - check_option->fix_fields(thd, 0, &check_option)) - goto err; + DBUG_RETURN(FALSE); +} + + +/* + Prepare check option expression of table + + SYNOPSIS + st_table_list::prep_check_option() + thd - thread handler + check_opt_type - WITH CHECK OPTION type (VIEW_CHECK_NONE, + VIEW_CHECK_LOCAL, VIEW_CHECK_CASCADED) + we use this parameter instead of direct check of + effective_with_check to change type of underlying + views to VIEW_CHECK_CASCADED if outer view have + such option and prevent processing of underlying + view check options if outer view have just + VIEW_CHECK_LOCAL option. + + NOTE + This method build check options for every call + (usual execution or every SP/PS call) + This method have to be called after WHERE preparation + (st_table_list::prep_where) - /* WHERE/ON resolved => we can rename fields */ + RETURN + FALSE - OK + TRUE - error +*/ + +bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type) +{ + DBUG_ENTER("st_table_list::prep_check_option"); + + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) { - Field_translator *end= field_translation + select->item_list.elements; - for (transl= field_translation; transl < end; transl++) + /* see comment of check_opt_type parameter */ + if (tbl->view && + tbl->prep_check_option(thd, + ((check_opt_type == VIEW_CHECK_CASCADED) ? + VIEW_CHECK_CASCADED : + VIEW_CHECK_NONE))) { - transl->item->rename((char *)transl->name); + DBUG_RETURN(TRUE); } } - /* full text function moving to current select */ - if (view->select_lex.ftfunc_list->elements) + if (check_opt_type) { - Query_arena *arena= thd->current_arena, backup; - if (arena->is_conventional()) - arena= 0; // For easier test - else - thd->set_n_backup_item_arena(arena, &backup); - - Item_func_match *ifm; - List_iterator_fast<Item_func_match> - li(*(view->select_lex.ftfunc_list)); - while ((ifm= li++)) - current_select_save->ftfunc_list->push_front(ifm); - if (arena) - thd->restore_backup_item_arena(arena, &backup); + Item *item= 0; + if (where) + { + DBUG_ASSERT(where->fixed); + item= where->copy_andor_structure(thd); + } + if (check_opt_type == VIEW_CHECK_CASCADED) + { + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) + { + if (tbl->check_option) + item= and_conds(item, tbl->check_option); + } + } + if (item) + thd->change_item_tree(&check_option, item); + } + + if (check_option) + { + const char *save_where= thd->where; + thd->where= "check option"; + if (!check_option->fixed && + check_option->fix_fields(thd, &check_option) || + check_option->check_cols(1)) + { + DBUG_RETURN(TRUE); + } + thd->where= save_where; } + DBUG_RETURN(FALSE); +} + - goto ok; +/* + Hide errors which show view underlying table information + + SYNOPSIS + st_table_list::hide_view_error() + thd thread handler -err: - res= TRUE; +*/ + +void st_table_list::hide_view_error(THD *thd) +{ /* Hide "Unknown column" or "Unknown function" error */ if (thd->net.last_errno == ER_BAD_FIELD_ERROR || thd->net.last_errno == ER_SP_DOES_NOT_EXIST) @@ -2042,15 +1977,12 @@ err: thd->clear_error(); my_error(ER_VIEW_INVALID, MYF(0), view_db.str, view_name.str); } - -ok: - select_lex->no_wrap_view_item= save_wrapper; - thd->lex->current_select= current_select_save; - select_lex->table_list.first= main_table_list_save; - select_lex->master_unit()->first_select()->linkage= linkage_save; - thd->set_query_id= save_set_query_id; - thd->allow_sum_func= save_allow_sum_func; - DBUG_RETURN(res); + else if (thd->net.last_errno == ER_NO_DEFAULT_FOR_FIELD) + { + thd->clear_error(); + // TODO: make correct error message + my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0), view_db.str, view_name.str); + } } @@ -2094,9 +2026,9 @@ void st_table_list::cleanup_items() if (!field_translation) return; - Field_translator *end= (field_translation + - view->select_lex.item_list.elements); - for (Field_translator *transl= field_translation; transl < end; transl++) + for (Field_translator *transl= field_translation; + transl < field_translation_end; + transl++) transl->item->walk(&Item::cleanup_processor, 0); } @@ -2209,8 +2141,9 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root) void Field_iterator_view::set(TABLE_LIST *table) { + view= table; ptr= table->field_translation; - array_end= ptr + table->view->select_lex.item_list.elements; + array_end= table->field_translation_end; } @@ -2220,9 +2153,9 @@ const char *Field_iterator_table::name() } -Item *Field_iterator_table::item(THD *thd) +Item *Field_iterator_table::create_item(THD *thd) { - return new Item_field(thd, *ptr); + return new Item_field(thd, &thd->lex->current_select->context, *ptr); } @@ -2232,6 +2165,51 @@ const char *Field_iterator_view::name() } +Item *Field_iterator_view::create_item(THD *thd) +{ + return create_view_field(thd, view, &ptr->item, ptr->name); +} + +Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, + const char *name) +{ + bool save_wrapper= thd->lex->select_lex.no_wrap_view_item; + Item *field= *field_ref; + DBUG_ENTER("create_view_field"); + + if (view->schema_table_reformed) + { + /* + In case of SHOW command (schema_table_reformed set) all items are + fixed + */ + DBUG_ASSERT(field && field->fixed); + DBUG_RETURN(field); + } + + DBUG_ASSERT(field); + thd->lex->current_select->no_wrap_view_item= TRUE; + if (!field->fixed) + { + if (field->fix_fields(thd, field_ref)) + { + thd->lex->current_select->no_wrap_view_item= save_wrapper; + DBUG_RETURN(0); + } + field= *field_ref; + } + thd->lex->current_select->no_wrap_view_item= save_wrapper; + if (thd->lex->current_select->no_wrap_view_item) + { + DBUG_RETURN(field); + } + Item *item= new Item_direct_view_ref(&view->view->select_lex.context, + field_ref, view->view_name.str, + name); + DBUG_RETURN(item); +} + + /***************************************************************************** ** Instansiate templates *****************************************************************************/ diff --git a/sql/table.h b/sql/table.h index 8bc4e01852f..d0c998c4c10 100644 --- a/sql/table.h +++ b/sql/table.h @@ -314,9 +314,9 @@ typedef struct st_schema_table #define JOIN_TYPE_LEFT 1 #define JOIN_TYPE_RIGHT 2 -#define VIEW_ALGORITHM_UNDEFINED 0 -#define VIEW_ALGORITHM_TMPTABLE 1 -#define VIEW_ALGORITHM_MERGE 2 +#define VIEW_ALGORITHM_UNDEFINED 0 +#define VIEW_ALGORITHM_TMPTABLE 1 +#define VIEW_ALGORITHM_MERGE 2 /* view WITH CHECK OPTION parameter options */ #define VIEW_CHECK_NONE 0 @@ -329,9 +329,13 @@ typedef struct st_schema_table #define VIEW_CHECK_SKIP 2 struct st_lex; +struct st_table_list; class select_union; class TMP_TABLE_PARAM; +Item *create_view_field(THD *thd, st_table_list *view, Item **field_ref, + const char *name); + struct Field_translator { Item *item; @@ -384,6 +388,8 @@ typedef struct st_table_list st_select_lex *select_lex; st_lex *view; /* link on VIEW lex for merging */ Field_translator *field_translation; /* array of VIEW fields */ + /* pointer to element after last one in translation table above */ + Field_translator *field_translation_end; /* list of ancestor(s) of this table (underlying table(s)/view(s) */ st_table_list *ancestor; /* most upper view this table belongs to */ @@ -408,8 +414,7 @@ typedef struct st_table_list algorithm) */ uint8 effective_with_check; - uint effective_algorithm; /* which algorithm was really used */ - uint privilege_backup; /* place for saving privileges */ + uint8 effective_algorithm; /* which algorithm was really used */ GRANT_INFO grant; /* data need by some engines in query cache*/ ulonglong engine_data; @@ -424,7 +429,6 @@ typedef struct st_table_list bool updating; /* for replicate-do/ignore table */ bool force_index; /* prefer index over table scan */ bool ignore_leaves; /* preload only non-leaf nodes */ - bool no_where_clause; /* do not attach WHERE to SELECT */ table_map dep_tables; /* tables the table depends on */ table_map on_expr_dep_tables; /* tables on expression depends on */ struct st_nested_join *nested_join; /* if the element is a nested join */ @@ -437,6 +441,8 @@ typedef struct st_table_list /* TRUE if this merged view contain auto_increment field */ bool contain_auto_increment; bool multitable_view; /* TRUE iff this is multitable view */ + /* view where processed */ + bool where_processed; /* FRMTYPE_ERROR if any type is acceptable */ enum frm_type_enum required_type; char timestamp_buffer[20]; /* buffer for timestamp (19+1) */ @@ -449,16 +455,32 @@ typedef struct st_table_list void calc_md5(char *buffer); void set_ancestor(); int view_check_option(THD *thd, bool ignore_failure); - bool setup_ancestor(THD *thd, Item **conds, uint8 check_option); + bool setup_ancestor(THD *thd); void cleanup_items(); bool placeholder() {return derived || view; } void print(THD *thd, String *str); - void save_and_clear_want_privilege(); - void restore_want_privilege(); bool check_single_table(st_table_list **table, table_map map, st_table_list *view); bool set_insert_values(MEM_ROOT *mem_root); + void hide_view_error(THD *thd); st_table_list *find_underlying_table(TABLE *table); + inline bool prepare_check_option(THD *thd) + { + bool res= FALSE; + if (effective_with_check) + res= prep_check_option(thd, effective_with_check); + return res; + } + inline bool prepare_where(THD *thd, Item **conds, + bool no_where_clause) + { + if (effective_algorithm == VIEW_ALGORITHM_MERGE) + return prep_where(thd, conds, no_where_clause); + return FALSE; + } +private: + bool prep_check_option(THD *thd, uint8 check_opt_type); + bool prep_where(THD *thd, Item **conds, bool no_where_clause); } TABLE_LIST; class Item; @@ -471,7 +493,7 @@ public: virtual void next()= 0; virtual bool end_of_fields()= 0; /* Return 1 at end of list */ virtual const char *name()= 0; - virtual Item *item(THD *)= 0; + virtual Item *create_item(THD *)= 0; virtual Field *field()= 0; }; @@ -486,7 +508,7 @@ public: void next() { ptr++; } bool end_of_fields() { return *ptr == 0; } const char *name(); - Item *item(THD *thd); + Item *create_item(THD *thd); Field *field() { return *ptr; } }; @@ -494,15 +516,18 @@ public: class Field_iterator_view: public Field_iterator { Field_translator *ptr, *array_end; + TABLE_LIST *view; public: Field_iterator_view() :ptr(0), array_end(0) {} void set(TABLE_LIST *table); void next() { ptr++; } bool end_of_fields() { return ptr == array_end; } const char *name(); - Item *item(THD *thd) { return ptr->item; } + Item *create_item(THD *thd); Item **item_ptr() {return &ptr->item; } Field *field() { return 0; } + + inline Item *item() { return ptr->item; } }; |