mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
MDEV-10139 Support for SEQUENCE objects
Working features: CREATE OR REPLACE [TEMPORARY] SEQUENCE [IF NOT EXISTS] name [ INCREMENT [ BY | = ] increment ] [ MINVALUE [=] minvalue | NO MINVALUE ] [ MAXVALUE [=] maxvalue | NO MAXVALUE ] [ START [ WITH | = ] start ] [ CACHE [=] cache ] [ [ NO ] CYCLE ] ENGINE=xxx COMMENT=".." SELECT NEXT VALUE FOR sequence_name; SELECT NEXTVAL(sequence_name); SELECT PREVIOUS VALUE FOR sequence_name; SELECT LASTVAL(sequence_name); SHOW CREATE SEQUENCE sequence_name; SHOW CREATE TABLE sequence_name; CREATE TABLE sequence-structure ... SEQUENCE=1 ALTER TABLE sequence RENAME TO sequence2; RENAME TABLE sequence TO sequence2; DROP [TEMPORARY] SEQUENCE [IF EXISTS] sequence_names Missing features - SETVAL(value,sequence_name), to be used with replication. - Check replication, including checking that sequence tables are marked not transactional. - Check that a commit happens for NEXT VALUE that changes table data (may already work) - ALTER SEQUENCE. ANSI SQL version of setval. - Share identical sequence entries to not add things twice to table list. - testing insert/delete/update/truncate/load data - Run and fix Alibaba sequence tests (part of mysql-test/suite/sql_sequence) - Write documentation for NEXT VALUE / PREVIOUS_VALUE - NEXTVAL in DEFAULT - Ensure that NEXTVAL in DEFAULT uses database from base table - Two NEXTVAL for same row should give same answer. - Oracle syntax sequence_table.nextval, without any FOR or FROM. - Sequence tables are treated as 'not read constant tables' by SELECT; Would be better if we would have a separate list for sequence tables so that select doesn't know about them, except if refereed to with FROM. Other things done: - Improved output for safemalloc backtrack - frm_type_enum changed to Table_type - Removed lex->is_view and replaced with lex->table_type. This allows use to more easy check if item is view, sequence or table. - Added table flag HA_CAN_TABLES_WITHOUT_ROLLBACK, needed for handlers that want's to support sequences - Added handler calls: - engine_name(), to simplify getting engine name for partition and sequences - update_first_row(), to be able to do efficient sequence implementations. - Made binlog_log_row() global to be able to call it from ha_sequence.cc - Added handler variable: row_already_logged, to be able to flag that the changed row is already logging to replication log. - Added CF_DB_CHANGE and CF_SCHEMA_CHANGE flags to simplify deny_updates_if_read_only_option() - Added sp_add_cfetch() to avoid new conflicts in sql_yacc.yy - Moved code for add_table_options() out from sql_show.cc::show_create_table() - Added String::append_longlong() and used it in sql_show.cc to simplify code. - Added extra option to dd_frm_type() and ha_table_exists to indicate if the table is a sequence. Needed by DROP SQUENCE to not drop a table.
This commit is contained in:
@ -41,6 +41,7 @@
|
||||
#include <mysql/psi/mysql_table.h>
|
||||
#include "debug_sync.h" // DEBUG_SYNC
|
||||
#include "sql_audit.h"
|
||||
#include "ha_sequence.h"
|
||||
|
||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||
#include "ha_partition.h"
|
||||
@ -291,7 +292,6 @@ handler *get_ha_partition(partition_info *part_info)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static const char **handler_errmsgs;
|
||||
|
||||
C_MODE_START
|
||||
@ -618,7 +618,7 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
|
||||
/*
|
||||
This is entirely for legacy. We will create a new "disk based" hton and a
|
||||
"memory" hton which will be configurable longterm. We should be able to
|
||||
remove partition and myisammrg.
|
||||
remove partition.
|
||||
*/
|
||||
switch (hton->db_type) {
|
||||
case DB_TYPE_HEAP:
|
||||
@ -630,6 +630,9 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
|
||||
case DB_TYPE_PARTITION_DB:
|
||||
partition_hton= hton;
|
||||
break;
|
||||
case DB_TYPE_SEQUENCE:
|
||||
sql_sequence_hton= hton;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
@ -2426,6 +2429,11 @@ err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LEX_STRING *handler::engine_name()
|
||||
{
|
||||
return hton_name(ht);
|
||||
}
|
||||
|
||||
|
||||
double handler::keyread_time(uint index, uint ranges, ha_rows rows)
|
||||
{
|
||||
@ -2549,6 +2557,7 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode,
|
||||
}
|
||||
reset_statistics();
|
||||
internal_tmp_table= MY_TEST(test_if_locked & HA_OPEN_INTERNAL_TABLE);
|
||||
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
@ -2797,10 +2806,11 @@ int handler::ha_rnd_init_with_error(bool scan)
|
||||
|
||||
|
||||
/**
|
||||
Read first row (only) from a table.
|
||||
Read first row (only) from a table. Used for reading tables with
|
||||
only one row, either based on table statistics or if table is a SEQUENCE.
|
||||
|
||||
This is never called for InnoDB tables, as these table types
|
||||
has the HA_STATS_RECORDS_IS_EXACT set.
|
||||
This is never called for normal InnoDB tables, as these table types
|
||||
does not have HA_STATS_RECORDS_IS_EXACT set.
|
||||
*/
|
||||
int handler::read_first_row(uchar * buf, uint primary_key)
|
||||
{
|
||||
@ -3992,7 +4002,7 @@ void handler::mark_trx_read_write_internal()
|
||||
*/
|
||||
if (ha_info->is_started())
|
||||
{
|
||||
DBUG_ASSERT(has_transactions());
|
||||
DBUG_ASSERT(has_transaction_manager());
|
||||
/*
|
||||
table_share can be NULL in ha_delete_table(). See implementation
|
||||
of standalone function ha_delete_table() in sql_base.cc.
|
||||
@ -5033,22 +5043,28 @@ private:
|
||||
loaded, frm is invalid), the return value will be true, but
|
||||
*hton will be NULL.
|
||||
*/
|
||||
|
||||
bool ha_table_exists(THD *thd, const char *db, const char *table_name,
|
||||
handlerton **hton)
|
||||
handlerton **hton, bool *is_sequence)
|
||||
{
|
||||
handlerton *dummy;
|
||||
bool dummy2;
|
||||
DBUG_ENTER("ha_table_exists");
|
||||
|
||||
if (hton)
|
||||
*hton= 0;
|
||||
else if (engines_with_discover)
|
||||
hton= &dummy;
|
||||
if (!is_sequence)
|
||||
is_sequence= &dummy2;
|
||||
*is_sequence= 0;
|
||||
|
||||
TDC_element *element= tdc_lock_share(thd, db, table_name);
|
||||
if (element && element != MY_ERRPTR)
|
||||
{
|
||||
if (hton)
|
||||
*hton= element->share->db_type();
|
||||
*is_sequence= element->share->table_type == TABLE_TYPE_SEQUENCE;
|
||||
tdc_unlock_share(element);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
@ -5066,7 +5082,7 @@ bool ha_table_exists(THD *thd, const char *db, const char *table_name,
|
||||
char engine_buf[NAME_CHAR_LEN + 1];
|
||||
LEX_STRING engine= { engine_buf, 0 };
|
||||
|
||||
if (dd_frm_type(thd, path, &engine) != FRMTYPE_VIEW)
|
||||
if (dd_frm_type(thd, path, &engine, is_sequence) != TABLE_TYPE_VIEW)
|
||||
{
|
||||
plugin_ref p= plugin_lock_by_name(thd, &engine, MYSQL_STORAGE_ENGINE_PLUGIN);
|
||||
*hton= p ? plugin_hton(p) : NULL;
|
||||
@ -5089,7 +5105,6 @@ bool ha_table_exists(THD *thd, const char *db, const char *table_name,
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
|
||||
if (need_full_discover_for_existence)
|
||||
{
|
||||
TABLE_LIST table;
|
||||
@ -5778,8 +5793,6 @@ static int write_locked_table_maps(THD *thd)
|
||||
}
|
||||
|
||||
|
||||
typedef bool Log_func(THD*, TABLE*, bool, const uchar*, const uchar*);
|
||||
|
||||
static int check_wsrep_max_ws_rows();
|
||||
|
||||
static int binlog_log_row_internal(TABLE* table,
|
||||
@ -5820,10 +5833,10 @@ static int binlog_log_row_internal(TABLE* table,
|
||||
return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
|
||||
}
|
||||
|
||||
static inline int binlog_log_row(TABLE* table,
|
||||
const uchar *before_record,
|
||||
const uchar *after_record,
|
||||
Log_func *log_func)
|
||||
int binlog_log_row(TABLE* table,
|
||||
const uchar *before_record,
|
||||
const uchar *after_record,
|
||||
Log_func *log_func)
|
||||
{
|
||||
if (!table->file->check_table_binlog_row_based(1))
|
||||
return 0;
|
||||
@ -5975,7 +5988,7 @@ int handler::ha_write_row(uchar *buf)
|
||||
{ error= write_row(buf); })
|
||||
|
||||
MYSQL_INSERT_ROW_DONE(error);
|
||||
if (likely(!error))
|
||||
if (likely(!error) && !row_already_logged)
|
||||
{
|
||||
rows_changed++;
|
||||
error= binlog_log_row(table, 0, buf, log_func);
|
||||
@ -6007,7 +6020,7 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
|
||||
{ error= update_row(old_data, new_data);})
|
||||
|
||||
MYSQL_UPDATE_ROW_DONE(error);
|
||||
if (likely(!error))
|
||||
if (likely(!error) && !row_already_logged)
|
||||
{
|
||||
rows_changed++;
|
||||
error= binlog_log_row(table, old_data, new_data, log_func);
|
||||
@ -6015,6 +6028,28 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
Update first row. Only used by sequence tables
|
||||
*/
|
||||
|
||||
int handler::update_first_row(uchar *new_data)
|
||||
{
|
||||
int error;
|
||||
if (!(error= ha_rnd_init(1)))
|
||||
{
|
||||
int end_error;
|
||||
if (!(error= ha_rnd_next(table->record[1])))
|
||||
error= update_row(table->record[1], new_data);
|
||||
end_error= ha_rnd_end();
|
||||
if (!error)
|
||||
error= end_error;
|
||||
/* Logging would be wrong if update_row works but ha_rnd_end fails */
|
||||
DBUG_ASSERT(!end_error || error != 0);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int handler::ha_delete_row(const uchar *buf)
|
||||
{
|
||||
int error;
|
||||
|
Reference in New Issue
Block a user