Files
mars-flaim/sql/src/createtable.cpp
dsandersoremutah 91816d4c49 Started adding support for SELECT statement.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@642 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2006-07-10 23:10:01 +00:00

638 lines
14 KiB
C++

//------------------------------------------------------------------------------
// Desc: This module contains the routines for creating a table.
//
// Tabs: 3
//
// Copyright (c) 2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// 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, 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$
//------------------------------------------------------------------------------
#include "flaimsys.h"
//------------------------------------------------------------------------------
// Desc: Create a new table in the database. Caller should have already
// verified that the table name is unique. This routine will verify
// that column names are unique in the table, and it will assign
// the table number as well as the column numbers.
//------------------------------------------------------------------------------
RCODE F_Db::createTable(
FLMUINT uiTableNum,
const char * pszTableName,
FLMUINT uiTableNameLen,
FLMUINT uiEncDefNum,
F_COLUMN_DEF * pColumnDefs,
FLMUINT uiNumColumnDefs)
{
RCODE rc = NE_SFLM_OK;
F_Row * pRow = NULL;
F_TABLE * pTable;
F_COLUMN * pColumn;
const char * pszTmp;
FLMUINT uiLen;
F_COLUMN_DEF * pColumnDef;
FLMUINT uiColumnNum;
FLMBOOL bStartedTrans = FALSE;
// Make sure we are in an update transaction.
if (RC_BAD( rc = checkTransaction( SFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// Create a new dictionary, if we don't already have one.
if (!(m_uiFlags & FDB_UPDATED_DICTIONARY))
{
if (RC_BAD( rc = dictClone()))
{
goto Exit;
}
}
// Create a row for the table in the table definition table.
if (RC_BAD( rc = gv_SFlmSysData.pRowCacheMgr->createRow( this,
SFLM_TBLNUM_TABLES, &pRow)))
{
goto Exit;
}
// Determine the table number to use - find lowest non-used table
// number.
if (!uiTableNum)
{
uiTableNum = 1;
while (uiTableNum <= m_pDict->m_uiHighestTableNum)
{
if (!m_pDict->m_pTableTbl [uiTableNum - 1].uiTableNum)
{
break;
}
uiTableNum++;
}
}
// The call to addTable will initialize either the empty slot we found, or
// the next slot at the end of the table table. It will reallocate the
// table array if necessary.
if (RC_BAD( rc = m_pDict->addTable( uiTableNum, pRow->m_ui64RowId,
pszTableName, FALSE, uiNumColumnDefs, uiEncDefNum)))
{
goto Exit;
}
pTable = m_pDict->getTable( uiTableNum);
// Populate the columns for the row in the table definition table.
if (RC_BAD( rc = pRow->setUTF8( this, SFLM_COLNUM_TABLES_TABLE_NAME,
pszTableName, uiTableNameLen, uiTableNameLen)))
{
goto Exit;
}
if (RC_BAD( rc = pRow->setUINT( this, SFLM_COLNUM_TABLES_TABLE_NUM,
uiTableNum)))
{
goto Exit;
}
if (RC_BAD( rc = pRow->setUINT( this, SFLM_COLNUM_TABLES_ENCDEF_NUM,
uiEncDefNum)))
{
goto Exit;
}
if (RC_BAD( rc = pRow->setUINT( this, SFLM_COLNUM_TABLES_NUM_COLUMNS,
uiNumColumnDefs)))
{
goto Exit;
}
// Add all of the columns to the column definition table.
for (uiColumnNum = 0, pColumnDef = pColumnDefs;
pColumnDef;
pColumnDef = pColumnDef->pNext)
{
// Create a row for the column in the column definition table.
if (pRow)
{
pRow->ReleaseRow();
pRow = NULL;
}
if (RC_BAD( rc = gv_SFlmSysData.pRowCacheMgr->createRow( this,
SFLM_TBLNUM_COLUMNS, &pRow)))
{
goto Exit;
}
// Verify that the column name is unique.
if ((pColumn = m_pDict->findColumn( pTable,
pColumnDef->pszColumnName)) != NULL)
{
rc = RC_SET( NE_SFLM_COLUMN_NAME_ALREADY_DEFINED);
goto Exit;
}
// Add the column definition to the in-memory dictionary structures.
uiColumnNum++;
if (RC_BAD( rc = m_pDict->addColumn( uiTableNum, pRow->m_ui64RowId,
uiColumnNum, pColumnDef->pszColumnName,
pColumnDef->uiFlags, pColumnDef->eColumnDataType,
pColumnDef->uiMaxLen, pColumnDef->uiEncDefNum)))
{
goto Exit;
}
// Populate the columns for the row in the column definition table.
if (RC_BAD( rc = pRow->setUINT( this, SFLM_COLNUM_COLUMNS_TABLE_NUM,
uiTableNum)))
{
goto Exit;
}
if (RC_BAD( rc = pRow->setUTF8( this, SFLM_COLNUM_COLUMNS_COLUMN_NAME,
pColumnDef->pszColumnName,
pColumnDef->uiColumnNameLen,
pColumnDef->uiColumnNameLen)))
{
goto Exit;
}
if (RC_BAD( rc = pRow->setUINT( this, SFLM_COLNUM_COLUMNS_COLUMN_NUM,
uiColumnNum)))
{
goto Exit;
}
switch (pColumnDef->eColumnDataType)
{
case SFLM_STRING_TYPE:
pszTmp = SFLM_STRING_OPTION_STR;
uiLen = SFLM_STRING_OPTION_STR_LEN;
break;
case SFLM_NUMBER_TYPE:
pszTmp = SFLM_INTEGER_OPTION_STR;
uiLen = SFLM_INTEGER_OPTION_STR_LEN;
break;
case SFLM_BINARY_TYPE:
pszTmp = SFLM_BINARY_OPTION_STR;
uiLen = SFLM_BINARY_OPTION_STR_LEN;
break;
default:
flmAssert( 0);
pszTmp = "Bad";
uiLen = 3;
break;
}
if (RC_BAD( rc = pRow->setUTF8( this, SFLM_COLNUM_COLUMNS_DATA_TYPE,
pszTmp, uiLen, uiLen)))
{
goto Exit;
}
if (pColumnDef->uiMaxLen)
{
if (RC_BAD( rc = pRow->setUINT( this, SFLM_COLNUM_COLUMNS_MAX_LEN,
pColumnDef->uiMaxLen)))
{
goto Exit;
}
}
if (pColumnDef->uiEncDefNum)
{
if (RC_BAD( rc = pRow->setUINT( this, SFLM_COLNUM_COLUMNS_ENCDEF_NUM,
pColumnDef->uiEncDefNum)))
{
goto Exit;
}
}
if (pColumnDef->uiFlags & COL_READ_ONLY)
{
if (RC_BAD( rc = pRow->setUTF8( this, SFLM_COLNUM_COLUMNS_READ_ONLY,
"yes", 3, 3)))
{
goto Exit;
}
}
if (pColumnDef->uiFlags & COL_NULL_ALLOWED)
{
if (RC_BAD( rc = pRow->setUTF8( this, SFLM_COLNUM_COLUMNS_NULL_ALLOWED,
"yes", 3, 3)))
{
goto Exit;
}
}
}
flmAssert( uiColumnNum == uiNumColumnDefs);
if (RC_BAD( rc = m_pDatabase->m_pRfl->logCreateTable( this, uiTableNum,
pszTableName, uiTableNameLen,
uiEncDefNum, pColumnDefs)))
{
goto Exit;
}
// Commit the transaction if we started it
if (bStartedTrans)
{
bStartedTrans = FALSE;
if (RC_BAD( rc = transCommit()))
{
goto Exit;
}
}
Exit:
if (bStartedTrans)
{
transAbort();
}
if (pRow)
{
pRow->ReleaseRow();
}
return( rc);
}
//------------------------------------------------------------------------------
// Desc: Parse the data type for a column.
//------------------------------------------------------------------------------
RCODE SQLStatement::getDataType(
eDataType * peDataType,
FLMUINT * puiMax,
FLMUINT * puiEncDefNum)
{
RCODE rc = NE_SFLM_OK;
char szToken [MAX_SQL_TOKEN_SIZE + 1];
FLMUINT uiTokenLineOffset;
char szEncDefName [MAX_SQL_NAME_LEN + 1];
FLMUINT uiEncDefNameLen;
F_ENCDEF * pEncDef;
// Leading whitespace has already been skipped
// Valid data types are:
// char(n)
// varchar(n)
// long varchar
// varwchar(n) - unicode
// longwvarchar - unicode
// smallint - 16 bit signed integer
// integer - 32 bit signed integer
// tinyint - 8 bit signed integer
// bigint - 64 bit signed integer
// binary(n)
// varbinary(n)
// long varbinary
if (RC_BAD( rc = getToken( szToken, sizeof( szToken), FALSE,
&uiTokenLineOffset, NULL)))
{
goto Exit;
}
if (f_stricmp( szToken, "char") == 0 ||
f_stricmp( szToken, "varchar") == 0 ||
f_stricmp( szToken, "varwchar") == 0)
{
if (RC_BAD( rc = haveToken( "(", FALSE, SQL_ERR_EXPECTING_LPAREN)))
{
goto Exit;
}
if (RC_BAD( rc = getUINT( FALSE, puiMax)))
{
goto Exit;
}
if (RC_BAD( rc = haveToken( ")", FALSE, SQL_ERR_EXPECTING_RPAREN)))
{
goto Exit;
}
*peDataType = SFLM_STRING_TYPE;
}
else if (f_stricmp( szToken, "longvarchar") == 0 ||
f_stricmp( szToken, "longwvarchar") == 0)
{
*peDataType = SFLM_STRING_TYPE;
*puiMax = 0;
}
else if (f_stricmp( szToken, "longvarbinary") == 0)
{
*peDataType = SFLM_BINARY_TYPE;
*puiMax = 0;
}
else if (f_stricmp( szToken, "long") == 0)
{
if (RC_BAD( rc = getToken( szToken, sizeof( szToken), FALSE,
&uiTokenLineOffset, NULL)))
{
goto Exit;
}
if (f_stricmp( szToken, "varchar") == 0 ||
f_stricmp( szToken, "varwchar") == 0)
{
*peDataType = SFLM_STRING_TYPE;
*puiMax = 0;
}
else if (f_stricmp( szToken, "varbinary") == 0)
{
*peDataType = SFLM_BINARY_TYPE;
*puiMax = 0;
}
else
{
goto Invalid_Data_Type;
}
}
else if (f_stricmp( szToken, "smallint") == 0 ||
f_stricmp( szToken, "integer") == 0 ||
f_stricmp( szToken, "tinyint") == 0 ||
f_stricmp( szToken, "bigint") == 0)
{
*peDataType = SFLM_NUMBER_TYPE;
}
else if (f_stricmp( szToken, "binary") == 0 ||
f_stricmp( szToken, "varbinary") == 0)
{
if (RC_BAD( rc = haveToken( "(", FALSE, SQL_ERR_EXPECTING_LPAREN)))
{
goto Exit;
}
if (RC_BAD( rc = getUINT( FALSE, puiMax)))
{
goto Exit;
}
if (RC_BAD( rc = haveToken( ")", FALSE, SQL_ERR_EXPECTING_RPAREN)))
{
goto Exit;
}
*peDataType = SFLM_BINARY_TYPE;
}
else
{
Invalid_Data_Type:
setErrInfo( m_uiCurrLineNum,
uiTokenLineOffset,
SQL_ERR_INVALID_DATA_TYPE,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_SFLM_INVALID_SQL);
goto Exit;
}
// See if they specified any encryption.
if (RC_BAD( rc = haveToken( "encrypt_with", FALSE)))
{
if (rc == NE_SFLM_NOT_FOUND)
{
rc = NE_SFLM_OK;
}
else
{
goto Exit;
}
}
else
{
if (RC_BAD( rc = getEncDefName( TRUE, szEncDefName, sizeof( szEncDefName),
&uiEncDefNameLen, &pEncDef)))
{
goto Exit;
}
*puiEncDefNum = pEncDef->uiEncDefNum;
}
Exit:
return( rc);
}
//------------------------------------------------------------------------------
// Desc: Process the create table statement. The "CREATE TABLE" keywords
// have already been parsed.
//------------------------------------------------------------------------------
RCODE SQLStatement::processCreateTable( void)
{
RCODE rc = NE_SFLM_OK;
FLMBOOL bStartedTrans = FALSE;
char szTableName [MAX_SQL_NAME_LEN + 1];
FLMUINT uiTableNameLen;
char szColumnName [MAX_SQL_NAME_LEN + 1];
FLMUINT uiColumnNameLen;
char szEncDefName [MAX_SQL_NAME_LEN + 1];
FLMUINT uiEncDefNameLen;
char * pszTmp;
F_COLUMN_DEF * pColumnDef;
F_COLUMN_DEF * pFirstColDef;
F_COLUMN_DEF * pLastColDef;
FLMUINT uiNumColumnDefs;
F_TABLE * pTable;
F_ENCDEF * pEncDef;
FLMUINT uiEncDefNum;
char szToken [MAX_SQL_TOKEN_SIZE + 1];
FLMUINT uiTokenLineOffset;
// If we are in a read transaction, we cannot do this operation
if (RC_BAD( rc = m_pDb->checkTransaction( SFLM_UPDATE_TRANS, &bStartedTrans)))
{
goto Exit;
}
// SYNTAX: CREATE TABLE <tablename> (<column_name> <data_type,...)
// [ENCRYPT_WITH <EncDefName>]
// Whitespace must follow the "CREATE TABLE"
if (RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
// Get the table name - must not already be defined.
if (RC_BAD( rc = getTableName( FALSE, szTableName, sizeof( szTableName),
&uiTableNameLen, &pTable)))
{
goto Exit;
}
// Left paren must follow table name
if (RC_BAD( rc = haveToken( "(", FALSE, SQL_ERR_EXPECTING_LPAREN)))
{
goto Exit;
}
// Get the table's columns
pFirstColDef = NULL;
pLastColDef = NULL;
uiNumColumnDefs = 0;
for (;;)
{
// Get the column name
if (RC_BAD( rc = getName( szColumnName, sizeof( szColumnName),
&uiColumnNameLen, &uiTokenLineOffset)))
{
goto Exit;
}
flmAssert( uiColumnNameLen);
// Allocate a column definition
if (RC_BAD( rc = m_tmpPool.poolAlloc( sizeof( F_COLUMN_DEF),
(void **)&pColumnDef)))
{
goto Exit;
}
uiNumColumnDefs++;
if (RC_BAD( rc = m_tmpPool.poolAlloc( uiColumnNameLen + 1,
(void **)&pszTmp)))
{
goto Exit;
}
f_memcpy( pszTmp, szColumnName, uiColumnNameLen + 1);
pColumnDef->pszColumnName = pszTmp;
pColumnDef->uiColumnNameLen = uiColumnNameLen;
pColumnDef->eColumnDataType = SFLM_UNKNOWN_TYPE;
pColumnDef->uiFlags = COL_NULL_ALLOWED;
pColumnDef->uiEncDefNum = 0;
pColumnDef->uiMaxLen = 0;
pColumnDef->pNext = NULL;
if (pLastColDef)
{
pLastColDef->pNext = pColumnDef;
}
else
{
pFirstColDef = pColumnDef;
}
pLastColDef = pColumnDef;
// Must be whitespace after the column name.
if (RC_BAD( rc = skipWhitespace( TRUE)))
{
goto Exit;
}
// Data type must follow
if (RC_BAD( rc = getDataType( &pColumnDef->eColumnDataType,
&pColumnDef->uiMaxLen,
&pColumnDef->uiEncDefNum)))
{
goto Exit;
}
// Skip any white space
if (RC_BAD( rc = skipWhitespace( FALSE)))
{
goto Exit;
}
if (RC_BAD( rc = getToken( szToken, sizeof( szToken), FALSE,
&uiTokenLineOffset, NULL)))
{
goto Exit;
}
// See if we are at the end of the list of columns
if (f_stricmp( szToken, ")") == 0)
{
break;
}
else if (f_stricmp( szToken, ",") != 0)
{
setErrInfo( m_uiCurrLineNum,
m_uiCurrLineOffset,
SQL_ERR_EXPECTING_COMMA,
m_uiCurrLineFilePos,
m_uiCurrLineBytes);
rc = RC_SET( NE_SFLM_INVALID_SQL);
goto Exit;
}
}
// See if an encryption definition was specified
uiEncDefNum = 0;
if (RC_BAD( rc = haveToken( "encrypt_with", TRUE)))
{
if (rc == NE_SFLM_NOT_FOUND || rc == NE_SFLM_EOF_HIT)
{
rc = NE_SFLM_OK;
}
else
{
goto Exit;
}
}
else
{
if (RC_BAD( rc = getEncDefName( TRUE, szEncDefName, sizeof( szEncDefName),
&uiEncDefNameLen, &pEncDef)))
{
goto Exit;
}
uiEncDefNum = pEncDef->uiEncDefNum;
}
// Create the table
if (RC_BAD( rc = m_pDb->createTable( 0, szTableName, uiTableNameLen,
uiEncDefNum, pFirstColDef, uiNumColumnDefs)))
{
goto Exit;
}
// Commit the transaction if we started it
if (bStartedTrans)
{
bStartedTrans = FALSE;
if (RC_BAD( rc = m_pDb->transCommit()))
{
goto Exit;
}
}
Exit:
if (bStartedTrans)
{
m_pDb->transAbort();
}
return( rc);
}