 35942cfb4f
			
		
	
	35942cfb4f
	
	
	
		
			
			A whole slew of missing builtin functions were added, not just the ones directly relevant for MXS-2242.
		
			
				
	
	
		
			618 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			618 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2016 MariaDB Corporation Ab
 | |
|  *
 | |
|  * Use of this software is governed by the Business Source License included
 | |
|  * in the LICENSE.TXT file and at www.mariadb.com/bsl11.
 | |
|  *
 | |
|  * Change Date: 2022-01-01
 | |
|  *
 | |
|  * On the date above, in accordance with the Business Source License, use
 | |
|  * of this software will be governed by version 2 or later of the General
 | |
|  * Public License.
 | |
|  */
 | |
| 
 | |
| #include "builtin_functions.h"
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <maxbase/assert.h>
 | |
| 
 | |
| static struct
 | |
| {
 | |
|     bool inited;
 | |
| } unit = {false};
 | |
| 
 | |
| // The functions have been taken from:
 | |
| // https://mariadb.com/kb/en/mariadb/functions-and-operators/
 | |
| 
 | |
| static const char* BUILTIN_FUNCTIONS[] =
 | |
| {
 | |
|     /*
 | |
|      * Bit Functions and Operators
 | |
|      * https://mariadb.com/kb/en/mariadb/bit-functions-and-operators
 | |
|      */
 | |
|     "bit_count",
 | |
| 
 | |
|     /*
 | |
|      * Control Flow Functions
 | |
|      * https://mariadb.com/kb/en/mariadb/control-flow-functions/
 | |
|      */
 | |
|     "if",
 | |
|     "ifnull",
 | |
|     "nullif",
 | |
| 
 | |
|     /*
 | |
|      * Date and Time Functions
 | |
|      * https://mariadb.com/kb/en/mariadb/date-and-time-functions/
 | |
|      */
 | |
|     "adddate",
 | |
|     "addtime",
 | |
|     "convert_tz",
 | |
|     "curdate",
 | |
|     "current_date",
 | |
|     "current_time",
 | |
|     "current_timestamp",
 | |
|     "curtime",
 | |
|     "date",
 | |
|     "datediff",
 | |
|     "date_add",
 | |
|     "date_format",
 | |
|     "date_sub",
 | |
|     "day",
 | |
|     "dayname",
 | |
|     "dayofmonth",
 | |
|     "dayofweek",
 | |
|     "dayofyear",
 | |
|     "extract",
 | |
|     "from_days",
 | |
|     "from_unixtime",
 | |
|     "get_format",
 | |
|     "hour",
 | |
|     "last_day",
 | |
|     "localtime",
 | |
|     "localtimestamp",
 | |
|     "makedate",
 | |
|     "maketime",
 | |
|     "microsecond",
 | |
|     "minute",
 | |
|     "month",
 | |
|     "monthname",
 | |
|     "now",
 | |
|     "period_add",
 | |
|     "period_diff",
 | |
|     "quarter",
 | |
|     "second",
 | |
|     "sec_to_time",
 | |
|     "str_to_date",
 | |
|     "subdate",
 | |
|     "subtime",
 | |
|     "sysdate",
 | |
|     "time",
 | |
|     "timediff"
 | |
|     "timestamp",
 | |
|     "timestampadd",
 | |
|     "timestampdiff",
 | |
|     "time_format",
 | |
|     "time_to_sec",
 | |
|     "to_days",
 | |
|     "to_seconds",
 | |
|     "unix_timestamp",
 | |
|     "utc_date",
 | |
|     "utc_time",
 | |
|     "week",
 | |
|     "weekday",
 | |
|     "weekofyear",
 | |
|     "year",
 | |
|     "yearweek",
 | |
| 
 | |
|     /*
 | |
|      * Columns Functions
 | |
|      * https://mariadb.com/kb/en/mariadb/dynamic-columns-functions/
 | |
|      */
 | |
|     "column_check",
 | |
|     "column_exists",
 | |
|     "column_get",
 | |
|     "column_json",
 | |
|     "column_list",
 | |
| 
 | |
|     /*
 | |
|      * Encryption, Hashing and Compression Functions
 | |
|      * https://mariadb.com/kb/en/mariadb/encryption-hashing-and-compression-functions/
 | |
|      */
 | |
|     "aes_decrypt",
 | |
|     "aes_encrypt",
 | |
|     "compress",
 | |
|     "decode",
 | |
|     "des_decrypt",
 | |
|     "des_encrypt",
 | |
|     "encode",
 | |
|     "encrypt",
 | |
|     "md5",
 | |
|     "old_password",
 | |
|     "password",
 | |
|     "sha1",
 | |
|     "sha2",
 | |
|     "uncompress",
 | |
|     "uncompressed_length",
 | |
| 
 | |
|     /*
 | |
|      * Comparison Operators
 | |
|      * https://mariadb.com/kb/en/mariadb/comparison-operators/
 | |
|      */
 | |
|     "coalesce",
 | |
|     "greatest",
 | |
|     "interval",
 | |
|     "isnull",
 | |
|     "least",
 | |
| 
 | |
|     /*
 | |
|      * Functions and Modifiers for use with GROUP BY
 | |
|      * https://mariadb.com/kb/en/mariadb/functions-and-modifiers-for-use-with-group-by/
 | |
|      */
 | |
|     "avg",
 | |
|     "bit_and",
 | |
|     "bit_or",
 | |
|     "bit_xor",
 | |
|     "count",
 | |
|     "group_concat",
 | |
|     "max",
 | |
|     "min",
 | |
|     "std",
 | |
|     "stddev",
 | |
|     "stddev_pop",
 | |
|     "stddev_samp",
 | |
|     "sum",
 | |
|     "variance",
 | |
|     "var_pop",
 | |
|     "var_samp",
 | |
| 
 | |
|     /*
 | |
|      * Geographic Functions
 | |
|      * https://mariadb.com/kb/en/mariadb/geographic-functions/
 | |
|      */
 | |
| 
 | |
|     // Geometry Constructors
 | |
|     // https://mariadb.com/kb/en/mariadb/geometry-constructors/
 | |
|     "geometrycollection",
 | |
|     "linestring",
 | |
|     "multilinestring",
 | |
|     "multipoint",
 | |
|     "point",
 | |
|     "polygon",
 | |
|     "st_buffer",
 | |
|     "st_convexhull",
 | |
|     "st_intersection",
 | |
|     "st_pointonsurface",
 | |
|     "st_symdifference",
 | |
|     "std_union",
 | |
| 
 | |
|     // Geometry Properties
 | |
|     // https://mariadb.com/kb/en/mariadb/geometry-properties/
 | |
|     "boundary",
 | |
|     "dimension",
 | |
|     "envelope",
 | |
|     "geometryn",
 | |
|     "geometrytype",
 | |
|     "isclosed",
 | |
|     "isempty",
 | |
|     "isring",
 | |
|     "issimple",
 | |
|     "numgeometries",
 | |
|     "srid",
 | |
|     "st_boundary",
 | |
|     "st_dimension",
 | |
|     "st_envelope",
 | |
|     "st_geometryn",
 | |
|     "st_geometrytype",
 | |
|     "st_isclosed",
 | |
|     "st_isempty",
 | |
|     "st_isring",
 | |
|     "st_issimple",
 | |
|     "st_numgeometries",
 | |
|     "st_relate",
 | |
|     "st_srid",
 | |
| 
 | |
|     // Geometry Relations
 | |
|     // https://mariadb.com/kb/en/library/geometry-relations/
 | |
|     "contains",
 | |
|     "crosses",
 | |
|     "disjoint",
 | |
|     "equals",
 | |
|     "intersects",
 | |
|     "overlaps",
 | |
|     "st_contains",
 | |
|     "st_crosses",
 | |
|     "st_difference",
 | |
|     "st_disjoint",
 | |
|     "st_distance",
 | |
|     "st_equals",
 | |
|     "st_intersects",
 | |
|     "st_length",
 | |
|     "st_overlaps",
 | |
|     "st_touches",
 | |
|     "st_within",
 | |
|     "touches",
 | |
|     "within",
 | |
| 
 | |
|     // LineString Properties
 | |
|     // https://mariadb.com/kb/en/library/linestring-properties/
 | |
|     "endpoint",
 | |
|     "glength",
 | |
|     "numpoints",
 | |
|     "pointn",
 | |
|     "startpoint",
 | |
|     "st_endpoint",
 | |
|     "st_numpoints",
 | |
|     "st_pointn",
 | |
|     "st_startpoint",
 | |
| 
 | |
|     // MBR
 | |
|     // https://mariadb.com/kb/en/library/mbr-minimum-bounding-rectangle/
 | |
|     "mbrcontains",
 | |
|     "mbrdisjoint",
 | |
|     "mbrequal",
 | |
|     "mbrintersects",
 | |
|     "mbroverlaps",
 | |
|     "mbrtouches",
 | |
|     "mbrwithin",
 | |
| 
 | |
|     // Point Properties
 | |
|     // https://mariadb.com/kb/en/library/point-properties/
 | |
|     "st_x",
 | |
|     "st_y",
 | |
|     "x",
 | |
|     "y",
 | |
| 
 | |
|     // Polygon Properties
 | |
|     // https://mariadb.com/kb/en/library/polygon-properties/
 | |
|     "area",
 | |
|     "centroid",
 | |
|     "exteriorring",
 | |
|     "interiorringn",
 | |
|     "numinteriorrings",
 | |
|     "st_area",
 | |
|     "st_centroid",
 | |
|     "st_exteriorring",
 | |
|     "st_interiorringn",
 | |
|     "st_numinteriorrings",
 | |
| 
 | |
|     // WKB
 | |
|     // https://mariadb.com/kb/en/library/wkb/
 | |
|     "asbinary",
 | |
|     "aswkb",
 | |
|     "mlinefromwkb",
 | |
|     "mpointfromwkb",
 | |
|     "mpolyfromwkb",
 | |
|     "geomcollfromwkb",
 | |
|     "geometrycollectionfromwkb",
 | |
|     "geometryfromwkb",
 | |
|     "geomfromwkb",
 | |
|     "linefromwkb",
 | |
|     "linestringfromwkb",
 | |
|     "multilinestringfromwkb",
 | |
|     "multipointfromwkb",
 | |
|     "multipolygonfromwkb",
 | |
|     "pointfromwkb",
 | |
|     "polyfromwkb",
 | |
|     "polygonfromwkb",
 | |
|     "st_asbinary",
 | |
|     "st_aswkb",
 | |
|     "st_geomcollfromwkb",
 | |
|     "st_geometrycollectionfromwkb",
 | |
|     "st_geometryfromwkb",
 | |
|     "st_geomfromwkb",
 | |
|     "st_linefromwkb",
 | |
|     "st_linestringfromwkb",
 | |
|     "st_pointfromwkb",
 | |
|     "st_polyfromwkb",
 | |
|     "st_polygonfromwkb",
 | |
| 
 | |
|     // WKT
 | |
|     // https://mariadb.com/kb/en/mariadb/wkt/
 | |
|     "MLineFromText",
 | |
|     "MPointFromText",
 | |
|     "MPolyFromText",
 | |
|     "ST_AsText",
 | |
|     "ST_ASWKT",
 | |
|     "ST_GeomCollFromText",
 | |
|     "ST_GeometryFromText",
 | |
|     "ST_LineFromText",
 | |
|     "ST_PointFromText",
 | |
|     "ST_PolyFromText",
 | |
|     // Deprecated
 | |
|     "geomfromtext",
 | |
| 
 | |
|     /*
 | |
|      * Information Functions
 | |
|      * https://mariadb.com/kb/en/mariadb/information-functions/
 | |
|      */
 | |
|     "benchmark",
 | |
|     "binlog_gtid_pos",
 | |
|     "charset",
 | |
|     "coercibility",
 | |
|     "collation",
 | |
|     "connection_id",
 | |
|     "current_role",
 | |
|     "current_user",
 | |
|     "database",
 | |
|     "decode_histogram",
 | |
|     "found_rows",
 | |
|     "last_insert_id",
 | |
|     "row_count",
 | |
|     "schema",
 | |
|     "session_user",
 | |
|     "system_user",
 | |
|     "user",
 | |
|     "version",
 | |
| 
 | |
|     /*
 | |
|      * Miscellanesous Functions
 | |
|      * https://mariadb.com/kb/en/mariadb/miscellaneous-functions/
 | |
|      */
 | |
|     "default",
 | |
|     "inet6_aton",
 | |
|     "inet6_ntoa",
 | |
|     "inet_aton",
 | |
|     "inet_ntoa",
 | |
|     "is_ipv4",
 | |
|     "is_ipv4_compat",
 | |
|     "is_ipv4_mapped",
 | |
|     "is_ipv6",
 | |
|     "last_value",
 | |
|     "master_gtid_wait",
 | |
|     "master_pos_wait",
 | |
|     "name_const",
 | |
|     "sleep",
 | |
|     "uuid",
 | |
|     "uuid_short",
 | |
|     "values",
 | |
| 
 | |
|     /**
 | |
|      * Although conceptually non-updating, we classify these as WRITE as
 | |
|      * that will force them to be sent to _master_ outside transactions.
 | |
|      *
 | |
|      * "get_lock",
 | |
|      * "is_free_lock",
 | |
|      * "is_used_lock",
 | |
|      * "release_lock",
 | |
|      */
 | |
| 
 | |
|     /*
 | |
|      * Numeric Functions
 | |
|      * https://mariadb.com/kb/en/mariadb/numeric-functions/
 | |
|      */
 | |
|     "abs",
 | |
|     "acos",
 | |
|     "asin",
 | |
|     "atan",
 | |
|     "atan2",
 | |
|     "ceil",
 | |
|     "ceiling",
 | |
|     "conv",
 | |
|     "cos",
 | |
|     "cot",
 | |
|     "crc32",
 | |
|     "degrees",
 | |
|     "div",
 | |
|     "exp",
 | |
|     "floor",
 | |
|     "greatest",
 | |
|     "least",
 | |
|     "ln",
 | |
|     "log",
 | |
|     "log10",
 | |
|     "log2",
 | |
|     "mod",
 | |
|     "oct",
 | |
|     "pi",
 | |
|     "pow",
 | |
|     "power",
 | |
|     "radians",
 | |
|     "rand",
 | |
|     "round",
 | |
|     "sign",
 | |
|     "sin",
 | |
|     "sqrt",
 | |
|     "tan",
 | |
|     "truncate",
 | |
| 
 | |
|     /*
 | |
|      * String Functions
 | |
|      * https://mariadb.com/kb/en/mariadb/string-functions/
 | |
|      */
 | |
|     "ascii",
 | |
|     "bin",
 | |
|     "bit_length",
 | |
|     "cast",
 | |
|     "char",
 | |
|     "character_length",
 | |
|     "char_length",
 | |
|     "concat",
 | |
|     "concat_ws",
 | |
|     "convert",
 | |
|     "elt",
 | |
|     "export_set",
 | |
|     "extractvalue",
 | |
|     "field",
 | |
|     "find_in_set",
 | |
|     "format",
 | |
|     "hex",
 | |
|     "insert",
 | |
|     "instr",
 | |
|     "lcase",
 | |
|     "left",
 | |
|     "length",
 | |
|     "like",
 | |
|     "load_file",
 | |
|     "locate",
 | |
|     "lower",
 | |
|     "lpad",
 | |
|     "ltrim",
 | |
|     "make_set",
 | |
|     "mid",
 | |
|     "octet_length",
 | |
|     "ord",
 | |
|     "position",
 | |
|     "quote",
 | |
|     "repeat",
 | |
|     "replace",
 | |
|     "reverse",
 | |
|     "right",
 | |
|     "rpad",
 | |
|     "rtrim",
 | |
|     "soundex",
 | |
|     "space",
 | |
|     "strcmp",
 | |
|     "substr",
 | |
|     "substring",
 | |
|     "substring_index",
 | |
|     "trim",
 | |
|     "ucase",
 | |
|     "unhex",
 | |
|     "updatexml",
 | |
|     "upper",
 | |
|     "from_base64",
 | |
|     "to_base64",
 | |
|     "weight_string",
 | |
| 
 | |
|     /*
 | |
|      * Regex functions
 | |
|      * https://mariadb.com/kb/en/mariadb/regular-expressions-functions/
 | |
|      */
 | |
|     "regexp",
 | |
|     "regexp_instr",
 | |
|     "regexp_replace",
 | |
|     "regexp_substr",
 | |
|     "rlike",
 | |
| 
 | |
|     /*
 | |
|      * http://dev.mysql.com/doc/refman/5.7/en/row-subqueries.html
 | |
|      */
 | |
|     "row"
 | |
| };
 | |
