diff options
Diffstat (limited to 'sql/sql_handler.cc')
-rw-r--r-- | sql/sql_handler.cc | 151 |
1 files changed, 88 insertions, 63 deletions
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 28e94d1a477..12acf344c31 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -1,5 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - +/* Copyright (C) 2000-2004 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -65,7 +64,7 @@ #define HANDLER_TABLES_HASH_SIZE 120 static enum enum_ha_read_modes rkey_to_rnext[]= - { RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV }; + { RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV }; #define HANDLER_TABLES_HACK(thd) { \ TABLE *tmp=thd->open_tables; \ @@ -148,12 +147,8 @@ static void mysql_ha_hash_free(TABLE_LIST *tables) int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) { TABLE_LIST *hash_tables; - char *db; - char *name; - char *alias; - uint dblen; - uint namelen; - uint aliaslen; + char *db, *name, *alias; + uint dblen, namelen, aliaslen, counter; int err; DBUG_ENTER("mysql_ha_open"); DBUG_PRINT("enter",("'%s'.'%s' as '%s' reopen: %d", @@ -165,7 +160,8 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) /* HASH entries are of type TABLE_LIST. */ - if (hash_init(&thd->handler_tables_hash, HANDLER_TABLES_HASH_SIZE, 0, 0, + if (hash_init(&thd->handler_tables_hash, &my_charset_latin1, + HANDLER_TABLES_HASH_SIZE, 0, 0, (hash_get_key) mysql_ha_hash_get_key, (hash_free_key) mysql_ha_hash_free, 0)) goto err; @@ -189,7 +185,7 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) */ DBUG_ASSERT(! tables->table); HANDLER_TABLES_HACK(thd); - err=open_tables(thd,tables); + err=open_tables(thd, tables, &counter); HANDLER_TABLES_HACK(thd); if (err) goto err; @@ -226,7 +222,7 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) memcpy(hash_tables->alias, tables->alias, aliaslen); /* add to hash */ - if (hash_insert(&thd->handler_tables_hash, (byte*) hash_tables)) + if (my_hash_insert(&thd->handler_tables_hash, (byte*) hash_tables)) { mysql_ha_close(thd, tables); goto err; @@ -234,7 +230,7 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) } if (! reopen) - send_ok(&thd->net); + send_ok(thd); DBUG_PRINT("exit",("OK")); DBUG_RETURN(0); @@ -294,6 +290,7 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables) { if (*table_ptr) { + (*table_ptr)->file->ha_index_or_rnd_end(); VOID(pthread_mutex_lock(&LOCK_open)); if (close_thread_table(thd, table_ptr)) { @@ -325,7 +322,7 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables) DBUG_RETURN(-1); } - send_ok(&thd->net); + send_ok(thd); DBUG_PRINT("exit", ("OK")); DBUG_RETURN(0); } @@ -359,15 +356,22 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, TABLE_LIST *hash_tables; TABLE **table_ptr; TABLE *table; - int err; - int keyno=-1; - uint num_rows; MYSQL_LOCK *lock; + List<Item> list; + Protocol *protocol= thd->protocol; + char buff[MAX_FIELD_WIDTH]; + String buffer(buff, sizeof(buff), system_charset_info); + int err, keyno= -1; + uint num_rows; + byte *key; + uint key_len; DBUG_ENTER("mysql_ha_read"); DBUG_PRINT("enter",("'%s'.'%s' as '%s'", tables->db, tables->real_name, tables->alias)); - List<Item> list; + LINT_INIT(key); + LINT_INIT(key_len); + list.push_front(new Item_field(NULL,NULL,"*")); List_iterator<Item> it(list); it++; @@ -447,11 +451,10 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } tables->table=table; - if (cond && cond->fix_fields(thd,tables)) + if (cond && ((!cond->fixed && + cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1))) goto err0; - table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it - if (keyname) { if ((keyno=find_type(keyname, &table->keynames, 1+2)-1)<0) @@ -460,55 +463,71 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, keyname,tables->alias); goto err0; } - table->file->index_init(keyno); } if (insert_fields(thd,tables,tables->db,tables->alias,&it)) goto err0; select_limit+=offset_limit; - send_fields(thd,list,1); + protocol->send_fields(&list,1); HANDLER_TABLES_HACK(thd); lock= mysql_lock_tables(thd, &tables->table, 1, 0); HANDLER_TABLES_HACK(thd); - - byte *key; - uint key_len; - LINT_INIT(key); - LINT_INIT(key_len); + if (!lock) goto err0; // mysql_lock_tables() printed error message already - table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it + /* + In ::external_lock InnoDB resets the fields which tell it that + the handle is used in the HANDLER interface. Tell it again that + we are using it for HANDLER. + */ + + table->file->init_table_handle_for_HANDLER(); for (num_rows=0; num_rows < select_limit; ) { - switch(mode) { + switch (mode) { + case RNEXT: + if (table->file->inited != handler::NONE) + { + err=keyname ? + table->file->index_next(table->record[0]) : + table->file->rnd_next(table->record[0]); + break; + } + /* else fall through */ case RFIRST: if (keyname) + { + table->file->ha_index_or_rnd_end(); + table->file->ha_index_init(keyno); err=table->file->index_first(table->record[0]); + } else { - if (!(err=table->file->rnd_init(1))) + table->file->ha_index_or_rnd_end(); + if (!(err=table->file->ha_rnd_init(1))) err=table->file->rnd_next(table->record[0]); } mode=RNEXT; break; + case RPREV: + DBUG_ASSERT(keyname != 0); + if (table->file->inited != handler::NONE) + { + err=table->file->index_prev(table->record[0]); + break; + } + /* else fall through */ case RLAST: DBUG_ASSERT(keyname != 0); + table->file->ha_index_or_rnd_end(); + table->file->ha_index_init(keyno); err=table->file->index_last(table->record[0]); mode=RPREV; break; - case RNEXT: - err=keyname ? - table->file->index_next(table->record[0]) : - table->file->rnd_next(table->record[0]); - break; - case RPREV: - DBUG_ASSERT(keyname != 0); - err=table->file->index_prev(table->record[0]); - break; case RNEXT_SAME: /* Continue scan on "(keypart1,keypart2,...)=(c1, c2, ...) */ DBUG_ASSERT(keyname != 0); @@ -521,37 +540,42 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, KEY_PART_INFO *key_part=keyinfo->key_part; if (key_expr->elements > keyinfo->key_parts) { - my_printf_error(ER_TOO_MANY_KEY_PARTS,ER(ER_TOO_MANY_KEY_PARTS), - MYF(0),keyinfo->key_parts); - goto err; + my_printf_error(ER_TOO_MANY_KEY_PARTS,ER(ER_TOO_MANY_KEY_PARTS), + MYF(0),keyinfo->key_parts); + goto err; } - List_iterator_fast<Item> it_ke(*key_expr); + List_iterator<Item> it_ke(*key_expr); Item *item; for (key_len=0 ; (item=it_ke++) ; key_part++) { - if (item->fix_fields(thd, tables)) - goto err; - if (item->used_tables() & ~RAND_TABLE_BIT) + // 'item' can be changed by fix_fields() call + if ((!item->fixed && + item->fix_fields(thd, tables, it_ke.ref())) || + (item= *it_ke.ref())->check_cols(1)) + goto err; + if (item->used_tables() & ~RAND_TABLE_BIT) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"HANDLER ... READ"); - goto err; + goto err; } - item->save_in_field(key_part->field, 1); - key_len+=key_part->store_length; + (void) item->save_in_field(key_part->field, 1); + key_len+=key_part->store_length; } if (!(key= (byte*) thd->calloc(ALIGN_SIZE(key_len)))) { - send_error(&thd->net,ER_OUTOFMEMORY); - goto err; + send_error(thd,ER_OUTOFMEMORY); + goto err; } key_copy(key, table, keyno, key_len); + table->file->ha_index_or_rnd_end(); + table->file->ha_index_init(keyno); err=table->file->index_read(table->record[0], - key,key_len,ha_rkey_mode); + key,key_len,ha_rkey_mode); mode=rkey_to_rnext[(int)ha_rkey_mode]; break; } default: - send_error(&thd->net,ER_ILLEGAL_HA); + send_error(thd,ER_ILLEGAL_HA); goto err; } @@ -572,26 +596,25 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, continue; if (num_rows >= offset_limit) { - String *packet = &thd->packet; Item *item; - packet->length(0); + protocol->prepare_for_resend(); it.rewind(); while ((item=it++)) { - if (item->send(thd,packet)) + if (item->send(thd->protocol, &buffer)) { - packet->free(); // Free used + protocol->free(); // Free used my_error(ER_OUT_OF_RESOURCES,MYF(0)); goto err; } } - my_net_write(&thd->net, (char*)packet->ptr(), packet->length()); + protocol->write(); } num_rows++; } ok: mysql_unlock_tables(thd,lock); - send_eof(&thd->net); + send_eof(thd); DBUG_PRINT("exit",("OK")); DBUG_RETURN(0); @@ -654,8 +677,10 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags, while (*table_ptr) { if ((! *tmp_tables->db || - ! my_strcasecmp((*table_ptr)->table_cache_key, tmp_tables->db)) && - ! my_strcasecmp((*table_ptr)->real_name, tmp_tables->real_name)) + ! my_strcasecmp(&my_charset_latin1, (*table_ptr)->table_cache_key, + tmp_tables->db)) && + ! my_strcasecmp(&my_charset_latin1, (*table_ptr)->real_name, + tmp_tables->real_name)) { DBUG_PRINT("info",("*table_ptr '%s'.'%s' as '%s'", (*table_ptr)->table_cache_key, @@ -749,6 +774,7 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags) } safe_mutex_assert_owner(&LOCK_open); + (*table_ptr)->file->ha_index_or_rnd_end(); if (close_thread_table(thd, table_ptr)) { /* Tell threads waiting for refresh that something has happened */ @@ -757,4 +783,3 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags) DBUG_RETURN(0); } - |