Server IP : 104.21.38.3 / Your IP : 172.69.176.166 Web Server : Apache System : Linux krdc-ubuntu-s-2vcpu-4gb-amd-blr1-01.localdomain 5.15.0-142-generic #152-Ubuntu SMP Mon May 19 10:54:31 UTC 2025 x86_64 User : www ( 1000) PHP Version : 7.4.33 Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /www/server/mysql/src/plugin/innodb_memcached/innodb_memcache/src/ |
Upload File : |
/***************************************************************************** Copyright (c) 2011, 2023, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is also distributed with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have included with MySQL. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA ****************************************************************************/ /**************************************************//** @file handler_api.c Created 3/14/2011 Jimmy Yang *******************************************************/ #include "handler_api.h" #include <my_global.h> #include <stdlib.h> #include <ctype.h> #include <mysql_version.h> #include <mysql/plugin.h> #include <my_dir.h> #include "my_thread.h" #include "my_sys.h" #include "m_string.h" #include "sql_plugin.h" #include "table.h" #include "sql_class.h" #include <sql_base.h> #include "key.h" #include "lock.h" #include "transaction.h" #include "sql_handler.h" #include "handler.h" #include "mysqld_thd_manager.h" #include "log_event.h" #include "innodb_config.h" #include "binlog.h" /** Some handler functions defined in sql/sql_table.cc and sql/handler.cc etc. and being used here */ extern int write_bin_log(THD *thd, bool clear_error, const char *query, size_t query_length, bool is_trans= false); /** function to close a connection and thd, defined in sql/handler.cc */ extern void ha_close_connection(THD* thd); /** binlog a row operation */ extern int binlog_log_row(TABLE* table, const uchar *before_record, const uchar *after_record, Log_func* log_func); /**********************************************************************//** Create a THD object. @return a pointer to the THD object, NULL if failed */ void* handler_create_thd( /*===============*/ bool enable_binlog) /*!< in: whether to enable binlog */ { THD* thd; if (enable_binlog && !binlog_enabled()) { fprintf(stderr, " InnoDB_Memcached: MySQL server" " binlog not enabled\n"); return(NULL); } my_thread_init(); thd = new THD; if (!thd) { return(NULL); } thd->get_protocol_classic()->init_net((st_vio *) 0); thd->set_new_thread_id(); thd->thread_stack = reinterpret_cast<char*>(&thd); thd->store_globals(); if (enable_binlog) { thd->binlog_setup_trx_data(); /* set binlog_format to "ROW" */ thd->set_current_stmt_binlog_format_row(); } return(thd); } /**********************************************************************//** This is used to temporarily switch to another session, so that POSIX thread looks like session attached to */ void handler_thd_attach( /*===============*/ void* my_thd, /*!< in: THD* */ void** original_thd) /*!< out: current THD */ { THD* thd = static_cast<THD*>(my_thd); if (original_thd) { *original_thd = current_thd; } thd->store_globals(); } /**********************************************************************//** Returns a MySQL "TABLE" object with specified database name and table name. @return a pointer to the TABLE object, NULL if does not exist */ void* handler_open_table( /*===============*/ void* my_thd, /*!< in: THD* */ const char* db_name, /*!< in: NUL terminated database name */ const char* table_name, /*!< in: NUL terminated table name */ int lock_type) /*!< in: lock mode */ { TABLE_LIST tables; THD* thd = static_cast<THD*>(my_thd); Open_table_context table_ctx(thd, 0); thr_lock_type lock_mode; lock_mode = (lock_type <= HDL_READ) ? TL_READ : TL_WRITE; tables.init_one_table(db_name, strlen(db_name), table_name, strlen(table_name), table_name, lock_mode); /* For flush, we need to request exclusive mdl lock. */ if (lock_type == HDL_FLUSH) { MDL_REQUEST_INIT(&tables.mdl_request, MDL_key::TABLE, db_name, table_name, MDL_EXCLUSIVE, MDL_TRANSACTION); } else { MDL_REQUEST_INIT(&tables.mdl_request, MDL_key::TABLE, db_name, table_name, (lock_mode > TL_READ) ? MDL_SHARED_WRITE : MDL_SHARED_READ, MDL_TRANSACTION); } if (!open_table(thd, &tables, &table_ctx)) { TABLE* table = tables.table; table->use_all_columns(); return(table); } return(NULL); } /**********************************************************************//** Wrapper of function binlog_log_row() to binlog an operation on a row */ void handler_binlog_row( /*===============*/ void* my_thd, /*!< in: THD* */ void* my_table, /*!< in: TABLE structure */ int mode) /*!< in: type of DML */ { TABLE* table = static_cast<TABLE*>(my_table); THD* thd = static_cast<THD*>(my_thd); Log_func* log_func; if (thd->get_binlog_table_maps() == 0) { /* Write the table map and BEGIN mark */ thd->binlog_write_table_map( static_cast<TABLE*>(my_table), 1, 0); } switch (mode) { case HDL_UPDATE: /* Updated record must be allocated and filled */ assert(table->record[1]); log_func = Update_rows_log_event::binlog_row_logging_function; binlog_log_row(table, table->record[1], table->record[0], log_func); break; case HDL_INSERT: log_func = Write_rows_log_event::binlog_row_logging_function; binlog_log_row(table, 0, table->record[0], log_func); break; case HDL_DELETE: log_func = Delete_rows_log_event::binlog_row_logging_function; binlog_log_row(table, table->record[0], 0, log_func); break; default: assert(0); } } /**********************************************************************//** Commit and flush binlog from cache to binlog file */ void handler_binlog_commit( /*==================*/ void* my_thd, /*!< in: THD* */ void* my_table) /*!< in: TABLE structure */ { THD* thd = static_cast<THD*>(my_thd); if (tc_log) { tc_log->commit(thd, true); } trans_commit_stmt(thd); } /**********************************************************************//** Rollback a transaction */ void handler_binlog_rollback( /*====================*/ void* my_thd, /*!< in: THD* */ void* my_table) /*!< in: TABLE structure */ { THD* thd = static_cast<THD*>(my_thd); /* Memcached plugin doesn't use thd_mark_transaction_to_rollback() on deadlocks. So no special handling for this flag is needed. */ assert(! thd->transaction_rollback_request); if (tc_log) { tc_log->rollback(thd, true); } trans_rollback_stmt(thd); } /**********************************************************************//** Binlog a truncate table statement */ void handler_binlog_truncate( /*====================*/ void* my_thd, /*!< in: THD* */ char* table_name) /*!< in: table name */ { THD* thd = (THD*) my_thd; char query_str[MAX_FULL_NAME_LEN + 16]; int len; memset(query_str, 0, sizeof(query_str)); assert(strlen(table_name) < MAX_FULL_NAME_LEN); snprintf(query_str, MAX_FULL_NAME_LEN + 16, "%s %s", "truncate table", table_name); len = strlen(query_str); write_bin_log(thd, 1, query_str, len); } /**********************************************************************//** Reset TABLE->record[0] */ void handler_rec_init( /*=============*/ void* my_table) /*!< in/out: TABLE structure */ { empty_record(static_cast<TABLE*>(my_table)); } /**********************************************************************//** Store a string in TABLE->record[0] for field specified by "field_id" */ void handler_rec_setup_str( /*==================*/ void* my_table, /*!< in/out: TABLE structure */ int field_id, /*!< in: Field ID for the field */ const char* str, /*!< in: string to set */ int len) /*!< in: length of string */ { Field* fld; TABLE* table = static_cast<TABLE*>(my_table); fld = table->field[field_id]; assert(len >= 0); if (len) { fld->store(str, len, &my_charset_bin); fld->set_notnull(); } else { fld->set_null(); } } /**********************************************************************//** Set up an integer field in TABLE->record[0] */ void handler_rec_setup_int( /*==================*/ void* my_table, /*!< in/out: TABLE structure */ int field_id, /*!< in: Field ID for the field */ int value, /*!< in: value to set */ bool unsigned_flag, /*!< in: whether it is unsigned */ bool is_null) /*!< in: whether it is null value */ { Field* fld; TABLE* table = static_cast<TABLE*>(my_table); fld = table->field[field_id]; if (is_null) { fld->set_null(); } else { fld->set_notnull(); fld->store(value, unsigned_flag); } } /**********************************************************************//** Set up an unsigned int64 field in TABLE->record[0] */ void handler_rec_setup_uint64( /*=====================*/ void* my_table, /*!< in/out: TABLE structure */ int field_id, /*!< in: Field ID for the field */ unsigned long long value, /*!< in: value to set */ bool unsigned_flag, /*!< in: whether it is unsigned */ bool is_null) /*!< in: whether it is null value */ { Field* fld; TABLE* table = static_cast<TABLE*>(my_table); fld = table->field[field_id]; if (is_null) { fld->set_null(); } else { fld->set_notnull(); fld->store(value, unsigned_flag); } } /**********************************************************************//** Store a record */ void handler_store_record( /*=================*/ void* my_table) /*!< in: TABLE */ { store_record(static_cast<TABLE*>(my_table), record[1]); } /**********************************************************************//** Close the handler */ void handler_close_thd( /*==============*/ void* my_thd) /*!< in: THD */ { THD* thd= static_cast<THD*>(my_thd); /* destructor will not free it, because net.vio is 0. */ thd->get_protocol_classic()->end_net(); thd->release_resources(); delete (thd); } /**********************************************************************//** Check if global read lock is active */ bool handler_check_global_read_lock_active() { return Global_read_lock::global_read_lock_active(); } /**********************************************************************//** Unlock a table and commit the transaction return 0 if failed to commit the transaction */ int handler_unlock_table( /*=================*/ void* my_thd, /*!< in: thread */ void* my_table, /*!< in: Table metadata */ int mode) /*!< in: mode */ { int result; THD* thd = static_cast<THD*>(my_thd); TABLE* table = static_cast<TABLE*>(my_table); thr_lock_type lock_mode; lock_mode = (mode & HDL_READ) ? TL_READ : TL_WRITE; if (lock_mode == TL_WRITE) { query_cache.invalidate(thd, table, TRUE); table->file->ha_release_auto_increment(); } result = trans_commit_stmt(thd); if (thd->lock) { mysql_unlock_tables(thd, thd->lock); } close_mysql_tables(thd); thd->lock = 0; return(result); } /********************************************************************** Following APIs can perform DMLs through MySQL handler interface. They are currently disabled and under HANDLER_API_MEMCACHED define **********************************************************************/ #ifdef HANDLER_API_MEMCACHED /**********************************************************************//** Search table for a record with particular search criteria @return a pointer to table->record[0] */ uchar* handler_select_rec( /*===============*/ TABLE* my_table, /*!< in: TABLE structure */ field_arg_t* srch_args, /*!< in: field to search */ int idx_to_use) /*!< in: index to use */ { KEY* key_info = &my_table->key_info[0]; uchar* srch_buf = new uchar[key_info->key_length]; size_t total_key_len = 0; key_part_map part_map; int result; handler* handle = my_table->file; assert(srch_args->num_arg <= key_info->key_parts); for (unsigned int i = 0; i < key_info->key_parts; i++) { KEY_PART_INFO* key_part; key_part = &key_info->key_part[i]; if (i < srch_args->num_arg) { int srch_len = srch_args->len[i]; assert(srch_len >= 0); if (srch_len != 0) { key_part->field->set_null(); } else { char* srch_value = srch_args->value[i]; key_part->field->set_notnull(); key_part->field->store(srch_value, srch_len, &my_charset_bin); total_key_len += key_part->store_length; } } else { key_part->field->set_null(); } } assert(key_info->key_length >= total_key_len); key_copy(srch_buf, my_table->record[0], key_info, total_key_len); my_table->read_set = &my_table->s->all_set; /* Max column supported is 4096 */ assert(srch_args->num_arg <= 4096); part_map = (1 << srch_args->num_arg) - 1; handle->ha_index_or_rnd_end(); handle->ha_index_init(idx_to_use, 1); result = handle->index_read_map(my_table->record[0], srch_buf, part_map, HA_READ_KEY_EXACT); delete[] srch_buf; if (!result) { return(my_table->record[0]); } return(NULL); } /**********************************************************************//** Insert a record to the table return 0 if successfully inserted */ int handler_insert_rec( /*===============*/ TABLE* my_table, /*!< in: TABLE structure */ field_arg_t* store_args) /*!< in: inserting row data */ { uchar* insert_buf; KEY* key_info = &(table->key_info[0]); handler* handle = my_table->file; empty_record(my_table); assert(table->reginfo.lock_type > TL_READ && table->reginfo.lock_type <= TL_WRITE_ONLY); insert_buf = my_table->record[0]; memset(insert_buf, 0, my_table->s->null_bytes); assert(store_args->num_arg == key_info->key_parts); for (unsigned int i = 0; i < key_info->key_parts; i++) { Field* fld; fld = table->field[i]; if (store_args->len[i]) { fld->store(store_args->value[i], store_args->len[i], &my_charset_bin); fld->set_notnull(); } else { fld->set_null(); } } return(handle->ha_write_row((uchar *)my_table->record[0])); } /**********************************************************************//** Update a record return 0 if successfully inserted */ int handler_update_rec( /*===============*/ TABLE* my_table, /*!< in: TABLE structure */ field_arg_t* store_args) /*!< in: update row data */ { uchar* buf = my_table->record[0]; handler* handle = my_table->file; KEY* key_info = &my_table->key_info[0]; store_record(my_table, record[1]); for (unsigned int i = 0; i < key_info->key_parts; i++) { Field* fld; fld = my_table->field[i]; fld->store(store_args->value[i], store_args->len[i], &my_charset_bin); fld->set_notnull(); } return(handle->ha_update_row(my_table->record[1], buf)); } /**********************************************************************//** Delete a record return 0 if successfully inserted */ int handler_delete_rec( /*===============*/ TABLE* my_table) /*!< in: TABLE structure */ { return(my_table->file->ha_delete_row(my_table->record[0])); } /**********************************************************************//** Lock a table return a lock structure pointer on success, NULL on error */ MYSQL_LOCK * handler_lock_table( /*===============*/ THD* my_thd, /*!< in: thread */ TABLE* my_table, /*!< in: Table metadata */ thr_lock_type lock_mode) /*!< in: lock mode */ { my_table->reginfo.lock_type = lock_mode; my_thd->lock = mysql_lock_tables(my_thd, &my_table, 1, 0); return(my_thd->lock); } #endif /* HANDLER_API_MEMCACHED */