/*
 * Copyright (c) 2015, 2016, 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 as
 * published by the Free Software Foundation; version 2 of the
 * License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#include <boost/unordered_set.hpp>
#include <boost/algorithm/string.hpp>

// list of built-in function names for MySQL
// taken from item_create.cc
static const char *native_mysql_functions[] =
{
  "ABS",
  "ACOS",
  "ADDTIME",
  "AES_DECRYPT",
  "AES_ENCRYPT",
  "ANY_VALUE",
  "AREA",
  "ASBINARY",
  "ASIN",
  "ASTEXT",
  "ASWKB",
  "ASWKT",
  "ATAN",
  "ATAN2",
  "AVG",
  "BENCHMARK",
  "BIN",
  "BIT_COUNT",
  "BUFFER",
  "BIT_LENGTH",
  "CEIL",
  "CEILING",
  "CENTROID",
  "CHARACTER_LENGTH",
  "CHAR_LENGTH",
  "COERCIBILITY",
  "COMPRESS",
  "CONCAT",
  "CONCAT_WS",
  "CONNECTION_ID",
  "CONV",
  "CONVERT_TZ",
  "CONVEXHULL",
  "COS",
  "COT",
  "CRC32",
  "CROSSES",
  "DATEDIFF",
  "DATE_FORMAT",
  "DAYNAME",
  "DAYOFMONTH",
  "DAYOFWEEK",
  "DAYOFYEAR",
  "DECODE",
  "DEGREES",
  "DES_DECRYPT",
  "DES_ENCRYPT",
  "DIMENSION",
  "DISJOINT",
  "DISTANCE",
  "ELT",
  "ENCODE",
  "ENCRYPT",
  "ENDPOINT",
  "ENVELOPE",
  "EQUALS",
  "EXP",
  "EXPORT_SET",
  "EXTERIORRING",
  "EXTRACTVALUE",
  "FIELD",
  "FIND_IN_SET",
  "FLOOR",
  "FOUND_ROWS",
  "FROM_BASE64",
  "FROM_DAYS",
  "FROM_UNIXTIME",
  "GEOMCOLLFROMTEXT",
  "GEOMCOLLFROMWKB",
  "GEOMETRYCOLLECTIONFROMTEXT",
  "GEOMETRYCOLLECTIONFROMWKB",
  "GEOMETRYFROMTEXT",
  "GEOMETRYFROMWKB",
  "GEOMETRYN",
  "GEOMETRYTYPE",
  "GEOMFROMTEXT",
  "GEOMFROMWKB",
  "GET_LOCK",
  "GLENGTH",
  "GREATEST",
  "GTID_SUBTRACT",
  "GTID_SUBSET",
  "HEX",
  "IFNULL",
  "INET_ATON",
  "INET_NTOA",
  "INET6_ATON",
  "INET6_NTOA",
  "IS_IPV4",
  "IS_IPV6",
  "IS_IPV4_COMPAT",
  "IS_IPV4_MAPPED",
  "INSTR",
  "INTERIORRINGN",
  "INTERSECTS",
  "ISCLOSED",
  "ISEMPTY",
  "ISNULL",
  "ISSIMPLE",
  "JSON_VALID",
  "JSON_CONTAINS",
  "JSON_CONTAINS_PATH",
  "JSON_LENGTH",
  "JSON_DEPTH",
  "JSON_TYPE",
  "JSON_KEYS",
  "JSON_EXTRACT",
  "JSON_ARRAY_APPEND",
  "JSON_INSERT",
  "JSON_ARRAY_INSERT",
  "JSON_OBJECT",
  "JSON_SEARCH",
  "JSON_SET",
  "JSON_REPLACE",
  "JSON_ARRAY",
  "JSON_REMOVE",
  "JSON_MERGE",
  "JSON_QUOTE",
  "JSON_UNQUOTE",
  "IS_FREE_LOCK",
  "IS_USED_LOCK",
  "LAST_DAY",
  "LAST_INSERT_ID",
  "LCASE",
  "LEAST",
  "LENGTH",
  "LIKE_RANGE_MIN",
  "LIKE_RANGE_MAX",
  "LINEFROMTEXT",
  "LINEFROMWKB",
  "LINESTRINGFROMTEXT",
  "LINESTRINGFROMWKB",
  "LN",
  "LOAD_FILE",
  "LOCATE",
  "LOG",
  "LOG10",
  "LOG2",
  "LOWER",
  "LPAD",
  "LTRIM",
  "MAKEDATE",
  "MAKETIME",
  "MAKE_SET",
  "MASTER_POS_WAIT",
  "MBRCONTAINS",
  "MBRCOVEREDBY",
  "MBRCOVERS",
  "MBRDISJOINT",
  "MBREQUAL",
  "MBREQUALS",
  "MBRINTERSECTS",
  "MBROVERLAPS",
  "MBRTOUCHES",
  "MBRWITHIN",
  "MD5",
  "MLINEFROMTEXT",
  "MLINEFROMWKB",
  "MONTHNAME",
  "MPOINTFROMTEXT",
  "MPOINTFROMWKB",
  "MPOLYFROMTEXT",
  "MPOLYFROMWKB",
  "MULTILINESTRINGFROMTEXT",
  "MULTILINESTRINGFROMWKB",
  "MULTIPOINTFROMTEXT",
  "MULTIPOINTFROMWKB",
  "MULTIPOLYGONFROMTEXT",
  "MULTIPOLYGONFROMWKB",
  "NAME_CONST",
  "NULLIF",
  "NUMGEOMETRIES",
  "NUMINTERIORRINGS",
  "NUMPOINTS",
  "OCT",
  "OCTET_LENGTH",
  "ORD",
  "OVERLAPS",
  "PERIOD_ADD",
  "PERIOD_DIFF",
  "PI",
  "POINTFROMTEXT",
  "POINTFROMWKB",
  "POINTN",
  "POLYFROMTEXT",
  "POLYFROMWKB",
  "POLYGONFROMTEXT",
  "POLYGONFROMWKB",
  "POW",
  "POWER",
  "QUOTE",
  "RADIANS",
  "RAND",
  "RANDOM_BYTES",
  "RELEASE_ALL_LOCKS",
  "RELEASE_LOCK",
  "REVERSE",
  "ROUND",
  "RPAD",
  "RTRIM",
  "SEC_TO_TIME",
  "SHA",
  "SHA1",
  "SHA2",
  "SIGN",
  "SIN",
  "SLEEP",
  "SOUNDEX",
  "SPACE",
  "WAIT_FOR_EXECUTED_GTID_SET",
  "WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS",
  "SQRT",
  "SRID",
  "STARTPOINT",
  "STRCMP",
  "STR_TO_DATE",
  "ST_AREA",
  "ST_ASBINARY",
  "ST_ASGEOJSON",
  "ST_ASTEXT",
  "ST_ASWKB",
  "ST_ASWKT",
  "ST_BUFFER",
  "ST_BUFFER_STRATEGY",
  "ST_CENTROID",
  "ST_CONTAINS",
  "ST_CONVEXHULL",
  "ST_CROSSES",
  "ST_DIFFERENCE",
  "ST_DIMENSION",
  "ST_DISJOINT",
  "ST_DISTANCE",
  "ST_DISTANCE_SPHERE",
  "ST_ENDPOINT",
  "ST_ENVELOPE",
  "ST_EQUALS",
  "ST_EXTERIORRING",
  "ST_GEOHASH",
  "ST_GEOMCOLLFROMTEXT",
  "ST_GEOMCOLLFROMTXT",
  "ST_GEOMCOLLFROMWKB",
  "ST_GEOMETRYCOLLECTIONFROMTEXT",
  "ST_GEOMETRYCOLLECTIONFROMWKB",
  "ST_GEOMETRYFROMTEXT",
  "ST_GEOMETRYFROMWKB",
  "ST_GEOMETRYN",
  "ST_GEOMETRYTYPE",
  "ST_GEOMFROMGEOJSON",
  "ST_GEOMFROMTEXT",
  "ST_GEOMFROMWKB",
  "ST_INTERIORRINGN",
  "ST_INTERSECTS",
  "ST_INTERSECTION",
  "ST_ISCLOSED",
  "ST_ISEMPTY",
  "ST_ISSIMPLE",
  "ST_ISVALID",
  "ST_LATFROMGEOHASH",
  "ST_LENGTH",
  "ST_LINEFROMTEXT",
  "ST_LINEFROMWKB",
  "ST_LINESTRINGFROMTEXT",
  "ST_LINESTRINGFROMWKB",
  "ST_LONGFROMGEOHASH",
  "ST_MAKEENVELOPE",
  "ST_MLINEFROMTEXT",
  "ST_MLINEFROMWKB",
  "ST_MPOINTFROMTEXT",
  "ST_MPOINTFROMWKB",
  "ST_MPOLYFROMTEXT",
  "ST_MPOLYFROMWKB",
  "ST_MULTILINESTRINGFROMTEXT",
  "ST_MULTILINESTRINGFROMWKB",
  "ST_MULTIPOINTFROMTEXT",
  "ST_MULTIPOINTFROMWKB",
  "ST_MULTIPOLYGONFROMTEXT",
  "ST_MULTIPOLYGONFROMWKB",
  "ST_NUMGEOMETRIES",
  "ST_NUMINTERIORRING",
  "ST_NUMINTERIORRINGS",
  "ST_NUMPOINTS",
  "ST_OVERLAPS",
  "ST_POINTFROMGEOHASH",
  "ST_POINTFROMTEXT",
  "ST_POINTFROMWKB",
  "ST_POINTN",
  "ST_POLYFROMTEXT",
  "ST_POLYFROMWKB",
  "ST_POLYGONFROMTEXT",
  "ST_POLYGONFROMWKB",
  "ST_SIMPLIFY",
  "ST_SRID",
  "ST_STARTPOINT",
  "ST_SYMDIFFERENCE",
  "ST_TOUCHES",
  "ST_UNION",
  "ST_VALIDATE",
  "ST_WITHIN",
  "ST_X",
  "ST_Y",
  "SUBSTRING_INDEX",
  "SUBTIME",
  "TAN",
  "TIMEDIFF",
  "TIME_FORMAT",
  "TIME_TO_SEC",
  "TOUCHES",
  "TO_BASE64",
  "TO_DAYS",
  "TO_SECONDS",
  "UCASE",
  "UNCOMPRESS",
  "UNCOMPRESSED_LENGTH",
  "UNHEX",
  "UNIX_TIMESTAMP",
  "UPDATEXML",
  "UPPER",
  "UUID",
  "UUID_SHORT",
  "VALIDATE_PASSWORD_STRENGTH",
  "VERSION",
  "WEEKDAY",
  "WEEKOFYEAR",
  "WITHIN",
  "X",
  "Y",
  "YEARWEEK",
  NULL
};

// taken from lex.h (SYM_FN)
static const char *special_mysql_functions[] = {
  "ADDDATE",
  "BIT_AND",
  "BIT_OR",
  "BIT_XOR",
  "CAST",
  "COUNT",
  "CURDATE",
  "CURTIME",
  "DATE_ADD",
  "DATE_SUB",
  "DISTINCT",
  "EXTRACT",
  "GROUP_CONCAT",
  "MAX",
  "MID",
  "MIN",
  "NOW",
  "POSITION",
  "SESSION_USER",
  "STD",
  "STDDEV",
  "STDDEV_POP",
  "STDDEV_SAMP",
  "SUBDATE",
  "SUBSTR",
  "SUBSTRING",
  "SUM",
  "SYSDATE",
  "SYSTEM_USER",
  "TRIM",
  "VARIANCE",
  "VAR_POP",
  "VAR_SAMP",
  NULL
};

// taken from sql_yacc.yy
static const char *other_mysql_functions[] = {
  "CONTAINS",
  "GEOMETRYCOLLECTION",
  "LINESTRING",
  "MULTILINESTRING",
  "MULTIPOINT",
  "MULTIPOLYGON",
  "POINT",
  "POLYGON",

  "STRONGLY",
  "SYSDATE",
  "UTC_TIMESTAMP",
  "TRIM_LEADING",
  "HOUR",

  "REVERSE",
  "USER",
  "CURTIME",
  "CURRENT_USER",
  "INSERT",
  "SECOND",
  "DATE_SUB_INTERVAL",
  "COALESCE",
  "MOD",
  "REPLACE",
  "SUBSTRING",
  "IN",
  "MICROSECOND",
  "POSITION",
  "TRUNCATE",
  "COLLATION",
  "INTERVAL",
  "UTC_DATE",
  "LEFT",
  "TRIM",
  "TIME",
  "QUARTER",
  "SUBDATE",
  "DAY",
  "REPEAT",
  "FORMAT",
  "CURDATE",
  "MINUTE",
  "DATE_ADD_INTERVAL",
  "ASCII",
  "TIMESTAMP_ADD",
  "PASSWORD",
  "CHARSET",
  "MONTH",
  "CHAR",
  "BINARY",
  "RIGHT",
  "DATABASE",
  "DATE",
  "TIMESTAMP",
  "IF",
  "YEAR",
  "ROW_COUNT",
  "EXTRACT",
  "TIMESTAMP_DIFF",
  "UTC_TIME",
  "MY_STRXFRM_PAD_WITH_SPACE",
  "USING",
  "WEEK",
  "WEIGHT_STRING",
  NULL
};

namespace xpl {
namespace mysqld
{
  bool is_native_mysql_function(const std::string &name)
  {
    static boost::unordered_set<std::string> names;
    static struct name_set_init
    {
      name_set_init()
      {
        for (const char **n = native_mysql_functions; *n; ++n)
          names.insert(*n);
        for (const char **n = special_mysql_functions; *n; ++n)
          names.insert(*n);
        for (const char **n = other_mysql_functions; *n; ++n)
          names.insert(*n);
      }
    } name_set_init;
    return names.find(boost::to_upper_copy(name).c_str()) != names.end();
  }
}
}
