init push

This commit is contained in:
oceanbase-admin
2021-05-31 22:56:52 +08:00
commit cea7de1475
7020 changed files with 5689869 additions and 0 deletions

View File

@ -0,0 +1,98 @@
# charset objects used for proxy_parser
set(ob_sql_parser_charset_object_list
ob_ctype_bin.c
ob_ctype_mb.c
ob_ctype_simple.c
ob_ctype_utf8.c
ob_ctype.c
ob_dtoa.c
)
list(TRANSFORM ob_sql_parser_charset_object_list
PREPEND ${PROJECT_SOURCE_DIR}/deps/oblib/src/lib/charset/)
# hash objects used for proxy parser
set(ob_sql_parser_hash_object_list
murmur_hash.cpp
)
list(TRANSFORM ob_sql_parser_hash_object_list
PREPEND ${PROJECT_SOURCE_DIR}/deps/oblib/src/lib/hash_func/)
add_library(ob_sql_parser_base INTERFACE)
target_include_directories(ob_sql_parser_base INTERFACE
${PROJECT_SOURCE_DIR}/deps/oblib/src/common/sql_mode/)
# parser objects for proxy parser
set(ob_inner_sql_parser_object_list
non_reserved_keywords_mysql_mode.c
ob_non_reserved_keywords.c
ob_sql_parser.cpp
parse_malloc.cpp
parse_node.c
parse_node_hash.cpp
sql_parser_base.c
sql_parser_mysql_mode_lex.c
sql_parser_mysql_mode_tab.c
parser_utility.cpp
type_name.c
)
# parser objects for server parser
set(ob_extra_sql_parser_object_list
ob_parser.cpp
parser_proxy_func.cpp
)
ob_set_subtarget(inner_sql_parser
${ob_inner_sql_parser_object_list}
)
ob_set_subtarget(sql_parser_charset
${ob_sql_parser_charset_object_list}
)
ob_set_subtarget(sql_parser_hash
${ob_sql_parser_hash_object_list}
)
ob_set_subtarget(extra_sql_parser
${ob_extra_sql_parser_object_list}
)
# ob_sql_proxy_parser_objects is the static library for proxy, it does not link against observer
add_library(ob_sql_proxy_parser_objects OBJECT
${ob_inner_sql_parser_object_list}
${ob_sql_parser_charset_object_list}
${ob_sql_parser_hash_object_list}
)
# ob_sql_server_parser_object is the static library for observer
add_library(ob_sql_server_parser_objects OBJECT
${ob_inner_sql_parser_object_list}
${ob_extra_sql_parser_object_list})
target_link_libraries(ob_sql_proxy_parser_objects PUBLIC ob_base ob_sql_parser_base)
target_link_libraries(ob_sql_server_parser_objects PUBLIC ob_base)
target_compile_definitions(ob_sql_proxy_parser_objects PUBLIC SQL_PARSER_COMPILATION)
disable_pch(ob_sql_server_parser_objects)
disable_pch(ob_sql_proxy_parser_objects)
add_library(ob_sql_proxy_parser_static
STATIC
EXCLUDE_FROM_ALL)
add_library(ob_sql_server_parser_static
STATIC
EXCLUDE_FROM_ALL)
target_link_libraries(ob_sql_proxy_parser_static
PUBLIC
ob_sql_proxy_parser_objects)
target_link_libraries(ob_sql_server_parser_static
PUBLIC
ob_sql_server_parser_objects)

32
src/sql/parser/gen_parser.sh Executable file
View File

@ -0,0 +1,32 @@
#!/bin/bash
#
# AUTHOR: Zhifeng YANG
# DATE: 2012-10-24
# DESCRIPTION:
#
set +x
CURDIR="$(dirname $(readlink -f "$0"))"
export PATH=$CURDIR/../../../deps/3rd/usr/local/oceanbase/devtools/bin:$PATH
export BISON_PKGDATADIR=$CURDIR/../../../deps/3rd/usr/local/oceanbase/devtools/share/bison
BISON_VERSION=`bison -V| grep 'bison (GNU Bison)'|awk '{ print $4;}'`
NEED_VERSION='2.4.1'
if [ "$BISON_VERSION" != "$NEED_VERSION" ]; then
echo "bison version not match, please use bison-$NEED_VERSION"
exit 1
fi
# generate sql_parser
bison -v -Werror -d ../../../src/sql/parser/sql_parser_mysql_mode.y -o ../../../src/sql/parser/sql_parser_mysql_mode_tab.c
if [ $? -ne 0 ]
then
echo Compile error[$?], abort.
exit 1
fi
flex -Cfa -B -8 -o ../../../src/sql/parser/sql_parser_mysql_mode_lex.c ../../../src/sql/parser/sql_parser_mysql_mode.l ../../../src/sql/parser/sql_parser_mysql_mode_tab.h
./gen_type_name.sh ./ob_item_type.h > type_name.c
sed "/Setup the input buffer state to scan the given bytes/,/}/{/int i/d}" -i sql_parser_mysql_mode_lex.c
sed "/Setup the input buffer state to scan the given bytes/,/}/{/for ( i = 0; i < _yybytes_len; ++i )/d}" -i sql_parser_mysql_mode_lex.c
sed "/Setup the input buffer state to scan the given bytes/,/}/{s/\tbuf\[i\] = yybytes\[i\]/memcpy(buf, yybytes, _yybytes_len)/g}" -i sql_parser_mysql_mode_lex.c

17
src/sql/parser/gen_type_name.sh Executable file
View File

@ -0,0 +1,17 @@
#!/bin/sh
echo '/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/'
echo -e '#include "sql/parser/ob_item_type.h"'
echo -e "const char* get_type_name(int type)\n{"
echo -e "\tswitch(type){"
sed -rn 's/\s*(T_[_A-Z1-9]+)[ =0-9]*,/\tcase \1 : return \"\1\";/p' $1
echo -e '\tdefault:return "Unknown";\n\t}\n}'

View File

