You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2612 lines
70 KiB

Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
13 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
13 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
13 years ago
13 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
13 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
13 years ago
Changing field::field_name and Item::name to LEX_CSTRING Benefits of this patch: - Removed a lot of calls to strlen(), especially for field_string - Strings generated by parser are now const strings, less chance of accidently changing a string - Removed a lot of calls with LEX_STRING as parameter (changed to pointer) - More uniform code - Item::name_length was not kept up to date. Now fixed - Several bugs found and fixed (Access to null pointers, access of freed memory, wrong arguments to printf like functions) - Removed a lot of casts from (const char*) to (char*) Changes: - This caused some ABI changes - lex_string_set now uses LEX_CSTRING - Some fucntions are now taking const char* instead of char* - Create_field::change and after changed to LEX_CSTRING - handler::connect_string, comment and engine_name() changed to LEX_CSTRING - Checked printf() related calls to find bugs. Found and fixed several errors in old code. - A lot of changes from LEX_STRING to LEX_CSTRING, especially related to parsing and events. - Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING* - Some changes for char* to const char* - Added printf argument checking for my_snprintf() - Introduced null_clex_str, star_clex_string, temp_lex_str to simplify code - Added item_empty_name and item_used_name to be able to distingush between items that was given an empty name and items that was not given a name This is used in sql_yacc.yy to know when to give an item a name. - select table_name."*' is not anymore same as table_name.* - removed not used function Item::rename() - Added comparision of item->name_length before some calls to my_strcasecmp() to speed up comparison - Moved Item_sp_variable::make_field() from item.h to item.cc - Some minimal code changes to avoid copying to const char * - Fixed wrong error message in wsrep_mysql_parse() - Fixed wrong code in find_field_in_natural_join() where real_item() was set when it shouldn't - ER_ERROR_ON_RENAME was used with extra arguments. - Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already give the error. TODO: - Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c - Change code to not modify LEX_CSTRING for database name (as part of lower_case_table_names)
9 years ago
  1. /*
  2. Copyright (c) 2012, Monty Program Ab
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; version 2 of the License.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program; if not, write to the Free Software
  12. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
  13. #ifdef USE_PRAGMA_IMPLEMENTATION
  14. #pragma implementation // gcc: Class implementation
  15. #endif
  16. #include <my_config.h>
  17. #include <mysql/plugin.h>
  18. #include "ha_cassandra.h"
  19. #include "sql_class.h"
  20. #define DYNCOL_USUAL 20
  21. #define DYNCOL_DELTA 100
  22. #define DYNCOL_USUAL_REC 1024
  23. #define DYNCOL_DELTA_REC 1024
  24. static handler *cassandra_create_handler(handlerton *hton,
  25. TABLE_SHARE *table,
  26. MEM_ROOT *mem_root);
  27. extern int dynamic_column_error_message(enum_dyncol_func_result rc);
  28. handlerton *cassandra_hton;
  29. /*
  30. Hash used to track the number of open tables; variable for example share
  31. methods
  32. */
  33. static HASH cassandra_open_tables;
  34. /* The mutex used to init the hash; variable for example share methods */
  35. mysql_mutex_t cassandra_mutex;
  36. /**
  37. Structure for CREATE TABLE options (table options).
  38. It needs to be called ha_table_option_struct.
  39. The option values can be specified in the CREATE TABLE at the end:
  40. CREATE TABLE ( ... ) *here*
  41. */
  42. struct ha_table_option_struct
  43. {
  44. const char *thrift_host;
  45. int thrift_port;
  46. const char *keyspace;
  47. const char *column_family;
  48. };
  49. ha_create_table_option cassandra_table_option_list[]=
  50. {
  51. /*
  52. one option that takes an arbitrary string
  53. */
  54. HA_TOPTION_STRING("thrift_host", thrift_host),
  55. HA_TOPTION_NUMBER("thrift_port", thrift_port, 9160, 1, 65535, 0),
  56. HA_TOPTION_STRING("keyspace", keyspace),
  57. HA_TOPTION_STRING("column_family", column_family),
  58. HA_TOPTION_END
  59. };
  60. /**
  61. Structure for CREATE TABLE options (field options).
  62. */
  63. struct ha_field_option_struct
  64. {
  65. bool dyncol_field;
  66. };
  67. ha_create_table_option cassandra_field_option_list[]=
  68. {
  69. /*
  70. Collect all other columns as dynamic here,
  71. the valid values are YES/NO, ON/OFF, 1/0.
  72. The default is 0, that is false, no, off.
  73. */
  74. HA_FOPTION_BOOL("DYNAMIC_COLUMN_STORAGE", dyncol_field, 0),
  75. HA_FOPTION_END
  76. };
  77. static MYSQL_THDVAR_ULONG(insert_batch_size, PLUGIN_VAR_RQCMDARG,
  78. "Number of rows in an INSERT batch",
  79. NULL, NULL, /*default*/ 100, /*min*/ 1, /*max*/ 1024*1024*1024, 0);
  80. static MYSQL_THDVAR_ULONG(multiget_batch_size, PLUGIN_VAR_RQCMDARG,
  81. "Number of rows in a multiget(MRR) batch",
  82. NULL, NULL, /*default*/ 100, /*min*/ 1, /*max*/ 1024*1024*1024, 0);
  83. static MYSQL_THDVAR_ULONG(rnd_batch_size, PLUGIN_VAR_RQCMDARG,
  84. "Number of rows in an rnd_read (full scan) batch",
  85. NULL, NULL, /*default*/ 10*1000, /*min*/ 1, /*max*/ 1024*1024*1024, 0);
  86. static MYSQL_THDVAR_ULONG(failure_retries, PLUGIN_VAR_RQCMDARG,
  87. "Number of times to retry Cassandra calls that failed due to timeouts or "
  88. "network communication problems. The default, 0, means not to retry.",
  89. NULL, NULL, /*default*/ 3, /*min*/ 1, /*max*/ 1024*1024*1024, 0);
  90. /* These match values in enum_cassandra_consistency_level */
  91. const char *cassandra_consistency_level[] =
  92. {
  93. "ONE",
  94. "QUORUM",
  95. "LOCAL_QUORUM",
  96. "EACH_QUORUM",
  97. "ALL",
  98. "ANY",
  99. "TWO",
  100. "THREE",
  101. NullS
  102. };
  103. TYPELIB cassandra_consistency_level_typelib= {
  104. array_elements(cassandra_consistency_level) - 1, "",
  105. cassandra_consistency_level, NULL
  106. };
  107. static MYSQL_THDVAR_ENUM(write_consistency, PLUGIN_VAR_RQCMDARG,
  108. "Cassandra consistency level to use for write operations", NULL, NULL,
  109. ONE, &cassandra_consistency_level_typelib);
  110. static MYSQL_THDVAR_ENUM(read_consistency, PLUGIN_VAR_RQCMDARG,
  111. "Cassandra consistency level to use for read operations", NULL, NULL,
  112. ONE, &cassandra_consistency_level_typelib);
  113. mysql_mutex_t cassandra_default_host_lock;
  114. static char* cassandra_default_thrift_host = NULL;
  115. static char cassandra_default_host_buf[256]="";
  116. static void
  117. cassandra_default_thrift_host_update(THD *thd,
  118. struct st_mysql_sys_var* var,
  119. void* var_ptr, /*!< out: where the
  120. formal string goes */
  121. const void* save) /*!< in: immediate result
  122. from check function */
  123. {
  124. const char *new_host= *((char**)save);
  125. const size_t max_len= sizeof(cassandra_default_host_buf);
  126. mysql_mutex_lock(&cassandra_default_host_lock);
  127. if (new_host)
  128. {
  129. strncpy(cassandra_default_host_buf, new_host, max_len-1);
  130. cassandra_default_host_buf[max_len-1]= 0;
  131. cassandra_default_thrift_host= cassandra_default_host_buf;
  132. }
  133. else
  134. {
  135. cassandra_default_host_buf[0]= 0;
  136. cassandra_default_thrift_host= NULL;
  137. }
  138. *((const char**)var_ptr)= cassandra_default_thrift_host;
  139. mysql_mutex_unlock(&cassandra_default_host_lock);
  140. }
  141. static MYSQL_SYSVAR_STR(default_thrift_host, cassandra_default_thrift_host,
  142. PLUGIN_VAR_RQCMDARG,
  143. "Default host for Cassandra thrift connections",
  144. /*check*/NULL,
  145. cassandra_default_thrift_host_update,
  146. /*default*/NULL);
  147. static struct st_mysql_sys_var* cassandra_system_variables[]= {
  148. MYSQL_SYSVAR(insert_batch_size),
  149. MYSQL_SYSVAR(multiget_batch_size),
  150. MYSQL_SYSVAR(rnd_batch_size),
  151. MYSQL_SYSVAR(default_thrift_host),
  152. MYSQL_SYSVAR(write_consistency),
  153. MYSQL_SYSVAR(read_consistency),
  154. MYSQL_SYSVAR(failure_retries),
  155. NULL
  156. };
  157. Cassandra_status_vars cassandra_counters;
  158. /**
  159. @brief
  160. Function we use in the creation of our hash to get key.
  161. */
  162. static uchar* cassandra_get_key(CASSANDRA_SHARE *share, size_t *length,
  163. my_bool not_used __attribute__((unused)))
  164. {
  165. *length=share->table_name_length;
  166. return (uchar*) share->table_name;
  167. }
  168. #ifdef HAVE_PSI_INTERFACE
  169. static PSI_mutex_key ex_key_mutex_example, ex_key_mutex_CASSANDRA_SHARE_mutex;
  170. static PSI_mutex_info all_cassandra_mutexes[]=
  171. {
  172. { &ex_key_mutex_example, "cassandra", PSI_FLAG_GLOBAL},
  173. { &ex_key_mutex_CASSANDRA_SHARE_mutex, "CASSANDRA_SHARE::mutex", 0}
  174. };
  175. static void init_cassandra_psi_keys()
  176. {
  177. const char* category= "cassandra";
  178. int count;
  179. if (PSI_server == NULL)
  180. return;
  181. count= array_elements(all_cassandra_mutexes);
  182. PSI_server->register_mutex(category, all_cassandra_mutexes, count);
  183. }
  184. #endif
  185. static int cassandra_init_func(void *p)
  186. {
  187. DBUG_ENTER("cassandra_init_func");
  188. #ifdef HAVE_PSI_INTERFACE
  189. init_cassandra_psi_keys();
  190. #endif
  191. cassandra_hton= (handlerton *)p;
  192. mysql_mutex_init(ex_key_mutex_example, &cassandra_mutex, MY_MUTEX_INIT_FAST);
  193. (void) my_hash_init(PSI_INSTRUMENT_ME, &cassandra_open_tables,system_charset_info,32,0,0,
  194. (my_hash_get_key) cassandra_get_key,0,0);
  195. cassandra_hton->create= cassandra_create_handler;
  196. /*
  197. Don't specify HTON_CAN_RECREATE in flags. re-create is used by TRUNCATE
  198. TABLE to create an *empty* table from scratch. Cassandra table won't be
  199. emptied if re-created.
  200. */
  201. cassandra_hton->flags= 0;
  202. cassandra_hton->table_options= cassandra_table_option_list;
  203. cassandra_hton->field_options= cassandra_field_option_list;
  204. mysql_mutex_init(0 /* no instrumentation */,
  205. &cassandra_default_host_lock, MY_MUTEX_INIT_FAST);
  206. DBUG_RETURN(0);
  207. }
  208. static int cassandra_done_func(void *p)
  209. {
  210. int error= 0;
  211. DBUG_ENTER("cassandra_done_func");
  212. if (cassandra_open_tables.records)
  213. error= 1;
  214. my_hash_free(&cassandra_open_tables);
  215. mysql_mutex_destroy(&cassandra_mutex);
  216. mysql_mutex_destroy(&cassandra_default_host_lock);
  217. DBUG_RETURN(error);
  218. }
  219. /**
  220. @brief
  221. Example of simple lock controls. The "share" it creates is a
  222. structure we will pass to each cassandra handler. Do you have to have
  223. one of these? Well, you have pieces that are used for locking, and
  224. they are needed to function.
  225. */
  226. static CASSANDRA_SHARE *get_share(const char *table_name, TABLE *table)
  227. {
  228. CASSANDRA_SHARE *share;
  229. uint length;
  230. char *tmp_name;
  231. mysql_mutex_lock(&cassandra_mutex);
  232. length=(uint) strlen(table_name);
  233. if (!(share=(CASSANDRA_SHARE*) my_hash_search(&cassandra_open_tables,
  234. (uchar*) table_name,
  235. length)))
  236. {
  237. if (!(share=(CASSANDRA_SHARE *)
  238. my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), PSI_INSTRUMENT_ME,
  239. &share, sizeof(*share),
  240. &tmp_name, length+1,
  241. NullS)))
  242. {
  243. mysql_mutex_unlock(&cassandra_mutex);
  244. return NULL;
  245. }
  246. share->use_count=0;
  247. share->table_name_length=length;
  248. share->table_name=tmp_name;
  249. strmov(share->table_name,table_name);
  250. if (my_hash_insert(&cassandra_open_tables, (uchar*) share))
  251. goto error;
  252. thr_lock_init(&share->lock);
  253. mysql_mutex_init(ex_key_mutex_CASSANDRA_SHARE_mutex,
  254. &share->mutex, MY_MUTEX_INIT_FAST);
  255. }
  256. share->use_count++;
  257. mysql_mutex_unlock(&cassandra_mutex);
  258. return share;
  259. error:
  260. mysql_mutex_destroy(&share->mutex);
  261. my_free(share);
  262. return NULL;
  263. }
  264. /**
  265. @brief
  266. Free lock controls. We call this whenever we close a table. If the table had
  267. the last reference to the share, then we free memory associated with it.
  268. */
  269. static int free_share(CASSANDRA_SHARE *share)
  270. {
  271. mysql_mutex_lock(&cassandra_mutex);
  272. if (!--share->use_count)
  273. {
  274. my_hash_delete(&cassandra_open_tables, (uchar*) share);
  275. thr_lock_delete(&share->lock);
  276. mysql_mutex_destroy(&share->mutex);
  277. my_free(share);
  278. }
  279. mysql_mutex_unlock(&cassandra_mutex);
  280. return 0;
  281. }
  282. static handler* cassandra_create_handler(handlerton *hton,
  283. TABLE_SHARE *table,
  284. MEM_ROOT *mem_root)
  285. {
  286. return new (mem_root) ha_cassandra(hton, table);
  287. }
  288. ha_cassandra::ha_cassandra(handlerton *hton, TABLE_SHARE *table_arg)
  289. :handler(hton, table_arg),
  290. se(NULL), field_converters(NULL),
  291. special_type_field_converters(NULL),
  292. special_type_field_names(NULL), n_special_type_fields(0),
  293. rowkey_converter(NULL),
  294. dyncol_field(0), dyncol_set(0)
  295. {}
  296. int ha_cassandra::connect_and_check_options(TABLE *table_arg)
  297. {
  298. ha_table_option_struct *options= table_arg->s->option_struct;
  299. int res;
  300. DBUG_ENTER("ha_cassandra::connect_and_check_options");
  301. if ((res= check_field_options(table_arg->s->field)) ||
  302. (res= check_table_options(options)))
  303. DBUG_RETURN(res);
  304. se= create_cassandra_se();
  305. se->set_column_family(options->column_family);
  306. const char *thrift_host= options->thrift_host? options->thrift_host:
  307. cassandra_default_thrift_host;
  308. if (se->connect(thrift_host, options->thrift_port, options->keyspace))
  309. {
  310. my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0), se->error_str());
  311. DBUG_RETURN(HA_ERR_NO_CONNECTION);
  312. }
  313. if (setup_field_converters(table_arg->field, table_arg->s->fields))
  314. {
  315. DBUG_RETURN(HA_ERR_NO_CONNECTION);
  316. }
  317. DBUG_RETURN(0);
  318. }
  319. int ha_cassandra::check_field_options(Field **fields)
  320. {
  321. Field **field;
  322. uint i;
  323. DBUG_ENTER("ha_cassandra::check_field_options");
  324. for (field= fields, i= 0; *field; field++, i++)
  325. {
  326. ha_field_option_struct *field_options= (*field)->option_struct;
  327. if (field_options && field_options->dyncol_field)
  328. {
  329. if (dyncol_set || (*field)->type() != MYSQL_TYPE_BLOB)
  330. {
  331. my_error(ER_WRONG_FIELD_SPEC, MYF(0), (*field)->field_name.str);
  332. DBUG_RETURN(HA_WRONG_CREATE_OPTION);
  333. }
  334. dyncol_set= 1;
  335. dyncol_field= i;
  336. bzero(&dynamic_values, sizeof(dynamic_values));
  337. bzero(&dynamic_names, sizeof(dynamic_names));
  338. bzero(&dynamic_rec, sizeof(dynamic_rec));
  339. }
  340. }
  341. DBUG_RETURN(0);
  342. }
  343. int ha_cassandra::open(const char *name, int mode, uint test_if_locked)
  344. {
  345. DBUG_ENTER("ha_cassandra::open");
  346. if (!(share = get_share(name, table)))
  347. DBUG_RETURN(1);
  348. thr_lock_data_init(&share->lock,&lock,NULL);
  349. DBUG_ASSERT(!se);
  350. /*
  351. Don't do the following on open: it prevents SHOW CREATE TABLE when the server
  352. has gone away.
  353. */
  354. /*
  355. int res;
  356. if ((res= connect_and_check_options(table)))
  357. {
  358. DBUG_RETURN(res);
  359. }
  360. */
  361. info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
  362. insert_lineno= 0;
  363. DBUG_RETURN(0);
  364. }
  365. int ha_cassandra::close(void)
  366. {
  367. DBUG_ENTER("ha_cassandra::close");
  368. delete se;
  369. se= NULL;
  370. free_field_converters();
  371. DBUG_RETURN(free_share(share));
  372. }
  373. int ha_cassandra::check_table_options(ha_table_option_struct *options)
  374. {
  375. if (!options->thrift_host && (!cassandra_default_thrift_host ||
  376. !cassandra_default_thrift_host[0]))
  377. {
  378. my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0),
  379. "thrift_host table option must be specified, or "
  380. "@@cassandra_default_thrift_host must be set");
  381. return HA_WRONG_CREATE_OPTION;
  382. }
  383. if (!options->keyspace || !options->column_family)
  384. {
  385. my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0),
  386. "keyspace and column_family table options must be specified");
  387. return HA_WRONG_CREATE_OPTION;
  388. }
  389. return 0;
  390. }
  391. /**
  392. @brief
  393. create() is called to create a table. The variable name will have the name
  394. of the table.
  395. @details
  396. When create() is called you do not need to worry about
  397. opening the table. Also, the .frm file will have already been
  398. created so adjusting create_info is not necessary. You can overwrite
  399. the .frm file at this point if you wish to change the table
  400. definition, but there are no methods currently provided for doing
  401. so.
  402. Called from handle.cc by ha_create_table().
  403. @see
  404. ha_create_table() in handle.cc
  405. */
  406. int ha_cassandra::create(const char *name, TABLE *table_arg,
  407. HA_CREATE_INFO *create_info)
  408. {
  409. int res;
  410. DBUG_ENTER("ha_cassandra::create");
  411. if (table_arg->s->keys != 1 || table_arg->s->primary_key !=0 ||
  412. table_arg->key_info[0].user_defined_key_parts != 1 ||
  413. table_arg->key_info[0].key_part[0].fieldnr != 1)
  414. {
  415. my_error(ER_WRONG_COLUMN_NAME, MYF(0),
  416. "Table must have PRIMARY KEY defined over the first column");
  417. DBUG_RETURN(HA_WRONG_CREATE_OPTION);
  418. }
  419. DBUG_ASSERT(!se);
  420. if ((res= connect_and_check_options(table_arg)))
  421. DBUG_RETURN(res);
  422. insert_lineno= 0;
  423. DBUG_RETURN(0);
  424. }
  425. /*
  426. Mapping needs to
  427. - copy value from MySQL record to Thrift buffer
  428. - copy value from Thrift bufer to MySQL record..
  429. */
  430. /* Converter base */
  431. class ColumnDataConverter
  432. {
  433. public:
  434. Field *field;
  435. /* This will save Cassandra's data in the Field */
  436. virtual int cassandra_to_mariadb(const char *cass_data,
  437. int cass_data_len)=0;
  438. /*
  439. This will get data from the Field pointer, store Cassandra's form
  440. in internal buffer, and return pointer/size.
  441. @return
  442. false - OK
  443. true - Failed to convert value (completely, there is no value to insert
  444. at all).
  445. */
  446. virtual bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)=0;
  447. virtual ~ColumnDataConverter() {};
  448. };
  449. class DoubleDataConverter : public ColumnDataConverter
  450. {
  451. double buf;
  452. public:
  453. int cassandra_to_mariadb(const char *cass_data, int cass_data_len)
  454. {
  455. DBUG_ASSERT(cass_data_len == sizeof(double));
  456. double *pdata= (double*) cass_data;
  457. field->store(*pdata);
  458. return 0;
  459. }
  460. bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)
  461. {
  462. buf= field->val_real();
  463. *cass_data= (char*)&buf;
  464. *cass_data_len=sizeof(double);
  465. return false;
  466. }
  467. ~DoubleDataConverter(){}
  468. };
  469. class FloatDataConverter : public ColumnDataConverter
  470. {
  471. float buf;
  472. public:
  473. int cassandra_to_mariadb(const char *cass_data, int cass_data_len)
  474. {
  475. DBUG_ASSERT(cass_data_len == sizeof(float));
  476. float *pdata= (float*) cass_data;
  477. field->store(*pdata);
  478. return 0;
  479. }
  480. bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)
  481. {
  482. buf= field->val_real();
  483. *cass_data= (char*)&buf;
  484. *cass_data_len=sizeof(float);
  485. return false;
  486. }
  487. ~FloatDataConverter(){}
  488. };
  489. static void flip64(const char *from, char* to)
  490. {
  491. to[0]= from[7];
  492. to[1]= from[6];
  493. to[2]= from[5];
  494. to[3]= from[4];
  495. to[4]= from[3];
  496. to[5]= from[2];
  497. to[6]= from[1];
  498. to[7]= from[0];
  499. }
  500. class BigintDataConverter : public ColumnDataConverter
  501. {
  502. longlong buf;
  503. bool flip; /* is false when reading counter columns */
  504. public:
  505. int cassandra_to_mariadb(const char *cass_data, int cass_data_len)
  506. {
  507. longlong tmp;
  508. DBUG_ASSERT(cass_data_len == sizeof(longlong));
  509. if (flip)
  510. flip64(cass_data, (char*)&tmp);
  511. else
  512. memcpy(&tmp, cass_data, sizeof(longlong));
  513. field->store(tmp);
  514. return 0;
  515. }
  516. bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)
  517. {
  518. longlong tmp= field->val_int();
  519. if (flip)
  520. flip64((const char*)&tmp, (char*)&buf);
  521. else
  522. memcpy(&buf, &tmp, sizeof(longlong));
  523. *cass_data= (char*)&buf;
  524. *cass_data_len=sizeof(longlong);
  525. return false;
  526. }
  527. BigintDataConverter(bool flip_arg) : flip(flip_arg) {}
  528. ~BigintDataConverter(){}
  529. };
  530. static void flip32(const char *from, char* to)
  531. {
  532. to[0]= from[3];
  533. to[1]= from[2];
  534. to[2]= from[1];
  535. to[3]= from[0];
  536. }
  537. class TinyintDataConverter : public ColumnDataConverter
  538. {
  539. char buf;
  540. public:
  541. int cassandra_to_mariadb(const char *cass_data, int cass_data_len)
  542. {
  543. DBUG_ASSERT(cass_data_len == 1);
  544. field->store(cass_data[0]);
  545. return 0;
  546. }
  547. bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)
  548. {
  549. buf= field->val_int()? 1 : 0; /* TODO: error handling? */
  550. *cass_data= (char*)&buf;
  551. *cass_data_len= 1;
  552. return false;
  553. }
  554. ~TinyintDataConverter(){}
  555. };
  556. class Int32DataConverter : public ColumnDataConverter
  557. {
  558. int32_t buf;
  559. public:
  560. int cassandra_to_mariadb(const char *cass_data, int cass_data_len)
  561. {
  562. int32_t tmp;
  563. DBUG_ASSERT(cass_data_len == sizeof(int32_t));
  564. flip32(cass_data, (char*)&tmp);
  565. field->store(tmp);
  566. return 0;
  567. }
  568. bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)
  569. {
  570. int32_t tmp= field->val_int();
  571. flip32((const char*)&tmp, (char*)&buf);
  572. *cass_data= (char*)&buf;
  573. *cass_data_len=sizeof(int32_t);
  574. return false;
  575. }
  576. ~Int32DataConverter(){}
  577. };
  578. class StringCopyConverter : public ColumnDataConverter
  579. {
  580. String buf;
  581. size_t max_length;
  582. public:
  583. int cassandra_to_mariadb(const char *cass_data, int cass_data_len)
  584. {
  585. if ((size_t)cass_data_len > max_length)
  586. return 1;
  587. field->store(cass_data, cass_data_len,field->charset());
  588. return 0;
  589. }
  590. bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)
  591. {
  592. String *pstr= field->val_str(&buf);
  593. *cass_data= (char*)pstr->ptr();
  594. *cass_data_len= pstr->length();
  595. return false;
  596. }
  597. StringCopyConverter(size_t max_length_arg) : max_length(max_length_arg) {}
  598. ~StringCopyConverter(){}
  599. };
  600. class TimestampDataConverter : public ColumnDataConverter
  601. {
  602. int64_t buf;
  603. public:
  604. int cassandra_to_mariadb(const char *cass_data, int cass_data_len)
  605. {
  606. /* Cassandra data is milliseconds-since-epoch in network byte order */
  607. int64_t tmp;
  608. DBUG_ASSERT(cass_data_len==8);
  609. flip64(cass_data, (char*)&tmp);
  610. /*
  611. store_TIME's arguments:
  612. - seconds since epoch
  613. - microsecond fraction of a second.
  614. */
  615. ((Field_timestamp*)field)->store_TIME(tmp / 1000, (tmp % 1000)*1000);
  616. return 0;
  617. }
  618. bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)
  619. {
  620. my_time_t ts_time;
  621. ulong ts_microsec;
  622. int64_t tmp;
  623. ts_time= ((Field_timestamp*)field)->get_timestamp(&ts_microsec);
  624. /* Cassandra needs milliseconds-since-epoch */
  625. tmp= ((int64_t)ts_time) * 1000 + ts_microsec/1000;
  626. flip64((const char*)&tmp, (char*)&buf);
  627. *cass_data= (char*)&buf;
  628. *cass_data_len= 8;
  629. return false;
  630. }
  631. ~TimestampDataConverter(){}
  632. };
  633. static int convert_hex_digit(const char c)
  634. {
  635. int num;
  636. if (c >= '0' && c <= '9')
  637. num= c - '0';
  638. else if (c >= 'A' && c <= 'F')
  639. num= c - 'A' + 10;
  640. else if (c >= 'a' && c <= 'f')
  641. num= c - 'a' + 10;
  642. else
  643. return -1; /* Couldn't convert */
  644. return num;
  645. }
  646. const char map2number[]="0123456789abcdef";
  647. static void convert_uuid2string(char *str, const char *cass_data)
  648. {
  649. char *ptr= str;
  650. /* UUID arrives as 16-byte number in network byte order */
  651. for (uint i=0; i < 16; i++)
  652. {
  653. *(ptr++)= map2number[(cass_data[i] >> 4) & 0xF];
  654. *(ptr++)= map2number[cass_data[i] & 0xF];
  655. if (i == 3 || i == 5 || i == 7 || i == 9)
  656. *(ptr++)= '-';
  657. }
  658. *ptr= 0;
  659. }
  660. static bool convert_string2uuid(char *buf, const char *str)
  661. {
  662. int lower, upper;
  663. for (uint i= 0; i < 16; i++)
  664. {
  665. if ((upper= convert_hex_digit(str[0])) == -1 ||
  666. (lower= convert_hex_digit(str[1])) == -1)
  667. {
  668. return true;
  669. }
  670. buf[i]= lower | (upper << 4);
  671. str += 2;
  672. if (i == 3 || i == 5 || i == 7 || i == 9)
  673. {
  674. if (str[0] != '-')
  675. return true;
  676. str++;
  677. }
  678. }
  679. return false;
  680. }
  681. class UuidDataConverter : public ColumnDataConverter
  682. {
  683. char buf[16]; /* Binary UUID representation */
  684. String str_buf;
  685. public:
  686. int cassandra_to_mariadb(const char *cass_data, int cass_data_len)
  687. {
  688. DBUG_ASSERT(cass_data_len==16);
  689. char str[37];
  690. convert_uuid2string(str, cass_data);
  691. field->store(str, 36,field->charset());
  692. return 0;
  693. }
  694. bool mariadb_to_cassandra(char **cass_data, int *cass_data_len)
  695. {
  696. String *uuid_str= field->val_str(&str_buf);
  697. if (uuid_str->length() != 36)
  698. return true;
  699. if (convert_string2uuid(buf, (char*)uuid_str->c_ptr()))
  700. return true;
  701. *cass_data= buf;
  702. *cass_data_len= 16;
  703. return false;
  704. }
  705. ~UuidDataConverter(){}
  706. };
  707. /**
  708. Converting dynamic columns types to/from casandra types
  709. */
  710. /**
  711. Check and initialize (if it is needed) string MEM_ROOT
  712. */
  713. static void alloc_strings_memroot(MEM_ROOT *mem_root)
  714. {
  715. if (!alloc_root_inited(mem_root))
  716. {
  717. /*
  718. The mem_root used to allocate UUID (of length 36 + \0) so make
  719. appropriate allocated size
  720. */
  721. init_alloc_root(PSI_INSTRUMENT_ME, mem_root,
  722. (36 + 1 + ALIGN_SIZE(sizeof(USED_MEM))) * 10 +
  723. ALLOC_ROOT_MIN_BLOCK_SIZE,
  724. (36 + 1 + ALIGN_SIZE(sizeof(USED_MEM))) * 10 +
  725. ALLOC_ROOT_MIN_BLOCK_SIZE, MYF(MY_THREAD_SPECIFIC));
  726. }
  727. }
  728. static void free_strings_memroot(MEM_ROOT *mem_root)
  729. {
  730. if (alloc_root_inited(mem_root))
  731. free_root(mem_root, MYF(0));
  732. }
  733. bool cassandra_to_dyncol_intLong(const char *cass_data,
  734. int cass_data_len __attribute__((unused)),
  735. DYNAMIC_COLUMN_VALUE *value,
  736. MEM_ROOT *mem_root __attribute__((unused)))
  737. {
  738. value->type= DYN_COL_INT;
  739. #ifdef WORDS_BIGENDIAN
  740. value->x.long_value= (longlong)*cass_data;
  741. #else
  742. flip64(cass_data, (char *)&value->x.long_value);
  743. #endif
  744. return 0;
  745. }
  746. bool dyncol_to_cassandraLong(DYNAMIC_COLUMN_VALUE *value,
  747. char **cass_data, int *cass_data_len,
  748. void* buff, void **freemem)
  749. {
  750. longlong *tmp= (longlong *) buff;
  751. enum enum_dyncol_func_result rc=
  752. mariadb_dyncol_val_long(tmp, value);
  753. if (rc < 0)
  754. return true;
  755. *cass_data_len= sizeof(longlong);
  756. #ifdef WORDS_BIGENDIAN
  757. *cass_data= (char *)buff;
  758. #else
  759. flip64((char *)buff, (char *)buff + sizeof(longlong));
  760. *cass_data= (char *)buff + sizeof(longlong);
  761. #endif
  762. *freemem= NULL;
  763. return false;
  764. }
  765. bool cassandra_to_dyncol_intInt32(const char *cass_data,
  766. int cass_data_len __attribute__((unused)),
  767. DYNAMIC_COLUMN_VALUE *value,
  768. MEM_ROOT *mem_root __attribute__((unused)))
  769. {
  770. int32 tmp;
  771. value->type= DYN_COL_INT;
  772. #ifdef WORDS_BIGENDIAN
  773. tmp= *((int32 *)cass_data);
  774. #else
  775. flip32(cass_data, (char *)&tmp);
  776. #endif
  777. value->x.long_value= tmp;
  778. return 0;
  779. }
  780. bool dyncol_to_cassandraInt32(DYNAMIC_COLUMN_VALUE *value,
  781. char **cass_data, int *cass_data_len,
  782. void* buff, void **freemem)
  783. {
  784. longlong *tmp= (longlong *) ((char *)buff + sizeof(longlong));
  785. enum enum_dyncol_func_result rc=
  786. mariadb_dyncol_val_long(tmp, value);
  787. if (rc < 0)
  788. return true;
  789. *cass_data_len= sizeof(int32);
  790. *cass_data= (char *)buff;
  791. #ifdef WORDS_BIGENDIAN
  792. *((int32 *) buff) = (int32) *tmp;
  793. #else
  794. {
  795. int32 tmp2= (int32) *tmp;
  796. flip32((char *)&tmp2, (char *)buff);
  797. }
  798. #endif
  799. *freemem= NULL;
  800. return false;
  801. }
  802. bool cassandra_to_dyncol_intCounter(const char *cass_data,
  803. int cass_data_len __attribute__((unused)),
  804. DYNAMIC_COLUMN_VALUE *value,
  805. MEM_ROOT *mem_root __attribute__((unused)))
  806. {
  807. value->type= DYN_COL_INT;
  808. value->x.long_value= *((longlong *)cass_data);
  809. return 0;
  810. }
  811. bool dyncol_to_cassandraCounter(DYNAMIC_COLUMN_VALUE *value,
  812. char **cass_data, int *cass_data_len,
  813. void* buff, void **freemem)
  814. {
  815. longlong *tmp= (longlong *)buff;
  816. enum enum_dyncol_func_result rc=
  817. mariadb_dyncol_val_long(tmp, value);
  818. if (rc < 0)
  819. return true;
  820. *cass_data_len= sizeof(longlong);
  821. *cass_data= (char *)buff;
  822. *freemem= NULL;
  823. return false;
  824. }
  825. bool cassandra_to_dyncol_doubleFloat(const char *cass_data,
  826. int cass_data_len __attribute__((unused)),
  827. DYNAMIC_COLUMN_VALUE *value,
  828. MEM_ROOT *mem_root __attribute__((unused)))
  829. {
  830. value->type= DYN_COL_DOUBLE;
  831. value->x.double_value= *((float *)cass_data);
  832. return 0;
  833. }
  834. bool dyncol_to_cassandraFloat(DYNAMIC_COLUMN_VALUE *value,
  835. char **cass_data, int *cass_data_len,
  836. void* buff, void **freemem)
  837. {
  838. double tmp;
  839. enum enum_dyncol_func_result rc=
  840. mariadb_dyncol_val_double(&tmp, value);
  841. if (rc < 0)
  842. return true;
  843. *((float *)buff)= (float) tmp;
  844. *cass_data_len= sizeof(float);
  845. *cass_data= (char *)buff;
  846. *freemem= NULL;
  847. return false;
  848. }
  849. bool cassandra_to_dyncol_doubleDouble(const char *cass_data,
  850. int cass_data_len __attribute__((unused)),
  851. DYNAMIC_COLUMN_VALUE *value,
  852. MEM_ROOT *mem_root
  853. __attribute__((unused)))
  854. {
  855. value->type= DYN_COL_DOUBLE;
  856. value->x.double_value= *((double *)cass_data);
  857. return 0;
  858. }
  859. bool dyncol_to_cassandraDouble(DYNAMIC_COLUMN_VALUE *value,
  860. char **cass_data, int *cass_data_len,
  861. void* buff, void **freemem)
  862. {
  863. double *tmp= (double *)buff;
  864. enum enum_dyncol_func_result rc=
  865. mariadb_dyncol_val_double(tmp, value);
  866. if (rc < 0)
  867. return true;
  868. *cass_data_len= sizeof(double);
  869. *cass_data= (char *)buff;
  870. *freemem= NULL;
  871. return false;
  872. }
  873. bool cassandra_to_dyncol_strStr(const char *cass_data,
  874. int cass_data_len,
  875. DYNAMIC_COLUMN_VALUE *value,
  876. CHARSET_INFO *cs)
  877. {
  878. value->type= DYN_COL_STRING;
  879. value->x.string.charset= cs;
  880. value->x.string.value.str= (char *)cass_data;
  881. value->x.string.value.length= cass_data_len;
  882. return 0;
  883. }
  884. bool dyncol_to_cassandraStr(DYNAMIC_COLUMN_VALUE *value,
  885. char **cass_data, int *cass_data_len,
  886. void* buff, void **freemem, CHARSET_INFO *cs)
  887. {
  888. DYNAMIC_STRING tmp;
  889. if (init_dynamic_string(&tmp, NULL, 1024, 1024))
  890. return 1;
  891. enum enum_dyncol_func_result rc=
  892. mariadb_dyncol_val_str(&tmp, value, cs, '\0');
  893. if (rc < 0)
  894. {
  895. dynstr_free(&tmp);
  896. return 1;
  897. }
  898. *cass_data_len= tmp.length;
  899. *(cass_data)= tmp.str;
  900. *freemem= tmp.str;
  901. return 0;
  902. }
  903. bool cassandra_to_dyncol_strBytes(const char *cass_data,
  904. int cass_data_len,
  905. DYNAMIC_COLUMN_VALUE *value,
  906. MEM_ROOT *mem_root __attribute__((unused)))
  907. {
  908. return cassandra_to_dyncol_strStr(cass_data, cass_data_len, value,
  909. &my_charset_bin);
  910. }
  911. bool dyncol_to_cassandraBytes(DYNAMIC_COLUMN_VALUE *value,
  912. char **cass_data, int *cass_data_len,
  913. void* buff, void **freemem)
  914. {
  915. return dyncol_to_cassandraStr(value, cass_data, cass_data_len,
  916. buff, freemem, &my_charset_bin);
  917. }
  918. bool cassandra_to_dyncol_strAscii(const char *cass_data,
  919. int cass_data_len,
  920. DYNAMIC_COLUMN_VALUE *value,
  921. MEM_ROOT *mem_root __attribute__((unused)))
  922. {
  923. return cassandra_to_dyncol_strStr(cass_data, cass_data_len, value,
  924. &my_charset_latin1_bin);
  925. }
  926. bool dyncol_to_cassandraAscii(DYNAMIC_COLUMN_VALUE *value,
  927. char **cass_data, int *cass_data_len,
  928. void* buff, void **freemem)
  929. {
  930. return dyncol_to_cassandraStr(value, cass_data, cass_data_len,
  931. buff, freemem, &my_charset_latin1_bin);
  932. }
  933. bool cassandra_to_dyncol_strUTF8(const char *cass_data,
  934. int cass_data_len,
  935. DYNAMIC_COLUMN_VALUE *value,
  936. MEM_ROOT *mem_root __attribute__((unused)))
  937. {
  938. return cassandra_to_dyncol_strStr(cass_data, cass_data_len, value,
  939. &my_charset_utf8mb3_unicode_ci);
  940. }
  941. bool dyncol_to_cassandraUTF8(DYNAMIC_COLUMN_VALUE *value,
  942. char **cass_data, int *cass_data_len,
  943. void* buff, void **freemem)
  944. {
  945. return dyncol_to_cassandraStr(value, cass_data, cass_data_len,
  946. buff, freemem, &my_charset_utf8mb3_unicode_ci);
  947. }
  948. bool cassandra_to_dyncol_strUUID(const char *cass_data,
  949. int cass_data_len,
  950. DYNAMIC_COLUMN_VALUE *value,
  951. MEM_ROOT *mem_root)
  952. {
  953. value->type= DYN_COL_STRING;
  954. value->x.string.charset= &my_charset_bin;
  955. alloc_strings_memroot(mem_root);
  956. value->x.string.value.str= (char *)alloc_root(mem_root, 37);
  957. if (!value->x.string.value.str)
  958. {
  959. value->x.string.value.length= 0;
  960. return 1;
  961. }
  962. convert_uuid2string(value->x.string.value.str, cass_data);
  963. value->x.string.value.length= 36;
  964. return 0;
  965. }
  966. bool dyncol_to_cassandraUUID(DYNAMIC_COLUMN_VALUE *value,
  967. char **cass_data, int *cass_data_len,
  968. void* buff, void **freemem)
  969. {
  970. DYNAMIC_STRING tmp;
  971. if (init_dynamic_string(&tmp, NULL, 1024, 1024))
  972. return true;
  973. enum enum_dyncol_func_result rc=
  974. mariadb_dyncol_val_str(&tmp, value, &my_charset_latin1_bin, '\0');
  975. if (rc < 0 || tmp.length != 36 || convert_string2uuid((char *)buff, tmp.str))
  976. {
  977. dynstr_free(&tmp);
  978. return true;
  979. }
  980. *cass_data_len= tmp.length;
  981. *(cass_data)= tmp.str;
  982. *freemem= tmp.str;
  983. return 0;
  984. }
  985. bool cassandra_to_dyncol_intBool(const char *cass_data,
  986. int cass_data_len,
  987. DYNAMIC_COLUMN_VALUE *value,
  988. MEM_ROOT *mem_root __attribute__((unused)))
  989. {
  990. value->type= DYN_COL_INT;
  991. value->x.long_value= (cass_data[0] ? 1 : 0);
  992. return 0;
  993. }
  994. bool dyncol_to_cassandraBool(DYNAMIC_COLUMN_VALUE *value,
  995. char **cass_data, int *cass_data_len,
  996. void* buff, void **freemem)
  997. {
  998. longlong tmp;
  999. enum enum_dyncol_func_result rc=
  1000. mariadb_dyncol_val_long(&tmp, value);
  1001. if (rc < 0)
  1002. return true;
  1003. ((char *)buff)[0]= (tmp ? 1 : 0);
  1004. *cass_data_len= 1;
  1005. *(cass_data)= (char *)buff;
  1006. *freemem= 0;
  1007. return 0;
  1008. }
  1009. const char * const validator_bigint= "org.apache.cassandra.db.marshal.LongType";
  1010. const char * const validator_int= "org.apache.cassandra.db.marshal.Int32Type";
  1011. const char * const validator_counter= "org.apache.cassandra.db.marshal.CounterColumnType";
  1012. const char * const validator_float= "org.apache.cassandra.db.marshal.FloatType";
  1013. const char * const validator_double= "org.apache.cassandra.db.marshal.DoubleType";
  1014. const char * const validator_blob= "org.apache.cassandra.db.marshal.BytesType";
  1015. const char * const validator_ascii= "org.apache.cassandra.db.marshal.AsciiType";
  1016. const char * const validator_text= "org.apache.cassandra.db.marshal.UTF8Type";
  1017. const char * const validator_timestamp="org.apache.cassandra.db.marshal.DateType";
  1018. const char * const validator_uuid= "org.apache.cassandra.db.marshal.UUIDType";
  1019. const char * const validator_boolean= "org.apache.cassandra.db.marshal.BooleanType";
  1020. /* VARINTs are stored as big-endian big numbers. */
  1021. const char * const validator_varint= "org.apache.cassandra.db.marshal.IntegerType";
  1022. const char * const validator_decimal= "org.apache.cassandra.db.marshal.DecimalType";
  1023. static CASSANDRA_TYPE_DEF cassandra_types[]=
  1024. {
  1025. {
  1026. validator_bigint,
  1027. &cassandra_to_dyncol_intLong,
  1028. &dyncol_to_cassandraLong
  1029. },
  1030. {
  1031. validator_int,
  1032. &cassandra_to_dyncol_intInt32,
  1033. &dyncol_to_cassandraInt32
  1034. },
  1035. {
  1036. validator_counter,
  1037. cassandra_to_dyncol_intCounter,
  1038. &dyncol_to_cassandraCounter
  1039. },
  1040. {
  1041. validator_float,
  1042. &cassandra_to_dyncol_doubleFloat,
  1043. &dyncol_to_cassandraFloat
  1044. },
  1045. {
  1046. validator_double,
  1047. &cassandra_to_dyncol_doubleDouble,
  1048. &dyncol_to_cassandraDouble
  1049. },
  1050. {
  1051. validator_blob,
  1052. &cassandra_to_dyncol_strBytes,
  1053. &dyncol_to_cassandraBytes
  1054. },
  1055. {
  1056. validator_ascii,
  1057. &cassandra_to_dyncol_strAscii,
  1058. &dyncol_to_cassandraAscii
  1059. },
  1060. {
  1061. validator_text,
  1062. &cassandra_to_dyncol_strUTF8,
  1063. &dyncol_to_cassandraUTF8
  1064. },
  1065. {
  1066. validator_timestamp,
  1067. &cassandra_to_dyncol_intLong,
  1068. &dyncol_to_cassandraLong
  1069. },
  1070. {
  1071. validator_uuid,
  1072. &cassandra_to_dyncol_strUUID,
  1073. &dyncol_to_cassandraUUID
  1074. },
  1075. {
  1076. validator_boolean,
  1077. &cassandra_to_dyncol_intBool,
  1078. &dyncol_to_cassandraBool
  1079. },
  1080. {
  1081. validator_varint,
  1082. &cassandra_to_dyncol_strBytes,
  1083. &dyncol_to_cassandraBytes
  1084. },
  1085. {
  1086. validator_decimal,
  1087. &cassandra_to_dyncol_strBytes,
  1088. &dyncol_to_cassandraBytes
  1089. }
  1090. };
  1091. CASSANDRA_TYPE get_cassandra_type(const char *validator)
  1092. {
  1093. CASSANDRA_TYPE rc;
  1094. switch(validator[32])
  1095. {
  1096. case 'L':
  1097. rc= CT_BIGINT;
  1098. break;
  1099. case 'I':
  1100. rc= (validator[35] == '3' ? CT_INT : CT_VARINT);
  1101. rc= CT_INT;
  1102. break;
  1103. case 'C':
  1104. rc= CT_COUNTER;
  1105. break;
  1106. case 'F':
  1107. rc= CT_FLOAT;
  1108. break;
  1109. case 'D':
  1110. switch (validator[33])
  1111. {
  1112. case 'o':
  1113. rc= CT_DOUBLE;
  1114. break;
  1115. case 'a':
  1116. rc= CT_TIMESTAMP;
  1117. break;
  1118. case 'e':
  1119. rc= CT_DECIMAL;
  1120. break;
  1121. default:
  1122. rc= CT_BLOB;
  1123. break;
  1124. }
  1125. break;
  1126. case 'B':
  1127. rc= (validator[33] == 'o' ? CT_BOOLEAN : CT_BLOB);
  1128. break;
  1129. case 'A':
  1130. rc= CT_ASCII;
  1131. break;
  1132. case 'U':
  1133. rc= (validator[33] == 'T' ? CT_TEXT : CT_UUID);
  1134. break;
  1135. default:
  1136. rc= CT_BLOB;
  1137. }
  1138. DBUG_ASSERT(strcmp(cassandra_types[rc].name, validator) == 0);
  1139. return rc;
  1140. }
  1141. ColumnDataConverter *map_field_to_validator(Field *field, const char *validator_name)
  1142. {
  1143. ColumnDataConverter *res= NULL;
  1144. switch(field->type()) {
  1145. case MYSQL_TYPE_TINY:
  1146. if (!strcmp(validator_name, validator_boolean))
  1147. {
  1148. res= new TinyintDataConverter;
  1149. break;
  1150. }
  1151. /* fall through: */
  1152. case MYSQL_TYPE_SHORT:
  1153. case MYSQL_TYPE_LONGLONG:
  1154. {
  1155. bool is_counter= false;
  1156. if (!strcmp(validator_name, validator_bigint) ||
  1157. !strcmp(validator_name, validator_timestamp) ||
  1158. (is_counter= !strcmp(validator_name, validator_counter)))
  1159. res= new BigintDataConverter(!is_counter);
  1160. break;
  1161. }
  1162. case MYSQL_TYPE_FLOAT:
  1163. if (!strcmp(validator_name, validator_float))
  1164. res= new FloatDataConverter;
  1165. break;
  1166. case MYSQL_TYPE_DOUBLE:
  1167. if (!strcmp(validator_name, validator_double))
  1168. res= new DoubleDataConverter;
  1169. break;
  1170. case MYSQL_TYPE_TIMESTAMP:
  1171. if (!strcmp(validator_name, validator_timestamp))
  1172. res= new TimestampDataConverter;
  1173. break;
  1174. case MYSQL_TYPE_STRING: // these are space padded CHAR(n) strings.
  1175. if (!strcmp(validator_name, validator_uuid) &&
  1176. field->real_type() == MYSQL_TYPE_STRING &&
  1177. field->field_length == 36)
  1178. {
  1179. // UUID maps to CHAR(36), its text representation
  1180. res= new UuidDataConverter;
  1181. break;
  1182. }
  1183. /* fall through: */
  1184. case MYSQL_TYPE_VAR_STRING:
  1185. case MYSQL_TYPE_VARCHAR:
  1186. case MYSQL_TYPE_BLOB:
  1187. {
  1188. /*
  1189. Cassandra's "varint" type is a binary-encoded arbitary-length
  1190. big-endian number.
  1191. - It can be mapped to VARBINARY(N), with sufficiently big N.
  1192. - If the value does not fit into N bytes, it is an error. We should not
  1193. truncate it, because that is just as good as returning garbage.
  1194. - varint should not be mapped to BINARY(N), because BINARY(N) values
  1195. are zero-padded, which will work as multiplying the value by
  1196. 2^k for some value of k.
  1197. */
  1198. if (field->type() == MYSQL_TYPE_VARCHAR &&
  1199. field->binary() &&
  1200. (!strcmp(validator_name, validator_varint) ||
  1201. !strcmp(validator_name, validator_decimal)))
  1202. {
  1203. res= new StringCopyConverter(field->field_length);
  1204. break;
  1205. }
  1206. if (!strcmp(validator_name, validator_blob) ||
  1207. !strcmp(validator_name, validator_ascii) ||
  1208. !strcmp(validator_name, validator_text))
  1209. {
  1210. res= new StringCopyConverter((size_t)-1);
  1211. }
  1212. break;
  1213. }
  1214. case MYSQL_TYPE_LONG:
  1215. if (!strcmp(validator_name, validator_int))
  1216. res= new Int32DataConverter;
  1217. break;
  1218. default:;
  1219. }
  1220. return res;
  1221. }
  1222. bool ha_cassandra::setup_field_converters(Field **field_arg, uint n_fields)
  1223. {
  1224. char *col_name;
  1225. int col_name_len;
  1226. char *col_type;
  1227. int col_type_len;
  1228. size_t ddl_fields= se->get_ddl_size();
  1229. const char *default_type= se->get_default_validator();
  1230. uint max_non_default_fields;
  1231. DBUG_ENTER("ha_cassandra::setup_field_converters");
  1232. DBUG_ASSERT(default_type);
  1233. DBUG_ASSERT(!field_converters);
  1234. DBUG_ASSERT(dyncol_set == 0 || dyncol_set == 1);
  1235. /*
  1236. We always should take into account that in case of using dynamic columns
  1237. sql description contain one field which does not described in
  1238. Cassandra DDL also key field is described separately. So that
  1239. is why we use "n_fields - dyncol_set - 1" or "ddl_fields + 2".
  1240. */
  1241. max_non_default_fields= ddl_fields + 2 - n_fields;
  1242. if (ddl_fields < (n_fields - dyncol_set - 1))
  1243. {
  1244. se->print_error("Some of SQL fields were not mapped to Cassandra's fields");
  1245. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  1246. DBUG_RETURN(true);
  1247. }
  1248. /* allocate memory in one chunk */
  1249. size_t memsize= sizeof(ColumnDataConverter*) * n_fields +
  1250. (sizeof(LEX_STRING) + sizeof(CASSANDRA_TYPE_DEF))*
  1251. (dyncol_set ? max_non_default_fields : 0);
  1252. if (!(field_converters= (ColumnDataConverter**)my_malloc(PSI_INSTRUMENT_ME, memsize, MYF(0))))
  1253. DBUG_RETURN(true);
  1254. bzero(field_converters, memsize);
  1255. n_field_converters= n_fields;
  1256. if (dyncol_set)
  1257. {
  1258. special_type_field_converters=
  1259. (CASSANDRA_TYPE_DEF *)(field_converters + n_fields);
  1260. special_type_field_names=
  1261. ((LEX_STRING*)(special_type_field_converters + max_non_default_fields));
  1262. if (my_init_dynamic_array(PSI_INSTRUMENT_ME, &dynamic_values,
  1263. sizeof(DYNAMIC_COLUMN_VALUE),
  1264. DYNCOL_USUAL, DYNCOL_DELTA, MYF(0)))
  1265. DBUG_RETURN(true);
  1266. else
  1267. if (my_init_dynamic_array(PSI_INSTRUMENT_ME, &dynamic_names,
  1268. sizeof(LEX_STRING),
  1269. DYNCOL_USUAL, DYNCOL_DELTA,MYF(0)))
  1270. {
  1271. delete_dynamic(&dynamic_values);
  1272. DBUG_RETURN(true);
  1273. }
  1274. else
  1275. if (init_dynamic_string(&dynamic_rec, NULL,
  1276. DYNCOL_USUAL_REC, DYNCOL_DELTA_REC))
  1277. {
  1278. delete_dynamic(&dynamic_values);
  1279. delete_dynamic(&dynamic_names);
  1280. DBUG_RETURN(true);
  1281. }
  1282. /* Dynamic column field has special processing */
  1283. field_converters[dyncol_field]= NULL;
  1284. default_type_def= cassandra_types + get_cassandra_type(default_type);
  1285. }
  1286. se->first_ddl_column();
  1287. uint n_mapped= 0;
  1288. while (!se->next_ddl_column(&col_name, &col_name_len, &col_type,
  1289. &col_type_len))
  1290. {
  1291. Field **field;
  1292. uint i;
  1293. /* Mapping for the 1st field is already known */
  1294. for (field= field_arg + 1, i= 1; *field; field++, i++)
  1295. {
  1296. if ((!dyncol_set || dyncol_field != i) &&
  1297. !strcmp((*field)->field_name.str, col_name))
  1298. {
  1299. n_mapped++;
  1300. ColumnDataConverter **conv= field_converters + (*field)->field_index;
  1301. if (!(*conv= map_field_to_validator(*field, col_type)))
  1302. {
  1303. se->print_error("Failed to map column %s to datatype %s",
  1304. (*field)->field_name.str, col_type);
  1305. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  1306. DBUG_RETURN(true);
  1307. }
  1308. (*conv)->field= *field;
  1309. break;
  1310. }
  1311. }
  1312. if (dyncol_set && !(*field)) // is needed and not found
  1313. {
  1314. DBUG_PRINT("info",("Field not found: %s", col_name));
  1315. if (strcmp(col_type, default_type))
  1316. {
  1317. DBUG_PRINT("info",("Field '%s' non-default type: '%s'",
  1318. col_name, col_type));
  1319. special_type_field_names[n_special_type_fields].length= col_name_len;
  1320. special_type_field_names[n_special_type_fields].str= col_name;
  1321. special_type_field_converters[n_special_type_fields]=
  1322. cassandra_types[get_cassandra_type(col_type)];
  1323. n_special_type_fields++;
  1324. }
  1325. }
  1326. }
  1327. if (n_mapped != n_fields - 1 - dyncol_set)
  1328. {
  1329. Field *first_unmapped= NULL;
  1330. /* Find the first field */
  1331. for (uint i= 1; i < n_fields;i++)
  1332. {
  1333. if (!field_converters[i])
  1334. {
  1335. first_unmapped= field_arg[i];
  1336. break;
  1337. }
  1338. }
  1339. DBUG_ASSERT(first_unmapped);
  1340. se->print_error("Field `%s` could not be mapped to any field in Cassandra",
  1341. first_unmapped->field_name.str);
  1342. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  1343. DBUG_RETURN(true);
  1344. }
  1345. /*
  1346. Setup type conversion for row_key.
  1347. */
  1348. se->get_rowkey_type(&col_name, &col_type);
  1349. if (col_name && strcmp(col_name, (*field_arg)->field_name.str))
  1350. {
  1351. se->print_error("PRIMARY KEY column must match Cassandra's name '%s'",
  1352. col_name);
  1353. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  1354. DBUG_RETURN(true);
  1355. }
  1356. if (!col_name && strcmp("rowkey", (*field_arg)->field_name.str))
  1357. {
  1358. se->print_error("target column family has no key_alias defined, "
  1359. "PRIMARY KEY column must be named 'rowkey'");
  1360. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  1361. DBUG_RETURN(true);
  1362. }
  1363. if (col_type != NULL)
  1364. {
  1365. if (!(rowkey_converter= map_field_to_validator(*field_arg, col_type)))
  1366. {
  1367. se->print_error("Failed to map PRIMARY KEY to datatype %s", col_type);
  1368. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  1369. DBUG_RETURN(true);
  1370. }
  1371. rowkey_converter->field= *field_arg;
  1372. }
  1373. else
  1374. {
  1375. se->print_error("Cassandra's rowkey has no defined datatype (todo: support this)");
  1376. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  1377. DBUG_RETURN(true);
  1378. }
  1379. DBUG_RETURN(false);
  1380. }
  1381. void ha_cassandra::free_field_converters()
  1382. {
  1383. delete rowkey_converter;
  1384. rowkey_converter= NULL;
  1385. if (dyncol_set)
  1386. {
  1387. delete_dynamic(&dynamic_values);
  1388. delete_dynamic(&dynamic_names);
  1389. dynstr_free(&dynamic_rec);
  1390. }
  1391. if (field_converters)
  1392. {
  1393. for (uint i=0; i < n_field_converters; i++)
  1394. if (field_converters[i])
  1395. {
  1396. DBUG_ASSERT(!dyncol_set || i != dyncol_field);
  1397. delete field_converters[i];
  1398. }
  1399. my_free(field_converters);
  1400. field_converters= NULL;
  1401. }
  1402. }
  1403. int ha_cassandra::index_init(uint idx, bool sorted)
  1404. {
  1405. int ires;
  1406. if (!se && (ires= connect_and_check_options(table)))
  1407. return ires;
  1408. return 0;
  1409. }
  1410. void store_key_image_to_rec(Field *field, uchar *ptr, uint len);
  1411. int ha_cassandra::index_read_map(uchar *buf, const uchar *key,
  1412. key_part_map keypart_map,
  1413. enum ha_rkey_function find_flag)
  1414. {
  1415. int rc= 0;
  1416. DBUG_ENTER("ha_cassandra::index_read_map");
  1417. if (find_flag != HA_READ_KEY_EXACT)
  1418. {
  1419. DBUG_ASSERT(0); /* Non-equality lookups should never be done */
  1420. DBUG_RETURN(HA_ERR_WRONG_COMMAND);
  1421. }
  1422. uint key_len= calculate_key_len(table, active_index, key, keypart_map);
  1423. store_key_image_to_rec(table->field[0], (uchar*)key, key_len);
  1424. char *cass_key;
  1425. int cass_key_len;
  1426. my_bitmap_map *old_map;
  1427. old_map= dbug_tmp_use_all_columns(table, table->read_set);
  1428. if (rowkey_converter->mariadb_to_cassandra(&cass_key, &cass_key_len))
  1429. {
  1430. /* We get here when making lookups like uuid_column='not-an-uuid' */
  1431. dbug_tmp_restore_column_map(table->read_set, old_map);
  1432. DBUG_RETURN(HA_ERR_KEY_NOT_FOUND);
  1433. }
  1434. dbug_tmp_restore_column_map(table->read_set, old_map);
  1435. bool found;
  1436. if (se->get_slice(cass_key, cass_key_len, &found))
  1437. {
  1438. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  1439. rc= HA_ERR_INTERNAL_ERROR;
  1440. }
  1441. /* TODO: what if we're not reading all columns?? */
  1442. if (!found)
  1443. rc= HA_ERR_KEY_NOT_FOUND;
  1444. else
  1445. rc= read_cassandra_columns(false);
  1446. DBUG_RETURN(rc);
  1447. }
  1448. void ha_cassandra::print_conversion_error(const char *field_name,
  1449. char *cass_value,
  1450. int cass_value_len)
  1451. {
  1452. char buf[32];
  1453. char *p= cass_value;
  1454. size_t i= 0;
  1455. for (; (i < sizeof(buf)-1) && (p < cass_value + cass_value_len); p++)
  1456. {
  1457. buf[i++]= map2number[(*p >> 4) & 0xF];
  1458. buf[i++]= map2number[*p & 0xF];
  1459. }
  1460. buf[i]=0;
  1461. se->print_error("Unable to convert value for field `%s` from Cassandra's data"
  1462. " format. Source data is %d bytes, 0x%s%s",
  1463. field_name, cass_value_len, buf,
  1464. (i == sizeof(buf) - 1)? "..." : "");
  1465. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  1466. }
  1467. CASSANDRA_TYPE_DEF * ha_cassandra::get_cassandra_field_def(char *cass_name,
  1468. int cass_name_len)
  1469. {
  1470. CASSANDRA_TYPE_DEF *type= default_type_def;
  1471. for(uint i= 0; i < n_special_type_fields; i++)
  1472. {
  1473. if (cass_name_len == (int)special_type_field_names[i].length &&
  1474. memcmp(cass_name, special_type_field_names[i].str,
  1475. cass_name_len) == 0)
  1476. {
  1477. type= special_type_field_converters + i;
  1478. break;
  1479. }
  1480. }
  1481. return type;
  1482. }
  1483. int ha_cassandra::read_cassandra_columns(bool unpack_pk)
  1484. {
  1485. MEM_ROOT strings_root;
  1486. char *cass_name;
  1487. char *cass_value;
  1488. int cass_value_len, cass_name_len;
  1489. Field **field;
  1490. int res= 0;
  1491. ulong total_name_len= 0;
  1492. clear_alloc_root(&strings_root);
  1493. /*
  1494. cassandra_to_mariadb() calls will use field->store(...) methods, which
  1495. require that the column is in the table->write_set
  1496. */
  1497. my_bitmap_map *old_map;
  1498. old_map= dbug_tmp_use_all_columns(table, table->write_set);
  1499. /* Start with all fields being NULL */
  1500. for (field= table->field + 1; *field; field++)
  1501. (*field)->set_null();
  1502. while (!se->get_next_read_column(&cass_name, &cass_name_len,
  1503. &cass_value, &cass_value_len))
  1504. {
  1505. // map to our column. todo: use hash or something..
  1506. bool found= 0;
  1507. for (field= table->field + 1; *field; field++)
  1508. {
  1509. uint fieldnr= (*field)->field_index;
  1510. if ((!dyncol_set || dyncol_field != fieldnr) &&
  1511. !strcmp((*field)->field_name.str, cass_name))
  1512. {
  1513. found= 1;
  1514. (*field)->set_notnull();
  1515. if (field_converters[fieldnr]->cassandra_to_mariadb(cass_value,
  1516. cass_value_len))
  1517. {
  1518. print_conversion_error((*field)->field_name.str, cass_value,
  1519. cass_value_len);
  1520. res=1;
  1521. goto err;
  1522. }
  1523. break;
  1524. }
  1525. }
  1526. if (dyncol_set && !found)
  1527. {
  1528. DYNAMIC_COLUMN_VALUE val;
  1529. LEX_STRING nm;
  1530. CASSANDRA_TYPE_DEF *type= get_cassandra_field_def(cass_name,
  1531. cass_name_len);
  1532. nm.str= cass_name;
  1533. nm.length= cass_name_len;
  1534. if (nm.length > MAX_NAME_LENGTH)
  1535. {
  1536. se->print_error("Unable to convert value for field `%s`"
  1537. " from Cassandra's data format. Name"
  1538. " length exceed limit of %u: '%s'",
  1539. table->field[dyncol_field]->field_name.str,
  1540. (uint)MAX_NAME_LENGTH, cass_name);
  1541. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  1542. res=1;
  1543. goto err;
  1544. }
  1545. total_name_len+= cass_name_len;
  1546. if (nm.length > MAX_TOTAL_NAME_LENGTH)
  1547. {
  1548. se->print_error("Unable to convert value for field `%s`"
  1549. " from Cassandra's data format. Sum of all names"
  1550. " length exceed limit of %lu",
  1551. table->field[dyncol_field]->field_name.str,
  1552. cass_name, (uint)MAX_TOTAL_NAME_LENGTH);
  1553. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  1554. res=1;
  1555. goto err;
  1556. }
  1557. if ((res= (*(type->cassandra_to_dynamic))(cass_value,
  1558. cass_value_len, &val,
  1559. &strings_root)) ||
  1560. insert_dynamic(&dynamic_names, (uchar *) &nm) ||
  1561. insert_dynamic(&dynamic_values, (uchar *) &val))
  1562. {
  1563. if (res)
  1564. {
  1565. print_conversion_error(cass_name, cass_value, cass_value_len);
  1566. }
  1567. free_strings_memroot(&strings_root);
  1568. // EOM shouldm be already reported if happened
  1569. res= 1;
  1570. goto err;
  1571. }
  1572. }
  1573. }
  1574. dynamic_rec.length= 0;
  1575. if (dyncol_set)
  1576. {
  1577. if (mariadb_dyncol_create_many_named(&dynamic_rec,
  1578. dynamic_names.elements,
  1579. (LEX_STRING *)dynamic_names.buffer,
  1580. (DYNAMIC_COLUMN_VALUE *)
  1581. dynamic_values.buffer,
  1582. FALSE) < 0)
  1583. dynamic_rec.length= 0;
  1584. free_strings_memroot(&strings_root);
  1585. dynamic_values.elements= dynamic_names.elements= 0;
  1586. if (dynamic_rec.length == 0)
  1587. table->field[dyncol_field]->set_null();
  1588. else
  1589. {
  1590. Field_blob *blob= (Field_blob *)table->field[dyncol_field];
  1591. blob->set_notnull();
  1592. blob->store_length(dynamic_rec.length);
  1593. *((char **)(((char *)blob->ptr) + blob->pack_length_no_ptr()))=
  1594. dynamic_rec.str;
  1595. }
  1596. }
  1597. if (unpack_pk)
  1598. {
  1599. /* Unpack rowkey to primary key */
  1600. field= table->field;
  1601. (*field)->set_notnull();
  1602. se->get_read_rowkey(&cass_value, &cass_value_len);
  1603. if (rowkey_converter->cassandra_to_mariadb(cass_value, cass_value_len))
  1604. {
  1605. print_conversion_error((*field)->field_name.str, cass_value, cass_value_len);
  1606. res=1;
  1607. goto err;
  1608. }
  1609. }
  1610. err:
  1611. dbug_tmp_restore_column_map(table->write_set, old_map);
  1612. return res;
  1613. }
  1614. int ha_cassandra::read_dyncol(uint *count,
  1615. DYNAMIC_COLUMN_VALUE **vals,
  1616. LEX_STRING **names,
  1617. String *valcol)
  1618. {
  1619. String *strcol;
  1620. DYNAMIC_COLUMN col;
  1621. enum enum_dyncol_func_result rc;
  1622. DBUG_ENTER("ha_cassandra::read_dyncol");
  1623. Field *field= table->field[dyncol_field];
  1624. DBUG_ASSERT(field->type() == MYSQL_TYPE_BLOB);
  1625. /* It is blob and it does not use buffer */
  1626. strcol= field->val_str(NULL, valcol);
  1627. if (field->is_null())
  1628. {
  1629. *count= 0;
  1630. *names= 0;
  1631. *vals= 0;
  1632. DBUG_RETURN(0); // nothing to write
  1633. }
  1634. /*
  1635. dynamic_column_vals only read the string so we can
  1636. cheat here with assignment
  1637. */
  1638. bzero(&col, sizeof(col));
  1639. col.str= (char *)strcol->ptr();
  1640. col.length= strcol->length();
  1641. if ((rc= mariadb_dyncol_unpack(&col, count, names, vals)) < 0)
  1642. {
  1643. dynamic_column_error_message(rc);
  1644. DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
  1645. }
  1646. DBUG_RETURN(0);
  1647. }
  1648. int ha_cassandra::write_dynamic_row(uint count,
  1649. DYNAMIC_COLUMN_VALUE *vals,
  1650. LEX_STRING *names)
  1651. {
  1652. uint i;
  1653. DBUG_ENTER("ha_cassandra::write_dynamic_row");
  1654. DBUG_ASSERT(dyncol_set);
  1655. for (i= 0; i < count; i++)
  1656. {
  1657. char buff[16];
  1658. CASSANDRA_TYPE_DEF *type;
  1659. void *freemem= NULL;
  1660. char *cass_data;
  1661. int cass_data_len;
  1662. DBUG_PRINT("info", ("field %*s", (int)names[i].length, names[i].str));
  1663. type= get_cassandra_field_def(names[i].str, (int) names[i].length);
  1664. if ((*type->dynamic_to_cassandra)(vals +i, &cass_data, &cass_data_len,
  1665. buff, &freemem))
  1666. {
  1667. my_error(ER_WARN_DATA_OUT_OF_RANGE, MYF(0),
  1668. names[i].str, insert_lineno);
  1669. DBUG_RETURN(HA_ERR_GENERIC);
  1670. }
  1671. se->add_insert_column(names[i].str, names[i].length,
  1672. cass_data, cass_data_len);
  1673. if (freemem)
  1674. my_free(freemem);
  1675. }
  1676. DBUG_RETURN(0);
  1677. }
  1678. void ha_cassandra::free_dynamic_row(DYNAMIC_COLUMN_VALUE **vals,
  1679. LEX_STRING **names)
  1680. {
  1681. mariadb_dyncol_unpack_free(*names, *vals);
  1682. *vals= 0;
  1683. *names= 0;
  1684. }
  1685. int ha_cassandra::write_row(const uchar *buf)
  1686. {
  1687. my_bitmap_map *old_map;
  1688. int ires;
  1689. DBUG_ENTER("ha_cassandra::write_row");
  1690. if (!se && (ires= connect_and_check_options(table)))
  1691. DBUG_RETURN(ires);
  1692. if (!doing_insert_batch)
  1693. se->clear_insert_buffer();
  1694. old_map= dbug_tmp_use_all_columns(table, table->read_set);
  1695. insert_lineno++;
  1696. /* Convert the key */
  1697. char *cass_key;
  1698. int cass_key_len;
  1699. if (rowkey_converter->mariadb_to_cassandra(&cass_key, &cass_key_len))
  1700. {
  1701. my_error(ER_WARN_DATA_OUT_OF_RANGE, MYF(0),
  1702. rowkey_converter->field->field_name.str, insert_lineno);
  1703. dbug_tmp_restore_column_map(table->read_set, old_map);
  1704. DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
  1705. }
  1706. se->start_row_insert(cass_key, cass_key_len);
  1707. /* Convert other fields */
  1708. for (uint i= 1; i < table->s->fields; i++)
  1709. {
  1710. char *cass_data;
  1711. int cass_data_len;
  1712. if (dyncol_set && dyncol_field == i)
  1713. {
  1714. String valcol;
  1715. DYNAMIC_COLUMN_VALUE *vals;
  1716. LEX_STRING *names;
  1717. uint count;
  1718. int rc;
  1719. DBUG_ASSERT(field_converters[i] == NULL);
  1720. if (!(rc= read_dyncol(&count, &vals, &names, &valcol)))
  1721. rc= write_dynamic_row(count, vals, names);
  1722. free_dynamic_row(&vals, &names);
  1723. if (rc)
  1724. {
  1725. dbug_tmp_restore_column_map(table->read_set, old_map);
  1726. DBUG_RETURN(rc);
  1727. }
  1728. }
  1729. else
  1730. {
  1731. if (field_converters[i]->mariadb_to_cassandra(&cass_data,
  1732. &cass_data_len))
  1733. {
  1734. my_error(ER_WARN_DATA_OUT_OF_RANGE, MYF(0),
  1735. field_converters[i]->field->field_name.str, insert_lineno);
  1736. dbug_tmp_restore_column_map(table->read_set, old_map);
  1737. DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
  1738. }
  1739. se->add_insert_column(field_converters[i]->field->field_name.str, 0,
  1740. cass_data, cass_data_len);
  1741. }
  1742. }
  1743. dbug_tmp_restore_column_map(table->read_set, old_map);
  1744. bool res;
  1745. if (doing_insert_batch)
  1746. {
  1747. res= 0;
  1748. if (++insert_rows_batched >= THDVAR(table->in_use, insert_batch_size))
  1749. {
  1750. res= se->do_insert();
  1751. insert_rows_batched= 0;
  1752. }
  1753. }
  1754. else
  1755. res= se->do_insert();
  1756. if (res)
  1757. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  1758. DBUG_RETURN(res? HA_ERR_INTERNAL_ERROR: 0);
  1759. }
  1760. void ha_cassandra::start_bulk_insert(ha_rows rows, uint flags)
  1761. {
  1762. int ires;
  1763. if (!se && (ires= connect_and_check_options(table)))
  1764. return;
  1765. doing_insert_batch= true;
  1766. insert_rows_batched= 0;
  1767. se->clear_insert_buffer();
  1768. }
  1769. int ha_cassandra::end_bulk_insert()
  1770. {
  1771. DBUG_ENTER("ha_cassandra::end_bulk_insert");
  1772. if (!doing_insert_batch)
  1773. {
  1774. /* SQL layer can make end_bulk_insert call without start_bulk_insert call */
  1775. DBUG_RETURN(0);
  1776. }
  1777. /* Flush out the insert buffer */
  1778. doing_insert_batch= false;
  1779. bool bres= se->do_insert();
  1780. se->clear_insert_buffer();
  1781. DBUG_RETURN(bres? HA_ERR_INTERNAL_ERROR: 0);
  1782. }
  1783. int ha_cassandra::rnd_init(bool scan)
  1784. {
  1785. bool bres;
  1786. int ires;
  1787. DBUG_ENTER("ha_cassandra::rnd_init");
  1788. if (!se && (ires= connect_and_check_options(table)))
  1789. DBUG_RETURN(ires);
  1790. if (!scan)
  1791. {
  1792. /* Prepare for rnd_pos() calls. We don't need to anything. */
  1793. DBUG_RETURN(0);
  1794. }
  1795. if (dyncol_set)
  1796. {
  1797. se->clear_read_all_columns();
  1798. }
  1799. else
  1800. {
  1801. se->clear_read_columns();
  1802. for (uint i= 1; i < table->s->fields; i++)
  1803. se->add_read_column(table->field[i]->field_name.str);
  1804. }
  1805. se->read_batch_size= THDVAR(table->in_use, rnd_batch_size);
  1806. bres= se->get_range_slices(false);
  1807. if (bres)
  1808. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  1809. DBUG_RETURN(bres? HA_ERR_INTERNAL_ERROR: 0);
  1810. }
  1811. int ha_cassandra::rnd_end()
  1812. {
  1813. DBUG_ENTER("ha_cassandra::rnd_end");
  1814. se->finish_reading_range_slices();
  1815. DBUG_RETURN(0);
  1816. }
  1817. int ha_cassandra::rnd_next(uchar *buf)
  1818. {
  1819. int rc;
  1820. bool reached_eof;
  1821. DBUG_ENTER("ha_cassandra::rnd_next");
  1822. // Unpack and return the next record.
  1823. if (se->get_next_range_slice_row(&reached_eof))
  1824. {
  1825. rc= HA_ERR_INTERNAL_ERROR;
  1826. }
  1827. else
  1828. {
  1829. if (reached_eof)
  1830. rc= HA_ERR_END_OF_FILE;
  1831. else
  1832. rc= read_cassandra_columns(true);
  1833. }
  1834. DBUG_RETURN(rc);
  1835. }
  1836. int ha_cassandra::delete_all_rows()
  1837. {
  1838. bool bres;
  1839. int ires;
  1840. DBUG_ENTER("ha_cassandra::delete_all_rows");
  1841. if (!se && (ires= connect_and_check_options(table)))
  1842. DBUG_RETURN(ires);
  1843. bres= se->truncate();
  1844. if (bres)
  1845. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  1846. DBUG_RETURN(bres? HA_ERR_INTERNAL_ERROR: 0);
  1847. }
  1848. int ha_cassandra::delete_row(const uchar *buf)
  1849. {
  1850. bool bres;
  1851. DBUG_ENTER("ha_cassandra::delete_row");
  1852. bres= se->remove_row();
  1853. if (bres)
  1854. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  1855. DBUG_RETURN(bres? HA_ERR_INTERNAL_ERROR: 0);
  1856. }
  1857. int ha_cassandra::info(uint flag)
  1858. {
  1859. DBUG_ENTER("ha_cassandra::info");
  1860. if (!table)
  1861. return 1;
  1862. if (flag & HA_STATUS_VARIABLE)
  1863. {
  1864. stats.records= 1000;
  1865. stats.deleted= 0;
  1866. }
  1867. if (flag & HA_STATUS_CONST)
  1868. {
  1869. ref_length= table->field[0]->key_length();
  1870. }
  1871. DBUG_RETURN(0);
  1872. }
  1873. void key_copy(uchar *to_key, const uchar *from_record, KEY *key_info,
  1874. uint key_length, bool with_zerofill);
  1875. void ha_cassandra::position(const uchar *record)
  1876. {
  1877. DBUG_ENTER("ha_cassandra::position");
  1878. /* Copy the primary key to rowid */
  1879. key_copy(ref, (uchar*)record, &table->key_info[0],
  1880. table->field[0]->key_length(), true);
  1881. DBUG_VOID_RETURN;
  1882. }
  1883. int ha_cassandra::rnd_pos(uchar *buf, uchar *pos)
  1884. {
  1885. int rc;
  1886. DBUG_ENTER("ha_cassandra::rnd_pos");
  1887. int save_active_index= active_index;
  1888. active_index= 0; /* The primary key */
  1889. rc= index_read_map(buf, pos, key_part_map(1), HA_READ_KEY_EXACT);
  1890. active_index= save_active_index;
  1891. DBUG_RETURN(rc);
  1892. }
  1893. int ha_cassandra::reset()
  1894. {
  1895. doing_insert_batch= false;
  1896. insert_lineno= 0;
  1897. if (se)
  1898. {
  1899. se->set_consistency_levels(THDVAR(table->in_use, read_consistency),
  1900. THDVAR(table->in_use, write_consistency));
  1901. se->set_n_retries(THDVAR(table->in_use, failure_retries));
  1902. }
  1903. return 0;
  1904. }
  1905. /////////////////////////////////////////////////////////////////////////////
  1906. // MRR implementation
  1907. /////////////////////////////////////////////////////////////////////////////
  1908. /*
  1909. - The key can be only primary key
  1910. - allow equality-ranges only.
  1911. - anything else?
  1912. */
  1913. ha_rows ha_cassandra::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
  1914. void *seq_init_param,
  1915. uint n_ranges, uint *bufsz,
  1916. uint *flags, Cost_estimate *cost)
  1917. {
  1918. /* No support for const ranges so far */
  1919. return HA_POS_ERROR;
  1920. }
  1921. ha_rows ha_cassandra::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
  1922. uint key_parts, uint *bufsz,
  1923. uint *flags, Cost_estimate *cost)
  1924. {
  1925. /* Can only be equality lookups on the primary key... */
  1926. // TODO anything else?
  1927. *flags &= ~HA_MRR_USE_DEFAULT_IMPL;
  1928. *flags |= HA_MRR_NO_ASSOCIATION;
  1929. return 10;
  1930. }
  1931. int ha_cassandra::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
  1932. uint n_ranges, uint mode, HANDLER_BUFFER *buf)
  1933. {
  1934. int res;
  1935. mrr_iter= seq->init(seq_init_param, n_ranges, mode);
  1936. mrr_funcs= *seq;
  1937. res= mrr_start_read();
  1938. return (res? HA_ERR_INTERNAL_ERROR: 0);
  1939. }
  1940. bool ha_cassandra::mrr_start_read()
  1941. {
  1942. uint key_len;
  1943. my_bitmap_map *old_map;
  1944. old_map= dbug_tmp_use_all_columns(table, table->read_set);
  1945. se->new_lookup_keys();
  1946. while (!(source_exhausted= mrr_funcs.next(mrr_iter, &mrr_cur_range)))
  1947. {
  1948. char *cass_key;
  1949. int cass_key_len;
  1950. DBUG_ASSERT(mrr_cur_range.range_flag & EQ_RANGE);
  1951. uchar *key= (uchar*)mrr_cur_range.start_key.key;
  1952. key_len= mrr_cur_range.start_key.length;
  1953. //key_len= calculate_key_len(table, active_index, key, keypart_map); // NEED THIS??
  1954. store_key_image_to_rec(table->field[0], (uchar*)key, key_len);
  1955. rowkey_converter->mariadb_to_cassandra(&cass_key, &cass_key_len);
  1956. // Primitive buffer control
  1957. if ((ulong) se->add_lookup_key(cass_key, cass_key_len) >
  1958. THDVAR(table->in_use, multiget_batch_size))
  1959. break;
  1960. }
  1961. dbug_tmp_restore_column_map(table->read_set, old_map);
  1962. return se->multiget_slice();
  1963. }
  1964. int ha_cassandra::multi_range_read_next(range_id_t *range_info)
  1965. {
  1966. int res;
  1967. while(1)
  1968. {
  1969. if (!se->get_next_multiget_row())
  1970. {
  1971. res= read_cassandra_columns(true);
  1972. break;
  1973. }
  1974. else
  1975. {
  1976. if (source_exhausted)
  1977. {
  1978. res= HA_ERR_END_OF_FILE;
  1979. break;
  1980. }
  1981. else
  1982. {
  1983. if (mrr_start_read())
  1984. {
  1985. res= HA_ERR_INTERNAL_ERROR;
  1986. break;
  1987. }
  1988. }
  1989. }
  1990. /*
  1991. We get here if we've refilled the buffer and done another read. Try
  1992. reading from results again
  1993. */
  1994. }
  1995. return res;
  1996. }
  1997. int ha_cassandra::multi_range_read_explain_info(uint mrr_mode, char *str, size_t size)
  1998. {
  1999. const char *mrr_str= "multiget_slice";
  2000. if (!(mrr_mode & HA_MRR_USE_DEFAULT_IMPL))
  2001. {
  2002. uint mrr_str_len= strlen(mrr_str);
  2003. uint copy_len= MY_MIN(mrr_str_len, size);
  2004. memcpy(str, mrr_str, size);
  2005. return copy_len;
  2006. }
  2007. return 0;
  2008. }
  2009. class Column_name_enumerator_impl : public Column_name_enumerator
  2010. {
  2011. ha_cassandra *obj;
  2012. uint idx;
  2013. public:
  2014. Column_name_enumerator_impl(ha_cassandra *obj_arg) : obj(obj_arg), idx(1) {}
  2015. const char* get_next_name()
  2016. {
  2017. if (idx == obj->table->s->fields)
  2018. return NULL;
  2019. else
  2020. return obj->table->field[idx++]->field_name.str;
  2021. }
  2022. };
  2023. int ha_cassandra::update_row(const uchar *old_data, const uchar *new_data)
  2024. {
  2025. DYNAMIC_COLUMN_VALUE *oldvals, *vals;
  2026. LEX_STRING *oldnames, *names;
  2027. uint oldcount, count;
  2028. String oldvalcol, valcol;
  2029. my_bitmap_map *old_map;
  2030. int res;
  2031. DBUG_ENTER("ha_cassandra::update_row");
  2032. /* Currently, it is guaranteed that new_data == table->record[0] */
  2033. DBUG_ASSERT(new_data == table->record[0]);
  2034. /* For now, just rewrite the full record */
  2035. se->clear_insert_buffer();
  2036. old_map= dbug_tmp_use_all_columns(table, table->read_set);
  2037. char *old_key;
  2038. int old_key_len;
  2039. se->get_read_rowkey(&old_key, &old_key_len);
  2040. /* Get the key we're going to write */
  2041. char *new_key;
  2042. int new_key_len;
  2043. if (rowkey_converter->mariadb_to_cassandra(&new_key, &new_key_len))
  2044. {
  2045. my_error(ER_WARN_DATA_OUT_OF_RANGE, MYF(0),
  2046. rowkey_converter->field->field_name.str, insert_lineno);
  2047. dbug_tmp_restore_column_map(table->read_set, old_map);
  2048. DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
  2049. }
  2050. /*
  2051. Compare it to the key we've read. For all types that Cassandra supports,
  2052. binary byte-wise comparison can be used
  2053. */
  2054. bool new_primary_key;
  2055. if (new_key_len != old_key_len || memcmp(old_key, new_key, new_key_len))
  2056. new_primary_key= true;
  2057. else
  2058. new_primary_key= false;
  2059. if (dyncol_set)
  2060. {
  2061. Field *field= table->field[dyncol_field];
  2062. /* move to get old_data */
  2063. my_ptrdiff_t diff;
  2064. diff= (my_ptrdiff_t) (old_data - new_data);
  2065. field->move_field_offset(diff); // Points now at old_data
  2066. if ((res= read_dyncol(&oldcount, &oldvals, &oldnames, &oldvalcol)))
  2067. DBUG_RETURN(res);
  2068. field->move_field_offset(-diff); // back to new_data
  2069. if ((res= read_dyncol(&count, &vals, &names, &valcol)))
  2070. {
  2071. free_dynamic_row(&oldvals, &oldnames);
  2072. DBUG_RETURN(res);
  2073. }
  2074. }
  2075. if (new_primary_key)
  2076. {
  2077. /*
  2078. Primary key value changed. This is essentially a DELETE + INSERT.
  2079. Add a DELETE operation into the batch
  2080. */
  2081. Column_name_enumerator_impl name_enumerator(this);
  2082. se->add_row_deletion(old_key, old_key_len, &name_enumerator,
  2083. oldnames,
  2084. (dyncol_set ? oldcount : 0));
  2085. oldcount= 0; // they will be deleted
  2086. }
  2087. se->start_row_insert(new_key, new_key_len);
  2088. /* Convert other fields */
  2089. for (uint i= 1; i < table->s->fields; i++)
  2090. {
  2091. char *cass_data;
  2092. int cass_data_len;
  2093. if (dyncol_set && dyncol_field == i)
  2094. {
  2095. DBUG_ASSERT(field_converters[i] == NULL);
  2096. if ((res= write_dynamic_row(count, vals, names)))
  2097. goto err;
  2098. }
  2099. else
  2100. {
  2101. if (field_converters[i]->mariadb_to_cassandra(&cass_data, &cass_data_len))
  2102. {
  2103. my_error(ER_WARN_DATA_OUT_OF_RANGE, MYF(0),
  2104. field_converters[i]->field->field_name.str, insert_lineno);
  2105. dbug_tmp_restore_column_map(table->read_set, old_map);
  2106. DBUG_RETURN(HA_ERR_INTERNAL_ERROR);
  2107. }
  2108. se->add_insert_column(field_converters[i]->field->field_name.str, 0,
  2109. cass_data, cass_data_len);
  2110. }
  2111. }
  2112. if (dyncol_set)
  2113. {
  2114. /* find removed fields */
  2115. uint i= 0, j= 0;
  2116. /* both array are sorted */
  2117. for(; i < oldcount; i++)
  2118. {
  2119. int scmp= 0;
  2120. while (j < count &&
  2121. (scmp = mariadb_dyncol_column_cmp_named(names + j,
  2122. oldnames + i)) < 0)
  2123. j++;
  2124. if (j < count &&
  2125. scmp == 0)
  2126. j++;
  2127. else
  2128. se->add_insert_delete_column(oldnames[i].str, oldnames[i].length);
  2129. }
  2130. }
  2131. dbug_tmp_restore_column_map(table->read_set, old_map);
  2132. res= se->do_insert();
  2133. if (res)
  2134. my_error(ER_INTERNAL_ERROR, MYF(0), se->error_str());
  2135. err:
  2136. if (dyncol_set)
  2137. {
  2138. free_dynamic_row(&oldvals, &oldnames);
  2139. free_dynamic_row(&vals, &names);
  2140. }
  2141. DBUG_RETURN(res? HA_ERR_INTERNAL_ERROR: 0);
  2142. }
  2143. /*
  2144. We can't really have any locks for Cassandra Storage Engine. We're reading
  2145. from Cassandra cluster, and other clients can asynchronously modify the data.
  2146. We can enforce locking within this process, but this will not be useful.
  2147. Thus, store_lock() should express that:
  2148. - Writes do not block other writes
  2149. - Reads should not block anything either, including INSERTs.
  2150. */
  2151. THR_LOCK_DATA **ha_cassandra::store_lock(THD *thd,
  2152. THR_LOCK_DATA **to,
  2153. enum thr_lock_type lock_type)
  2154. {
  2155. DBUG_ENTER("ha_cassandra::store_lock");
  2156. if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
  2157. {
  2158. /* Writes allow other writes */
  2159. if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
  2160. lock_type <= TL_WRITE))
  2161. lock_type = TL_WRITE_ALLOW_WRITE;
  2162. /* Reads allow everything, including INSERTs */
  2163. if (lock_type == TL_READ_NO_INSERT)
  2164. lock_type = TL_READ;
  2165. lock.type= lock_type;
  2166. }
  2167. *to++= &lock;
  2168. DBUG_RETURN(to);
  2169. }
  2170. ha_rows ha_cassandra::records_in_range(uint inx, key_range *min_key,
  2171. key_range *max_key)
  2172. {
  2173. DBUG_ENTER("ha_cassandra::records_in_range");
  2174. DBUG_RETURN(HA_POS_ERROR); /* Range scans are not supported */
  2175. }
  2176. /**
  2177. check_if_incompatible_data() called if ALTER TABLE can't detect otherwise
  2178. if new and old definition are compatible
  2179. @details If there are no other explicit signs like changed number of
  2180. fields this function will be called by compare_tables()
  2181. (sql/sql_tables.cc) to decide should we rewrite whole table or only .frm
  2182. file.
  2183. */
  2184. bool ha_cassandra::check_if_incompatible_data(HA_CREATE_INFO *info,
  2185. uint table_changes)
  2186. {
  2187. DBUG_ENTER("ha_cassandra::check_if_incompatible_data");
  2188. /* Checked, we intend to have this empty for Cassandra SE. */
  2189. DBUG_RETURN(COMPATIBLE_DATA_YES);
  2190. }
  2191. void Cassandra_se_interface::print_error(const char *format, ...)
  2192. {
  2193. va_list ap;
  2194. va_start(ap, format);
  2195. // it's not a problem if output was truncated
  2196. my_vsnprintf(err_buffer, sizeof(err_buffer), format, ap);
  2197. va_end(ap);
  2198. }
  2199. struct st_mysql_storage_engine cassandra_storage_engine=
  2200. { MYSQL_HANDLERTON_INTERFACE_VERSION };
  2201. static SHOW_VAR cassandra_status_variables[]= {
  2202. {"row_inserts",
  2203. (char*) &cassandra_counters.row_inserts, SHOW_LONG},
  2204. {"row_insert_batches",
  2205. (char*) &cassandra_counters.row_insert_batches, SHOW_LONG},
  2206. {"multiget_keys_scanned",
  2207. (char*) &cassandra_counters.multiget_keys_scanned, SHOW_LONG},
  2208. {"multiget_reads",
  2209. (char*) &cassandra_counters.multiget_reads, SHOW_LONG},
  2210. {"multiget_rows_read",
  2211. (char*) &cassandra_counters.multiget_rows_read, SHOW_LONG},
  2212. {"network_exceptions",
  2213. (char*) &cassandra_counters.network_exceptions, SHOW_LONG},
  2214. {"timeout_exceptions",
  2215. (char*) &cassandra_counters.timeout_exceptions, SHOW_LONG},
  2216. {"unavailable_exceptions",
  2217. (char*) &cassandra_counters.unavailable_exceptions, SHOW_LONG},
  2218. {NullS, NullS, SHOW_LONG}
  2219. };
  2220. maria_declare_plugin(cassandra)
  2221. {
  2222. MYSQL_STORAGE_ENGINE_PLUGIN,
  2223. &cassandra_storage_engine,
  2224. "CASSANDRA",
  2225. "Monty Program Ab",
  2226. "Cassandra storage engine",
  2227. PLUGIN_LICENSE_GPL,
  2228. cassandra_init_func, /* Plugin Init */
  2229. cassandra_done_func, /* Plugin Deinit */
  2230. 0x0001, /* version number (0.1) */
  2231. cassandra_status_variables, /* status variables */
  2232. cassandra_system_variables, /* system variables */
  2233. "0.1", /* string version */
  2234. MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */
  2235. }
  2236. maria_declare_plugin_end;