summaryrefslogtreecommitdiffstats
path: root/sql/select_handler.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sql/select_handler.cc172
1 files changed, 172 insertions, 0 deletions
diff --git a/sql/select_handler.cc b/sql/select_handler.cc
new file mode 100644
index 00000000..795ed8eb
--- /dev/null
+++ b/sql/select_handler.cc
@@ -0,0 +1,172 @@
+/*
+ Copyright (c) 2018, 2020, MariaDB
+
+ 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; version 2 of the License.
+
+ 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 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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
+
+#include "mariadb.h"
+#include "sql_priv.h"
+#include "sql_select.h"
+#include "select_handler.h"
+
+
+/**
+ The methods of the select_handler class.
+
+ The objects of this class are used for pushdown of the select queries
+ into engines. The main method of the class is select_handler::execute()
+ that initiates execution of a select query by a foreign engine, receives the
+ rows of the result set, put it in a buffer of a temporary table and send
+ them from the buffer directly into output.
+
+ The method uses the functions of the select_handle interface to do this.
+ It also employes plus some helper functions to create the needed temporary
+ table and to send rows from the temporary table into output.
+ The constructor of the class gets the select_handler interface as a parameter.
+*/
+
+
+select_handler::select_handler(THD *thd_arg, handlerton *ht_arg)
+ : thd(thd_arg), ht(ht_arg), table(NULL),
+ is_analyze(thd_arg->lex->analyze_stmt)
+{}
+
+
+select_handler::~select_handler()
+{
+ if (table)
+ free_tmp_table(thd, table);
+}
+
+
+TABLE *select_handler::create_tmp_table(THD *thd, SELECT_LEX *select)
+{
+ DBUG_ENTER("select_handler::create_tmp_table");
+ List<Item> types;
+ TMP_TABLE_PARAM tmp_table_param;
+ if (select->master_unit()->join_union_item_types(thd, types, 1))
+ DBUG_RETURN(NULL);
+ tmp_table_param.init();
+ tmp_table_param.field_count= types.elements;
+
+ TABLE *table= ::create_tmp_table(thd, &tmp_table_param, types,
+ (ORDER *) 0, false, 0,
+ TMP_TABLE_ALL_COLUMNS, 1,
+ &empty_clex_str, true, false);
+ DBUG_RETURN(table);
+}
+
+
+bool select_handler::prepare()
+{
+ DBUG_ENTER("select_handler::prepare");
+ /*
+ Some engines (e.g. XPand) initialize "table" on their own.
+ So we need to create a temporary table only if "table" is NULL.
+ */
+ if (!table && !(table= create_tmp_table(thd, select)))
+ DBUG_RETURN(true);
+ DBUG_RETURN(table->fill_item_list(&result_columns));
+}
+
+
+bool select_handler::send_result_set_metadata()
+{
+ DBUG_ENTER("select_handler::send_result_set_metadata");
+
+#ifdef WITH_WSREP
+ if (WSREP(thd) && thd->wsrep_retry_query)
+ {
+ WSREP_DEBUG("skipping select metadata");
+ DBUG_RETURN(false);
+ }
+ #endif /* WITH_WSREP */
+ if (select->join->result->send_result_set_metadata(result_columns,
+ Protocol::SEND_NUM_ROWS |
+ Protocol::SEND_EOF))
+ DBUG_RETURN(true);
+
+ DBUG_RETURN(false);
+}
+
+
+bool select_handler::send_data()
+{
+ DBUG_ENTER("Pushdown_select::send_data");
+
+ if (select->join->result->send_data(result_columns))
+ DBUG_RETURN(true);
+
+ DBUG_RETURN(false);
+}
+
+
+bool select_handler::send_eof()
+{
+ DBUG_ENTER("select_handler::send_eof");
+
+ if (select->join->result->send_eof())
+ DBUG_RETURN(true);
+ DBUG_RETURN(false);
+}
+
+
+int select_handler::execute()
+{
+ int err;
+
+ DBUG_ENTER("select_handler::execute");
+
+ if ((err= init_scan()))
+ goto error;
+
+ if (is_analyze)
+ {
+ end_scan();
+ DBUG_RETURN(0);
+ }
+
+ if (send_result_set_metadata())
+ DBUG_RETURN(-1);
+
+ while (!(err= next_row()))
+ {
+ if (thd->check_killed() || send_data())
+ {
+ end_scan();
+ DBUG_RETURN(-1);
+ }
+ }
+
+ if (err != 0 && err != HA_ERR_END_OF_FILE)
+ goto error;
+
+ if ((err= end_scan()))
+ goto error_2;
+
+ if (send_eof())
+ DBUG_RETURN(-1);
+
+ DBUG_RETURN(0);
+
+error:
+ end_scan();
+error_2:
+ print_error(err, MYF(0));
+ DBUG_RETURN(-1); // Error not sent to client
+}
+
+void select_handler::print_error(int error, myf errflag)
+{
+ my_error(ER_GET_ERRNO, MYF(0), error, hton_name(ht)->str);
+}