You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
426 lines
11 KiB
426 lines
11 KiB
5 months ago
|
/* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||
|
|
||
|
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, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
||
|
|
||
|
#ifndef TABLE_FUNCTION_INCLUDED
|
||
|
#define TABLE_FUNCTION_INCLUDED
|
||
|
|
||
|
#include <sys/types.h>
|
||
|
#include <array> // std::array
|
||
|
|
||
|
#include "field.h" // Field
|
||
|
#include "json_dom.h" // Json_wrapper
|
||
|
#include "json_path.h" // Json_path
|
||
|
#include "lex_string.h"
|
||
|
#include "my_dbug.h"
|
||
|
#include "my_inttypes.h"
|
||
|
#include "my_table_map.h"
|
||
|
#include "psi_memory_key.h" // key_memory_JSON
|
||
|
#include "sql/create_field.h"
|
||
|
#include "sql/enum_query_type.h"
|
||
|
|
||
|
#include "sql/mem_root_array.h"
|
||
|
#include "sql_list.h" // List
|
||
|
#include "table.h" // TABLE
|
||
|
|
||
|
class Item;
|
||
|
class String;
|
||
|
class THD;
|
||
|
|
||
|
/**
|
||
|
Class representing a table function.
|
||
|
*/
|
||
|
|
||
|
class Table_function {
|
||
|
protected:
|
||
|
/// Thread handler
|
||
|
THD *thd;
|
||
|
/// Table function's result table
|
||
|
TABLE *table;
|
||
|
/// Whether the table funciton was already initialized
|
||
|
bool inited;
|
||
|
|
||
|
public:
|
||
|
Table_function(THD *thd_arg) : thd(thd_arg), table(nullptr), inited(false) {}
|
||
|
|
||
|
virtual ~Table_function() {}
|
||
|
/**
|
||
|
Create, but not instantiate the result table
|
||
|
|
||
|
@param options options to create table
|
||
|
@param table_alias table's alias
|
||
|
|
||
|
@returns
|
||
|
true on error
|
||
|
false on success
|
||
|
*/
|
||
|
bool create_result_table(ulonglong options, const char *table_alias);
|
||
|
/**
|
||
|
Write current record to the result table and handle overflow to disk
|
||
|
|
||
|
@returns
|
||
|
true on error
|
||
|
false on success
|
||
|
*/
|
||
|
bool write_row();
|
||
|
|
||
|
/**
|
||
|
Returns a field with given index
|
||
|
|
||
|
@param i field's index
|
||
|
|
||
|
@returns
|
||
|
field with given index
|
||
|
*/
|
||
|
Field *get_field(uint i) {
|
||
|
DBUG_ASSERT(i < table->s->fields);
|
||
|
return table->field[i];
|
||
|
}
|
||
|
/**
|
||
|
Delete all rows in the table
|
||
|
*/
|
||
|
void empty_table();
|
||
|
|
||
|
/**
|
||
|
Set the default row
|
||
|
*/
|
||
|
void default_row() {}
|
||
|
/**
|
||
|
Initialize table function
|
||
|
@returns
|
||
|
true on error
|
||
|
false on success
|
||
|
*/
|
||
|
virtual bool init() = 0;
|
||
|
/**
|
||
|
Initialize table function after the result table has been created
|
||
|
@returns
|
||
|
true on error
|
||
|
false on success
|
||
|
*/
|
||
|
virtual bool init_args();
|
||
|
/**
|
||
|
Execute the table function - fill the result table
|
||
|
@returns
|
||
|
true on error
|
||
|
false on success
|
||
|
*/
|
||
|
virtual bool fill_result_table() = 0;
|
||
|
/**
|
||
|
Returns table function's name
|
||
|
*/
|
||
|
virtual const char *func_name() const = 0;
|
||
|
/**
|
||
|
Return table_map of tables used by the function
|
||
|
*/
|
||
|
virtual table_map used_tables() { return 0; }
|
||
|
/**
|
||
|
Print table function
|
||
|
|
||
|
@param str string to print to
|
||
|
@param query_type type of the query
|
||
|
|
||
|
@returns
|
||
|
true on error
|
||
|
false on success
|
||
|
*/
|
||
|
virtual bool print(String *str, enum_query_type query_type) = 0;
|
||
|
/**
|
||
|
Clean up table function
|
||
|
*/
|
||
|
void cleanup() {
|
||
|
do_cleanup();
|
||
|
table = nullptr;
|
||
|
inited = false;
|
||
|
}
|
||
|
/**
|
||
|
Retruns thread handler
|
||
|
|
||
|
@returns
|
||
|
thread handler
|
||
|
*/
|
||
|
inline THD *get_thd() { return thd; }
|
||
|
|
||
|
virtual bool walk(Item_processor processor, enum_walk walk, uchar *arg) = 0;
|
||
|
|
||
|
private:
|
||
|
/**
|
||
|
Get the list of fields to create the result table
|
||
|
*/
|
||
|
virtual List<Create_field> *get_field_list() = 0;
|
||
|
/**
|
||
|
Initialize table function's arguments
|
||
|
|
||
|
@returns
|
||
|
true on error
|
||
|
false on success
|
||
|
*/
|
||
|
virtual bool do_init_args() = 0;
|
||
|
friend bool TABLE_LIST::setup_table_function(THD *thd);
|
||
|
virtual void do_cleanup() {}
|
||
|
};
|
||
|
|
||
|
/****************************************************************************
|
||
|
JSON_TABLE function
|
||
|
****************************************************************************/
|
||
|
|
||
|
/// Type of columns for JSON_TABLE function
|
||
|
enum class enum_jt_column {
|
||
|
JTC_ORDINALITY,
|
||
|
JTC_PATH,
|
||
|
JTC_EXISTS,
|
||
|
JTC_NESTED_PATH
|
||
|
};
|
||
|
|
||
|
/// Types of ON ERROR/ON EMPTY clause for JSON_TABLE function
|
||
|
/// @note uint16 enum base limitation is necessary for YYSTYPE.
|
||
|
enum class enum_jtc_on : uint16 {
|
||
|
JTO_ERROR,
|
||
|
JTO_NULL,
|
||
|
JTO_DEFAULT,
|
||
|
JTO_IMPLICIT
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
JT_data_source is used as a data source. It's assigned to each NESTED PATH
|
||
|
node.
|
||
|
*/
|
||
|
|
||
|
class JT_data_source {
|
||
|
public:
|
||
|
/// Vector of found values
|
||
|
Json_wrapper_vector v;
|
||
|
/// Iterator for vector above
|
||
|
Json_wrapper_vector::iterator it;
|
||
|
/// JSON data to seek columns' paths in
|
||
|
Json_wrapper jdata;
|
||
|
/// Current m_rowid, used for ORDINALITY columns
|
||
|
uint m_rowid;
|
||
|
/**
|
||
|
true <=> NESTED PATH associated with this element is producing records.
|
||
|
Used to turn off (set to null) sibling NESTED PATHs, when one of them is
|
||
|
used to fill result table.
|
||
|
*/
|
||
|
bool producing_records;
|
||
|
|
||
|
JT_data_source() : v(key_memory_JSON), producing_records(false) {}
|
||
|
~JT_data_source() {}
|
||
|
|
||
|
void cleanup();
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
Reason for skipping a NESTED PATH
|
||
|
*/
|
||
|
enum jt_skip_reason {
|
||
|
JTS_NONE = 0, // NESTED PATH isn't skipped
|
||
|
JTS_EOD, // No more data
|
||
|
JTS_SIBLING // Skipped due to other sibling NESTED PATH is running
|
||
|
};
|
||
|
|
||
|
/// Column description for JSON_TABLE function
|
||
|
class Json_table_column : public Create_field {
|
||
|
public:
|
||
|
/// Column type
|
||
|
enum_jt_column m_jtc_type;
|
||
|
/// Type of ON ERROR clause
|
||
|
enum_jtc_on m_on_error{enum_jtc_on::JTO_IMPLICIT};
|
||
|
/// Type of ON EMPTY clause
|
||
|
enum_jtc_on m_on_empty{enum_jtc_on::JTO_IMPLICIT};
|
||
|
/// Default value string for ON EMPTY clause
|
||
|
LEX_STRING m_default_empty_str;
|
||
|
/// Parsed JSON for default value of ON MISSING clause
|
||
|
Json_wrapper m_default_empty_json;
|
||
|
/// Default value string for ON ERROR clause
|
||
|
LEX_STRING m_default_error_str;
|
||
|
/// Parsed JSON string for ON ERROR clause
|
||
|
Json_wrapper m_default_error_json;
|
||
|
/// List of nested columns, valid only for NESTED PATH
|
||
|
List<Json_table_column> *m_nested_columns;
|
||
|
/// Nested path
|
||
|
LEX_STRING m_path_str;
|
||
|
/// parsed nested path
|
||
|
Json_path m_path_json;
|
||
|
/// An element in table function's data source array
|
||
|
JT_data_source *m_jds_elt{nullptr};
|
||
|
/**
|
||
|
Element in table function's data source array to feed data to child
|
||
|
nodes. Valid only for NESTED PATH.
|
||
|
*/
|
||
|
JT_data_source *m_child_jds_elt{nullptr};
|
||
|
/// Next sibling NESTED PATH
|
||
|
Json_table_column *m_next_nested{nullptr};
|
||
|
/// Previous sibling NESTED PATH
|
||
|
Json_table_column *m_prev_nested{nullptr};
|
||
|
/// Index of field in the result table
|
||
|
int m_field_idx{-1};
|
||
|
|
||
|
public:
|
||
|
Json_table_column(enum_jt_column type)
|
||
|
: m_jtc_type(type),
|
||
|
m_jds_elt(nullptr),
|
||
|
m_child_jds_elt(nullptr),
|
||
|
m_next_nested(nullptr),
|
||
|
m_prev_nested(nullptr),
|
||
|
m_field_idx(-1) {}
|
||
|
Json_table_column(enum_jt_column col_type, const LEX_STRING &path,
|
||
|
enum_jtc_on on_err, const LEX_STRING error_def,
|
||
|
enum_jtc_on on_miss, const LEX_STRING &missing_def)
|
||
|
: m_jtc_type(col_type),
|
||
|
m_on_error(on_err),
|
||
|
m_on_empty(on_miss),
|
||
|
m_default_empty_str(missing_def),
|
||
|
m_default_error_str(error_def),
|
||
|
m_path_str(path) {}
|
||
|
Json_table_column(LEX_STRING path, List<Json_table_column> *cols)
|
||
|
: m_jtc_type(enum_jt_column::JTC_NESTED_PATH),
|
||
|
m_nested_columns(cols),
|
||
|
m_path_str(path) {}
|
||
|
void cleanup();
|
||
|
|
||
|
/**
|
||
|
Process JSON_TABLE's column
|
||
|
|
||
|
@param fld field to save data to, if applicable, NULL otherwise
|
||
|
@param[out] skip whether current NESTED PATH column should be
|
||
|
completely skipped
|
||
|
@returns
|
||
|
true on error
|
||
|
false on success
|
||
|
*/
|
||
|
bool fill_column(Field *fld, jt_skip_reason *skip);
|
||
|
};
|
||
|
|
||
|
#define MAX_NESTED_PATH 16
|
||
|
|
||
|
class Table_function_json final : public Table_function {
|
||
|
/// Array of JSON Data Source for each NESTED PATH clause
|
||
|
std::array<JT_data_source, MAX_NESTED_PATH> m_jds;
|
||
|
/// List of fields for tmp table creation
|
||
|
List<Json_table_column> m_vt_list;
|
||
|
/// Tree of COLUMN clauses
|
||
|
List<Json_table_column> *m_columns;
|
||
|
/// Array of all columns - the flattened tree above
|
||
|
Mem_root_array<Json_table_column *> m_all_columns;
|
||
|
/// JSON_TABLE's alias, for error reporting
|
||
|
const char *m_table_alias;
|
||
|
|
||
|
/** Whether source data has been parsed. */
|
||
|
bool is_source_parsed;
|
||
|
/// JSON_TABLE's data source expression
|
||
|
Item *source;
|
||
|
|
||
|
public:
|
||
|
Table_function_json(THD *thd_arg, const char *alias, Item *a,
|
||
|
List<Json_table_column> *cols);
|
||
|
|
||
|
/**
|
||
|
Returns function's name
|
||
|
*/
|
||
|
const char *func_name() const override { return "json_table"; }
|
||
|
/**
|
||
|
Initialize the table function before creation of result table
|
||
|
|
||
|
@returns
|
||
|
true on error
|
||
|
false on success
|
||
|
*/
|
||
|
bool init() override;
|
||
|
|
||
|
/**
|
||
|
Execute table function
|
||
|
|
||
|
@returns
|
||
|
true on error
|
||
|
false on success
|
||
|
*/
|
||
|
bool fill_result_table() override;
|
||
|
|
||
|
/**
|
||
|
Return table_map of tables used by function's data source
|
||
|
*/
|
||
|
table_map used_tables() override;
|
||
|
|
||
|
/**
|
||
|
JSON_TABLE printout
|
||
|
|
||
|
@param str string to print to
|
||
|
@param query_type type of query
|
||
|
|
||
|
@returns
|
||
|
true on error
|
||
|
false on success
|
||
|
*/
|
||
|
bool print(String *str, enum_query_type query_type) override;
|
||
|
|
||
|
bool walk(Item_processor processor, enum_walk walk, uchar *arg) override;
|
||
|
|
||
|
private:
|
||
|
/**
|
||
|
Fill the result table
|
||
|
|
||
|
@returns
|
||
|
true on error
|
||
|
false on success
|
||
|
*/
|
||
|
bool fill_json_table();
|
||
|
|
||
|
/**
|
||
|
Prepare lists used to create tmp table and function execution
|
||
|
|
||
|
@param nest_idx index of parent's element in the nesting data array
|
||
|
@param parent Parent of the NESTED PATH clause being initialized
|
||
|
|
||
|
@returns
|
||
|
true on error
|
||
|
false on success
|
||
|
*/
|
||
|
bool init_json_table_col_lists(uint *nest_idx, Json_table_column *parent);
|
||
|
/**
|
||
|
Set all underlying columns of a NESTED PATH to nullptr
|
||
|
|
||
|
@param root root NESTED PATH column
|
||
|
@param [out] last last column which belongs to the given NESTED PATH
|
||
|
*/
|
||
|
void set_subtree_to_null(Json_table_column *root, Json_table_column **last);
|
||
|
/**
|
||
|
Helper function to print single NESTED PATH column
|
||
|
|
||
|
@param col column to print
|
||
|
@param str string to print to
|
||
|
@param query_type type of the query
|
||
|
|
||
|
@returns
|
||
|
true on error
|
||
|
false on success
|
||
|
*/
|
||
|
bool print_nested_path(Json_table_column *col, String *str,
|
||
|
enum_query_type query_type);
|
||
|
|
||
|
/**
|
||
|
Return list of fields to create result table from
|
||
|
*/
|
||
|
List<Create_field> *get_field_list() override;
|
||
|
bool do_init_args() override;
|
||
|
void do_cleanup() override;
|
||
|
};
|
||
|
#endif /* TABLE_FUNCTION_INCLUDED */
|