@ -0,0 +1,813 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#include <stdio.h>
#include "lib/alloc/alloc_assist.h"
#include "ob_non_reserved_keywords.h"
#include "sql/parser/sql_parser_mysql_mode_tab.h"
static t_node* mysql_none_reserved_keywords_root = NULL;
static t_node* mysql_sql_keywords_in_pl_root = NULL;
/* List of non-reserved keywords */
static const NonReservedKeyword Mysql_none_reserved_keywords[] = {{"access", ACCESS},
{"account", ACCOUNT},
{"action", ACTION},
{"activate", ACTIVATE},
{"active", ACTIVE},
{"adddate", ADDDATE},
{"after", AFTER},
{"against", AGAINST},
{"aggregate", AGGREGATE},
{"algorithm", ALGORITHM},
{"always", ALWAYS},
{"analyse", ANALYSE},
{"any", ANY},
{"approx_count_distinct", APPROX_COUNT_DISTINCT},
{"approx_count_distinct_synopsis", APPROX_COUNT_DISTINCT_SYNOPSIS},
{"approx_count_distinct_synopsis_merge", APPROX_COUNT_DISTINCT_SYNOPSIS_MERGE},
{"archivelog", ARCHIVELOG},
{"ascii", ASCII},
{"at", AT},
{"authors", AUTHORS},
{"auto", AUTO},
{"auto_increment", AUTO_INCREMENT},
{"autoextend_size", AUTOEXTEND_SIZE},
{"availability", AVAILABILITY},
{"avg", AVG},
{"avg_row_length", AVG_ROW_LENGTH},
{"backup", BACKUP},
{"backupset", BACKUPSET},
{"balance", BALANCE},
{"base", BASE},
{"baseline", BASELINE},
{"baseline_id", BASELINE_ID},
{"basic", BASIC},
{"begin", BEGI},
{"binlog", BINLOG},
{"bit", BIT},
{"block", BLOCK},
{"block_size", BLOCK_SIZE},
{"bool", BOOL},
{"boolean", BOOLEAN},
{"bootstrap", BOOTSTRAP},
{"breadth", BREADTH},
{"btree", BTREE},
{"byte", BYTE},
{"buckets", BUCKETS},
{"cache", CACHE},
{"cancel", CANCEL},
{"cascaded", CASCADED},
{"cast", CAST},
{"catalog_name", CATALOG_NAME},
{"chain", CHAIN},
{"changed", CHANGED},
{"charset", CHARSET},
{"checksum", CHECKSUM},
{"checkpoint", CHECKPOINT},
{"chunk", CHUNK},
{"cipher", CIPHER},
{"class_origin", CLASS_ORIGIN},
{"clean", CLEAN},
{"clear", CLEAR},
{"client", CLIENT},
{"close", CLOSE},
{"cluster", CLUSTER},
{"cluster_id", CLUSTER_ID},
{"coalesce", COALESCE},
{"code", CODE},
{"collation", COLLATION},
{"column_format", COLUMN_FORMAT},
{"column_name", COLUMN_NAME},
{"columns", COLUMNS},
{"comment", COMMENT},
{"commit", COMMIT},
{"committed", COMMITTED},
{"compact", COMPACT},
{"completion", COMPLETION},
{"compressed", COMPRESSED},
{"compression", COMPRESSION},
{"concurrent", CONCURRENT},
{"connection", CONNECTION},
{"consistent", CONSISTENT},
{"constraint_catalog", CONSTRAINT_CATALOG},
{"constraint_name", CONSTRAINT_NAME},
{"constraint_schema", CONSTRAINT_SCHEMA},
{"contains", CONTAINS},
{"context", CONTEXT},
{"contributors", CONTRIBUTORS},
{"copy", COPY},
{"count", COUNT},
{"cpu", CPU},
{"create_timestamp", CREATE_TIMESTAMP},
{"cube", CUBE},
{"cume_dist", CUME_DIST},
{"curdate", CURDATE},
{"current", CURRENT},
{"cursor_name", CURSOR_NAME},
{"curtime", CURTIME},
{"ctx_id", CTX_ID},
{"cycle", CYCLE},
{"dag", DAG},
{"data", DATA},
{"database_id", DATABASE_ID},
{"datafile", DATAFILE},
{"data_table_id", DATA_TABLE_ID},
{"date", DATE},
{"date_add", DATE_ADD},
{"date_sub", DATE_SUB},
{"datetime", DATETIME},
{"day", DAY},
{"deallocate", DEALLOCATE},
{"decryption", DECRYPTION},
{"default_auth", DEFAULT_AUTH},
{"definer", DEFINER},
{"delay", DELAY},
{"delay_key_write", DELAY_KEY_WRITE},
{"depth", DEPTH},
{"des_key_file", DES_KEY_FILE},
{"destination", DESTINATION},
{"dense_rank", DENSE_RANK},
{"diagnostics", DIAGNOSTICS},
{"directory", DIRECTORY},
{"disable", DISABLE},
{"discard", DISCARD},
{"disk", DISK},
{"diskgroup", DISKGROUP},
{"do", DO},
{"dump", DUMP},
{"dumpfile", DUMPFILE},
{"duplicate", DUPLICATE},
{"dynamic", DYNAMIC},
{"default_tablegroup", DEFAULT_TABLEGROUP},
{"effective", EFFECTIVE},
{"enable", ENABLE},
{"encryption", ENCRYPTION},
{"end", END},
{"ends", ENDS},
{"engine", ENGINE_},
{"engines", ENGINES},
{"enum", ENUM},
{"entity", ENTITY},
{"error", ERROR_P},
{"error_code", ERROR_CODE},
{"errors", ERRORS},
{"escape", ESCAPE},
{"event", EVENT},
{"events", EVENTS},
{"every", EVERY},
{"except", EXCEPT},
{"exchange", EXCHANGE},
{"execute", EXECUTE},
{"expansion", EXPANSION},
{"expire", EXPIRE},
{"expired", EXPIRED},
{"expire_info", EXPIRE_INFO},
{"export", EXPORT},
{"extended", EXTENDED},
{"extended_noaddr", EXTENDED_NOADDR},
{"extent_size", EXTENT_SIZE},
{"extract", EXTRACT},
{"failover", FAILOVER},
{"fast", FAST},
{"faults", FAULTS},
{"fields", FIELDS},
{"file", FILEX},
{"file_id", FILE_ID},
{"final_count", FINAL_COUNT},
{"first", FIRST},
{"first_value", FIRST_VALUE},
{"fixed", FIXED},
{"flush", FLUSH},
{"follower", FOLLOWER},
{"format", FORMAT},
{"found", FOUND},
{"freeze", FREEZE},
{"frequency", FREQUENCY},
{"frozen", FROZEN},
{"function", FUNCTION},
{"full", FULL},
{"following", FOLLOWING},
{"general", GENERAL},
{"geometry", GEOMETRY},
{"geometrycollection", GEOMETRYCOLLECTION},
{"get_format", GET_FORMAT},
{"global", GLOBAL},
{"global_name", GLOBAL_NAME},
{"grants", GRANTS},
{"grouping", GROUPING},
{"group_concat", GROUP_CONCAT},
{"gts", GTS},
{"handler", HANDLER},
{"hash", HASH},
{"help", HELP},
{"histogram", HISTOGRAM},
{"host", HOST},
{"hosts", HOSTS},
{"hour", HOUR},
{"id", ID},
{"idc", IDC},
{"identified", IDENTIFIED},
{"ignore", IGNORE},
{"ignore_server_ids", IGNORE_SERVER_IDS},
{"import", IMPORT},
{"incr", INCR},
{"incremental", INCREMENTAL},
{"indexes", INDEXES},
{"index_table_id", INDEX_TABLE_ID},
{"info", INFO},
{"initial_size", INITIAL_SIZE},
{"innodb", INNODB},
{"insert_method", INSERT_METHOD},
{"install", INSTALL},
{"instance", INSTANCE},
{"intersect", INTERSECT},
{"invisible", INVISIBLE},
{"invoker", INVOKER},
{"io", IO},
{"io_thread", IO_THREAD},
{"ipc", IPC},
{"isnull", ISNULL},
{"isolate", ISOLATE},
{"isolation", ISOLATION},
{"issuer", ISSUER},
{"job", JOB},
{"json", JSON},
{"key_block_size", KEY_BLOCK_SIZE},
{"key_version", KEY_VERSION},
{"kvcache", KVCACHE},
{"ilogcache", ILOGCACHE},
{"file_id", FILE_ID},
{"lag", LAG},
{"language", LANGUAGE},
{"last", LAST},
{"last_value", LAST_VALUE},
{"lead", LEAD},
{"leader", LEADER},
{"leaves", LEAVES},
{"leak", LEAK},
{"leak_mod", LEAK_MOD},
{"leak_rate", LEAK_RATE},
{"less", LESS},
{"level", LEVEL},
{"linestring", LINESTRING},
{"list", LIST_},
{"listagg", LISTAGG},
{"local", LOCAL},
{"locality", LOCALITY},
{"location", LOCATION},
{"locked", LOCKED},
{"locks", LOCKS},
{"logfile", LOGFILE},
{"logonly_replica_num", LOGONLY_REPLICA_NUM},
{"logs", LOGS},
{"major", MAJOR},
{"manual", MANUAL},
{"master", MASTER},
{"master_auto_position", MASTER_AUTO_POSITION},
{"master_connect_retry", MASTER_CONNECT_RETRY},
{"master_delay", MASTER_DELAY},
{"master_heartbeat_period", MASTER_HEARTBEAT_PERIOD},
{"master_host", MASTER_HOST},
{"master_log_file", MASTER_LOG_FILE},
{"master_log_pos", MASTER_LOG_POS},
{"master_password", MASTER_PASSWORD},
{"master_port", MASTER_PORT},
{"master_retry_count", MASTER_RETRY_COUNT},
{"master_server_id", MASTER_SERVER_ID},
{"master_ssl", MASTER_SSL},
{"master_ssl_ca", MASTER_SSL_CA},
{"master_ssl_capath", MASTER_SSL_CAPATH},
{"master_ssl_cert", MASTER_SSL_CERT},
{"master_ssl_cipher", MASTER_SSL_CIPHER},
{"master_ssl_crl", MASTER_SSL_CRL},
{"master_ssl_crlpath", MASTER_SSL_CRLPATH},
{"master_ssl_key", MASTER_SSL_KEY},
{"master_user", MASTER_USER},
{"max", MAX},
{"maximize", MAXIMIZE},
{"max_connections_per_hour", MAX_CONNECTIONS_PER_HOUR},
{"max_cpu", MAX_CPU},
{"max_disk_size", MAX_DISK_SIZE},
{"max_iops", MAX_IOPS},
{"max_memory", MAX_MEMORY},
{"max_queries_per_hour", MAX_QUERIES_PER_HOUR},
{"max_rows", MAX_ROWS},
{"max_session_num", MAX_SESSION_NUM},
{"max_size", MAX_SIZE},
{"max_updates_per_hour", MAX_UPDATES_PER_HOUR},
{"max_used_part_id", MAX_USED_PART_ID},
{"max_user_connections", MAX_USER_CONNECTIONS},
{"medium", MEDIUM},
{"memory", MEMORY},
{"memstore_percent", MEMSTORE_PERCENT},
{"memtable", MEMTABLE},
{"merge", MERGE},
{"message_text", MESSAGE_TEXT},
{"meta", META},
{"microsecond", MICROSECOND},
{"migrate", MIGRATE},
{"migration", MIGRATION},
{"min", MIN},
{"min_cpu", MIN_CPU},
{"min_iops", MIN_IOPS},
{"min_memory", MIN_MEMORY},
{"min_rows", MIN_ROWS},
{"minor", MINOR},
{"minute", MINUTE},
{"minus", MINUS},
{"mode", MODE},
{"modify", MODIFY},
{"month", MONTH},
{"move", MOVE},
{"multilinestring", MULTILINESTRING},
{"multipoint", MULTIPOINT},
{"multipolygon", MULTIPOLYGON},
{"mutex", MUTEX},
{"mysql_errno", MYSQL_ERRNO},
{"name", NAME},
{"names", NAMES},
{"national", NATIONAL},
{"nchar", NCHAR},
{"ndb", NDB},
{"ndbcluster", NDBCLUSTER},
{"new", NEW},
{"next", NEXT},
{"no", NO},
{"noarchivelog", NOARCHIVELOG},
{"noaudit", NOAUDIT},
{"no_parallel", NO_PARALLEL},
{"no_rewrite", NO_REWRITE},
{"no_wait", NO_WAIT},
{"nodegroup", NODEGROUP},
{"none", NONE},
{"noparallel", NOPARALLEL},
{"normal", NORMAL},
{"now", NOW},
{"nowait", NOWAIT},
{"nulls", NULLS},
{"number", NUMBER},
{"nvarchar", NVARCHAR},
{"occur", OCCUR},
{"ntile", NTILE},
{"nth_value", NTH_VALUE},
{"of", OF},
{"off", OFF},
{"offset", OFFSET},
{"old_key", OLD_KEY},
{"over", OVER},
{"old_password", OLD_PASSWORD},
{"one", ONE},
{"one_shot", ONE_SHOT},
{"only", ONLY},
{"open", OPEN},
{"options", OPTIONS},
{"orig_default", ORIG_DEFAULT},
{"outline", OUTLINE},
{"owner", OWNER},
{"pack_keys", PACK_KEYS},
{"page", PAGE},
{"parameters", PARAMETERS},
{"parallel", PARALLEL},
{"parser", PARSER},
{"partial", PARTIAL},
{"partition_id", PARTITION_ID},
{"partitioning", PARTITIONING},
{"partitions", PARTITIONS},
{"password", PASSWORD},
{"pause", PAUSE},
{"percent_rank", PERCENT_RANK},
{"performance", PERFORMANCE},
{"phase", PHASE},
{"physical", PHYSICAL},
{"plan", PLAN},
{"planregress", PLANREGRESS},
{"plugin", PLUGIN},
{"plugin_dir", PLUGIN_DIR},
{"plugins", PLUGINS},
{"point", POINT},
{"polygon", POLYGON},
{"pool", POOL},
{"port", PORT},
{"position", POSITION},
{"prepare", PREPARE},
{"preserve", PRESERVE},
{"prev", PREV},
{"primary_cluster_id", PRIMARY_CLUSTER_ID},
{"primary_rootservice_list", PRIMARY_ROOTSERVICE_LIST},
{"primary_zone", PRIMARY_ZONE},
{"privileges", PRIVILEGES},
{"process", PROCESS},
{"processlist", PROCESSLIST},
{"profile", PROFILE},
{"profiles", PROFILES},
{"progressive_merge_num", PROGRESSIVE_MERGE_NUM},
{"protection", PROTECTION},
{"proxy", PROXY},
{"public", PUBLIC},
{"p_entity", P_ENTITY},
{"p_chunk", P_CHUNK},
{"preceding", PRECEDING},
{"pctfree", PCTFREE},
{"ps", PS},
{"quarter", QUARTER},
{"query", QUERY},
{"quick", QUICK},
{"rank", RANK},
{"read_consistency", READ_CONSISTENCY},
{"read_only", READ_ONLY},
{"rebuild", REBUILD},
{"recover", RECOVER},
{"recovery", RECOVERY},
{"recycle", RECYCLE},
{"recyclebin", RECYCLEBIN},
{"redo_buffer_size", REDO_BUFFER_SIZE},
{"redo_transport_options", REDO_TRANSPORT_OPTIONS},
{"redofile", REDOFILE},
{"redundant", REDUNDANT},
{"refresh", REFRESH},
{"region", REGION},
{"relay", RELAY},
{"relay_log_file", RELAY_LOG_FILE},
{"relay_log_pos", RELAY_LOG_POS},
{"relay_thread", RELAY_THREAD},
{"relaylog", RELAYLOG},
{"reload", RELOAD},
{"remove", REMOVE},
{"reorganize", REORGANIZE},
{"repair", REPAIR},
{"repeatable", REPEATABLE},
{"replica", REPLICA},
{"replica_num", REPLICA_NUM},
{"replica_type", REPLICA_TYPE},
{"duplicate_scope", DUPLICATE_SCOPE},
{"replication", REPLICATION},
{"report", REPORT},
{"reset", RESET},
{"resource", RESOURCE},
{"resource_pool_list", RESOURCE_POOL_LIST},
{"respect", RESPECT},
{"restart", RESTART},
{"restore", RESTORE},
{"resume", RESUME},
{"returned_sqlstate", RETURNED_SQLSTATE},
{"returns", RETURNS},
{"reverse", REVERSE},
{"rewrite_merge_version", REWRITE_MERGE_VERSION},
{"rollback", ROLLBACK},
{"rolling", ROLLING},
{"rollup", ROLLUP},
{"root", ROOT},
{"rootservice", ROOTSERVICE},
{"rootservice_list", ROOTSERVICE_LIST},
{"roottable", ROOTTABLE},
{"rotate", ROTATE},
{"routine", ROUTINE},
{"row", ROW},
{"row_count", ROW_COUNT},
{"row_format", ROW_FORMAT},
{"row_number", ROW_NUMBER},
{"rows", ROWS},
{"rtree", RTREE},
{"run", RUN},
{"sample", SAMPLE},
{"savepoint", SAVEPOINT},
{"schedule", SCHEDULE},
{"schema_name", SCHEMA_NAME},
{"scope", SCOPE},
{"second", SECOND},
{"security", SECURITY},
{"seed", SEED},
{"serial", SERIAL},
{"serializable", SERIALIZABLE},
{"server", SERVER},
{"server_ip", SERVER_IP},
{"server_port", SERVER_PORT},
{"server_type", SERVER_TYPE},
{"session", SESSION},
{"session_user", SESSION_USER},
{"statements", STATEMENTS},
{"binding", BINDING},
{"set_master_cluster", SET_MASTER_CLUSTER},
{"set_slave_cluster", SET_SLAVE_CLUSTER},
{"set_tp", SET_TP},
{"share", SHARE},
{"shutdown", SHUTDOWN},
{"signed", SIGNED},
{"simple", SIMPLE},
{"slave", SLAVE},
{"size", SIZE},
{"slow", SLOW},
{"slot_idx", SLOT_IDX},
{"snapshot", SNAPSHOT},
{"socket", SOCKET},
{"some", SOME},
{"soname", SONAME},
{"sounds", SOUNDS},
{"source", SOURCE},
{"spfile", SPFILE},
{"split", SPLIT},
{"sql_after_gtids", SQL_AFTER_GTIDS},
{"sql_after_mts_gaps", SQL_AFTER_MTS_GAPS},
{"sql_before_gtids", SQL_BEFORE_GTIDS},
{"sql_buffer_result", SQL_BUFFER_RESULT},
{"sql_cache", SQL_CACHE},
{"sql_id", SQL_ID},
{"sql_no_cache", SQL_NO_CACHE},
{"sql_thread", SQL_THREAD},
{"sql_tsi_day", SQL_TSI_DAY},
{"sql_tsi_hour", SQL_TSI_HOUR},
{"sql_tsi_minute", SQL_TSI_MINUTE},
{"sql_tsi_month", SQL_TSI_MONTH},
{"sql_tsi_quarter", SQL_TSI_QUARTER},
{"sql_tsi_second", SQL_TSI_SECOND},
{"sql_tsi_week", SQL_TSI_WEEK},
{"sql_tsi_year", SQL_TSI_YEAR},
{"standby", STANDBY},
{"start", START},
{"starts", STARTS},
{"stat", STAT},
{"stats_auto_recalc", STATS_AUTO_RECALC},
{"stats_persistent", STATS_PERSISTENT},
{"stats_sample_pages", STATS_SAMPLE_PAGES},
{"status", STATUS},
{"std", STD},
{"stddev", STDDEV},
{"stddev_pop", STDDEV_POP},
{"stddev_samp", STDDEV_SAMP},
{"stop", STOP},
{"storage", STORAGE},
{"storage_format_version", STORAGE_FORMAT_VERSION},
{"storage_format_work_version", STORAGE_FORMAT_WORK_VERSION},
{"storing", STORING},
{"string", STRING},
{"strong", STRONG},
{"subclass_origin", SUBCLASS_ORIGIN},
{"subdate", SUBDATE},
{"subject", SUBJECT},
{"subpartition", SUBPARTITION},
{"subpartitions", SUBPARTITIONS},
{"substr", SUBSTR},
{"substring", SUBSTRING},
{"sum", SUM},
{"super", SUPER},
{"suspend", SUSPEND},
{"successful", SUCCESSFUL},
{"synchronization", SYNCHRONIZATION},
{"sysdate", SYSDATE},
{"system", SYSTEM},
{"system_user", SYSTEM_USER},
{"synonym", SYNONYM},
{"swaps", SWAPS},
{"switch", SWITCH},
{"switches", SWITCHES},
{"switchover", SWITCHOVER},
{"table_checksum", TABLE_CHECKSUM},
{"table_mode", TABLE_MODE},
{"table_id", TABLE_ID},
{"table_name", TABLE_NAME},
{"tablegroup", TABLEGROUP},
{"tablegroups", TABLEGROUPS},
{"tablegroup_id", TABLEGROUP_ID},
{"tables", TABLES},
{"tablespace", TABLESPACE},
{"tablet", TABLET},
{"tablet_max_size", TABLET_MAX_SIZE},
{"task", TASK},
{"template", TEMPLATE},
{"temporary", TEMPORARY},
{"temptable", TEMPTABLE},
{"tenant", TENANT},
{"tenant_id", TENANT_ID},
{"text", TEXT},
{"than", THAN},
{"time", TIME},
{"timestamp", TIMESTAMP},
{"timestampadd", TIMESTAMPADD},
{"timestampdiff", TIMESTAMPDIFF},
{"tablet_size", TABLET_SIZE},
{"tp_name", TP_NAME},
{"tp_no", TP_NO},
{"trace", TRACE},
{"traditional", TRADITIONAL},
{"transaction", TRANSACTION},
{"trigger", TRIGGER},
{"triggers", TRIGGERS},
{"trim", TRIM},
{"truncate", TRUNCATE},
{"type", TYPE},
{"types", TYPES},
{"uncommitted", UNCOMMITTED},
{"undefined", UNDEFINED},
{"undo_buffer_size", UNDO_BUFFER_SIZE},
{"undofile", UNDOFILE},
{"unicode", UNICODE},
{"uninstall", UNINSTALL},
{"unit", UNIT},
{"unit_num", UNIT_NUM},
{"unknown", UNKNOWN},
{"unlocked", UNLOCKED},
{"until", UNTIL},
{"unusual", UNUSUAL},
{"upgrade", UPGRADE},
{"use_bloom_filter", USE_BLOOM_FILTER},
{"use_frm", USE_FRM},
{"user", USER},
{"user_resources", USER_RESOURCES},
{"unbounded", UNBOUNDED},
{"valid", VALID},
{"validate", VALIDATE},
{"value", VALUE},
{"variance", VARIANCE},
{"variables", VARIABLES},
{"var_pop", VAR_POP},
{"var_samp", VAR_SAMP},
{"verbose", VERBOSE},
{"verify", VERIFY},
{"materialized", MATERIALIZED},
{"validate", VALIDATE},
{"view", VIEW},
{"virtual_column_id", VIRTUAL_COLUMN_ID},
{"visible", VISIBLE},
{"wait", WAIT},
{"warnings", WARNINGS},
{"weak", WEAK},
{"week", WEEK},
{"weight_string", WEIGHT_STRING},
{"whenever", WHENEVER},
{"window", WINDOW},
{"work", WORK},
{"wrapper", WRAPPER},
{"x509", X509},
{"xa", XA},
{"xml", XML},
{"year", YEAR},
{"zone", ZONE},
{"zone_list", ZONE_LIST},
{"time_zone_info", TIME_ZONE_INFO},
{"zone_type", ZONE_TYPE},
{"audit", AUDIT},
{"PL", PL},
{"remote_oss", REMOTE_OSS},
{"throttle", THROTTLE},
{"priority", PRIORITY},
{"rt", RT},
{"network", NETWORK},
{"logical_reads", LOGICAL_READS},
{"queue_time", QUEUE_TIME},
{"obsolete", OBSOLETE}};
/** https://dev.mysql.com/doc/refman/5.7/en/sql-syntax-prepared-statements.html
ALTER TABLE
ALTER USER
ANALYZE TABLE
CACHE INDEX
CALL
CHANGE MASTER
CHECKSUM {TABLE | TABLES}
COMMIT
{CREATE | DROP} INDEX
{CREATE | RENAME | DROP} DATABASE
{CREATE | DROP} TABLE
{CREATE | RENAME | DROP} USER
{CREATE | DROP} VIEW
DELETE
DO
FLUSH {TABLE | TABLES | TABLES WITH READ LOCK | HOSTS | PRIVILEGES
| LOGS | STATUS | MASTER | SLAVE | DES_KEY_FILE | USER_RESOURCES}
GRANT
INSERT
INSTALL PLUGIN
KILL
\LOAD INDEX INTO CACHE
OPTIMIZE TABLE
RENAME TABLE
REPAIR TABLE
REPLACE
RESET {MASTER | SLAVE | QUERY CACHE}
REVOKE
SELECT
SET
SHOW {WARNINGS | ERRORS}
SHOW BINLOG EVENTS
SHOW CREATE {PROCEDURE | FUNCTION | EVENT | TABLE | VIEW}
SHOW {MASTER | BINARY} LOGS
SHOW {MASTER | SLAVE} STATUS
SLAVE {START | STOP}
TRUNCATE TABLE
UNINSTALL PLUGIN
UPDATE
*/
static const NonReservedKeyword Mysql_sql_keywords_in_pl[] = {
{"alter", ALTER},
{"analyze", ANALYZE},
{"binary", BINARY},
{"binlog", BINLOG},
{"cache", CACHE},
{"call", CALL},
{"change", CHANGE},
{"checksum", CHECKSUM},
{"commit", COMMIT},
{"create", CREATE},
{"database", DATABASE},
{"delete", DELETE},
{"des_key_file", DES_KEY_FILE},
{"do", DO},
{"drop", DROP},
{"errors", ERRORS},
{"event", EVENT},
{"events", EVENTS},
{"flush", FLUSH},
{"function", FUNCTION},
{"grant", GRANT},
{"hosts", HOSTS},
{"index", INDEX},
{"insert", INSERT},
{"install", INSTALL},
{"into", INTO},
{"kill", KILL},
{"load", LOAD},
{"lock", LOCK_},
{"logs", LOGS},
{"master", MASTER},
{"optimize", OPTIMIZE},
{"plugin", PLUGIN},
{"privileges", PRIVILEGES},
{"procedure", PROCEDURE},
{"query", QUERY},
{"read", READ},
{"rename", RENAME},
{"repair", REPAIR},
{"replace", REPLACE},
{"reset", RESET},
{"revoke", REVOKE},
{"select", SELECT},
{"set", SET},
{"show", SHOW},
{"slave", SLAVE},
{"start", START},
{"status", STATUS},
{"stop", STOP},
{"table", TABLE},
{"tables", TABLES},
{"truncate", TRUNCATE},
{"uninstall", UNINSTALL},
{"update", UPDATE},
{"user", USER},
{"user_resources", USER_RESOURCES},
{"view", VIEW},
{"warnings", WARNINGS},
{"with", WITH},
{"prepare", PREPARE},
{"execute", EXECUTE},
{"deallocate", DEALLOCATE},
};
const NonReservedKeyword* mysql_non_reserved_keyword_lookup(const char* word)
{
return find_word(word, mysql_none_reserved_keywords_root, Mysql_none_reserved_keywords);
}
int mysql_sql_reserved_keyword_lookup(const char* word)
{
int ret = -1;
const NonReservedKeyword* res_word = find_word(word, mysql_sql_keywords_in_pl_root, Mysql_sql_keywords_in_pl);
if (NULL != res_word) {
ret = res_word->keyword_type;
}
return ret;
}
// return 0 if succ, return 1 if fail
int create_mysql_trie_tree()
{
int ret = 0;
if (0 != (ret = create_trie_tree(Mysql_none_reserved_keywords,
LENGTH_OF(Mysql_none_reserved_keywords),
&mysql_none_reserved_keywords_root))) {
(void)printf("ERROR create trie tree failed! \n");
} else if (0 !=
(ret = create_trie_tree(
Mysql_sql_keywords_in_pl, LENGTH_OF(Mysql_sql_keywords_in_pl), &mysql_sql_keywords_in_pl_root))) {
(void)printf("ERROR create trie tree failed! \n");
} else { /*do nothing*/
}
return ret;
}
void __attribute__((constructor)) init_mysql_non_reserved_keywords_tree()
{
int ret = 0;
if (0 != (ret = create_mysql_trie_tree())) {
(void)printf("ERROR build mysql_non_reserved_keywords tree failed=>%d", ret);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,71 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef _OB_ITEM_TYPE_STR_H
#define _OB_ITEM_TYPE_STR_H 1
#include "sql/parser/ob_item_type.h"
namespace oceanbase {
namespace sql {
inline const char* ob_aggr_func_str(ObItemType aggr_func)
{
const char* ret = "UNKNOWN_AGGR";
switch (aggr_func) {
case T_FUN_MAX:
ret = "MAX";
break;
case T_FUN_MIN:
ret = "MIN";
break;
case T_FUN_COUNT_SUM:
ret = "COUNT_SUM";
break;
case T_FUN_SUM:
ret = "SUM";
break;
case T_FUN_COUNT:
ret = "COUNT";
break;
case T_FUN_AVG:
ret = "AVG";
break;
case T_FUN_GROUPING:
ret = "GROUPING";
break;
case T_FUN_GROUP_CONCAT:
ret = "GROUP_CONCAT";
break;
case T_FUN_APPROX_COUNT_DISTINCT:
ret = "APPROX_COUNT_DISTINCT";
break;
case T_FUN_APPROX_COUNT_DISTINCT_SYNOPSIS:
ret = "APPROX_COUNT_DISTINCT_SYNOPSIS";
break;
case T_FUN_APPROX_COUNT_DISTINCT_SYNOPSIS_MERGE:
ret = "APPROX_COUNT_DISTINCT_SYNOPSIS_MERGE";
break;
case T_FUN_VARIANCE:
ret = "VARIANCE";
break;
case T_FUN_STDDEV:
ret = "STDDEV";
break;
default:
break;
}
return ret;
}
} // end namespace sql
} // end namespace oceanbase
#endif /* _OB_ITEM_TYPE_STR_H */

View File

@ -0,0 +1,133 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#include "ob_non_reserved_keywords.h"
#include <stdio.h>
#include <ctype.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include "lib/alloc/alloc_assist.h"
#include "sql/parser/sql_parser_mysql_mode_tab.h"
#include "sql/parser/parse_define.h"
int32_t get_next_id(char c)
{
int32_t ch_id = -1;
if (c >= 'A' && c <= 'Z') {
c += 'a' - 'A';
}
if ('_' == c) {
ch_id = 36;
} else if (c >= 'a' && c <= 'z') {
ch_id = c - 'a';
} else if (c >= '0' && c <= '9') {
ch_id = c - '0' + 26;
}
return ch_id;
}
int casesame_cstr(const char* a, const char* b)
{
size_t len1 = strlen(a);
size_t len2 = strlen(b);
return (len1 == len2) && (strncasecmp(a, b, len1) == 0);
}
// return 0 if succ, return 1 if fail
int add_word(t_node* root, const char* str, const int32_t idx)
{
int ret = 0;
t_node* pt = root;
if (OB_UNLIKELY(NULL == root)) {
ret = 1;
printf("ERROR root is NULL! \n");
} else if (OB_UNLIKELY(NULL == str)) {
ret = 1;
printf("ERROR word str is NULL! \n");
} else if (OB_UNLIKELY(idx < 0)) {
printf("ERROR invalid idx:%d\n", idx);
} else {
for (; '\0' != *str && 0 == ret; ++str) {
int32_t ch_id = get_next_id(*str);
if (ch_id >= 0 && NULL == pt->next[ch_id]) {
t_node* new_node = (t_node*)calloc(1, sizeof(t_node));
if (OB_UNLIKELY(NULL == new_node)) {
ret = 1;
printf("ERROR malloc memory failed! \n");
} else {
new_node->idx = -1;
pt->next[ch_id] = new_node;
}
}
if (OB_LIKELY(0 == ret)) {
if (OB_LIKELY(ch_id >= 0)) {
pt = pt->next[ch_id];
} else {
printf("ERROR ob_non_reserved_keywords.c: wrong index! \n");
ret = 1;
}
}
}
}
if (0 == ret) {
pt->idx = idx;
}
return ret;
}
const NonReservedKeyword* find_word(const char* word, const t_node* root, const NonReservedKeyword* words)
{
const NonReservedKeyword* res_word = NULL;
const t_node* pt = root;
if (OB_UNLIKELY(NULL == word)) {
// do nothing
} else {
for (; *word != '\0' && NULL != pt; ++word) {
char c = *word;
int32_t ch_id = get_next_id(c);
if (ch_id < 0) {
pt = NULL;
} else {
pt = pt->next[ch_id];
}
}
}
if (OB_LIKELY(NULL != pt && -1 != pt->idx)) {
res_word = &words[pt->idx];
}
return res_word;
}
// return 0 if succ, return 1 if fail
int create_trie_tree(const NonReservedKeyword* words, int32_t count, t_node** root)
{
int ret = 0;
if (OB_UNLIKELY(NULL == root)) {
(void)printf("ERROR invalid root! \n");
ret = 1;
} else {
*root = (t_node*)calloc(1, sizeof(t_node));
if (OB_UNLIKELY(NULL == *root)) {
(void)printf("ERROR malloc memory failed! \n");
ret = 1;
} else {
(*root)->idx = -1;
int32_t i = 0;
for (; 0 == ret && i < count; ++i) {
ret = add_word(*root, words[i].keyword_name, i);
}
}
}
return ret;
}

View File

@ -0,0 +1,54 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef OCEANBASE_SQL_PARSER_NON_RESERVED_KEYWORDS_
#define OCEANBASE_SQL_PARSER_NON_RESERVED_KEYWORDS_
#include <stdint.h>
#define LENGTH_OF(arr) (sizeof(arr) / sizeof(arr[0]))
#define CHAR_LEN 37 // sum of A-Z,0-9,_
typedef struct _NonReservedKeyword {
const char* keyword_name;
int keyword_type;
} NonReservedKeyword;
typedef NonReservedKeyword ReservedKeyword;
typedef struct trie_node {
int32_t idx;
struct trie_node* next[CHAR_LEN];
} t_node;
extern const NonReservedKeyword* mysql_non_reserved_keyword_lookup(const char* word);
extern const NonReservedKeyword* oracle_non_reserved_keyword_lookup(const char* word);
extern int mysql_sql_reserved_keyword_lookup(const char* word);
extern int oracle_sql_reserved_keyword_lookup(const char* word);
extern const ReservedKeyword* oracle_pl_reserved_keyword_lookup(const char* word);
extern const ReservedKeyword* oracle_reserved_keyword_lookup(const char* word);
#ifdef __cplusplus
extern "C" {
#endif
extern int verify_non_reserved_keywords_order();
extern int create_trie_tree(const NonReservedKeyword* words, int32_t count, t_node** root);
extern int add_word(t_node* root, const char* str, const int32_t idx);
extern const NonReservedKeyword* find_word(const char* word, const t_node* root, const NonReservedKeyword* words);
extern int32_t get_next_id(char c);
extern int casesame_cstr(const char* a, const char* b);
#ifdef __cplusplus
}
#endif
#endif /*OCEANBASE_SQL_PARSER_NON_RESERVED_KEYWORDS_*/

View File

@ -0,0 +1,473 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#define USING_LOG_PREFIX SQL_PARSER
#include "ob_parser.h"
#include "lib/oblog/ob_log.h"
#include "common/sql_mode/ob_sql_mode_utils.h"
#include "parse_malloc.h"
#include "parse_node.h"
#include "ob_sql_parser.h"
#include "share/ob_define.h"
using namespace oceanbase::sql;
using namespace oceanbase::common;
ObParser::ObParser(common::ObIAllocator& allocator, ObSQLMode mode, ObCollationType conn_collation)
: allocator_(&allocator), sql_mode_(mode), connection_collation_(conn_collation)
{}
ObParser::~ObParser()
{}
#define ISSPACE(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || (c) == '\t' || (c) == '\f' || (c) == '\v')
bool ObParser::is_pl_stmt(const ObString& stmt, bool* is_create_func)
{
UNUSED(stmt);
UNUSED(is_create_func);
return false;
}
bool ObParser::is_single_stmt(const ObString& stmt)
{
int64_t count = 0;
int64_t end_trim_offset = stmt.length();
while (end_trim_offset > 0 && ISSPACE(stmt[end_trim_offset - 1])) {
end_trim_offset--;
}
for (int64_t i = 0; i < end_trim_offset; i++) {
if (';' == stmt[i]) {
count++;
}
}
return (0 == count || (1 == count && stmt[end_trim_offset - 1] == ';'));
}
// In multi-stmt mode(delimiter #) eg: create t1; create t2; create t3
// in the case of is_ret_first_stmt(false), queries will return the following stmts:
// queries[0]: create t1; create t2; create t3;
// queries[1]: create t2; create t3;
// queries[2]: create t3;
// in the case of is_ret_first_stmt(true) and it will return one element
// queries[0]: create t1;
// Actually, sql executor only executes the first stmt(create t1) and ignore the others
// even though try to execute stmts like 'create t1; create t2; create t3;'
int ObParser::split_multiple_stmt(
const ObString& stmt, ObIArray<ObString>& queries, ObMPParseStat& parse_stat, bool is_ret_first_stmt)
{
int ret = OB_SUCCESS;
if (is_single_stmt(stmt) || is_pl_stmt(stmt)) {
ObString query(stmt.length(), stmt.ptr());
ret = queries.push_back(query);
} else {
ParseResult parse_result;
ParseMode parse_mode = MULTI_MODE;
int64_t offset = 0;
int64_t remain = stmt.length();
parse_stat.reset();
while (remain > 0 && ISSPACE(stmt[remain - 1])) {
--remain;
}
if (remain > 0 && '\0' == stmt[remain - 1]) {
--remain;
}
while (remain > 0 && ISSPACE(stmt[remain - 1])) {
--remain;
}
if (OB_UNLIKELY(0 >= remain)) {
ObString part;
ret = queries.push_back(part);
}
int tmp_ret = OB_SUCCESS;
while (remain > 0 && OB_SUCC(ret) && !parse_stat.parse_fail_) {
ObArenaAllocator allocator(CURRENT_CONTEXT.get_malloc_allocator());
allocator.set_label("SplitMultiStmt");
ObIAllocator* bak_allocator = allocator_;
allocator_ = &allocator;
ObString part(remain, stmt.ptr() + offset);
if (OB_SUCC(tmp_ret = parse(part, parse_result, parse_mode))) {
// length: length of the remainer statements
// size: length of the single statement
int32_t single_stmt_length = parse_result.end_col_;
if ((!is_ret_first_stmt) && (';' == *(stmt.ptr() + offset + parse_result.end_col_ - 1))) {
--single_stmt_length;
}
if (is_ret_first_stmt) {
ObString first_query(single_stmt_length, stmt.ptr());
ret = queries.push_back(first_query);
break; // only return the first stmt, so ignore the remaining stmts
} else {
ObString query(single_stmt_length, static_cast<int32_t>(remain), stmt.ptr() + offset);
ret = queries.push_back(query);
}
remain -= parse_result.end_col_;
offset += parse_result.end_col_;
if (remain < 0 || offset > stmt.length()) {
LOG_ERROR("split_multiple_stmt data error", K(remain), K(offset), K(stmt.length()), K(ret));
}
} else {
int32_t single_stmt_length = parse_result.end_col_;
if (';' == *(stmt.ptr() + offset + parse_result.end_col_ - 1)) {
--single_stmt_length;
}
ObString query(single_stmt_length, static_cast<int32_t>(remain), stmt.ptr() + offset);
ret = queries.push_back(query);
if (OB_SUCCESS == ret) {
parse_stat.parse_fail_ = true;
parse_stat.fail_query_idx_ = queries.count() - 1;
parse_stat.fail_ret_ = tmp_ret;
}
LOG_WARN("fail parse multi part", K(part), K(stmt), K(ret));
}
allocator_ = bak_allocator;
}
}
return ret;
}
int ObParser::parse_sql(const ObString& stmt, ParseResult& parse_result)
{
int ret = OB_SUCCESS;
ObSQLParser sql_parser(*(ObIAllocator*)(parse_result.malloc_pool_), sql_mode_);
if (OB_FAIL(sql_parser.parse(stmt.ptr(), stmt.length(), parse_result))) {
LOG_INFO("failed to parse stmt as sql", K(stmt), K(ret));
} else if (parse_result.is_dynamic_sql_) {
memmove(parse_result.no_param_sql_ + parse_result.no_param_sql_len_,
parse_result.input_sql_ + parse_result.pl_parse_info_.last_pl_symbol_pos_,
parse_result.input_sql_len_ - parse_result.pl_parse_info_.last_pl_symbol_pos_);
parse_result.no_param_sql_len_ += parse_result.input_sql_len_ - parse_result.pl_parse_info_.last_pl_symbol_pos_;
} else { /*do nothing*/
}
if (parse_result.is_fp_ || parse_result.is_multi_query_) {
if (OB_FAIL(ret)) {
LOG_WARN("failed to fast parameterize", K(stmt), K(ret));
}
}
if (OB_FAIL(ret)) {
auto err_charge_sql_mode = lib::is_oracle_mode();
LOG_WARN("failed to parse the statement",
K(stmt),
K(parse_result.is_fp_),
K(parse_result.is_multi_query_),
K(parse_result.yyscan_info_),
K(parse_result.result_tree_),
K(parse_result.malloc_pool_),
"message",
parse_result.error_msg_,
"start_col",
parse_result.start_col_,
"end_col",
parse_result.end_col_,
K(parse_result.line_),
K(parse_result.yycolumn_),
K(parse_result.yylineno_),
K(parse_result.extra_errno_),
K(err_charge_sql_mode),
K(sql_mode_),
K(parse_result.sql_mode_),
K(parse_result.may_bool_value_),
K(ret));
static const int32_t max_error_length = 80;
int32_t error_length = std::min(stmt.length() - (parse_result.start_col_ - 1), max_error_length);
if (OB_ERR_PARSE_SQL == ret) {
LOG_USER_ERROR(OB_ERR_PARSE_SQL,
ob_errpkt_strerror(OB_ERR_PARSER_SYNTAX, false),
error_length,
stmt.ptr() + parse_result.start_col_ - 1,
parse_result.line_ + 1);
} else {
// other errors handle outer side.
}
}
return ret;
}
int ObParser::parse(
const ObString& query, ParseResult& parse_result, ParseMode parse_mode, const bool is_batched_multi_stmt_split_on)
{
int ret = OB_SUCCESS;
int64_t len = query.length();
while (len > 0 && ISSPACE(query[len - 1])) {
--len;
}
if (MULTI_MODE != parse_mode) {
if (len > 0 && '\0' == query[len - 1]) {
--len;
}
while (len > 0 && ISSPACE(query[len - 1])) {
--len;
}
}
const ObString stmt(len, query.ptr());
parse_reset(&parse_result);
parse_result.is_fp_ = (FP_MODE == parse_mode || FP_PARAMERIZE_AND_FILTER_HINT_MODE == parse_mode ||
FP_NO_PARAMERIZE_AND_FILTER_HINT_MODE == parse_mode);
parse_result.is_multi_query_ = (MULTI_MODE == parse_mode);
parse_result.malloc_pool_ = allocator_;
parse_result.sql_mode_ = sql_mode_;
parse_result.is_ignore_hint_ =
(FP_PARAMERIZE_AND_FILTER_HINT_MODE == parse_mode || FP_NO_PARAMERIZE_AND_FILTER_HINT_MODE == parse_mode);
parse_result.is_ignore_token_ = false;
parse_result.need_parameterize_ = (FP_MODE == parse_mode || FP_PARAMERIZE_AND_FILTER_HINT_MODE == parse_mode);
parse_result.pl_parse_info_.is_pl_parse_ = false;
parse_result.minus_ctx_.has_minus_ = false;
parse_result.minus_ctx_.pos_ = -1;
parse_result.minus_ctx_.raw_sql_offset_ = -1;
parse_result.is_for_trigger_ = (TRIGGER_MODE == parse_mode);
parse_result.is_dynamic_sql_ = (DYNAMIC_SQL_MODE == parse_mode);
parse_result.is_dbms_sql_ = (DBMS_SQL_MODE == parse_mode);
parse_result.is_batched_multi_enabled_split_ = is_batched_multi_stmt_split_on;
parse_result.charset_info_ = ObCharset::get_charset(connection_collation_);
parse_result.is_not_utf8_connection_ =
ObCharset::is_valid_collation(connection_collation_)
? (ObCharset::charset_type_by_coll(connection_collation_) != CHARSET_UTF8MB4)
: false;
if (parse_result.is_fp_ || parse_result.is_dynamic_sql_) {
int64_t new_length = parse_result.is_fp_ ? stmt.length() + 1 : stmt.length() * 2;
char* buf = (char*)parse_malloc(new_length, parse_result.malloc_pool_);
if (OB_UNLIKELY(NULL == buf)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_ERROR("no memory for parser");
} else {
parse_result.param_nodes_ = NULL;
parse_result.tail_param_node_ = NULL;
parse_result.no_param_sql_ = buf;
parse_result.no_param_sql_buf_len_ = stmt.length() + 1;
}
}
if (OB_SUCC(ret) && OB_ISNULL(parse_result.charset_info_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("charset info is null", K(ret), "connection charset", ObCharset::charset_name(connection_collation_));
} else {
LOG_DEBUG("check parse_result param", "connection charset", ObCharset::charset_name(connection_collation_));
}
if (OB_SUCC(ret)) {
if (OB_FAIL(parse_sql(stmt, parse_result))) {
LOG_WARN("failed to parse stmt as sql", K(stmt), K(parse_mode), K(ret));
}
}
return ret;
}
int ObParser::prepare_parse(const ObString& query, void* ns, ParseResult& parse_result)
{
int ret = OB_SUCCESS;
int64_t len = query.length();
while (len > 0 && ISSPACE(query[len - 1])) {
--len;
}
if (len > 0 && '\0' == query[len - 1]) {
--len;
}
while (len > 0 && ISSPACE(query[len - 1])) {
--len;
}
const ObString stmt(len, query.ptr());
memset(&parse_result, 0, sizeof(ParseResult));
parse_result.pl_parse_info_.pl_ns_ = ns;
parse_result.malloc_pool_ = allocator_;
parse_result.sql_mode_ = sql_mode_;
parse_result.pl_parse_info_.is_pl_parse_ = true;
parse_result.pl_parse_info_.is_pl_parse_expr_ = false;
char* buf = (char*)parse_malloc(stmt.length() * 2, parse_result.malloc_pool_);
if (OB_UNLIKELY(NULL == buf)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("no memory for parser");
} else {
parse_result.param_nodes_ = NULL;
parse_result.tail_param_node_ = NULL;
parse_result.no_param_sql_ = buf;
parse_result.no_param_sql_buf_len_ = stmt.length() * 2;
parse_result.may_bool_value_ = false;
}
if (OB_SUCC(ret)) {
ObSQLParser sql_parser(*(ObIAllocator*)(parse_result.malloc_pool_), sql_mode_);
if (OB_FAIL(sql_parser.parse(stmt.ptr(), stmt.length(), parse_result))) {
LOG_WARN("failed to parse the statement",
K(parse_result.yyscan_info_),
K(parse_result.result_tree_),
K(parse_result.malloc_pool_),
"message",
parse_result.error_msg_,
"start_col",
parse_result.start_col_,
"end_col",
parse_result.end_col_,
K(parse_result.line_),
K(parse_result.yycolumn_),
K(parse_result.yylineno_),
K(parse_result.extra_errno_));
static const int32_t max_error_length = 80;
int32_t error_length = std::min(stmt.length() - (parse_result.start_col_ - 1), max_error_length);
if (OB_ERR_PARSE_SQL == ret) {
LOG_USER_ERROR(OB_ERR_PARSE_SQL,
ob_errpkt_strerror(OB_ERR_PARSER_SYNTAX, false),
error_length,
stmt.ptr() + parse_result.start_col_ - 1,
parse_result.line_ + 1);
} else {
// other errors handle outer side.
}
} else {
memmove(parse_result.no_param_sql_ + parse_result.no_param_sql_len_,
parse_result.input_sql_ + parse_result.pl_parse_info_.last_pl_symbol_pos_,
parse_result.input_sql_len_ - parse_result.pl_parse_info_.last_pl_symbol_pos_);
parse_result.no_param_sql_len_ += parse_result.input_sql_len_ - parse_result.pl_parse_info_.last_pl_symbol_pos_;
}
}
return ret;
}
int ObParser::pre_parse(const common::ObString& stmt, PreParseResult& res)
{
int ret = OB_SUCCESS;
// /*tracd_id=xxx*/
int64_t len = stmt.length();
if (len <= 13) {
// do_nothing
} else {
int32_t pos = 0;
const char* ptr = stmt.ptr();
while (pos < len && is_space(ptr[pos])) {
pos++;
};
if (pos + 2 < len && ptr[pos++] == '/' && ptr[pos++] == '*') { // start with '/*'
char expect_char = 't';
bool find_trace = false;
while (!find_trace && pos < len) {
if (pos < len && ptr[pos] == '*') {
expect_char = 't';
if (++pos < len && ptr[pos] == '/') {
break;
}
}
if (pos >= len) {
break;
} else if (ptr[pos] == expect_char ||
(expect_char != '_' && expect_char != '=' && ptr[pos] == expect_char - 32)) {
switch (expect_char) {
case 't': {
expect_char = 'r';
break;
}
case 'r': {
expect_char = 'a';
break;
}
case 'a': {
expect_char = 'c';
break;
}
case 'c': {
expect_char = 'e';
break;
}
case 'e': {
expect_char = '_';
break;
}
case '_': {
expect_char = 'i';
break;
}
case 'i': {
expect_char = 'd';
break;
}
case 'd': {
expect_char = '=';
break;
}
case '=': {
find_trace = true;
break;
}
default: {
// do nothing
}
}
} else {
expect_char = 't';
}
pos++;
}
if (find_trace) {
scan_trace_id(ptr, len, pos, res.trace_id_);
}
} else { // not start with '/*'
// do nothing
}
}
return ret;
}
int ObParser::scan_trace_id(const char* ptr, int64_t len, int32_t& pos, ObString& trace_id)
{
int ret = OB_SUCCESS;
trace_id.reset();
int32_t start = pos;
int32_t end = pos;
while (pos < len && !is_trace_id_end(ptr[pos])) {
pos++;
}
end = pos;
if (start < end) {
while (pos < len) {
if (pos < len && ptr[pos] == '*') {
if (++pos < len && ptr[pos] == '/') {
int32_t trace_id_len = std::min(static_cast<int32_t>(OB_MAX_TRACE_ID_BUFFER_SIZE), end - start);
trace_id.assign_ptr(ptr + start, trace_id_len);
break;
}
} else {
pos++;
}
}
}
return ret;
}
bool ObParser::is_space(char ch)
{
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\f';
}
bool ObParser::is_trace_id_end(char ch)
{
return is_space(ch) || ch == ',' || ch == '*';
}
void ObParser::free_result(ParseResult& parse_result)
{
UNUSED(parse_result);
// destroy_tree(parse_result.result_tree_);
// parse_terminate(&parse_result);
// parse_result.yyscan_info_ = NULL;
}

102
src/sql/parser/ob_parser.h Normal file
View File

@ -0,0 +1,102 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef _OB_PARSER_H
#define _OB_PARSER_H 1
#include "sql/parser/parse_node.h"
#include "sql/parser/parse_define.h"
#include "lib/allocator/ob_allocator.h"
#include "lib/container/ob_iarray.h"
#include "lib/string/ob_string.h"
#include "lib/charset/ob_charset.h"
#include "sql/parser/ob_parser_utils.h"
namespace oceanbase {
namespace sql {
struct ObMPParseStat {
public:
ObMPParseStat() : parse_fail_(false), fail_ret_(common::OB_SUCCESS), fail_query_idx_(-1)
{}
void reset()
{
parse_fail_ = false;
fail_ret_ = common::OB_SUCCESS;
fail_query_idx_ = -1;
}
bool parse_fail_;
int fail_ret_;
int64_t fail_query_idx_;
};
struct PreParseResult {
common::ObString trace_id_;
};
class ObParser {
public:
explicit ObParser(common::ObIAllocator& allocator, ObSQLMode mode,
common::ObCollationType conn_collation = common::CS_TYPE_UTF8MB4_GENERAL_CI);
virtual ~ObParser();
/// @param queries Note that all three members of ObString is valid, size() is the length
/// of the single statement, length() is the length of remainer statements
static bool is_pl_stmt(const common::ObString& stmt, bool* is_create_func = NULL);
bool is_single_stmt(const common::ObString& stmt);
int split_multiple_stmt(const common::ObString& stmt, common::ObIArray<common::ObString>& queries,
ObMPParseStat& parse_fail, bool is_ret_first_stmt = false);
int parse_sql(const common::ObString& stmt, ParseResult& parse_result);
virtual int parse(const common::ObString& stmt, ParseResult& parse_result, ParseMode mode = STD_MODE,
const bool is_batched_multi_stmt_split_on = false);
virtual void free_result(ParseResult& parse_result);
/**
* @brief The parse interface for prepare
* @param [in] query - To be parsed statement
* @param [in] ns - External namespace
* @param [out] parse_result - parse result
* @retval OB_SUCCESS execute success
* @retval OB_SOME_ERROR special errno need to handle
*
* Compared with general prepare, the external name space is passed in and the redundant process
* that this path will not go to is simplified. The main idea is that in the process of parser,
* whenever you encounter a variable in sql, try to find it in the pl namespace. If you can find
* it, copy the SQL statement before this variable and rewrite this variable as question mark,Also
* record this variable.At the same time, all objects (tables, views, functions) encountered are
* also recorded.
*
*/
int prepare_parse(const common::ObString& query, void* ns, ParseResult& parse_result);
static int pre_parse(const common::ObString& stmt, PreParseResult& res);
private:
static int scan_trace_id(const char* ptr, int64_t len, int32_t& pos, common::ObString& trace_id);
static bool is_trace_id_end(char ch);
static bool is_space(char ch);
// types and constants
private:
// disallow copy
DISALLOW_COPY_AND_ASSIGN(ObParser);
// function members
private:
// data members
common::ObIAllocator* allocator_;
// when sql_mode = "ANSI_QUOTES", Treat " as an identifier quote character
// we don't use it in parser now
ObSQLMode sql_mode_;
common::ObCollationType connection_collation_;
};
} // end namespace sql
} // end namespace oceanbase
#endif /* _OB_PARSER_H */

View File

@ -0,0 +1,139 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef _OB_PARSER_UTILS_H
#define _OB_PARSER_UTILS_H 1
#include "lib/utility/ob_print_utils.h"
#include "sql/parser/parse_node.h"
#include "lib/ob_name_def.h"
const char* get_type_name(int type);
namespace oceanbase {
namespace sql {
inline void databuff_print_stmt_location(char* buf, int64_t buf_len, int64_t& pos, const ObStmtLoc& obj)
{
if (obj.first_column_ > 0 || obj.last_column_ > 0 || obj.first_line_ > 0 || obj.last_line_ > 0) {
J_COMMA();
int first_line = obj.first_line_;
int last_line = obj.last_line_;
int first_column = obj.first_column_;
int last_column = obj.last_column_;
J_KV(K(first_line), K(last_line), K(first_column), K(last_column));
}
}
inline void databuff_print_obj(char* buf, const int64_t buf_len, int64_t& pos, const ParseNode& obj)
{
J_OBJ_START();
J_KV(N_TYPE,
get_type_name(obj.type_),
N_INT_VALUE,
obj.value_,
N_STR_VALUE_LEN,
obj.str_len_,
N_STR_VALUE,
common::ObString(obj.str_len_, obj.str_value_));
databuff_print_stmt_location(buf, buf_len, pos, obj.stmt_loc_);
if (0 < obj.num_child_) {
J_COMMA();
J_NAME(N_CHILDREN);
J_COLON();
J_ARRAY_START();
for (int64_t i = 0; i < obj.num_child_; ++i) {
if (NULL == obj.children_[i]) {
J_EMPTY_OBJ();
} else {
databuff_print_obj(buf, buf_len, pos, *obj.children_[i]);
}
if (i != obj.num_child_ - 1) {
common::databuff_printf(buf, buf_len, pos, ", ");
}
}
J_ARRAY_END();
}
J_OBJ_END();
}
inline void print_indent(char* buf, const int64_t buf_len, int64_t& pos, const int level)
{
for (int i = 0; i < level; ++i) {
common::databuff_printf(buf, buf_len, pos, "\t");
}
}
inline void databuff_simple_print_obj(
char* buf, const int64_t buf_len, const int64_t index, int64_t& pos, const ParseNode* obj, int level)
{
print_indent(buf, buf_len, pos, level);
if (NULL != obj) {
common::databuff_printf(buf,
buf_len,
pos,
"|--[%ld],[%s], str_value_=[%.*s], value=[%ld]\n",
index,
get_type_name(obj->type_),
int32_t(obj->str_len_),
obj->str_value_,
obj->value_);
} else {
common::databuff_printf(buf, buf_len, pos, "|--[%ld]\n", index);
}
for (int64_t i = 0; i < obj->num_child_; ++i) {
if (NULL != obj->children_[i]) {
databuff_simple_print_obj(buf, buf_len, i, pos, obj->children_[i], level + 1);
}
}
}
class ObParserResultTreePrintWrapper {
public:
explicit ObParserResultTreePrintWrapper(const ParseNode& parse_tree) : parse_tree_(parse_tree)
{}
int64_t to_string(char* buf, const int64_t buf_len) const
{
int64_t pos = 0;
common::databuff_printf(buf, buf_len, pos, "\n");
databuff_simple_print_obj(buf, buf_len, 0, pos, &parse_tree_, 0);
return pos;
}
private:
DISALLOW_COPY_AND_ASSIGN(ObParserResultTreePrintWrapper);
private:
const ParseNode& parse_tree_;
};
class ObParserResultPrintWrapper {
public:
explicit ObParserResultPrintWrapper(const ParseNode& parse_tree) : parse_tree_(parse_tree)
{}
int64_t to_string(char* buf, const int64_t buf_len) const
{
int64_t pos = 0;
databuff_print_obj(buf, buf_len, pos, parse_tree_);
return pos;
}
private:
DISALLOW_COPY_AND_ASSIGN(ObParserResultPrintWrapper);
private:
const ParseNode& parse_tree_;
};
} // end namespace sql
} // end namespace oceanbase
#endif /* _OB_PARSER_UTILS_H */

View File

@ -0,0 +1,97 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#define USING_LOG_PREFIX SQL
#include "ob_sql_parser.h"
#include "sql/parser/parse_node.h"
#include "sql/parser/parse_malloc.h"
#include "share/ob_errno.h"
#include "lib/utility/ob_macro_utils.h"
#include "sql/parser/parser_utility.h"
#include <openssl/md5.h>
namespace oceanbase {
using namespace common;
namespace sql {
int ObSQLParser::parse(const char* str_ptr, const int64_t str_len, ParseResult& result)
{
int ret = OB_SUCCESS;
if (0 != parse_init(&result)) {
ret = OB_ERR_PARSER_INIT;
} else {
ret = parse_sql(&result, str_ptr, static_cast<size_t>(str_len));
}
return ret;
}
int ObSQLParser::parse_and_gen_sqlid(
void* malloc_pool, const char* str_ptr, const int64_t str_len, const int64_t len, char* sql_id)
{
int ret = OB_SUCCESS;
ParseResult* parse_result = (ParseResult*)parse_malloc(sizeof(ParseResult), malloc_pool);
if (OB_ISNULL(parse_result)) {
ret = OB_ALLOCATE_MEMORY_FAILED;
} else {
memset((void*)parse_result, 0, sizeof(ParseResult));
parse_result->is_fp_ = true;
parse_result->is_multi_query_ = false;
parse_result->malloc_pool_ = malloc_pool;
parse_result->is_ignore_hint_ = false;
parse_result->need_parameterize_ = true;
parse_result->pl_parse_info_.is_pl_parse_ = false;
parse_result->minus_ctx_.has_minus_ = false;
parse_result->minus_ctx_.pos_ = -1;
parse_result->minus_ctx_.raw_sql_offset_ = -1;
parse_result->is_for_trigger_ = false;
parse_result->is_dynamic_sql_ = false;
parse_result->is_batched_multi_enabled_split_ = false;
parse_result->may_bool_value_ = false;
int64_t new_length = str_len + 1;
char* buf = (char*)parse_malloc(new_length, parse_result->malloc_pool_);
parse_result->param_nodes_ = NULL;
parse_result->tail_param_node_ = NULL;
parse_result->no_param_sql_ = buf;
parse_result->no_param_sql_buf_len_ = new_length;
ret = parse(str_ptr, new_length, *parse_result);
if (OB_SUCC(ret)) {
ret = gen_sqlid(parse_result->no_param_sql_, parse_result->no_param_sql_len_, len, sql_id);
}
}
return ret;
}
int ObSQLParser::gen_sqlid(const char* paramed_sql, const int64_t sql_len, const int64_t len, char* sql_id)
{
int ret = OB_SUCCESS;
const int32_t MD5_LENGTH = 16;
if (OB_ISNULL(sql_id) || len < 32) {
ret = OB_INVALID_ARGUMENT;
} else {
unsigned char md5_buf[MD5_LENGTH];
unsigned char* res = MD5(reinterpret_cast<const unsigned char*>(paramed_sql), sql_len, md5_buf);
if (OB_ISNULL(res)) {
ret = OB_ERR_UNEXPECTED;
} else {
ret = parser_to_hex_cstr(md5_buf, MD5_LENGTH, sql_id, len);
}
}
return ret;
}
} // namespace sql
} // namespace oceanbase

View File

@ -0,0 +1,49 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef OCEANBASE_SRC_SQL_PARSER_OB_SQL_PARSER_H_
#define OCEANBASE_SRC_SQL_PARSER_OB_SQL_PARSER_H_
#ifdef SQL_PARSER_COMPILATION
#include "parse_node.h"
#else
#include "sql/parser/parse_node.h"
#endif
namespace oceanbase {
namespace common {
class ObIAllocator;
} // namespace common
namespace sql {
class ObSQLParser {
public:
ObSQLParser(common::ObIAllocator& allocator, ObSQLMode mode) : allocator_(allocator), sql_mode_(mode)
{}
int parse(const char* str_ptr, const int64_t str_len, ParseResult& result);
// only for obproxy fast parser
// do not use the this function in observer kernel
int parse_and_gen_sqlid(
void* malloc_pool, const char* str_ptr, const int64_t str_len, const int64_t len, char* sql_id);
private:
int gen_sqlid(const char* paramed_sql, const int64_t sql_len, const int64_t len, char* sql_id);
private:
common::ObIAllocator& allocator_;
ObSQLMode sql_mode_;
};
} // namespace sql
} // namespace oceanbase
#endif /* OCEANBASE_SRC_SQL_PARSER_OB_SQL_PARSER_H_ */

View File

@ -0,0 +1,30 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef OCEANBASE_SQL_PARSER_PARSE_DEFINE_
#define OCEANBASE_SQL_PARSER_PARSE_DEFINE_
#include "lib/utility/ob_macro_utils.h"
#define NULL_PTR(x) (OB_UNLIKELY(NULL == (x)))
static const int64_t OB_MAX_PARSER_INT16_VALUE = 32738;
// errno keep consistency with with ob_define.h
static const int32_t OB_PARSER_ERR_NO_MEMORY = -4013;
static const int32_t OB_PARSER_ERR_UNEXPECTED = -4016;
static const int32_t OB_PARSER_ERR_EMPTY_QUERY = -5253;
static const int32_t OB_PARSER_ERR_PARSE_SQL = -5001;
static const int32_t OB_PARSER_ERR_SIZE_OVERFLOW = -4019;
static const int32_t OB_PARSER_SUCCESS = 0;
static const int32_t OB_PARSER_ERR_ILLEGAL_NAME = -5018;
#endif /*OCEANBASE_SQL_PARSER_PARSE_DEFINE_*/

View File

@ -0,0 +1,165 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#define USING_LOG_PREFIX SQL_PARSER
#include "sql/parser/parse_malloc.h"
#include <string.h>
#include <lib/alloc/alloc_assist.h>
#include "lib/charset/ob_ctype.h"
#include "sql/parser/parse_define.h"
#include "sql/parser/parser_proxy_func.h"
// get memory from the thread obStringBuf, and not release untill thread quits
void* parse_malloc(const size_t nbyte, void* malloc_pool)
{
void* ptr = NULL;
size_t headlen = sizeof(int64_t);
if (OB_ISNULL(malloc_pool)) {
} else if (OB_UNLIKELY(nbyte <= 0)) {
} else {
if (OB_UNLIKELY(NULL == (ptr = parser_alloc_buffer(malloc_pool, headlen + nbyte)))) {
} else {
*(static_cast<int64_t*>(ptr)) = nbyte;
ptr = static_cast<char*>(ptr) + headlen;
MEMSET(ptr, 0, nbyte);
}
}
return ptr;
}
/* ptr must point to a memory allocated by parse_malloc.cpp */
void* parse_realloc(void* ptr, size_t nbyte, void* malloc_pool)
{
void* new_ptr = NULL;
// need not to check nbyte
if (OB_ISNULL(malloc_pool)) {
} else {
if (OB_UNLIKELY(NULL == ptr)) {
new_ptr = parser_alloc_buffer(malloc_pool, nbyte);
} else {
size_t headlen = sizeof(int64_t);
if (OB_UNLIKELY(NULL == (new_ptr = parser_alloc_buffer(malloc_pool, headlen + nbyte)))) {
} else {
int64_t obyte = *(reinterpret_cast<int64_t*>(static_cast<char*>(ptr) - headlen));
*(static_cast<int64_t*>(new_ptr)) = nbyte;
new_ptr = static_cast<char*>(new_ptr) + headlen;
MEMMOVE(new_ptr, ptr, static_cast<int64_t>(nbyte) > obyte ? obyte : nbyte);
parser_free_buffer(malloc_pool, static_cast<char*>(ptr) - headlen);
}
}
}
return new_ptr;
}
char* parse_strndup(const char* str, size_t nbyte, void* malloc_pool)
{
char* new_str = NULL;
// need not to check nbyte
if (OB_ISNULL(str)) {
} else {
if (OB_LIKELY(NULL != (new_str = static_cast<char*>(parse_malloc(nbyte + 1, malloc_pool))))) {
MEMMOVE(new_str, str, nbyte);
new_str[nbyte] = '\0';
} else {
}
}
return new_str;
}
char* parse_strdup(const char* str, void* malloc_pool, int64_t* out_len)
{
char* out_str = NULL;
if (OB_ISNULL(str)) {
} else if (OB_ISNULL(out_len)) {
} else {
size_t dup_len = STRLEN(str);
out_str = parse_strndup(str, dup_len, malloc_pool);
*out_len = dup_len;
}
return out_str;
}
char* parse_str_convert_utf8(
const struct ObCharsetInfo* src_cs, const char* str, void* malloc_pool, int64_t* out_len, int* extra_errno)
{
char* out_str = NULL;
if (OB_ISNULL(str) || OB_ISNULL(out_len) || OB_ISNULL(extra_errno)) {
} else {
uint errors;
size_t str_len = STRLEN(str);
size_t dst_len = str_len * 4;
if (OB_ISNULL(out_str = static_cast<char*>(parse_malloc(dst_len + 1, malloc_pool)))) {
} else {
*out_len = ob_convert(out_str, dst_len, &ob_charset_utf8mb4_general_ci, str, str_len, src_cs, &errors);
out_str[*out_len] = '\0';
if (0 != errors) {
*extra_errno = OB_PARSER_ERR_ILLEGAL_NAME;
}
}
}
return out_str;
}
char* strndup_with_prefix(const char* prefix, const char* str, size_t nbyte, void* malloc_pool)
{
char* new_str = NULL;
size_t prefix_len = strlen(prefix);
// need not to check nbyte
if (OB_ISNULL(str)) {
} else {
if (OB_LIKELY(NULL != (new_str = static_cast<char*>(parse_malloc(nbyte + prefix_len, malloc_pool))))) {
MEMMOVE(new_str, prefix, prefix_len);
MEMMOVE(new_str + prefix_len, str, nbyte);
} else {
// do nothing
}
}
return new_str;
}
char* strndup_with_prefix_and_postfix(
const char* prefix, const char* postfix, const char* str, size_t nbyte, void* malloc_pool)
{
char* new_str = NULL;
size_t prefix_len = strlen(prefix);
size_t postfix_len = strlen(postfix);
if (OB_ISNULL(str)) {
} else {
if (OB_LIKELY(
NULL != (new_str = static_cast<char*>(parse_malloc(nbyte + prefix_len + postfix_len, malloc_pool))))) {
MEMMOVE(new_str, prefix, prefix_len);
MEMMOVE(new_str + prefix_len, str, nbyte);
MEMMOVE(new_str + prefix_len + nbyte, postfix, postfix_len);
} else {
}
}
return new_str;
}
void parse_free(void* ptr)
{
UNUSED(ptr);
/* do nothing, we don't really free the memory */
}
char* cp_str_value(const char* src, const size_t nbyte, void* malloc_pool)
{
char* new_str = NULL;
if (OB_ISNULL(src)) {
} else {
if (OB_LIKELY(NULL != (new_str = static_cast<char*>(parse_malloc(nbyte, malloc_pool))))) {
MEMCPY(new_str, src, nbyte);
} else {
}
}
return new_str;
}

View File

@ -0,0 +1,40 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef OCEANBASE_SQL_PARSER_PARSE_MALLOC_
#define OCEANBASE_SQL_PARSER_PARSE_MALLOC_
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
// NB: Be careful!!!, it is only used in parser module
// NOTE, parse_malloc will memset the allocated memory to 0
extern void* parse_malloc(const size_t nbyte, void* malloc_pool);
extern void* parse_realloc(void* ptr, size_t nbyte, void* malloc_pool);
extern void parse_free(void* ptr);
extern char* parse_strndup(const char* str, size_t nbyte, void* malloc_pool);
extern char* parse_strdup(const char* str, void* malloc_pool, int64_t* out_len);
extern char* parse_str_convert_utf8(
const struct ObCharsetInfo* src_cs, const char* str, void* malloc_pool, int64_t* out_len, int* extra_errno);
extern char* strndup_with_prefix(const char* prefix, const char* str, size_t nbyte, void* malloc_pool);
extern char* strndup_with_prefix_and_postfix(
const char* prefix, const char* postfix, const char* str, size_t nbyte, void* malloc_pool);
extern char* cp_str_value(const char* src, const size_t nbyte, void* malloc_pool);
#ifdef __cplusplus
}
#endif
#endif // OCEANBASE_SQL_PARSER_PARSE_MALLOC_

634
src/sql/parser/parse_node.c Normal file
View File

@ -0,0 +1,634 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#include "sql/parser/parse_node.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "lib/alloc/alloc_assist.h"
#include "sql/parser/parse_malloc.h"
#include "sql/parser/parse_node_hash.h"
#include "sql/parser/parse_define.h"
#include "sql/parser/sql_parser_base.h"
extern const char* get_type_name(int type);
#ifdef SQL_PARSER_COMPILATION
#include "sql/parser/parser_proxy_func.h"
#endif // SQL_PARSER_COMPILATION
#define WINDOW_FUNCTION_NUM 41
struct FuncPair {
char* func_name_;
int yytokentype_;
};
int count_child(ParseNode* root, void* malloc_pool, int* count);
// merge_child:if succ ,return 0, else return 1
int merge_child(ParseNode* node, void* malloc_pool, ParseNode* source_tree, int* index);
void destroy_tree(ParseNode* root)
{
(void)root;
/*
if (OB_UNLIKELY(NULL == root)) {
//do nothing
} else {
int64_t i = 0;
if (root->num_child_ > 0) {
if (OB_UNLIKELY(NULL == root->children_)) {
(void)fprintf(stderr, "ERROR children of root is NULL\n");
} else {
for (; i < root->num_child_; ++i) {
destroy_tree(root->children_[i]);
root->children_[i] = NULL;
}
parse_free(root->children_);
root->children_ = NULL;
}
}
if (NULL != root->str_value_) {
parse_free((char *)root->str_value_);
root->str_value_ = NULL;
}
parse_free(root);
}*/
}
ParseNode* new_node(void* malloc_pool, ObItemType type, int num)
{
// the mem alloced by parse_malloc has been memset;
ParseNode* node = (ParseNode*)parse_malloc(sizeof(ParseNode), malloc_pool);
if (OB_UNLIKELY(NULL == node)) {
(void)printf("malloc memory failed\n");
} else {
node->type_ = type;
node->num_child_ = num;
node->param_num_ = 0;
node->is_neg_ = 0;
node->is_hidden_const_ = 0;
node->is_date_unit_ = 0;
node->is_tree_not_param_ = 0;
node->length_semantics_ = 0;
node->is_change_to_char_ = 0;
node->is_val_paramed_item_idx_ = 0;
node->is_copy_raw_text_ = 0;
node->is_column_varchar_ = 0;
node->is_trans_from_minus_ = 0;
node->is_assigned_from_child_ = 0;
node->is_num_must_be_pos_ = 0;
node->value_ = INT64_MAX;
node->str_len_ = 0;
node->str_value_ = NULL;
node->text_len_ = 0;
node->raw_text_ = NULL;
node->pos_ = 0;
#ifdef SQL_PARSER_COMPILATION
node->token_off_ = -1;
node->token_len_ = -1;
#endif
if (num > 0) {
int64_t alloc_size = sizeof(ParseNode*) * num;
node->children_ = (ParseNode**)parse_malloc(alloc_size, malloc_pool);
if (OB_UNLIKELY(NULL == node->children_)) {
parse_free(node);
node = NULL;
}
} else {
node->children_ = NULL;
}
}
return node;
}
int count_child(ParseNode* root, void* malloc_pool, int* count)
{
int ret = OB_PARSER_SUCCESS;
ParserLinkNode* stack_top = NULL;
if (NULL == count) {
ret = OB_PARSER_ERR_UNEXPECTED;
(void)fprintf(stderr, "ERROR invalid parameter ret=%d\n", ret);
} else if (NULL == root) {
*count = 0;
} else if (NULL == (stack_top = new_link_node(malloc_pool))) {
ret = 1;
(void)fprintf(stderr, "ERROR failed to malloc memory\n");
} else {
*count = 0;
stack_top->val_ = root;
do {
ParseNode* tree = NULL;
if (NULL == stack_top || NULL == (tree = (ParseNode*)stack_top->val_)) {
ret = 1;
(void)fprintf(stderr, "ERROR invalid null argument\n");
} else {
stack_top = stack_top->next_;
}
if (OB_PARSER_SUCCESS != ret) {
} else if (T_LINK_NODE != tree->type_) {
*count += 1;
} else if (tree->num_child_ <= 0) {
// do nothing
} else {
if (NULL == tree->children_) {
ret = 1;
(void)fprintf(stderr, "ERROR invalid null children\n");
}
ParserLinkNode* tmp_node = NULL;
for (int64_t i = tree->num_child_ - 1; OB_PARSER_SUCCESS == ret && i >= 0; i--) {
ParseNode* child = tree->children_[i];
if (NULL == child) {
// do nothing
} else if (NULL == (tmp_node = new_link_node(malloc_pool))) {
ret = 1;
(void)fprintf(stderr, "ERROR failed to allocate memory\n");
} else {
tmp_node->val_ = child;
tmp_node->next_ = stack_top;
stack_top = tmp_node;
}
} // for end
}
} while (OB_PARSER_SUCCESS == ret && NULL != stack_top);
}
return ret;
}
// merge_child:if succ ,return 0, else return 1
int merge_child(ParseNode* node, void* malloc_pool, ParseNode* source_tree, int* index)
{
int ret = 0;
ParserLinkNode* stack_top = NULL;
if (OB_UNLIKELY(NULL == node || NULL == index)) {
ret = 1;
(void)fprintf(stderr, "ERROR node%p or index:%p is NULL\n", node, index);
} else if (NULL == source_tree) {
// do nothing
} else if (NULL == (stack_top = new_link_node(malloc_pool))) {
ret = 1;
(void)fprintf(stderr, "ERROR failed to malloc memory\n");
} else {
stack_top->val_ = source_tree;
do {
ParseNode* tree = NULL;
if (NULL == stack_top || NULL == (tree = (ParseNode*)stack_top->val_)) {
ret = 1;
(void)fprintf(stderr, "ERROR invalid null argument\n");
} else {
// pop stack
stack_top = stack_top->next_;
}
if (OB_PARSER_SUCCESS != ret) {
// do nothing
} else if (T_LINK_NODE != tree->type_) {
if (OB_UNLIKELY(*index < 0 || *index >= node->num_child_)) {
ret = 1;
(void)fprintf(
stderr, "ERROR invalid index: %d, num_child:%d\n tree: %d", *index, node->num_child_, tree->type_);
} else if (NULL == node->children_) {
ret = 1;
(void)fprintf(stderr, "ERROR invalid null children pointer\n");
} else {
node->children_[*index] = tree;
++(*index);
}
} else if (tree->num_child_ <= 0) {
// do nothing
} else if (NULL == tree->children_) {
ret = 1;
(void)fprintf(stderr, "ERROR invalid children pointer\n");
} else {
ParserLinkNode* tmp_node = NULL;
for (int64_t i = tree->num_child_ - 1; OB_PARSER_SUCCESS == ret && i >= 0; i--) {
if (NULL == tree->children_[i]) {
// do nothing
} else if (NULL == (tmp_node = new_link_node(malloc_pool))) {
ret = 1;
(void)fprintf(stderr, "ERROR failed to malloc memory\n");
} else {
// push stack
tmp_node->val_ = tree->children_[i];
tmp_node->next_ = stack_top;
stack_top = tmp_node;
}
} // for end
}
} while (OB_PARSER_SUCCESS == ret && (stack_top != NULL));
}
return ret;
}
ParseNode* merge_tree(void* malloc_pool, int* fatal_error, ObItemType node_tag, ParseNode* source_tree)
{
ParseNode* node = NULL;
ParseNode* ret_node = NULL;
if (OB_UNLIKELY(NULL == malloc_pool) || OB_UNLIKELY(NULL == fatal_error)) {
(void)fprintf(stderr, "ERROR parser result is NULL\n");
} else if (NULL == source_tree) {
// source_tree may be NULL, do nothing
} else {
int index = 0;
int num = 0;
int tmp_ret = 0;
if (OB_UNLIKELY(OB_PARSER_SUCCESS != (tmp_ret = count_child(source_tree, malloc_pool, &num)))) {
(void)fprintf(stderr, "ERROR fail to , count child num code : %d\n", tmp_ret);
*fatal_error = tmp_ret;
} else if (OB_LIKELY(NULL != (node = new_node(malloc_pool, node_tag, num)))) {
if (OB_UNLIKELY(OB_PARSER_SUCCESS != (tmp_ret = merge_child(node, malloc_pool, source_tree, &index)))) {
(void)fprintf(stderr, "ERROR fail to merge_child, error code : %d\n", tmp_ret);
*fatal_error = tmp_ret;
} else if (index != num) {
(void)fprintf(stderr, "ERROR index:%d is not equal to num:%d\n", index, num);
} else {
ret_node = node;
}
} else {
*fatal_error = OB_PARSER_ERR_NO_MEMORY;
}
}
return ret_node;
}
ParseNode* new_terminal_node(void* malloc_pool, ObItemType type)
{
int children_num = 0;
return new_node(malloc_pool, type, children_num);
}
ParseNode* new_non_terminal_node(void* malloc_pool, ObItemType node_tag, int num, ...)
{
ParseNode* ret_node = NULL;
if (OB_UNLIKELY(num <= 0)) {
(void)fprintf(stderr, "ERROR invalid num:%d\n", num);
} else {
int32_t i = 0;
va_list va;
ret_node = new_node(malloc_pool, node_tag, num);
if (OB_LIKELY(NULL != ret_node)) {
va_start(va, num);
for (; i < num; ++i) {
ret_node->children_[i] = va_arg(va, ParseNode*);
}
va_end(va);
}
}
return ret_node;
}
char* copy_expr_string(ParseResult* p, int expr_start, int expr_end)
{
char* expr_string = NULL;
if (OB_UNLIKELY(NULL == p)) {
(void)fprintf(stderr, "ERROR parser result is NULL\n");
} else if (OB_UNLIKELY(NULL == p->input_sql_)) {
(void)fprintf(stderr, "ERROR input sql is NULL\n");
} else if (OB_UNLIKELY(expr_start < 0 || expr_end < 0 || expr_end < expr_start)) {
(void)fprintf(stderr, "ERROR invalid argument, expr_start:%d, expr_end:%d\n", expr_start, expr_end);
} else {
int len = expr_end - expr_start + 1;
expr_string = (char*)parse_malloc(len + 1, p->malloc_pool_);
if (OB_UNLIKELY(NULL == expr_string)) {
(void)printf("malloc memory failed\n");
} else {
memmove(expr_string, p->input_sql_ + expr_start - 1, len);
expr_string[len] = '\0';
}
}
return expr_string;
}
unsigned char escaped_char(unsigned char c, int* with_back_slash)
{
*with_back_slash = 0;
switch (c) {
case 'n':
return '\n';
case 't':
return '\t';
case 'r':
return '\r';
case 'b':
return '\b';
case '0':
return '\0';
case 'Z':
return '\032';
case '_':
case '%':
*with_back_slash = 1;
return c;
default:
return c;
}
}
///* quote_type: 0 - single quotes; 1 - double quotation marks */
// int64_t ob_parse_string(const char *src, char *dest, int64_t len, int quote_type)
//{
// int64_t i;
// int64_t index = 0;
// int with_back_slash = 1;
// for (i = 0; i < len; ++i) {
// unsigned char c = src[i];
// if (c == '\\') {
// if (i < len - 1) {
// c = src[++i];
// } else {
// break;
// }
// c = escaped_char(c, &with_back_slash);
// if (with_back_slash)
// {
// dest[index++] = '\\';
// }
// } else if (quote_type == 0 && c == '\'' && i + 1 < len && src[i + 1] == '\'') {
// ++i;
// } else if (quote_type == 1 && c == '"' && i + 1 < len && src[i + 1] == '"') {
// ++i;
// }
// dest[index++] = c;
// }
// assert(index <= len);
// dest[index] = '\0';
// return index;
//}
static char char_int(char c)
{
return (c >= '0' && c <= '9' ? c - '0' : (c >= 'A' && c <= 'Z' ? c - 'A' + 10 : c - 'a' + 10));
}
int64_t ob_parse_binary_len(int64_t len)
{
return (len + 1) / 2;
}
void ob_parse_binary(const char* src, int64_t len, char* dest)
{
if (OB_UNLIKELY(NULL == src || len <= 0 || NULL == dest)) {
// do nothing
} else {
if (len > 0 && len % 2 != 0) {
*dest = char_int(src[0]);
++src;
++dest;
}
const char* end = src + len - 1;
for (; src <= end; src += 2) {
*dest = (char)(16 * char_int(src[0]) + char_int(src[1]));
++dest;
}
}
}
int64_t ob_parse_bit_string_len(int64_t len)
{
return (len + 7) / 8;
}
void ob_parse_bit_string(const char* src, int64_t len, char* dest)
{
if (OB_UNLIKELY(NULL == src || len <= 0 || NULL == dest)) {
// do nothing
} else {
const char* end = src + len - 1;
char* dest_end = dest + ob_parse_bit_string_len(len) - 1;
if (len > 0) {
unsigned char c = 0;
unsigned int one_bit = 1;
for (; end >= src; --end) {
if (256 == one_bit) /* one byte ready */
{
*dest_end = c;
--dest_end;
c = 0;
one_bit = 1;
}
if ('1' == *end) {
c |= one_bit;
}
one_bit <<= 1;
} /* end for */
*dest_end = c; /* the first byte */
}
}
}
char* str_tolower(char* buff, int64_t len)
{
if (OB_LIKELY(NULL != buff)) {
char* ptr = buff;
char* end = buff + len;
unsigned char ch = *ptr;
while (ptr != end) {
ch = *ptr;
if (ch >= 'A' && ch <= 'Z') {
ch += 'a' - 'A';
} else if (ch >= 0x80 && isupper(ch)) {
ch = tolower(ch);
}
*ptr = ch;
ptr++;
}
}
return buff;
}
char* str_toupper(char* buff, int64_t len)
{
if (OB_LIKELY(NULL != buff)) {
char* ptr = buff;
char* end = buff + len;
unsigned char ch = *ptr;
while (ptr != end) {
ch = *ptr;
if (ch >= 'a' && ch <= 'z') {
ch -= 'a' - 'A';
} else if (ch >= 0x80 && islower(ch)) {
ch = toupper(ch);
}
*ptr = ch;
ptr++;
}
}
return buff;
}
int64_t str_remove_space(char* buff, int64_t len)
{
int64_t length = 0;
if (OB_LIKELY(NULL != buff)) {
for (int i = 0; i < len; i++) {
if (!isspace(buff[i])) {
buff[length++] = buff[i];
}
}
}
return length;
}
// calculate hash value of syntax tree recursively
// every member of ParseNode is calculated using murmurhash
uint64_t parsenode_hash(const ParseNode* node)
{
uint64_t hash_val = 0;
if (check_stack_overflow_c()) {
(void)fprintf(stderr, "ERROR stack overflow in recursive function\n");
} else if (OB_LIKELY(NULL != node)) {
hash_val = murmurhash(&node->type_, sizeof(node->type_), hash_val);
hash_val = murmurhash(&node->value_, sizeof(node->value_), hash_val);
hash_val = murmurhash(&node->str_len_, sizeof(node->str_len_), hash_val);
if (NULL != node->str_value_) {
hash_val = murmurhash(node->str_value_, node->str_len_, hash_val);
}
uint64_t child_hash_val = 0;
int32_t i = 0;
if (node->num_child_ > 0) {
if (OB_UNLIKELY(NULL == node->children_)) {
(void)fprintf(stderr, "ERROR children of node is NULL\n");
} else {
for (; i < node->num_child_; ++i) {
if (NULL != node->children_[i]) {
child_hash_val = parsenode_hash(node->children_[i]);
hash_val = murmurhash(&child_hash_val, sizeof(child_hash_val), hash_val);
}
}
}
}
}
return hash_val;
}
// compare syntax tree recursively
// every member of ParseNode is compared
bool parsenode_equal(const ParseNode* lnode, const ParseNode* rnode)
{
bool result = true;
if (check_stack_overflow_c()) {
(void)fprintf(stderr, "ERROR stack overflow in recursive function\n");
} else if (NULL == lnode && NULL == rnode) {
result = true;
} else if ((NULL == lnode && NULL != rnode) || (NULL != lnode && NULL == rnode)) {
result = false;
} else {
if (lnode->type_ != rnode->type_ || lnode->value_ != rnode->value_ || lnode->str_len_ != rnode->str_len_ ||
lnode->num_child_ != rnode->num_child_) {
result = false;
} else {
if (NULL == lnode->str_value_ && NULL == rnode->str_value_) {
result = true;
} else if ((NULL == lnode->str_value_ && NULL != rnode->str_value_) ||
(NULL != lnode->str_value_ && NULL == rnode->str_value_)) {
result = false;
} else if (lnode->str_len_ != rnode->str_len_) {
result = false;
} else {
// T_VARCHAR type: value_ is length, str_value_ is ptr
// @ref ob_raw_expr.cpp
if (0 != strncmp(lnode->str_value_, rnode->str_value_, lnode->str_len_)) {
result = false;
}
}
if (result) {
if (lnode->num_child_ > 0) {
if (NULL == lnode->children_ || NULL == rnode->children_) {
result = false;
} else {
int32_t i = 0;
for (; result && i < lnode->num_child_; ++i) {
result = parsenode_equal(lnode->children_[i], rnode->children_[i]);
}
}
}
}
}
}
return result;
}
// Search according to the name, return the subscript of the name when found, add the name and return the subscript when
// found
int64_t get_question_mark(ObQuestionMarkCtx* ctx, void* malloc_pool, const char* name)
{
int64_t idx = -1;
if (OB_UNLIKELY(NULL == ctx || NULL == name)) {
(void)fprintf(stderr, "ERROR question mark ctx or name is NULL\n");
} else {
bool valid_name = true;
for (int64_t i = 0; valid_name && -1 == idx && i < ctx->count_; ++i) {
if (NULL == ctx->name_[i]) {
(void)fprintf(stderr, "ERROR name_ in question mark ctx is null\n");
valid_name = false;
} else if (0 == STRCASECMP(ctx->name_[i], name)) {
idx = i;
}
}
if (-1 == idx && valid_name) {
int64_t len = 0;
ctx->name_[ctx->count_] = parse_strdup(name, malloc_pool, &len);
idx = ctx->count_++;
}
}
return idx;
}
ParserLinkNode* new_link_node(void* malloc)
{
ParserLinkNode* new_node = (ParserLinkNode*)parse_malloc(sizeof(ParserLinkNode), malloc);
if (NULL == new_node) {
(void)printf("ERROR malloc memory failed\n");
} else {
new_node->next_ = NULL;
new_node->prev_ = NULL;
new_node->val_ = NULL;
}
return new_node;
}
bool nodename_equal(const ParseNode* node, const char* pattern, int64_t pat_len)
{
bool result = true;
if (NULL == node || NULL == node->str_value_ || NULL == pattern || node->str_len_ != pat_len) {
result = false;
} else {
result = true;
for (int64_t i = 0; result && i < pat_len; ++i) {
if (toupper(node->str_value_[i]) != toupper(pattern[i])) {
result = false;
}
}
}
return result;
}
int binary_search(const struct FuncPair* window_func, int64_t begin, int64_t end, const char* value)
{
int result = -1;
bool need_break = false;
while (!need_break && begin <= end) {
int mid = begin + (end - begin) / 2;
int cmp = strcmp(window_func[mid].func_name_, value);
if (cmp > 0) {
end = mid - 1;
} else if (cmp < 0) {
begin = mid + 1;
} else {
result = window_func[mid].yytokentype_;
need_break = true;
}
}
return result;
}

354
src/sql/parser/parse_node.h Normal file
View File

@ -0,0 +1,354 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef OCEANBASE_SQL_PARSER_PARSE_NODE_H_
#define OCEANBASE_SQL_PARSER_PARSE_NODE_H_
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdbool.h>
#include <setjmp.h>
#ifdef SQL_PARSER_COMPILATION
#include "ob_sql_mode.h"
#include "ob_item_type.h"
#else
#include "common/sql_mode/ob_sql_mode.h"
#include "sql/parser/ob_item_type.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_ERROR_MSG 1024
struct ObCharsetInfo;
enum SelectParserOffset {
PARSE_SELECT_WITH,
PARSE_SELECT_DISTINCT,
PARSE_SELECT_SELECT,
PARSE_SELECT_INTO, // into before from
PARSE_SELECT_FROM,
PARSE_SELECT_WHERE,
PARSE_SELECT_DYNAMIC_SW_CBY, // connect by node or start with node
PARSE_SELECT_DYNAMIC_CBY_SW, // connect by node or start with node
PARSE_SELECT_GROUP,
PARSE_SELECT_HAVING,
PARSE_SELECT_SET,
PARSE_SELECT_ALL,
PARSE_SELECT_FORMER,
PARSE_SELECT_LATER,
PARSE_SELECT_ORDER,
PARSE_SELECT_LIMIT,
PARSE_SELECT_FOR_UPD,
PARSE_SELECT_HINTS,
PARSE_SELECT_WHEN,
PARSE_SELECT_NAMED_WINDOWS,
PARSE_SELECT_FETCH,
PARSE_SELECT_FETCH_TEMP, // use to temporary store fetch clause in parser
PARSE_SELECT_INTO_EXTRA, // ATTENTION!! SELECT_INTO_EXTRA must be the last one
PARSE_SELECT_MAX_IDX
};
enum GrantParseOffset {
PARSE_GRANT_ROLE_LIST,
PARSE_GRANT_ROLE_GRANTEE,
PARSE_GRANT_ROLE_OPT_WITH,
PARSE_GRANT_ROLE_MAX_IDX
};
enum GrantParseSysOffset {
PARSE_GRANT_SYS_PRIV_ORACLE_LIST,
PARSE_GRANT_SYS_PRIV_ORACLE_GRANTEE,
PARSE_GRANT_SYS_PRIV_ORACLE_OPT_WITH,
PARSE_GRANT_SYS_PRIV_ORACLE_MAX_IDX
};
enum ParseMode {
STD_MODE = 0,
FP_MODE, /* fast parse, keep hint, and do parameterization*/
MULTI_MODE, /* multi query ultra-fast parse */
FP_PARAMERIZE_AND_FILTER_HINT_MODE, /*Filter out the hint and do parameterization*/
FP_NO_PARAMERIZE_AND_FILTER_HINT_MODE, /*Filter out hints and do not parameterize*/
TRIGGER_MODE, /* treat ':xxx' as identifier */
DYNAMIC_SQL_MODE, /*In the process of parsing dynamic sql: iidx and:identifier should be determined
according to the statement type whether to check the name of the placeholder*/
DBMS_SQL_MODE,
};
typedef struct {
int err_code_;
char err_msg_[MAX_ERROR_MSG];
} ErrStat;
struct _ParseNode;
typedef struct _ObStmtLoc {
int first_column_;
int last_column_;
int first_line_;
int last_line_;
} ObStmtLoc;
typedef struct _ParseNode {
ObItemType type_;
int32_t num_child_;
int16_t param_num_;
struct {
uint16_t is_neg_ : 1;
uint16_t is_hidden_const_ : 1;
uint16_t is_tree_not_param_ : 1;
uint16_t length_semantics_ : 2;
uint16_t is_change_to_char_ : 1;
uint16_t is_val_paramed_item_idx_ : 1;
uint16_t is_copy_raw_text_ : 1;
uint16_t is_column_varchar_ : 1;
uint16_t is_trans_from_minus_ : 1;
uint16_t is_assigned_from_child_ : 1;
uint16_t is_num_must_be_pos_ : 1;
uint16_t is_date_unit_ : 1;
uint16_t reserved_ : 3;
};
union {
int64_t value_;
int32_t int32_values_[2];
int16_t int16_values_[4];
};
const char* str_value_;
int64_t str_len_;
const char* raw_text_;
int64_t text_len_;
int64_t pos_;
struct _ParseNode** children_; /* attributes for non-terninal node, which has children */
ObStmtLoc stmt_loc_;
union {
int64_t raw_param_idx_;
int64_t raw_sql_offset_;
};
#ifdef SQL_PARSER_COMPILATION
int token_off_;
int token_len_;
#endif
} ParseNode;
struct _ParamList;
typedef struct _ParamList {
ParseNode* node_;
struct _ParamList* next_;
} ParamList;
enum RefType {
REF_REL = 0,
REF_PROC,
REF_FUNC,
};
typedef struct _RefObjList {
enum RefType type_;
ParseNode* node_;
struct _RefObjList* next_;
} RefObjList;
typedef struct _PLParseInfo {
bool is_pl_parse_;
bool is_pl_parse_expr_;
/*for mysql pl*/
void* pl_ns_; // ObPLBlockNS
int last_pl_symbol_pos_;
RefObjList* ref_object_nodes_;
RefObjList* tail_ref_object_node_;
} PLParseInfo;
#define MAX_QUESTION_MARK 128
typedef struct _ObQuestionMarkCtx {
char* name_[MAX_QUESTION_MARK];
int count_;
bool by_ordinal_;
bool by_name_;
} ObQuestionMarkCtx;
// record the minus status while parsing the sql
// for example, 'select - -1 from dual'
// when parser sees the first '-', pos_ = 7, raw_sql_offset = 7, has_minus_ = true, is_cur_numeric_ = false
// after seeing the second '-', members are reseted, pos_ = 9, raw_sql_offset_ = 9, has_minus_ = true, is_cur_numberic
// = false after seeing '1', is_cur_numeric = true, then param node '-1' is returned
typedef struct _ObMinusStatuCtx {
int pos_;
int raw_sql_offset_;
bool has_minus_;
bool is_cur_numeric_;
} ObMinusStatusCtx;
#ifdef SQL_PARSER_COMPILATION
// for comment_list_ in ParseResult
typedef struct TokenPosInfo {
int token_off_;
int token_len_;
} TokenPosInfo;
#endif
typedef struct {
void* yyscan_info_;
ParseNode* result_tree_;
jmp_buf jmp_buf_; // handle fatal error
const char* input_sql_;
int input_sql_len_;
void* malloc_pool_; // ObIAllocator
int extra_errno_;
char error_msg_[MAX_ERROR_MSG];
int start_col_;
int end_col_;
int line_;
int yycolumn_;
int yylineno_;
char* tmp_literal_;
ObQuestionMarkCtx question_mark_ctx_;
ObSQLMode sql_mode_;
bool has_encount_comment_;
/*for faster parser*/
bool is_fp_;
/* for multi query fast parse (split queries) */
bool is_multi_query_;
char* no_param_sql_;
int no_param_sql_len_;
int no_param_sql_buf_len_;
ParamList* param_nodes_;
ParamList* tail_param_node_;
int param_node_num_;
int token_num_;
bool is_ignore_hint_; // used for outline
bool is_ignore_token_; // used for outline
bool need_parameterize_; // used for outline, to support signature of outline can contain hint
/*for pl*/
PLParseInfo pl_parse_info_;
/*for q-quote*/
bool in_q_quote_;
ObMinusStatusCtx minus_ctx_; // for fast parser to parse negative value
bool is_for_trigger_;
bool is_dynamic_sql_;
bool is_dbms_sql_;
bool is_batched_multi_enabled_split_;
bool is_not_utf8_connection_;
const struct ObCharsetInfo* charset_info_;
int last_well_formed_len_;
bool may_bool_value_; // used for true/false in sql parser
#ifdef SQL_PARSER_COMPILATION
TokenPosInfo* comment_list_;
int comment_cnt_;
int comment_cap_;
int realloc_cnt_;
bool stop_add_comment_;
#endif
} ParseResult;
typedef struct _ObFastParseCtx {
bool is_fp_;
} ObFastParseCtx;
typedef enum ObSizeUnitType {
SIZE_UNIT_TYPE_INVALID = -1,
SIZE_UNIT_TYPE_K,
SIZE_UNIT_TYPE_M,
SIZE_UNIT_TYPE_G,
SIZE_UNIT_TYPE_T,
SIZE_UNIT_TYPE_P,
SIZE_UNIT_TYPE_E,
SIZE_UNIT_TYPE_MAX
} ObSizeUnitType;
extern int parse_init(ParseResult* p);
extern int parse_reset(ParseResult* p);
extern int parse_terminate(ParseResult* p);
extern int parse_sql(ParseResult* p, const char* pszSql, size_t iLen);
extern void destroy_tree(ParseNode* pRoot);
extern unsigned char escaped_char(unsigned char c, int* with_back_slash);
extern char* str_tolower(char* buff, int64_t len);
extern char* str_toupper(char* buff, int64_t len);
extern int64_t str_remove_space(char* buff, int64_t len);
// extern int64_t ob_parse_string(const char *src, char *dest, int64_t len, int quote_type);
extern ParseNode* new_node(void* malloc_pool, ObItemType type, int num);
extern ParseNode* new_non_terminal_node(void* malloc_pool, ObItemType node_tag, int num, ...);
extern ParseNode* new_terminal_node(void* malloc_pool, ObItemType type);
/// convert x'42ab' to binary string
void ob_parse_binary(const char* src, int64_t len, char* dest);
int64_t ob_parse_binary_len(int64_t len);
// convert b'10010110' to binary string
// @pre dest buffer is enough
void ob_parse_bit_string(const char* src, int64_t len, char* dest);
int64_t ob_parse_bit_string_len(int64_t len);
// calculate hash value of syntax tree recursively
// @param [in] node syntax tree root
// @return hash value of syntax tree
extern uint64_t parsenode_hash(const ParseNode* node);
// compare syntax tree recursively
// @param [in] node1 first syntax tree
// @param [in] node2 second syntax tree
extern bool parsenode_equal(const ParseNode* node1, const ParseNode* node2);
extern int64_t get_question_mark(ObQuestionMarkCtx* ctx, void* malloc_pool, const char* name);
// compare ParseNode str_value_ to pattern
// @param [in] node ParseNode
// @param [in] pattern pattern_str
// @param [in] pat_len length of pattern
extern bool nodename_equal(const ParseNode* node, const char* pattern, int64_t pat_len);
#define OB_NODE_CAST_TYPE_IDX 0
#define OB_NODE_CAST_COLL_IDX 1
#define OB_NODE_CAST_N_PREC_IDX 2
#define OB_NODE_CAST_N_SCALE_IDX 3
#define OB_NODE_CAST_NUMBER_TYPE_IDX 1
#define OB_NODE_CAST_C_LEN_IDX 1
typedef enum ObNumberParseType {
NPT_PERC_SCALE = 0,
NPT_STAR_SCALE,
NPT_STAR,
NPT_PERC,
NPT_EMPTY,
} ObNumberParseType;
#ifndef SQL_PARSER_COMPILATION
bool check_stack_overflow_c();
#endif
typedef struct _ParserLinkNode {
struct _ParserLinkNode* next_;
struct _ParserLinkNode* prev_;
void* val_;
} ParserLinkNode;
ParserLinkNode* new_link_node(void* malloc);
typedef enum ObTranslateCharset {
TRANSLATE_CHAR_CS = 0,
TRANSLATE_NCHAR_CS = 1,
} ObTranslateCharset;
#ifdef __cplusplus
}
#endif
#endif // OCEANBASE_SQL_PARSER_PARSE_NODE_H_

View File

@ -0,0 +1,20 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#include "parse_node_hash.h"
#include "lib/hash_func/murmur_hash.h"
// this is a C wrapper to call murmurhash in C++ definition
uint64_t murmurhash(const void* data, int32_t len, uint64_t hash)
{
return oceanbase::common::murmurhash(data, len, hash);
}

View File

@ -0,0 +1,28 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef OCEANBASE_SQL_PARSER_PARSENODE_HASH_
#define OCEANBASE_SQL_PARSER_PARSENODE_HASH_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// this is a C wrapper to call murmurhash in C++ definition
uint64_t murmurhash(const void* data, int32_t len, uint64_t hash);
#ifdef __cplusplus
}
#endif
#endif /*OCEANBASE_SQL_PARSER_PARSENODE_HASH_*/