| 
 | |
| const size_t N_BUILTIN_FUNCTIONS = sizeof(BUILTIN_FUNCTIONS) / sizeof(BUILTIN_FUNCTIONS[0]);
 | |
| 
 | |
| static const char* BUILTIN_10_2_3_FUNCTIONS[] =
 | |
| {
 | |
|     //
 | |
|     // JSON functions: https://mariadb.com/kb/en/mariadb/json-functions
 | |
|     //
 | |
|     "json_array",
 | |
|     "json_array_append",
 | |
|     "json_array_insert",
 | |
|     "json_compact",
 | |
|     "json_contains",
 | |
|     "json_contains_path",
 | |
|     "json_depth",
 | |
|     "json_detailed",
 | |
|     "json_exists",
 | |
|     "json_extract",
 | |
|     "json_insert",
 | |
|     "json_keys",
 | |
|     "json_length",
 | |
|     "json_loose",
 | |
|     "json_merge",
 | |
|     "json_object",
 | |
|     "json_query",
 | |
|     "json_quote",
 | |
|     "json_remove"
 | |
|     "json_replace",
 | |
|     "json_search",
 | |
|     "json_set",
 | |
|     "json_type",
 | |
|     "json_unquote",
 | |
|     "json_valid",
 | |
|     "json_value",
 | |
| 
 | |
|     //
 | |
|     // Window functions: https://mariadb.com/kb/en/mariadb/window-functions/
 | |
|     //
 | |
|     "cume_dist",
 | |
|     "dense_rank",
 | |
|     "first_value",
 | |
|     "lag",
 | |
|     "last_value",
 | |
|     "lead",
 | |
|     "nth_value",
 | |
|     "ntile",
 | |
|     "percent_rank",
 | |
|     "rank",
 | |
|     "row_number",
 | |
| };
 | |
| 
 | |
| const size_t N_BUILTIN_10_2_3_FUNCTIONS =
 | |
|     sizeof(BUILTIN_10_2_3_FUNCTIONS) / sizeof(BUILTIN_10_2_3_FUNCTIONS[0]);
 | |
| 
 | |
| static const char* ORACLE_FUNCTIONS[] =
 | |
| {
 | |
|     "nvl",
 | |
|     "nvl2"
 | |
| };
 | |
| 
 | |
| const size_t N_ORACLE_FUNCTIONS = sizeof(ORACLE_FUNCTIONS) / sizeof(ORACLE_FUNCTIONS[0]);
 | |
| 
 | |
| // NOTE: sort_compare and search_compare are not identical, so don't
 | |
| // NOTE: optimize either of them away.
 | |
| static int sort_compare(const void* key, const void* value)
 | |
| {
 | |
|     return strcasecmp(*(const char**) key, *(const char**) value);
 | |
| }
 | |
| 
 | |
| static int search_compare(const void* key, const void* value)
 | |
| {
 | |
|     return strcasecmp((const char*) key, *(const char**) value);
 | |
| }
 | |
| 
 | |
| //
 | |
| // API
 | |
| //
 | |
| 
 | |
| void init_builtin_functions()
 | |
| {
 | |
|     mxb_assert(!unit.inited);
 | |
| 
 | |
|     qsort(BUILTIN_FUNCTIONS, N_BUILTIN_FUNCTIONS, sizeof(char*), sort_compare);
 | |
|     qsort(BUILTIN_10_2_3_FUNCTIONS, N_BUILTIN_10_2_3_FUNCTIONS, sizeof(char*), sort_compare);
 | |
|     qsort(ORACLE_FUNCTIONS, N_ORACLE_FUNCTIONS, sizeof(char*), sort_compare);
 | |
| 
 | |
|     unit.inited = true;
 | |
| }
 | |
