|
16 | 16 | #ifndef PARSE_TREE_NODES_INCLUDED
|
17 | 17 | #define PARSE_TREE_NODES_INCLUDED
|
18 | 18 |
|
| 19 | +#include <cctype> // std::isspace |
| 20 | +#include <limits> |
19 | 21 | #include <stddef.h>
|
20 | 22 | #include <sys/types.h>
|
21 | 23 |
|
|
56 | 58 | #include "sql/sql_admin.h" // Sql_cmd_shutdown etc.
|
57 | 59 | #include "sql/sql_alter.h"
|
58 | 60 | #include "sql/sql_class.h" // THD
|
| 61 | +#include "sql/sql_cmd_srs.h" |
59 | 62 | #include "sql/sql_exchange.h"
|
60 | 63 | #include "sql/sql_lex.h" // LEX
|
61 | 64 | #include "sql/sql_list.h"
|
@@ -2723,6 +2726,225 @@ class PT_shutdown final : public Parse_tree_root
|
2723 | 2726 | };
|
2724 | 2727 |
|
2725 | 2728 |
|
| 2729 | +/** |
| 2730 | + Top-level node for the CREATE [OR REPLACE] SPATIAL REFERENCE SYSTEM statement. |
| 2731 | +
|
| 2732 | + @ingroup ptn_stmt |
| 2733 | +*/ |
| 2734 | +class PT_create_srs final : public Parse_tree_root |
| 2735 | +{ |
| 2736 | + /// The SQL command object. |
| 2737 | + Sql_cmd_create_srs sql_cmd; |
| 2738 | + /// Whether OR REPLACE is specified. |
| 2739 | + bool m_or_replace; |
| 2740 | + /// Whether IF NOT EXISTS is specified. |
| 2741 | + bool m_if_not_exists; |
| 2742 | + /// SRID of the SRS to create. |
| 2743 | + /// |
| 2744 | + /// The range is larger than that of gis::srid_t, so it must be |
| 2745 | + /// verified to be less than the uint32 maximum value. |
| 2746 | + unsigned long long m_srid; |
| 2747 | + /// All attributes except SRID. |
| 2748 | + const Sql_cmd_srs_attributes &m_attributes; |
| 2749 | + |
| 2750 | + /// Check if a UTF-8 string contains control characters. |
| 2751 | + /// |
| 2752 | + /// @note This function only checks single byte control characters (U+0000 to |
| 2753 | + /// U+001F, and U+007F). There are some control characters at U+0080 to U+00A0 |
| 2754 | + /// that are not detected by this function. |
| 2755 | + /// |
| 2756 | + /// @param str The string. |
| 2757 | + /// @param length Length of the string. |
| 2758 | + /// |
| 2759 | + /// @retval false The string contains no control characters. |
| 2760 | + /// @retval true The string contains at least one control character. |
| 2761 | + bool contains_control_char(char *str, size_t length) |
| 2762 | + { |
| 2763 | + for (size_t pos= 0; pos < length; pos++) |
| 2764 | + { |
| 2765 | + if (std::iscntrl(str[pos])) |
| 2766 | + return true; |
| 2767 | + } |
| 2768 | + return false; |
| 2769 | + } |
| 2770 | + |
| 2771 | +public: |
| 2772 | + PT_create_srs (unsigned long long srid, |
| 2773 | + const Sql_cmd_srs_attributes &attributes, |
| 2774 | + bool or_replace, bool if_not_exists) |
| 2775 | + : m_or_replace(or_replace), m_if_not_exists(if_not_exists), m_srid(srid), |
| 2776 | + m_attributes(attributes) |
| 2777 | + {} |
| 2778 | + |
| 2779 | + Sql_cmd *make_cmd(THD *thd) override |
| 2780 | + { |
| 2781 | + // Note: This function hard-codes the maximum length of various |
| 2782 | + // strings. These lengths must match those in |
| 2783 | + // sql/dd/impl/tables/spatial_reference_systems.cc. |
| 2784 | + |
| 2785 | + thd->lex->sql_command= SQLCOM_CREATE_SRS; |
| 2786 | + |
| 2787 | + if (m_srid > std::numeric_limits<gis::srid_t>::max()) |
| 2788 | + { |
| 2789 | + my_error(ER_DATA_OUT_OF_RANGE, MYF(0), "SRID", |
| 2790 | + m_or_replace ? "CREATE OR REPLACE SPATIAL REFERENCE SYSTEM" |
| 2791 | + : "CREATE SPATIAL REFERENCE SYSTEM"); |
| 2792 | + return nullptr; |
| 2793 | + } |
| 2794 | + if (m_srid == 0) |
| 2795 | + { |
| 2796 | + my_error(ER_CANT_MODIFY_SRID_0, MYF(0)); |
| 2797 | + return nullptr; |
| 2798 | + } |
| 2799 | + |
| 2800 | + if (m_attributes.srs_name.str == nullptr) |
| 2801 | + { |
| 2802 | + my_error(ER_SRS_MISSING_MANDATORY_ATTRIBUTE, MYF(0), "NAME"); |
| 2803 | + return nullptr; |
| 2804 | + } |
| 2805 | + MYSQL_LEX_STRING srs_name_utf8= {nullptr, 0}; |
| 2806 | + if (thd->convert_string(&srs_name_utf8, |
| 2807 | + &my_charset_utf8_bin, |
| 2808 | + m_attributes.srs_name.str, |
| 2809 | + m_attributes.srs_name.length, |
| 2810 | + thd->charset())) |
| 2811 | + { |
| 2812 | + /* purecov: begin inspected */ |
| 2813 | + my_error(ER_OOM, MYF(0)); |
| 2814 | + return nullptr; |
| 2815 | + /* purecov: end */ |
| 2816 | + } |
| 2817 | + if (srs_name_utf8.length == 0 || |
| 2818 | + std::isspace(srs_name_utf8.str[0]) || |
| 2819 | + std::isspace(srs_name_utf8.str[srs_name_utf8.length - 1])) |
| 2820 | + { |
| 2821 | + my_error(ER_SRS_NAME_CANT_BE_EMPTY_OR_WHITESPACE, MYF(0)); |
| 2822 | + return nullptr; |
| 2823 | + } |
| 2824 | + if (contains_control_char(srs_name_utf8.str, srs_name_utf8.length)) |
| 2825 | + { |
| 2826 | + my_error(ER_SRS_INVALID_CHARACTER_IN_ATTRIBUTE, MYF(0), "NAME"); |
| 2827 | + return nullptr; |
| 2828 | + } |
| 2829 | + String srs_name_str(srs_name_utf8.str, srs_name_utf8.length, |
| 2830 | + &my_charset_utf8_bin); |
| 2831 | + if (srs_name_str.numchars() > 80) |
| 2832 | + { |
| 2833 | + my_error(ER_SRS_ATTRIBUTE_STRING_TOO_LONG, MYF(0), "NAME", 80); |
| 2834 | + return nullptr; |
| 2835 | + } |
| 2836 | + |
| 2837 | + if (m_attributes.definition.str == nullptr) |
| 2838 | + { |
| 2839 | + my_error(ER_SRS_MISSING_MANDATORY_ATTRIBUTE, MYF(0), "DEFINITION"); |
| 2840 | + return nullptr; |
| 2841 | + } |
| 2842 | + MYSQL_LEX_STRING definition_utf8= {nullptr, 0}; |
| 2843 | + if (thd->convert_string(&definition_utf8, |
| 2844 | + &my_charset_utf8_bin, |
| 2845 | + m_attributes.definition.str, |
| 2846 | + m_attributes.definition.length, |
| 2847 | + thd->charset())) |
| 2848 | + { |
| 2849 | + /* purecov: begin inspected */ |
| 2850 | + my_error(ER_OOM, MYF(0)); |
| 2851 | + return nullptr; |
| 2852 | + /* purecov: end */ |
| 2853 | + } |
| 2854 | + String definition_str(definition_utf8.str, definition_utf8.length, |
| 2855 | + &my_charset_utf8_bin); |
| 2856 | + if (contains_control_char(definition_utf8.str, definition_utf8.length)) |
| 2857 | + { |
| 2858 | + my_error(ER_SRS_INVALID_CHARACTER_IN_ATTRIBUTE, MYF(0), "DEFINITION"); |
| 2859 | + return nullptr; |
| 2860 | + } |
| 2861 | + if (definition_str.numchars() > 4096) |
| 2862 | + { |
| 2863 | + my_error(ER_SRS_ATTRIBUTE_STRING_TOO_LONG, MYF(0), "DEFINITION", 4096); |
| 2864 | + return nullptr; |
| 2865 | + } |
| 2866 | + |
| 2867 | + MYSQL_LEX_STRING organization_utf8= {nullptr, 0}; |
| 2868 | + if (m_attributes.organization.str != nullptr) |
| 2869 | + { |
| 2870 | + if (thd->convert_string(&organization_utf8, |
| 2871 | + &my_charset_utf8_bin, |
| 2872 | + m_attributes.organization.str, |
| 2873 | + m_attributes.organization.length, |
| 2874 | + thd->charset())) |
| 2875 | + { |
| 2876 | + /* purecov: begin inspected */ |
| 2877 | + my_error(ER_OOM, MYF(0)); |
| 2878 | + return nullptr; |
| 2879 | + /* purecov: end */ |
| 2880 | + } |
| 2881 | + if (organization_utf8.length == 0 || |
| 2882 | + std::isspace(organization_utf8.str[0]) || |
| 2883 | + std::isspace(organization_utf8.str[organization_utf8.length - 1])) |
| 2884 | + { |
| 2885 | + my_error(ER_SRS_ORGANIZATION_CANT_BE_EMPTY_OR_WHITESPACE, MYF(0)); |
| 2886 | + return nullptr; |
| 2887 | + } |
| 2888 | + String organization_str(organization_utf8.str, organization_utf8.length, |
| 2889 | + &my_charset_utf8_bin); |
| 2890 | + if (contains_control_char(organization_utf8.str, |
| 2891 | + organization_utf8.length)) |
| 2892 | + { |
| 2893 | + my_error(ER_SRS_INVALID_CHARACTER_IN_ATTRIBUTE, MYF(0), "ORGANIZATION"); |
| 2894 | + return nullptr; |
| 2895 | + } |
| 2896 | + if (organization_str.numchars() > 256) |
| 2897 | + { |
| 2898 | + my_error(ER_SRS_ATTRIBUTE_STRING_TOO_LONG, MYF(0), "ORGANIZATION", 256); |
| 2899 | + return nullptr; |
| 2900 | + } |
| 2901 | + |
| 2902 | + if (m_attributes.organization_coordsys_id > |
| 2903 | + std::numeric_limits<gis::srid_t>::max()) |
| 2904 | + { |
| 2905 | + my_error(ER_DATA_OUT_OF_RANGE, MYF(0), "IDENTIFIED BY", |
| 2906 | + m_or_replace ? "CREATE OR REPLACE SPATIAL REFERENCE SYSTEM" |
| 2907 | + : "CREATE SPATIAL REFERENCE SYSTEM"); |
| 2908 | + return nullptr; |
| 2909 | + } |
| 2910 | + } |
| 2911 | + |
| 2912 | + MYSQL_LEX_STRING description_utf8= {nullptr, 0}; |
| 2913 | + if (m_attributes.description.str != nullptr) |
| 2914 | + { |
| 2915 | + if (thd->convert_string(&description_utf8, |
| 2916 | + &my_charset_utf8_bin, |
| 2917 | + m_attributes.description.str, |
| 2918 | + m_attributes.description.length, |
| 2919 | + thd->charset())) |
| 2920 | + { |
| 2921 | + /* purecov: begin inspected */ |
| 2922 | + my_error(ER_OOM, MYF(0)); |
| 2923 | + return nullptr; |
| 2924 | + /* purecov: end */ |
| 2925 | + } |
| 2926 | + String description_str(description_utf8.str, description_utf8.length, |
| 2927 | + &my_charset_utf8_bin); |
| 2928 | + if (contains_control_char(description_utf8.str, description_utf8.length)) |
| 2929 | + { |
| 2930 | + my_error(ER_SRS_INVALID_CHARACTER_IN_ATTRIBUTE, MYF(0), "DESCRIPTION"); |
| 2931 | + return nullptr; |
| 2932 | + } |
| 2933 | + if (description_str.numchars() > 2048) |
| 2934 | + { |
| 2935 | + my_error(ER_SRS_ATTRIBUTE_STRING_TOO_LONG, MYF(0), "DESCRIPTION", 2048); |
| 2936 | + return nullptr; |
| 2937 | + } |
| 2938 | + } |
| 2939 | + |
| 2940 | + sql_cmd.init(m_or_replace, m_if_not_exists, m_srid, srs_name_utf8, |
| 2941 | + definition_utf8, organization_utf8, |
| 2942 | + m_attributes.organization_coordsys_id, description_utf8); |
| 2943 | + return &sql_cmd; |
| 2944 | + } |
| 2945 | +}; |
| 2946 | + |
| 2947 | + |
2726 | 2948 | /**
|
2727 | 2949 | Top-level node for the ALTER INSTANCE statement
|
2728 | 2950 |
|
|
0 commit comments