View File

@ -0,0 +1,53 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#define USING_LOG_PREFIX SQL_PARSER
#include "parser_proxy_func.h"
#include "share/ob_errno.h"
#include "lib/utility/ob_macro_utils.h"
#include "lib/oblog/ob_log.h"
#include "lib/allocator/ob_allocator.h"
using namespace oceanbase::common;
void* parser_alloc_buffer(void* malloc_pool, const int64_t alloc_size)
{
int ret = OB_SUCCESS;
void* alloced_buf = NULL;
if (OB_ISNULL(malloc_pool)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid malloc pool", K(ret));
} else {
ObIAllocator* allocator = static_cast<ObIAllocator*>(malloc_pool);
if (OB_ISNULL(alloced_buf = allocator->alloc(alloc_size))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allocate memory", K(ret), K(alloc_size));
} else {
// do nothing
}
}
return alloced_buf;
}
void parser_free_buffer(void* malloc_pool, void* buffer)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(malloc_pool)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid null malloc pool", K(ret));
} else {
ObIAllocator* allocator = static_cast<ObIAllocator*>(malloc_pool);
allocator->free(buffer);
}
}

View File

@ -0,0 +1,37 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef PARSER_ALLOC_FUNC_H_
#define PARSER_ALLOC_FUNC_H_
#include <stdint.h>
// ObSQLParser module extracts a static link library to Proxy, Proxy must implement the following
// functions by itself to link correctly
void* parser_alloc_buffer(void* malloc_pool, const int64_t alloc_size);
void parser_free_buffer(void* malloc_pool, void* buffer);
#ifdef SQL_PARSER_COMPILATION
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
extern bool check_stack_overflow_c();
extern int check_stack_overflow_in_c(int* check_overflow);
extern void right_to_die_or_duty_to_live_c();
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // SQL_PARSER_COMPILATION
#endif // !PASER_ALLOC_FUNC_H_

