File func_type.cpp¶
File List > cubrid > src > parser > func_type.cpp
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* func_type.cpp
*/
#include "dbtype.h"
#include "func_type.hpp"
#include "message_catalog.h"
#include "object_primitive.h"
#include "parse_tree.h"
#include "parser.h"
#include "parser_message.h"
#include <algorithm>
//PT_TYPE_MAYBE
// - for the moment I don't see how to eliminate PT_TYPE_MAYBE from functions with multiple signature
// - with PT_TYPE_MAYBE in signature, the final type will not be decided during type checking but later
// - without PT_TYPE_MAYBE in signature you must either:
// 1. choose one signature and apply cast
// ... but what about "prepare median(?)... execute with date'2018-06-13'... execute with 123"?
// 2. handle from code
// ... but there are cases when the cast should be made
// but neither one of them is OK
func_all_signatures sig_ret_int_no_arg =
{
{PT_TYPE_INTEGER, {}, {}},
};
func_all_signatures sig_ret_int_arg_any =
{
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_ANY}, {}},
};
func_all_signatures sig_ret_int_arg_doc =
{
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_JSON_DOC}, {}},
};
func_all_signatures sig_ret_int_arg_str =
{
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_STRING}, {}},
};
func_all_signatures sig_ret_bigint =
{
{PT_TYPE_BIGINT, {}, {}},
};
func_all_signatures sig_of_percentile_cont =
{
#if 1
{PT_TYPE_MAYBE, {PT_GENERIC_TYPE_NUMBER}, {}},
{0, {PT_GENERIC_TYPE_DATETIME}, {}},
{PT_TYPE_MAYBE, {PT_GENERIC_TYPE_STRING}, {}},
{0, {PT_TYPE_MAYBE}, {}},
#else //use double as return type (as documentation says)... but tests are failing (adjust doc or tests)
{PT_TYPE_DOUBLE, {PT_GENERIC_TYPE_NUMBER}, {}},
{0, {PT_GENERIC_TYPE_STRING}, {}},
{PT_TYPE_DOUBLE, {PT_GENERIC_TYPE_DATETIME}, {}},
{0, {PT_TYPE_MAYBE}, {}},
{0, {PT_TYPE_NA}, {}},
#endif
};
func_all_signatures sig_of_percentile_disc =
{
{PT_TYPE_MAYBE, {PT_GENERIC_TYPE_NUMBER}, {}},
{0, {PT_GENERIC_TYPE_DATETIME}, {}},
{PT_TYPE_MAYBE, {PT_GENERIC_TYPE_STRING}, {}},
{0, {PT_TYPE_MAYBE}, {}},
};
func_all_signatures sig_ret_bigint_arg_discrete =
{
{PT_TYPE_BIGINT, {PT_GENERIC_TYPE_DISCRETE_NUMBER}, {}},
{PT_TYPE_BIGINT, {PT_TYPE_NA}, {}}, //not needed???
};
func_all_signatures sig_of_avg =
{
{PT_TYPE_DOUBLE, {PT_GENERIC_TYPE_NUMBER}, {}},
};
func_all_signatures sig_ret_double_arg_number =
{
{PT_TYPE_DOUBLE, {PT_GENERIC_TYPE_NUMBER}, {}},
};
func_all_signatures sig_of_count_star =
{
{PT_TYPE_BIGINT, {}, {}},
};
func_all_signatures sig_of_count =
{
{PT_TYPE_BIGINT, {PT_GENERIC_TYPE_ANY}, {}},
};
func_all_signatures sig_of_sum =
{
{0, {PT_GENERIC_TYPE_NUMBER}, {}},
{0, {PT_TYPE_MAYBE}, {}},
{0, {PT_TYPE_SET}, {}},
{0, {PT_TYPE_MULTISET}, {}},
{0, {PT_TYPE_SEQUENCE}, {}},
};
func_all_signatures sig_ret_double_arg_r_any =
{
{PT_TYPE_DOUBLE, {}, {}},
{PT_TYPE_DOUBLE, {}, {PT_GENERIC_TYPE_ANY}},
};
func_all_signatures sig_of_ntile =
{
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_NUMBER}, {}}, //argument value will be truncated at execution
};
/*cannot define a clear signature because casting depends on actual value
MEDIAN('123456') <=> MEDIAN(double) -> double
MEDIAN('2018-03-14') <=> MEDIAN(date) -> date */
func_all_signatures sig_of_median =
{
{PT_TYPE_MAYBE, {PT_GENERIC_TYPE_NUMBER}, {}}, //if ret type is double => tests with median(int) will fail
{0, {PT_GENERIC_TYPE_DATETIME}, {}},
{PT_TYPE_MAYBE, {PT_GENERIC_TYPE_STRING}, {}},
{0, {PT_TYPE_MAYBE}, {}}, //DISCUSSION: can we get rid of MAYBE here??? prepare median(?)...execute with date'2018-06-13'
};
func_all_signatures sig_ret_type0_arg_scalar =
{
{0, {PT_GENERIC_TYPE_SCALAR}, {}},
};
func_all_signatures sig_ret_type0_arg_nr_or_str_discrete =
{
{0, {PT_GENERIC_TYPE_NUMBER, PT_GENERIC_TYPE_DISCRETE_NUMBER}, {}},
{0, {PT_GENERIC_TYPE_DATETIME, PT_GENERIC_TYPE_DISCRETE_NUMBER}, {}},
{0, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_DISCRETE_NUMBER}, {}},
{0, {PT_GENERIC_TYPE_BIT, PT_GENERIC_TYPE_DISCRETE_NUMBER}, {}},
{0, {PT_TYPE_ENUMERATION, PT_GENERIC_TYPE_DISCRETE_NUMBER}, {}},
};
func_all_signatures sig_of_group_concat =
{
{PT_TYPE_VARCHAR, {PT_TYPE_ENUMERATION, PT_GENERIC_TYPE_CHAR}, {}}, //needed because pt_are_equivalent_types(PT_GENERIC_TYPE_CHAR, PT_TYPE_ENUMERATION) and casting to VCHR will affect order
//normal cases
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_CHAR, PT_GENERIC_TYPE_CHAR}, {}},
{PT_TYPE_VARBIT, {PT_GENERIC_TYPE_BIT, PT_GENERIC_TYPE_BIT}, {}},
#if 0 //anything else should be casted to separator's type (if possible! makes sense to detect incompatible types when detecting/applying signatures?); NOTE: casting affects the order!!!
{PT_TYPE_VARCHAR, {1, PT_GENERIC_TYPE_CHAR }, {}}, //test
#else //anything else should be left untouched (like in the original code), maybe it will be casted later?
#if 0 //it allows group_concat(SET) but it should not!
//{PT_TYPE_VARCHAR , {PT_GENERIC_TYPE_ANY , PT_GENERIC_TYPE_CHAR }, {}},
#else //OK to keep the order but it allows cast (n)char -> number and it should not because group_concat(n'123', ', ') should be rejected?!
//like that it allows group_concat(n'123', ', ') or group_concat(<nchar field>, ', ') when <nchar field> can be casted to double (acceptable for me)
//but solved in preprocess for compatibility to original behaviour
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_NUMBER, PT_GENERIC_TYPE_CHAR}, {}},
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_DATETIME, PT_GENERIC_TYPE_CHAR}, {}},
#endif
#endif
};
func_all_signatures sig_of_lead_lag =
{
{0, {PT_GENERIC_TYPE_NUMBER}, {}},
{0, {PT_GENERIC_TYPE_STRING}, {}},
{0, {PT_GENERIC_TYPE_DATETIME}, {}},
{0, {PT_GENERIC_TYPE_BIT}, {}},
{0, {PT_GENERIC_TYPE_SEQUENCE}, {}},
};
func_all_signatures sig_of_elt =
{
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_DISCRETE_NUMBER}, {PT_TYPE_VARCHAR}}, //get_current_result() expects args to be VCHAR, not just equivalent
{PT_TYPE_NULL, {PT_GENERIC_TYPE_DISCRETE_NUMBER}, {}},
};
func_all_signatures sig_of_insert_substring =
{
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_CHAR, PT_TYPE_INTEGER, PT_TYPE_INTEGER, PT_GENERIC_TYPE_CHAR}, {}},
//{0, {3, PT_TYPE_INTEGER, PT_TYPE_INTEGER, PT_GENERIC_TYPE_STRING}, {}}, //for insert(?, i, i, 'char or anything else')
};
func_all_signatures sig_ret_json_arg_r_jkey_jval_or_empty =
{
{PT_TYPE_JSON, {}, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_JSON_VAL}},
{PT_TYPE_JSON, {}, {}}
};
func_all_signatures sig_json_arg_r_jval_or_empty =
{
{PT_TYPE_JSON, {}, {PT_GENERIC_TYPE_JSON_VAL}},
{PT_TYPE_JSON, {}, {}}
};
func_all_signatures sig_ret_json_arg_jdoc =
{
{PT_TYPE_JSON, {PT_GENERIC_TYPE_JSON_DOC}, {}},
};
func_all_signatures sig_ret_json_arg_jdoc_r_jdoc =
{
{PT_TYPE_JSON, {PT_GENERIC_TYPE_JSON_DOC}, {PT_GENERIC_TYPE_JSON_DOC}},
};
func_all_signatures sig_ret_json_arg_jdoc_jpath =
{
{PT_TYPE_JSON, {PT_GENERIC_TYPE_JSON_DOC, PT_GENERIC_TYPE_STRING}, {}},
};
func_all_signatures sig_ret_json_arg_jdoc_r_jpath =
{
{PT_TYPE_JSON, {PT_GENERIC_TYPE_JSON_DOC}, {PT_GENERIC_TYPE_STRING}},
};
func_all_signatures sig_ret_json_arg_jdoc_str_r_jpath =
{
{PT_TYPE_JSON, {PT_GENERIC_TYPE_JSON_DOC, PT_GENERIC_TYPE_STRING}, {PT_GENERIC_TYPE_STRING}},
};
func_all_signatures sig_ret_json_arg_jdoc_r_jpath_jval =
{
{PT_TYPE_JSON, {PT_GENERIC_TYPE_JSON_DOC}, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_JSON_VAL}},
};
func_all_signatures sig_of_json_contains =
{
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_JSON_DOC, PT_GENERIC_TYPE_JSON_DOC}, {}},
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_JSON_DOC, PT_GENERIC_TYPE_JSON_DOC, PT_GENERIC_TYPE_STRING}, {}},
};
func_all_signatures sig_of_json_contains_path =
{
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_JSON_DOC, PT_GENERIC_TYPE_STRING}, {PT_GENERIC_TYPE_STRING}},
};
func_all_signatures sig_of_json_keys =
{
{PT_TYPE_JSON, {PT_GENERIC_TYPE_JSON_DOC}, {}},
{PT_TYPE_JSON, {PT_GENERIC_TYPE_JSON_DOC, PT_GENERIC_TYPE_STRING}, {}},
};
func_all_signatures sig_of_json_length =
{
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_JSON_DOC}, {}},
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_JSON_DOC, PT_GENERIC_TYPE_STRING}, {}},
};
func_all_signatures sig_of_json_search =
{
// all signatures: json_doc, one_or_all_str, search_str[, escape_char[, path] ... -> JSON_DOC
// first overload: json_doc, one_or_all_str, search_str:
{PT_TYPE_JSON, {PT_GENERIC_TYPE_JSON_DOC, PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING}, {}},
// second overload: json_doc, one_or_all_str, search_str, escape_char
{PT_TYPE_JSON, {PT_GENERIC_TYPE_JSON_DOC, PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING}, {}},
// third overload: json_doc, one_or_all_str, search_str, escape_char, path...
{
PT_TYPE_JSON,
{PT_GENERIC_TYPE_JSON_DOC, PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING},
{PT_GENERIC_TYPE_STRING}
},
};
func_all_signatures sig_of_json_arrayagg =
{
{PT_TYPE_JSON, {PT_GENERIC_TYPE_JSON_VAL}, {}}
};
func_all_signatures sig_of_json_objectagg =
{
{PT_TYPE_JSON, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_JSON_VAL}, {}}
};
func_all_signatures sig_ret_set_arg_r_any =
{
{PT_TYPE_SET, {}, {PT_GENERIC_TYPE_ANY}},
};
func_all_signatures sig_ret_multiset_arg_r_any =
{
{PT_TYPE_MULTISET, {}, {PT_GENERIC_TYPE_ANY}},
};
func_all_signatures sig_ret_sequence_arg_r_any =
{
{PT_TYPE_SEQUENCE, {}, {PT_GENERIC_TYPE_ANY}},
};
func_all_signatures sig_of_generic =
{
{0, {PT_GENERIC_TYPE_ANY}, {}},
};
func_all_signatures sig_ret_string_arg_jdoc =
{
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_JSON_DOC}, {}},
};
func_all_signatures sig_ret_type0_arg_str =
{
{0, {PT_GENERIC_TYPE_STRING}, {}},
};
func_all_signatures sig_of_benchmark =
{
{PT_TYPE_DOUBLE, {PT_GENERIC_TYPE_DISCRETE_NUMBER, PT_GENERIC_TYPE_ANY}, {}},
};
func_all_signatures sig_of_regexp_count =
{
// all signatures: src, pattern [,position, [,match_type ]] -> INTEGER
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING}, {}},
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_TYPE_INTEGER}, {}},
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_TYPE_INTEGER, PT_GENERIC_TYPE_CHAR}, {}},
};
func_all_signatures sig_of_regexp_instr =
{
// all signatures: src, pattern [,position [,occurrence [,return_option [,match_type ]]]] -> INTEGER
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING}, {}},
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_TYPE_INTEGER}, {}},
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_TYPE_INTEGER, PT_TYPE_INTEGER}, {}},
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_TYPE_INTEGER, PT_TYPE_INTEGER, PT_TYPE_INTEGER}, {}},
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_TYPE_INTEGER, PT_TYPE_INTEGER, PT_TYPE_INTEGER, PT_GENERIC_TYPE_CHAR}, {}},
};
func_all_signatures sig_of_regexp_like =
{
// all signatures: src, pattern [,match_type ] -> INTEGER
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING}, {}},
{PT_TYPE_INTEGER, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_CHAR}, {}},
};
func_all_signatures sig_of_regexp_replace =
{
// all signatures: src, pattern, replacement [,position [,occurrence [, match_type]]] -> STRING
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING}, {}},
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_TYPE_INTEGER}, {}},
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_TYPE_INTEGER, PT_TYPE_INTEGER}, {}},
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_TYPE_INTEGER, PT_TYPE_INTEGER, PT_GENERIC_TYPE_STRING}, {}},
};
func_all_signatures sig_of_regexp_substr =
{
// all signatures: src, pattern [,position [,occurrence [, match_type]]] -> STRING
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING}, {}},
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_TYPE_INTEGER}, {}},
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_TYPE_INTEGER, PT_TYPE_INTEGER}, {}},
{PT_TYPE_VARCHAR, {PT_GENERIC_TYPE_STRING, PT_GENERIC_TYPE_STRING, PT_TYPE_INTEGER, PT_TYPE_INTEGER, PT_GENERIC_TYPE_CHAR}, {}},
};
func_all_signatures *
get_signatures (FUNC_CODE ft)
{
switch (ft)
{
case PT_MIN:
case PT_MAX:
return &sig_ret_type0_arg_scalar;
case PT_SUM:
return &sig_of_sum;
case PT_AVG:
return &sig_of_avg;
case PT_STDDEV:
case PT_VARIANCE:
case PT_STDDEV_POP:
case PT_VAR_POP:
case PT_STDDEV_SAMP:
case PT_VAR_SAMP:
return &sig_ret_double_arg_number;
case PT_COUNT:
return &sig_of_count;
case PT_COUNT_STAR:
return &sig_of_count_star;
case PT_GROUPBY_NUM:
return &sig_ret_bigint;
case PT_AGG_BIT_AND:
case PT_AGG_BIT_OR:
case PT_AGG_BIT_XOR:
return &sig_ret_bigint_arg_discrete;
case PT_GROUP_CONCAT:
return &sig_of_group_concat;
case PT_ROW_NUMBER:
case PT_RANK:
case PT_DENSE_RANK:
return &sig_ret_int_no_arg;
case PT_NTILE:
return &sig_of_ntile;
case PT_TOP_AGG_FUNC:
return nullptr;
case PT_LEAD:
case PT_LAG:
return &sig_of_lead_lag;
case PT_GENERIC:
return &sig_of_generic;
case F_SET:
case F_TABLE_SET:
return &sig_ret_set_arg_r_any;
case F_MULTISET:
case F_TABLE_MULTISET:
return &sig_ret_multiset_arg_r_any;
case F_SEQUENCE:
case F_TABLE_SEQUENCE:
return &sig_ret_sequence_arg_r_any;
case F_TOP_TABLE_FUNC:
return nullptr;
case F_MIDXKEY:
return nullptr;
case F_VID:
case F_GENERIC:
case F_CLASS_OF:
return nullptr;
case F_INSERT_SUBSTRING:
return &sig_of_insert_substring;
case F_ELT:
return &sig_of_elt;
case F_BENCHMARK:
return &sig_of_benchmark;
case F_JSON_ARRAY:
return &sig_json_arg_r_jval_or_empty;
case F_JSON_ARRAY_APPEND:
case F_JSON_ARRAY_INSERT:
return &sig_ret_json_arg_jdoc_r_jpath_jval;
case F_JSON_CONTAINS:
return &sig_of_json_contains;
case F_JSON_CONTAINS_PATH:
return &sig_of_json_contains_path;
case F_JSON_DEPTH:
return &sig_ret_int_arg_doc;
case F_JSON_EXTRACT:
return &sig_ret_json_arg_jdoc_r_jpath;
case F_JSON_GET_ALL_PATHS:
return &sig_ret_json_arg_jdoc;
case F_JSON_INSERT:
return &sig_ret_json_arg_jdoc_r_jpath_jval;
case F_JSON_KEYS:
return &sig_of_json_keys;
case F_JSON_LENGTH:
return &sig_of_json_length;
case F_JSON_MERGE:
case F_JSON_MERGE_PATCH:
return &sig_ret_json_arg_jdoc_r_jdoc;
case F_JSON_OBJECT:
return &sig_ret_json_arg_r_jkey_jval_or_empty;
case F_JSON_PRETTY:
return &sig_ret_string_arg_jdoc;
case F_JSON_QUOTE:
return &sig_ret_type0_arg_str;
case F_JSON_REMOVE:
return &sig_ret_json_arg_jdoc_r_jpath;
case F_JSON_REPLACE:
return &sig_ret_json_arg_jdoc_r_jpath_jval;
case F_JSON_SEARCH:
return &sig_of_json_search;
case F_JSON_SET:
return &sig_ret_json_arg_jdoc_r_jpath_jval;
case F_JSON_TYPE:
return &sig_ret_string_arg_jdoc;
case F_JSON_UNQUOTE:
return &sig_ret_string_arg_jdoc;
case F_JSON_VALID:
return &sig_ret_int_arg_any;
case PT_FIRST_VALUE:
case PT_LAST_VALUE:
return &sig_ret_type0_arg_scalar;
case PT_NTH_VALUE:
return &sig_ret_type0_arg_nr_or_str_discrete;
case PT_MEDIAN:
return &sig_of_median;
case PT_CUME_DIST:
case PT_PERCENT_RANK:
return &sig_ret_double_arg_r_any;
case PT_PERCENTILE_CONT:
return &sig_of_percentile_cont;
case PT_PERCENTILE_DISC:
return &sig_of_percentile_disc;
case PT_JSON_ARRAYAGG:
return &sig_of_json_arrayagg;
case PT_JSON_OBJECTAGG:
return &sig_of_json_objectagg;
case F_REGEXP_COUNT:
return &sig_of_regexp_count;
case F_REGEXP_INSTR:
return &sig_of_regexp_instr;
case F_REGEXP_LIKE:
return &sig_of_regexp_like;
case F_REGEXP_REPLACE:
return &sig_of_regexp_replace;
case F_REGEXP_SUBSTR:
return &sig_of_regexp_substr;
default:
assert (false);
return nullptr;
}
}
void
func_signature::to_string_buffer (string_buffer &sb) const
{
bool first = true;
for (auto fix_arg : fix)
{
if (first)
{
first = false;
}
else
{
sb (", ");
}
pt_arg_type_to_string_buffer (fix_arg, sb);
}
if (!rep.empty ())
{
if (!first)
{
sb (", ");
}
sb ("repeat[");
first = true;
for (auto rep_arg : rep)
{
if (first)
{
first = false;
}
else
{
sb (", ");
}
pt_arg_type_to_string_buffer (rep_arg, sb);
}
sb ("]");
}
sb (" -> ");
pt_arg_type_to_string_buffer (ret, sb);
}
namespace func_type
{
argument_resolve::argument_resolve ()
: m_type (PT_TYPE_NONE)
, m_check_coll_infer (false)
, m_coll_infer ()
{
//
}
signature_compatibility::signature_compatibility ()
: m_compat (type_compatibility::INCOMPATIBLE)
, m_args_resolve {}
, m_common_collation {}
, m_collation_action (TP_DOMAIN_COLL_LEAVE)
, m_signature (NULL)
{
//
}
bool
sig_has_json_args (const func_signature &sig)
{
auto find_pred = [] (const pt_arg_type & arg)
{
return arg.type == arg.GENERIC && (arg.val.generic_type == PT_GENERIC_TYPE_JSON_DOC
|| arg.val.generic_type == PT_GENERIC_TYPE_JSON_VAL);
};
auto it_found = std::find_if (sig.fix.begin (), sig.fix.end (), find_pred);
if (it_found != sig.fix.end ())
{
return true;
}
// also search in repeateable args
it_found = std::find_if (sig.rep.begin (), sig.rep.end (), find_pred);
return it_found != sig.rep.end ();
}
bool
is_type_with_collation (PT_TYPE_ENUM type)
{
return PT_HAS_COLLATION (type) || type == PT_TYPE_MAYBE;
}
bool
can_signature_have_collation (const pt_arg_type &arg_sig)
{
switch (arg_sig.type)
{
case pt_arg_type::NORMAL:
// types that can have collations
return is_type_with_collation (arg_sig.val.type);
case pt_arg_type::GENERIC:
// all generic that can accept string (and result is still string)
return arg_sig.val.generic_type == PT_GENERIC_TYPE_STRING
|| arg_sig.val.generic_type == PT_GENERIC_TYPE_STRING_VARYING
|| arg_sig.val.generic_type == PT_GENERIC_TYPE_CHAR
|| arg_sig.val.generic_type == PT_GENERIC_TYPE_PRIMITIVE
|| arg_sig.val.generic_type == PT_GENERIC_TYPE_ANY
|| arg_sig.val.generic_type == PT_GENERIC_TYPE_SCALAR;
case pt_arg_type::INDEX:
default:
assert (false);
return false;
}
}
bool
cmp_types_equivalent (const pt_arg_type &type, pt_type_enum type_enum)
{
assert (type.type != pt_arg_type::INDEX);
return type_enum == PT_TYPE_NULL || pt_are_equivalent_types (type, type_enum);
}
bool
cmp_types_castable (const pt_arg_type &type, pt_type_enum type_enum) //is possible to cast type_enum -> type?
{
assert (type.type != pt_arg_type::INDEX);
if (type_enum == PT_TYPE_NULL)
{
return true; // PT_TYPE_NULL is castable to any type
}
if (type_enum == PT_TYPE_MAYBE)
{
return true; // consider this castable, and truth will be told after late binding
}
if (type.type == pt_arg_type::NORMAL)
{
switch (type.val.type)
{
case PT_TYPE_INTEGER:
return (PT_IS_NUMERIC_TYPE (type_enum) || PT_IS_STRING_TYPE (type_enum));
case PT_TYPE_BIGINT:
return (PT_IS_DISCRETE_NUMBER_TYPE (type_enum));
case PT_TYPE_VARCHAR:
return (PT_IS_SIMPLE_CHAR_STRING_TYPE (type_enum) || PT_IS_NUMERIC_TYPE (type_enum)
|| PT_IS_DATE_TIME_TYPE (type_enum) || PT_IS_BIT_STRING_TYPE (type_enum)
|| type_enum == PT_TYPE_ENUMERATION); //monetary should be here???
default:
return type.val.type == type_enum;
}
}
//type.type == pt_arg_type::GENERIC
switch (type.val.generic_type)
{
case PT_GENERIC_TYPE_NUMBER:
return (PT_IS_NUMERIC_TYPE (type_enum) || PT_IS_STRING_TYPE (type_enum) || type_enum == PT_TYPE_JSON);
case PT_GENERIC_TYPE_DISCRETE_NUMBER:
return (PT_IS_NUMERIC_TYPE (type_enum) || PT_IS_STRING_TYPE (type_enum));
case PT_GENERIC_TYPE_ANY:
case PT_GENERIC_TYPE_PRIMITIVE:
case PT_GENERIC_TYPE_STRING:
case PT_GENERIC_TYPE_STRING_VARYING:
case PT_GENERIC_TYPE_BIT:
// any non-set?
return !PT_IS_COLLECTION_TYPE (type_enum);
case PT_GENERIC_TYPE_CHAR:
return (PT_IS_NUMERIC_TYPE (type_enum) || PT_IS_SIMPLE_CHAR_STRING_TYPE (type_enum)
|| PT_IS_DATE_TIME_TYPE (type_enum) || type_enum == PT_TYPE_JSON);
case PT_GENERIC_TYPE_DATE:
case PT_GENERIC_TYPE_DATETIME:
return PT_IS_STRING_TYPE (type_enum) || PT_IS_DATE_TIME_TYPE (type_enum);
case PT_GENERIC_TYPE_SCALAR:
return !PT_IS_COLLECTION_TYPE (type_enum);
case PT_GENERIC_TYPE_JSON_VAL:
// it will be resolved at runtime
return PT_IS_NUMERIC_TYPE (type_enum); // numerics can be converted to a json value
case PT_GENERIC_TYPE_JSON_DOC:
return false; // only equivalent types
case PT_GENERIC_TYPE_SEQUENCE:
// todo -
return false;
case PT_GENERIC_TYPE_LOB:
// todo -
return false;
case PT_GENERIC_TYPE_QUERY:
// ??
assert (false);
return false;
default:
assert (false);
return false;
}
}
parser_node *
Node::get_arg (size_t index)
{
for (auto arg = m_node->info.function.arg_list; arg; arg = arg->next, --index)
{
if (index == 0)
{
return arg;
}
}
return NULL;
}
parser_node *
Node::apply_argument (parser_node *prev, parser_node *arg, const argument_resolve &arg_res)
{
parser_node *save_next = arg->next;
if (arg_res.m_type != arg->type_enum)
{
arg = pt_wrap_with_cast_op (m_parser, arg, arg_res.m_type, TP_FLOATING_PRECISION_VALUE, 0, NULL);
if (arg == NULL)
{
assert (false);
return NULL;
}
}
if (m_best_signature.m_common_collation.coll_id != -1 && arg_res.m_check_coll_infer)
{
if (m_best_signature.m_common_collation.coll_id != arg_res.m_coll_infer.coll_id)
{
PT_NODE *new_node = pt_coerce_node_collation (m_parser, arg, m_best_signature.m_common_collation.coll_id,
m_best_signature.m_common_collation.codeset,
arg_res.m_coll_infer.can_force_cs, false, arg_res.m_type,
PT_TYPE_NONE);
if (new_node != NULL)
{
arg = new_node;
}
else
{
// what if it is null?
}
}
}
// restore links
if (prev != NULL)
{
prev->next = arg;
}
else
{
m_node->info.function.arg_list = arg;
}
arg->next = save_next;
return arg;
}
PT_NODE *
Node::type_checking ()
{
if (m_node->info.function.is_type_checked)
{
// already checked
return m_node;
}
if (preprocess ())
{
auto func_sigs = get_signatures (m_node->info.function.function_type);
assert ("ERR no function signature" && func_sigs != NULL);
if (!func_sigs)
{
pt_cat_error (m_parser, m_node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_NO_SIGNATURES,
fcode_get_uppercase_name (m_node->info.function.function_type));
return m_node;
}
const func_signature *func_sig = get_signature (*func_sigs);
if (func_sig == NULL || !apply_signature (*func_sig))
{
m_node->type_enum = PT_TYPE_NA;
// reserve previous error
if (!pt_has_error (m_parser))
{
pt_cat_error (m_parser, m_node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_NO_VALID_FUNCTION_SIGNATURE,
fcode_get_uppercase_name (m_node->info.function.function_type));
}
}
else
{
set_return_type (*func_sig);
}
}
else
{
// do nothing??
}
m_node->info.function.is_type_checked = true;
return m_node;
}
bool
Node::preprocess ()
{
auto arg_list = m_node->info.function.arg_list;
switch (m_node->info.function.function_type)
{
case F_GENERIC:
case F_CLASS_OF: //move it to the beginning of pt_eval_function_type() ... not without complicating the code
m_node->type_enum = (arg_list) ? arg_list->type_enum : PT_TYPE_NONE;
return false; //no need to continue with generic code
default:
;
}
return true;
}
const char *
Node::get_types (const func_all_signatures &signatures, size_t index, string_buffer &sb)
{
for (auto &signature: signatures)
{
auto i = index;
if (index < signature.fix.size ())
{
pt_arg_type_to_string_buffer (signature.fix[i], sb);
sb (", ");
}
else
{
i -= signature.fix.size ();
if (signature.rep.size () > 0)
{
i %= signature.rep.size ();
pt_arg_type_to_string_buffer (signature.rep[i], sb);
sb (", ");
}
}
}
return sb.get_buffer ();
}
const func_signature *
Node::get_signature (const func_all_signatures &signatures)
{
if (pt_has_error (m_parser))
{
return nullptr;
}
pt_reset_error (m_parser);
size_t arg_count = static_cast<size_t> (pt_length_of_list (m_node->info.function.arg_list));
signature_compatibility sgn_compat;
int sigIndex = 0;
for (auto &sig: signatures)
{
++sigIndex;
parser_node *arg = m_node->info.function.arg_list;
size_t arg_idx = 0;
sgn_compat.m_args_resolve.resize (arg_count);
sgn_compat.m_compat = type_compatibility::EQUIVALENT;
sgn_compat.m_signature = &sig;
// collation action is initialized as leave. if string-signature arguments are all maybes, then it will remain
// leave, and is decided at runtime. if any argument is string, it will be set to TP_DOMAIN_COLL_NORMAL.
sgn_compat.m_collation_action = TP_DOMAIN_COLL_LEAVE;
bool coerce_args_utf8 = sig_has_json_args (sig);
//check fix part of the signature
for (auto &fix: sig.fix)
{
if (arg == NULL)
{
invalid_arg_count_error (arg_count, sig);
sgn_compat.m_compat = type_compatibility::INCOMPATIBLE;
break;
}
// todo - index type signature should copy argument type, not argument signature
auto t = ((fix.type == pt_arg_type::INDEX) ? sig.fix[fix.val.index] : fix);
if (!check_arg_compat (t, arg, sgn_compat, sgn_compat.m_args_resolve[arg_idx], coerce_args_utf8))
{
break;
}
++arg_idx;
arg = arg->next;
}
if (sgn_compat.m_compat == type_compatibility::INCOMPATIBLE)
{
continue;
}
if ((arg != NULL && sig.rep.size () == 0) || (arg == NULL && sig.rep.size () != 0))
{
// number of arguments don't match
invalid_arg_count_error (arg_count, sig);
continue;
}
//check repetitive args
int index = 0;
for (; arg; arg = arg->next, index = (index + 1) % sig.rep.size ())
{
auto &rep = sig.rep[index];
// todo - index type signature should copy argument type, not argument signature
auto t = ((rep.type == pt_arg_type::INDEX) ? sig.rep[rep.val.index] : rep);
if (!check_arg_compat (t, arg, sgn_compat, sgn_compat.m_args_resolve[arg_idx], coerce_args_utf8))
{
break;
}
++arg_idx;
}
if (index != 0 && sgn_compat.m_compat != type_compatibility::INCOMPATIBLE)
{
invalid_arg_count_error (arg_count, sig);
sgn_compat.m_compat = type_compatibility::INCOMPATIBLE;
continue;
}
if (sgn_compat.m_compat == type_compatibility::EQUIVALENT)
{
m_best_signature = std::move (sgn_compat);
break; //stop at 1st equivalent signature
}
if (sgn_compat.m_compat == type_compatibility::COERCIBLE && m_best_signature.m_signature == NULL)
{
//don't stop, continue because it is possible to find an equivalent signature later
m_best_signature = sgn_compat;
}
}
if (m_best_signature.m_signature != NULL)
{
// signature found => clear error messages accumulated during signature checking
pt_reset_error (m_parser);
}
return m_best_signature.m_signature;
}
void
Node::set_return_type (const func_signature &signature)
{
parser_node *arg_list = m_node->info.function.arg_list;
if (m_node->type_enum == PT_TYPE_NONE || m_node->data_type == NULL) //return type
{
// todo - make this really generic
//set node->type_enum
switch (signature.ret.type)
{
case pt_arg_type::NORMAL:
m_node->type_enum = signature.ret.val.type;
break;
case pt_arg_type::GENERIC:
assert (false);
break;
case pt_arg_type::INDEX:
{
parser_node *arg_node = get_arg (signature.ret.val.index);
if (arg_node != NULL)
{
m_node->type_enum = arg_node->type_enum;
if (m_node->type_enum == PT_TYPE_MAYBE && arg_node->expected_domain != NULL)
{
m_node->type_enum = pt_db_to_type_enum (arg_node->expected_domain->type->id);
}
if (arg_node->data_type != NULL)
{
m_node->data_type = parser_copy_tree_list (m_parser, arg_node->data_type);
}
}
else
{
// ??
assert (false);
}
break;
}
}
// set node->data_type
// todo - remove this switch
switch (m_node->info.function.function_type)
{
case PT_MAX:
case PT_MIN:
case PT_LEAD:
case PT_LAG:
case PT_FIRST_VALUE:
case PT_LAST_VALUE:
case PT_NTH_VALUE:
m_node->data_type = (arg_list ? parser_copy_tree_list (m_parser, arg_list->data_type) : NULL);
break;
case PT_SUM:
m_node->data_type = (arg_list ? parser_copy_tree_list (m_parser, arg_list->data_type) : NULL);
if (arg_list && arg_list->type_enum == PT_TYPE_NUMERIC && m_node->data_type)
{
m_node->data_type->info.data_type.precision = DB_MAX_NUMERIC_PRECISION;
}
break;
case F_ELT:
m_node->data_type = pt_make_prim_data_type (m_parser, m_node->type_enum);
if (m_node->data_type)
{
m_node->data_type->info.data_type.precision = DB_MAX_VARCHAR_PRECISION;
m_node->data_type->info.data_type.dec_precision = 0;
}
break;
case PT_GROUP_CONCAT:
case F_INSERT_SUBSTRING:
m_node->data_type = pt_make_prim_data_type (m_parser, m_node->type_enum);
if (m_node->data_type)
{
m_node->data_type->info.data_type.precision = TP_FLOATING_PRECISION_VALUE;
}
break;
case F_SET:
case F_MULTISET:
case F_SEQUENCE:
pt_add_type_to_set (m_parser, arg_list, &m_node->data_type);
break;
case F_TABLE_SET:
case F_TABLE_MULTISET:
case F_TABLE_SEQUENCE:
pt_add_type_to_set (m_parser, pt_get_select_list (m_parser, arg_list), &m_node->data_type);
break;
default:
// m_node->data_type = NULL;
break;
}
if (m_node->data_type == NULL)
{
m_node->data_type = pt_make_prim_data_type (m_parser, m_node->type_enum);
}
if (m_node->data_type != NULL && PT_IS_STRING_TYPE (m_node->type_enum))
{
// always return string without precision
m_node->type_enum = pt_to_variable_size_type (m_node->type_enum);
m_node->data_type->info.data_type.precision = TP_FLOATING_PRECISION_VALUE;
m_node->data_type->type_enum = pt_to_variable_size_type (m_node->type_enum);
assert (m_node->type_enum == m_node->data_type->type_enum);
}
}
else
{
// when is this already set??
}
// set collation on result node... I am not sure this is correct
if (PT_HAS_COLLATION (m_node->type_enum) && m_best_signature.m_common_collation.coll_id != -1)
{
pt_coll_infer result_coll_infer;
if (is_type_with_collation (m_node->type_enum) && m_best_signature.m_collation_action == TP_DOMAIN_COLL_LEAVE
&& m_node->data_type != NULL)
{
// all maybes case. leave collation coming from arguments
m_node->data_type->info.data_type.collation_flag = TP_DOMAIN_COLL_LEAVE;
}
else if (pt_get_collation_info (m_node, &result_coll_infer)
&& m_best_signature.m_common_collation.coll_id != result_coll_infer.coll_id)
{
parser_node *new_node = pt_coerce_node_collation (m_parser, m_node,
m_best_signature.m_common_collation.coll_id,
m_best_signature.m_common_collation.codeset,
true, false, PT_TYPE_VARCHAR, PT_TYPE_NONE);
if (new_node != NULL)
{
m_node = new_node;
}
}
}
}
bool
Node::apply_signature (const func_signature &signature)
{
FUNC_CODE func_type = m_node->info.function.function_type;
parser_node *arg = m_node->info.function.arg_list;
parser_node *prev = NULL;
size_t arg_pos = 0;
// check fixed part of the function signature
for (auto type: signature.fix)
{
if (arg == NULL)
{
assert (false);
return false;
}
arg = apply_argument (prev, arg, m_best_signature.m_args_resolve[arg_pos]);
if (arg == NULL)
{
assert (false);
return false;
}
++arg_pos;
prev = arg;
arg = arg->next;
}
if (arg != NULL && signature.rep.size () == 0)
{
assert (false);
return false;
}
//check repetitive part of the function signature
int index = 0;
for (; arg != NULL; prev = arg, arg = arg->next, index = (index + 1) % signature.rep.size (), ++arg_pos)
{
arg = apply_argument (prev, arg, m_best_signature.m_args_resolve[arg_pos]);
if (arg == NULL)
{
assert (false);
return false;
}
}
if (index != 0)
{
assert (false);
return false;
}
return true;
}
bool
Node::check_arg_compat (const pt_arg_type &arg_signature, const PT_NODE *arg_node,
signature_compatibility &compat, argument_resolve &arg_res, bool string_args_to_utf8)
{
arg_res.m_type = PT_TYPE_NONE;
if (arg_node == nullptr)
{
compat.m_compat = type_compatibility::INCOMPATIBLE;
return false;
}
PT_TYPE_ENUM arg_type = arg_node->type_enum;
if (PT_IS_PARAMETER (arg_node) && arg_type == PT_TYPE_NONE)
{
DB_VALUE *db_value = pt_find_value_of_label (arg_node->info.name.original);
if (db_value == NULL)
{
// check invalid paramter, unresolved
compat.m_compat = type_compatibility::INCOMPATIBLE;
invalid_arg_param_error (arg_node);
return false;
}
else
{
arg_type = pt_db_to_type_enum (db_value_type (db_value));
}
}
// todo - equivalent type & coercible type checks should all be in a the same place to have a better view of how
// each type can convert to another
if (cmp_types_equivalent (arg_signature, arg_type))
{
arg_res.m_type = pt_get_equivalent_type (arg_signature, arg_type);
}
else if (cmp_types_castable (arg_signature, arg_type))
{
compat.m_compat = type_compatibility::COERCIBLE;
arg_res.m_type = pt_get_equivalent_type (arg_signature, arg_type);
}
else
{
compat.m_compat = type_compatibility::INCOMPATIBLE;
invalid_arg_error (arg_signature, arg_node, *compat.m_signature);
return false;
}
// if compatible, pt_get_equivalent_type should return a valid type. but we need to double-check
if (arg_res.m_type == PT_TYPE_NONE)
{
assert (false);
compat.m_compat = type_compatibility::INCOMPATIBLE;
invalid_arg_error (arg_signature, arg_node, *compat.m_signature);
return false;
}
// three conditions should be met to require collation inference:
//
// 1. argument signature should allow collation. e.g. all generic strings allow collations, but json docs and values
// don't allow
//
// 2. equivalent type should have collation.
//
// 3. original argument type should have collation. if it doesn't have, it doesn't affect common collation.
// NOTE - if first two conditions are true and this is false, we don't do collation inference, but argument will
// be coerced to common collation.
//
// todo - what happens when all arguments are maybe??
//
// NOTE:
// Most of the time, first and second conditions are similar. There are cases when first condition is false and
// second is true. I don't know at this moment if second argument can be false while first is true. To be on the
// safe side, we check them both.
//
if (!can_signature_have_collation (arg_signature) || !is_type_with_collation (arg_res.m_type))
{
// collation does not matter for this argument
arg_res.m_coll_infer.coll_id = -1;
arg_res.m_check_coll_infer = false;
}
else
{
// collation matters for this argument
if (string_args_to_utf8)
{
compat.m_common_collation.coll_id = LANG_COLL_UTF8_BINARY;
compat.m_common_collation.codeset = INTL_CODESET_UTF8;
compat.m_common_collation.can_force_cs = true;
compat.m_common_collation.coerc_level = PT_COLLATION_FULLY_COERC;
return true;
}
arg_res.m_coll_infer.coll_id = -1;
arg_res.m_check_coll_infer = true;
if (is_type_with_collation (arg_node->type_enum) && pt_get_collation_info (arg_node, &arg_res.m_coll_infer))
{
// do collation inference
int common_coll;
INTL_CODESET common_cs;
if (compat.m_common_collation.coll_id == -1)
{
compat.m_common_collation.coll_id = arg_res.m_coll_infer.coll_id;
compat.m_common_collation.codeset = arg_res.m_coll_infer.codeset;
compat.m_common_collation.can_force_cs = arg_res.m_coll_infer.can_force_cs;
compat.m_common_collation.coerc_level = arg_res.m_coll_infer.coerc_level;
}
else if (pt_common_collation (&compat.m_common_collation, &arg_res.m_coll_infer, NULL, 2, false,
&common_coll, &common_cs) == NO_ERROR)
{
compat.m_common_collation.coll_id = common_coll;
compat.m_common_collation.codeset = common_cs;
}
else
{
// todo: we'll need a clear error here
compat.m_compat = type_compatibility::INCOMPATIBLE;
invalid_coll_error (*compat.m_signature);
return false;
}
if (arg_node->type_enum != PT_TYPE_MAYBE)
{
compat.m_collation_action = TP_DOMAIN_COLL_NORMAL;
}
}
else
{
// third condition is not met; this argument does not contribute to common collation.
}
}
return true;
}
void
Node::invalid_arg_error (const pt_arg_type &arg_sgn, const PT_NODE *arg_node, const func_signature &func_sgn)
{
string_buffer expected_sb;
string_buffer sgn_sb;
pt_arg_type_to_string_buffer (arg_sgn, expected_sb);
func_sgn.to_string_buffer (sgn_sb);
pt_cat_error (m_parser, arg_node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_INCOMPATIBLE_ARGUMENT_TYPE,
pt_show_type_enum (arg_node->type_enum), expected_sb.get_buffer ());
pt_cat_error (m_parser, m_node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_INCOMPATIBLE_SIGNATURE,
sgn_sb.get_buffer ());
}
void
Node::invalid_arg_param_error (const PT_NODE *arg_node)
{
pt_cat_error (m_parser, arg_node, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_PARM_IS_NOT_SET,
arg_node->info.name.original);
}
void
Node::invalid_coll_error (const func_signature &func_sgn)
{
string_buffer sgn_sb;
func_sgn.to_string_buffer (sgn_sb);
pt_cat_error (m_parser, m_node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_COLLATION_OP_ERROR,
fcode_get_lowercase_name (m_node->info.function.function_type));
pt_cat_error (m_parser, m_node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_INCOMPATIBLE_SIGNATURE,
sgn_sb.get_buffer ());
}
void
Node::invalid_arg_count_error (std::size_t arg_count, const func_signature &func_sgn)
{
string_buffer sgn_sb;
func_sgn.to_string_buffer (sgn_sb);
pt_cat_error (m_parser, m_node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_WRONG_ARGS_COUNT,
(int) arg_count);
pt_cat_error (m_parser, m_node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_INCOMPATIBLE_SIGNATURE,
sgn_sb.get_buffer ());
}
} // namespace func_type
/*
* pt_are_equivalent_types () - check if a node type is equivalent with a
* definition type
* return : true if the types are equivalent, false otherwise
* def_type(in) : the definition type
* op_type(in) : argument type
*/
bool
pt_are_equivalent_types (const PT_ARG_TYPE def_type, const PT_TYPE_ENUM op_type)
{
if (def_type.type == pt_arg_type::NORMAL)
{
if (def_type.val.type == op_type && op_type == PT_TYPE_NONE)
{
/* return false if both arguments are of type none */
return false;
}
if (def_type.val.type == op_type)
{
/* return true if both have the same type */
return true;
}
/* if def_type is a PT_TYPE_ENUM and the conditions above did not hold then the two types are not equivalent. */
return false;
}
switch (def_type.val.generic_type)
{
case PT_GENERIC_TYPE_ANY:
/* PT_GENERIC_TYPE_ANY is equivalent to any type */
return true;
case PT_GENERIC_TYPE_PRIMITIVE:
if (PT_IS_PRIMITIVE_TYPE (op_type))
{
return true;
}
break;
case PT_GENERIC_TYPE_DISCRETE_NUMBER:
if (PT_IS_DISCRETE_NUMBER_TYPE (op_type) || op_type == PT_TYPE_ENUMERATION)
{
/* PT_GENERIC_TYPE_DISCRETE_NUMBER is equivalent with SHORT, INTEGER and BIGINT */
return true;
}
break;
case PT_GENERIC_TYPE_NUMBER:
if (PT_IS_NUMERIC_TYPE (op_type) || op_type == PT_TYPE_ENUMERATION)
{
/* any NUMBER type is equivalent with PT_GENERIC_TYPE_NUMBER */
return true;
}
break;
case PT_GENERIC_TYPE_STRING:
if (PT_IS_CHAR_STRING_TYPE (op_type) || op_type == PT_TYPE_ENUMERATION)
{
/* any STRING type is equivalent with PT_GENERIC_TYPE_STRING */
return true;
}
break;
case PT_GENERIC_TYPE_CHAR:
if (op_type == PT_TYPE_CHAR || op_type == PT_TYPE_VARCHAR || op_type == PT_TYPE_ENUMERATION)
{
/* CHAR and VARCHAR are equivalent to PT_GENERIC_TYPE_CHAR */
return true;
}
break;
case PT_GENERIC_TYPE_BIT:
if (PT_IS_BIT_STRING_TYPE (op_type))
{
/* BIT and BIT VARYING are equivalent to PT_GENERIC_TYPE_BIT */
return true;
}
break;
case PT_GENERIC_TYPE_DATETIME:
if (PT_IS_DATE_TIME_TYPE (op_type))
{
return true;
}
break;
case PT_GENERIC_TYPE_DATE:
if (PT_HAS_DATE_PART (op_type))
{
return true;
}
break;
case PT_GENERIC_TYPE_SEQUENCE:
if (PT_IS_COLLECTION_TYPE (op_type))
{
/* any COLLECTION is equivalent with PT_GENERIC_TYPE_SEQUENCE */
return true;
}
break;
case PT_GENERIC_TYPE_JSON_VAL:
return pt_is_json_value_type (op_type);
case PT_GENERIC_TYPE_JSON_DOC:
return pt_is_json_doc_type (op_type);
case PT_GENERIC_TYPE_SCALAR:
return ((op_type == PT_TYPE_ENUMERATION) || PT_IS_NUMERIC_TYPE (op_type) || PT_IS_STRING_TYPE (op_type)
|| PT_IS_DATE_TIME_TYPE (op_type));
default:
return false;
}
return false;
}
// TODO: remove me
#define PT_COLL_WRAP_TYPE_FOR_MAYBE(type) \
((PT_IS_CHAR_STRING_TYPE (type)) ? (type) : PT_TYPE_VARCHAR)
#define PT_IS_CAST_MAYBE(node) \
((node)->node_type == PT_EXPR && (node)->info.expr.op == PT_CAST \
&& (node)->info.expr.arg1 != NULL && (node)->info.expr.arg1->type_enum == PT_TYPE_MAYBE)
static PT_NODE *pt_check_function_collation (PARSER_CONTEXT *parser, PT_NODE *node);
static int pt_character_length_for_node (PT_NODE *node, const PT_TYPE_ENUM coerce_type);
/*
* pt_eval_function_type_aggregate () -
* return: returns a node of the same type.
* parser(in): parser global context info for reentrancy
* node(in): a parse tree node of type PT_FUNCTION denoting an
* an expression with aggregate functions.
*
* TODO - remove me when all functions are migrated to new evaluation
* GIVEUP - just moved from type_check.c to type_eval_func.cpp
*/
PT_NODE *
pt_eval_function_type_aggregate (PARSER_CONTEXT *parser, PT_NODE *node)
{
PT_NODE *arg_list;
PT_TYPE_ENUM arg_type;
FUNC_CODE fcode;
bool check_agg_single_arg = false;
bool is_agg_function = false;
PT_NODE *prev = NULL;
PT_NODE *arg = NULL;
is_agg_function = pt_is_aggregate_function (parser, node);
arg_list = node->info.function.arg_list;
fcode = node->info.function.function_type;
/*
* Should only get one arg to function; set to 0 if the function
* accepts more than one.
*/
check_agg_single_arg = true;
arg_type = (arg_list) ? arg_list->type_enum : PT_TYPE_NONE;
switch (fcode)
{
case PT_STDDEV:
case PT_STDDEV_POP:
case PT_STDDEV_SAMP:
case PT_VARIANCE:
case PT_VAR_POP:
case PT_VAR_SAMP:
case PT_AVG:
if (arg_type != PT_TYPE_MAYBE && arg_type != PT_TYPE_NULL && arg_type != PT_TYPE_NA)
{
if (!PT_IS_NUMERIC_TYPE (arg_type))
{
arg_list = pt_wrap_with_cast_op (parser, arg_list, PT_TYPE_DOUBLE, TP_FLOATING_PRECISION_VALUE, 0, NULL);
if (arg_list == NULL)
{
return node;
}
}
node->info.function.arg_list = arg_list;
}
arg_type = PT_TYPE_DOUBLE;
break;
case PT_AGG_BIT_AND:
case PT_AGG_BIT_OR:
case PT_AGG_BIT_XOR:
if (!PT_IS_DISCRETE_NUMBER_TYPE (arg_type) && arg_type != PT_TYPE_MAYBE && arg_type != PT_TYPE_NULL
&& arg_type != PT_TYPE_NA)
{
/* cast arg_list to bigint */
arg_list = pt_wrap_with_cast_op (parser, arg_list, PT_TYPE_BIGINT, 0, 0, NULL);
if (arg_list == NULL)
{
return node;
}
arg_type = PT_TYPE_BIGINT;
node->info.function.arg_list = arg_list;
}
break;
case PT_SUM:
if (!PT_IS_NUMERIC_TYPE (arg_type) && arg_type != PT_TYPE_MAYBE && arg_type != PT_TYPE_NULL
&& arg_type != PT_TYPE_NA && !pt_is_set_type (arg_list))
{
/* To display the sum as integer and not scientific */
PT_TYPE_ENUM cast_type = (arg_type == PT_TYPE_ENUMERATION ? PT_TYPE_INTEGER : PT_TYPE_DOUBLE);
/* cast arg_list to double or integer */
arg_list = pt_wrap_with_cast_op (parser, arg_list, cast_type, 0, 0, NULL);
if (arg_list == NULL)
{
return node;
}
arg_type = cast_type;
node->info.function.arg_list = arg_list;
}
break;
case PT_MAX:
case PT_MIN:
case PT_FIRST_VALUE:
case PT_LAST_VALUE:
case PT_NTH_VALUE:
if (!PT_IS_NUMERIC_TYPE (arg_type) && !PT_IS_STRING_TYPE (arg_type) && !PT_IS_DATE_TIME_TYPE (arg_type)
&& arg_type != PT_TYPE_ENUMERATION && arg_type != PT_TYPE_MAYBE && arg_type != PT_TYPE_NULL
&& arg_type != PT_TYPE_NA)
{
PT_ERRORmf2 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_INCOMPATIBLE_OPDS,
fcode_get_lowercase_name (fcode), pt_show_type_enum (arg_type));
}
break;
case PT_LEAD:
case PT_LAG:
break;
case PT_COUNT:
assert (false);
break;
case PT_GROUP_CONCAT:
{
PT_TYPE_ENUM sep_type;
sep_type = (arg_list->next) ? arg_list->next->type_enum : PT_TYPE_NONE;
check_agg_single_arg = false;
if (!PT_IS_NUMERIC_TYPE (arg_type) && !PT_IS_STRING_TYPE (arg_type) && !PT_IS_DATE_TIME_TYPE (arg_type)
&& arg_type != PT_TYPE_ENUMERATION && arg_type != PT_TYPE_MAYBE && arg_type != PT_TYPE_NULL
&& arg_type != PT_TYPE_NA)
{
PT_ERRORmf2 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_INCOMPATIBLE_OPDS,
fcode_get_lowercase_name (fcode), pt_show_type_enum (arg_type));
break;
}
if (!PT_IS_STRING_TYPE (sep_type) && sep_type != PT_TYPE_NONE)
{
PT_ERRORmf2 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_INCOMPATIBLE_OPDS,
fcode_get_lowercase_name (fcode), pt_show_type_enum (sep_type));
break;
}
if ((arg_type == PT_TYPE_BIT || arg_type == PT_TYPE_VARBIT) && sep_type != PT_TYPE_BIT
&& sep_type != PT_TYPE_VARBIT && sep_type != PT_TYPE_NONE)
{
PT_ERRORmf3 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_OP_NOT_DEFINED_ON,
fcode_get_lowercase_name (fcode), pt_show_type_enum (arg_type), pt_show_type_enum (sep_type));
break;
}
if ((arg_type != PT_TYPE_BIT && arg_type != PT_TYPE_VARBIT)
&& (sep_type == PT_TYPE_BIT || sep_type == PT_TYPE_VARBIT))
{
PT_ERRORmf3 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_OP_NOT_DEFINED_ON,
fcode_get_lowercase_name (fcode), pt_show_type_enum (arg_type), pt_show_type_enum (sep_type));
break;
}
}
break;
case PT_CUME_DIST:
case PT_PERCENT_RANK:
check_agg_single_arg = false;
break;
case PT_NTILE:
if (!PT_IS_DISCRETE_NUMBER_TYPE (arg_type) && arg_type != PT_TYPE_MAYBE && arg_type != PT_TYPE_NULL
&& arg_type != PT_TYPE_NA)
{
/* cast arg_list to double */
arg_list = pt_wrap_with_cast_op (parser, arg_list, PT_TYPE_DOUBLE, 0, 0, NULL);
if (arg_list == NULL)
{
return node;
}
arg_type = PT_TYPE_INTEGER;
node->info.function.arg_list = arg_list;
}
break;
case F_ELT:
{
/* all types used in the arguments list */
bool has_arg_type[PT_TYPE_MAX - PT_TYPE_MIN];
/* a subset of argument types given to ELT that can not be cast to [N]CHAR VARYING */
PT_TYPE_ENUM bad_types[4] =
{
PT_TYPE_NONE, PT_TYPE_NONE, PT_TYPE_NONE, PT_TYPE_NONE
};
PT_NODE *arg = arg_list;
size_t num_bad = 0; /* used to index bad_types */
memset (has_arg_type, 0, sizeof (has_arg_type));
/* check the index argument (null, numeric or host var) */
if (PT_IS_NUMERIC_TYPE (arg->type_enum) || PT_IS_CHAR_STRING_TYPE (arg->type_enum)
|| arg->type_enum == PT_TYPE_NONE || arg->type_enum == PT_TYPE_NA || arg->type_enum == PT_TYPE_NULL
|| arg->type_enum == PT_TYPE_MAYBE)
{
arg = arg->next;
}
else
{
arg_type = PT_TYPE_NONE;
PT_ERRORmf2 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_FUNC_NOT_DEFINED_ON_INDEX,
fcode_get_lowercase_name (fcode), pt_show_type_enum (arg->type_enum));
break;
}
/* make a list of all other argument types (null, [N]CHAR [VARYING], or host var) */
while (arg)
{
if (arg->type_enum < PT_TYPE_MAX)
{
has_arg_type[arg->type_enum - PT_TYPE_MIN] = true;
arg = arg->next;
}
else
{
assert (false); /* invalid data type */
arg_type = PT_TYPE_NONE;
PT_ERRORmf2 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_FUNC_NOT_DEFINED_ON,
fcode_get_lowercase_name (fcode), pt_show_type_enum (arg->type_enum));
break;
}
}
/* look for unsupported argument types in the list */
for (int i = 0; i < DIM (has_arg_type); i++)
{
if (has_arg_type[i] == false)
{
continue;
}
switch (PT_TYPE_MIN + i)
{
/* NUMERIC TYPE */
case PT_TYPE_INTEGER:
case PT_TYPE_BIGINT:
case PT_TYPE_FLOAT:
case PT_TYPE_DOUBLE:
case PT_TYPE_SMALLINT:
case PT_TYPE_MONETARY:
case PT_TYPE_LOGICAL:
case PT_TYPE_NUMERIC:
/* CHAR STRING TYPE */
case PT_TYPE_CHAR:
case PT_TYPE_VARCHAR:
/* DATE TIME TYPE */
case PT_TYPE_DATE:
case PT_TYPE_TIME:
case PT_TYPE_TIMESTAMP:
case PT_TYPE_DATETIME:
case PT_TYPE_DATETIMETZ:
case PT_TYPE_DATETIMELTZ:
case PT_TYPE_TIMESTAMPTZ:
case PT_TYPE_TIMESTAMPLTZ:
/* Others */
case PT_TYPE_ENUMERATION:
case PT_TYPE_NONE:
case PT_TYPE_NA:
case PT_TYPE_NULL:
case PT_TYPE_MAYBE:
break;
default:
{
/* type is not NULL, unknown and is not known coercible to [N]CHAR VARYING */
size_t k = 0;
while (k < num_bad && bad_types[k] != PT_TYPE_MIN + i)
{
k++;
}
if (k == num_bad)
{
bad_types[num_bad++] = (PT_TYPE_ENUM) (PT_TYPE_MIN + i);
if (num_bad == DIM (bad_types))
{
break;
}
}
}
} // switch()
}
/* report any unsupported arguments */
switch (num_bad)
{
case 1:
arg_type = PT_TYPE_NONE;
PT_ERRORmf2 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_FUNC_NOT_DEFINED_ON,
fcode_get_lowercase_name (fcode), pt_show_type_enum (bad_types[0]));
break;
case 2:
arg_type = PT_TYPE_NONE;
PT_ERRORmf3 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_FUNC_NOT_DEFINED_ON_2,
fcode_get_lowercase_name (fcode), pt_show_type_enum (bad_types[0]),
pt_show_type_enum (bad_types[1]));
break;
case 3:
arg_type = PT_TYPE_NONE;
PT_ERRORmf4 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_FUNC_NOT_DEFINED_ON_3,
fcode_get_lowercase_name (fcode), pt_show_type_enum (bad_types[0]),
pt_show_type_enum (bad_types[1]), pt_show_type_enum (bad_types[2]));
break;
case 4:
arg_type = PT_TYPE_NONE;
PT_ERRORmf5 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_FUNC_NOT_DEFINED_ON_4,
fcode_get_lowercase_name (fcode), pt_show_type_enum (bad_types[0]),
pt_show_type_enum (bad_types[1]), pt_show_type_enum (bad_types[2]),
pt_show_type_enum (bad_types[3]));
break;
}
}
break;
case F_INSERT_SUBSTRING:
{
PT_TYPE_ENUM arg1_type = PT_TYPE_NONE, arg2_type = PT_TYPE_NONE, arg3_type = PT_TYPE_NONE, arg4_type =
PT_TYPE_NONE;
PT_NODE *arg_array[NUM_F_INSERT_SUBSTRING_ARGS];
int num_args = 0;
/* arg_list to array */
if (pt_node_list_to_array (parser, arg_list, arg_array, NUM_F_INSERT_SUBSTRING_ARGS, &num_args) != NO_ERROR)
{
break;
}
if (num_args != NUM_F_INSERT_SUBSTRING_ARGS)
{
assert (false);
break;
}
arg1_type = arg_array[0]->type_enum;
arg2_type = arg_array[1]->type_enum;
arg3_type = arg_array[2]->type_enum;
arg4_type = arg_array[3]->type_enum;
/* check arg2 and arg3 */
if (!PT_IS_NUMERIC_TYPE (arg2_type) && !PT_IS_CHAR_STRING_TYPE (arg2_type) && arg2_type != PT_TYPE_MAYBE
&& arg2_type != PT_TYPE_NULL && arg2_type != PT_TYPE_NA)
{
arg_type = PT_TYPE_NONE;
PT_ERRORmf5 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_FUNC_NOT_DEFINED_ON_4,
fcode_get_lowercase_name (fcode), pt_show_type_enum (arg1_type), pt_show_type_enum (arg2_type),
pt_show_type_enum (arg3_type), pt_show_type_enum (arg4_type));
break;
}
if (!PT_IS_NUMERIC_TYPE (arg3_type) && !PT_IS_CHAR_STRING_TYPE (arg3_type) && arg3_type != PT_TYPE_MAYBE
&& arg3_type != PT_TYPE_NULL && arg3_type != PT_TYPE_NA)
{
arg_type = PT_TYPE_NONE;
PT_ERRORmf5 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_FUNC_NOT_DEFINED_ON_4,
fcode_get_lowercase_name (fcode), pt_show_type_enum (arg1_type), pt_show_type_enum (arg2_type),
pt_show_type_enum (arg3_type), pt_show_type_enum (arg4_type));
break;
}
/* check arg1 */
if (!PT_IS_NUMERIC_TYPE (arg1_type) && !PT_IS_STRING_TYPE (arg1_type) && !PT_IS_DATE_TIME_TYPE (arg1_type)
&& arg1_type != PT_TYPE_ENUMERATION && arg1_type != PT_TYPE_MAYBE && arg1_type != PT_TYPE_NULL
&& arg1_type != PT_TYPE_NA)
{
arg_type = PT_TYPE_NONE;
PT_ERRORmf5 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_FUNC_NOT_DEFINED_ON_4,
fcode_get_lowercase_name (fcode), pt_show_type_enum (arg1_type), pt_show_type_enum (arg2_type),
pt_show_type_enum (arg3_type), pt_show_type_enum (arg4_type));
break;
}
/* check arg4 */
if (!PT_IS_NUMERIC_TYPE (arg4_type) && !PT_IS_STRING_TYPE (arg4_type) && !PT_IS_DATE_TIME_TYPE (arg4_type)
&& arg4_type != PT_TYPE_MAYBE && arg4_type != PT_TYPE_NULL && arg4_type != PT_TYPE_NA)
{
arg_type = PT_TYPE_NONE;
PT_ERRORmf5 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_FUNC_NOT_DEFINED_ON_4,
fcode_get_lowercase_name (fcode), pt_show_type_enum (arg1_type), pt_show_type_enum (arg2_type),
pt_show_type_enum (arg3_type), pt_show_type_enum (arg4_type));
break;
}
}
break;
case PT_MEDIAN:
case PT_PERCENTILE_CONT:
case PT_PERCENTILE_DISC:
if (arg_type != PT_TYPE_NULL && arg_type != PT_TYPE_NA && !PT_IS_NUMERIC_TYPE (arg_type)
&& !PT_IS_STRING_TYPE (arg_type) && !PT_IS_DATE_TIME_TYPE (arg_type) && arg_type != PT_TYPE_MAYBE)
{
PT_ERRORmf2 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_INCOMPATIBLE_OPDS,
fcode_get_lowercase_name (fcode), pt_show_type_enum (arg_type));
}
break;
default:
check_agg_single_arg = false;
break;
}
if (is_agg_function && check_agg_single_arg)
{
if (arg_list->next)
{
PT_ERRORmf (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_AGG_FUN_WANT_1_ARG,
pt_short_print (parser, node));
}
}
if (node->type_enum == PT_TYPE_NONE || node->data_type == NULL || ! (node->info.function.is_type_checked))
{
/* determine function result type */
switch (fcode)
{
case PT_COUNT:
case PT_COUNT_STAR:
assert (false);
break;
case PT_ROW_NUMBER:
case PT_RANK:
case PT_DENSE_RANK:
case PT_NTILE:
node->type_enum = PT_TYPE_INTEGER;
break;
case PT_CUME_DIST:
case PT_PERCENT_RANK:
node->type_enum = PT_TYPE_DOUBLE;
break;
case PT_GROUPBY_NUM:
node->type_enum = PT_TYPE_BIGINT;
break;
case PT_AGG_BIT_AND:
case PT_AGG_BIT_OR:
case PT_AGG_BIT_XOR:
node->type_enum = PT_TYPE_BIGINT;
break;
case F_TABLE_SET:
node->type_enum = PT_TYPE_SET;
pt_add_type_to_set (parser, pt_get_select_list (parser, arg_list), &node->data_type);
break;
case F_TABLE_MULTISET:
node->type_enum = PT_TYPE_MULTISET;
pt_add_type_to_set (parser, pt_get_select_list (parser, arg_list), &node->data_type);
break;
case F_TABLE_SEQUENCE:
node->type_enum = PT_TYPE_SEQUENCE;
pt_add_type_to_set (parser, pt_get_select_list (parser, arg_list), &node->data_type);
break;
case F_SET:
node->type_enum = PT_TYPE_SET;
pt_add_type_to_set (parser, arg_list, &node->data_type);
break;
case F_MULTISET:
node->type_enum = PT_TYPE_MULTISET;
pt_add_type_to_set (parser, arg_list, &node->data_type);
break;
case F_SEQUENCE:
node->type_enum = PT_TYPE_SEQUENCE;
pt_add_type_to_set (parser, arg_list, &node->data_type);
break;
case PT_SUM:
node->type_enum = arg_type;
node->data_type = parser_copy_tree_list (parser, arg_list->data_type);
if (arg_type == PT_TYPE_NUMERIC && node->data_type)
{
node->data_type->info.data_type.precision = DB_MAX_NUMERIC_PRECISION;
}
break;
case PT_AVG:
case PT_STDDEV:
case PT_STDDEV_POP:
case PT_STDDEV_SAMP:
case PT_VARIANCE:
case PT_VAR_POP:
case PT_VAR_SAMP:
node->type_enum = arg_type;
node->data_type = NULL;
break;
case PT_MEDIAN:
case PT_PERCENTILE_CONT:
case PT_PERCENTILE_DISC:
/* let calculation decide the type */
node->type_enum = PT_TYPE_MAYBE;
node->data_type = NULL;
break;
case PT_GROUP_CONCAT:
{
if (arg_type == PT_TYPE_BIT || arg_type == PT_TYPE_VARBIT)
{
node->type_enum = PT_TYPE_VARBIT;
node->data_type = pt_make_prim_data_type (parser, PT_TYPE_VARBIT);
if (node->data_type == NULL)
{
node->type_enum = PT_TYPE_NONE;
assert (false);
}
node->data_type->info.data_type.precision = TP_FLOATING_PRECISION_VALUE;
}
else
{
node->type_enum = PT_TYPE_VARCHAR;
node->data_type = pt_make_prim_data_type (parser, PT_TYPE_VARCHAR);
if (node->data_type == NULL)
{
node->type_enum = PT_TYPE_NONE;
assert (false);
}
node->data_type->info.data_type.precision = TP_FLOATING_PRECISION_VALUE;
}
}
break;
case F_INSERT_SUBSTRING:
{
PT_NODE *new_att = NULL;
PT_TYPE_ENUM arg1_type = PT_TYPE_NONE, arg2_type = PT_TYPE_NONE, arg3_type = PT_TYPE_NONE, arg4_type =
PT_TYPE_NONE;
PT_TYPE_ENUM arg1_orig_type, arg2_orig_type, arg3_orig_type, arg4_orig_type;
PT_NODE *arg_array[NUM_F_INSERT_SUBSTRING_ARGS];
int num_args;
/* arg_list to array */
if (pt_node_list_to_array (parser, arg_list, arg_array, NUM_F_INSERT_SUBSTRING_ARGS, &num_args) != NO_ERROR)
{
break;
}
if (num_args != NUM_F_INSERT_SUBSTRING_ARGS)
{
assert (false);
break;
}
arg1_orig_type = arg1_type = arg_array[0]->type_enum;
arg2_orig_type = arg2_type = arg_array[1]->type_enum;
arg3_orig_type = arg3_type = arg_array[2]->type_enum;
arg4_orig_type = arg4_type = arg_array[3]->type_enum;
arg_type = PT_TYPE_NONE;
/* validate and/or convert arguments */
/* arg1 should be VAR-str, but compatible with arg4 (except when arg4 is BIT - no casting to bit on arg1) */
if (! (PT_IS_STRING_TYPE (arg1_type)))
{
new_att =
pt_wrap_with_cast_op (parser, arg_array[0], PT_TYPE_VARCHAR, TP_FLOATING_PRECISION_VALUE, 0, NULL);
if (new_att == NULL)
{
break;
}
node->info.function.arg_list = arg_array[0] = new_att;
arg_type = arg1_type = PT_TYPE_VARCHAR;
}
else
{
arg_type = arg1_type;
}
if (arg2_type != PT_TYPE_INTEGER)
{
new_att =
pt_wrap_with_cast_op (parser, arg_array[1], PT_TYPE_INTEGER, TP_FLOATING_PRECISION_VALUE, 0, NULL);
if (new_att == NULL)
{
break;
}
arg_array[0]->next = arg_array[1] = new_att;
arg2_type = PT_TYPE_INTEGER;
}
if (arg3_type != PT_TYPE_INTEGER)
{
new_att =
pt_wrap_with_cast_op (parser, arg_array[2], PT_TYPE_INTEGER, TP_FLOATING_PRECISION_VALUE, 0, NULL);
if (new_att == NULL)
{
break;
}
arg_array[1]->next = arg_array[2] = new_att;
arg3_type = PT_TYPE_INTEGER;
}
/* set result type and precision */
if (arg_type == PT_TYPE_BIT || arg_type == PT_TYPE_VARBIT)
{
node->type_enum = PT_TYPE_VARBIT;
node->data_type = pt_make_prim_data_type (parser, PT_TYPE_VARBIT);
node->data_type->info.data_type.precision = TP_FLOATING_PRECISION_VALUE;
}
else
{
arg_type = node->type_enum = PT_TYPE_VARCHAR;
node->data_type = pt_make_prim_data_type (parser, PT_TYPE_VARCHAR);
node->data_type->info.data_type.precision = TP_FLOATING_PRECISION_VALUE;
}
/* validate and/or set arg4 */
if (! (PT_IS_STRING_TYPE (arg4_type)))
{
new_att = pt_wrap_with_cast_op (parser, arg_array[3], arg_type, TP_FLOATING_PRECISION_VALUE, 0, NULL);
if (new_att == NULL)
{
break;
}
arg_array[2]->next = arg_array[3] = new_att;
}
/* final check of arg and arg4 type matching */
if ((arg_type == PT_TYPE_VARBIT || arg_type == PT_TYPE_BIT)
&& (arg4_type != PT_TYPE_VARBIT && arg4_type != PT_TYPE_BIT))
{
arg_type = PT_TYPE_NONE;
PT_ERRORmf5 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_FUNC_NOT_DEFINED_ON_4,
fcode_get_lowercase_name (fcode), pt_show_type_enum (arg1_orig_type),
pt_show_type_enum (arg2_orig_type), pt_show_type_enum (arg3_orig_type),
pt_show_type_enum (arg4_orig_type));
}
else if ((arg4_type == PT_TYPE_VARBIT || arg4_type == PT_TYPE_BIT)
&& (arg_type != PT_TYPE_VARBIT && arg_type != PT_TYPE_BIT))
{
arg_type = PT_TYPE_NONE;
PT_ERRORmf5 (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_FUNC_NOT_DEFINED_ON_4,
fcode_get_lowercase_name (fcode), pt_show_type_enum (arg1_orig_type),
pt_show_type_enum (arg2_orig_type), pt_show_type_enum (arg3_orig_type),
pt_show_type_enum (arg4_orig_type));
}
}
break;
case F_ELT:
{
PT_NODE *new_att = NULL;
PT_NODE *arg = arg_list, *prev_arg = arg_list;
int max_precision = 0;
/* check and cast the type for the index argument. */
if (!PT_IS_DISCRETE_NUMBER_TYPE (arg->type_enum))
{
new_att = pt_wrap_with_cast_op (parser, arg, PT_TYPE_BIGINT, TP_FLOATING_PRECISION_VALUE, 0, NULL);
if (new_att)
{
prev_arg = arg_list = arg = new_att;
node->info.function.arg_list = arg_list;
}
else
{
break;
}
}
/*
* Look for the first argument of character string type and obtain its category (CHAR). All other
* arguments should be converted to this type, which is also the return type. */
arg_type = PT_TYPE_NONE;
arg = arg->next;
while (arg && arg_type == PT_TYPE_NONE)
{
if (PT_IS_CHAR_STRING_TYPE (arg->type_enum))
{
arg_type = PT_TYPE_VARCHAR;
}
else
{
arg = arg->next;
}
}
if (arg_type == PT_TYPE_NONE)
{
/* no [N]CHAR [VARYING] argument passed; convert them all to VARCHAR */
arg_type = PT_TYPE_VARCHAR;
}
/* take the maximum precision among all value arguments */
arg = arg_list->next;
while (arg)
{
int precision = TP_FLOATING_PRECISION_VALUE;
precision = pt_character_length_for_node (arg, arg_type);
if (max_precision != TP_FLOATING_PRECISION_VALUE)
{
if (precision == TP_FLOATING_PRECISION_VALUE || max_precision < precision)
{
max_precision = precision;
}
}
arg = arg->next;
}
/* cast all arguments to [N]CHAR VARYING(max_precision) */
arg = arg_list->next;
while (arg)
{
if ((arg->type_enum != arg_type) ||
(arg->data_type && arg->data_type->info.data_type.precision != max_precision))
{
PT_NODE *new_attr = pt_wrap_with_cast_op (parser, arg, arg_type,
max_precision, 0, NULL);
if (new_attr)
{
prev_arg->next = arg = new_attr;
}
else
{
break;
}
}
arg = arg->next;
prev_arg = prev_arg->next;
}
/* Return the selected data type and precision */
node->data_type = pt_make_prim_data_type (parser, arg_type);
if (node->data_type)
{
node->type_enum = arg_type;
node->data_type->info.data_type.precision = max_precision;
node->data_type->info.data_type.dec_precision = 0;
}
}
break;
default:
/* otherwise, f(x) has same type as x */
node->type_enum = arg_type;
node->data_type = parser_copy_tree_list (parser, arg_list->data_type);
break;
}
/* to prevent recheck of function return type at pt_eval_function_type_old() */
node->info.function.is_type_checked = true;
}
/* collation checking */
arg_list = node->info.function.arg_list;
switch (fcode)
{
case PT_GROUP_CONCAT:
{
PT_COLL_INFER coll_infer1;
PT_NODE *new_node;
PT_TYPE_ENUM sep_type;
(void) pt_get_collation_info (arg_list, &coll_infer1);
sep_type = (arg_list->next) ? arg_list->next->type_enum : PT_TYPE_NONE;
if (PT_HAS_COLLATION (sep_type))
{
assert (arg_list->next != NULL);
new_node =
pt_coerce_node_collation (parser, arg_list->next, coll_infer1.coll_id, coll_infer1.codeset, false, false,
PT_COLL_WRAP_TYPE_FOR_MAYBE (sep_type), PT_TYPE_NONE);
if (new_node == NULL)
{
goto error_collation;
}
arg_list->next = new_node;
}
if (arg_list->type_enum != PT_TYPE_MAYBE)
{
new_node =
pt_coerce_node_collation (parser, node, coll_infer1.coll_id, coll_infer1.codeset, true, false,
PT_COLL_WRAP_TYPE_FOR_MAYBE (arg_list->type_enum), PT_TYPE_NONE);
if (new_node == NULL)
{
goto error_collation;
}
node = new_node;
}
else if (node->data_type != NULL)
{
/* argument is not determined, collation of result will be resolved at execution */
node->data_type->info.data_type.collation_flag = TP_DOMAIN_COLL_LEAVE;
}
}
break;
case F_INSERT_SUBSTRING:
{
PT_TYPE_ENUM arg1_type = PT_TYPE_NONE, arg4_type = PT_TYPE_NONE;
PT_NODE *arg_array[NUM_F_INSERT_SUBSTRING_ARGS];
int num_args = 0;
PT_COLL_INFER coll_infer1, coll_infer4;
INTL_CODESET common_cs = LANG_SYS_CODESET;
int common_coll = LANG_SYS_COLLATION;
PT_NODE *new_node;
int args_w_coll = 0;
coll_infer1.codeset = LANG_SYS_CODESET;
coll_infer4.codeset = LANG_SYS_CODESET;
coll_infer1.coll_id = LANG_SYS_COLLATION;
coll_infer4.coll_id = LANG_SYS_COLLATION;
coll_infer1.coerc_level = PT_COLLATION_NOT_APPLICABLE;
coll_infer4.coerc_level = PT_COLLATION_NOT_APPLICABLE;
coll_infer1.can_force_cs = true;
coll_infer4.can_force_cs = true;
if (pt_node_list_to_array (parser, arg_list, arg_array, NUM_F_INSERT_SUBSTRING_ARGS, &num_args) != NO_ERROR)
{
break;
}
if (num_args != NUM_F_INSERT_SUBSTRING_ARGS)
{
assert (false);
break;
}
arg1_type = arg_array[0]->type_enum;
arg4_type = arg_array[3]->type_enum;
if (PT_HAS_COLLATION (arg1_type) || arg1_type == PT_TYPE_MAYBE)
{
if (pt_get_collation_info (arg_array[0], &coll_infer1))
{
args_w_coll++;
}
if (arg1_type != PT_TYPE_MAYBE)
{
common_coll = coll_infer1.coll_id;
common_cs = coll_infer1.codeset;
}
}
if (PT_HAS_COLLATION (arg4_type) || arg4_type == PT_TYPE_MAYBE)
{
if (pt_get_collation_info (arg_array[3], &coll_infer4))
{
args_w_coll++;
}
if (arg1_type != PT_TYPE_MAYBE)
{
common_coll = coll_infer4.coll_id;
common_cs = coll_infer4.codeset;
}
}
if (coll_infer1.coll_id == coll_infer4.coll_id)
{
assert (coll_infer1.codeset == coll_infer4.codeset);
common_coll = coll_infer1.coll_id;
common_cs = coll_infer1.codeset;
}
else
{
if (pt_common_collation (&coll_infer1, &coll_infer4, NULL, args_w_coll, false, &common_coll, &common_cs) !=
0)
{
goto error_collation;
}
}
/* coerce collation of arguments */
if ((common_coll != coll_infer1.coll_id || common_cs != coll_infer1.codeset)
&& (PT_HAS_COLLATION (arg1_type) || arg1_type == PT_TYPE_MAYBE))
{
new_node =
pt_coerce_node_collation (parser, arg_array[0], common_coll, common_cs, coll_infer1.can_force_cs, false,
PT_COLL_WRAP_TYPE_FOR_MAYBE (arg1_type), PT_TYPE_NONE);
if (new_node == NULL)
{
goto error_collation;
}
node->info.function.arg_list = arg_array[0] = new_node;
}
/* coerce collation of arguments */
if ((common_coll != coll_infer4.coll_id || common_cs != coll_infer4.codeset)
&& (PT_HAS_COLLATION (arg4_type) || arg4_type == PT_TYPE_MAYBE))
{
new_node =
pt_coerce_node_collation (parser, arg_array[3], common_coll, common_cs, coll_infer4.can_force_cs, false,
PT_COLL_WRAP_TYPE_FOR_MAYBE (arg4_type), PT_TYPE_NONE);
if (new_node == NULL)
{
goto error_collation;
}
arg_array[2]->next = arg_array[3] = new_node;
}
if ((arg_array[3]->type_enum == PT_TYPE_MAYBE || PT_IS_CAST_MAYBE (arg_array[3]))
&& (arg_array[0]->type_enum == PT_TYPE_MAYBE || PT_IS_CAST_MAYBE (arg_array[0])) && node->data_type != NULL)
{
node->data_type->info.data_type.collation_flag = TP_DOMAIN_COLL_LEAVE;
}
else
{
new_node =
pt_coerce_node_collation (parser, node, common_coll, common_cs, true, false, PT_TYPE_NONE, PT_TYPE_NONE);
if (new_node == NULL)
{
goto error_collation;
}
node = new_node;
}
}
break;
default:
node = pt_check_function_collation (parser, node);
break;
}
return node;
error_collation:
PT_ERRORmf (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_COLLATION_OP_ERROR,
fcode_get_lowercase_name (fcode));
return node;
}
/*
* pt_check_function_collation () - checks the collation of function
* (PT_FUNCTION)
*
* return: error code
* parser(in): parser context
* node(in/out): a parse tree function node
*
*/
static PT_NODE *
pt_check_function_collation (PARSER_CONTEXT *parser, PT_NODE *node)
{
PT_NODE *arg_list, *arg, *prev_arg, *new_node;
PT_COLL_INFER common_coll_infer, res_coll_infer;
bool need_arg_coerc = false;
TP_DOMAIN_COLL_ACTION res_collation_flag = TP_DOMAIN_COLL_LEAVE;
FUNC_CODE fcode;
assert (node != NULL);
assert (node->node_type == PT_FUNCTION);
if (node->info.function.arg_list == NULL)
{
return node;
}
fcode = node->info.function.function_type;
arg_list = node->info.function.arg_list;
prev_arg = NULL;
if (fcode == F_ELT)
{
if (arg_list->next == NULL)
{
return node;
}
arg_list = arg_list->next;
prev_arg = arg_list;
}
arg = arg_list;
common_coll_infer.coll_id = -1;
common_coll_infer.codeset = INTL_CODESET_NONE;
common_coll_infer.can_force_cs = true;
common_coll_infer.coerc_level = PT_COLLATION_NOT_APPLICABLE;
while (arg != NULL)
{
PT_COLL_INFER arg_coll_infer;
arg_coll_infer.coll_id = -1;
if (arg->type_enum != PT_TYPE_MAYBE && ! (PT_IS_CAST_MAYBE (arg)))
{
res_collation_flag = TP_DOMAIN_COLL_NORMAL;
}
if ((PT_HAS_COLLATION (arg->type_enum) || arg->type_enum == PT_TYPE_MAYBE)
&& pt_get_collation_info (arg, &arg_coll_infer))
{
bool apply_common_coll = false;
int common_coll;
INTL_CODESET common_cs;
if (common_coll_infer.coll_id != -1 || common_coll_infer.coll_id != arg_coll_infer.coll_id)
{
need_arg_coerc = true;
}
if (common_coll_infer.coll_id == -1)
{
apply_common_coll = true;
}
else
{
if (pt_common_collation (&common_coll_infer, &arg_coll_infer, NULL, 2, false, &common_coll, &common_cs) ==
0)
{
if (common_coll != common_coll_infer.coll_id)
{
apply_common_coll = true;
}
}
else
{
goto error_collation;
}
}
if (apply_common_coll)
{
common_coll_infer = arg_coll_infer;
}
}
arg = arg->next;
}
if (common_coll_infer.coll_id == -1)
{
return node;
}
arg = arg_list;
while (need_arg_coerc && arg != NULL)
{
PT_COLL_INFER arg_coll_infer;
arg_coll_infer.coll_id = -1;
if (! (PT_HAS_COLLATION (arg->type_enum) || arg->type_enum == PT_TYPE_MAYBE))
{
prev_arg = arg;
arg = arg->next;
continue;
}
if (!pt_get_collation_info (arg, &arg_coll_infer))
{
prev_arg = arg;
arg = arg->next;
continue;
}
if (common_coll_infer.coll_id != arg_coll_infer.coll_id)
{
PT_NODE *save_next;
save_next = arg->next;
new_node =
pt_coerce_node_collation (parser, arg, common_coll_infer.coll_id, common_coll_infer.codeset,
arg_coll_infer.can_force_cs, false, PT_COLL_WRAP_TYPE_FOR_MAYBE (arg->type_enum),
PT_TYPE_NONE);
if (new_node != NULL)
{
arg = new_node;
if (prev_arg == NULL)
{
node->info.function.arg_list = arg;
}
else
{
prev_arg->next = arg;
}
arg->next = save_next;
}
}
prev_arg = arg;
arg = arg->next;
}
if (need_arg_coerc)
{
switch (fcode)
{
case F_SET:
case F_MULTISET:
case F_SEQUENCE:
/* add the new data_type to the set of data_types */
pt_add_type_to_set (parser, arg_list, &node->data_type);
break;
default:
break;
}
}
if (PT_HAS_COLLATION (node->type_enum) && res_collation_flag == TP_DOMAIN_COLL_LEAVE && node->data_type != NULL)
{
node->data_type->info.data_type.collation_flag = res_collation_flag;
}
else if ((PT_HAS_COLLATION (node->type_enum) || node->type_enum == PT_TYPE_MAYBE)
&& pt_get_collation_info (node, &res_coll_infer) && res_coll_infer.coll_id != common_coll_infer.coll_id)
{
new_node =
pt_coerce_node_collation (parser, node, common_coll_infer.coll_id, common_coll_infer.codeset, true, false,
PT_COLL_WRAP_TYPE_FOR_MAYBE (node->type_enum), PT_TYPE_NONE);
if (new_node != NULL)
{
node = new_node;
}
}
return node;
error_collation:
PT_ERRORmf (parser, node, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_COLLATION_OP_ERROR,
fcode_get_lowercase_name (node->info.function.function_type));
return node;
}
/* pt_character_length_for_node() -
return: number of characters that a value of the given type can possibly
occuppy when cast to a CHAR type.
node(in): node with type whose character length is to be returned.
coerce_type(in): string type that node will be cast to
*/
static int
pt_character_length_for_node (PT_NODE *node, const PT_TYPE_ENUM coerce_type)
{
int precision = DB_DEFAULT_PRECISION;
switch (node->type_enum)
{
case PT_TYPE_DOUBLE:
precision = TP_DOUBLE_AS_CHAR_LENGTH;
break;
case PT_TYPE_FLOAT:
precision = TP_FLOAT_AS_CHAR_LENGTH;
break;
case PT_TYPE_MONETARY:
precision = TP_MONETARY_AS_CHAR_LENGTH;
break;
case PT_TYPE_BIGINT:
precision = TP_BIGINT_AS_CHAR_LENGTH;
break;
case PT_TYPE_INTEGER:
precision = TP_INTEGER_AS_CHAR_LENGTH;
break;
case PT_TYPE_SMALLINT:
precision = TP_SMALLINT_AS_CHAR_LENGTH;
break;
case PT_TYPE_TIME:
precision = TP_TIME_AS_CHAR_LENGTH;
break;
case PT_TYPE_DATE:
precision = TP_DATE_AS_CHAR_LENGTH;
break;
case PT_TYPE_TIMESTAMP:
precision = TP_TIMESTAMP_AS_CHAR_LENGTH;
break;
case PT_TYPE_TIMESTAMPLTZ:
case PT_TYPE_TIMESTAMPTZ:
precision = TP_TIMESTAMPTZ_AS_CHAR_LENGTH;
break;
case PT_TYPE_DATETIME:
precision = TP_DATETIME_AS_CHAR_LENGTH;
break;
case PT_TYPE_DATETIMETZ:
case PT_TYPE_DATETIMELTZ:
precision = TP_DATETIMETZ_AS_CHAR_LENGTH;
break;
case PT_TYPE_NUMERIC:
if (node->data_type == NULL)
{
precision = DB_DEFAULT_NUMERIC_PRECISION + 1; /* sign */
break;
}
precision = node->data_type->info.data_type.precision;
if (precision == 0 || precision == DB_DEFAULT_PRECISION)
{
precision = DB_DEFAULT_NUMERIC_PRECISION;
}
precision++; /* for sign */
if (node->data_type->info.data_type.dec_precision
&& (node->data_type->info.data_type.dec_precision != DB_DEFAULT_SCALE
|| node->data_type->info.data_type.dec_precision != DB_DEFAULT_NUMERIC_SCALE))
{
precision++; /* for decimal point */
}
break;
case PT_TYPE_CHAR:
if (node->data_type != NULL)
{
precision = node->data_type->info.data_type.precision;
}
if (precision == DB_DEFAULT_PRECISION)
{
precision = DB_MAX_CHAR_PRECISION;
}
break;
case PT_TYPE_VARCHAR:
if (node->data_type != NULL)
{
precision = node->data_type->info.data_type.precision;
}
if (precision == DB_DEFAULT_PRECISION)
{
precision = DB_MAX_VARCHAR_PRECISION;
}
break;
case PT_TYPE_NULL:
case PT_TYPE_NA:
precision = 0;
break;
default:
/* for host vars */
precision = (coerce_type == PT_TYPE_VARCHAR) ? DB_MAX_VARCHAR_PRECISION : TP_FLOATING_PRECISION_VALUE;
break;
}
return precision;
}
/*
* pt_get_equivalent_type () - get the type to which a node should be
* converted to in order to match an expression
* definition
* return : the new type
* def_type(in) : the type defined in the expression signature
* arg_type(in) : the type of the received expression argument
*/
PT_TYPE_ENUM
pt_get_equivalent_type (const PT_ARG_TYPE def_type, const PT_TYPE_ENUM arg_type)
{
if (arg_type == PT_TYPE_NULL || arg_type == PT_TYPE_NONE)
{
/* either the argument is null or not defined */
return arg_type;
}
if (def_type.type != pt_arg_type::GENERIC)
{
/* if the definition does not have a generic type, return the definition type */
return def_type.val.type;
}
/* In some cases that involve ENUM (e.g. bit_length function) we need to convert ENUM to the other type even if the
* types are equivalent */
if (pt_are_equivalent_types (def_type, arg_type) && arg_type != PT_TYPE_ENUMERATION)
{
/* def_type includes type */
if (arg_type == PT_TYPE_LOGICAL)
{
/* def_type is a generic type and even though logical type might be equivalent with the generic definition,
* we are sure that we don't want it to be logical here */
return PT_TYPE_INTEGER;
}
return arg_type;
}
/* At this point we do not have a clear match. We will return the "largest" type for the generic type defined in the
* expression signature */
switch (def_type.val.generic_type)
{
case PT_GENERIC_TYPE_ANY:
if (arg_type == PT_TYPE_LOGICAL)
{
/* if PT_TYPE_LOGICAL appears for a PT_GENERIC_TYPE_ANY, it should be converted to PT_TYPE_INTEGER. */
return PT_TYPE_INTEGER;
}
return arg_type;
case PT_GENERIC_TYPE_PRIMITIVE:
if (PT_IS_PRIMITIVE_TYPE (arg_type))
{
return arg_type;
}
break;
case PT_GENERIC_TYPE_LOB:
if (PT_IS_LOB_TYPE (arg_type))
{
return arg_type;
}
break;
case PT_GENERIC_TYPE_DISCRETE_NUMBER:
return PT_TYPE_BIGINT;
case PT_GENERIC_TYPE_NUMBER:
if (arg_type == PT_TYPE_ENUMERATION)
{
return PT_TYPE_SMALLINT;
}
return PT_TYPE_DOUBLE;
case PT_GENERIC_TYPE_CHAR:
case PT_GENERIC_TYPE_STRING:
case PT_GENERIC_TYPE_STRING_VARYING:
return PT_TYPE_VARCHAR;
case PT_GENERIC_TYPE_BIT:
return PT_TYPE_VARBIT;
case PT_GENERIC_TYPE_DATE:
return PT_TYPE_DATETIME;
case PT_GENERIC_TYPE_SCALAR:
if (arg_type == PT_TYPE_ENUMERATION || arg_type == PT_TYPE_MAYBE || PT_IS_NUMERIC_TYPE (arg_type)
|| PT_IS_STRING_TYPE (arg_type) || PT_IS_DATE_TIME_TYPE (arg_type))
{
return arg_type;
}
else
{
return PT_TYPE_NONE;
}
case PT_GENERIC_TYPE_JSON_VAL:
if (pt_is_json_value_type (arg_type))
{
return arg_type;
}
else if (PT_IS_NUMERIC_TYPE (arg_type))
{
return PT_TYPE_JSON;
}
else
{
return PT_TYPE_NONE;
}
case PT_GENERIC_TYPE_JSON_DOC:
if (pt_is_json_doc_type (arg_type))
{
return arg_type;
}
else
{
return PT_TYPE_NONE;
}
default:
return PT_TYPE_NONE;
}
return PT_TYPE_NONE;
}
bool
pt_is_function_unsupported (FUNC_CODE fcode)
{
switch (fcode)
{
case PT_TOP_AGG_FUNC:
case F_MIDXKEY:
case F_TOP_TABLE_FUNC:
case F_VID:
return true;
default:
return false;
}
}
bool
pt_is_function_no_arg (FUNC_CODE fcode)
{
switch (fcode)
{
case PT_COUNT_STAR:
case PT_GROUPBY_NUM:
case PT_ROW_NUMBER:
case PT_RANK:
case PT_DENSE_RANK:
case PT_CUME_DIST:
case PT_PERCENT_RANK:
case F_JSON_ARRAY:
case F_JSON_OBJECT:
return true;
default:
return false;
}
}
bool
pt_is_function_new_type_checking (FUNC_CODE fcode)
{
switch (fcode)
{
// old functions
// case PT_MIN:
// case PT_MAX:
// case PT_SUM:
// case PT_AVG:
case PT_STDDEV:
case PT_VARIANCE:
case PT_STDDEV_POP:
case PT_VAR_POP:
case PT_STDDEV_SAMP:
case PT_VAR_SAMP:
case PT_GROUPBY_NUM:
// case PT_AGG_BIT_AND:
// case PT_AGG_BIT_OR:
// case PT_AGG_BIT_XOR:
// case PT_GROUP_CONCAT:
case PT_ROW_NUMBER:
case PT_RANK:
case PT_DENSE_RANK:
// case PT_NTILE:
// case PT_LEAD:
// case PT_LAG:
case F_SET:
case F_TABLE_SET:
case F_MULTISET:
case F_TABLE_MULTISET:
case F_SEQUENCE:
case F_TABLE_SEQUENCE:
// case F_INSERT_SUBSTRING:
// case F_ELT:
// case PT_FIRST_VALUE:
// case PT_LAST_VALUE:
// case PT_NTH_VALUE:
// case PT_MEDIAN:
case PT_CUME_DIST:
case PT_PERCENT_RANK:
// case PT_PERCENTILE_CONT:
// case PT_PERCENTILE_DISC:
case F_BENCHMARK:
// JSON functions are migrated to new checking function
case F_JSON_ARRAY:
case F_JSON_ARRAY_APPEND:
case F_JSON_ARRAY_INSERT:
case PT_JSON_ARRAYAGG:
case F_JSON_CONTAINS:
case F_JSON_CONTAINS_PATH:
case F_JSON_DEPTH:
case F_JSON_EXTRACT:
case F_JSON_GET_ALL_PATHS:
case F_JSON_KEYS:
case F_JSON_INSERT:
case F_JSON_LENGTH:
case F_JSON_MERGE:
case F_JSON_MERGE_PATCH:
case F_JSON_OBJECT:
case PT_JSON_OBJECTAGG:
case F_JSON_PRETTY:
case F_JSON_QUOTE:
case F_JSON_REMOVE:
case F_JSON_REPLACE:
case F_JSON_SEARCH:
case F_JSON_SET:
case F_JSON_TYPE:
case F_JSON_UNQUOTE:
case F_JSON_VALID:
// REGEXP functions are migrated to new checking function
case F_REGEXP_COUNT:
case F_REGEXP_INSTR:
case F_REGEXP_LIKE:
case F_REGEXP_REPLACE:
case F_REGEXP_SUBSTR:
// COUNT functions
case PT_COUNT:
case PT_COUNT_STAR:
return true;
default:
return false;
}
}