//------------------------------------------------------------------------------ // Desc: This file contains SQL statement class. // 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$ //------------------------------------------------------------------------------ #ifndef SQLSTATEMENT_H #define SQLSTATEMENT_H // Maximum name length for table names, column names, and index names #define MAX_SQL_NAME_LEN 128 class SQLQuery; typedef struct SELECT_EXPR { SQLQuery * pSqlQuery; SELECT_EXPR * pNext; } SELECT_EXPR; typedef struct COLUMN_SET { FLMUINT uiColumnNum; SQLQuery * pSqlQuery; COLUMN_SET * pNext; } COLUMN_SET; typedef struct TABLE_ITEM { FLMUINT uiTableNum; const char * pszTableAlias; FLMUINT uiIndexNum; FLMBOOL bScan; } TABLE_ITEM; typedef enum { SQL_PARSE_STATS } eSQLStatus; typedef RCODE (* SQL_STATUS_HOOK)( eSQLStatus eStatusType, void * pvArg1, void * pvArg2, void * pvArg3, void * pvUserData); //------------------------------------------------------------------------------ // Desc: Base object that defines methods which must be present for all ODBC // handle objects. //------------------------------------------------------------------------------ class ODBCObject : public F_Object { public: ODBCObject() { m_hMutex = F_MUTEX_NULL; m_pszStateInfo = NULL; m_uiErrMsgLen = 0; m_bHaveError = FALSE; m_uiNumDiagRecs = 0; } virtual ~ODBCObject() { if (m_hMutex != F_MUTEX_NULL) { f_mutexDestroy( &m_hMutex); } } FINLINE FLMINT FLMAPI AddRef( void) { return( f_atomicInc( &m_refCnt); } FINLINE FLMINT FLMAPI Release( void) { FLMINT iRefCnt; if ((iRefCnt = f_atomicDec( &m_refCnt)) == 0) { delete this; } return( iRefCnt); } FINLINE RCODE setupObject( void) { return( f_mutexCreate( &m_hMutex)); } FINLINE void lockObject( void) { f_mutexLock( m_hMutex); } FINLINE void unlockObject( void) { f_mutexUnlock( m_hMutex); } FINLINE const char * getStateInfo( void) { return( m_pszStateInfo); } FINLINE FLMUINT getErrMsgLen( void) { return( m_uiErrMsgLen); } FINLINE const char * getErrMsg( void) { if (m_uiErrMsgLen) { return( &m_szErrMsg [0]); } else { return( NULL); } } FINLINE RCODE getRCODE( void) { return( m_rc); } FINLINE FLMBOOL haveError( void) { return( m_bHaveError); } FINLINE void clearState( void) { m_bHaveError = FALSE; m_uiNumDiagRecs = 0; } FINLINE void setStateInfo( const char * pszStateInfo) { m_pszStateInfo = pszStateInfo; m_uiErrMsgLen = 0; m_rc = NE_SFLM_OK; m_bHaveError = TRUE; } FINLINE void setGeneralErrMsg( const char * pszErrMsg, RCODE rc = NE_SFLM_OK) { m_pszStateInfo = "HY000"; m_uiErrMsgLen = f_strlen( pszErrMsg); // Copy null terminator character too. f_memcpy( m_szErrMsg, pszErrMsg, m_uiErrMsgLen + 1); m_rc = rc; m_bHaveError = TRUE; } // Must be implemented by inheriting class. virtual FLMBOOL canRelease( void) = 0; private: F_MUTEX m_hMutex; const char * m_pszLastStateInfo; char * m_szErrMsg [200]; FLMUINT m_uiErrMsgLen; RCODE m_rc; FLMUINT m_bHaveError; FLMUINT m_uiNumDiagRecs; } /*============================================================================ Desc: SQL statement class. Parses and executes SQL statements. This object type is returned for ODBC for handles of type SQL_HANDLE_STMT or SQLHSTMT. ============================================================================*/ class SQLStatement : public ODBCObject { public: #define MAX_SQL_TOKEN_SIZE 80 SQLStatement(); virtual ~SQLStatement(); FLMBOOL canRelease( void); RCODE setupStatement( void); void resetStatement( void); RCODE executeSQL( IF_IStream * pStream, F_Db * pDb, SQL_STATS * pSQLStats); FINLINE FLMBOOL canRelease( void) { // VISIT: Need to determine whether or not this is possible. return( TRUE); } SQLConnection * getConnection( void) { return( m_pConnection); } private: // Methods RCODE getByte( FLMBYTE * pucByte); FINLINE void ungetByte( FLMBYTE ucByte) { // Can only unget a single byte. flmAssert( !m_ucUngetByte); m_ucUngetByte = ucByte; m_sqlStats.uiChars--; } RCODE getLine( void); FINLINE FLMBYTE getChar( void) { if (m_uiCurrLineOffset == m_uiCurrLineBytes) { return( (FLMBYTE)0); } else { FLMBYTE ucChar = m_pucCurrLineBuf [m_uiCurrLineOffset++]; return( ucChar); } } FINLINE FLMBYTE peekChar( void) { if (m_uiCurrLineOffset == m_uiCurrLineBytes) { return( (FLMBYTE)0); } else { return( m_pucCurrLineBuf [m_uiCurrLineOffset]); } } FINLINE void ungetChar( void) { // There should never be a reason to unget past the beginning of the current // line. flmAssert( m_uiCurrLineOffset); m_uiCurrLineOffset--; } RCODE skipWhitespace( FLMBOOL bRequired); RCODE haveToken( const char * pszToken, FLMBOOL bEofOK, SQLParseError eNotHaveErr = SQL_NO_ERROR); RCODE getToken( char * pszToken, FLMUINT uiTokenBufSize, FLMBOOL bEofOK, FLMUINT * puiTokenLineOffset, FLMUINT * puiTokenLen); FINLINE void setErrInfo( FLMUINT uiErrLineNum, FLMUINT uiErrLineOffset, SQLParseError eErrorType, FLMUINT uiErrLineFilePos, FLMUINT uiErrLineBytes) { m_sqlStats.uiErrLineNum = uiErrLineNum; m_sqlStats.uiErrLineOffset = uiErrLineOffset; m_sqlStats.eErrorType = eErrorType; m_sqlStats.uiErrLineFilePos = uiErrLineFilePos; m_sqlStats.uiErrLineBytes = uiErrLineBytes; } RCODE getBinaryValue( F_DynaBuf * pDynaBuf); RCODE getUTF8String( FLMBOOL bMustHaveEqual, FLMBOOL bStripWildcardEscapes, FLMBYTE * pszStr, FLMUINT uiStrBufSize, FLMUINT * puiStrLen, FLMUINT * puiNumChars, F_DynaBuf * pDynaBuf); RCODE getNumber( FLMBOOL bMustHaveEqual, FLMUINT64 * pui64Num, FLMBOOL * pbNeg, FLMBOOL bNegAllowed); RCODE getBool( FLMBOOL bMustHaveEqual, FLMBOOL * pbBool); RCODE getUINT( FLMBOOL bMustHaveEqual, FLMUINT * puiNum); RCODE getName( char * pszName, FLMUINT uiNameBufSize, FLMUINT * puiNameLen, FLMUINT * puiTokenLineOffset); RCODE getEncDefName( FLMBOOL bMustExist, char * pszEncDefName, FLMUINT uiEncDefNameBufSize, FLMUINT * puiEncDefNameLen, F_ENCDEF ** ppEncDef); RCODE getTableName( FLMBOOL bMustExist, char * pszTableName, FLMUINT uiTableNameBufSize, FLMUINT * puiTableNameLen, F_TABLE ** ppTable); RCODE getIndexName( FLMBOOL bMustExist, F_TABLE * pTable, char * pszIndexName, FLMUINT uiIndexNameBufSize, FLMUINT * puiIndexNameLen, F_INDEX ** ppIndex); RCODE getStringValue( F_COLUMN * pColumn, F_COLUMN_VALUE * pColumnValue); RCODE getNumberValue( F_COLUMN_VALUE * pColumnValue); RCODE getBinaryValue( F_COLUMN * pColumn, F_COLUMN_VALUE * pColumnValue); RCODE getValue( F_COLUMN * pColumn, F_COLUMN_VALUE * pColumnValue); RCODE insertRow( void); RCODE processCreateDatabase( void); RCODE processOpenDatabase( void); RCODE processDropDatabase( void); RCODE getDataType( eDataType * peDataType, FLMUINT * puiMax, FLMUINT * puiEncDefNum, FLMUINT * puiFlags); RCODE processCreateTable( void); RCODE processDropTable( void); RCODE processCreateIndex( FLMBOOL bUnique); RCODE processDropIndex( void); RCODE processInsertRow( void); RCODE parseSetColumns( TABLE_ITEM * pTableList, COLUMN_SET ** ppFirstColumnSet, COLUMN_SET ** ppLastColumnSet, FLMUINT * puiNumColumnsToSet, FLMBOOL * pbHadWhere); RCODE processUpdateRows( void); RCODE processDeleteRows( void); RCODE processAlphaToken( TABLE_ITEM * pTableList, const char ** ppszTerminatingTokens, const char ** ppszTerminator, SQLQuery * pSqlQuery, FLMBOOL * pbDone); RCODE parseCriteria( TABLE_ITEM * pTableList, const char ** ppszTerminatingTokens, FLMBOOL bEofOK, const char ** ppszTerminator, SQLQuery * pSqlQuery); RCODE parseSelectExpressions( SELECT_EXPR ** ppFirstSelectExpr, SELECT_EXPR ** ppLastSelectExpr); RCODE processSelect( void); // Data F_Db * m_pDb; IF_XML * m_pXml; FLMBYTE m_ucUngetByte; FLMBYTE * m_pucCurrLineBuf; FLMUINT m_uiCurrLineBufMaxBytes; FLMUINT m_uiCurrLineOffset; FLMUINT m_uiCurrLineNum; FLMUINT m_uiCurrLineFilePos; FLMUINT m_uiCurrLineBytes; IF_IStream * m_pStream; FLMUINT m_uiFlags; SQL_STATUS_HOOK m_fnStatus; void * m_pvCallbackData; SQL_STATS m_sqlStats; F_Pool m_tmpPool; SQLConnection * m_pConnection; SQLStatement * m_pNextInConnection; SQLStatement * m_pPrevInConnection; friend class F_Db; friend class F_Database; friend class SQLConnection; friend class SQLEnv; friend class SQLDesc; }; RCODE resolveColumnName( F_Db * pDb, TABLE_ITEM * pTableList, const char * pszTableAlias, const char * pszColumnName, FLMUINT * puiTableNum, FLMUINT * puiColumnNum, SQLParseError * peParseError); #endif // SQLSTATEMENT_H