Commit 2a33d248 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-15975 PL/SQL parser does not understand historical queries

Merging the following features from sql_yacc.yy to sql_yacc_ora.yy:

- system versioning
- column compression
- table value constructor
- spatial predicate WITHIN
- DELETE_DOMAIN_ID
parent 395c8ca7
SET sql_mode=ORACLE;
SET column_compression_zlib_wrap=true;
CREATE TABLE t1 (a BLOB COMPRESSED);
INSERT INTO t1 VALUES (REPEAT('a',10000));
SELECT DATA_LENGTH<100 AS c FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test';
c
1
DROP TABLE t1;
SELECT WITHIN(POINT(1,1), POINT(1,1));
WITHIN(POINT(1,1), POINT(1,1))
1
SELECT WITHIN(POINT(1,1), POINT(0,0));
WITHIN(POINT(1,1), POINT(0,0))
0
This diff is collapsed.
SET sql_mode=ORACLE;
#
# MDEV-15975 PL/SQL parser does not understand historical queries
#
CREATE TABLE t1 (a INT) WITH SYSTEM VERSIONING;
INSERT INTO t1 VALUES (10);
DELETE FROM t1;
INSERT INTO t1 VALUES (20);
SELECT * FROM t1 FOR SYSTEM_TIME ALL;
a
10
20
SELECT * FROM t1 FOR SYSTEM_TIME AS OF (NOW()+INTERVAL 10 YEAR);
a
20
DROP TABLE t1;
--source include/have_innodb.inc
--source include/have_csv.inc
SET sql_mode=ORACLE;
SET column_compression_zlib_wrap=true;
CREATE TABLE t1 (a BLOB COMPRESSED);
INSERT INTO t1 VALUES (REPEAT('a',10000));
SELECT DATA_LENGTH<100 AS c FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test';
DROP TABLE t1;
-- source include/have_geometry.inc
SELECT WITHIN(POINT(1,1), POINT(1,1));
SELECT WITHIN(POINT(1,1), POINT(0,0));
This diff is collapsed.
SET sql_mode=ORACLE;
--echo #
--echo # MDEV-15975 PL/SQL parser does not understand historical queries
--echo #
CREATE TABLE t1 (a INT) WITH SYSTEM VERSIONING;
INSERT INTO t1 VALUES (10);
DELETE FROM t1;
INSERT INTO t1 VALUES (20);
SELECT * FROM t1 FOR SYSTEM_TIME ALL;
SELECT * FROM t1 FOR SYSTEM_TIME AS OF (NOW()+INTERVAL 10 YEAR);
DROP TABLE t1;
......@@ -31,6 +31,7 @@
#include "sql_select.h"
#include "sql_cte.h"
#include "sql_signal.h"
#include "sql_partition.h"
void LEX::parse_error(uint err_number)
......@@ -7977,3 +7978,171 @@ bool Lex_ident_sys_st::convert(THD *thd,
length= tmp.length;
return false;
}
bool Lex_ident_sys_st::to_size_number(THD *thd, ulonglong *to) const
{
ulonglong number;
uint text_shift_number= 0;
longlong prefix_number;
const char *start_ptr= str;
size_t str_len= length;
const char *end_ptr= start_ptr + str_len;
int error;
prefix_number= my_strtoll10(start_ptr, (char**) &end_ptr, &error);
if (likely((start_ptr + str_len - 1) == end_ptr))
{
switch (end_ptr[0])
{
case 'g':
case 'G': text_shift_number+=30; break;
case 'm':
case 'M': text_shift_number+=20; break;
case 'k':
case 'K': text_shift_number+=10; break;
default:
my_error(ER_WRONG_SIZE_NUMBER, MYF(0));
return true;
}
if (unlikely(prefix_number >> 31))
{
my_error(ER_SIZE_OVERFLOW_ERROR, MYF(0));
return true;
}
number= prefix_number << text_shift_number;
}
else
{
my_error(ER_WRONG_SIZE_NUMBER, MYF(0));
return true;
}
*to= number;
return false;
}
bool LEX::part_values_current(THD *thd)
{
partition_element *elem= part_info->curr_part_elem;
if (!is_partition_management())
{
if (unlikely(part_info->part_type != VERSIONING_PARTITION))
{
my_error(ER_PARTITION_WRONG_TYPE, MYF(0), "SYSTEM_TIME");
return true;
}
}
else
{
DBUG_ASSERT(create_last_non_select_table);
DBUG_ASSERT(create_last_non_select_table->table_name.str);
// FIXME: other ALTER commands?
my_error(ER_VERS_WRONG_PARTS, MYF(0),
create_last_non_select_table->table_name.str);
return true;
}
elem->type(partition_element::CURRENT);
DBUG_ASSERT(part_info->vers_info);
part_info->vers_info->now_part= elem;
if (unlikely(part_info->init_column_part(thd)))
return true;
return false;
}
bool LEX::part_values_history(THD *thd)
{
partition_element *elem= part_info->curr_part_elem;
if (!is_partition_management())
{
if (unlikely(part_info->part_type != VERSIONING_PARTITION))
{
my_error(ER_PARTITION_WRONG_TYPE, MYF(0), "SYSTEM_TIME");
return true;
}
}
else
{
part_info->vers_init_info(thd);
elem->id= UINT_MAX32;
}
DBUG_ASSERT(part_info->vers_info);
if (unlikely(part_info->vers_info->now_part))
{
DBUG_ASSERT(create_last_non_select_table);
DBUG_ASSERT(create_last_non_select_table->table_name.str);
my_error(ER_VERS_WRONG_PARTS, MYF(0),
create_last_non_select_table->table_name.str);
return true;
}
elem->type(partition_element::HISTORY);
if (unlikely(part_info->init_column_part(thd)))
return true;
return false;
}
bool LEX::last_field_generated_always_as_row_start_or_end(Lex_ident *p,
const char *type,
uint flag)
{
if (unlikely(p->str))
{
my_error(ER_VERS_DUPLICATE_ROW_START_END, MYF(0), type,
last_field->field_name.str);
return true;
}
last_field->flags|= (flag | NOT_NULL_FLAG);
DBUG_ASSERT(p);
*p= last_field->field_name;
return false;
}
bool LEX::last_field_generated_always_as_row_start()
{
Vers_parse_info &info= vers_get_info();
Lex_ident *p= &info.as_row.start;
return last_field_generated_always_as_row_start_or_end(p, "START",
VERS_SYS_START_FLAG);
}
bool LEX::last_field_generated_always_as_row_end()
{
Vers_parse_info &info= vers_get_info();
Lex_ident *p= &info.as_row.end;
return last_field_generated_always_as_row_start_or_end(p, "END",
VERS_SYS_END_FLAG);
}
bool LEX::tvc_finalize()
{
mysql_init_select(this);
if (unlikely(!(current_select->tvc=
new (thd->mem_root)
table_value_constr(many_values,
current_select,
current_select->options))))
return true;
many_values.empty();
return false;
}
bool LEX::tvc_finalize_derived()
{
derived_tables|= DERIVED_SUBQUERY;
if (unlikely(!expr_allows_subselect || sql_command == (int)SQLCOM_PURGE))
{
thd->parse_error();
return true;
}
if (current_select->linkage == GLOBAL_OPTIONS_TYPE ||
unlikely(mysql_new_select(this, 1, NULL)))
return true;
current_select->linkage= DERIVED_TABLE_TYPE;
return tvc_finalize();
}
......@@ -143,6 +143,7 @@ struct Lex_ident_sys_st: public LEX_CSTRING
bool convert(THD *thd, const LEX_CSTRING *str, CHARSET_INFO *cs);
bool copy_or_convert(THD *thd, const Lex_ident_cli_st *str, CHARSET_INFO *cs);
bool is_null() const { return str == NULL; }
bool to_size_number(THD *thd, ulonglong *to) const;
};
......@@ -3262,7 +3263,10 @@ struct LEX: public Query_tables_list
void restore_backup_query_tables_list(Query_tables_list *backup);
bool table_or_sp_used();
bool is_partition_management() const;
bool part_values_current(THD *thd);
bool part_values_history(THD *thd);
/**
@brief check if the statement is a single-level join
......@@ -3294,6 +3298,11 @@ struct LEX: public Query_tables_list
void init_last_field(Column_definition *field, const LEX_CSTRING *name,
const CHARSET_INFO *cs);
bool last_field_generated_always_as_row_start_or_end(Lex_ident *p,
const char *type,
uint flags);
bool last_field_generated_always_as_row_start();
bool last_field_generated_always_as_row_end();
bool set_bincmp(CHARSET_INFO *cs, bool bin);
bool get_dynamic_sql_string(LEX_CSTRING *dst, String *buffer);
......@@ -3919,6 +3928,15 @@ struct LEX: public Query_tables_list
}
return false;
}
void tvc_start()
{
field_list.empty();
many_values.empty();
insert_list= 0;
}
bool tvc_finalize();
bool tvc_finalize_derived();
};
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment