git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@1009 0109f412-320b-0410-ab79-c3e0c5ffbbe6
3354 lines
67 KiB
C++
3354 lines
67 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: FLAIM handler for MySQL
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 2006-2007 Novell, Inc. All Rights Reserved.
|
|
//
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
// License as published by the Free Software Foundation; version 2.1
|
|
// of the License.
|
|
//
|
|
// This library 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
|
|
// Library Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; if not, contact Novell, Inc.
|
|
//
|
|
// To contact Novell about this file by physical or electronic mail,
|
|
// you may find current contact information at www.novell.com.
|
|
//
|
|
// $Id$
|
|
//------------------------------------------------------------------------------
|
|
|
|
#ifdef USE_PRAGMA_IMPLEMENTATION
|
|
#pragma implementation
|
|
#endif
|
|
|
|
#include "mysql_priv.h"
|
|
|
|
//#ifdef HAVE_FLAIM
|
|
|
|
#include "ha_flaim.h"
|
|
|
|
#define FLAIM_DB_NAME "flaim.db"
|
|
#define FLM_TABLE_INFO_FIELD_NAME "table_info"
|
|
#define FLM_TABLE_INFO_FIELD_ID 1
|
|
#define FLM_ROW_CONTEXT_FIELD_NAME "row"
|
|
#define FLM_ROW_CONTEXT_FIELD_ID 2
|
|
#define FLM_ROW_NULL_BITS_FIELD_NAME "null_bits"
|
|
#define FLM_ROW_NULL_BITS_FIELD_ID 3
|
|
#define FLM_ROW_COUNT_FIELD_NAME "row_count"
|
|
#define FLM_ROW_COUNT_FIELD_ID 4
|
|
|
|
const char * gv_pszBaseDict =
|
|
"0 @1@ field " FLM_TABLE_INFO_FIELD_NAME "\n" \
|
|
" 1 type context\n" \
|
|
"0 @2@ field " FLM_ROW_CONTEXT_FIELD_NAME "\n" \
|
|
" 1 type context\n" \
|
|
"0 @3@ field " FLM_ROW_NULL_BITS_FIELD_NAME "\n" \
|
|
" 1 type binary\n" \
|
|
"0 @4@ field " FLM_ROW_COUNT_FIELD_NAME "\n" \
|
|
" 1 type number";
|
|
|
|
static int flaim_commit(
|
|
THD * pThread,
|
|
bool bAll);
|
|
|
|
static int flaim_rollback(
|
|
THD * pThread,
|
|
bool bAll);
|
|
|
|
FlmConnectionTable * gv_pConnTbl = NULL;
|
|
pthread_mutex_t gv_hShareMutex;
|
|
static HASH gv_openTables;
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
static const char * ha_flaim_exts[] =
|
|
{
|
|
NullS
|
|
};
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
handlerton flaim_hton =
|
|
{
|
|
"FLAIM", // name
|
|
SHOW_OPTION_YES, // state
|
|
"FLAIM storage engine", // comment
|
|
DB_TYPE_FLAIM, // db_type
|
|
flaim_init, // init
|
|
0, // slot
|
|
0, // savepoint size
|
|
NULL, // close connection
|
|
NULL, // savepoint
|
|
NULL, // rollback to savepoint
|
|
NULL, // release savepoint
|
|
flaim_commit, // commit
|
|
flaim_rollback, // rollback
|
|
NULL, // prepare
|
|
NULL, // recover
|
|
NULL, // commit_by_xid
|
|
NULL, // rollback_by_xid
|
|
NULL, // create_cursor_read_view
|
|
NULL, // set_cursor_read_view
|
|
NULL, // close_cursor_read_view
|
|
HTON_NO_FLAGS // flags
|
|
};
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
inline void buildDbPathFromTablePath(
|
|
const char * pszTablePath,
|
|
char * pszDbPath)
|
|
{
|
|
f_pathReduce( pszTablePath, pszDbPath, NULL);
|
|
f_pathAppend( pszDbPath, FLAIM_DB_NAME);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
static byte * flmShareGetKey(
|
|
FLAIM_SHARE * pShare,
|
|
uint * puiLength,
|
|
my_bool not_used __attribute__((unused)))
|
|
{
|
|
*puiLength = pShare->uiTablePathLen;
|
|
return( (byte *)pShare->pszTablePath);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
static RCODE flmGetShare(
|
|
FlmConnection * pConn,
|
|
const char * pszTablePath,
|
|
TABLE * pTable,
|
|
FLAIM_SHARE ** ppShare)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLAIM_SHARE * pShare;
|
|
FLMBOOL bCreatedMutex = FALSE;
|
|
FLMBOOL bShareLocked = FALSE;
|
|
F_NameTable nameTable;
|
|
Field ** ppMyField;
|
|
FIELD_INFO * pColumnFields;
|
|
FIELD_INFO * pKeyFields;
|
|
INDEX_INFO * pIndexes;
|
|
FLMUINT uiLoop;
|
|
uint uiLength;
|
|
char * pszTmpPath;
|
|
char szTmpBuf[ 512];
|
|
|
|
*ppShare = NULL;
|
|
|
|
pthread_mutex_lock( &gv_hShareMutex);
|
|
bShareLocked = TRUE;
|
|
|
|
uiLength = (uint)strlen( pszTablePath);
|
|
|
|
if( (pShare = (FLAIM_SHARE *)hash_search( &gv_openTables,
|
|
(byte *)pszTablePath, uiLength)) == NULL)
|
|
{
|
|
if( !(pShare = (FLAIM_SHARE *)my_multi_malloc(
|
|
MYF( MY_WME | MY_ZEROFILL), &pShare, sizeof( *pShare),
|
|
&pszTmpPath, uiLength + 1,
|
|
&pColumnFields, pTable->s->fields * sizeof( FIELD_INFO),
|
|
&pKeyFields, pTable->s->keys * sizeof( FIELD_INFO),
|
|
&pIndexes, pTable->s->keys * sizeof( INDEX_INFO),
|
|
NullS)))
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
pShare->uiUseCount = 0;
|
|
pShare->uiTablePathLen = uiLength;
|
|
pShare->pszTablePath = pszTmpPath;
|
|
strmov( pShare->pszTablePath, pszTablePath);
|
|
pShare->pColumnFields = pColumnFields;
|
|
pShare->pKeyFields = pKeyFields;
|
|
pShare->pIndexes = pIndexes;
|
|
|
|
if( RC_BAD( rc = nameTable.setupFromDb( pConn->getDb())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
sprintf( szTmpBuf, ":%s:", pTable->s->table_name);
|
|
|
|
if( !nameTable.getFromTagTypeAndName( NULL, szTmpBuf,
|
|
FLM_CONTAINER_TAG, &pShare->uiTableContainer))
|
|
{
|
|
rc = FERR_DATA_ERROR;
|
|
goto Exit;
|
|
}
|
|
|
|
for( ppMyField = pTable->field; *ppMyField; ppMyField++)
|
|
{
|
|
FIELD_INFO * pFieldInfo = &pShare->pColumnFields[
|
|
(*ppMyField)->field_index];
|
|
|
|
sprintf( szTmpBuf, ":%s:col:%s:",
|
|
pTable->s->table_name, (*ppMyField)->field_name);
|
|
|
|
if( !nameTable.getFromTagTypeAndName( NULL, szTmpBuf, FLM_FIELD_TAG,
|
|
&pFieldInfo->uiDictNum, &pFieldInfo->uiDataType))
|
|
{
|
|
rc = FERR_DATA_ERROR;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
for( uiLoop = 0; uiLoop < pTable->s->keys; uiLoop++)
|
|
{
|
|
sprintf( szTmpBuf, ":%s:key:%u:", pTable->s->table_name, uiLoop);
|
|
|
|
if( !nameTable.getFromTagTypeAndName( NULL, szTmpBuf, FLM_FIELD_TAG,
|
|
&pShare->pKeyFields[ uiLoop].uiDictNum,
|
|
&pShare->pKeyFields[ uiLoop].uiDataType))
|
|
{
|
|
rc = FERR_DATA_ERROR;
|
|
goto Exit;
|
|
}
|
|
|
|
sprintf( szTmpBuf, ":%s:index:%u:", pTable->s->table_name, uiLoop);
|
|
|
|
if( !nameTable.getFromTagTypeAndName( NULL, szTmpBuf, FLM_INDEX_TAG,
|
|
&pShare->pIndexes[ uiLoop].uiDictNum, NULL))
|
|
{
|
|
rc = FERR_DATA_ERROR;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( my_hash_insert( &gv_openTables, (byte *)pShare))
|
|
{
|
|
rc = FERR_FAILURE;
|
|
goto Exit;
|
|
}
|
|
|
|
thr_lock_init( &pShare->lock);
|
|
bCreatedMutex = TRUE;
|
|
pthread_mutex_init( &pShare->hMutex, MY_MUTEX_INIT_FAST);
|
|
}
|
|
|
|
pShare->uiUseCount++;
|
|
pthread_mutex_unlock( &gv_hShareMutex);
|
|
bShareLocked = FALSE;
|
|
|
|
*ppShare = pShare;
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
if( pShare)
|
|
{
|
|
if( bCreatedMutex)
|
|
{
|
|
pthread_mutex_destroy( &pShare->hMutex);
|
|
}
|
|
|
|
my_free( (gptr)pShare, MYF(0));
|
|
}
|
|
}
|
|
|
|
if( bShareLocked)
|
|
{
|
|
pthread_mutex_unlock( &gv_hShareMutex);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
static int flmReleaseShare(
|
|
FLAIM_SHARE * pShare)
|
|
{
|
|
pthread_mutex_lock( &gv_hShareMutex);
|
|
if( --pShare->uiUseCount == 0)
|
|
{
|
|
hash_delete( &gv_openTables, (byte *)pShare);
|
|
thr_lock_delete( &pShare->lock);
|
|
pthread_mutex_destroy( &pShare->hMutex);
|
|
my_free( (gptr)pShare, MYF(0));
|
|
}
|
|
|
|
pthread_mutex_unlock( &gv_hShareMutex);
|
|
return( 0);
|
|
}
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
bool flaim_init( void)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMBOOL bCleanup = FALSE;
|
|
|
|
DBUG_ENTER( "flmInit");
|
|
|
|
if( have_flaim != SHOW_OPTION_YES)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmStartup()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bCleanup = TRUE;
|
|
|
|
if( (gv_pConnTbl = new FlmConnectionTable) == NULL)
|
|
{
|
|
rc = FERR_FAILURE;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->setup()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (pthread_mutex_init( &gv_hShareMutex, MY_MUTEX_INIT_FAST)) != 0)
|
|
{
|
|
rc = FERR_FAILURE;
|
|
goto Exit;
|
|
}
|
|
|
|
if( (hash_init( &gv_openTables, system_charset_info, 32, 0, 0,
|
|
(hash_get_key)flmShareGetKey, 0, 0)) != 0)
|
|
{
|
|
rc = FERR_FAILURE;
|
|
goto Exit;
|
|
}
|
|
|
|
DBUG_RETURN( FALSE);
|
|
|
|
Exit:
|
|
|
|
if( bCleanup)
|
|
{
|
|
flaim_end();
|
|
}
|
|
|
|
have_flaim = SHOW_OPTION_DISABLED;
|
|
DBUG_RETURN( TRUE);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
bool flaim_end( void)
|
|
{
|
|
DBUG_ENTER( "flaim_end");
|
|
|
|
if( gv_pConnTbl)
|
|
{
|
|
gv_pConnTbl->Release();
|
|
gv_pConnTbl = NULL;
|
|
}
|
|
|
|
FlmShutdown();
|
|
DBUG_RETURN( FALSE);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
ha_flaim::ha_flaim( TABLE * table_arg) : handler( &flaim_hton, table_arg)
|
|
{
|
|
m_pConn = NULL;
|
|
m_pShare = NULL;
|
|
m_uiCurrRowDrn = 0;
|
|
active_index = MAX_KEY;
|
|
m_pCurrKey = NULL;
|
|
m_szDbPath[ 0] = 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
const char ** ha_flaim::bas_ext( void) const
|
|
{
|
|
return( ha_flaim_exts);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Used for opening tables. The name will be the name of the file.
|
|
A table is opened when it needs to be opened. For instance
|
|
when a request comes in for a select on the table (tables are not
|
|
open and closed for each request, they are cached).
|
|
****************************************************************************/
|
|
int ha_flaim::open(
|
|
const char * pszTablePath,
|
|
int iMode,
|
|
uint bTestIfLocked)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
|
|
DBUG_ENTER( "ha_flaim::open");
|
|
|
|
buildDbPathFromTablePath( pszTablePath, m_szDbPath);
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection( m_szDbPath, &m_pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = flmGetShare( m_pConn, pszTablePath, table, &m_pShare)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
thr_lock_data_init( &m_pShare->lock, &m_lockData, NULL);
|
|
ref_length = sizeof( FLMUINT32);
|
|
|
|
Exit:
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Closes a table
|
|
****************************************************************************/
|
|
int ha_flaim::close(void)
|
|
{
|
|
DBUG_ENTER( "ha_flaim::close");
|
|
|
|
flmReleaseShare( m_pShare);
|
|
m_pShare = NULL;
|
|
m_szDbPath[ 0] = 0;
|
|
m_uiCurrRowDrn = 0;
|
|
active_index = MAX_KEY;
|
|
|
|
if( m_pConn)
|
|
{
|
|
m_pConn->Release();
|
|
m_pConn = NULL;
|
|
}
|
|
|
|
if( m_pCurrKey)
|
|
{
|
|
m_pCurrKey->Release();
|
|
m_pCurrKey = NULL;
|
|
}
|
|
|
|
DBUG_RETURN( 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Inserts a row. The buffer is a byte array of data. The field
|
|
information can be used to extract the data from the native byte
|
|
array.
|
|
****************************************************************************/
|
|
int ha_flaim::write_row(
|
|
byte * pucData)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmRecord * pRec = NULL;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
|
|
DBUG_ENTER( "ha_flaim::write_row");
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection( m_szDbPath, &m_pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = exportRowToRec( pucData, &pRec)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
m_uiCurrRowDrn = 0;
|
|
if( RC_BAD( rc = FlmRecordAdd( m_pConn->getDb(),
|
|
m_pShare->uiTableContainer, &m_uiCurrRowDrn, pRec, 0)))
|
|
{
|
|
if( rc == FERR_NOT_UNIQUE)
|
|
{
|
|
rc = (RCODE)HA_ERR_FOUND_DUPP_KEY;
|
|
bMustAbortOnError = FALSE;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pConn->incrementRowCount(
|
|
m_pShare->uiTableContainer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
statistic_increment( table->in_use->status_var.ha_write_count,
|
|
&LOCK_status);
|
|
|
|
// If we have a timestamp column, update it to the current time
|
|
|
|
if( table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
|
|
{
|
|
table->timestamp_field->set_time();
|
|
}
|
|
|
|
// If we have an auto_increment column and we are writing a changed row
|
|
// or a new row, then update the auto_increment value in the record.
|
|
|
|
if( table->next_number_field && pucData == table->record[ 0])
|
|
{
|
|
update_auto_increment();
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pRec)
|
|
{
|
|
pRec->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
m_pConn->setAbortFlag();
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Updates a row. old_data will have the previous row record in
|
|
it, while new_data will have the newest data in it.
|
|
****************************************************************************/
|
|
int ha_flaim::update_row(
|
|
const byte * pucOldData,
|
|
byte * pucNewData)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmRecord * pRec = NULL;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
|
|
DBUG_ENTER( "ha_flaim::update_row");
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection( m_szDbPath, &m_pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = exportRowToRec( pucNewData, &pRec)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = FlmRecordModify( m_pConn->getDb(),
|
|
m_pShare->uiTableContainer, m_uiCurrRowDrn, pRec, 0)))
|
|
{
|
|
if( rc == FERR_NOT_UNIQUE)
|
|
{
|
|
rc = (RCODE)HA_ERR_FOUND_DUPP_KEY;
|
|
bMustAbortOnError = FALSE;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
|
|
&LOCK_status);
|
|
|
|
// If we have a timestamp column, update it to the current time
|
|
|
|
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
|
|
{
|
|
table->timestamp_field->set_time();
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pRec)
|
|
{
|
|
pRec->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
m_pConn->setAbortFlag();
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: This will delete a row. pucData will contain a copy of the row to
|
|
be deleted.
|
|
****************************************************************************/
|
|
int ha_flaim::delete_row(
|
|
const byte * pucData)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
|
|
DBUG_ENTER( "ha_flaim::delete_row");
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection( m_szDbPath, &m_pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = FlmRecordDelete( m_pConn->getDb(),
|
|
m_pShare->uiTableContainer, m_uiCurrRowDrn, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pConn->decrementRowCount(
|
|
m_pShare->uiTableContainer)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
statistic_increment( table->in_use->status_var.ha_delete_count,
|
|
&LOCK_status);
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
m_pConn->setAbortFlag();
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
int ha_flaim::index_init(
|
|
uint uiIndex)
|
|
{
|
|
DBUG_ENTER( "ha_flaim::index_init");
|
|
|
|
active_index = uiIndex;
|
|
assert( m_pCurrKey == NULL);
|
|
|
|
DBUG_RETURN( 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
int ha_flaim::index_end( void)
|
|
{
|
|
DBUG_ENTER( "ha_flaim::index_end");
|
|
|
|
active_index = MAX_KEY;
|
|
|
|
if( m_pCurrKey)
|
|
{
|
|
m_pCurrKey->Release();
|
|
m_pCurrKey = NULL;
|
|
}
|
|
|
|
DBUG_RETURN( 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Positions an index cursor to the index specified in the handle.
|
|
Fetches the row if available. If the key value is null, begin at
|
|
the first key of the index.
|
|
****************************************************************************/
|
|
int ha_flaim::index_read(
|
|
byte * pucData,
|
|
const byte * pucKey,
|
|
uint uiKeyLen,
|
|
enum ha_rkey_function eFindFlag)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmRecord * pKeyRec = NULL;
|
|
FlmRecord * pRec = NULL;
|
|
FLMUINT uiReference;
|
|
FLMUINT uiFindFlags = 0;
|
|
void * pvField;
|
|
|
|
DBUG_ENTER( "ha_flaim::index_read");
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection( m_szDbPath, &m_pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pucKey)
|
|
{
|
|
if( RC_BAD( rc = exportKeyToTree( active_index,
|
|
pucKey, uiKeyLen, &pKeyRec)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
switch( eFindFlag)
|
|
{
|
|
case HA_READ_KEY_EXACT:
|
|
{
|
|
uiFindFlags = FO_INCL;
|
|
break;
|
|
}
|
|
|
|
case HA_READ_KEY_OR_NEXT:
|
|
{
|
|
uiFindFlags = FO_INCL;
|
|
break;
|
|
}
|
|
|
|
case HA_READ_AFTER_KEY:
|
|
{
|
|
uiFindFlags = FO_EXCL;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
rc = (RCODE)HA_ERR_WRONG_COMMAND;
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiFindFlags = FO_FIRST;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmKeyRetrieve( m_pConn->getDb(),
|
|
m_pShare->pIndexes[ active_index].uiDictNum, 0,
|
|
pKeyRec, 0, uiFindFlags, &m_pCurrKey, &uiReference)))
|
|
{
|
|
if( rc == FERR_NOT_FOUND)
|
|
{
|
|
rc = (RCODE)HA_ERR_KEY_NOT_FOUND;
|
|
table->status = STATUS_NOT_FOUND;
|
|
}
|
|
else if( rc == FERR_EOF_HIT)
|
|
{
|
|
rc = (RCODE)HA_ERR_END_OF_FILE;
|
|
table->status = STATUS_NOT_FOUND;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( eFindFlag == HA_READ_KEY_EXACT)
|
|
{
|
|
FLMUINT uiTmpKeyLen = uiKeyLen;
|
|
char * pucBuf = m_pucKeyBuf;
|
|
char * pucBufEnd = &m_pucKeyBuf[ FLM_MAX_KEY_LENGTH];
|
|
KEY * pKey = table->key_info + active_index;
|
|
KEY_PART_INFO * pCurKeyPart = pKey->key_part;
|
|
KEY_PART_INFO * pEndKeyPart = pCurKeyPart + pKey->key_parts;
|
|
|
|
if( (pvField = m_pCurrKey->find( m_pCurrKey->root(),
|
|
m_pShare->pKeyFields[ active_index].uiDictNum)) == NULL)
|
|
{
|
|
rc = FERR_DATA_ERROR;
|
|
goto Exit;
|
|
}
|
|
|
|
for( ; pCurKeyPart != pEndKeyPart && uiTmpKeyLen > 0; pCurKeyPart++)
|
|
{
|
|
FLMUINT uiOffset = 0;
|
|
|
|
if( pCurKeyPart->null_bit)
|
|
{
|
|
*pucBuf++ = *pucKey ? 1 : 0;
|
|
uiTmpKeyLen -= pCurKeyPart->store_length;
|
|
pucKey += pCurKeyPart->store_length;
|
|
uiOffset = 1;
|
|
}
|
|
|
|
pucBuf = pCurKeyPart->field->pack_key_from_key_image( pucBuf,
|
|
(const char *)pucKey + uiOffset, pCurKeyPart->length);
|
|
pucKey += pCurKeyPart->store_length;
|
|
uiTmpKeyLen -= pCurKeyPart->store_length;
|
|
|
|
assert( pucBuf <= pucBufEnd);
|
|
}
|
|
|
|
uiTmpKeyLen = pucBuf - m_pucKeyBuf;
|
|
|
|
if( m_pCurrKey->getDataLength( pvField) < uiTmpKeyLen ||
|
|
memcmp( m_pCurrKey->getDataPtr( pvField), m_pucKeyBuf, uiTmpKeyLen) != 0)
|
|
{
|
|
rc = (RCODE)HA_ERR_END_OF_FILE;
|
|
table->status = STATUS_NOT_FOUND;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmRecordRetrieve( m_pConn->getDb(),
|
|
m_pShare->uiTableContainer, uiReference,
|
|
FO_EXACT, &pRec, &m_uiCurrRowDrn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = importRowFromRec( pRec, pucData)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
table->status = 0;
|
|
|
|
Exit:
|
|
|
|
if( pRec)
|
|
{
|
|
pRec->Release();
|
|
}
|
|
|
|
if( pKeyRec)
|
|
{
|
|
pKeyRec->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
m_uiCurrRowDrn = 0;
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Used to read forward through the index
|
|
****************************************************************************/
|
|
int ha_flaim::index_next(
|
|
byte * pucData)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMUINT uiReference;
|
|
FlmRecord * pRec = NULL;
|
|
|
|
DBUG_ENTER( "ha_flaim::index_read");
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection( m_szDbPath, &m_pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmKeyRetrieve( m_pConn->getDb(),
|
|
m_pShare->pIndexes[ active_index].uiDictNum, 0,
|
|
m_pCurrKey, 0, FO_EXCL, &m_pCurrKey, &uiReference)))
|
|
{
|
|
if( rc == FERR_NOT_FOUND)
|
|
{
|
|
rc = (RCODE)HA_ERR_KEY_NOT_FOUND;
|
|
table->status = STATUS_NOT_FOUND;
|
|
}
|
|
else if( rc == FERR_EOF_HIT)
|
|
{
|
|
rc = (RCODE)HA_ERR_END_OF_FILE;
|
|
table->status = STATUS_NOT_FOUND;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmRecordRetrieve( m_pConn->getDb(),
|
|
m_pShare->uiTableContainer, uiReference,
|
|
FO_EXACT, &pRec, &m_uiCurrRowDrn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = importRowFromRec( pRec, pucData)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
table->status = 0;
|
|
|
|
Exit:
|
|
|
|
if( pRec)
|
|
{
|
|
pRec->Release();
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns the first key in the index
|
|
****************************************************************************/
|
|
int ha_flaim::index_first(
|
|
byte * pucData)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmRecord * pRec = NULL;
|
|
FLMUINT uiReference;
|
|
|
|
DBUG_ENTER( "ha_flaim::index_first");
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection( m_szDbPath, &m_pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmKeyRetrieve( m_pConn->getDb(),
|
|
m_pShare->pIndexes[ active_index].uiDictNum, 0,
|
|
NULL, 0, FO_FIRST, &m_pCurrKey, &uiReference)))
|
|
{
|
|
if( rc == FERR_NOT_FOUND)
|
|
{
|
|
rc = (RCODE)HA_ERR_KEY_NOT_FOUND;
|
|
table->status = STATUS_NOT_FOUND;
|
|
}
|
|
else if( rc == FERR_EOF_HIT)
|
|
{
|
|
rc = (RCODE)HA_ERR_END_OF_FILE;
|
|
table->status = STATUS_NOT_FOUND;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmRecordRetrieve( m_pConn->getDb(),
|
|
m_pShare->uiTableContainer, uiReference,
|
|
FO_EXACT, &pRec, &m_uiCurrRowDrn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = importRowFromRec( pRec, pucData)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
table->status = 0;
|
|
|
|
Exit:
|
|
|
|
if( pRec)
|
|
{
|
|
pRec->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
m_uiCurrRowDrn = 0;
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns the last key in the index
|
|
****************************************************************************/
|
|
int ha_flaim::index_last(
|
|
byte * pucData)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmRecord * pRec = NULL;
|
|
FLMUINT uiReference;
|
|
|
|
DBUG_ENTER( "ha_flaim::index_last");
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection( m_szDbPath, &m_pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmKeyRetrieve( m_pConn->getDb(),
|
|
m_pShare->pIndexes[ active_index].uiDictNum, 0,
|
|
NULL, 0, FO_LAST, &m_pCurrKey, &uiReference)))
|
|
{
|
|
if( rc == FERR_NOT_FOUND)
|
|
{
|
|
rc = (RCODE)HA_ERR_KEY_NOT_FOUND;
|
|
table->status = STATUS_NOT_FOUND;
|
|
}
|
|
else if( rc == FERR_EOF_HIT)
|
|
{
|
|
rc = (RCODE)HA_ERR_END_OF_FILE;
|
|
table->status = STATUS_NOT_FOUND;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmRecordRetrieve( m_pConn->getDb(),
|
|
m_pShare->uiTableContainer, uiReference,
|
|
FO_EXACT, &pRec, &m_uiCurrRowDrn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = importRowFromRec( pRec, pucData)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
table->status = 0;
|
|
|
|
Exit:
|
|
|
|
if( pRec)
|
|
{
|
|
pRec->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
m_uiCurrRowDrn = 0;
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Called when the system wants the storage engine to do a table scan.
|
|
****************************************************************************/
|
|
int ha_flaim::rnd_init(
|
|
bool scan)
|
|
{
|
|
DBUG_ENTER( "ha_flaim::rnd_init");
|
|
m_uiCurrRowDrn = 0;
|
|
DBUG_RETURN( 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
int ha_flaim::rnd_end( void)
|
|
{
|
|
DBUG_ENTER( "ha_flaim::rnd_end");
|
|
m_uiCurrRowDrn = 0;
|
|
DBUG_RETURN( 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: This is called for each row of the table scan. When the end of the
|
|
table is hit, HA_ERR_END_OF_FILE is returned. The buffer is filled
|
|
with the row information.
|
|
****************************************************************************/
|
|
int ha_flaim::rnd_next(
|
|
byte * pucData)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmRecord * pRec = NULL;
|
|
|
|
DBUG_ENTER( "ha_flaim::rnd_next");
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection(
|
|
m_szDbPath, &m_pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmRecordRetrieve( m_pConn->getDb(),
|
|
m_pShare->uiTableContainer,
|
|
m_uiCurrRowDrn, FO_EXCL, &pRec, &m_uiCurrRowDrn)))
|
|
{
|
|
if( rc == FERR_EOF_HIT)
|
|
{
|
|
m_uiCurrRowDrn = 0;
|
|
rc = (RCODE)HA_ERR_END_OF_FILE;
|
|
table->status = STATUS_NOT_FOUND;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = importRowFromRec( pRec, pucData)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
table->status = 0;
|
|
|
|
Exit:
|
|
|
|
if( pRec)
|
|
{
|
|
pRec->Release();
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Called after each call to rnd_next() if the data needs
|
|
to be ordered.
|
|
****************************************************************************/
|
|
void ha_flaim::position( const byte *record)
|
|
{
|
|
DBUG_ENTER( "ha_flaim::position");
|
|
my_store_ptr( ref, ref_length, m_uiCurrRowDrn);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: This is like rnd_next, but a position is specified and is used to
|
|
determine the row. The position will be of the type that was stored
|
|
in position().
|
|
****************************************************************************/
|
|
int ha_flaim::rnd_pos(
|
|
byte * pucData,
|
|
byte * pucPos)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmRecord * pRec = NULL;
|
|
FLMUINT uiLength;
|
|
|
|
DBUG_ENTER( "ha_flaim::rnd_pos");
|
|
|
|
statistic_increment( table->in_use->status_var.ha_read_rnd_next_count,
|
|
&LOCK_status);
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection(
|
|
m_szDbPath, &m_pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
m_uiCurrRowDrn = (FLMUINT)my_get_ptr( pucPos, ref_length);
|
|
|
|
if( RC_BAD( rc = FlmRecordRetrieve( m_pConn->getDb(),
|
|
m_pShare->uiTableContainer,
|
|
m_uiCurrRowDrn, FO_EXACT, &pRec, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiLength = table->s->reclength;
|
|
if( RC_BAD( rc = pRec->getBinary( pRec->root(),
|
|
pucData, &uiLength)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pRec)
|
|
{
|
|
pRec->Release();
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Used to return information to the optimizer.
|
|
****************************************************************************/
|
|
void ha_flaim::info(
|
|
uint uiFlag)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
|
|
DBUG_ENTER( "ha_flaim::info");
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection( m_szDbPath, &m_pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pConn->retrieveRowCount(
|
|
m_pShare->uiTableContainer, &records)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
records = 2;
|
|
}
|
|
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Called whenever the server wishes to send a hint to the storage
|
|
engine.
|
|
****************************************************************************/
|
|
int ha_flaim::extra(
|
|
enum ha_extra_function eOperation)
|
|
{
|
|
DBUG_ENTER( "ha_flaim::extra");
|
|
DBUG_RETURN( 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
int ha_flaim::reset( void)
|
|
{
|
|
DBUG_ENTER( "ha_flaim::reset");
|
|
DBUG_RETURN( 0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Used to delete all rows in a table
|
|
****************************************************************************/
|
|
int ha_flaim::delete_all_rows( void)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmRecord * pRec = NULL;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
|
|
DBUG_ENTER( "ha_flaim::delete_all_rows");
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection(
|
|
m_szDbPath, &m_pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmRecordRetrieve( m_pConn->getDb(),
|
|
FLM_DICT_CONTAINER,
|
|
m_pShare->uiTableContainer, FO_EXACT, &pRec, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = FlmRecordDelete( m_pConn->getDb(),
|
|
FLM_DICT_CONTAINER,
|
|
m_pShare->uiTableContainer, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pRec->isReadOnly())
|
|
{
|
|
FlmRecord * pTmpRec;
|
|
|
|
if( (pTmpRec = pRec->copy()) == NULL)
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
pRec->Release();
|
|
pRec = pTmpRec;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmRecordAdd( m_pConn->getDb(),
|
|
FLM_DICT_CONTAINER,
|
|
&m_pShare->uiTableContainer, pRec, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = m_pConn->storeRowCount(
|
|
m_pShare->uiTableContainer, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
m_uiCurrRowDrn = 0;
|
|
|
|
Exit:
|
|
|
|
if( pRec)
|
|
{
|
|
pRec->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
m_pConn->setAbortFlag();
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
int ha_flaim::external_lock(
|
|
THD * pThread,
|
|
int iLockType)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMBOOL bDecLockCountOnError = FALSE;
|
|
|
|
DBUG_ENTER( "ha_flaim::external_lock");
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection(
|
|
m_szDbPath, &m_pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( iLockType != F_UNLCK)
|
|
{
|
|
if( iLockType == F_WRLCK &&
|
|
(m_pConn->getTransType() == FLM_READ_TRANS ||
|
|
m_pConn->getTransTypeNeeded() == FLM_READ_TRANS))
|
|
{
|
|
rc = (RCODE)HA_ERR_READ_ONLY_TRANSACTION;
|
|
goto Exit;
|
|
}
|
|
|
|
if( m_pConn->incLockCount() == 1 &&
|
|
m_pConn->getTransType() == FLM_NO_TRANS)
|
|
{
|
|
bDecLockCountOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = FlmDbTransBegin( m_pConn->getDb(),
|
|
m_pConn->getTransTypeNeeded(), FLM_NO_TIMEOUT)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
m_pConn->setTransTypeNeeded( FLM_NO_TRANS);
|
|
|
|
if( pThread->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))
|
|
{
|
|
trans_register_ha( pThread, TRUE, &flaim_hton);
|
|
|
|
// Since this transaction has been registered with
|
|
// MySQL, flaim_commit or flaim_rollback will be called
|
|
// when appropriate. To prevent external_unlock from
|
|
// releasing the transaction too soon, increment the
|
|
// lock count again. This allows us to handle the case
|
|
// of a multi-statement transaction.
|
|
|
|
m_pConn->incLockCount();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_lockData.type = TL_UNLOCK;
|
|
|
|
if( m_pConn->getLockCount() != 0 &&
|
|
m_pConn->decLockCount() == 0 &&
|
|
m_pConn->getTransType() != FLM_NO_TRANS)
|
|
{
|
|
if( m_pConn->getAbortFlag())
|
|
{
|
|
FlmDbTransAbort( m_pConn->getDb());
|
|
m_pConn->clearAbortFlag();
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = FlmDbTransCommit( m_pConn->getDb())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
if( bDecLockCountOnError)
|
|
{
|
|
m_pConn->decLockCount();
|
|
}
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
int flaim_start_trx_and_assign_read_view(
|
|
THD * pThread)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmConnection * pConn = NULL;
|
|
char szDbPath[ F_PATH_MAX_SIZE];
|
|
|
|
DBUG_ENTER( "flaim_start_trx_and_assign_read_view");
|
|
|
|
szDbPath[ 0] = 0;
|
|
f_pathAppend( szDbPath, ".");
|
|
f_pathAppend( szDbPath, pThread->db);
|
|
f_pathAppend( szDbPath, FLAIM_DB_NAME);
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection( szDbPath, &pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pConn->getLockCount() == 0 &&
|
|
pConn->getTransType() == FLM_NO_TRANS)
|
|
{
|
|
if( RC_BAD( rc = FlmDbTransBegin( pConn->getDb(),
|
|
FLM_READ_TRANS, FLM_NO_TIMEOUT)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pConn->setTransTypeNeeded( FLM_NO_TRANS);
|
|
trans_register_ha( pThread, TRUE, &flaim_hton);
|
|
pConn->incLockCount();
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pConn)
|
|
{
|
|
pConn->Release();
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
THR_LOCK_DATA ** ha_flaim::store_lock(
|
|
THD * pThread,
|
|
THR_LOCK_DATA ** pLockData,
|
|
enum thr_lock_type eLockType)
|
|
{
|
|
if( RC_BAD( gv_pConnTbl->getConnection(
|
|
m_szDbPath, &m_pConn)))
|
|
{
|
|
assert( 0);
|
|
}
|
|
|
|
if( eLockType != TL_IGNORE && m_lockData.type == TL_UNLOCK)
|
|
{
|
|
if( eLockType >= TL_WRITE_ALLOW_WRITE &&
|
|
eLockType <= TL_WRITE_ONLY)
|
|
{
|
|
eLockType = TL_WRITE_ALLOW_READ;
|
|
}
|
|
else if( eLockType >= TL_READ && eLockType <= TL_READ_NO_INSERT)
|
|
{
|
|
eLockType = TL_READ_HIGH_PRIORITY;
|
|
}
|
|
|
|
if( eLockType == TL_WRITE_ALLOW_READ ||
|
|
(pThread->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT)))
|
|
{
|
|
eLockType = TL_WRITE_ALLOW_READ;
|
|
if( m_pConn->getTransType() == FLM_NO_TRANS)
|
|
{
|
|
m_pConn->setTransTypeNeeded( FLM_UPDATE_TRANS);
|
|
}
|
|
}
|
|
else if( m_pConn->getTransTypeNeeded() == FLM_NO_TRANS)
|
|
{
|
|
eLockType = TL_READ_HIGH_PRIORITY;
|
|
if( m_pConn->getTransType() == FLM_NO_TRANS)
|
|
{
|
|
m_pConn->setTransTypeNeeded( FLM_READ_TRANS);
|
|
}
|
|
}
|
|
|
|
m_lockData.type = eLockType;
|
|
}
|
|
|
|
*pLockData++ = &m_lockData;
|
|
return( pLockData);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Renames a table
|
|
****************************************************************************/
|
|
int ha_flaim::rename_table(
|
|
const char * pszOldName,
|
|
const char * pszNewName)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMUINT uiDictNum;
|
|
F_NameTable nameTable;
|
|
FlmRecord * pDictRec = NULL;
|
|
char szOldPrefix[ F_PATH_MAX_SIZE];
|
|
char szNewPrefix[ F_PATH_MAX_SIZE];
|
|
char szTmpBuf[ F_PATH_MAX_SIZE];
|
|
char szNewName[ F_PATH_MAX_SIZE];
|
|
int iCmp;
|
|
FLMUINT uiOldPrefixLen;
|
|
FLMUINT uiNewPrefixLen;
|
|
FLMUINT uiLoop;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
|
|
DBUG_ENTER( "ha_flaim::rename_table");
|
|
|
|
buildDbPathFromTablePath( pszOldName, m_szDbPath);
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection(
|
|
m_szDbPath, &m_pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( m_pConn->getTransType() != FLM_UPDATE_TRANS)
|
|
{
|
|
if( RC_BAD( rc = FlmDbTransBegin( m_pConn->getDb(),
|
|
FLM_UPDATE_TRANS, FLM_NO_TIMEOUT)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartedTrans = TRUE;
|
|
}
|
|
|
|
if( RC_BAD( rc = nameTable.setupFromDb( m_pConn->getDb())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
f_pathReduce( pszOldName, NULL, szTmpBuf);
|
|
sprintf( szOldPrefix, ":%s:", szTmpBuf);
|
|
uiOldPrefixLen = strlen( szOldPrefix);
|
|
|
|
f_pathReduce( pszNewName, NULL, szTmpBuf);
|
|
sprintf( szNewPrefix, ":%s:", szTmpBuf);
|
|
uiNewPrefixLen = strlen( szNewPrefix);
|
|
|
|
// From this point forward, any errors must cause the
|
|
// transaction to abort
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
// Rename indexes, fields, and the table container
|
|
|
|
uiLoop = 0;
|
|
for( ;;)
|
|
{
|
|
if( !nameTable.getNextTagNameOrder( &uiLoop, NULL, szTmpBuf,
|
|
sizeof( szTmpBuf), &uiDictNum, NULL, NULL))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( (iCmp = strnicmp( szTmpBuf, szOldPrefix, uiOldPrefixLen)) > 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( iCmp == 0)
|
|
{
|
|
if( RC_BAD( rc = FlmRecordRetrieve( m_pConn->getDb(),
|
|
FLM_DICT_CONTAINER, uiDictNum, FO_EXACT, &pDictRec, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pDictRec->isReadOnly())
|
|
{
|
|
FlmRecord * pTmpRec;
|
|
|
|
if( (pTmpRec = pDictRec->copy()) == NULL)
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
pDictRec->Release();
|
|
pDictRec = pTmpRec;
|
|
}
|
|
|
|
sprintf( szNewName, "%s%s", szNewPrefix,
|
|
strchr( &szTmpBuf[ 1], ':') + 1);
|
|
|
|
if( RC_BAD( rc = pDictRec->setNative(
|
|
pDictRec->root(), szNewName)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmRecordModify( m_pConn->getDb(),
|
|
FLM_DICT_CONTAINER, uiDictNum, pDictRec, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = FlmDbTransCommit( m_pConn->getDb())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pDictRec)
|
|
{
|
|
pDictRec->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
m_pConn->setAbortFlag();
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
int ha_flaim::delete_table(
|
|
const char * pszTablePath)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMUINT uiDictNum;
|
|
F_NameTable nameTable;
|
|
FlmRecord * pDictRec = NULL;
|
|
char szPrefix[ F_PATH_MAX_SIZE];
|
|
char szTmpBuf[ F_PATH_MAX_SIZE];
|
|
int iCmp;
|
|
void * pvField;
|
|
FLMUINT uiPrefixLen;
|
|
FLMUINT uiLoop;
|
|
FLMUINT uiDefType;
|
|
FLMBOOL bSweep = FALSE;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
|
|
DBUG_ENTER( "ha_flaim::delete_table");
|
|
|
|
buildDbPathFromTablePath( pszTablePath, m_szDbPath);
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection(
|
|
m_szDbPath, &m_pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( m_pConn->getTransType() != FLM_UPDATE_TRANS)
|
|
{
|
|
if( RC_BAD( rc = FlmDbTransBegin( m_pConn->getDb(),
|
|
FLM_UPDATE_TRANS, FLM_NO_TIMEOUT)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartedTrans = TRUE;
|
|
}
|
|
|
|
if( RC_BAD( rc = nameTable.setupFromDb( m_pConn->getDb())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
f_pathReduce( pszTablePath, NULL, szTmpBuf);
|
|
sprintf( szPrefix, ":%s:", szTmpBuf);
|
|
uiPrefixLen = strlen( szPrefix);
|
|
|
|
// From this point forward, any errors must cause the
|
|
// transaction to abort
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
// Drop indexes and mark fields for deletion
|
|
|
|
uiLoop = 0;
|
|
for( ;;)
|
|
{
|
|
if( !nameTable.getNextTagNameOrder( &uiLoop, NULL, szTmpBuf,
|
|
sizeof( szTmpBuf), &uiDictNum, &uiDefType, NULL))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( (iCmp = strnicmp( szTmpBuf, szPrefix, uiPrefixLen)) > 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( iCmp == 0)
|
|
{
|
|
if( uiDefType == FLM_FIELD_TAG)
|
|
{
|
|
if( RC_BAD( rc = FlmRecordRetrieve( m_pConn->getDb(),
|
|
FLM_DICT_CONTAINER, uiDictNum, FO_EXACT, &pDictRec, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pDictRec->isReadOnly())
|
|
{
|
|
FlmRecord * pTmpRec;
|
|
|
|
if( (pTmpRec = pDictRec->copy()) == NULL)
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
pDictRec->Release();
|
|
pDictRec = pTmpRec;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDictRec->insertLast( 1, FLM_STATE_TAG,
|
|
FLM_TEXT_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDictRec->setNative( pvField, "purge")))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmRecordModify( m_pConn->getDb(),
|
|
FLM_DICT_CONTAINER, uiDictNum, pDictRec, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bSweep = TRUE;
|
|
}
|
|
else if( uiDefType == FLM_INDEX_TAG)
|
|
{
|
|
if( RC_BAD( rc = FlmRecordDelete( m_pConn->getDb(),
|
|
FLM_DICT_CONTAINER, uiDictNum, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Drop the table container
|
|
|
|
if( !nameTable.getFromTagTypeAndName( NULL, szPrefix,
|
|
FLM_CONTAINER_TAG, &uiDictNum))
|
|
{
|
|
rc = FERR_DATA_ERROR;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmRecordDelete( m_pConn->getDb(),
|
|
FLM_DICT_CONTAINER, uiDictNum, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Delete the table info record
|
|
|
|
if( RC_BAD( rc = FlmRecordDelete( m_pConn->getDb(),
|
|
FLM_DATA_CONTAINER, uiDictNum, 0)))
|
|
{
|
|
if( rc != FERR_NOT_FOUND)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
rc = FERR_OK;
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = FlmDbTransCommit( m_pConn->getDb())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( bSweep)
|
|
{
|
|
if( RC_BAD( rc = FlmDbSweep( m_pConn->getDb(),
|
|
SWEEP_PURGED_FLDS, 0, NULL, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pDictRec)
|
|
{
|
|
pDictRec->Release();
|
|
}
|
|
|
|
if( RC_BAD( rc) && bMustAbortOnError)
|
|
{
|
|
m_pConn->setAbortFlag();
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Given a starting key and an ending key, estimate the number of rows
|
|
that will exist between the two. The end key may be empty.
|
|
****************************************************************************/
|
|
ha_rows ha_flaim::records_in_range(
|
|
uint uiIndex,
|
|
key_range * pMinKey,
|
|
key_range * pMaxKey)
|
|
{
|
|
// VISIT: Implement
|
|
DBUG_ENTER( "ha_flaim::records_in_range");
|
|
DBUG_RETURN( 2);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Called to create a database and/or table.
|
|
****************************************************************************/
|
|
int ha_flaim::create(
|
|
const char * pszFormFilePath,
|
|
TABLE * pTable,
|
|
HA_CREATE_INFO * pCreateInfo)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmRecord * pRec = NULL;
|
|
void * pvField;
|
|
char szTmpBuf[ 512];
|
|
FLMUINT uiTableDefId;
|
|
FLMUINT uiLoop;
|
|
FLMUINT uiLastDrnUsed = 0;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMBOOL bMustAbortOnError = FALSE;
|
|
FLMBOOL bCreatedDatabase = FALSE;
|
|
|
|
DBUG_ENTER( "ha_flaim::create");
|
|
|
|
Retry:
|
|
|
|
f_pathReduce( pszFormFilePath, m_szDbPath, NULL);
|
|
f_pathAppend( m_szDbPath, FLAIM_DB_NAME);
|
|
|
|
assert( m_pConn == NULL);
|
|
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection( m_szDbPath, &m_pConn)))
|
|
{
|
|
if( rc == FERR_IO_PATH_NOT_FOUND)
|
|
{
|
|
if( RC_BAD( rc = FlmDbCreate( m_szDbPath, NULL, NULL, NULL,
|
|
gv_pszBaseDict, NULL, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bCreatedDatabase = TRUE;
|
|
}
|
|
|
|
goto Retry;
|
|
}
|
|
|
|
if( pTable && pTable->s->table_name)
|
|
{
|
|
if( m_pConn->getTransType() != FLM_UPDATE_TRANS)
|
|
{
|
|
if( RC_BAD( rc = FlmDbTransBegin( m_pConn->getDb(),
|
|
FLM_UPDATE_TRANS, FLM_NO_TIMEOUT)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bStartedTrans = TRUE;
|
|
}
|
|
|
|
// Create the table container
|
|
|
|
if( (pRec = new FlmRecord) == NULL)
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->insertLast( 0, FLM_CONTAINER_TAG,
|
|
FLM_TEXT_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
sprintf( szTmpBuf, ":%s:", pTable->s->table_name);
|
|
|
|
if( RC_BAD( rc = pRec->setNative( pvField, szTmpBuf)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bMustAbortOnError = TRUE;
|
|
|
|
if( RC_BAD( rc = FlmFindUnusedDictDrn( m_pConn->getDb(),
|
|
uiLastDrnUsed, FLM_RESERVED_TAG_NUMS - 1, &uiLastDrnUsed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiTableDefId = uiLastDrnUsed;
|
|
|
|
if( RC_BAD( rc = FlmRecordAdd( m_pConn->getDb(),
|
|
FLM_DICT_CONTAINER, &uiTableDefId, pRec, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pRec->Release();
|
|
|
|
// Create the table column fields
|
|
|
|
for( Field ** ppField = table->field; *ppField; ppField++)
|
|
{
|
|
if( (pRec = new FlmRecord) == NULL)
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->insertLast( 0, FLM_FIELD_TAG,
|
|
FLM_TEXT_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
sprintf( szTmpBuf, ":%s:col:%s:", pTable->s->table_name,
|
|
(*ppField)->field_name);
|
|
|
|
if( RC_BAD( rc = pRec->setNative( pvField, szTmpBuf)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->insertLast( 1, FLM_TYPE_TAG,
|
|
FLM_TEXT_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
switch( (*ppField)->type())
|
|
{
|
|
case MYSQL_TYPE_VARCHAR:
|
|
case MYSQL_TYPE_VAR_STRING:
|
|
case MYSQL_TYPE_STRING:
|
|
case MYSQL_TYPE_DECIMAL:
|
|
{
|
|
if( RC_BAD( rc = pRec->setNative( pvField, "text")))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case MYSQL_TYPE_TINY:
|
|
case MYSQL_TYPE_SHORT:
|
|
case MYSQL_TYPE_LONG:
|
|
case MYSQL_TYPE_INT24:
|
|
case MYSQL_TYPE_DATE:
|
|
case MYSQL_TYPE_TIME:
|
|
case MYSQL_TYPE_TIMESTAMP:
|
|
case MYSQL_TYPE_YEAR:
|
|
case MYSQL_TYPE_NEWDATE:
|
|
{
|
|
if( RC_BAD( rc = pRec->setNative( pvField, "number")))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case MYSQL_TYPE_FLOAT:
|
|
case MYSQL_TYPE_DOUBLE:
|
|
case MYSQL_TYPE_NULL:
|
|
case MYSQL_TYPE_LONGLONG:
|
|
case MYSQL_TYPE_DATETIME:
|
|
case MYSQL_TYPE_BIT:
|
|
case MYSQL_TYPE_NEWDECIMAL:
|
|
case MYSQL_TYPE_ENUM:
|
|
case MYSQL_TYPE_SET:
|
|
case MYSQL_TYPE_TINY_BLOB:
|
|
case MYSQL_TYPE_MEDIUM_BLOB:
|
|
case MYSQL_TYPE_LONG_BLOB:
|
|
case MYSQL_TYPE_BLOB:
|
|
case MYSQL_TYPE_GEOMETRY:
|
|
{
|
|
if( RC_BAD( rc = pRec->setNative( pvField, "binary")))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
assert( 0);
|
|
rc = FERR_NOT_IMPLEMENTED;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmFindUnusedDictDrn( m_pConn->getDb(),
|
|
uiLastDrnUsed, FLM_RESERVED_TAG_NUMS - 1, &uiLastDrnUsed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmRecordAdd( m_pConn->getDb(),
|
|
FLM_DICT_CONTAINER, &uiLastDrnUsed, pRec, 0)))
|
|
{
|
|
if( rc != FERR_DUPLICATE_DICT_NAME)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
rc = FERR_OK;
|
|
}
|
|
}
|
|
|
|
// Create the table key fields
|
|
|
|
for( uiLoop = 0; uiLoop < pTable->s->keys; uiLoop++)
|
|
{
|
|
KEY * pKey = table->key_info + uiLoop;
|
|
FLMUINT uiKeyField;
|
|
|
|
if( (pRec = new FlmRecord) == NULL)
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->insertLast( 0, FLM_FIELD_TAG,
|
|
FLM_TEXT_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
sprintf( szTmpBuf, ":%s:key:%u:", pTable->s->table_name, uiLoop);
|
|
|
|
if( RC_BAD( rc = pRec->setNative( pvField, szTmpBuf)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->insertLast( 1, FLM_TYPE_TAG,
|
|
FLM_TEXT_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->setNative( pvField, "binary")))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmFindUnusedDictDrn( m_pConn->getDb(),
|
|
uiLastDrnUsed, FLM_RESERVED_TAG_NUMS - 1, &uiLastDrnUsed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiKeyField = uiLastDrnUsed;
|
|
|
|
if( RC_BAD( rc = FlmRecordAdd( m_pConn->getDb(),
|
|
FLM_DICT_CONTAINER, &uiKeyField, pRec, 0)))
|
|
{
|
|
if( rc != FERR_DUPLICATE_DICT_NAME)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
rc = FERR_OK;
|
|
}
|
|
|
|
pRec->Release();
|
|
pRec = NULL;
|
|
|
|
// Add the index
|
|
|
|
if( (pRec = new FlmRecord) == NULL)
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->insertLast( 0, FLM_INDEX_TAG,
|
|
FLM_TEXT_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
sprintf( szTmpBuf, ":%s:index:%u:", pTable->s->table_name, uiLoop);
|
|
|
|
if( RC_BAD( rc = pRec->setNative( pvField, szTmpBuf)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->insertLast( 1, FLM_CONTAINER_TAG,
|
|
FLM_TEXT_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
sprintf( szTmpBuf, "%u", uiTableDefId);
|
|
|
|
if( RC_BAD( rc = pRec->setNative( pvField, szTmpBuf)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->insertLast( 1, FLM_KEY_TAG,
|
|
FLM_TEXT_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (pKey->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
|
|
{
|
|
if( RC_BAD( rc = pRec->insertLast( 2, FLM_UNIQUE_TAG,
|
|
FLM_TEXT_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->insertLast( 2, FLM_FIELD_TAG,
|
|
FLM_TEXT_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
sprintf( szTmpBuf, "%u", uiKeyField);
|
|
|
|
if( RC_BAD( rc = pRec->setNative( pvField, szTmpBuf)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmFindUnusedDictDrn( m_pConn->getDb(),
|
|
uiLastDrnUsed, FLM_RESERVED_TAG_NUMS - 1, &uiLastDrnUsed)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmRecordAdd( m_pConn->getDb(),
|
|
FLM_DICT_CONTAINER, &uiLastDrnUsed, pRec, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pRec->Release();
|
|
pRec = NULL;
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
bStartedTrans = FALSE;
|
|
|
|
if( RC_BAD( rc = FlmDbTransCommit( m_pConn->getDb())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pRec)
|
|
{
|
|
pRec->Release();
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
FlmDbTransAbort( m_pConn->getDb());
|
|
bMustAbortOnError = FALSE;
|
|
}
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
if( bMustAbortOnError)
|
|
{
|
|
assert( !bCreatedDatabase);
|
|
m_pConn->setAbortFlag();
|
|
}
|
|
|
|
if( bCreatedDatabase)
|
|
{
|
|
FlmDbRemove( m_szDbPath, NULL, NULL, TRUE);
|
|
}
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE ha_flaim::importRowFromRec(
|
|
FlmRecord * pRec,
|
|
FLMBYTE * pucData)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
Field ** ppMyField;
|
|
void * pvField;
|
|
FLMUINT uiLength;
|
|
FIELD_INFO * pColumnFields = m_pShare->pColumnFields;
|
|
FLMBYTE * pucAllocBuf = NULL;
|
|
|
|
pvField = pRec->firstChild( pRec->root());
|
|
|
|
// Import NULL bitmap
|
|
|
|
if( (uiLength = table->s->null_bytes) != 0)
|
|
{
|
|
if( (pvField = pRec->find( pvField,
|
|
FLM_ROW_NULL_BITS_FIELD_ID)) == NULL)
|
|
{
|
|
rc = FERR_DATA_ERROR;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->getBinary( pvField, pucData, &uiLength)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Import each column's data
|
|
|
|
for( ppMyField = table->field; *ppMyField; ppMyField++)
|
|
{
|
|
if( !isFieldNull( table, *ppMyField, (const char *)pucData))
|
|
{
|
|
FIELD_INFO * pFieldInfo = &pColumnFields[ (*ppMyField)->field_index];
|
|
char * pucFieldData = (char *)(pucData + (*ppMyField)->offset());
|
|
|
|
if( (pvField = pRec->find( pvField, pFieldInfo->uiDictNum)) == NULL)
|
|
{
|
|
rc = FERR_DATA_ERROR;
|
|
goto Exit;
|
|
}
|
|
|
|
switch( pFieldInfo->uiDataType)
|
|
{
|
|
case FLM_TEXT_TYPE:
|
|
{
|
|
FLMUNICODE uzTmpBuf[ 256];
|
|
FLMUNICODE * puzStr = uzTmpBuf;
|
|
FLMUINT uiStrLen;
|
|
|
|
uiStrLen = sizeof( uzTmpBuf);
|
|
if( RC_BAD( rc = pRec->getUnicode( pvField, uzTmpBuf, &uiStrLen)))
|
|
{
|
|
if( rc != FERR_CONV_DEST_OVERFLOW)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->getUnicode( pvField, NULL, &uiStrLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !my_multi_malloc( MYF( MY_WME), &pucAllocBuf, uiStrLen + 2, NullS))
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
uiStrLen += 2;
|
|
|
|
if( RC_BAD( rc = pRec->getUnicode( pvField,
|
|
(FLMUNICODE *)pucAllocBuf, &uiStrLen)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
puzStr = (FLMUNICODE *)pucAllocBuf;
|
|
}
|
|
|
|
#ifndef WORDS_BIGENDIAN
|
|
{
|
|
FLMUNICODE * puzTmp = puzStr;
|
|
|
|
while( *puzTmp)
|
|
{
|
|
*puzTmp++ = (*puzTmp >> 8) | (*puzTmp << 8);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
String tmpStr( (const char *)puzStr, uiStrLen, &my_charset_ucs2_bin);
|
|
|
|
if( convertString( &tmpStr, &my_charset_ucs2_bin, (*ppMyField)->charset()))
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
uiStrLen = tmpStr.length();
|
|
|
|
switch( (*ppMyField)->type())
|
|
{
|
|
case MYSQL_TYPE_STRING:
|
|
case MYSQL_TYPE_VAR_STRING:
|
|
case MYSQL_TYPE_DECIMAL:
|
|
{
|
|
memcpy( pucFieldData, tmpStr.ptr(), uiStrLen);
|
|
break;
|
|
}
|
|
|
|
case MYSQL_TYPE_VARCHAR:
|
|
{
|
|
if( ((Field_varstring *)(*ppMyField))->length_bytes == 1)
|
|
{
|
|
*pucFieldData++ = (uchar)uiStrLen;
|
|
}
|
|
else
|
|
{
|
|
int2store( pucFieldData, tmpStr.length());
|
|
pucFieldData += 2;
|
|
}
|
|
|
|
memcpy( pucFieldData, tmpStr.ptr(), uiStrLen);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
assert( 0);
|
|
rc = FERR_NOT_IMPLEMENTED;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case FLM_NUMBER_TYPE:
|
|
{
|
|
longlong i64Val;
|
|
|
|
if( (*ppMyField)->flags & UNSIGNED_FLAG)
|
|
{
|
|
FLMUINT uiVal;
|
|
|
|
if( RC_BAD( rc = pRec->getUINT( pvField, &uiVal)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
i64Val = (longlong)uiVal;
|
|
}
|
|
else
|
|
{
|
|
FLMINT iVal;
|
|
|
|
if( RC_BAD( rc = pRec->getINT( pvField, &iVal)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
i64Val = (longlong)iVal;
|
|
}
|
|
|
|
switch( (*ppMyField)->type())
|
|
{
|
|
case MYSQL_TYPE_TINY:
|
|
case MYSQL_TYPE_YEAR:
|
|
{
|
|
*pucFieldData = (char)i64Val;
|
|
break;
|
|
}
|
|
|
|
case MYSQL_TYPE_SHORT:
|
|
{
|
|
#ifdef WORDS_BIGENDIAN
|
|
if( table->s->db_low_byte_first)
|
|
{
|
|
int2store( pucFieldData, i64Val);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
shortstore( pucFieldData, i64Val);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case MYSQL_TYPE_INT24:
|
|
case MYSQL_TYPE_TIME:
|
|
case MYSQL_TYPE_NEWDATE:
|
|
{
|
|
int3store( pucFieldData, i64Val);
|
|
break;
|
|
}
|
|
|
|
case MYSQL_TYPE_LONG:
|
|
case MYSQL_TYPE_DATE:
|
|
case MYSQL_TYPE_TIMESTAMP:
|
|
{
|
|
#ifdef WORDS_BIGENDIAN
|
|
if( table->s->db_low_byte_first)
|
|
{
|
|
int4store( pucFieldData, i64Val);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
longstore( pucFieldData, i64Val);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
assert( 0);
|
|
rc = FERR_NOT_IMPLEMENTED;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case FLM_BINARY_TYPE:
|
|
{
|
|
(*ppMyField)->unpack( pucFieldData,
|
|
(const char *)(pRec->getDataPtr( pvField)));
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
assert( 0);
|
|
rc = FERR_NOT_IMPLEMENTED;
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pucAllocBuf)
|
|
{
|
|
my_free( (gptr)pucAllocBuf, MYF(0));
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE ha_flaim::exportRowToRec(
|
|
FLMBYTE * pucData,
|
|
FlmRecord ** ppRec)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMUINT uiLoop;
|
|
FlmRecord * pRec = NULL;
|
|
Field ** ppMyField;
|
|
void * pvField;
|
|
FIELD_INFO * pColumnFields = m_pShare->pColumnFields;
|
|
FIELD_INFO * pKeyFields = m_pShare->pKeyFields;
|
|
|
|
assert( *ppRec == NULL);
|
|
|
|
if( (pRec = new FlmRecord) == NULL)
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->insertLast( 0,
|
|
FLM_ROW_CONTEXT_FIELD_ID, FLM_CONTEXT_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Store NULL bitmap
|
|
|
|
if( table->s->null_bytes)
|
|
{
|
|
if( RC_BAD( rc = pRec->insertLast( 1,
|
|
FLM_ROW_NULL_BITS_FIELD_ID, FLM_BINARY_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->setBinary( pvField,
|
|
pucData, table->s->null_bytes)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Store each column's data
|
|
|
|
for( ppMyField = table->field; *ppMyField; ppMyField++)
|
|
{
|
|
if( !isFieldNull( table, *ppMyField, (const char *)pucData))
|
|
{
|
|
FIELD_INFO * pFieldInfo = &pColumnFields[ (*ppMyField)->field_index];
|
|
|
|
if( RC_BAD( rc = pRec->insertLast( 1,
|
|
pFieldInfo->uiDictNum, pFieldInfo->uiDataType, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
switch( pFieldInfo->uiDataType)
|
|
{
|
|
case FLM_TEXT_TYPE:
|
|
{
|
|
String tmpStr;
|
|
|
|
(*ppMyField)->val_str( &tmpStr);
|
|
|
|
if( convertString( &tmpStr, (*ppMyField)->charset(),
|
|
&my_charset_ucs2_bin))
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
if( tmpStr.append( "\0\0", 2, &my_charset_ucs2_bin))
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
// FLAIM expects the Unicode string to have the
|
|
// same endian order as the host platform. MySQL
|
|
// always represents Unicode as big endian. Thus,
|
|
// we need to do some byte swapping if we are on
|
|
// a little-endian platform.
|
|
|
|
#ifndef WORDS_BIGENDIAN
|
|
{
|
|
FLMUNICODE * puzTmp = (FLMUNICODE *)tmpStr.ptr();
|
|
|
|
while( *puzTmp)
|
|
{
|
|
*puzTmp++ = (*puzTmp >> 8) | (*puzTmp << 8);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if( RC_BAD( rc = pRec->setUnicode( pvField,
|
|
(FLMUNICODE *)tmpStr.ptr())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case FLM_NUMBER_TYPE:
|
|
{
|
|
longlong iNum = (*ppMyField)->val_int();
|
|
|
|
if( (*ppMyField)->flags & UNSIGNED_FLAG)
|
|
{
|
|
if( RC_BAD( rc = pRec->setUINT( pvField, (FLMUINT)iNum)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = pRec->setINT( pvField, (FLMINT)iNum)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case FLM_BINARY_TYPE:
|
|
{
|
|
if( RC_BAD( rc = pRec->setBinary( pvField,
|
|
&pucData[ (*ppMyField)->offset()],
|
|
(*ppMyField)->packed_col_length(
|
|
(const char *)&pucData[ (*ppMyField)->offset()],
|
|
(*ppMyField)->pack_length()))))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
assert( 0);
|
|
rc = FERR_NOT_IMPLEMENTED;
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Store the row's keys
|
|
|
|
for( uiLoop = 0; uiLoop < table->s->keys; uiLoop++)
|
|
{
|
|
if( RC_BAD( rc = exportKeyToRec( uiLoop, pucData, pRec)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
*ppRec = pRec;
|
|
pRec = NULL;
|
|
|
|
Exit:
|
|
|
|
if( pRec)
|
|
{
|
|
pRec->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE ha_flaim::exportKeyToTree(
|
|
FLMUINT uiIndexOffset,
|
|
const byte * pucKey,
|
|
FLMUINT uiKeyLen,
|
|
FlmRecord ** ppKeyTree)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
char * pucBuf = m_pucKeyBuf;
|
|
char * pucBufEnd = &m_pucKeyBuf[ FLM_MAX_KEY_LENGTH];
|
|
FlmRecord * pKeyTree = NULL;
|
|
void * pvField;
|
|
KEY * pKey = table->key_info + uiIndexOffset;
|
|
KEY_PART_INFO * pCurKeyPart = pKey->key_part;
|
|
KEY_PART_INFO * pEndKeyPart = pCurKeyPart + pKey->key_parts;
|
|
|
|
DBUG_ENTER( "ha_flaim::exportKeyToTree");
|
|
|
|
assert( *ppKeyTree == NULL);
|
|
|
|
if( (pKeyTree = new FlmRecord) == NULL)
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pKeyTree->insertLast( 0,
|
|
FLM_KEY_TAG, FLM_CONTEXT_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pKeyTree->insertLast( 1,
|
|
m_pShare->pKeyFields[ uiIndexOffset].uiDictNum,
|
|
FLM_BINARY_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
for( ; pCurKeyPart != pEndKeyPart && uiKeyLen > 0; pCurKeyPart++)
|
|
{
|
|
FLMUINT uiOffset = 0;
|
|
|
|
if( pCurKeyPart->null_bit)
|
|
{
|
|
*pucBuf++ = *pucKey ? 1 : 0;
|
|
uiKeyLen -= pCurKeyPart->store_length;
|
|
pucKey += pCurKeyPart->store_length;
|
|
uiOffset = 1;
|
|
}
|
|
|
|
pucBuf = pCurKeyPart->field->pack_key_from_key_image( pucBuf,
|
|
(const char *)pucKey + uiOffset, pCurKeyPart->length);
|
|
pucKey += pCurKeyPart->store_length;
|
|
uiKeyLen -= pCurKeyPart->store_length;
|
|
|
|
assert( pucBuf <= pucBufEnd);
|
|
}
|
|
|
|
if( RC_BAD( rc = pKeyTree->setBinary( pvField, m_pucKeyBuf,
|
|
pucBuf - m_pucKeyBuf)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
*ppKeyTree = pKeyTree;
|
|
pKeyTree = NULL;
|
|
|
|
Exit:
|
|
|
|
if( pKeyTree)
|
|
{
|
|
pKeyTree->Release();
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FlmConnectionTable::getConnection(
|
|
const char * pszDbPath,
|
|
FlmConnection ** ppConnection)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
HFDB hDb = HFDB_NULL;
|
|
FlmConnection * pConn = NULL;
|
|
FLMUINT uiThreadId = my_thread_id();
|
|
FLMBOOL bMutexLocked = FALSE;
|
|
|
|
if( *ppConnection)
|
|
{
|
|
if( (*ppConnection)->getThreadId() == uiThreadId)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
(*ppConnection)->Release();
|
|
*ppConnection = NULL;
|
|
}
|
|
|
|
// Search the connection list for an existing connection
|
|
|
|
pthread_mutex_lock( &m_hMutex);
|
|
bMutexLocked = TRUE;
|
|
|
|
pConn = m_pConnList;
|
|
while( pConn)
|
|
{
|
|
if( pConn->getThreadId() == uiThreadId)
|
|
{
|
|
break;
|
|
}
|
|
|
|
pConn = pConn->getNext();
|
|
}
|
|
|
|
if( pConn)
|
|
{
|
|
// VISIT: Add debug code to make sure this thread
|
|
// is still accessing the same database as the last
|
|
// time this connection was used.
|
|
|
|
pConn->AddRef();
|
|
*ppConnection = pConn;
|
|
pConn = NULL;
|
|
goto Exit;
|
|
}
|
|
|
|
pthread_mutex_unlock( &m_hMutex);
|
|
bMutexLocked = FALSE;
|
|
|
|
if( !pszDbPath)
|
|
{
|
|
rc = FERR_ILLEGAL_OP;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FlmDbOpen( pszDbPath, NULL, NULL, 0, NULL, &hDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (pConn = new FlmConnection( gv_pConnTbl)) == NULL)
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
pConn->setThreadId( uiThreadId);
|
|
pConn->setDb( hDb);
|
|
hDb = HFDB_NULL;
|
|
|
|
pthread_mutex_lock( &m_hMutex);
|
|
bMutexLocked = TRUE;
|
|
|
|
if( (pConn->m_pNext = m_pConnList) != NULL)
|
|
{
|
|
pConn->m_pNext->m_pPrev = pConn;
|
|
}
|
|
|
|
m_pConnList = pConn;
|
|
m_pConnList->AddRef();
|
|
*ppConnection = pConn;
|
|
pConn = NULL;
|
|
|
|
Exit:
|
|
|
|
if( pConn)
|
|
{
|
|
pConn->Release();
|
|
}
|
|
|
|
if( bMutexLocked)
|
|
{
|
|
pthread_mutex_unlock( &m_hMutex);
|
|
}
|
|
|
|
if( hDb != HFDB_NULL)
|
|
{
|
|
FlmDbClose( &hDb);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FlmConnectionTable::setup( void)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
|
|
if( pthread_mutex_init( &m_hMutex, MY_MUTEX_INIT_FAST))
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
m_bFreeMutex = TRUE;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FLMUINT FlmConnection::Release(
|
|
FLMBOOL bMutexLocked)
|
|
{
|
|
FLMUINT uiRefCount = --m_ui32RefCnt;
|
|
|
|
if( uiRefCount == 1)
|
|
{
|
|
m_pConnTbl->closeConnection( this, bMutexLocked);
|
|
delete this;
|
|
}
|
|
|
|
return( uiRefCount);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FlmConnectionTable::closeConnection(
|
|
FlmConnection * pConn,
|
|
FLMBOOL bMutexLocked)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMBOOL bLastConnection = FALSE;
|
|
|
|
if( !bMutexLocked)
|
|
{
|
|
lockMutex();
|
|
}
|
|
|
|
if( pConn->m_pPrev)
|
|
{
|
|
pConn->m_pPrev->m_pNext = pConn->m_pNext;
|
|
}
|
|
else
|
|
{
|
|
if( (m_pConnList = pConn->m_pNext) == NULL)
|
|
{
|
|
bLastConnection = TRUE;
|
|
}
|
|
}
|
|
|
|
if( pConn->m_pNext)
|
|
{
|
|
pConn->m_pNext->m_pPrev = pConn->m_pPrev;
|
|
}
|
|
|
|
if( !bMutexLocked)
|
|
{
|
|
unlockMutex();
|
|
}
|
|
|
|
if( pConn->m_hDb != HFDB_NULL)
|
|
{
|
|
FLMBYTE szDbPath[ F_PATH_MAX_SIZE];
|
|
|
|
szDbPath[ 0] = 0;
|
|
|
|
if( bLastConnection)
|
|
{
|
|
if( RC_BAD( FlmDbGetConfig( pConn->m_hDb, FDB_GET_PATH, szDbPath)))
|
|
{
|
|
szDbPath[ 0] = 0;
|
|
}
|
|
}
|
|
|
|
FlmDbClose( &pConn->m_hDb);
|
|
|
|
if( szDbPath[ 0])
|
|
{
|
|
FlmConfig( FLM_CLOSE_FILE, szDbPath, NULL);
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FlmConnection::FlmConnection( FlmConnectionTable * pConnTbl)
|
|
{
|
|
m_uiThreadId = 0;
|
|
m_hDb = HFDB_NULL;
|
|
m_pPrev = NULL;
|
|
m_pNext = NULL;
|
|
m_bAbortFlag = FALSE;
|
|
|
|
m_uiLockCount = 0;
|
|
m_uiTransTypeNeeded = FLM_NO_TRANS;
|
|
|
|
m_pConnTbl = pConnTbl;
|
|
m_pConnTbl->AddRef();
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
FlmConnection::~FlmConnection()
|
|
{
|
|
assert( !m_pPrev);
|
|
assert( !m_pNext);
|
|
|
|
if( m_hDb != HFDB_NULL)
|
|
{
|
|
FlmDbClose( &m_hDb);
|
|
}
|
|
|
|
if( m_pConnTbl)
|
|
{
|
|
m_pConnTbl->Release();
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
static int flaim_commit(
|
|
THD * pThread,
|
|
bool bAll)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmConnection * pConn = NULL;
|
|
|
|
DBUG_ENTER( "flaim_commit");
|
|
|
|
if( bAll)
|
|
{
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection(
|
|
NULL, &pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
assert( pConn->getTransType() == FLM_UPDATE_TRANS);
|
|
|
|
if( pConn->getTransType() != FLM_NO_TRANS)
|
|
{
|
|
assert( pConn->getLockCount() == 1);
|
|
|
|
pConn->setLockCount( 0);
|
|
pConn->setTransTypeNeeded( FLM_NO_TRANS);
|
|
|
|
if( RC_BAD( rc = FlmDbTransCommit( pConn->getDb())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pConn)
|
|
{
|
|
pConn->Release();
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
static int flaim_rollback(
|
|
THD * pThread,
|
|
bool bAll)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmConnection * pConn = NULL;
|
|
|
|
DBUG_ENTER( "flaim_rollback");
|
|
|
|
if( bAll)
|
|
{
|
|
if( RC_BAD( rc = gv_pConnTbl->getConnection(
|
|
NULL, &pConn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
assert( pConn->getTransType() == FLM_UPDATE_TRANS);
|
|
|
|
if( pConn->getTransType() != FLM_NO_TRANS)
|
|
{
|
|
assert( pConn->getLockCount() == 1);
|
|
|
|
pConn->setLockCount( 0);
|
|
pConn->setTransTypeNeeded( FLM_NO_TRANS);
|
|
|
|
if( RC_BAD( rc = FlmDbTransAbort( pConn->getDb())))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pConn)
|
|
{
|
|
pConn->Release();
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FlmConnection::storeRowCount(
|
|
FLMUINT uiTableId,
|
|
FLMUINT uiRowCount)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmRecord * pRec = NULL;
|
|
void * pvField;
|
|
FLMBOOL bAddNewRec = FALSE;
|
|
|
|
if( RC_BAD( rc = FlmRecordRetrieve( m_hDb, FLM_DATA_CONTAINER,
|
|
uiTableId, FO_EXACT, &pRec, NULL)))
|
|
{
|
|
if( rc != FERR_NOT_FOUND)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( (pRec = new FlmRecord) == NULL)
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->insertLast( 0, FLM_TABLE_INFO_FIELD_ID,
|
|
FLM_CONTEXT_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
bAddNewRec = TRUE;
|
|
}
|
|
|
|
if( pRec->isReadOnly())
|
|
{
|
|
FlmRecord * pTmpRec;
|
|
|
|
if( (pTmpRec = pRec->copy()) == NULL)
|
|
{
|
|
rc = FERR_MEM;
|
|
goto Exit;
|
|
}
|
|
|
|
pRec->Release();
|
|
pRec = pTmpRec;
|
|
}
|
|
|
|
if( (pvField = pRec->find( pRec->root(), FLM_ROW_COUNT_FIELD_ID)) == NULL)
|
|
{
|
|
if( RC_BAD( rc = pRec->insertLast( 1, FLM_ROW_COUNT_FIELD_ID,
|
|
FLM_NUMBER_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->setUINT( pvField, uiRowCount)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !bAddNewRec)
|
|
{
|
|
if( RC_BAD( rc = FlmRecordModify( m_hDb,
|
|
FLM_DATA_CONTAINER, uiTableId, pRec, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( RC_BAD( rc = FlmRecordAdd( m_hDb,
|
|
FLM_DATA_CONTAINER, &uiTableId, pRec, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pRec)
|
|
{
|
|
pRec->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FlmConnection::retrieveRowCount(
|
|
FLMUINT uiTableId,
|
|
FLMUINT * puiRowCount)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmRecord * pRec = NULL;
|
|
void * pvField;
|
|
|
|
*puiRowCount = 0;
|
|
|
|
if( RC_BAD( rc = FlmRecordRetrieve( m_hDb, FLM_DATA_CONTAINER,
|
|
uiTableId, FO_EXACT, &pRec, NULL)))
|
|
{
|
|
if( rc == FERR_NOT_FOUND)
|
|
{
|
|
rc = FERR_OK;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
if( (pvField = pRec->find( pRec->root(), FLM_ROW_COUNT_FIELD_ID)) != NULL)
|
|
{
|
|
if( RC_BAD( rc = pRec->getUINT( pvField, puiRowCount)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pRec)
|
|
{
|
|
pRec->Release();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FlmConnection::incrementRowCount(
|
|
FLMUINT uiTableId)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMUINT uiRowCount;
|
|
|
|
if( RC_BAD( rc = retrieveRowCount( uiTableId, &uiRowCount)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = storeRowCount( uiTableId, uiRowCount + 1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE FlmConnection::decrementRowCount(
|
|
FLMUINT uiTableId)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMUINT uiRowCount;
|
|
|
|
if( RC_BAD( rc = retrieveRowCount( uiTableId, &uiRowCount)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( !uiRowCount)
|
|
{
|
|
rc = FERR_ILLEGAL_OP;
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = storeRowCount( uiTableId, uiRowCount - 1)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
RCODE ha_flaim::exportKeyToRec(
|
|
uint uiKeyNum,
|
|
const byte * pucRecord,
|
|
FlmRecord * pRec)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
char * pucBuf = m_pucKeyBuf;
|
|
char * pucBufEnd = &m_pucKeyBuf[ FLM_MAX_KEY_LENGTH];
|
|
FIELD_INFO * pKeyFields = m_pShare->pKeyFields;
|
|
void * pvField;
|
|
KEY * pKey = table->key_info + uiKeyNum;
|
|
KEY_PART_INFO * pCurKeyPart = pKey->key_part;
|
|
KEY_PART_INFO * pEndKeyPart = pCurKeyPart + pKey->key_parts;
|
|
|
|
DBUG_ENTER( "ha_flaim::exportKeyToRec");
|
|
|
|
for( ; pCurKeyPart != pEndKeyPart && pucBuf < pucBufEnd; pCurKeyPart++)
|
|
{
|
|
if( pCurKeyPart->null_bit)
|
|
{
|
|
// Store 0 if the key part is a NULL part
|
|
|
|
if( pucRecord[ pCurKeyPart->null_offset] & pCurKeyPart->null_bit)
|
|
{
|
|
*pucBuf++ = 0;
|
|
continue;
|
|
}
|
|
|
|
// Store NOT NULL marker
|
|
|
|
*pucBuf++ = 1;
|
|
}
|
|
|
|
pucBuf = pCurKeyPart->field->pack_key( pucBuf,
|
|
(const char *)(pucRecord + pCurKeyPart->offset),
|
|
pCurKeyPart->length);
|
|
|
|
assert( pucBuf <= pucBufEnd);
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->insertLast( 1,
|
|
pKeyFields[ uiKeyNum].uiDictNum, FLM_BINARY_TYPE, &pvField)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pRec->setBinary( pvField, m_pucKeyBuf, pucBuf - m_pucKeyBuf)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
bool ha_flaim::convertString(
|
|
String * pString,
|
|
CHARSET_INFO * pFromCharSet,
|
|
CHARSET_INFO * pToCharSet)
|
|
{
|
|
uint dummy_errors;
|
|
|
|
if( m_convertBuffer.copy( pString->ptr(), pString->length(),
|
|
pFromCharSet, pToCharSet, &dummy_errors))
|
|
{
|
|
return( true);
|
|
}
|
|
|
|
if( m_convertBuffer.alloced_length() >= m_convertBuffer.length() * 2 ||
|
|
!pString->is_alloced())
|
|
{
|
|
return( pString->copy( m_convertBuffer));
|
|
}
|
|
|
|
pString->swap( m_convertBuffer);
|
|
return( false);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc:
|
|
****************************************************************************/
|
|
int ha_flaim::check(
|
|
THD * pThread,
|
|
HA_CHECK_OPT * pCheckOpt)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
char szDbPath[ F_PATH_MAX_SIZE];
|
|
|
|
DBUG_ENTER( "ha_flaim::check");
|
|
|
|
szDbPath[ 0] = 0;
|
|
f_pathAppend( szDbPath, ".");
|
|
f_pathAppend( szDbPath, pThread->db);
|
|
f_pathAppend( szDbPath, FLAIM_DB_NAME);
|
|
|
|
if( RC_BAD( rc = FlmDbCheck( NULL, szDbPath, NULL,
|
|
NULL, 0, NULL, NULL, NULL, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( rc == FERR_DATA_ERROR)
|
|
{
|
|
rc = (RCODE)HA_ADMIN_CORRUPT;
|
|
}
|
|
|
|
DBUG_RETURN( rc);
|
|
}
|
|
|
|
//#endif /* HAVE_FLAIM */
|