Server IP : 104.21.38.3 / Your IP : 162.158.108.77 Web Server : Apache System : Linux krdc-ubuntu-s-2vcpu-4gb-amd-blr1-01.localdomain 5.15.0-142-generic #152-Ubuntu SMP Mon May 19 10:54:31 UTC 2025 x86_64 User : www ( 1000) PHP Version : 7.4.33 Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /www/server/mysql/src/sql/ |
Upload File : |
/* Copyright (c) 2002, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ /* Derived tables These were introduced by Sinisa <[email protected]> */ #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_derived.h" #include "sql_select.h" #include "sql_resolver.h" #include "sql_optimizer.h" // JOIN #include "sql_view.h" // check_duplicate_names #include "auth_common.h" // SELECT_ACL #include "sql_tmp_table.h" // Tmp tables #include "sql_union.h" // Query_result_union #include "opt_trace.h" // opt_trace_disable_etc /** Resolve a derived table or view reference, including recursively resolving contained subqueries. @param thd thread handle @param apply_semijoin Apply possible semi-join transforms if this is true @returns false if success, true if error */ bool TABLE_LIST::resolve_derived(THD *thd, bool apply_semijoin) { DBUG_ENTER("TABLE_LIST::resolve_derived"); if (!is_view_or_derived() || is_merged()) DBUG_RETURN(false); const bool derived_tables_saved= thd->derived_tables_processing; thd->derived_tables_processing= true; #ifndef NDEBUG for (SELECT_LEX *sl= derived->first_select(); sl; sl= sl->next_select()) { // Make sure there are no outer references assert(sl->context.outer_context == NULL); } #endif if (!(derived_result= new (thd->mem_root) Query_result_union)) DBUG_RETURN(true); /* Prepare the underlying query expression of the derived table. The SELECT_STRAIGHT_JOIN option prevents semi-join transformation. */ if (derived->prepare(thd, derived_result, !apply_semijoin ? SELECT_NO_SEMI_JOIN : 0, 0)) DBUG_RETURN(true); if (check_duplicate_names(derived->types, 0)) DBUG_RETURN(true); #ifndef NO_EMBEDDED_ACCESS_CHECKS /* A derived table is transparent with respect to privilege checking. This setting means that privilege checks ignore the derived table and are done properly in underlying base tables and views. SELECT_ACL is used because derived tables cannot be used for update, delete or insert. */ if (is_derived()) set_privileges(SELECT_ACL); #endif thd->derived_tables_processing= derived_tables_saved; DBUG_RETURN(false); } /** Prepare a derived table or view for materialization. @param thd THD pointer @return false if successful, true if error */ bool TABLE_LIST::setup_materialized_derived(THD *thd) { DBUG_ENTER("TABLE_LIST::setup_materialized_derived"); assert(is_view_or_derived() && !is_merged() && table == NULL); DBUG_PRINT("info", ("algorithm: TEMPORARY TABLE")); Opt_trace_context *const trace= &thd->opt_trace; Opt_trace_object trace_wrapper(trace); Opt_trace_object trace_derived(trace, is_view() ? "view" : "derived"); trace_derived.add_utf8_table(this). add("select#", derived->first_select()->select_number). add("materialized", true); set_uses_materialization(); // Create the result table for the materialization const ulonglong create_options= derived->first_select()->active_options() | TMP_TABLE_ALL_COLUMNS; if (derived_result->create_result_table(thd, &derived->types, false, create_options, alias, false, false)) DBUG_RETURN(true); /* purecov: inspected */ table= derived_result->table; table->pos_in_table_list= this; // Make table's name same as the underlying materialized table set_name_temporary(); table->s->tmp_table= NON_TRANSACTIONAL_TMP_TABLE; #ifndef NO_EMBEDDED_ACCESS_CHECKS if (referencing_view) table->grant= grant; else table->grant.privilege= SELECT_ACL; #endif // Table is "nullable" if inner table of an outer_join if (is_inner_table_of_outer_join()) table->set_nullable(); // Add new temporary table to list of open derived tables table->next= thd->derived_tables; thd->derived_tables= table; for (SELECT_LEX *sl= derived->first_select(); sl; sl= sl->next_select()) { /* Derived tables/view are materialized prior to UPDATE, thus we can skip them from table uniqueness check */ sl->propagate_unique_test_exclusion(); /* SELECT privilege is needed for all materialized derived tables and views, and columns must be marked for read, unless command is SHOW FIELDS. */ if (thd->lex->sql_command == SQLCOM_SHOW_FIELDS) continue; if (sl->check_view_privileges(thd, SELECT_ACL, SELECT_ACL)) DBUG_RETURN(true); // Set all selected fields to be read: // @todo Do not set fields that are not referenced from outer query assert(thd->mark_used_columns == MARK_COLUMNS_READ); List_iterator<Item> it(sl->all_fields); Item *item; Column_privilege_tracker tracker(thd, SELECT_ACL); Mark_field mf(thd->mark_used_columns); while ((item= it++)) { if (item->walk(&Item::check_column_privileges, Item::WALK_PREFIX, (uchar *)thd)) DBUG_RETURN(true); item->walk(&Item::mark_field_in_map, Item::WALK_POSTFIX, (uchar *)&mf); } } DBUG_RETURN(false); } /** Optimize the query expression representing a derived table/view. @note If optimizer finds out that the derived table/view is of the type "SELECT a_constant" this functions also materializes it. @param thd thread handle @returns false if success, true if error. */ bool TABLE_LIST::optimize_derived(THD *thd) { DBUG_ENTER("TABLE_LIST::optimize_derived"); SELECT_LEX_UNIT *const unit= derived_unit(); assert(unit && !unit->is_optimized()); if (unit->optimize(thd) || thd->is_error()) DBUG_RETURN(true); if (materializable_is_const() && (create_derived(thd) || materialize_derived(thd))) DBUG_RETURN(true); DBUG_RETURN(false); } /** Create result table for a materialized derived table/view. @param thd thread handle This function actually creates the result table for given 'derived' table/view, but it doesn't fill it. @returns false if success, true if error. */ bool TABLE_LIST::create_derived(THD *thd) { DBUG_ENTER("TABLE_LIST::create_derived"); SELECT_LEX_UNIT *const unit= derived_unit(); // @todo: Be able to assert !table->is_created() as well assert(unit && uses_materialization() && table); /* Don't create result table if: 1) Table is already created, or 2) Table is a constant one with all NULL values. */ if (table->is_created() || // 1 (select_lex->join != NULL && // 2 (select_lex->join->const_table_map & map()))) // 2 { /* At this point, JT_CONST derived tables should be null rows. Otherwise they would have been materialized already. */ #ifndef NDEBUG if (table != NULL) { QEP_TAB *tab= table->reginfo.qep_tab; assert(tab == NULL || tab->type() != JT_CONST || table->has_null_row()); } #endif DBUG_RETURN(false); } /* create tmp table */ Query_result_union *result= (Query_result_union*)unit->query_result(); if (instantiate_tmp_table(table, table->key_info, result->tmp_table_param.start_recinfo, &result->tmp_table_param.recinfo, unit->first_select()->active_options() | thd->lex->select_lex->active_options() | TMP_TABLE_ALL_COLUMNS, thd->variables.big_tables, &thd->opt_trace)) DBUG_RETURN(true); /* purecov: inspected */ table->file->extra(HA_EXTRA_WRITE_CACHE); table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); table->set_created(); DBUG_RETURN(false); } /** Materialize derived table @param thd Thread handle Derived table is resolved with temporary table. It is created based on the queries defined. After temporary table is materialized, if this is not EXPLAIN, then the entire unit / node is deleted. unit is deleted if UNION is used for derived table and node is deleted is it is a simple SELECT. If you use this function, make sure it's not called at prepare. Due to evaluation of LIMIT clause it can not be used at prepared stage. @returns false if success, true if error. */ bool TABLE_LIST::materialize_derived(THD *thd) { DBUG_ENTER("TABLE_LIST::materialize_derived"); assert(is_view_or_derived() && uses_materialization()); SELECT_LEX_UNIT *const unit= derived_unit(); bool res= false; assert(table && table->is_created()); if (unit->is_union()) { // execute union without clean up res= unit->execute(thd); } else { SELECT_LEX *first_select= unit->first_select(); JOIN *join= first_select->join; SELECT_LEX *save_current_select= thd->lex->current_select(); thd->lex->set_current_select(first_select); assert(join && join->is_optimized()); unit->set_limit(first_select); join->exec(); res= join->error; thd->lex->set_current_select(save_current_select); } if (!res) { /* Here we entirely fix both TABLE_LIST and list of SELECT's as there were no derived tables */ if (derived_result->flush()) res= true; /* purecov: inspected */ } DBUG_RETURN(res); } /** Clean up the query expression for a materialized derived table */ bool TABLE_LIST::cleanup_derived() { assert(is_view_or_derived() && uses_materialization()); return derived_unit()->cleanup(false); }