| 
 | |
| void finish_builtin_functions()
 | |
| {
 | |
|     mxb_assert(unit.inited);
 | |
|     unit.inited = false;
 | |
| }
 | |
| 
 | |
| bool is_builtin_readonly_function(const char* key,
 | |
|                                   uint32_t major,
 | |
|                                   uint32_t minor,
 | |
|                                   uint32_t patch,
 | |
|                                   bool check_oracle)
 | |
| {
 | |
|     mxb_assert(unit.inited);
 | |
| 
 | |
|     char* value = bsearch(key, BUILTIN_FUNCTIONS, N_BUILTIN_FUNCTIONS, sizeof(char*), search_compare);
 | |
| 
 | |
|     if (!value)
 | |
|     {
 | |
|         if ((major > 10)
 | |
|             || ((major == 10) && (minor > 2))
 | |
|             || ((major == 10) && (minor == 2) && (patch >= 3)))
 | |
|         {
 | |
|             value = bsearch(key,
 | |
|                             BUILTIN_10_2_3_FUNCTIONS,
 | |
|                             N_BUILTIN_10_2_3_FUNCTIONS,
 | |
|                             sizeof(char*),
 | |
|                             search_compare);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (!value && check_oracle)
 | |
|     {
 | |
|         value = bsearch(key, ORACLE_FUNCTIONS, N_ORACLE_FUNCTIONS, sizeof(char*), search_compare);
 | |
|     }
 | |
| 
 | |
|     return value ? true : false;
 | |
| }
 |