View File

@ -0,0 +1,54 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#include "sql/parser/parser_utility.h"
#include "lib/utility/ob_macro_utils.h"
#include <cstddef>
int parser_to_hex_cstr(const void* in_data, const int64_t data_length, char* buff, const int64_t buff_size)
{
int ret = 0;
int64_t pos = 0;
int64_t cstr_pos = 0;
if (0 != (ret = parser_to_hex_cstr_(in_data, data_length, buff, buff_size, &pos, &cstr_pos))) {}
return ret;
}
static const char* HEXCHARS = "0123456789ABCDEF";
int parser_to_hex_cstr_(
const void* in_data, const int64_t data_length, char* buf, const int64_t buf_len, int64_t* pos, int64_t* cstr_pos)
{
int ret = 0;
*cstr_pos = *pos;
if ((OB_UNLIKELY(data_length > 0) && OB_ISNULL(in_data)) || OB_ISNULL(buf) || OB_UNLIKELY(*pos < 0) ||
OB_UNLIKELY(buf_len - *pos) < 1) {
ret = -1;
// LOG_WARN("Invalid argument", KP(in_data), KP(buf), K(data_length), K(buf_len), K(ret));
} else if ((buf_len - *pos) < (data_length * 2 + 1)) {
buf[*pos++] = '\0';
ret = -2;
// LOG_WARN("size is overflow", K(buf_len), K(data_length), K(buf_len), K(pos), K(ret));
} else {
unsigned const char* p = (unsigned const char*)in_data;
char* dst = static_cast<char*>(buf + *pos);
for (int64_t i = 0; i < data_length; ++i) {
*dst++ = HEXCHARS[*p >> 4 & 0xF];
*dst++ = HEXCHARS[*p & 0xF];
p++;
}
*dst = '\0';
*pos += (data_length * 2 + 1);
}
return ret;
}

