diff options
author | monty@mysql.com <> | 2004-10-29 19:26:52 +0300 |
---|---|---|
committer | monty@mysql.com <> | 2004-10-29 19:26:52 +0300 |
commit | afbe601302fc59c498437321b296ed6c8d360564 (patch) | |
tree | 23bcc9a71fe7237887a111b158e30f5a6bb665d3 /sql/sql_class.h | |
parent | 67456bb970cc949ceb5779b230592e455843c35c (diff) | |
parent | 541883f9d89a8d38affba60bf9506289a6232da1 (diff) | |
download | mariadb-git-afbe601302fc59c498437321b296ed6c8d360564.tar.gz |
merge with 4.1
Diffstat (limited to 'sql/sql_class.h')
-rw-r--r-- | sql/sql_class.h | 187 |
1 files changed, 117 insertions, 70 deletions
diff --git a/sql/sql_class.h b/sql/sql_class.h index 32f156fbee8..6e0aacc4fce 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -427,6 +427,9 @@ struct system_variables my_bool low_priority_updates; my_bool new_mode; my_bool query_cache_wlock_invalidate; +#ifdef HAVE_INNOBASE_DB + my_bool innodb_table_locks; +#endif /* HAVE_INNOBASE_DB */ my_bool old_passwords; /* Only charset part of these variables is sensible */ @@ -527,15 +530,29 @@ public: STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE }; + /* + This constructor is used only when Item_arena is created as + backup storage for another instance of Item_arena. + */ + Item_arena() {}; + /* + Create arena for already constructed THD using its variables as + parameters for memory root initialization. + */ Item_arena(THD *thd); - Item_arena(); + /* + Create arena and optionally init memory root with minimal values. + Particularly used if Item_arena is part of Statement. + */ Item_arena(bool init_mem_root); virtual Type type() const; - virtual ~Item_arena(); + virtual ~Item_arena() {}; inline bool is_stmt_prepare() const { return (int)state < (int)PREPARED; } inline bool is_first_stmt_execute() const { return state == PREPARED; } - inline bool is_conventional() const + inline bool is_stmt_execute() const + { return state == PREPARED || state == EXECUTED; } + inline bool is_conventional_execution() const { return state == CONVENTIONAL_EXECUTION; } inline gptr alloc(unsigned int size) { return alloc_root(&mem_root,size); } inline gptr calloc(unsigned int size) @@ -620,6 +637,23 @@ public: Points to the query associated with this statement. It's const, but we need to declare it char * because all table handlers are written in C and need to point to it. + + Note that (A) if we set query = NULL, we must at the same time set + query_length = 0, and protect the whole operation with the + LOCK_thread_count mutex. And (B) we are ONLY allowed to set query to a + non-NULL value if its previous value is NULL. We do not need to protect + operation (B) with any mutex. To avoid crashes in races, if we do not + know that thd->query cannot change at the moment, one should print + thd->query like this: + (1) reserve the LOCK_thread_count mutex; + (2) check if thd->query is NULL; + (3) if not NULL, then print at most thd->query_length characters from + it. We will see the query_length field as either 0, or the right value + for it. + Assuming that the write and read of an n-bit memory field in an n-bit + computer is atomic, we can avoid races in the above way. + This printing is needed at least in SHOW PROCESSLIST and SHOW INNODB + STATUS. */ char *query; uint32 query_length; // current query length @@ -642,12 +676,6 @@ public: void restore_backup_statement(Statement *stmt, Statement *backup); /* return class type */ virtual Type type() const; - - /* - Cleanup statement parse state (parse tree, lex) after execution of - a non-prepared SQL statement. - */ - void end_statement(); }; @@ -657,7 +685,7 @@ public: assignment in Statement::Statement) Non-empty statement names are unique too: attempt to insert a new statement with duplicate name causes older statement to be deleted - + Statements are auto-deleted when they are removed from the map and when the map is deleted. */ @@ -666,7 +694,7 @@ class Statement_map { public: Statement_map(); - + int insert(Statement *statement); Statement *find_by_name(LEX_STRING *name) @@ -699,11 +727,18 @@ public: } hash_delete(&st_hash, (byte *) statement); } + /* Erase all statements (calls Statement destructor) */ + void reset() + { + hash_reset(&names_hash); + hash_reset(&st_hash); + last_found_statement= 0; + } ~Statement_map() { - hash_free(&st_hash); hash_free(&names_hash); + hash_free(&st_hash); } private: HASH st_hash; @@ -713,6 +748,17 @@ private: /* + A registry for item tree transformations performed during + query optimization. We register only those changes which require + a rollback to re-execute a prepared statement or stored procedure + yet another time. +*/ + +struct Item_change_record; +typedef I_List<Item_change_record> Item_change_list; + + +/* For each client connection we create a separate thread with THD serving as a thread/connection descriptor */ @@ -744,24 +790,6 @@ public: struct system_variables variables; // Changeable local variables struct system_status_var status_var; // Per thread statistic vars pthread_mutex_t LOCK_delete; // Locked before thd is deleted - /* - Note that (A) if we set query = NULL, we must at the same time set - query_length = 0, and protect the whole operation with the - LOCK_thread_count mutex. And (B) we are ONLY allowed to set query to a - non-NULL value if its previous value is NULL. We do not need to protect - operation (B) with any mutex. To avoid crashes in races, if we do not - know that thd->query cannot change at the moment, one should print - thd->query like this: - (1) reserve the LOCK_thread_count mutex; - (2) check if thd->query is NULL; - (3) if not NULL, then print at most thd->query_length characters from - it. We will see the query_length field as either 0, or the right value - for it. - Assuming that the write and read of an n-bit memory field in an n-bit - computer is atomic, we can avoid races in the above way. - This printing is needed at least in SHOW PROCESSLIST and SHOW INNODB - STATUS. - */ /* all prepared statements and cursors of this connection */ Statement_map stmt_map; /* @@ -831,6 +859,7 @@ public: */ MYSQL_LOCK *lock; /* Current locks */ MYSQL_LOCK *locked_tables; /* Tables locked with LOCK */ + HASH handler_tables_hash; /* One thread can hold up to one named user-level lock. This variable points to a lock object if the lock is present. See item_func.cc and @@ -864,10 +893,10 @@ public: THD_TRANS all; // Trans since BEGIN WORK THD_TRANS stmt; // Trans for current statement uint bdb_lock_count; - uint ndb_lock_count; #ifdef HAVE_NDBCLUSTER_DB - void* ndb; + void* thd_ndb; #endif + bool on; /* Tables changed in transaction (that must be invalidated in query cache). List contain only transactional tables, that not invalidated in query @@ -889,6 +918,14 @@ public: Vio* active_vio; #endif /* + This is to track items changed during execution of a prepared + statement/stored procedure. It's created by + register_item_tree_change() in memory root of THD, and freed in + rollback_item_tree_changes(). For conventional execution it's always 0. + */ + Item_change_list change_list; + + /* Current prepared Item_arena if there one, or 0 */ Item_arena *current_arena; @@ -1126,6 +1163,23 @@ public: } inline CHARSET_INFO *charset() { return variables.character_set_client; } void update_charset(); + + void change_item_tree(Item **place, Item *new_value) + { + /* TODO: check for OOM condition here */ + if (!current_arena->is_conventional_execution()) + nocheck_register_item_tree_change(place, *place, &mem_root); + *place= new_value; + } + void nocheck_register_item_tree_change(Item **place, Item *old_value, + MEM_ROOT *runtime_memroot); + void rollback_item_tree_changes(); + + /* + Cleanup statement parse state (parse tree, lex) and execution + state after execution of a non-prepared SQL statement. + */ + void end_statement(); inline int killed_errno() const { return killed != KILL_BAD_DATA ? killed : 0; @@ -1150,27 +1204,6 @@ public: #define SYSTEM_THREAD_SLAVE_SQL 4 /* - Disables binary logging for one thread, and resets it back to what it was - before being disabled. - Some functions (like the internal mysql_create_table() when it's called by - mysql_alter_table()) must NOT write to the binlog (binlogging is done at the - at a later stage of the command already, and must be, for locking reasons); - so we internally disable it temporarily by creating the Disable_binlog - object and reset the state by destroying the object (don't forget that! or - write code so that the object gets automatically destroyed when leaving a - block, see example in sql_table.cc). -*/ -class Disable_binlog { -private: - THD *thd; - ulong save_options; -public: - Disable_binlog(THD *thd_arg); - ~Disable_binlog(); -}; - - -/* Used to hold information about file and file structure in exchainge via non-DB file (...INTO OUTFILE..., ...LOAD DATA...) XXX: We never call destructor for objects of this class. @@ -1209,6 +1242,13 @@ public: unit= u; return 0; } + /* + Because of peculiarities of prepared statements protocol + we need to know number of columns in the result set (if + there is a result set) apart from sending columns metadata. + */ + virtual uint field_count(List<Item> &fields) const + { return fields.elements; } virtual bool send_fields(List<Item> &list, uint flags)=0; virtual bool send_data(List<Item> &items)=0; virtual bool initialize_tables (JOIN *join=0) { return 0; } @@ -1223,6 +1263,20 @@ public: }; +/* + Base class for select_result descendands which intercept and + transform result set rows. As the rows are not sent to the client, + sending of result set metadata should be suppressed as well. +*/ + +class select_result_interceptor: public select_result +{ +public: + uint field_count(List<Item> &fields) const { return 0; } + bool send_fields(List<Item> &fields, uint flag) { return FALSE; } +}; + + class select_send :public select_result { public: select_send() {} @@ -1232,7 +1286,7 @@ public: }; -class select_to_file :public select_result { +class select_to_file :public select_result_interceptor { protected: sql_exchange *exchange; File file; @@ -1244,7 +1298,6 @@ public: select_to_file(sql_exchange *ex) :exchange(ex), file(-1),row_count(0L) { path[0]=0; } ~select_to_file(); - bool send_fields(List<Item> &list, uint flags) { return 0; } void send_error(uint errcode,const char *err); bool send_eof(); void cleanup(); @@ -1271,7 +1324,7 @@ public: }; -class select_insert :public select_result { +class select_insert :public select_result_interceptor { public: TABLE_LIST *table_list; TABLE *table; @@ -1285,7 +1338,6 @@ class select_insert :public select_result { bool ignore_check_option_errors); ~select_insert(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); - bool send_fields(List<Item> &list, uint flags) { return 0; } bool send_data(List<Item> &items); void send_error(uint errcode,const char *err); bool send_eof(); @@ -1345,10 +1397,12 @@ public: uint group_parts,group_length,group_null_parts; uint quick_group; bool using_indirect_summary_function; + /* If >0 convert all blob fields to varchar(convert_blob_length) */ + uint convert_blob_length; TMP_TABLE_PARAM() :copy_funcs_it(copy_funcs), copy_field(0), group_parts(0), - group_length(0), group_null_parts(0) + group_length(0), group_null_parts(0), convert_blob_length(0) {} ~TMP_TABLE_PARAM() { @@ -1365,7 +1419,7 @@ public: } }; -class select_union :public select_result { +class select_union :public select_result_interceptor { public: TABLE *table; COPY_INFO info; @@ -1374,7 +1428,6 @@ class select_union :public select_result { select_union(TABLE *table_par); ~select_union(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); - bool send_fields(List<Item> &list, uint flags) { return 0; } bool send_data(List<Item> &items); bool send_eof(); bool flush(); @@ -1382,17 +1435,14 @@ class select_union :public select_result { }; /* Base subselect interface class */ -class select_subselect :public select_result +class select_subselect :public select_result_interceptor { protected: Item_subselect *item; public: select_subselect(Item_subselect *item); - bool send_fields(List<Item> &list, uint flags) { return 0; } bool send_data(List<Item> &items)=0; bool send_eof() { return 0; }; - - friend class Ttem_subselect; }; /* Single value subselect interface class */ @@ -1544,7 +1594,7 @@ public: }; -class multi_delete :public select_result +class multi_delete :public select_result_interceptor { TABLE_LIST *delete_tables, *table_being_deleted; Unique **tempfiles; @@ -1557,7 +1607,6 @@ public: multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables); ~multi_delete(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); - bool send_fields(List<Item> &list, uint flags) { return 0; } bool send_data(List<Item> &items); bool initialize_tables (JOIN *join); void send_error(uint errcode,const char *err); @@ -1566,7 +1615,7 @@ public: }; -class multi_update :public select_result +class multi_update :public select_result_interceptor { TABLE_LIST *all_tables, *update_tables, *table_being_updated; THD *thd; @@ -1585,7 +1634,6 @@ public: List<Item> *values, enum_duplicates handle_duplicates); ~multi_update(); int prepare(List<Item> &list, SELECT_LEX_UNIT *u); - bool send_fields(List<Item> &list, uint flags) { return 0; } bool send_data(List<Item> &items); bool initialize_tables (JOIN *join); void send_error(uint errcode,const char *err); @@ -1605,7 +1653,7 @@ public: ~my_var() {} }; -class select_dumpvar :public select_result { +class select_dumpvar :public select_result_interceptor { ha_rows row_count; public: List<my_var> var_list; @@ -1614,7 +1662,6 @@ public: select_dumpvar(void) { var_list.empty(); local_vars.empty(); vars.empty(); row_count=0;} ~select_dumpvar() {} int prepare(List<Item> &list, SELECT_LEX_UNIT *u); - bool send_fields(List<Item> &list, uint flags) { return 0; } bool send_data(List<Item> &items); bool send_eof(); void cleanup(); |