summaryrefslogtreecommitdiff
path: root/sql/ha_gemini.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/ha_gemini.cc')
-rw-r--r--sql/ha_gemini.cc3630
1 files changed, 0 insertions, 3630 deletions
diff --git a/sql/ha_gemini.cc b/sql/ha_gemini.cc
deleted file mode 100644
index a60841c3fe6..00000000000
--- a/sql/ha_gemini.cc
+++ /dev/null
@@ -1,3630 +0,0 @@
-/* Copyright (C) 2000 MySQL AB & NuSphere Corporation
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-/* This file is based on ha_berkeley.cc */
-
-#ifdef __GNUC__
-#pragma implementation // gcc: Class implementation
-#endif
-
-#include "mysql_priv.h"
-#ifdef HAVE_GEMINI_DB
-#include "ha_gemini.h"
-#include "dbconfig.h"
-#include "dsmpub.h"
-#include "recpub.h"
-#include "vststat.h"
-
-#include <m_ctype.h>
-#include <myisampack.h>
-#include <m_string.h>
-#include <assert.h>
-#include <hash.h>
-#include <stdarg.h>
-#include "geminikey.h"
-
-#define gemini_msg MSGD_CALLBACK
-
-pthread_mutex_t gem_mutex;
-
-static HASH gem_open_tables;
-static GEM_SHARE *get_share(const char *table_name, TABLE *table);
-static int free_share(GEM_SHARE *share, bool mutex_is_locked);
-static byte* gem_get_key(GEM_SHARE *share,uint *length,
- my_bool not_used __attribute__((unused)));
-static void gemini_lock_table_overflow_error(dsmContext_t *pcontext);
-
-const char *ha_gemini_ext=".gmd";
-const char *ha_gemini_idx_ext=".gmi";
-
-bool gemini_skip=0;
-long gemini_options = 0;
-long gemini_buffer_cache;
-long gemini_io_threads;
-long gemini_log_cluster_size;
-long gemini_locktablesize;
-long gemini_lock_wait_timeout;
-long gemini_spin_retries;
-long gemini_connection_limit;
-char *gemini_basedir;
-
-const char gemini_dbname[] = "gemini";
-dsmContext_t *pfirstContext = NULL;
-
-ulong gemini_recovery_options = GEMINI_RECOVERY_FULL;
-/* bits in gemini_recovery_options */
-const char *gemini_recovery_names[] =
-{ "FULL", "NONE", "FORCE" };
-TYPELIB gemini_recovery_typelib= {array_elements(gemini_recovery_names)-1,"",
- gemini_recovery_names};
-
-const int start_of_name = 2; /* Name passed as ./<db>/<table-name>
- and we're not interested in the ./ */
-static const int keyBufSize = MAXKEYSZ + FULLKEYHDRSZ + MAX_REF_PARTS + 16;
-
-static int gemini_tx_begin(THD *thd);
-static void print_msg(THD *thd, const char *table_name, const char *op_name,
- const char *msg_type, const char *fmt, ...);
-
-static int gemini_helper_threads(dsmContext_t *pContext);
-pthread_handler_decl(gemini_watchdog,arg );
-pthread_handler_decl(gemini_rl_writer,arg );
-pthread_handler_decl(gemini_apw,arg);
-
-/* General functions */
-
-bool gemini_init(void)
-{
- dsmStatus_t rc = 0;
- char pmsgsfile[MAXPATHN];
-
- DBUG_ENTER("gemini_init");
-
- gemini_basedir=mysql_home;
- /* If datadir isn't set, bail out */
- if (*mysql_real_data_home == '\0')
- {
- goto badret;
- }
-
- /* dsmContextCreate and dsmContextSetString(DSM_TAGDB_DBNAME) must
- ** be the first DSM calls we make so that we can log any errors which
- ** occur in subsequent DSM calls. DO NOT INSERT ANY DSM CALLS IN
- ** BETWEEN THIS COMMENT AND THE COMMENT THAT SAYS "END OF CODE..."
- */
- /* Gotta connect to the database regardless of the operation */
- rc = dsmContextCreate(&pfirstContext);
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "dsmContextCreate failed %l",rc);
- goto badret;
- }
- /* This call will also open the log file */
- rc = dsmContextSetString(pfirstContext, DSM_TAGDB_DBNAME,
- strlen(gemini_dbname), (TEXT *)gemini_dbname);
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "Dbname tag failed %l", rc);
- goto badret;
- }
- /* END OF CODE NOT TO MESS WITH */
-
- fn_format(pmsgsfile, GEM_MSGS_FILE, language, ".db", 2 | 4);
- rc = dsmContextSetString(pfirstContext, DSM_TAGDB_MSGS_FILE,
- strlen(pmsgsfile), (TEXT *)pmsgsfile);
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "MSGS_DIR tag failed %l", rc);
- goto badret;
- }
-
- strxmov(pmsgsfile, gemini_basedir, GEM_SYM_FILE, NullS);
- rc = dsmContextSetString(pfirstContext, DSM_TAGDB_SYMFILE,
- strlen(pmsgsfile), (TEXT *)pmsgsfile);
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "SYMFILE tag failed %l", rc);
- goto badret;
- }
-
- rc = dsmContextSetLong(pfirstContext,DSM_TAGDB_ACCESS_TYPE,DSM_ACCESS_STARTUP);
- if ( rc != 0 )
- {
- gemini_msg(pfirstContext, "ACCESS TAG set failed %l",rc);
- goto badret;
- }
- rc = dsmContextSetLong(pfirstContext,DSM_TAGDB_ACCESS_ENV, DSM_SQL_ENGINE);
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "ACCESS_ENV set failed %l",rc);
- goto badret;
- }
-
- rc = dsmContextSetString(pfirstContext, DSM_TAGDB_DATADIR,
- strlen(mysql_real_data_home),
- (TEXT *)mysql_real_data_home);
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "Datadir tag failed %l", rc);
- goto badret;
- }
-
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_MAX_USERS,
- gemini_connection_limit);
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "MAX_USERS tag set failed %l",rc);
- goto badret;
- }
-
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_DEFAULT_LOCK_TIMEOUT,
- gemini_lock_wait_timeout);
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "MAX_LOCK_ENTRIES tag set failed %l",rc);
- goto badret;
- }
-
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_MAX_LOCK_ENTRIES,
- gemini_locktablesize);
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "MAX_LOCK_ENTRIES tag set failed %l",rc);
- goto badret;
- }
-
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_SPIN_AMOUNT,
- gemini_spin_retries);
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "SPIN_AMOUNT tag set failed %l",rc);
- goto badret;
- }
-
- /* blocksize is hardcoded to 8K. Buffer cache is in bytes
- need to convert this to 8K blocks */
- gemini_buffer_cache = gemini_buffer_cache / 8192;
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_DB_BUFFERS,
- gemini_buffer_cache);
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "DB_BUFFERS tag set failed %l",rc);
- goto badret;
- }
-
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_FLUSH_AT_COMMIT,
- ((gemini_options & GEMOPT_FLUSH_LOG) ? 0 : 1));
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "FLush_Log_At_Commit tag set failed %l",rc);
- goto badret;
- }
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_DIRECT_IO,
- ((gemini_options & GEMOPT_UNBUFFERED_IO) ? 1 : 0));
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "DIRECT_IO tag set failed %l",rc);
- goto badret;
- }
-
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_CRASH_PROTECTION,
- ((gemini_recovery_options & GEMINI_RECOVERY_FULL) ? 1 : 0));
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "CRASH_PROTECTION tag set failed %l",rc);
- goto badret;
- }
-
- if (gemini_recovery_options & GEMINI_RECOVERY_FORCE)
- {
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_FORCE_ACCESS, 1);
- if(rc != 0)
- {
- printf("CRASH_PROTECTION tag set failed %ld",rc);
- goto badret;
- }
- }
-
- /* cluster size will come in bytes, need to convert it to
- 16 K units. */
- gemini_log_cluster_size = (gemini_log_cluster_size + 16383) / 16384;
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_BI_CLUSTER_SIZE,
- gemini_log_cluster_size);
-
- if(rc != 0)
- {
- gemini_msg(pfirstContext, "CRASH_PROTECTION tag set failed %l",rc);
- goto badret;
- }
-
- rc = dsmUserConnect(pfirstContext,(TEXT *)"Multi-user",
- DSM_DB_OPENDB | DSM_DB_OPENFILE);
- if( rc != 0 )
- {
- /* Message is output in dbenv() */
- goto badret;
- }
- /* Set access to shared for subsequent user connects */
- rc = dsmContextSetLong(pfirstContext,DSM_TAGDB_ACCESS_TYPE,DSM_ACCESS_SHARED);
-
- rc = gemini_helper_threads(pfirstContext);
-
-
- (void) hash_init(&gem_open_tables,32,0,0,
- (hash_get_key) gem_get_key,0,0);
- pthread_mutex_init(&gem_mutex,NULL);
-
-
- DBUG_RETURN(0);
-
-badret:
- gemini_skip = 1;
- DBUG_RETURN(0);
-}
-
-static int gemini_helper_threads(dsmContext_t *pContext)
-{
- int rc = 0;
- int i;
- pthread_attr_t thr_attr;
-
- pthread_t hThread;
- DBUG_ENTER("gemini_helper_threads");
-
- (void) pthread_attr_init(&thr_attr);
-#if !defined(HAVE_DEC_3_2_THREADS)
- pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_SYSTEM);
- (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
- pthread_attr_setstacksize(&thr_attr,32768);
-#endif
- rc = pthread_create (&hThread, &thr_attr, gemini_watchdog, (void *)pContext);
- if (rc)
- {
- gemini_msg(pContext, "Can't Create gemini watchdog thread");
- goto done;
- }
- if(!gemini_io_threads)
- goto done;
-
- rc = pthread_create(&hThread, &thr_attr, gemini_rl_writer, (void *)pContext);
- if(rc)
- {
- gemini_msg(pContext, "Can't create Gemini recovery log writer thread");
- goto done;
- }
-
- for(i = gemini_io_threads - 1;i;i--)
- {
- rc = pthread_create(&hThread, &thr_attr, gemini_apw, (void *)pContext);
- if(rc)
- {
- gemini_msg(pContext, "Can't create Gemini database page writer thread");
- goto done;
- }
- }
-done:
-
- DBUG_RETURN(rc);
-}
-
-pthread_handler_decl(gemini_watchdog,arg )
-{
- int rc = 0;
- dsmContext_t *pcontext = (dsmContext_t *)arg;
- dsmContext_t *pmyContext = NULL;
-
-
- rc = dsmContextCopy(pcontext,&pmyContext, DSMCONTEXTDB);
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmContextCopy failed for Gemini watchdog %d",rc);
-
- return 0;
- }
- rc = dsmUserConnect(pmyContext,NULL,0);
-
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmUserConnect failed for Gemini watchdog %d",rc);
-
- return 0;
- }
-
- my_thread_init();
- pthread_detach_this_thread();
-
- while(rc == 0)
- {
- rc = dsmDatabaseProcessEvents(pmyContext);
- if(!rc)
- rc = dsmWatchdog(pmyContext);
- sleep(1);
- }
- rc = dsmUserDisconnect(pmyContext,0);
- my_thread_end();
- return 0;
-}
-
-pthread_handler_decl(gemini_rl_writer,arg )
-{
- int rc = 0;
- dsmContext_t *pcontext = (dsmContext_t *)arg;
- dsmContext_t *pmyContext = NULL;
-
-
- rc = dsmContextCopy(pcontext,&pmyContext, DSMCONTEXTDB);
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmContextCopy failed for Gemini recovery log writer %d",rc);
-
- return 0;
- }
- rc = dsmUserConnect(pmyContext,NULL,0);
-
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmUserConnect failed for Gemini recovery log writer %d",rc);
-
- return 0;
- }
-
- my_thread_init();
- pthread_detach_this_thread();
-
- while(rc == 0)
- {
- rc = dsmRLwriter(pmyContext);
- }
- rc = dsmUserDisconnect(pmyContext,0);
- my_thread_end();
- return 0;
-}
-
-pthread_handler_decl(gemini_apw,arg )
-{
- int rc = 0;
- dsmContext_t *pcontext = (dsmContext_t *)arg;
- dsmContext_t *pmyContext = NULL;
-
- my_thread_init();
- pthread_detach_this_thread();
-
- rc = dsmContextCopy(pcontext,&pmyContext, DSMCONTEXTDB);
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmContextCopy failed for Gemini page writer %d",rc);
- my_thread_end();
- return 0;
- }
- rc = dsmUserConnect(pmyContext,NULL,0);
-
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmUserConnect failed for Gemini page writer %d",rc);
- my_thread_end();
- return 0;
- }
-
- while(rc == 0)
- {
- rc = dsmAPW(pmyContext);
- }
- rc = dsmUserDisconnect(pmyContext,0);
- my_thread_end();
- return 0;
-}
-
-int gemini_set_option_long(int optid, long optval)
-{
- dsmStatus_t rc = 0;
-
- switch (optid)
- {
- case GEM_OPTID_SPIN_RETRIES:
- /* If we don't have a context yet, skip the set and just save the
- ** value in gemini_spin_retries for a later gemini_init(). This
- ** may not ever happen, but we're covered if it does.
- */
- if (pfirstContext)
- {
- rc = dsmContextSetLong(pfirstContext, DSM_TAGDB_SPIN_AMOUNT,
- optval);
- }
- if (rc)
- {
- gemini_msg(pfirstContext, "SPIN_AMOUNT tag set failed %l",rc);
- }
- else
- {
- gemini_spin_retries = optval;
- }
- break;
- }
-
- return rc;
-}
-
-static int gemini_connect(THD *thd)
-{
- DBUG_ENTER("gemini_connect");
-
- dsmStatus_t rc;
-
- rc = dsmContextCopy(pfirstContext,(dsmContext_t **)&thd->gemini.context,
- DSMCONTEXTDB);
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "dsmContextCopy failed %l",rc);
-
- return(rc);
- }
- rc = dsmUserConnect((dsmContext_t *)thd->gemini.context,NULL,0);
-
- if( rc != 0 )
- {
- gemini_msg(pfirstContext, "dsmUserConnect failed %l",rc);
-
- return(rc);
- }
- rc = (dsmStatus_t)gemini_tx_begin(thd);
-
- DBUG_RETURN(rc);
-}
-
-void gemini_disconnect(THD *thd)
-{
- dsmStatus_t rc;
-
- if(thd->gemini.context)
- {
- rc = dsmUserDisconnect((dsmContext_t *)thd->gemini.context,0);
- }
- return;
-}
-
-bool gemini_end(void)
-{
- dsmStatus_t rc;
- THD *thd;
-
- DBUG_ENTER("gemini_end");
-
- hash_free(&gem_open_tables);
- pthread_mutex_destroy(&gem_mutex);
- if(pfirstContext)
- {
- rc = dsmShutdownSet(pfirstContext, DSM_SHUTDOWN_NORMAL);
- sleep(2);
- rc = dsmContextSetLong(pfirstContext,DSM_TAGDB_ACCESS_TYPE,DSM_ACCESS_STARTUP);
- rc = dsmShutdown(pfirstContext, DSMNICEBIT,DSMNICEBIT);
- }
- DBUG_RETURN(0);
-}
-
-bool gemini_flush_logs()
-{
- DBUG_ENTER("gemini_flush_logs");
-
- DBUG_RETURN(0);
-}
-
-static int gemini_tx_begin(THD *thd)
-{
- dsmStatus_t rc;
- DBUG_ENTER("gemini_tx_begin");
-
- thd->gemini.savepoint = 1;
-
- rc = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,DSMTXN_START,0,NULL);
- if(!rc)
- thd->gemini.needSavepoint = 1;
-
- thd->gemini.tx_isolation = thd->tx_isolation;
-
- DBUG_PRINT("trans",("beginning transaction"));
- DBUG_RETURN(rc);
-}
-
-int gemini_commit(THD *thd)
-{
- dsmStatus_t rc;
- LONG txNumber = 0;
-
- DBUG_ENTER("gemini_commit");
-
- if(!thd->gemini.context)
- DBUG_RETURN(0);
-
- rc = dsmTransaction((dsmContext_t *)thd->gemini.context,
- 0,DSMTXN_COMMIT,0,NULL);
- if(!rc)
- rc = gemini_tx_begin(thd);
-
- thd->gemini.lock_count = 0;
-
- DBUG_PRINT("trans",("ending transaction"));
- DBUG_RETURN(rc);
-}
-
-int gemini_rollback(THD *thd)
-{
- dsmStatus_t rc;
- LONG txNumber;
-
- DBUG_ENTER("gemini_rollback");
- DBUG_PRINT("trans",("aborting transaction"));
-
- if(!thd->gemini.context)
- DBUG_RETURN(0);
-
- thd->gemini.savepoint = 0;
- rc = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,DSMTXN_ABORT,0,NULL);
- if(!rc)
- rc = gemini_tx_begin(thd);
-
- thd->gemini.lock_count = 0;
-
- DBUG_RETURN(rc);
-}
-
-int gemini_rollback_to_savepoint(THD *thd)
-{
- dsmStatus_t rc = 0;
- DBUG_ENTER("gemini_rollback_to_savepoint");
- if(thd->gemini.savepoint > 1)
- {
- rc = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,DSMTXN_UNSAVE,0,NULL);
- }
- DBUG_RETURN(rc);
-}
-
-int gemini_recovery_logging(THD *thd, bool on)
-{
- int error;
- int noLogging;
-
- if(!thd->gemini.context)
- return 0;
-
- if(on)
- noLogging = 0;
- else
- noLogging = 1;
-
- error = dsmContextSetLong((dsmContext_t *)thd->gemini.context,
- DSM_TAGCONTEXT_NO_LOGGING,noLogging);
- return error;
-}
-
-/* gemDataType - translates from mysql data type constant to gemini
- key services data type contstant */
-int gemDataType ( int mysqlType )
-{
- switch (mysqlType)
- {
- case FIELD_TYPE_LONG:
- case FIELD_TYPE_TINY:
- case FIELD_TYPE_SHORT:
- case FIELD_TYPE_TIMESTAMP:
- case FIELD_TYPE_LONGLONG:
- case FIELD_TYPE_INT24:
- case FIELD_TYPE_DATE:
- case FIELD_TYPE_TIME:
- case FIELD_TYPE_DATETIME:
- case FIELD_TYPE_YEAR:
- case FIELD_TYPE_NEWDATE:
- case FIELD_TYPE_ENUM:
- case FIELD_TYPE_SET:
- return GEM_INT;
- case FIELD_TYPE_DECIMAL:
- return GEM_DECIMAL;
- case FIELD_TYPE_FLOAT:
- return GEM_FLOAT;
- case FIELD_TYPE_DOUBLE:
- return GEM_DOUBLE;
- case FIELD_TYPE_TINY_BLOB:
- return GEM_TINYBLOB;
- case FIELD_TYPE_MEDIUM_BLOB:
- return GEM_MEDIUMBLOB;
- case FIELD_TYPE_LONG_BLOB:
- return GEM_LONGBLOB;
- case FIELD_TYPE_BLOB:
- return GEM_BLOB;
- case FIELD_TYPE_VAR_STRING:
- case FIELD_TYPE_STRING:
- return GEM_CHAR;
- }
- return -1;
-}
-
-/*****************************************************************************
-** Gemini tables
-*****************************************************************************/
-
-const char **ha_gemini::bas_ext() const
-{ static const char *ext[]= { ha_gemini_ext, ha_gemini_idx_ext, NullS };
- return ext;
-}
-
-
-int ha_gemini::open(const char *name, int mode, uint test_if_locked)
-{
- dsmObject_t tableId = 0;
- THD *thd;
- char name_buff[FN_REFLEN];
- char tabname_buff[FN_REFLEN];
- char dbname_buff[FN_REFLEN];
- unsigned i,nameLen;
- LONG txNumber;
- dsmStatus_t rc;
-
- DBUG_ENTER("ha_gemini::open");
-
- thd = current_thd;
- /* Init shared structure */
- if (!(share=get_share(name,table)))
- {
- DBUG_RETURN(1); /* purecov: inspected */
- }
- thr_lock_data_init(&share->lock,&lock,(void*) 0);
-
- ref_length = sizeof(dsmRecid_t);
-
- if(thd->gemini.context == NULL)
- {
- /* Need to get this thread a connection into the database */
- rc = gemini_connect(thd);
- if(rc)
- return rc;
- }
- if (!(rec_buff=(byte*)my_malloc(table->rec_buff_length,
- MYF(MY_WME))))
- {
- DBUG_RETURN(1);
- }
-
- /* separate out the name of the table and the database (a VST must be
- ** created in the mysql database)
- */
- rc = gemini_parse_table_name(name, dbname_buff, tabname_buff);
- if (rc == 0)
- {
- if (strcmp(dbname_buff, "mysql") == 0)
- {
- tableId = gemini_is_vst(tabname_buff);
- }
- }
- sprintf(name_buff, "%s.%s", dbname_buff, tabname_buff);
-
- /* if it's not a VST, get the table number the regular way */
- if (!tableId)
- {
- rc = dsmObjectNameToNum((dsmContext_t *)thd->gemini.context,
- (dsmText_t *)name_buff,
- &tableId);
- if (rc)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Unable to find table number for %s", name_buff);
- DBUG_RETURN(rc);
- }
- }
- tableNumber = tableId;
-
- if(!rc)
- rc = index_open(name_buff);
-
- fixed_length_row=!(table->db_create_options & HA_OPTION_PACK_RECORD);
- key_read = 0;
- using_ignore = 0;
-
- /* Get the gemini table status -- we want to know if the table
- crashed while being in the midst of a repair operation */
- rc = dsmTableStatus((dsmContext_t *)thd->gemini.context,
- tableNumber,&tableStatus);
- if(tableStatus == DSM_OBJECT_IN_REPAIR)
- tableStatus = HA_ERR_CRASHED;
-
- pthread_mutex_lock(&share->mutex);
- share->use_count++;
- pthread_mutex_unlock(&share->mutex);
-
- if (table->blob_fields)
- {
- /* Allocate room for the blob ids from an unpacked row. Note that
- ** we may not actually need all of this space because tiny blobs
- ** are stored in the packed row, not in a separate storage object
- ** like larger blobs. But we allocate an entry for all blobs to
- ** keep the code simpler.
- */
- pBlobDescs = (gemBlobDesc_t *)my_malloc(
- table->blob_fields * sizeof(gemBlobDesc_t),
- MYF(MY_WME | MY_ZEROFILL));
- }
- else
- {
- pBlobDescs = 0;
- }
-
- get_index_stats(thd);
- info(HA_STATUS_CONST);
-
- DBUG_RETURN (rc);
-}
-
-/* Look up and store the object numbers for the indexes on this table */
-int ha_gemini::index_open(char *tableName)
-{
- dsmStatus_t rc = 0;
- int nameLen;
-
- DBUG_ENTER("ha_gemini::index_open");
- if(table->keys)
- {
- THD *thd = current_thd;
- dsmObject_t objectNumber;
- if (!(pindexNumbers=(dsmIndex_t *)my_malloc(table->keys*sizeof(dsmIndex_t),
- MYF(MY_WME))))
- {
- DBUG_RETURN(1);
- }
- nameLen = strlen(tableName);
- tableName[nameLen] = '.';
- nameLen++;
-
- for( uint i = 0; i < table->keys && !rc; i++)
- {
- strcpy(&tableName[nameLen],table->key_info[i].name);
- rc = dsmObjectNameToNum((dsmContext_t *)thd->gemini.context,
- (dsmText_t *)tableName,
- &objectNumber);
- if (rc)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Unable to file Index number for %s", tableName);
- DBUG_RETURN(rc);
- }
- pindexNumbers[i] = objectNumber;
- }
- }
- else
- pindexNumbers = 0;
-
- DBUG_RETURN(rc);
-}
-
-int ha_gemini::close(void)
-{
- DBUG_ENTER("ha_gemini::close");
- my_free((char*)rec_buff,MYF(MY_ALLOW_ZERO_PTR));
- rec_buff = 0;
- my_free((char *)pindexNumbers,MYF(MY_ALLOW_ZERO_PTR));
- pindexNumbers = 0;
-
- if (pBlobDescs)
- {
- for (uint i = 0; i < table->blob_fields; i++)
- {
- my_free((char*)pBlobDescs[i].pBlob, MYF(MY_ALLOW_ZERO_PTR));
- }
- my_free((char *)pBlobDescs, MYF(0));
- pBlobDescs = 0;
- }
-
- DBUG_RETURN(free_share(share, 0));
-}
-
-
-int ha_gemini::write_row(byte * record)
-{
- int error = 0;
- dsmRecord_t dsmRecord;
- THD *thd;
-
- DBUG_ENTER("write_row");
-
- if(tableStatus == HA_ERR_CRASHED)
- DBUG_RETURN(tableStatus);
-
- thd = current_thd;
-
- statistic_increment(ha_write_count,&LOCK_status);
- if (table->time_stamp)
- update_timestamp(record+table->time_stamp-1);
-
- if(thd->gemini.needSavepoint || using_ignore)
- {
- thd->gemini.savepoint++;
- error = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,
- DSMTXN_SAVE, 0, 0);
- if (error)
- DBUG_RETURN(error);
- thd->gemini.needSavepoint = 0;
- }
-
- if (table->next_number_field && record == table->record[0])
- {
- if(thd->next_insert_id)
- {
- ULONG64 nr;
- /* A set insert-id statement so set the auto-increment value if this
- value is higher than it's current value */
- error = dsmTableAutoIncrement((dsmContext_t *)thd->gemini.context,
- tableNumber, (ULONG64 *)&nr,1);
- if(thd->next_insert_id > nr)
- {
- error = dsmTableAutoIncrementSet((dsmContext_t *)thd->gemini.context,
- tableNumber,
- (ULONG64)thd->next_insert_id);
- }
- }
-
- update_auto_increment();
- }
-
- dsmRecord.table = tableNumber;
- dsmRecord.maxLength = table->rec_buff_length;
-
- if ((error=pack_row((byte **)&dsmRecord.pbuffer, (int *)&dsmRecord.recLength,
- record, FALSE)))
- {
- DBUG_RETURN(error);
- }
-
- error = dsmRecordCreate((dsmContext_t *)thd->gemini.context,
- &dsmRecord,0);
-
- if(!error)
- {
- error = handleIndexEntries(record, dsmRecord.recid,KEY_CREATE);
- if(error == HA_ERR_FOUND_DUPP_KEY && using_ignore)
- {
- dsmStatus_t rc;
- rc = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,DSMTXN_UNSAVE,0,NULL);
- thd->gemini.needSavepoint = 1;
- }
- }
- if(error == DSM_S_RQSTREJ)
- error = HA_ERR_LOCK_WAIT_TIMEOUT;
-
- DBUG_RETURN(error);
-}
-
-longlong ha_gemini::get_auto_increment()
-{
- longlong nr;
- int error;
- int update;
- THD *thd=current_thd;
-
- if(thd->lex.sql_command == SQLCOM_SHOW_TABLES)
- update = 0;
- else
- update = 1;
-
- error = dsmTableAutoIncrement((dsmContext_t *)thd->gemini.context,
- tableNumber, (ULONG64 *)&nr,
- update);
- return nr;
-}
-
-/* Put or delete index entries for a row */
-int ha_gemini::handleIndexEntries(const byte * record, dsmRecid_t recid,
- enum_key_string_options option)
-{
- dsmStatus_t rc = 0;
-
- DBUG_ENTER("handleIndexEntries");
-
- for (uint i = 0; i < table->keys && rc == 0; i++)
- {
- rc = handleIndexEntry(record, recid,option, i);
- }
- DBUG_RETURN(rc);
-}
-
-int ha_gemini::handleIndexEntry(const byte * record, dsmRecid_t recid,
- enum_key_string_options option,uint keynr)
-{
- dsmStatus_t rc = 0;
- KEY *key_info;
- int keyStringLen;
- bool thereIsAnull;
- THD *thd;
-
- AUTOKEY(theKey,keyBufSize);
-
- DBUG_ENTER("handleIndexEntry");
-
- thd = current_thd;
- key_info=table->key_info+keynr;
- thereIsAnull = FALSE;
- rc = createKeyString(record, key_info, theKey.akey.keystr,
- sizeof(theKey.apad),&keyStringLen,
- (short)pindexNumbers[keynr],
- &thereIsAnull);
- if(!rc)
- {
- theKey.akey.index = pindexNumbers[keynr];
- theKey.akey.keycomps = (COUNT)key_info->key_parts;
-
- /* We have to subtract three here since cxKeyPrepare
- expects that the three lead bytes of the header are
- not counted in this length -- But cxKeyPrepare also
- expects that these three bytes are present in the keystr */
- theKey.akey.keyLen = (COUNT)keyStringLen - FULLKEYHDRSZ;
- theKey.akey.unknown_comp = (dsmBoolean_t)thereIsAnull;
- theKey.akey.word_index = 0;
- theKey.akey.descending_key =0;
- if(option == KEY_CREATE)
- {
- rc = dsmKeyCreate((dsmContext_t *)thd->gemini.context, &theKey.akey,
- (dsmTable_t)tableNumber, recid, NULL);
- if(rc == DSM_S_IXDUPKEY)
- {
- last_dup_key=keynr;
- rc = HA_ERR_FOUND_DUPP_KEY;
- }
- }
- else if(option == KEY_DELETE)
- {
- rc = dsmKeyDelete((dsmContext_t *)thd->gemini.context, &theKey.akey,
- (dsmTable_t)tableNumber, recid, 0, NULL);
- }
- else
- {
- /* KEY_CHECK */
- dsmCursid_t aCursorId;
- int error;
-
- rc = dsmCursorCreate((dsmContext_t *)thd->gemini.context,
- (dsmTable_t)tableNumber,
- (dsmIndex_t)pindexNumbers[keynr],
- &aCursorId,NULL);
-
- rc = dsmCursorFind((dsmContext_t *)thd->gemini.context,
- &aCursorId,&theKey.akey,NULL,DSMDBKEY,
- DSMFINDFIRST,DSM_LK_SHARE,0,
- &lastRowid,0);
- error = dsmCursorDelete((dsmContext_t *)thd->gemini.context,
- &aCursorId, 0);
-
- }
- }
- DBUG_RETURN(rc);
-}
-
-int ha_gemini::createKeyString(const byte * record, KEY *pkeyinfo,
- unsigned char *pkeyBuf, int bufSize,
- int *pkeyStringLen,
- short geminiIndexNumber,
- bool *thereIsAnull)
-{
- dsmStatus_t rc = 0;
- int componentLen;
- int fieldType;
- int isNull;
- uint key_part_length;
-
- KEY_PART_INFO *key_part;
-
- DBUG_ENTER("createKeyString");
-
- rc = gemKeyInit(pkeyBuf,pkeyStringLen, geminiIndexNumber);
-
- for(uint i = 0; i < pkeyinfo->key_parts && rc == 0; i++)
- {
- unsigned char *pos;
-
- key_part = pkeyinfo->key_part + i;
- key_part_length = key_part->length;
- fieldType = gemDataType(key_part->field->type());
- switch (fieldType)
- {
- case GEM_CHAR:
- {
- /* Save the current ptr to the field in case we're building a key
- to remove an old key value when an indexed character column
- gets updated. */
- char *ptr = key_part->field->ptr;
- key_part->field->ptr = (char *)record + key_part->offset;
- key_part->field->sort_string((char*)rec_buff, key_part->length);
- key_part->field->ptr = ptr;
- pos = (unsigned char *)rec_buff;
- }
- break;
-
- case GEM_TINYBLOB:
- case GEM_BLOB:
- case GEM_MEDIUMBLOB:
- case GEM_LONGBLOB:
- ((Field_blob*)key_part->field)->get_ptr((char**)&pos);
- key_part_length = ((Field_blob*)key_part->field)->get_length(
- (char*)record + key_part->offset);
- break;
-
- default:
- pos = (unsigned char *)record + key_part->offset;
- break;
- }
-
- isNull = record[key_part->null_offset] & key_part->null_bit;
- if(isNull)
- *thereIsAnull = TRUE;
-
- rc = gemFieldToIdxComponent(pos,
- (unsigned long) key_part_length,
- fieldType,
- isNull ,
- key_part->field->flags & UNSIGNED_FLAG,
- pkeyBuf + *pkeyStringLen,
- bufSize,
- &componentLen);
- *pkeyStringLen += componentLen;
- }
- DBUG_RETURN(rc);
-}
-
-
-int ha_gemini::update_row(const byte * old_record, byte * new_record)
-{
- int error = 0;
- dsmRecord_t dsmRecord;
- unsigned long savepoint;
- THD *thd = current_thd;
- DBUG_ENTER("update_row");
-
- statistic_increment(ha_update_count,&LOCK_status);
- if (table->time_stamp)
- update_timestamp(new_record+table->time_stamp-1);
-
- if(thd->gemini.needSavepoint || using_ignore)
- {
- thd->gemini.savepoint++;
- error = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,
- DSMTXN_SAVE, 0, 0);
- if (error)
- DBUG_RETURN(error);
- thd->gemini.needSavepoint = 0;
- }
- for (uint keynr=0 ; keynr < table->keys ; keynr++)
- {
- if(key_cmp(keynr,old_record, new_record,FALSE))
- {
- error = handleIndexEntry(old_record,lastRowid,KEY_DELETE,keynr);
- if(error)
- DBUG_RETURN(error);
- error = handleIndexEntry(new_record, lastRowid, KEY_CREATE, keynr);
- if(error)
- {
- if (using_ignore && error == HA_ERR_FOUND_DUPP_KEY)
- {
- dsmStatus_t rc;
- rc = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,DSMTXN_UNSAVE,0,NULL);
- thd->gemini.needSavepoint = 1;
- }
- DBUG_RETURN(error);
- }
- }
- }
-
- dsmRecord.table = tableNumber;
- dsmRecord.recid = lastRowid;
- dsmRecord.maxLength = table->rec_buff_length;
-
- if ((error=pack_row((byte **)&dsmRecord.pbuffer, (int *)&dsmRecord.recLength,
- new_record, TRUE)))
- {
- DBUG_RETURN(error);
- }
- error = dsmRecordUpdate((dsmContext_t *)thd->gemini.context,
- &dsmRecord, 0, NULL);
-
- DBUG_RETURN(error);
-}
-
-
-int ha_gemini::delete_row(const byte * record)
-{
- int error = 0;
- dsmRecord_t dsmRecord;
- THD *thd = current_thd;
- dsmContext_t *pcontext = (dsmContext_t *)thd->gemini.context;
- DBUG_ENTER("delete_row");
-
- statistic_increment(ha_delete_count,&LOCK_status);
-
- if(thd->gemini.needSavepoint)
- {
- thd->gemini.savepoint++;
- error = dsmTransaction(pcontext, &thd->gemini.savepoint, DSMTXN_SAVE, 0, 0);
- if (error)
- DBUG_RETURN(error);
- thd->gemini.needSavepoint = 0;
- }
-
- dsmRecord.table = tableNumber;
- dsmRecord.recid = lastRowid;
-
- error = handleIndexEntries(record, dsmRecord.recid,KEY_DELETE);
- if(!error)
- {
- error = dsmRecordDelete(pcontext, &dsmRecord, 0, NULL);
- }
-
- /* Delete any blobs associated with this row */
- if (table->blob_fields)
- {
- dsmBlob_t gemBlob;
-
- gemBlob.areaType = DSMOBJECT_BLOB;
- gemBlob.blobObjNo = tableNumber;
- for (uint i = 0; i < table->blob_fields; i++)
- {
- if (pBlobDescs[i].blobId)
- {
- gemBlob.blobId = pBlobDescs[i].blobId;
- my_free((char *)pBlobDescs[i].pBlob, MYF(MY_ALLOW_ZERO_PTR));
- dsmBlobStart(pcontext, &gemBlob);
- dsmBlobDelete(pcontext, &gemBlob, NULL);
- /* according to DSM doc, no need to call dsmBlobEnd() */
- }
- }
- }
-
- DBUG_RETURN(error);
-}
-
-int ha_gemini::index_init(uint keynr)
-{
- int error = 0;
- THD *thd;
- DBUG_ENTER("index_init");
- thd = current_thd;
-
- lastRowid = 0;
- active_index=keynr;
- error = dsmCursorCreate((dsmContext_t *)thd->gemini.context,
- (dsmTable_t)tableNumber,
- (dsmIndex_t)pindexNumbers[keynr],
- &cursorId,NULL);
- pbracketBase = (dsmKey_t *)my_malloc(sizeof(dsmKey_t) + keyBufSize,
- MYF(MY_WME));
- if(!pbracketBase)
- DBUG_RETURN(1);
- pbracketLimit = (dsmKey_t *)my_malloc(sizeof(dsmKey_t) + keyBufSize,MYF(MY_WME));
- if(!pbracketLimit)
- {
- my_free((char *)pbracketLimit,MYF(0));
- DBUG_RETURN(1);
- }
- pbracketBase->index = 0;
- pbracketLimit->index = (dsmIndex_t)pindexNumbers[keynr];
- pbracketBase->descending_key = pbracketLimit->descending_key = 0;
- pbracketBase->ksubstr = pbracketLimit->ksubstr = 0;
- pbracketLimit->keycomps = pbracketBase->keycomps = 1;
-
- pfoundKey = (dsmKey_t *)my_malloc(sizeof(dsmKey_t) + keyBufSize,MYF(MY_WME));
- if(!pfoundKey)
- {
- my_free((char *)pbracketLimit,MYF(0));
- my_free((char *)pbracketBase,MYF(0));
- DBUG_RETURN(1);
- }
-
- DBUG_RETURN(error);
-}
-
-int ha_gemini::index_end()
-{
- int error = 0;
- THD *thd;
- DBUG_ENTER("index_end");
- thd = current_thd;
- error = dsmCursorDelete((dsmContext_t *)thd->gemini.context,
- &cursorId, 0);
- if(pbracketLimit)
- my_free((char *)pbracketLimit,MYF(0));
- if(pbracketBase)
- my_free((char *)pbracketBase,MYF(0));
- if(pfoundKey)
- my_free((char *)pfoundKey,MYF(0));
-
- pbracketLimit = 0;
- pbracketBase = 0;
- pfoundKey = 0;
- DBUG_RETURN(error);
-}
-
-/* This is only used to read whole keys */
-
-int ha_gemini::index_read_idx(byte * buf, uint keynr, const byte * key,
- uint key_len, enum ha_rkey_function find_flag)
-{
- int error = 0;
- DBUG_ENTER("index_read_idx");
- statistic_increment(ha_read_key_count,&LOCK_status);
-
- error = index_init(keynr);
- if (!error)
- error = index_read(buf,key,key_len,find_flag);
-
- if(error == HA_ERR_END_OF_FILE)
- error = HA_ERR_KEY_NOT_FOUND;
-
- table->status = error ? STATUS_NOT_FOUND : 0;
- DBUG_RETURN(error);
-}
-
-int ha_gemini::pack_key( uint keynr, dsmKey_t *pkey,
- const byte *key_ptr, uint key_length)
-{
- KEY *key_info=table->key_info+keynr;
- KEY_PART_INFO *key_part=key_info->key_part;
- KEY_PART_INFO *end=key_part+key_info->key_parts;
- int rc;
- int componentLen;
- DBUG_ENTER("pack_key");
-
- rc = gemKeyInit(pkey->keystr,&componentLen,
- (short)pindexNumbers[active_index]);
- pkey->keyLen = componentLen;
-
- for (; key_part != end && (int) key_length > 0 && !rc; key_part++)
- {
- uint offset=0;
- unsigned char *pos;
- uint key_part_length = key_part->length;
-
- int fieldType;
- if (key_part->null_bit)
- {
- offset=1;
- if (*key_ptr != 0) // Store 0 if NULL
- {
- key_length-= key_part->store_length;
- key_ptr+= key_part->store_length;
- rc = gemFieldToIdxComponent(
- (unsigned char *)key_ptr + offset,
- (unsigned long) key_part_length,
- 0,
- 1 , /* Tells it to build a null component */
- key_part->field->flags & UNSIGNED_FLAG,
- pkey->keystr + pkey->keyLen,
- keyBufSize,
- &componentLen);
- pkey->keyLen += componentLen;
- continue;
- }
- }
- fieldType = gemDataType(key_part->field->type());
- switch (fieldType)
- {
- case GEM_CHAR:
- key_part->field->store((char*)key_ptr + offset, key_part->length);
- key_part->field->sort_string((char*)rec_buff, key_part->length);
- pos = (unsigned char *)rec_buff;
- break;
-
- case GEM_TINYBLOB:
- case GEM_BLOB:
- case GEM_MEDIUMBLOB:
- case GEM_LONGBLOB:
- ((Field_blob*)key_part->field)->get_ptr((char**)&pos);
- key_part_length = ((Field_blob*)key_part->field)->get_length(
- (char*)key_ptr + offset);
- break;
-
- default:
- pos = (unsigned char *)key_ptr + offset;
- break;
- }
-
- rc = gemFieldToIdxComponent(
- pos,
- (unsigned long) key_part_length,
- fieldType,
- 0 ,
- key_part->field->flags & UNSIGNED_FLAG,
- pkey->keystr + pkey->keyLen,
- keyBufSize,
- &componentLen);
-
- key_ptr+=key_part->store_length;
- key_length-=key_part->store_length;
- pkey->keyLen += componentLen;
- }
- DBUG_RETURN(rc);
-}
-
-void ha_gemini::unpack_key(char *record, dsmKey_t *key, uint index)
-{
- KEY *key_info=table->key_info+index;
- KEY_PART_INFO *key_part= key_info->key_part,
- *end=key_part+key_info->key_parts;
- int fieldIsNull, fieldType;
- int rc = 0;
-
- char unsigned *pos= &key->keystr[FULLKEYHDRSZ+4/* 4 for the index number*/];
-
- for ( ; key_part != end; key_part++)
- {
- fieldType = gemDataType(key_part->field->type());
- if(fieldType == GEM_CHAR)
- {
- /* Can't get data from character indexes since the sort weights
- are in the index and not the characters. */
- key_read = 0;
- }
- rc = gemIdxComponentToField(pos, fieldType,
- (unsigned char *)record + key_part->field->offset(),
- //key_part->field->field_length,
- key_part->length,
- key_part->field->decimals(),
- &fieldIsNull);
- if(fieldIsNull)
- {
- record[key_part->null_offset] |= key_part->null_bit;
- }
- else if (key_part->null_bit)
- {
- record[key_part->null_offset]&= ~key_part->null_bit;
- }
- while(*pos++); /* Advance to next field in key by finding */
- /* a null byte */
- }
-}
-
-int ha_gemini::index_read(byte * buf, const byte * key,
- uint key_len, enum ha_rkey_function find_flag)
-{
- int error = 0;
- THD *thd;
- int componentLen;
-
- DBUG_ENTER("index_read");
- statistic_increment(ha_read_key_count,&LOCK_status);
-
-
- pbracketBase->index = (short)pindexNumbers[active_index];
- pbracketBase->keycomps = 1;
-
-
- /* Its a greater than operation so create a base bracket
- from the input key data. */
- error = pack_key(active_index, pbracketBase, key, key_len);
- if(error)
- goto errorReturn;
-
- if(find_flag == HA_READ_AFTER_KEY)
- {
- /* A greater than operation */
- error = gemKeyAddLow(pbracketBase->keystr + pbracketBase->keyLen,
- &componentLen);
- pbracketBase->keyLen += componentLen;
- }
- if(find_flag == HA_READ_KEY_EXACT)
- {
- /* Need to set up a high bracket for an equality operator
- Which is a copy of the base bracket plus a hi lim term */
- bmove(pbracketLimit,pbracketBase,(size_t)pbracketBase->keyLen + sizeof(dsmKey_t));
- error = gemKeyAddHigh(pbracketLimit->keystr + pbracketLimit->keyLen,
- &componentLen);
- if(error)
- goto errorReturn;
- pbracketLimit->keyLen += componentLen;
- }
- else
- {
- /* Always add a high range -- except for HA_READ_KEY_EXACT this
- is all we need for the upper index bracket */
- error = gemKeyHigh(pbracketLimit->keystr, &componentLen,
- pbracketLimit->index);
-
- pbracketLimit->keyLen = componentLen;
- }
- /* We have to subtract the header size here since cxKeyPrepare
- expects that the three lead bytes of the header are
- not counted in this length -- But cxKeyPrepare also
- expects that these three bytes are present in the keystr */
- pbracketBase->keyLen -= FULLKEYHDRSZ;
- pbracketLimit->keyLen -= FULLKEYHDRSZ;
-
- thd = current_thd;
-
- error = findRow(thd, DSMFINDFIRST, buf);
-
-errorReturn:
- if (error == DSM_S_ENDLOOP)
- error = HA_ERR_KEY_NOT_FOUND;
-
- table->status = error ? STATUS_NOT_FOUND : 0;
- DBUG_RETURN(error);
-}
-
-
-int ha_gemini::index_next(byte * buf)
-{
- THD *thd;
- int error = 1;
- int keyStringLen=0;
- dsmMask_t findMode;
- DBUG_ENTER("index_next");
-
- if(tableStatus == HA_ERR_CRASHED)
- DBUG_RETURN(tableStatus);
-
- thd = current_thd;
-
- if(pbracketBase->index == 0)
- {
- error = gemKeyLow(pbracketBase->keystr, &keyStringLen,
- pbracketLimit->index);
-
- pbracketBase->keyLen = (COUNT)keyStringLen - FULLKEYHDRSZ;
- pbracketBase->index = pbracketLimit->index;
- error = gemKeyHigh(pbracketLimit->keystr, &keyStringLen,
- pbracketLimit->index);
- pbracketLimit->keyLen = (COUNT)keyStringLen - FULLKEYHDRSZ;
-
- findMode = DSMFINDFIRST;
- }
- else
- findMode = DSMFINDNEXT;
-
- error = findRow(thd,findMode,buf);
-
- if (error == DSM_S_ENDLOOP)
- error = HA_ERR_END_OF_FILE;
-
- table->status = error ? STATUS_NOT_FOUND : 0;
- DBUG_RETURN(error);
-}
-
-int ha_gemini::index_next_same(byte * buf, const byte *key, uint keylen)
-{
- int error = 0;
- DBUG_ENTER("index_next_same");
- statistic_increment(ha_read_next_count,&LOCK_status);
- DBUG_RETURN(index_next(buf));
-}
-
-
-int ha_gemini::index_prev(byte * buf)
-{
- int error = 0;
- THD *thd = current_thd;
-
- DBUG_ENTER("index_prev");
- statistic_increment(ha_read_prev_count,&LOCK_status);
-
- error = findRow(thd, DSMFINDPREV, buf);
-
- if (error == DSM_S_ENDLOOP)
- error = HA_ERR_END_OF_FILE;
-
-
- table->status = error ? STATUS_NOT_FOUND : 0;
- DBUG_RETURN(error);
-}
-
-
-int ha_gemini::index_first(byte * buf)
-{
- DBUG_ENTER("index_first");
- statistic_increment(ha_read_first_count,&LOCK_status);
- DBUG_RETURN(index_next(buf));
-}
-
-int ha_gemini::index_last(byte * buf)
-{
- int error = 0;
- THD *thd;
- int keyStringLen;
- dsmMask_t findMode;
- thd = current_thd;
-
- DBUG_ENTER("index_last");
- statistic_increment(ha_read_last_count,&LOCK_status);
-
- error = gemKeyLow(pbracketBase->keystr, &keyStringLen,
- pbracketLimit->index);
-
- pbracketBase->keyLen = (COUNT)keyStringLen - FULLKEYHDRSZ;
- pbracketBase->index = pbracketLimit->index;
- error = gemKeyHigh(pbracketLimit->keystr, &keyStringLen,
- pbracketLimit->index);
- pbracketLimit->keyLen = (COUNT)keyStringLen - FULLKEYHDRSZ;
-
- error = findRow(thd,DSMFINDLAST,buf);
-
- if (error == DSM_S_ENDLOOP)
- error = HA_ERR_END_OF_FILE;
-
- table->status = error ? STATUS_NOT_FOUND : 0;
- DBUG_RETURN(error);
-}
-
-int ha_gemini::rnd_init(bool scan)
-{
- THD *thd = current_thd;
-
- lastRowid = 0;
-
- return 0;
-}
-
-int ha_gemini::rnd_end()
-{
-/*
- return gem_scan_end();
-*/
- return 0;
-}
-
-int ha_gemini::rnd_next(byte *buf)
-{
- int error = 0;
- dsmRecord_t dsmRecord;
- THD *thd;
-
- DBUG_ENTER("rnd_next");
-
- if(tableStatus == HA_ERR_CRASHED)
- DBUG_RETURN(tableStatus);
-
- thd = current_thd;
- if(thd->gemini.tx_isolation == ISO_READ_COMMITTED && !(lockMode & DSM_LK_EXCL)
- && lastRowid)
- error = dsmObjectUnlock((dsmContext_t *)thd->gemini.context,
- tableNumber, DSMOBJECT_RECORD, lastRowid,
- lockMode | DSM_UNLK_FREE, 0);
-
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
- dsmRecord.table = tableNumber;
- dsmRecord.recid = lastRowid;
- dsmRecord.pbuffer = (dsmBuffer_t *)rec_buff;
- dsmRecord.recLength = table->reclength;
- dsmRecord.maxLength = table->rec_buff_length;
-
- error = dsmTableScan((dsmContext_t *)thd->gemini.context,
- &dsmRecord, DSMFINDNEXT, lockMode, 0);
-
- if(!error)
- {
- lastRowid = dsmRecord.recid;
- error = unpack_row((char *)buf,(char *)dsmRecord.pbuffer);
- }
- if(!error)
- ;
- else
- {
- lastRowid = 0;
- if (error == DSM_S_ENDLOOP)
- error = HA_ERR_END_OF_FILE;
- else if (error == DSM_S_RQSTREJ)
- error = HA_ERR_LOCK_WAIT_TIMEOUT;
- else if (error == DSM_S_LKTBFULL)
- {
- error = HA_ERR_LOCK_TABLE_FULL;
- gemini_lock_table_overflow_error((dsmContext_t *)thd->gemini.context);
- }
- }
- table->status = error ? STATUS_NOT_FOUND : 0;
- DBUG_RETURN(error);
-}
-
-
-int ha_gemini::rnd_pos(byte * buf, byte *pos)
-{
- int error;
- int rc;
-
- THD *thd;
-
- statistic_increment(ha_read_rnd_count,&LOCK_status);
- thd = current_thd;
- memcpy((void *)&lastRowid,pos,ref_length);
- if(thd->gemini.tx_isolation == ISO_READ_COMMITTED && !(lockMode & DSM_LK_EXCL))
- {
- /* Lock the row */
-
- error = dsmObjectLock((dsmContext_t *)thd->gemini.context,
- (dsmObject_t)tableNumber,DSMOBJECT_RECORD,lastRowid,
- lockMode, 1, 0);
- if ( error )
- goto errorReturn;
- }
- error = fetch_row(thd->gemini.context, buf);
- if(thd->gemini.tx_isolation == ISO_READ_COMMITTED && !(lockMode & DSM_LK_EXCL))
- {
- /* Unlock the row */
-
- rc = dsmObjectUnlock((dsmContext_t *)thd->gemini.context,
- (dsmObject_t)tableNumber,DSMOBJECT_RECORD,lastRowid,
- lockMode | DSM_UNLK_FREE , 0);
- }
- if(error == DSM_S_RMNOTFND)
- error = HA_ERR_RECORD_DELETED;
-
- errorReturn:
- table->status = error ? STATUS_NOT_FOUND : 0;
- return error;
-}
-
-int ha_gemini::fetch_row(void *gemini_context,const byte *buf)
-{
- dsmStatus_t rc = 0;
- dsmRecord_t dsmRecord;
-
- DBUG_ENTER("fetch_row");
- dsmRecord.table = tableNumber;
- dsmRecord.recid = lastRowid;
- dsmRecord.pbuffer = (dsmBuffer_t *)rec_buff;
- dsmRecord.recLength = table->reclength;
- dsmRecord.maxLength = table->rec_buff_length;
-
- rc = dsmRecordGet((dsmContext_t *)gemini_context,
- &dsmRecord, 0);
-
- if(!rc)
- {
- rc = unpack_row((char *)buf,(char *)dsmRecord.pbuffer);
- }
-
- DBUG_RETURN(rc);
-}
-int ha_gemini::findRow(THD *thd, dsmMask_t findMode, byte *buf)
-{
- dsmStatus_t rc;
- dsmKey_t *pkey;
-
- DBUG_ENTER("findRow");
-
- if(thd->gemini.tx_isolation == ISO_READ_COMMITTED && !(lockMode & DSM_LK_EXCL)
- && lastRowid)
- rc = dsmObjectUnlock((dsmContext_t *)thd->gemini.context,
- tableNumber, DSMOBJECT_RECORD, lastRowid,
- lockMode | DSM_UNLK_FREE, 0);
- if( key_read )
- pkey = pfoundKey;
- else
- pkey = 0;
-
- rc = dsmCursorFind((dsmContext_t *)thd->gemini.context,
- &cursorId,
- pbracketBase,
- pbracketLimit,
- DSMPARTIAL,
- findMode,
- lockMode,
- NULL,
- &lastRowid,
- pkey);
- if( rc )
- goto errorReturn;
-
- if(key_read)
- {
- unpack_key((char*)buf, pkey, active_index);
- }
- if(!key_read) /* unpack_key may have turned off key_read */
- {
- rc = fetch_row((dsmContext_t *)thd->gemini.context,buf);
- }
-
-errorReturn:
- if(!rc)
- ;
- else
- {
- lastRowid = 0;
- if(rc == DSM_S_RQSTREJ)
- rc = HA_ERR_LOCK_WAIT_TIMEOUT;
- else if (rc == DSM_S_LKTBFULL)
- {
- rc = HA_ERR_LOCK_TABLE_FULL;
- gemini_lock_table_overflow_error((dsmContext_t *)thd->gemini.context);
- }
- }
-
- DBUG_RETURN(rc);
-}
-
-void ha_gemini::position(const byte *record)
-{
- memcpy(ref,&lastRowid,ref_length);
-}
-
-
-void ha_gemini::info(uint flag)
-{
- DBUG_ENTER("info");
-
- if ((flag & HA_STATUS_VARIABLE))
- {
- THD *thd = current_thd;
- dsmStatus_t error;
- ULONG64 rows;
-
- if(thd->gemini.context == NULL)
- {
- /* Need to get this thread a connection into the database */
- error = gemini_connect(thd);
- if(error)
- DBUG_VOID_RETURN;
- }
-
- error = dsmRowCount((dsmContext_t *)thd->gemini.context,tableNumber,&rows);
- records = (ha_rows)rows;
- deleted = 0;
- }
- if ((flag & HA_STATUS_CONST))
- {
- ha_rows *rec_per_key = share->rec_per_key;
- for (uint i = 0; i < table->keys; i++)
- for(uint k=0;
- k < table->key_info[i].key_parts; k++,rec_per_key++)
- table->key_info[i].rec_per_key[k] = *rec_per_key;
- }
- if ((flag & HA_STATUS_ERRKEY))
- {
- errkey=last_dup_key;
- }
- if ((flag & HA_STATUS_TIME))
- {
- ;
- }
- if ((flag & HA_STATUS_AUTO))
- {
- THD *thd = current_thd;
- dsmStatus_t error;
-
- error = dsmTableAutoIncrement((dsmContext_t *)thd->gemini.context,
- tableNumber,
- (ULONG64 *)&auto_increment_value,
- 0);
- /* Should return the next auto-increment value that
- will be given -- so we need to increment the one dsm
- currently reports. */
- auto_increment_value++;
- }
-
- DBUG_VOID_RETURN;
-}
-
-
-int ha_gemini::extra(enum ha_extra_function operation)
-{
- switch (operation)
- {
- case HA_EXTRA_RESET:
- case HA_EXTRA_RESET_STATE:
- key_read=0;
- using_ignore=0;
- break;
- case HA_EXTRA_KEYREAD:
- key_read=1; // Query satisfied with key
- break;
- case HA_EXTRA_NO_KEYREAD:
- key_read=0;
- break;
- case HA_EXTRA_IGNORE_DUP_KEY:
- using_ignore=1;
- break;
- case HA_EXTRA_NO_IGNORE_DUP_KEY:
- using_ignore=0;
- break;
-
- default:
- break;
- }
- return 0;
-}
-
-
-int ha_gemini::reset(void)
-{
- key_read=0; // Reset to state after open
- return 0;
-}
-
-
-/*
- As MySQL will execute an external lock for every new table it uses
- we can use this to start the transactions.
-*/
-
-int ha_gemini::external_lock(THD *thd, int lock_type)
-{
- dsmStatus_t rc = 0;
- LONG txNumber;
-
- DBUG_ENTER("ha_gemini::external_lock");
-
- if (lock_type != F_UNLCK)
- {
- if (!thd->gemini.lock_count)
- {
- thd->gemini.lock_count = 1;
- thd->gemini.tx_isolation = thd->tx_isolation;
- }
- // lockMode has already been set in store_lock
- // If the statement about to be executed calls for
- // exclusive locks and we're running at read uncommitted
- // isolation level then raise an error.
- if(thd->gemini.tx_isolation == ISO_READ_UNCOMMITTED)
- {
- if(lockMode == DSM_LK_EXCL)
- {
- DBUG_RETURN(HA_ERR_READ_ONLY_TRANSACTION);
- }
- else
- {
- lockMode = DSM_LK_NOLOCK;
- }
- }
-
- if(thd->gemini.context == NULL)
- {
- /* Need to get this thread a connection into the database */
- rc = gemini_connect(thd);
- if(rc)
- return rc;
- }
- /* Set need savepoint flag */
- thd->gemini.needSavepoint = 1;
-
- if(rc)
- DBUG_RETURN(rc);
-
-
- if( thd->in_lock_tables || thd->gemini.tx_isolation == ISO_SERIALIZABLE )
- {
- rc = dsmObjectLock((dsmContext_t *)thd->gemini.context,
- (dsmObject_t)tableNumber,DSMOBJECT_TABLE,0,
- lockMode, 1, 0);
- if(rc == DSM_S_RQSTREJ)
- rc = HA_ERR_LOCK_WAIT_TIMEOUT;
- }
- }
- else /* lock_type == F_UNLK */
- {
- /* Commit the tx if we're in auto-commit mode */
- if (!(thd->options & OPTION_NOT_AUTO_COMMIT)&&
- !(thd->options & OPTION_BEGIN))
- gemini_commit(thd);
- }
-
- DBUG_RETURN(rc);
-}
-
-
-THR_LOCK_DATA **ha_gemini::store_lock(THD *thd, THR_LOCK_DATA **to,
- enum thr_lock_type lock_type)
-{
- if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
- {
- /* If we are not doing a LOCK TABLE, then allow multiple writers */
- if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
- lock_type <= TL_WRITE) &&
- !thd->in_lock_tables)
- lock_type = TL_WRITE_ALLOW_WRITE;
- lock.type=lock_type;
- }
- if(table->reginfo.lock_type > TL_WRITE_ALLOW_READ)
- lockMode = DSM_LK_EXCL;
- else
- lockMode = DSM_LK_SHARE;
-
- *to++= &lock;
- return to;
-}
-
-void ha_gemini::update_create_info(HA_CREATE_INFO *create_info)
-{
- table->file->info(HA_STATUS_AUTO | HA_STATUS_CONST);
- if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
- {
- create_info->auto_increment_value=auto_increment_value;
- }
-}
-
-int ha_gemini::create(const char *name, register TABLE *form,
- HA_CREATE_INFO *create_info)
-{
- THD *thd;
- char name_buff[FN_REFLEN];
- char dbname_buff[FN_REFLEN];
- DBUG_ENTER("ha_gemini::create");
- dsmContext_t *pcontext;
- dsmStatus_t rc;
- dsmArea_t areaNumber;
- dsmObject_t tableNumber = 0;
- dsmDbkey_t dummy = 0;
- unsigned i;
- int baseNameLen;
- dsmObject_t indexNumber;
-
- /* separate out the name of the table and the database (a VST must be
- ** created in the mysql database)
- */
- rc = gemini_parse_table_name(name, dbname_buff, name_buff);
- if (rc == 0)
- {
- /* If the table is a VST, don't create areas or extents */
- if (strcmp(dbname_buff, "mysql") == 0)
- {
- tableNumber = gemini_is_vst(name_buff);
- if (tableNumber)
- {
- return 0;
- }
- }
- }
-
- thd = current_thd;
- if(thd->gemini.context == NULL)
- {
- /* Need to get this thread a connection into the database */
- rc = gemini_connect(thd);
- if(rc)
- return rc;
- }
- pcontext = (dsmContext_t *)thd->gemini.context;
-
- if(thd->gemini.needSavepoint || using_ignore)
- {
- thd->gemini.savepoint++;
- rc = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,
- DSMTXN_SAVE, 0, 0);
- if (rc)
- DBUG_RETURN(rc);
- thd->gemini.needSavepoint = 0;
- }
-
- fn_format(name_buff, name, "", ha_gemini_ext, 2 | 4);
- /* Create a storage area */
- rc = dsmAreaNew(pcontext,gemini_blocksize,DSMAREA_TYPE_DATA,
- &areaNumber, gemini_recbits,
- (dsmText_t *)"gemini_data_area");
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmAreaNew failed %l",rc);
- return(rc);
- }
-
- /* Create an extent */
- /* Don't pass in leading ./ in name_buff */
- rc = dsmExtentCreate(pcontext,areaNumber,1,15,5,
- (dsmText_t *)&name_buff[start_of_name]);
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmExtentCreate failed %l",rc);
- return(rc);
- }
-
- /* Create the table storage object */
- /* Change slashes in the name to periods */
- for( i = 0; i < strlen(name_buff); i++)
- if(name_buff[i] == '/' || name_buff[i] == '\\')
- name_buff[i] = '.';
-
- /* Get rid of .gmd suffix */
- name_buff[strlen(name_buff) - 4] = '\0';
-
- rc = dsmObjectCreate(pcontext, areaNumber, &tableNumber,
- DSMOBJECT_MIXTABLE,0,0,0,
- (dsmText_t *)&name_buff[start_of_name],
- &dummy,&dummy);
-
- if (rc == 0 && table->blob_fields)
- {
- /* create a storage object record for blob fields */
- rc = dsmObjectCreate(pcontext, areaNumber, &tableNumber,
- DSMOBJECT_BLOB,0,0,0,
- (dsmText_t *)&name_buff[start_of_name],
- &dummy,&dummy);
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmObjectCreate for blob object failed %l",rc);
- return(rc);
- }
- }
-
- if(rc == 0 && form->keys)
- {
- fn_format(name_buff, name, "", ha_gemini_idx_ext, 2 | 4);
- /* Create a storage area */
- rc = dsmAreaNew(pcontext,gemini_blocksize,DSMAREA_TYPE_DATA,
- &areaNumber, gemini_recbits,
- (dsmText_t *)"gemini_index_area");
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmAreaNew failed %l",rc);
- return(rc);
- }
- /* Create an extent */
- /* Don't pass in leading ./ in name_buff */
- rc = dsmExtentCreate(pcontext,areaNumber,1,15,5,
- (dsmText_t *)&name_buff[start_of_name]);
- if( rc != 0 )
- {
- gemini_msg(pcontext, "dsmExtentCreate failed %l",rc);
- return(rc);
- }
-
- /* Change slashes in the name to periods */
- for( i = 0; i < strlen(name_buff); i++)
- if(name_buff[i] == '/' || name_buff[i] == '\\')
- name_buff[i] = '.';
-
- /* Get rid of .gmi suffix */
- name_buff[strlen(name_buff) - 4] = '\0';
-
- baseNameLen = strlen(name_buff);
- name_buff[baseNameLen] = '.';
- baseNameLen++;
- for( i = 0; i < form->keys; i++)
- {
- dsmObjectAttr_t indexUnique;
-
- indexNumber = DSMINDEX_INVALID;
- /* Create a storage object record for each index */
- /* Add the index name so the object name is in the form
- <db>.<table>.<index_name> */
- strcpy(&name_buff[baseNameLen],table->key_info[i].name);
- if(table->key_info[i].flags & HA_NOSAME)
- indexUnique = 1;
- else
- indexUnique = 0;
- rc = dsmObjectCreate(pcontext, areaNumber, &indexNumber,
- DSMOBJECT_MIXINDEX,indexUnique,tableNumber,
- DSMOBJECT_MIXTABLE,
- (dsmText_t *)&name_buff[start_of_name],
- &dummy,&dummy);
-
- }
- }
- /* The auto_increment value is the next one to be given
- out so give dsm one less than this value */
- if(create_info->auto_increment_value)
- rc = dsmTableAutoIncrementSet(pcontext,tableNumber,
- create_info->auto_increment_value-1);
-
- /* Get a table lock on this table in case this table is being
- created as part of an alter table statement. We don't want
- the alter table statement to abort because of a lock table overflow
- */
- if (thd->lex.sql_command == SQLCOM_CREATE_INDEX ||
- thd->lex.sql_command == SQLCOM_ALTER_TABLE ||
- thd->lex.sql_command == SQLCOM_DROP_INDEX)
- {
- rc = dsmObjectLock(pcontext,
- (dsmObject_t)tableNumber,DSMOBJECT_TABLE,0,
- DSM_LK_EXCL, 1, 0);
- /* and don't commit so we won't release the table on the table number
- of the table being altered */
- }
- else
- {
- if(!rc)
- rc = gemini_commit(thd);
- }
-
- DBUG_RETURN(rc);
-}
-
-int ha_gemini::delete_table(const char *pname)
-{
- THD *thd;
- dsmStatus_t rc;
- dsmContext_t *pcontext;
- unsigned i,nameLen;
- dsmArea_t indexArea = 0;
- dsmArea_t tableArea = 0;
- dsmObjectAttr_t objectAttr;
- dsmObject_t associate;
- dsmObjectType_t associateType;
- dsmDbkey_t block, root;
- int need_txn = 0;
- dsmObject_t tableNum = 0;
- char name_buff[FN_REFLEN];
- char dbname_buff[FN_REFLEN];
- DBUG_ENTER("ha_gemini::delete_table");
-
- /* separate out the name of the table and the database (a VST must be
- ** located in the mysql database)
- */
- rc = gemini_parse_table_name(pname, dbname_buff, name_buff);
- if (rc == 0)
- {
- /* If the table is a VST, there are no areas or extents to delete */
- if (strcmp(dbname_buff, "mysql") == 0)
- {
- tableNum = gemini_is_vst(name_buff);
- if (tableNum)
- {
- return 0;
- }
- }
- }
-
- thd = current_thd;
- if(thd->gemini.context == NULL)
- {
- /* Need to get this thread a connection into the database */
- rc = gemini_connect(thd);
- if(rc)
- {
- DBUG_RETURN(rc);
- }
- }
- pcontext = (dsmContext_t *)thd->gemini.context;
-
-
- bzero(name_buff, FN_REFLEN);
-
- nameLen = strlen(pname);
- for( i = start_of_name; i < nameLen; i++)
- {
- if(pname[i] == '/' || pname[i] == '\\')
- name_buff[i-start_of_name] = '.';
- else
- name_buff[i-start_of_name] = pname[i];
- }
-
- rc = dsmObjectNameToNum(pcontext, (dsmText_t *)name_buff,
- (dsmObject_t *)&tableNum);
- if (rc)
- {
- gemini_msg(pcontext, "Unable to find table number for %s", name_buff);
- rc = gemini_rollback(thd);
- if (rc)
- {
- gemini_msg(pcontext, "Error in rollback %l",rc);
- }
- DBUG_RETURN(rc);
- }
-
- rc = dsmObjectInfo(pcontext, tableNum, DSMOBJECT_MIXTABLE, tableNum,
- &tableArea, &objectAttr, &associateType, &block, &root);
- if (rc)
- {
- gemini_msg(pcontext, "Failed to get area number for table %d, %s, return %l",
- tableNum, pname, rc);
- rc = gemini_rollback(thd);
- if (rc)
- {
- gemini_msg(pcontext, "Error in rollback %l",rc);
- }
- }
-
- indexArea = DSMAREA_INVALID;
-
- /* Delete the indexes and tables storage objects for with the table */
- rc = dsmObjectDeleteAssociate(pcontext, tableNum, &indexArea);
- if (rc)
- {
- gemini_msg(pcontext, "Error deleting storage objects for table number %d, return %l",
- (int)tableNum, rc);
-
- /* roll back txn and return */
- rc = gemini_rollback(thd);
- if (rc)
- {
- gemini_msg(pcontext, "Error in rollback %l",rc);
- }
- DBUG_RETURN(rc);
- }
-
- if (indexArea != DSMAREA_INVALID)
- {
- /* Delete the extents for both Index and Table */
- rc = dsmExtentDelete(pcontext, indexArea);
- rc = dsmAreaDelete(pcontext, indexArea);
- if (rc)
- {
- gemini_msg(pcontext, "Error deleting Index Area %l, return %l", indexArea, rc);
-
- /* roll back txn and return */
- rc = gemini_rollback(thd);
- if (rc)
- {
- gemini_msg(pcontext, "Error in rollback %l",rc);
- }
- DBUG_RETURN(rc);
- }
- }
-
- rc = dsmExtentDelete(pcontext, tableArea);
- rc = dsmAreaDelete(pcontext, tableArea);
- if (rc)
- {
- gemini_msg(pcontext, "Error deleting table Area %l, name %s, return %l",
- tableArea, pname, rc);
- /* roll back txn and return */
- rc = gemini_rollback(thd);
- if (rc)
- {
- gemini_msg(pcontext, "Error in rollback %l",rc);
- }
- DBUG_RETURN(rc);
- }
-
-
- /* Commit the transaction */
- rc = gemini_commit(thd);
- if (rc)
- {
- gemini_msg(pcontext, "Failed to commit transaction %l",rc);
- }
-
-
- /* now remove all the files that need to be removed and
- cause a checkpoint so recovery will work */
- rc = dsmExtentUnlink(pcontext);
-
- DBUG_RETURN(0);
-}
-
-
-int ha_gemini::rename_table(const char *pfrom, const char *pto)
-{
- THD *thd;
- dsmContext_t *pcontext;
- dsmStatus_t rc;
- char dbname_buff[FN_REFLEN];
- char name_buff[FN_REFLEN];
- char newname_buff[FN_REFLEN];
- char newextname_buff[FN_REFLEN];
- char newidxextname_buff[FN_REFLEN];
- unsigned i, nameLen;
- dsmObject_t tableNum;
- dsmArea_t indexArea = 0;
- dsmArea_t tableArea = 0;
-
- DBUG_ENTER("ha_gemini::rename_table");
-
- /* don't allow rename of VSTs */
- rc = gemini_parse_table_name(pfrom, dbname_buff, name_buff);
- if (rc == 0)
- {
- /* If the table is a VST, don't create areas or extents */
- if (strcmp(dbname_buff, "mysql") == 0)
- {
- if (gemini_is_vst(name_buff))
- {
- return DSM_S_CANT_RENAME_VST;
- }
- }
- }
-
- thd = current_thd;
- if (thd->gemini.context == NULL)
- {
- /* Need to get this thread a connection into the database */
- rc = gemini_connect(thd);
- if (rc)
- {
- DBUG_RETURN(rc);
- }
- }
-
- pcontext = (dsmContext_t *)thd->gemini.context;
-
- /* change the slashes to dots in the old and new names */
- nameLen = strlen(pfrom);
- for( i = start_of_name; i < nameLen; i++)
- {
- if(pfrom[i] == '/' || pfrom[i] == '\\')
- name_buff[i-start_of_name] = '.';
- else
- name_buff[i-start_of_name] = pfrom[i];
- }
- name_buff[i-start_of_name] = '\0';
-
- nameLen = strlen(pto);
- for( i = start_of_name; i < nameLen; i++)
- {
- if(pto[i] == '/' || pto[i] == '\\')
- newname_buff[i-start_of_name] = '.';
- else
- newname_buff[i-start_of_name] = pto[i];
- }
- newname_buff[i-start_of_name] = '\0';
-
- /* generate new extent names (for table and index extents) */
- fn_format(newextname_buff, pto, "", ha_gemini_ext, 2 | 4);
- fn_format(newidxextname_buff, pto, "", ha_gemini_idx_ext, 2 | 4);
-
- rc = dsmObjectNameToNum(pcontext, (dsmText_t *)name_buff, &tableNum);
- if (rc)
- {
- gemini_msg(pcontext, "Unable to file Table number for %s", name_buff);
- goto errorReturn;
- }
-
- rc = dsmObjectRename(pcontext, tableNum,
- (dsmText_t *)newname_buff,
- (dsmText_t *)&newidxextname_buff[start_of_name],
- (dsmText_t *)&newextname_buff[start_of_name],
- &indexArea, &tableArea);
- if (rc)
- {
- gemini_msg(pcontext, "Failed to rename %s to %s",name_buff,newname_buff);
- goto errorReturn;
- }
-
- /* Rename the physical table and index files (if necessary).
- ** Close the file, rename it, and reopen it (have to do it this
- ** way so rename works on Windows).
- */
- if (!(rc = dsmAreaClose(pcontext, tableArea)))
- {
- if (!(rc = rename_file_ext(pfrom, pto, ha_gemini_ext)))
- {
- rc = dsmAreaOpen(pcontext, tableArea, 0);
- if (rc)
- {
- gemini_msg(pcontext, "Failed to reopen area %d",tableArea);
- }
- }
- }
-
- if (!rc && indexArea)
- {
- if (!(rc = dsmAreaClose(pcontext, indexArea)))
- {
- if (!(rc = rename_file_ext(pfrom, pto, ha_gemini_idx_ext)))
- {
- rc = dsmAreaOpen(pcontext, indexArea, 0);
- if (rc)
- {
- gemini_msg(pcontext, "Failed to reopen area %d",tableArea);
- }
- }
- }
- }
-
-errorReturn:
- DBUG_RETURN(rc);
-}
-
-
-/*
- How many seeks it will take to read through the table
- This is to be comparable to the number returned by records_in_range so
- that we can decide if we should scan the table or use keys.
-*/
-
-double ha_gemini::scan_time()
-{
- return (double)records /
- (double)((gemini_blocksize / (double)table->reclength));
-}
-
-int ha_gemini::analyze(THD* thd, HA_CHECK_OPT* check_opt)
-{
- int error;
- uint saveIsolation;
- dsmMask_t saveLockMode;
-
- check_opt->quick = TRUE;
- check_opt->optimize = TRUE; // Tells check not to get table lock
- saveLockMode = lockMode;
- saveIsolation = thd->gemini.tx_isolation;
- thd->gemini.tx_isolation = ISO_READ_UNCOMMITTED;
- lockMode = DSM_LK_NOLOCK;
- error = check(thd,check_opt);
- lockMode = saveLockMode;
- thd->gemini.tx_isolation = saveIsolation;
- return (error);
-}
-
-int ha_gemini::check(THD* thd, HA_CHECK_OPT* check_opt)
-{
- int error = 0;
- int checkStatus = HA_ADMIN_OK;
- ha_rows indexCount;
- byte *buf = 0, *indexBuf = 0, *prevBuf = 0;
- int errorCount = 0;
-
- info(HA_STATUS_VARIABLE); // Makes sure row count is up to date
-
- /* Get a shared table lock */
- if(thd->gemini.needSavepoint)
- {
- /* We don't really need a savepoint here but do it anyway
- just to keep the savepoint number correct. */
- thd->gemini.savepoint++;
- error = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,
- DSMTXN_SAVE, 0, 0);
- if (error)
- return(error);
- thd->gemini.needSavepoint = 0;
- }
- buf = (byte*)my_malloc(table->rec_buff_length,MYF(MY_WME));
- indexBuf = (byte*)my_malloc(table->rec_buff_length,MYF(MY_WME));
- prevBuf = (byte*)my_malloc(table->rec_buff_length,MYF(MY_WME |MY_ZEROFILL ));
-
- /* Lock the table */
- if (!check_opt->optimize)
- error = dsmObjectLock((dsmContext_t *)thd->gemini.context,
- (dsmObject_t)tableNumber,
- DSMOBJECT_TABLE,0,
- DSM_LK_SHARE, 1, 0);
- if(error)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Failed to lock table %d, error %d",tableNumber, error);
- return error;
- }
-
- ha_rows *rec_per_key = share->rec_per_key;
- /* If quick option just scan along index converting and counting entries */
- for (uint i = 0; i < table->keys; i++)
- {
- key_read = 1; // Causes data to be extracted from the keys
- indexCount = 0;
- // Clear the cardinality stats for this index
- memset(table->key_info[i].rec_per_key,0,
- sizeof(table->key_info[0].rec_per_key[0]) *
- table->key_info[i].key_parts);
- error = index_init(i);
- error = index_first(indexBuf);
- while(!error)
- {
- indexCount++;
- if(!check_opt->quick)
- {
- /* Fetch row and compare to data produced from key */
- error = fetch_row(thd->gemini.context,buf);
- if(!error)
- {
- if(key_cmp(i,buf,indexBuf,FALSE))
- {
-
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Check Error! Key does not match row for rowid %d for index %s",
- lastRowid,table->key_info[i].name);
- print_msg(thd,table->real_name,"check","error",
- "Key does not match row for rowid %d for index %s",
- lastRowid,table->key_info[i].name);
- checkStatus = HA_ADMIN_CORRUPT;
- errorCount++;
- if(errorCount > 1000)
- goto error_return;
- }
- else if(error == DSM_S_RMNOTFND)
- {
- errorCount++;
- checkStatus = HA_ADMIN_CORRUPT;
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Check Error! Key does not have a valid row pointer %d for index %s",
- lastRowid,table->key_info[i].name);
- print_msg(thd,table->real_name,"check","error",
- "Key does not have a valid row pointer %d for index %s",
- lastRowid,table->key_info[i].name);
- if(errorCount > 1000)
- goto error_return;
- error = 0;
- }
- }
- }
-
- key_cmp(i,indexBuf,prevBuf,TRUE);
- bcopy((void *)indexBuf,(void *)prevBuf,table->rec_buff_length);
-
- if(!error)
- error = index_next(indexBuf);
- }
-
- for(uint j=1; j < table->key_info[i].key_parts; j++)
- {
- table->key_info[i].rec_per_key[j] += table->key_info[i].rec_per_key[j-1];
- }
- for(uint k=0; k < table->key_info[i].key_parts; k++)
- {
- if (table->key_info[i].rec_per_key[k])
- table->key_info[i].rec_per_key[k] =
- records / table->key_info[i].rec_per_key[k];
- *rec_per_key = table->key_info[i].rec_per_key[k];
- rec_per_key++;
- }
-
- if(error == HA_ERR_END_OF_FILE)
- {
- /* Check count of rows */
-
- if(records != indexCount)
- {
- /* Number of index entries does not agree with the number of
- rows in the index. */
- checkStatus = HA_ADMIN_CORRUPT;
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Check Error! Total rows %d does not match total index entries %d for %s",
- records, indexCount,
- table->key_info[i].name);
- print_msg(thd,table->real_name,"check","error",
- "Total rows %d does not match total index entries %d for %s",
- records, indexCount,
- table->key_info[i].name);
- }
- }
- else
- {
- checkStatus = HA_ADMIN_FAILED;
- goto error_return;
- }
- index_end();
- }
- if(!check_opt->quick)
- {
- /* Now scan the table and for each row generate the keys
- and find them in the index */
- error = fullCheck(thd, buf);
- if(error)
- checkStatus = error;
- }
- // Store the key distribution information
- error = saveKeyStats(thd);
-
-error_return:
- my_free((char*)buf,MYF(MY_ALLOW_ZERO_PTR));
- my_free((char*)indexBuf,MYF(MY_ALLOW_ZERO_PTR));
- my_free((char*)prevBuf,MYF(MY_ALLOW_ZERO_PTR));
-
- index_end();
- key_read = 0;
- if(!check_opt->optimize)
- {
- error = dsmObjectUnlock((dsmContext_t *)thd->gemini.context,
- (dsmObject_t)tableNumber,
- DSMOBJECT_TABLE,0,
- DSM_LK_SHARE,0);
- if (error)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Unable to unlock table %d", tableNumber);
- }
- }
-
- return checkStatus;
-}
-
-int ha_gemini::saveKeyStats(THD *thd)
-{
- dsmStatus_t rc = 0;
-
- /* Insert a row in the indexStats table for each column of
- each index of the table */
-
- for(uint i = 0; i < table->keys; i++)
- {
- for (uint j = 0; j < table->key_info[i].key_parts && !rc ;j++)
- {
- rc = dsmIndexStatsPut((dsmContext_t *)thd->gemini.context,
- tableNumber, pindexNumbers[i],
- j, (LONG64)table->key_info[i].rec_per_key[j]);
- if (rc)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Failed to update index stats for table %d, index %d",
- tableNumber, pindexNumbers[i]);
- }
- }
- }
- return rc;
-}
-
-int ha_gemini::fullCheck(THD *thd,byte *buf)
-{
- int error;
- int errorCount = 0;
- int checkStatus = 0;
-
- lastRowid = 0;
-
- while(((error = rnd_next( buf)) != HA_ERR_END_OF_FILE) && errorCount <= 1000)
- {
- if(!error)
- {
- error = handleIndexEntries(buf,lastRowid,KEY_CHECK);
- if(error)
- {
- /* Error finding an index entry for a row. */
- print_msg(thd,table->real_name,"check","error",
- "Unable to find all index entries for row %d",
- lastRowid);
- errorCount++;
- checkStatus = HA_ADMIN_CORRUPT;
- error = 0;
- }
- }
- else
- {
- /* Error reading a row */
- print_msg(thd,table->real_name,"check","error",
- "Error reading row %d status = %d",
- lastRowid,error);
- errorCount++;
- checkStatus = HA_ADMIN_CORRUPT;
- error = 0;
- }
- }
-
- return checkStatus;
-}
-
-int ha_gemini::repair(THD* thd, HA_CHECK_OPT* check_opt)
-{
- int error;
- dsmRecord_t dsmRecord;
- byte *buf;
-
- if(thd->gemini.needSavepoint)
- {
- /* We don't really need a savepoint here but do it anyway
- just to keep the savepoint number correct. */
- thd->gemini.savepoint++;
- error = dsmTransaction((dsmContext_t *)thd->gemini.context,
- &thd->gemini.savepoint,
- DSMTXN_SAVE, 0, 0);
- if (error)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Error setting savepoint number %d, error %d",
- thd->gemini.savepoint++, error);
- return(error);
- }
- thd->gemini.needSavepoint = 0;
- }
-
-
- /* Lock the table */
- error = dsmObjectLock((dsmContext_t *)thd->gemini.context,
- (dsmObject_t)tableNumber,
- DSMOBJECT_TABLE,0,
- DSM_LK_EXCL, 1, 0);
- if(error)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Failed to lock table %d, error %d",tableNumber, error);
- return error;
- }
-
- error = dsmContextSetLong((dsmContext_t *)thd->gemini.context,
- DSM_TAGCONTEXT_NO_LOGGING,1);
-
- error = dsmTableReset((dsmContext_t *)thd->gemini.context,
- (dsmTable_t)tableNumber, table->keys,
- pindexNumbers);
- if (error)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "dsmTableReset failed for table %d, error %d",tableNumber, error);
- }
-
- buf = (byte*)my_malloc(table->rec_buff_length,MYF(MY_WME));
- dsmRecord.table = tableNumber;
- dsmRecord.recid = 0;
- dsmRecord.pbuffer = (dsmBuffer_t *)rec_buff;
- dsmRecord.recLength = table->reclength;
- dsmRecord.maxLength = table->rec_buff_length;
- while(!error)
- {
- error = dsmTableScan((dsmContext_t *)thd->gemini.context,
- &dsmRecord, DSMFINDNEXT, DSM_LK_NOLOCK,
- 1);
- if(!error)
- {
- if (!(error = unpack_row((char *)buf,(char *)dsmRecord.pbuffer)))
- {
- error = handleIndexEntries(buf,dsmRecord.recid,KEY_CREATE);
- if(error == HA_ERR_FOUND_DUPP_KEY)
- {
- /* We don't want to stop on duplicate keys -- we're repairing
- here so let's get as much repaired as possible. */
- error = 0;
- }
- }
- }
- }
- error = dsmObjectUnlock((dsmContext_t *)thd->gemini.context,
- (dsmObject_t)tableNumber,
- DSMOBJECT_TABLE,0,
- DSM_LK_EXCL,0);
- if (error)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Unable to unlock table %d", tableNumber);
- }
-
- my_free((char*)buf,MYF(MY_ALLOW_ZERO_PTR));
-
- error = dsmContextSetLong((dsmContext_t *)thd->gemini.context,
- DSM_TAGCONTEXT_NO_LOGGING,0);
-
- return error;
-}
-
-
-int ha_gemini::restore(THD* thd, HA_CHECK_OPT *check_opt)
-{
- dsmContext_t *pcontext = (dsmContext_t *)thd->gemini.context;
- char* backup_dir = thd->lex.backup_dir;
- char src_path[FN_REFLEN], dst_path[FN_REFLEN];
- char* table_name = table->real_name;
- int error = 0;
- int errornum;
- const char* errmsg = "";
- dsmArea_t tableArea = 0;
- dsmObjectAttr_t objectAttr;
- dsmObject_t associate;
- dsmObjectType_t associateType;
- dsmDbkey_t block, root;
- dsmStatus_t rc;
-
- rc = dsmObjectInfo(pcontext, tableNumber, DSMOBJECT_MIXTABLE, tableNumber,
- &tableArea, &objectAttr, &associateType, &block, &root);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmObjectInfo (.gmd) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- rc = dsmAreaFlush(pcontext, tableArea, FLUSH_BUFFERS | FLUSH_SYNC);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmAreaFlush (.gmd) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- rc = dsmAreaClose(pcontext, tableArea);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmAreaClose (.gmd) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- /* Restore the data file */
- if (!fn_format(src_path, table_name, backup_dir, ha_gemini_ext, 4 + 64))
- {
- return HA_ADMIN_INVALID;
- }
-
- if (my_copy(src_path, fn_format(dst_path, table->path, "",
- ha_gemini_ext, 4), MYF(MY_WME)))
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in my_copy (.gmd) (Error %d)";
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- rc = dsmAreaFlush(pcontext, tableArea, FREE_BUFFERS);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmAreaFlush (.gmd) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- rc = dsmAreaOpen(pcontext, tableArea, 1);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmAreaOpen (.gmd) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
-#ifdef GEMINI_BACKUP_IDX
- dsmArea_t indexArea = 0;
-
- rc = dsmObjectInfo(pcontext, tableNumber, DSMOBJECT_MIXINDEX, &indexArea,
- &objectAttr, &associate, &associateType, &block, &root);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmObjectInfo (.gmi) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- rc = dsmAreaClose(pcontext, indexArea);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmAreaClose (.gmi) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- /* Restore the index file */
- if (!fn_format(src_path, table_name, backup_dir, ha_gemini_idx_ext, 4 + 64))
- {
- return HA_ADMIN_INVALID;
- }
-
- if (my_copy(src_path, fn_format(dst_path, table->path, "",
- ha_gemini_idx_ext, 4), MYF(MY_WME)))
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in my_copy (.gmi) (Error %d)";
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- rc = dsmAreaOpen(pcontext, indexArea, 1);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmAreaOpen (.gmi) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- return HA_ADMIN_OK;
-#else /* #ifdef GEMINI_BACKUP_IDX */
- HA_CHECK_OPT tmp_check_opt;
- tmp_check_opt.init();
- /* The following aren't currently implemented in ha_gemini::repair
- ** tmp_check_opt.quick = 1;
- ** tmp_check_opt.flags |= T_VERY_SILENT;
- */
- return (repair(thd, &tmp_check_opt));
-#endif /* #ifdef GEMINI_BACKUP_IDX */
-
- err:
- {
-#if 0
- /* mi_check_print_error is in ha_myisam.cc, so none of the informative
- ** error messages above is currently being printed
- */
- MI_CHECK param;
- myisamchk_init(&param);
- param.thd = thd;
- param.op_name = (char*)"restore";
- param.table_name = table->table_name;
- param.testflag = 0;
- mi_check_print_error(&param,errmsg, errornum);
-#endif
- return error;
- }
-}
-
-
-int ha_gemini::backup(THD* thd, HA_CHECK_OPT *check_opt)
-{
- dsmContext_t *pcontext = (dsmContext_t *)thd->gemini.context;
- char* backup_dir = thd->lex.backup_dir;
- char src_path[FN_REFLEN], dst_path[FN_REFLEN];
- char* table_name = table->real_name;
- int error = 0;
- int errornum;
- const char* errmsg = "";
- dsmArea_t tableArea = 0;
- dsmObjectAttr_t objectAttr;
- dsmObject_t associate;
- dsmObjectType_t associateType;
- dsmDbkey_t block, root;
- dsmStatus_t rc;
-
- rc = dsmObjectInfo(pcontext, tableNumber, DSMOBJECT_MIXTABLE, tableNumber,
- &tableArea, &objectAttr, &associateType, &block, &root);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmObjectInfo (.gmd) (Error %d)";
- errornum = rc;
- goto err;
- }
-
- /* Flush the buffers before backing up the table */
- dsmAreaFlush((dsmContext_t *)thd->gemini.context, tableArea,
- FLUSH_BUFFERS | FLUSH_SYNC);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmAreaFlush (.gmd) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- /* Backup the .FRM file */
- if (!fn_format(dst_path, table_name, backup_dir, reg_ext, 4 + 64))
- {
- errmsg = "Failed in fn_format() for .frm file: errno = %d";
- error = HA_ADMIN_INVALID;
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- if (my_copy(fn_format(src_path, table->path,"", reg_ext, 4),
- dst_path,
- MYF(MY_WME | MY_HOLD_ORIGINAL_MODES )))
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed copying .frm file: errno = %d";
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- /* Backup the data file */
- if (!fn_format(dst_path, table_name, backup_dir, ha_gemini_ext, 4 + 64))
- {
- errmsg = "Failed in fn_format() for .GMD file: errno = %d";
- error = HA_ADMIN_INVALID;
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- if (my_copy(fn_format(src_path, table->path,"", ha_gemini_ext, 4),
- dst_path,
- MYF(MY_WME | MY_HOLD_ORIGINAL_MODES )) )
- {
- errmsg = "Failed copying .GMD file: errno = %d";
- error= HA_ADMIN_FAILED;
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
-#ifdef GEMINI_BACKUP_IDX
- dsmArea_t indexArea = 0;
-
- rc = dsmObjectInfo(pcontext, tableNumber, DSMOBJECT_MIXINDEX, &indexArea,
- &objectAttr, &associate, &associateType, &block, &root);
- if (rc)
- {
- error = HA_ADMIN_FAILED;
- errmsg = "Failed in dsmObjectInfo (.gmi) (Error %d)";
- errornum = rc;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- /* Backup the index file */
- if (!fn_format(dst_path, table_name, backup_dir, ha_gemini_idx_ext, 4 + 64))
- {
- errmsg = "Failed in fn_format() for .GMI file: errno = %d";
- error = HA_ADMIN_INVALID;
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-
- if (my_copy(fn_format(src_path, table->path,"", ha_gemini_idx_ext, 4),
- dst_path,
- MYF(MY_WME | MY_HOLD_ORIGINAL_MODES )) )
- {
- errmsg = "Failed copying .GMI file: errno = %d";
- error= HA_ADMIN_FAILED;
- errornum = errno;
- gemini_msg(pcontext, errmsg ,errornum);
- goto err;
- }
-#endif /* #ifdef GEMINI_BACKUP_IDX */
-
- return HA_ADMIN_OK;
-
- err:
- {
-#if 0
- /* mi_check_print_error is in ha_myisam.cc, so none of the informative
- ** error messages above is currently being printed
- */
- MI_CHECK param;
- myisamchk_init(&param);
- param.thd = thd;
- param.op_name = (char*)"backup";
- param.table_name = table->table_name;
- param.testflag = 0;
- mi_check_print_error(&param,errmsg, errornum);
-#endif
- return error;
- }
-}
-
-
-int ha_gemini::optimize(THD* thd, HA_CHECK_OPT *check_opt)
-{
- return HA_ADMIN_ALREADY_DONE;
-}
-
-
-ha_rows ha_gemini::records_in_range(int keynr,
- const byte *start_key,uint start_key_len,
- enum ha_rkey_function start_search_flag,
- const byte *end_key,uint end_key_len,
- enum ha_rkey_function end_search_flag)
-{
- int error;
- int componentLen;
- float pctInrange;
- ha_rows rows = 5;
-
- DBUG_ENTER("records_in_range");
-
- error = index_init(keynr);
- if(error)
- DBUG_RETURN(rows);
-
- pbracketBase->index = (short)pindexNumbers[keynr];
- pbracketBase->keycomps = 1;
-
- if(start_key)
- {
- error = pack_key(keynr, pbracketBase, start_key, start_key_len);
- if(start_search_flag == HA_READ_AFTER_KEY)
- {
- /* A greater than operation */
- error = gemKeyAddLow(pbracketBase->keystr + pbracketBase->keyLen,
- &componentLen);
- pbracketBase->keyLen += componentLen;
- }
- }
- else
- {
- error = gemKeyLow(pbracketBase->keystr, &componentLen,
- pbracketBase->index);
- pbracketBase->keyLen = componentLen;
-
- }
- pbracketBase->keyLen -= FULLKEYHDRSZ;
-
- if(end_key)
- {
- error = pack_key(keynr, pbracketLimit, end_key, end_key_len);
- if(!error && end_search_flag == HA_READ_AFTER_KEY)
- {
- error = gemKeyAddHigh(pbracketLimit->keystr + pbracketLimit->keyLen,
- &componentLen);
- pbracketLimit->keyLen += componentLen;
- }
- }
- else
- {
- error = gemKeyHigh(pbracketLimit->keystr,&componentLen,
- pbracketLimit->index);
- pbracketLimit->keyLen = componentLen;
- }
-
- pbracketLimit->keyLen -= FULLKEYHDRSZ;
- error = dsmIndexRowsInRange((dsmContext_t *)current_thd->gemini.context,
- pbracketBase,pbracketLimit,
- tableNumber,
- &pctInrange);
- if(pctInrange >= 1)
- rows = (ha_rows)pctInrange;
- else
- {
- rows = (ha_rows)(records * pctInrange);
- if(!rows && pctInrange > 0)
- rows = 1;
- }
- index_end();
-
- DBUG_RETURN(rows);
-}
-
-
-/*
- Pack a row for storage. If the row is of fixed length, just store the
- row 'as is'.
- If not, we will generate a packed row suitable for storage.
- This will only fail if we don't have enough memory to pack the row, which;
- may only happen in rows with blobs, as the default row length is
- pre-allocated.
-*/
-int ha_gemini::pack_row(byte **pprow, int *ppackedLength, const byte *record,
- bool update)
-{
- THD *thd = current_thd;
- dsmContext_t *pcontext = (dsmContext_t *)thd->gemini.context;
- gemBlobDesc_t *pBlobDesc = pBlobDescs;
-
- if (fixed_length_row)
- {
- *pprow = (byte *)record;
- *ppackedLength=(int)table->reclength;
- return 0;
- }
- /* Copy null bits */
- memcpy(rec_buff, record, table->null_bytes);
- byte *ptr=rec_buff + table->null_bytes;
-
- for (Field **field=table->field ; *field ; field++)
- {
-#ifdef GEMINI_TINYBLOB_IN_ROW
- /* Tiny blobs (255 bytes or less) are stored in the row; larger
- ** blobs are stored in a separate storage object (see ha_gemini::create).
- */
- if ((*field)->type() == FIELD_TYPE_BLOB &&
- ((Field_blob*)*field)->blobtype() != FIELD_TYPE_TINY_BLOB)
-#else
- if ((*field)->type() == FIELD_TYPE_BLOB)
-#endif
- {
- dsmBlob_t gemBlob;
- char *blobptr;
-
- gemBlob.areaType = DSMOBJECT_BLOB;
- gemBlob.blobObjNo = tableNumber;
- gemBlob.blobId = 0;
- gemBlob.totLength = gemBlob.segLength =
- ((Field_blob*)*field)->get_length((char*)record + (*field)->offset());
- ((Field_blob*)*field)->get_ptr((char**) &blobptr);
- gemBlob.pBuffer = (dsmBuffer_t *)blobptr;
- gemBlob.blobContext.blobOffset = 0;
- if (gemBlob.totLength)
- {
- dsmBlobStart(pcontext, &gemBlob);
- if (update && pBlobDesc->blobId)
- {
- gemBlob.blobId = pBlobDesc->blobId;
- dsmBlobUpdate(pcontext, &gemBlob, NULL);
- }
- else
- {
- dsmBlobPut(pcontext, &gemBlob, NULL);
- }
- dsmBlobEnd(pcontext, &gemBlob);
- }
- ptr = (byte*)((Field_blob*)*field)->pack_id((char*) ptr,
- (char*)record + (*field)->offset(), (longlong)gemBlob.blobId);
-
- pBlobDesc++;
- }
- else
- {
- ptr=(byte*) (*field)->pack((char*) ptr, (char*)record + (*field)->offset());
- }
- }
-
- *pprow=rec_buff;
- *ppackedLength= (ptr - rec_buff);
- return 0;
-}
-
-int ha_gemini::unpack_row(char *record, char *prow)
-{
- THD *thd = current_thd;
- dsmContext_t *pcontext = (dsmContext_t *)thd->gemini.context;
- gemBlobDesc_t *pBlobDesc = pBlobDescs;
-
- if (fixed_length_row)
- {
- /* If the table is a VST, the row is in Gemini internal format.
- ** Convert the fields to MySQL format.
- */
- if (RM_IS_VST(tableNumber))
- {
- int i = 2; /* VST fields are numbered sequentially starting at 2 */
- long longValue;
- char *fld;
- unsigned long unknown;
-
- for (Field **field = table->field; *field; field++, i++)
- {
- switch ((*field)->type())
- {
- case FIELD_TYPE_LONG:
- case FIELD_TYPE_TINY:
- case FIELD_TYPE_SHORT:
- case FIELD_TYPE_TIMESTAMP:
- case FIELD_TYPE_LONGLONG:
- case FIELD_TYPE_INT24:
- case FIELD_TYPE_DATE:
- case FIELD_TYPE_TIME:
- case FIELD_TYPE_DATETIME:
- case FIELD_TYPE_YEAR:
- case FIELD_TYPE_NEWDATE:
- case FIELD_TYPE_ENUM:
- case FIELD_TYPE_SET:
- recGetLONG((dsmText_t *)prow, i, 0, &longValue, &unknown);
- if (unknown)
- {
- (*field)->set_null();
- }
- else
- {
- (*field)->set_notnull();
- (*field)->store((longlong)longValue);
- }
- break;
-
- case FIELD_TYPE_DECIMAL:
- case FIELD_TYPE_DOUBLE:
- case FIELD_TYPE_TINY_BLOB:
- case FIELD_TYPE_MEDIUM_BLOB:
- case FIELD_TYPE_LONG_BLOB:
- case FIELD_TYPE_BLOB:
- case FIELD_TYPE_VAR_STRING:
- break;
-
- case FIELD_TYPE_STRING:
- svcByteString_t stringFld;
-
- fld = (char *)my_malloc((*field)->field_length, MYF(MY_WME));
- stringFld.pbyte = (TEXT *)fld;
- stringFld.size = (*field)->field_length;
- recGetBYTES((dsmText_t *)prow, i, 0, &stringFld, &unknown);
- if (unknown)
- {
- (*field)->set_null();
- }
- else
- {
- (*field)->set_notnull();
- (*field)->store(fld, (*field)->field_length);
- }
- my_free(fld, MYF(MY_ALLOW_ZERO_PTR));
- break;
-
- default:
- break;
- }
- }
- }
- else
- {
- memcpy(record,(char*) prow,table->reclength);
- }
- }
- else
- {
- /* Copy null bits */
- const char *ptr= (const char*) prow;
- memcpy(record, ptr, table->null_bytes);
- ptr+=table->null_bytes;
-
- for (Field **field=table->field ; *field ; field++)
- {
-#ifdef GEMINI_TINYBLOB_IN_ROW
- /* Tiny blobs (255 bytes or less) are stored in the row; larger
- ** blobs are stored in a separate storage object (see ha_gemini::create).
- */
- if ((*field)->type() == FIELD_TYPE_BLOB &&
- ((Field_blob*)*field)->blobtype() != FIELD_TYPE_TINY_BLOB)
-#else
- if ((*field)->type() == FIELD_TYPE_BLOB)
-#endif
- {
- dsmBlob_t gemBlob;
-
- gemBlob.areaType = DSMOBJECT_BLOB;
- gemBlob.blobObjNo = tableNumber;
- gemBlob.blobId = (dsmBlobId_t)(((Field_blob*)*field)->get_id(ptr));
- if (gemBlob.blobId)
- {
- gemBlob.totLength =
- gemBlob.segLength = ((Field_blob*)*field)->get_length(ptr);
- /* Allocate memory to store the blob. This memory is freed
- ** the next time unpack_row is called for this table.
- */
- gemBlob.pBuffer = (dsmBuffer_t *)my_malloc(gemBlob.totLength,
- MYF(0));
- if (!gemBlob.pBuffer)
- {
- return HA_ERR_OUT_OF_MEM;
- }
- gemBlob.blobContext.blobOffset = 0;
- dsmBlobStart(pcontext, &gemBlob);
- dsmBlobGet(pcontext, &gemBlob, NULL);
- dsmBlobEnd(pcontext, &gemBlob);
- }
- else
- {
- gemBlob.pBuffer = 0;
- }
- ptr = ((Field_blob*)*field)->unpack_id(record + (*field)->offset(),
- ptr, (char *)gemBlob.pBuffer);
- pBlobDesc->blobId = gemBlob.blobId;
- my_free((char*)pBlobDesc->pBlob, MYF(MY_ALLOW_ZERO_PTR));
- pBlobDesc->pBlob = gemBlob.pBuffer;
- pBlobDesc++;
- }
- else
- {
- ptr= (*field)->unpack(record + (*field)->offset(), ptr);
- }
- }
- }
-
- return 0;
-}
-
-int ha_gemini::key_cmp(uint keynr, const byte * old_row,
- const byte * new_row, bool updateStats)
-{
- KEY_PART_INFO *key_part=table->key_info[keynr].key_part;
- KEY_PART_INFO *end=key_part+table->key_info[keynr].key_parts;
-
- for ( uint i = 0 ; key_part != end ; key_part++, i++)
- {
- if (key_part->null_bit)
- {
- if ((old_row[key_part->null_offset] & key_part->null_bit) !=
- (new_row[key_part->null_offset] & key_part->null_bit))
- {
- if(updateStats)
- table->key_info[keynr].rec_per_key[i]++;
- return 1;
- }
- else if((old_row[key_part->null_offset] & key_part->null_bit) &&
- (new_row[key_part->null_offset] & key_part->null_bit))
- /* Both are null */
- continue;
- }
- if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH))
- {
- if (key_part->field->cmp_binary((char*)(old_row + key_part->offset),
- (char*)(new_row + key_part->offset),
- (ulong) key_part->length))
- {
- if(updateStats)
- table->key_info[keynr].rec_per_key[i]++;
- return 1;
- }
- }
- else
- {
- if (memcmp(old_row+key_part->offset, new_row+key_part->offset,
- key_part->length))
- {
- /* Check for special case of -0 which causes table check
- to find an invalid key when comparing the the index
- value of 0 to the -0 stored in the row */
- if(key_part->field->type() == FIELD_TYPE_DECIMAL)
- {
- double fieldValue;
- char *ptr = key_part->field->ptr;
-
- key_part->field->ptr = (char *)old_row + key_part->offset;
- fieldValue = key_part->field->val_real();
- if(fieldValue == 0)
- {
- key_part->field->ptr = (char *)new_row + key_part->offset;
- fieldValue = key_part->field->val_real();
- if(fieldValue == 0)
- {
- key_part->field->ptr = ptr;
- continue;
- }
- }
- key_part->field->ptr = ptr;
- }
- if(updateStats)
- {
- table->key_info[keynr].rec_per_key[i]++;
- }
- return 1;
- }
- }
- }
- return 0;
-}
-
-int gemini_parse_table_name(const char *fullname, char *dbname, char *tabname)
-{
- char *namestart;
- char *nameend;
-
- /* separate out the name of the table and the database
- */
- namestart = (char *)strchr(fullname + start_of_name, '/');
- if (!namestart)
- {
- /* if on Windows, slashes go the other way */
- namestart = (char *)strchr(fullname + start_of_name, '\\');
- }
- nameend = (char *)strchr(fullname + start_of_name, '.');
- /* sometimes fullname has an extension, sometimes it doesn't */
- if (!nameend)
- {
- nameend = (char *)fullname + strlen(fullname);
- }
- strncpy(dbname, fullname + start_of_name,
- (namestart - fullname) - start_of_name);
- dbname[(namestart - fullname) - start_of_name] = '\0';
- strncpy(tabname, namestart + 1, (nameend - namestart) - 1);
- tabname[nameend - namestart - 1] = '\0';
-
- return 0;
-}
-
-/* PROGRAM: gemini_is_vst - if the name is the name of a VST, return
- * its number
- *
- * RETURNS: Table number if a match is found
- * 0 if not a VST
- */
-int
-gemini_is_vst(const char *pname) /* IN the name */
-{
- int tablenum = 0;
-
- for (int i = 0; i < vstnumfils; i++)
- {
- if (strcmp(pname, vstfil[i].filename) == 0)
- {
- tablenum = vstfil[i].filnum;
- break;
- }
- }
-
- return tablenum;
-}
-
-static void print_msg(THD *thd, const char *table_name, const char *op_name,
- const char *msg_type, const char *fmt, ...)
-{
- String* packet = &thd->packet;
- packet->length(0);
- char msgbuf[256];
- msgbuf[0] = 0;
- va_list args;
- va_start(args,fmt);
-
- my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
- msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
-
- DBUG_PRINT(msg_type,("message: %s",msgbuf));
-
- net_store_data(packet, table_name);
- net_store_data(packet, op_name);
- net_store_data(packet, msg_type);
- net_store_data(packet, msgbuf);
- if (my_net_write(&thd->net, (char*)thd->packet.ptr(),
- thd->packet.length()))
- thd->killed=1;
-}
-
-/* Load shared area with rows per key statistics */
-void
-ha_gemini::get_index_stats(THD *thd)
-{
- dsmStatus_t rc = 0;
- ha_rows *rec_per_key = share->rec_per_key;
-
- for(uint i = 0; i < table->keys && !rc; i++)
- {
- for (uint j = 0; j < table->key_info[i].key_parts && !rc;j++)
- {
- LONG64 rows_per_key;
- rc = dsmIndexStatsGet((dsmContext_t *)thd->gemini.context,
- tableNumber, pindexNumbers[i],(int)j,
- &rows_per_key);
- if (rc)
- {
- gemini_msg((dsmContext_t *)thd->gemini.context,
- "Index Statistics faild for table %d index %d, error %d",
- tableNumber, pindexNumbers[i], rc);
- }
- *rec_per_key = (ha_rows)rows_per_key;
- rec_per_key++;
- }
- }
- return;
-}
-
-/****************************************************************************
- Handling the shared GEM_SHARE structure that is needed to provide
- a global in memory storage location of the rec_per_key stats used
- by the optimizer.
-****************************************************************************/
-
-static byte* gem_get_key(GEM_SHARE *share,uint *length,
- my_bool not_used __attribute__((unused)))
-{
- *length=share->table_name_length;
- return (byte*) share->table_name;
-}
-
-static GEM_SHARE *get_share(const char *table_name, TABLE *table)
-{
- GEM_SHARE *share;
-
- pthread_mutex_lock(&gem_mutex);
- uint length=(uint) strlen(table_name);
- if (!(share=(GEM_SHARE*) hash_search(&gem_open_tables, (byte*) table_name,
- length)))
- {
- ha_rows *rec_per_key;
- char *tmp_name;
-
- if ((share=(GEM_SHARE *)
- my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
- &share, sizeof(*share),
- &rec_per_key, table->key_parts * sizeof(ha_rows),
- &tmp_name, length+1,
- NullS)))
- {
- share->rec_per_key = rec_per_key;
- share->table_name = tmp_name;
- share->table_name_length=length;
- strcpy(share->table_name,table_name);
- if (hash_insert(&gem_open_tables, (byte*) share))
- {
- pthread_mutex_unlock(&gem_mutex);
- my_free((gptr) share,0);
- return 0;
- }
- thr_lock_init(&share->lock);
- pthread_mutex_init(&share->mutex,NULL);
- }
- }
- pthread_mutex_unlock(&gem_mutex);
- return share;
-}
-
-static int free_share(GEM_SHARE *share, bool mutex_is_locked)
-{
- pthread_mutex_lock(&gem_mutex);
- if (mutex_is_locked)
- pthread_mutex_unlock(&share->mutex);
- if (!--share->use_count)
- {
- hash_delete(&gem_open_tables, (byte*) share);
- thr_lock_delete(&share->lock);
- pthread_mutex_destroy(&share->mutex);
- my_free((gptr) share, MYF(0));
- }
- pthread_mutex_unlock(&gem_mutex);
- return 0;
-}
-
-static void gemini_lock_table_overflow_error(dsmContext_t *pcontext)
-{
- gemini_msg(pcontext, "The total number of locks exceeds the lock table size");
- gemini_msg(pcontext, "Either increase gemini_lock_table_size or use a");
- gemini_msg(pcontext, "different transaction isolation level");
-}
-
-#endif /* HAVE_GEMINI_DB */