|
22 | 22 |
|
23 | 23 | #include "sql/parse_tree_items.h"
|
24 | 24 |
|
| 25 | +#include <sys/types.h> |
| 26 | + |
| 27 | +#include "m_string.h" |
25 | 28 | #include "my_dbug.h"
|
26 | 29 | #include "my_sqlcommand.h"
|
| 30 | +#include "my_sys.h" |
| 31 | +#include "my_time.h" |
27 | 32 | #include "mysql/udf_registration_types.h"
|
28 | 33 | #include "mysql_com.h"
|
| 34 | +#include "mysqld_error.h" |
29 | 35 | #include "sql/auth/auth_acls.h"
|
30 | 36 | #include "sql/item_cmpfunc.h" // Item_func_eq
|
31 |
| -#include "sql/mysqld.h" // using_udf_functions |
| 37 | +#include "sql/item_create.h" |
| 38 | +#include "sql/mysqld.h" // using_udf_functions |
32 | 39 | #include "sql/parse_tree_nodes.h"
|
33 | 40 | #include "sql/protocol.h"
|
34 | 41 | #include "sql/sp.h"
|
| 42 | +#include "sql/sp_head.h" |
35 | 43 | #include "sql/sp_pcontext.h" // sp_pcontext
|
| 44 | +#include "sql/sql_class.h" |
| 45 | +#include "sql/sql_error.h" |
| 46 | +#include "sql/sql_lex.h" |
| 47 | +#include "sql/sql_list.h" |
36 | 48 | #include "sql/sql_udf.h"
|
| 49 | +#include "sql/system_variables.h" |
37 | 50 | #include "sql/table.h"
|
38 | 51 | #include "sql/trigger_def.h"
|
| 52 | +#include "sql_string.h" |
| 53 | +#include "template_utils.h" |
39 | 54 |
|
40 | 55 | /**
|
41 | 56 | Apply a truth test to given expression. Either the expression can implement
|
@@ -150,7 +165,7 @@ bool PTI_table_wild::itemize(Parse_context *pc, Item **item) {
|
150 | 165 | if (super::itemize(pc, item)) return true;
|
151 | 166 |
|
152 | 167 | schema = pc->thd->get_protocol()->has_client_capability(CLIENT_NO_SCHEMA)
|
153 |
| - ? NullS |
| 168 | + ? nullptr |
154 | 169 | : schema;
|
155 | 170 | *item = new (pc->mem_root) Item_field(POS(), schema, table, "*");
|
156 | 171 | if (*item == NULL || (*item)->itemize(pc, item)) return true;
|
@@ -395,7 +410,8 @@ bool PTI_simple_ident_q_3d::itemize(Parse_context *pc, Item **res) {
|
395 | 410 | } else {
|
396 | 411 | *res = new (pc->mem_root) Item_ref(POS(), schema, table, field);
|
397 | 412 | }
|
398 |
| - return *res == nullptr || (*res)->itemize(pc, res); |
| 413 | + if (*res == nullptr) return true; |
| 414 | + return (*res)->itemize(pc, res); |
399 | 415 | }
|
400 | 416 |
|
401 | 417 | bool PTI_simple_ident_q_2d::itemize(Parse_context *pc, Item **res) {
|
@@ -449,9 +465,267 @@ bool PTI_simple_ident_q_2d::itemize(Parse_context *pc, Item **res) {
|
449 | 465 | return false;
|
450 | 466 | }
|
451 | 467 |
|
| 468 | +bool PTI_simple_ident_nospvar_ident::itemize(Parse_context *pc, Item **res) { |
| 469 | + if (super::itemize(pc, res)) return true; |
| 470 | + |
| 471 | + if ((pc->select->parsing_place != CTX_HAVING) || |
| 472 | + (pc->select->get_in_sum_expr() > 0)) { |
| 473 | + *res = new (pc->mem_root) Item_field(POS(), nullptr, nullptr, ident.str); |
| 474 | + } else { |
| 475 | + *res = new (pc->mem_root) Item_ref(POS(), nullptr, nullptr, ident.str); |
| 476 | + } |
| 477 | + if (*res == nullptr) return true; |
| 478 | + return (*res)->itemize(pc, res); |
| 479 | +} |
| 480 | + |
452 | 481 | bool PTI_truth_transform::itemize(Parse_context *pc, Item **res) {
|
453 | 482 | if (super::itemize(pc, res) || expr->itemize(pc, &expr)) return true;
|
454 | 483 |
|
455 | 484 | *res = change_truth_value_of_condition(pc, expr, truth_test);
|
456 |
| - return *res == NULL; |
| 485 | + return *res == nullptr; |
| 486 | +} |
| 487 | + |
| 488 | +bool PTI_function_call_nonkeyword_now::itemize(Parse_context *pc, Item **res) { |
| 489 | + if (super::itemize(pc, res)) return true; |
| 490 | + |
| 491 | + pc->thd->lex->safe_to_cache_query = false; |
| 492 | + return false; |
| 493 | +} |
| 494 | + |
| 495 | +bool PTI_text_literal_text_string::itemize(Parse_context *pc, Item **res) { |
| 496 | + if (super::itemize(pc, res)) return true; |
| 497 | + |
| 498 | + THD *thd = pc->thd; |
| 499 | + LEX_STRING tmp; |
| 500 | + const CHARSET_INFO *cs_con = thd->variables.collation_connection; |
| 501 | + const CHARSET_INFO *cs_cli = thd->variables.character_set_client; |
| 502 | + uint repertoire = is_7bit && my_charset_is_ascii_based(cs_cli) |
| 503 | + ? MY_REPERTOIRE_ASCII |
| 504 | + : MY_REPERTOIRE_UNICODE30; |
| 505 | + if (thd->charset_is_collation_connection || |
| 506 | + (repertoire == MY_REPERTOIRE_ASCII && my_charset_is_ascii_based(cs_con))) |
| 507 | + tmp = literal; |
| 508 | + else { |
| 509 | + if (thd->convert_string(&tmp, cs_con, literal.str, literal.length, cs_cli)) |
| 510 | + return true; |
| 511 | + } |
| 512 | + init(tmp.str, tmp.length, cs_con, DERIVATION_COERCIBLE, repertoire); |
| 513 | + return false; |
| 514 | +} |
| 515 | + |
| 516 | +bool PTI_text_literal_concat::itemize(Parse_context *pc, Item **res) { |
| 517 | + Item *tmp_head; |
| 518 | + if (super::itemize(pc, res) || head->itemize(pc, &tmp_head)) return true; |
| 519 | + |
| 520 | + DBUG_ASSERT(tmp_head->type() == STRING_ITEM); |
| 521 | + Item_string *head_str = down_cast<Item_string *>(tmp_head); |
| 522 | + head_str->append(literal.str, literal.length); |
| 523 | + if ((head_str->collation.repertoire & MY_REPERTOIRE_EXTENDED) == 0) { |
| 524 | + // If the string has been pure ASCII so far, check the new part. |
| 525 | + const CHARSET_INFO *cs = pc->thd->variables.collation_connection; |
| 526 | + head_str->collation.repertoire |= |
| 527 | + my_string_repertoire(cs, literal.str, literal.length); |
| 528 | + } |
| 529 | + *res = head_str; |
| 530 | + return false; |
| 531 | +} |
| 532 | + |
| 533 | +bool PTI_temporal_literal::itemize(Parse_context *pc, Item **res) { |
| 534 | + if (super::itemize(pc, res)) return true; |
| 535 | + |
| 536 | + *res = create_temporal_literal(pc->thd, literal.str, literal.length, cs, |
| 537 | + field_type, true); |
| 538 | + return *res == nullptr; |
| 539 | +} |
| 540 | + |
| 541 | +bool PTI_variable_aux_set_var::itemize(Parse_context *pc, Item **res) { |
| 542 | + if (super::itemize(pc, res)) return true; |
| 543 | + |
| 544 | + LEX *lex = pc->thd->lex; |
| 545 | + if (!lex->parsing_options.allows_variable) { |
| 546 | + my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); |
| 547 | + return true; |
| 548 | + } |
| 549 | + lex->set_uncacheable(pc->select, UNCACHEABLE_RAND); |
| 550 | + return lex->set_var_list.push_back(this); |
| 551 | +} |
| 552 | + |
| 553 | +bool PTI_variable_aux_ident_or_text::itemize(Parse_context *pc, Item **res) { |
| 554 | + if (super::itemize(pc, res)) return true; |
| 555 | + |
| 556 | + LEX *lex = pc->thd->lex; |
| 557 | + if (!lex->parsing_options.allows_variable) { |
| 558 | + my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); |
| 559 | + return true; |
| 560 | + } |
| 561 | + lex->set_uncacheable(pc->select, UNCACHEABLE_RAND); |
| 562 | + return false; |
| 563 | +} |
| 564 | + |
| 565 | +bool PTI_variable_aux_3d::itemize(Parse_context *pc, Item **res) { |
| 566 | + if (super::itemize(pc, res)) return true; |
| 567 | + |
| 568 | + LEX *lex = pc->thd->lex; |
| 569 | + if (!lex->parsing_options.allows_variable) { |
| 570 | + my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); |
| 571 | + return true; |
| 572 | + } |
| 573 | + |
| 574 | + /* disallow "SELECT @@global.global.variable" */ |
| 575 | + if (ident1.str && ident2.str && check_reserved_words(ident1.str)) { |
| 576 | + error(pc, ident1_pos); |
| 577 | + return true; |
| 578 | + } |
| 579 | + |
| 580 | + LEX_STRING *domain; |
| 581 | + LEX_STRING *variable; |
| 582 | + if (ident2.str && !is_key_cache_variable_suffix(ident2.str)) { |
| 583 | + LEX_STRING component_var; |
| 584 | + domain = &ident1; |
| 585 | + variable = &ident2; |
| 586 | + String tmp_name; |
| 587 | + if (tmp_name.reserve(domain->length + 1 + variable->length + 1) || |
| 588 | + tmp_name.append(domain->str) || tmp_name.append('.') || |
| 589 | + tmp_name.append(variable->str)) |
| 590 | + return true; // OOM |
| 591 | + component_var.str = tmp_name.c_ptr(); |
| 592 | + component_var.length = tmp_name.length(); |
| 593 | + variable->str = nullptr; |
| 594 | + variable->length = 0; |
| 595 | + *res = get_system_var(pc, var_type, component_var, *variable); |
| 596 | + } else |
| 597 | + *res = get_system_var(pc, var_type, ident1, ident2); |
| 598 | + if (*res == nullptr) return true; |
| 599 | + if (is_identifier(ident1, "warning_count") || |
| 600 | + is_identifier(ident1, "error_count")) { |
| 601 | + /* |
| 602 | + "Diagnostics variable" used in a non-diagnostics statement. |
| 603 | + Save the information we need for the former, but clear the |
| 604 | + rest of the diagnostics area on account of the latter. |
| 605 | + See reset_condition_info(). |
| 606 | + */ |
| 607 | + lex->keep_diagnostics = DA_KEEP_COUNTS; |
| 608 | + } |
| 609 | + if (!down_cast<Item_func_get_system_var *>(*res)->is_written_to_binlog()) |
| 610 | + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_VARIABLE); |
| 611 | + |
| 612 | + return false; |
| 613 | +} |
| 614 | + |
| 615 | +bool PTI_count_sym::itemize(Parse_context *pc, Item **res) { |
| 616 | + args[0] = new (pc->mem_root) Item_int(int32{0}, 1); |
| 617 | + if (args[0] == nullptr) return true; |
| 618 | + return super::itemize(pc, res); |
| 619 | +} |
| 620 | + |
| 621 | +bool PTI_in_sum_expr::itemize(Parse_context *pc, Item **res) { |
| 622 | + pc->select->in_sum_expr++; |
| 623 | + if (super::itemize(pc, res) || expr->itemize(pc, &expr)) return true; |
| 624 | + pc->select->in_sum_expr--; |
| 625 | + *res = expr; |
| 626 | + return false; |
| 627 | +} |
| 628 | + |
| 629 | +bool PTI_odbc_date::itemize(Parse_context *pc, Item **res) { |
| 630 | + if (super::itemize(pc, res) || expr->itemize(pc, &expr)) return true; |
| 631 | + |
| 632 | + *res = nullptr; |
| 633 | + /* |
| 634 | + If "expr" is reasonably short pure ASCII string literal, |
| 635 | + try to parse known ODBC style date, time or timestamp literals, |
| 636 | + e.g: |
| 637 | + SELECT {d'2001-01-01'}; |
| 638 | + SELECT {t'10:20:30'}; |
| 639 | + SELECT {ts'2001-01-01 10:20:30'}; |
| 640 | + */ |
| 641 | + if (expr->type() == Item::STRING_ITEM && |
| 642 | + expr->collation.repertoire == MY_REPERTOIRE_ASCII) { |
| 643 | + String buf; |
| 644 | + String *tmp_str = expr->val_str(&buf); |
| 645 | + if (tmp_str->length() < MAX_DATE_STRING_REP_LENGTH * 4) { |
| 646 | + enum_field_types type = MYSQL_TYPE_STRING; |
| 647 | + ErrConvString str(tmp_str); |
| 648 | + LEX_STRING *ls = &ident; |
| 649 | + if (ls->length == 1) { |
| 650 | + if (ls->str[0] == 'd') /* {d'2001-01-01'} */ |
| 651 | + type = MYSQL_TYPE_DATE; |
| 652 | + else if (ls->str[0] == 't') /* {t'10:20:30'} */ |
| 653 | + type = MYSQL_TYPE_TIME; |
| 654 | + } else if (ls->length == 2) /* {ts'2001-01-01 10:20:30'} */ |
| 655 | + { |
| 656 | + if (ls->str[0] == 't' && ls->str[1] == 's') type = MYSQL_TYPE_DATETIME; |
| 657 | + } |
| 658 | + if (type != MYSQL_TYPE_STRING) |
| 659 | + *res = create_temporal_literal(pc->thd, str.ptr(), str.length(), |
| 660 | + system_charset_info, type, false); |
| 661 | + } |
| 662 | + } |
| 663 | + if (*res == nullptr) *res = expr; |
| 664 | + return false; |
| 665 | +} |
| 666 | + |
| 667 | +bool PTI_limit_option_ident::itemize(Parse_context *pc, Item **res) { |
| 668 | + if (super::itemize(pc, res)) return true; |
| 669 | + |
| 670 | + LEX *lex = pc->thd->lex; |
| 671 | + sp_head *sp = lex->sphead; |
| 672 | + const char *query_start_ptr = |
| 673 | + sp ? sp->m_parser_data.get_current_stmt_start_ptr() : nullptr; |
| 674 | + |
| 675 | + Item_splocal *v = create_item_for_sp_var( |
| 676 | + pc->thd, ident, nullptr, query_start_ptr, ident_loc.start, ident_loc.end); |
| 677 | + if (v == nullptr) return true; |
| 678 | + |
| 679 | + lex->safe_to_cache_query = false; |
| 680 | + |
| 681 | + if (v->type() != Item::INT_ITEM) { |
| 682 | + my_error(ER_WRONG_SPVAR_TYPE_IN_LIMIT, MYF(0)); |
| 683 | + return true; |
| 684 | + } |
| 685 | + |
| 686 | + v->limit_clause_param = true; |
| 687 | + *res = v; |
| 688 | + return false; |
| 689 | +} |
| 690 | + |
| 691 | +bool PTI_limit_option_param_marker::itemize(Parse_context *pc, Item **res) { |
| 692 | + Item *tmp_param; |
| 693 | + if (super::itemize(pc, res) || param_marker->itemize(pc, &tmp_param)) |
| 694 | + return true; |
| 695 | + |
| 696 | + /* |
| 697 | + The Item_param::type() function may return various values, so we can't |
| 698 | + simply compare tmp_param->type() with some constant, cast tmp_param |
| 699 | + to Item_param* and assign the result back to param_marker. |
| 700 | + OTOH we ensure that Item_param::itemize() always substitute the output |
| 701 | + parameter with "this" pointer of Item_param object, so we can skip |
| 702 | + the check and the assignment. |
| 703 | + */ |
| 704 | + DBUG_ASSERT(tmp_param == param_marker); |
| 705 | + |
| 706 | + param_marker->limit_clause_param = true; |
| 707 | + *res = param_marker; |
| 708 | + return false; |
| 709 | +} |
| 710 | + |
| 711 | +bool PTI_context::itemize(Parse_context *pc, Item **res) { |
| 712 | + if (super::itemize(pc, res)) return true; |
| 713 | + |
| 714 | + pc->select->parsing_place = m_parsing_place; |
| 715 | + |
| 716 | + if (expr->itemize(pc, &expr)) return true; |
| 717 | + |
| 718 | + if (!expr->is_bool_func()) { |
| 719 | + expr = make_condition(pc, expr); |
| 720 | + if (expr == nullptr) return true; |
| 721 | + } |
| 722 | + |
| 723 | + // Ensure we're resetting parsing place of the right select |
| 724 | + DBUG_ASSERT(pc->select->parsing_place == m_parsing_place); |
| 725 | + pc->select->parsing_place = CTX_NONE; |
| 726 | + DBUG_ASSERT(expr != nullptr); |
| 727 | + expr->apply_is_true(); |
| 728 | + |
| 729 | + *res = expr; |
| 730 | + return false; |
457 | 731 | }
|
0 commit comments