View File

@ -0,0 +1,29 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef PARSER_UTILITY_H_
#define PARSER_UTILITY_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
int parser_to_hex_cstr(const void* in_data, const int64_t data_length, char* buff, const int64_t buff_size);
int parser_to_hex_cstr_(
const void* in_data, const int64_t data_length, char* buf, const int64_t buf_len, int64_t* pos, int64_t* cstr_pos);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,274 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#include "sql_parser_base.h"
#define YY_EXTRA_TYPE void*
#define yyconst const
typedef void* yyscan_t;
typedef struct yy_buffer_state* YY_BUFFER_STATE;
#define IS_ORACLE_MODE(mode) (0 != (mode & SMO_ORACLE))
#define IS_ORACLE_COMPATIBLE (IS_ORACLE_MODE(p->sql_mode_))
extern int obsql_mysql_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals);
extern int obsql_mysql_yyparse(ParseResult* result);
extern int obsql_mysql_multi_fast_parse(ParseResult* p);
extern int obsql_mysql_fast_parse(ParseResult* p);
extern int obsql_mysql_yylex_destroy(yyscan_t yyscanner);
extern YY_BUFFER_STATE obsql_mysql_yy_scan_bytes(yyconst char* bytes, int len, yyscan_t yyscanner);
extern void obsql_mysql_yy_switch_to_buffer(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner);
extern void obsql_mysql_yy_delete_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner);
int parse_init(ParseResult* p)
{
int ret = 0; // can not include C++ file "ob_define.h"
if (OB_UNLIKELY(NULL == p || NULL == p->malloc_pool_)) {
ret = -1;
if (NULL != p) {
(void)snprintf(p->error_msg_, MAX_ERROR_MSG, "malloc_pool_ must be set");
}
}
if (OB_LIKELY(0 == ret)) {
ret = IS_ORACLE_COMPATIBLE ? OB_PARSER_ERR_PARSE_SQL : obsql_mysql_yylex_init_extra(p, &(p->yyscan_info_));
}
return ret;
}
int parse_reset(ParseResult* p)
{
if (NULL != p) {
p->yyscan_info_ = NULL;
p->result_tree_ = NULL;
p->input_sql_ = NULL;
p->input_sql_len_ = 0;
p->malloc_pool_ = NULL;
p->extra_errno_ = 0;
p->error_msg_[0] = '\0';
p->start_col_ = 0;
p->end_col_ = 0;
p->line_ = 0;
p->yycolumn_ = 0;
p->yylineno_ = 0;
p->tmp_literal_ = NULL;
p->question_mark_ctx_.count_ = 0;
p->question_mark_ctx_.by_ordinal_ = false;
p->question_mark_ctx_.by_name_ = false;
p->sql_mode_ = 0;
p->has_encount_comment_ = false;
p->is_fp_ = false;
p->is_multi_query_ = false;
p->no_param_sql_ = NULL;
p->no_param_sql_len_ = 0;
p->no_param_sql_buf_len_ = 0;
p->param_nodes_ = NULL;
p->tail_param_node_ = NULL;
p->param_node_num_ = 0;
p->token_num_ = 0;
p->is_ignore_hint_ = false;
p->is_ignore_token_ = false;
p->need_parameterize_ = false;
/*for pl*/
p->pl_parse_info_.is_pl_parse_ = false;
p->pl_parse_info_.is_pl_parse_expr_ = false;
p->pl_parse_info_.pl_ns_ = NULL;
p->pl_parse_info_.last_pl_symbol_pos_ = 0;
p->pl_parse_info_.ref_object_nodes_ = NULL;
p->pl_parse_info_.tail_ref_object_node_ = NULL;
/*for q-quote*/
p->in_q_quote_ = false;
p->minus_ctx_.pos_ = 0;
p->minus_ctx_.raw_sql_offset_ = 0;
p->minus_ctx_.has_minus_ = false;
p->minus_ctx_.is_cur_numeric_ = false;
p->is_for_trigger_ = false;
p->is_dynamic_sql_ = false;
p->is_dbms_sql_ = false;
p->is_batched_multi_enabled_split_ = false;
p->is_not_utf8_connection_ = false;
p->charset_info_ = NULL;
p->last_well_formed_len_ = 0;
p->may_bool_value_ = false;
#ifdef SQL_PARSER_COMPILATION
p->comment_list_ = NULL;
p->comment_cnt_ = 0;
p->comment_cap_ = 0;
p->realloc_cnt_ = 0;
p->stop_add_comment_ = false;
#endif
}
return 0;
}
int parse_terminate(ParseResult* p)
{
int ret = 0;
if (OB_LIKELY(NULL != p->yyscan_info_)) {
ret = IS_ORACLE_COMPATIBLE ? OB_PARSER_ERR_PARSE_SQL : obsql_mysql_yylex_destroy(p->yyscan_info_);
}
return ret;
}
int parse_sql(ParseResult* p, const char* buf, size_t len)
{
int ret = OB_PARSER_ERR_PARSE_SQL;
if (OB_UNLIKELY(NULL == p)) {
} else if (IS_ORACLE_COMPATIBLE) {
ret = OB_PARSER_ERR_PARSE_SQL;
} else if (OB_UNLIKELY(NULL == buf || len <= 0)) {
snprintf(p->error_msg_, MAX_ERROR_MSG, "Input SQL can not be empty");
ret = OB_PARSER_ERR_EMPTY_QUERY;
} else {
p->result_tree_ = 0;
p->error_msg_[0] = 0;
p->input_sql_ = buf;
p->input_sql_len_ = len;
p->start_col_ = 1;
p->end_col_ = 1;
p->line_ = 1;
p->yycolumn_ = 1;
p->yylineno_ = 1;
p->tmp_literal_ = NULL;
p->last_well_formed_len_ = 0;
#ifdef SQL_PARSER_COMPILATION
p->realloc_cnt_ = p->realloc_cnt_ <= 0 ? 10 : p->realloc_cnt_;
p->comment_cap_ = p->realloc_cnt_;
p->comment_cnt_ = 0;
p->stop_add_comment_ = false;
#endif
if (false == p->pl_parse_info_.is_pl_parse_) {
p->question_mark_ctx_.count_ = 0;
}
// while (len > 0 && ISSPACE(buf[len - 1])) {
// --len;
// }
// if (OB_UNLIKELY(len <= 0)) {
// (void)snprintf(p->error_msg_, MAX_ERROR_MSG, "Input SQL can not be white space only");
// ret = OB_PARSER_ERR_EMPTY_QUERY;
// } else {
{
int val = setjmp(p->jmp_buf_);
if (val) {
ret = OB_PARSER_ERR_NO_MEMORY;
#ifdef SQL_PARSER_COMPILATION
} else if (OB_ISNULL(p->comment_list_ = (TokenPosInfo*)(parse_malloc(
p->realloc_cnt_ * sizeof(TokenPosInfo), p->malloc_pool_)))) {
ret = OB_PARSER_ERR_NO_MEMORY;
#endif
} else {
// bp = yy_scan_string(buf, p->yyscan_info_);
YY_BUFFER_STATE bp = obsql_mysql_yy_scan_bytes(buf, len, p->yyscan_info_);
obsql_mysql_yy_switch_to_buffer(bp, p->yyscan_info_);
int tmp_ret = -1;
if (p->is_fp_) {
tmp_ret = obsql_mysql_fast_parse(p);
} else if (p->is_multi_query_) {
tmp_ret = obsql_mysql_multi_fast_parse(p);
} else {
tmp_ret = obsql_mysql_yyparse(p);
}
if (0 == tmp_ret) {
ret = OB_PARSER_SUCCESS;
} else if (2 == tmp_ret) {
ret = OB_PARSER_ERR_NO_MEMORY;
} else {
if (0 != p->extra_errno_) {
ret = p->extra_errno_;
} else {
ret = OB_PARSER_ERR_PARSE_SQL;
}
}
obsql_mysql_yy_delete_buffer(bp, p->yyscan_info_);
}
}
}
return ret;
}
int parse_sql_stmt(ParseResult* parse_result)
{
int ret = -1;
if (0 != (ret = parse_init(parse_result))) {
// fix bug #16298144
// fprintf(stderr, "init parse result failed, ret=%d\n", ret);
} else if (0 != (ret = parse_sql(parse_result, parse_result->input_sql_, parse_result->input_sql_len_))) {
// fix bug #16298144
// fprintf(stderr, "parse sql failed, ret=%d, input_sql=%.*s\n", ret, parse_result->input_sql_len_,
// parse_result->input_sql_);
}
return ret;
}
void setup_token_pos_info(ParseNode* node, int off, int len)
{
#ifdef SQL_PARSER_COMPILATION
node->token_off_ = off;
node->token_len_ = len;
#else
// do nothing
#endif
}
int setup_token_pos_info_and_dup_string(ParseNode* node, ParseResult* result, int start, int end)
{
int ret = OB_PARSER_SUCCESS;
#ifdef SQL_PARSER_COMPILATION
node->token_off_ = start - 1;
node->token_len_ = end - start + 1;
if (start > end) {
ret = OB_PARSER_ERR_UNEXPECTED;
} else if (OB_UNLIKELY((NULL == (node->str_value_ = copy_expr_string(result, start, end))))) {
ret = OB_PARSER_ERR_NO_MEMORY;
} else {
node->str_len_ = end - start + 1;
}
#else
// do nothing
#endif
return ret;
}
#ifdef SQL_PARSER_COMPILATION
int add_comment_list(ParseResult* p, const TokenPosInfo* info)
{
int ret = OB_PARSER_SUCCESS;
if (OB_ISNULL(p) || OB_ISNULL(info)) {
ret = OB_PARSER_ERR_UNEXPECTED;
}
if (OB_PARSER_SUCCESS == ret && p->comment_cnt_ + 1 >= p->comment_cap_) {
int alloc_cnt = p->comment_cnt_ + p->realloc_cnt_;
char* buf = parse_malloc(sizeof(TokenPosInfo) * alloc_cnt, p->malloc_pool_);
if (OB_ISNULL(buf)) {
ret = OB_PARSER_ERR_NO_MEMORY;
} else {
memset(buf, 0, sizeof(TokenPosInfo) * alloc_cnt);
memcpy(buf, (void*)(p->comment_list_), sizeof(TokenPosInfo) * p->comment_cnt_);
p->comment_list_ = (TokenPosInfo*)buf;
p->comment_cap_ += p->realloc_cnt_;
}
}
if (OB_PARSER_SUCCESS == ret) {
p->comment_list_[p->comment_cnt_].token_off_ = info->token_off_;
p->comment_list_[p->comment_cnt_].token_len_ = info->token_len_;
p->comment_cnt_ += 1;
}
return ret;
}
#endif

View File

@ -0,0 +1,742 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef OCEANBASE_SRC_SQL_PARSER_SQL_PARSER_BASE_H_
#define OCEANBASE_SRC_SQL_PARSER_SQL_PARSER_BASE_H_
#include <stdint.h>
#include <assert.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include "lib/charset/ob_ctype.h"
#include "lib/ob_date_unit_type.h"
#include "share/schema/ob_priv_type.h"
#include "sql/ob_trans_character.h"
#include "parse_node.h"
#include "parse_malloc.h"
#include "ob_non_reserved_keywords.h"
#include "parse_define.h"
#include <math.h>
#define MAX_VARCHAR_LENGTH 4194303
#define INT16NUM_OVERFLOW INT16_MAX
#define OUT_OF_STR_LEN -2
#define DEFAULT_STR_LENGTH -1
#define BINARY_COLLATION 63
#define INVALID_COLLATION 0
#define INVALID_INDEX -1
#define YYLEX_PARAM result->yyscan_info_
#define JOIN_MERGE_NODES(node1, node2) \
do { \
if (T_LINK_NODE == node1->type_) { \
merge_nodes(node1, result, T_TABLE_REFERENCES, node1); \
} \
if (T_LINK_NODE == node2->type_) { \
merge_nodes(node2, result, T_TABLE_REFERENCES, node2); \
} \
} while (0)
extern void yyerror(void* yylloc, ParseResult* p, char* s, ...);
extern ParseNode* merge_tree(void* malloc_pool, int* fatal_error, ObItemType node_tag, ParseNode* source_tree);
extern ParseNode* new_terminal_node(void* malloc_pool, ObItemType type);
extern ParseNode* new_non_terminal_node(void* malloc_pool, ObItemType node_tag, int num, ...);
extern char* copy_expr_string(ParseResult* p, int expr_start, int expr_end);
#define ISSPACE(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || (c) == '\t' || (c) == '\f' || (c) == '\v')
#define YYABORT_NO_MEMORY \
do { \
if (OB_UNLIKELY(NULL == result)) { \
(void)fprintf(stderr, "ERROR : result is NULL\n"); \
} else if (0 == result->extra_errno_) { \
result->extra_errno_ = OB_PARSER_ERR_NO_MEMORY; \
} else { /*do nothing*/ \
} \
YYABORT; \
} while (0)
#define YYABORT_UNEXPECTED \
do { \
if (OB_UNLIKELY(NULL == result)) { \
(void)fprintf(stderr, "ERROR : result is NULL\n"); \
} else if (0 == result->extra_errno_) { \
result->extra_errno_ = OB_PARSER_ERR_UNEXPECTED; \
} else { /*do nothing*/ \
} \
YYABORT; \
} while (0)
#define YYABORT_PARSE_SQL_ERROR YYERROR
#define malloc_terminal_node(node, malloc_pool, type) \
do { \
if (OB_UNLIKELY(NULL == (node = new_terminal_node(malloc_pool, type)))) { \
yyerror(NULL, result, "No more space for malloc\n"); \
YYABORT_NO_MEMORY; \
} \
} while (0)
#define malloc_non_terminal_node(node, malloc_pool, node_tag, ...) \
do { \
if (OB_UNLIKELY(NULL == (node = new_non_terminal_node(malloc_pool, node_tag, ##__VA_ARGS__)))) { \
yyerror(NULL, result, "No more space for malloc\n"); \
YYABORT_NO_MEMORY; \
} \
} while (0)
#define merge_nodes(node, result, node_tag, source_tree) \
do { \
if (OB_UNLIKELY(NULL == source_tree)) { \
node = NULL; \
} else if (OB_UNLIKELY(NULL == (node = merge_tree( \
result->malloc_pool_, &(result->extra_errno_), node_tag, source_tree)))) { \
yyerror(NULL, result, "No more space for merging nodes\n"); \
YYABORT_NO_MEMORY; \
} \
} while (0)
#define dup_expr_string(node, result, expr_start, expr_end) \
do { \
if (OB_UNLIKELY(NULL == node || NULL == result || NULL == result->input_sql_)) { \
yyerror(NULL, result, "invalid argument, node:%p, result:%p or input_sql is NULL\n", node, result); \
YYABORT_UNEXPECTED; \
} else if (OB_UNLIKELY(expr_start < 0 || expr_end < 0 || expr_start > expr_end)) { \
yyerror(NULL, result, "invalid argument, expr_start:%d, expr_end:%d\n", (int32_t)expr_start, (int32_t)expr_end); \
YYABORT_UNEXPECTED; \
} else { \
int start = expr_start; \
node->str_value_ = NULL; \
node->str_len_ = 0; \
while (start <= expr_end && ISSPACE(result->input_sql_[start - 1])) { \
start++; \
} \
if (start >= expr_start && \
(OB_UNLIKELY((NULL == (node->str_value_ = copy_expr_string(result, start, expr_end)))))) { \
yyerror(NULL, result, "No more space for copying expression string\n"); \
YYABORT_NO_MEMORY; \
} else { \
node->str_len_ = expr_end - start + 1; \
} \
} \
} while (0)
#define dup_string(node, result, start, end) \
if (start > end || (OB_UNLIKELY((NULL == (node->str_value_ = copy_expr_string(result, start, end)))))) { \
yyerror(NULL, result, "No more space for copying expression string\n"); \
YYABORT_NO_MEMORY; \
} else { \
node->str_len_ = end - start + 1; \
}
#define dup_modify_key_string(node, result, expr_start, expr_end, prefix) \
do { \
if (OB_UNLIKELY(NULL == node || NULL == result || NULL == result->input_sql_)) { \
yyerror(NULL, result, "invalid argument, node:%p, result:%p or input_sql is NULL\n", node, result); \
YYABORT_UNEXPECTED; \
} else if (OB_UNLIKELY(expr_start < 0 || expr_end < 0 || expr_start > expr_end)) { \
yyerror(NULL, result, "invalid argument, expr_start:%d, expr_end:%d\n", (int32_t)expr_start, (int32_t)expr_end); \
YYABORT_UNEXPECTED; \
} else { \
int start = expr_start; \
node->str_value_ = NULL; \
node->str_len_ = 0; \
while (start <= expr_end && ISSPACE(result->input_sql_[start - 1])) { \
start++; \
} \
int len = expr_end - start + sizeof(prefix); \
char* expr_string = (char*)parse_malloc(len + 1, result->malloc_pool_); \
if (OB_UNLIKELY(NULL == expr_string)) { \
yyerror(NULL, result, "No more space for copying expression string\n"); \
YYABORT_NO_MEMORY; \
} else { \
memmove(expr_string, (prefix), strlen(prefix)); \
memmove(expr_string + strlen(prefix), result->input_sql_ + start - 1, expr_end - start + 1); \
expr_string[len] = '\0'; \
node->str_value_ = expr_string; \
node->str_len_ = len; \
} \
} \
} while (0)
#define get_non_reserved_node(node, malloc_pool, word_start, word_end) \
do { \
malloc_terminal_node(node, malloc_pool, T_IDENT); \
dup_expr_string(node, result, word_start, word_end); \
setup_token_pos_info(node, word_start - 1, word_end - word_start + 1); \
} while (0)
#define make_name_node(node, malloc_pool, name) \
do { \
malloc_terminal_node(node, malloc_pool, T_IDENT); \
node->str_value_ = parse_strdup(name, malloc_pool, &(node->str_len_)); \
if (OB_UNLIKELY(NULL == node->str_value_)) { \
yyerror(NULL, result, "No more space for string duplicate\n"); \
YYABORT_NO_MEMORY; \
} \
} while (0)
#define dup_string_to_node(node, malloc_pool, name) \
do { \
if (OB_UNLIKELY(NULL == node)) { \
yyerror(NULL, result, "invalid arguments node: %p\n", node); \
YYABORT_UNEXPECTED; \
} else { \
node->str_value_ = parse_strdup(name, malloc_pool, &(node->str_len_)); \
if (OB_UNLIKELY(NULL == node->str_value_)) { \
yyerror(NULL, result, "No more space for string duplicate\n"); \
YYABORT_NO_MEMORY; \
} \
} \
} while (0)
#define dup_node_string(node_src, node_dest, malloc_pool) \
do { \
if (OB_UNLIKELY((NULL == node_src || NULL == node_dest || NULL == node_src->str_value_))) { \
yyerror(NULL, result, "invalid arguments node_src: %p, node_dest: %p\n", node_src, node_dest); \
YYABORT_UNEXPECTED; \
} else { \
node_dest->str_value_ = parse_strndup(node_src->str_value_, node_src->str_len_, malloc_pool); \
if (OB_UNLIKELY(NULL == node_dest->str_value_)) { \
yyerror(NULL, result, "No more space for dup_node_string\n"); \
YYABORT_NO_MEMORY; \
} else { \
node_dest->str_len_ = node_src->str_len_; \
} \
} \
} while (0)
/* to minimize modification, we use stmt->value_ as question mark size */
#define question_mark_issue(node, result) \
do { \
if (OB_UNLIKELY(NULL == node || NULL == result)) { \
yyerror(NULL, result, "node or result is NULL\n"); \
YYABORT_UNEXPECTED; \
} else if (OB_UNLIKELY(INT64_MAX != node->value_)) { \
yyerror(NULL, result, "node value is not INT64_MAX\n"); \
YYABORT_UNEXPECTED; \
} else { \
node->value_ = result->question_mark_ctx_.count_; \
} \
} while (0)
#define check_question_mark(node, result) \
do { \
if (OB_UNLIKELY(NULL == node || NULL == result)) { \
yyerror(NULL, result, "node or result is NULL\n"); \
YYABORT_UNEXPECTED; \
} else if (OB_UNLIKELY(!result->pl_parse_info_.is_pl_parse_ && 0 != result->question_mark_ctx_.count_)) { \
yyerror(NULL, result, "Unknown column '?'\n"); \
YYABORT_UNEXPECTED; \
} else { \
node->value_ = result->question_mark_ctx_.count_; \
} \
} while (0)
#define store_pl_symbol(node, head, tail) \
do { \
ParamList* param = (ParamList*)parse_malloc(sizeof(ParamList), result->malloc_pool_); \
if (OB_UNLIKELY(NULL == param)) { \
yyerror(NULL, result, "No more space for alloc ParamList\n"); \
YYABORT_NO_MEMORY; \
} else { \
param->node_ = node; \
param->next_ = NULL; \
if (NULL == head) { \
head = param; \
} else { \
tail->next_ = param; \
} \
tail = param; \
} \
} while (0)
#define copy_and_replace_questionmark(result, start, end, idx) \
do { \
if (NULL == result) { \
YY_FATAL_ERROR("invalid var node\n"); \
} else if ((result->pl_parse_info_.is_pl_parse_ && NULL == result->pl_parse_info_.pl_ns_) || \
result->is_dynamic_sql_) { \
if (result->no_param_sql_len_ + (start - result->pl_parse_info_.last_pl_symbol_pos_ - 1) + (int)(log10(idx)) + \
3 > \
result->no_param_sql_buf_len_) { \
char* buf = parse_malloc(result->no_param_sql_buf_len_ * 2, result->malloc_pool_); \
if (OB_UNLIKELY(NULL == buf)) { \
YY_FATAL_ERROR("no memory to alloc\n"); \
} else { \
memmove(buf, result->no_param_sql_, result->no_param_sql_len_); \
result->no_param_sql_ = buf; \
result->no_param_sql_buf_len_ = result->no_param_sql_buf_len_ * 2; \
} \
} \
memmove(result->no_param_sql_ + result->no_param_sql_len_, \
result->input_sql_ + result->pl_parse_info_.last_pl_symbol_pos_, \
start - result->pl_parse_info_.last_pl_symbol_pos_ - 1); \
result->no_param_sql_len_ += start - result->pl_parse_info_.last_pl_symbol_pos_ - 1; \
result->pl_parse_info_.last_pl_symbol_pos_ = end; \
result->no_param_sql_[result->no_param_sql_len_++] = ':'; \
result->no_param_sql_len_ += sprintf(result->no_param_sql_ + result->no_param_sql_len_, "%ld", idx); \
} \
} while (0)
#define copy_and_skip_symbol(result, start, end) \
do { \
if (NULL == result) { \
yyerror(NULL, result, "invalid var node\n"); \
YYABORT_UNEXPECTED; \
} else if (NULL == result->pl_parse_info_.pl_ns_) { \
} else { \
memmove(result->no_param_sql_ + result->no_param_sql_len_, \
result->input_sql_ + result->pl_parse_info_.last_pl_symbol_pos_, \
start - result->pl_parse_info_.last_pl_symbol_pos_ - 1); \
result->no_param_sql_len_ += start - result->pl_parse_info_.last_pl_symbol_pos_ - 1; \
result->pl_parse_info_.last_pl_symbol_pos_ = end; \
} \
} while (0)
#define store_pl_ref_object_symbol(node, result, type) \
do { \
if (OB_UNLIKELY((NULL == node || NULL == result))) { \
yyerror(NULL, result, "invalid var node: %p\n", node); \
YYABORT_UNEXPECTED; \
} else if (NULL == result->pl_parse_info_.pl_ns_) { \
} else { \
RefObjList* object = (RefObjList*)parse_malloc(sizeof(RefObjList), result->malloc_pool_); \
if (OB_UNLIKELY(NULL == object)) { \
yyerror(NULL, result, "No more space for alloc ParamList\n"); \
YYABORT_NO_MEMORY; \
} else { \
object->type_ = type; \
object->node_ = node; \
object->next_ = NULL; \
if (NULL == result->pl_parse_info_.ref_object_nodes_) { \
result->pl_parse_info_.ref_object_nodes_ = object; \
} else { \
result->pl_parse_info_.tail_ref_object_node_->next_ = object; \
} \
result->pl_parse_info_.tail_ref_object_node_ = object; \
} \
} \
} while (0)
#define process_placeholder_for_dynamic \
do { \
if (p->pl_parse_info_.is_pl_parse_) { \
yylval->node->value_ = get_question_mark(&p->question_mark_ctx_, p->malloc_pool_, yytext); \
} else { \
yylval->node->value_ = p->question_mark_ctx_.count_++; \
} \
} while (0)
//////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
#define YY_USER_ACTION \
do { \
check_value(yylloc); \
ParseResult* p = (ParseResult*)yyextra; \
yylloc->first_line = yylloc->last_line = yylineno; \
yylloc->first_column = p->yycolumn_; \
yylloc->last_column = yylloc->first_column + yyleng - 1; \
p->yycolumn_ += yyleng; \
} while (0);
extern ParseNode* new_node(void* malloc_pool, ObItemType type, int num);
#define malloc_new_node(node, malloc_pool, type, num) \
do { \
if (OB_UNLIKELY(NULL == (node = new_node(malloc_pool, type, num)))) { \
((ParseResult*)yyextra)->extra_errno_ = OB_PARSER_ERR_NO_MEMORY; \
yyerror(yylloc, yyextra, "No more space for mallocing '%s'\n", yytext); \
return ERROR; \
} \
} while (0);
#define malloc_time_node(malloc_pool, type, find_char) \
do { \
ParseNode* node = NULL; \
malloc_new_node(node, malloc_pool, type, 0); \
char* begin = strchr(yytext, find_char); \
check_value(begin); \
char* end = strchr(begin + 1, find_char); \
check_value(end); \
char* dest = NULL; \
size_t len = end - begin - 1; \
dest = parse_strndup(begin + 1, len, malloc_pool); \
check_value(dest); \
node->str_value_ = dest; \
node->str_len_ = len; \
check_value(yylval); \
yylval->node = node; \
} while (0);
#define malloc_time_node_s(malloc_pool, type) malloc_time_node(malloc_pool, type, '\'');
#define malloc_time_node_d(malloc_pool, type) malloc_time_node(malloc_pool, type, '\"');
#define check_value(val_ptr) \
do { \
if (OB_UNLIKELY(NULL == val_ptr)) { \
((ParseResult*)yyextra)->extra_errno_ = OB_PARSER_ERR_UNEXPECTED; \
yyerror(yylloc, yyextra, "'%s' is NULL\n", #val_ptr); \
return ERROR; \
} \
} while (0);
#define check_malloc(val_ptr, nbyte) \
do { \
if (OB_UNLIKELY(NULL == val_ptr)) { \
((ParseResult*)yyextra)->extra_errno_ = OB_PARSER_ERR_NO_MEMORY; \
yyerror(yylloc, yyextra, "No more space for malloc(size: %ld)\n", (size_t)nbyte); \
return ERROR; \
} \
} while (0);
#define check_identifier_convert_result(errno) \
do { \
if (OB_PARSER_ERR_ILLEGAL_NAME == errno) { \
yyerror(yylloc, yyextra, "name '%s' is illegal\n", yytext); \
return ERROR; \
} \
} while (0);
#define IS_FAST_PARAMETERIZE ((ParseResult*)yyextra)->is_fp_
#define IS_NEED_PARAMETERIZE ((ParseResult*)yyextra)->need_parameterize_
#define IS_FOR_TRIGGER ((ParseResult*)yyextra)->is_for_trigger_
#define COPY_STRING(src, src_len, dst) \
do { \
if (IS_FAST_PARAMETERIZE && IS_NEED_PARAMETERIZE) { \
dst = src; \
} else { \
ParseResult* p = (ParseResult*)yyextra; \
dst = parse_strndup(src, src_len, p->malloc_pool_); \
check_value(dst); \
} \
} while (0);
#define COPY_STR_NODE_TO_TMP_LITERAL(str_node) \
do { \
ParseResult* p = (ParseResult*)yyextra; \
char** tmp_literal = &(p->tmp_literal_); \
if (NULL == *tmp_literal) { \
*tmp_literal = (char*)parse_malloc(p->input_sql_len_ + 1, p->malloc_pool_); \
check_value(*tmp_literal); \
} \
if (str_node->str_value_ != NULL) { \
memmove(((ParseResult*)yyextra)->tmp_literal_, str_node->str_value_, str_node->str_len_); \
str_node->str_value_ = NULL; \
} \
} while (0);
#define STORE_STR_CONTENT(str_node) \
do { \
ParseResult* p = (ParseResult*)yyextra; \
if (str_node->str_len_ <= 0 && IS_FAST_PARAMETERIZE && IS_NEED_PARAMETERIZE) { \
str_node->str_value_ = p->input_sql_ + yylloc->first_column - 1; \
str_node->str_len_ = yyleng; \
} else { \
char** tmp_literal = &(p->tmp_literal_); \
if (NULL == *tmp_literal) { \
*tmp_literal = (char*)parse_malloc(p->input_sql_len_ + 1, p->malloc_pool_); \
check_value(*tmp_literal); \
} \
memmove(*tmp_literal + str_node->str_len_, yytext, yyleng); \
str_node->str_len_ += yyleng; \
} \
} while (0);
#define FORMAT_STR_NODE(str_node) \
do { \
ParseResult* p = (ParseResult*)yyextra; \
if (str_node->str_value_ == NULL && str_node->str_len_ > 0) { \
char* tmp_literal = p->tmp_literal_; \
tmp_literal[yylval->node->str_len_] = '\0'; \
str_node->str_value_ = parse_strndup(tmp_literal, str_node->str_len_ + 1, p->malloc_pool_); \
check_value(str_node->str_value_); \
} \
} while (0);
#define COPY_WRITE() \
do { \
ParseResult* p = (ParseResult*)yyextra; \
memmove(p->no_param_sql_ + p->no_param_sql_len_, yytext, yyleng); \
p->no_param_sql_len_ += yyleng; \
p->no_param_sql_[p->no_param_sql_len_] = '\0'; \
} while (0);
#define REPUT_NEG_SIGN(parse_result) \
do { \
if (parse_result->minus_ctx_.has_minus_) { \
int start_pos = parse_result->no_param_sql_len_; \
int end_pos = parse_result->minus_ctx_.pos_; \
for (; start_pos > end_pos; start_pos--) { \
parse_result->no_param_sql_[start_pos] = parse_result->no_param_sql_[start_pos - 1]; \
} \
parse_result->no_param_sql_[end_pos] = '-'; \
parse_result->no_param_sql_[++parse_result->no_param_sql_len_] = '\0'; \
parse_result->minus_ctx_.pos_ = -1; \
parse_result->minus_ctx_.raw_sql_offset_ = -1; \
parse_result->minus_ctx_.has_minus_ = false; \
} \
} while (0);
#define STORE_PARAM_NODE() \
do { \
ParseResult* p = (ParseResult*)yyextra; \
if (p->need_parameterize_) { \
if (p->minus_ctx_.has_minus_ && p->minus_ctx_.is_cur_numeric_) { \
p->no_param_sql_[p->minus_ctx_.pos_] = '?'; \
p->no_param_sql_len_ = p->minus_ctx_.pos_ + 1; \
} else { \
if (p->minus_ctx_.has_minus_) { \
REPUT_NEG_SIGN(p); \
} \
p->no_param_sql_[p->no_param_sql_len_++] = '?'; \
} \
p->no_param_sql_[p->no_param_sql_len_] = '\0'; \
size_t alloc_len = sizeof(ParamList); \
ParamList* param = (ParamList*)parse_malloc(alloc_len, p->malloc_pool_); \
check_malloc(param, alloc_len); \
check_value(yylval); \
check_value(yylval->node); \
yylval->node->pos_ = p->no_param_sql_len_ - 1; \
yylval->node->raw_sql_offset_ = (p->minus_ctx_.has_minus_ && p->minus_ctx_.is_cur_numeric_) \
? p->minus_ctx_.raw_sql_offset_ \
: yylloc->first_column - 1; \
param->node_ = yylval->node; \
param->next_ = NULL; \
if (NULL == p->param_nodes_) { \
p->param_nodes_ = param; \
} else { \
p->tail_param_node_->next_ = param; \
} \
p->tail_param_node_ = param; \
p->param_node_num_++; \
p->token_num_++; \
p->minus_ctx_.has_minus_ = false; \
p->minus_ctx_.pos_ = -1; \
p->minus_ctx_.is_cur_numeric_ = false; \
p->minus_ctx_.raw_sql_offset_ = -1; \
} else { \
return OUTLINE_DEFAULT_TOKEN; \
} \
} while (0);
#define STORE_UNIT_TYPE_NODE(str_val) \
do { \
ParseResult* p = (ParseResult*)yyextra; \
if (p->need_parameterize_) { \
ParseNode* node = NULL; \
malloc_new_node(node, ((ParseResult*)yyextra)->malloc_pool_, T_INT, 0); \
check_value(yylval); \
yylval->node = node; \
yylval->node->raw_text_ = \
parse_strdup(yytext, ((ParseResult*)yyextra)->malloc_pool_, &(yylval->node->text_len_)); \
check_value(yylval->node->raw_text_); \
node->str_value_ = parse_strdup((char*)str_val, ((ParseResult*)yyextra)->malloc_pool_, &(node->str_len_)); \
check_value(node->str_value_); \
node->value_ = strtoll(node->str_value_, NULL, 10); \
STORE_PARAM_NODE() \
} else { \
return OUTLINE_DEFAULT_TOKEN; \
} \
} while (0);
#define HANDLE_UNIT_TYPE(type) \
do { \
if (IS_FAST_PARAMETERIZE) { \
ParseResult* p = (ParseResult*)yyextra; \
if (p->need_parameterize_) { \
STORE_UNIT_TYPE_NODE(ob_date_unit_type_num_str(DATE_UNIT_##type)); \
} else { \
return OUTLINE_DEFAULT_TOKEN; \
} \
} else { \
return type; \
} \
} while (0);
#define HANDLE_ESCAPE(presult) \
do { \
int with_back_slash = 1; \
unsigned char c = escaped_char(yytext[1], &with_back_slash); \
if (with_back_slash) { \
presult->tmp_literal_[yylval->node->str_len_++] = '\\'; \
} \
presult->tmp_literal_[yylval->node->str_len_++] = c; \
} while (0);
#define HANDLE_FALSE_ESCAPE(presult) \
do { \
presult->tmp_literal_[yylval->node->str_len_++] = '\\'; \
yyless(1); \
presult->yycolumn_--; \
} while (0);
#define CHECK_REAL_ESCAPE(is_real_escape) \
do { \
if (NULL != p->charset_info_ && p->charset_info_->escape_with_backslash_is_dangerous) { \
char* cur_pos = p->tmp_literal_ + yylval->node->str_len_; \
char* last_check_pos = p->tmp_literal_ + p->last_well_formed_len_; \
int error = 0; \
int expected_well_formed_len = cur_pos - last_check_pos; \
int real_well_formed_len = \
p->charset_info_->cset->well_formed_len(last_check_pos, cur_pos - last_check_pos, UINT64_MAX, &error); \
if (error != 0) { \
*cur_pos = '\\'; \
if (real_well_formed_len == expected_well_formed_len - 1 && p->charset_info_->cset->ismbchar(cur_pos, 2)) { \
is_real_escape = false; \
p->last_well_formed_len_ = yylval->node->str_len_ + 1; \
} else { \
p->last_well_formed_len_ = yylval->node->str_len_; \
} \
} else { \
p->last_well_formed_len_ = yylval->node->str_len_; \
} \
} \
} while (0);
#define CHECK_NODE_STRING_VALUE_ASCII(token, my_str_ptr, my_str_len) \
do { \
if (p->charset_info_ != NULL && p->is_not_utf8_connection_) { \
if (my_str_len != p->charset_info_->cset->numchars(p->charset_info_, my_str_ptr, my_str_ptr + my_str_len)) { \
p->extra_errno_ = OB_PARSER_ERR_ILLEGAL_NAME; \
yyerror(yylloc, \
yyextra, \
"multi-byte identifier '%.*s' not support in charset '%s'\n", \
my_str_len, \
my_str_ptr, \
p->charset_info_->csname); \
token = PARSER_SYNTAX_ERROR; \
} \
} \
} while (0)
#define ADD_YYLINENO(_yytext, _yyleng) \
for (int32_t _i = 0; _i < _yyleng; ++_i) { \
if (_yytext[_i] == '\n') { \
++yylineno; \
} \
}
#define COPY_NUM_STRING(parse_result, node) \
do { \
if (IS_FAST_PARAMETERIZE) { \
if (parse_result->minus_ctx_.has_minus_) { \
int64_t start_pos = parse_result->minus_ctx_.raw_sql_offset_; \
int64_t cp_len = yylloc->first_column - start_pos - 1 + yyleng; \
COPY_STRING(p->input_sql_ + start_pos, cp_len, node->str_value_); \
node->str_len_ = cp_len; \
} else { \
COPY_STRING(p->input_sql_ + yylloc->first_column - 1, yyleng, node->str_value_); \
node->str_len_ = yyleng; \
} \
} else { \
COPY_STRING(p->input_sql_ + yylloc->first_column - 1, yyleng, node->str_value_); \
node->str_len_ = yyleng; \
} \
} while (0);
#define PARSE_INT_STR_MYSQL(param_node, malloc_pool, errno) \
do { \
if ('-' == param_node->str_value_[0]) { \
char* copied_str = parse_strndup(param_node->str_value_, param_node->str_len_, malloc_pool); \
if (OB_ISNULL(copied_str)) { \
yyerror(NULL, yyextra, "No more space for mallocing"); \
return ERROR; \
} else { \
int pos = 1; \
for (; pos < param_node->str_len_ && ISSPACE(copied_str[pos]); pos++) \
; \
copied_str[--pos] = '-'; \
param_node->value_ = ob_strntoll(copied_str + pos, param_node->str_len_ - pos, 10, NULL, &errno); \
if (ERANGE == errno) { \
param_node->type_ = T_NUMBER; \
token_ret = DECIMAL_VAL; \
} \
} \
} else { \
uint64_t value = ob_strntoull(param_node->str_value_, param_node->str_len_, 10, NULL, &errno); \
param_node->value_ = value; \
if (ERANGE == errno) { \
param_node->type_ = T_NUMBER; \
token_ret = DECIMAL_VAL; \
} else if (value > INT64_MAX) { \
param_node->type_ = T_UINT64; \
} \
} \
} while (0);
#define RM_MULTI_STMT_END_P(p) \
do { \
int pos = p->no_param_sql_len_ - 1; \
for (; pos >= 0 && ISSPACE(p->no_param_sql_[pos]); --pos) \
; \
p->no_param_sql_len_ = pos + 1; \
p->no_param_sql_[p->no_param_sql_len_] = '\0'; \
p->end_col_ = p->no_param_sql_len_; \
} while (0);
#define malloc_select_node(node, malloc_pool) \
malloc_non_terminal_node(node, \
malloc_pool, \
T_SELECT, \
PARSE_SELECT_MAX_IDX, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL);
// only used by setup_token_pos_info_and_dup_string for now
#define check_ret(stmt, loc, extra) \
int ret = (stmt); \
if (OB_UNLIKELY(ret != OB_PARSER_SUCCESS)) { \
yyerror((loc), (extra), "setup token pos info failed ret: %d\n", ret); \
}
#define REPUT_TOKEN_NEG_SIGN(TOKEN) \
ParseResult* p = (ParseResult*)yyextra; \
REPUT_NEG_SIGN(p); \
return TOKEN;
extern void setup_token_pos_info(ParseNode* node, int off, int len);
// setup pos info and copy sql from p->input_sql_([strat, end]) to node->str_value_
extern int setup_token_pos_info_and_dup_string(ParseNode* node, ParseResult* p, int start, int end);
#ifdef SQL_PARSER_COMPILATION
int add_comment_list(ParseResult* p, const TokenPosInfo* info);
#endif
#endif /* OCEANBASE_SRC_SQL_PARSER_SQL_PARSER_BASE_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

3054
src/sql/parser/type_name.c Normal file

File diff suppressed because it is too large Load Diff