From 3e8e0030506381e2429b66252e002791d93fabc8 Mon Sep 17 00:00:00 2001 From: dsandersoremutah Date: Thu, 6 Jul 2006 15:47:13 +0000 Subject: [PATCH] Added code for evaluating query expressions against a row. git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@635 0109f412-320b-0410-ab79-c3e0c5ffbbe6 --- sql/src/flaimsys.h | 2 +- sql/src/sqleval.cpp | 852 ++++++++++++++++++++++++++-- sql/src/sqloptimize.cpp | 57 +- sql/src/{flaimodbc.h => sqlquery.h} | 82 ++- sql/src/updaterow.cpp | 29 +- sql/src/whereclause.cpp | 257 ++------- 6 files changed, 946 insertions(+), 333 deletions(-) rename sql/src/{flaimodbc.h => sqlquery.h} (88%) diff --git a/sql/src/flaimsys.h b/sql/src/flaimsys.h index 059c815..6b5398b 100644 --- a/sql/src/flaimsys.h +++ b/sql/src/flaimsys.h @@ -4411,7 +4411,7 @@ private: // More includes -#include "flaimodbc.h" +#include "sqlquery.h" #include "fscursor.h" #endif // FLAIMSYS_H diff --git a/sql/src/sqleval.cpp b/sql/src/sqleval.cpp index 96ccb97..f002f7f 100644 --- a/sql/src/sqleval.cpp +++ b/sql/src/sqleval.cpp @@ -34,6 +34,11 @@ FSTATIC RCODE sqlCompareText( FLMUINT uiLanguage, FLMINT * piResult); +FSTATIC RCODE sqlApproxCompare( + SQL_VALUE * pLValue, + SQL_VALUE * pRValue, + FLMINT * piResult); + FSTATIC RCODE sqlCompareBinary( SQL_VALUE * pLValue, SQL_VALUE * pRValue, @@ -154,6 +159,27 @@ FSTATIC void sqlArithOpSUMinus( SQL_VALUE * pRValue, SQL_VALUE * pResult); +FSTATIC RCODE sqlCompareOperands( + FLMUINT uiLanguage, + SQL_VALUE * pLValue, + SQL_VALUE * pRValue, + eSQLQueryOperators eOperator, + FLMUINT uiCompareRules, + FLMBOOL bNotted, + SQLBoolType * peBool); + +FSTATIC RCODE sqlGetColumnValue( + F_Db * pDb, + F_Row * pRow, + FLMUINT uiTableNum, + FLMUINT uiColumnNum, + F_Pool * pPool, + SQL_VALUE * pSqlValue); + +FSTATIC RCODE sqlEvalOperator( + FLMUINT uiLanguage, + SQL_NODE * pQNode); + typedef void SQL_ARITH_OP( SQL_VALUE * pLValue, SQL_VALUE * pRValue, @@ -210,34 +236,20 @@ FSTATIC RCODE sqlCompareText( // Open the streams - if( !(pLValue->uiFlags & SQL_VAL_IS_STREAM)) + if (RC_BAD( rc = bufferLStream.open( (const char *)pLValue->val.str.pszStr, + pLValue->val.str.uiByteLen))) { - if (RC_BAD( rc = bufferLStream.open( (const char *)pLValue->val.str.pszStr, - pLValue->val.str.uiByteLen))) - { - goto Exit; - } - - pLStream = &bufferLStream; - } - else - { - pLStream = pLValue->val.pIStream; + goto Exit; } - if( !(pRValue->uiFlags & SQL_VAL_IS_STREAM)) + pLStream = &bufferLStream; + + if( RC_BAD( rc = bufferRStream.open( (const char *)pRValue->val.str.pszStr, + pRValue->val.str.uiByteLen))) { - if( RC_BAD( rc = bufferRStream.open( (const char *)pRValue->val.str.pszStr, - pRValue->val.str.uiByteLen))) - { - goto Exit; - } - pRStream = &bufferRStream; - } - else - { - pRStream = pRValue->val.pIStream; + goto Exit; } + pRStream = &bufferRStream; if( RC_BAD( rc = f_compareUTF8Streams( pLStream, @@ -254,9 +266,142 @@ Exit: return( rc); } +//------------------------------------------------------------------------- +// Desc: Performs approximate compare on two strings. +//------------------------------------------------------------------------- +FSTATIC RCODE sqlApproxCompare( + SQL_VALUE * pLValue, + SQL_VALUE * pRValue, + FLMINT * piResult) +{ + RCODE rc = NE_SFLM_OK; + FLMUINT uiLMeta; + FLMUINT uiRMeta; + FLMUINT64 ui64StartPos; + F_BufferIStream bufferLStream; + IF_PosIStream * pLStream; + F_BufferIStream bufferRStream; + IF_PosIStream * pRStream; + + // Types must be text + + if (pLValue->eValType != SQL_UTF8_VAL || + pRValue->eValType != SQL_UTF8_VAL) + { + rc = RC_SET_AND_ASSERT( NE_SFLM_NOT_IMPLEMENTED); + goto Exit; + } + + // Open the streams + + if (RC_BAD( rc = bufferLStream.open( + (const char *)pLValue->val.str.pszStr, pLValue->val.str.uiByteLen))) + { + goto Exit; + } + pLStream = &bufferLStream; + + if( RC_BAD( rc = bufferRStream.open( + (const char *)pRValue->val.str.pszStr, pRValue->val.str.uiByteLen))) + { + goto Exit; + } + pRStream = &bufferRStream; + + if ((pLValue->uiFlags & SQL_VAL_IS_CONSTANT) || + !(pRValue->uiFlags & SQL_VAL_IS_CONSTANT)) + { + for( ;;) + { + if (RC_BAD( rc = f_getNextMetaphone( pLStream, &uiLMeta))) + { + if( rc == NE_FLM_EOF_HIT) + { + *piResult = 0; + rc = NE_SFLM_OK; + } + goto Exit; + } + + ui64StartPos = pRStream->getCurrPosition(); + + for( ;;) + { + if( RC_BAD( rc = f_getNextMetaphone( pRStream, &uiRMeta))) + { + if( rc == NE_FLM_EOF_HIT) + { + rc = NE_SFLM_OK; + *piResult = -1; + } + + goto Exit; + } + + if( uiLMeta == uiRMeta) + { + break; + } + + } + + if( RC_BAD( rc = pRStream->positionTo( ui64StartPos))) + { + goto Exit; + } + } + } + else + { + for( ;;) + { + if( RC_BAD( rc = f_getNextMetaphone( pRStream, &uiRMeta))) + { + if( rc == NE_FLM_EOF_HIT) + { + *piResult = 0; + rc = NE_SFLM_OK; + } + goto Exit; + } + + ui64StartPos = pLStream->getCurrPosition(); + + for( ;;) + { + if( RC_BAD( rc = f_getNextMetaphone( pLStream, &uiLMeta))) + { + if( rc == NE_FLM_EOF_HIT) + { + rc = NE_SFLM_OK; + *piResult = 1; + } + + goto Exit; + } + + if( uiLMeta == uiRMeta) + { + break; + } + + } + + if( RC_BAD( rc = pLStream->positionTo( ui64StartPos))) + { + goto Exit; + } + } + } + +Exit: + + return( rc); +} + //------------------------------------------------------------------------- // Desc: Performs binary comparison on two streams - may be text or binary, -// it really doesn't matter. Returns XFLM_TRUE or XFLM_FALSE. +// it really doesn't matter. Returns SQL_TRUE or SQL_FALSE. //------------------------------------------------------------------------- FSTATIC RCODE sqlCompareBinary( SQL_VALUE * pLValue, @@ -286,34 +431,19 @@ FSTATIC RCODE sqlCompareBinary( // Open the streams - if( !(pLValue->uiFlags & SQL_VAL_IS_STREAM)) + if (RC_BAD( rc = bufferLStream.open( (const char *)pLValue->val.str.pszStr, + pLValue->val.str.uiByteLen))) { - if (RC_BAD( rc = bufferLStream.open( (const char *)pLValue->val.str.pszStr, - pLValue->val.str.uiByteLen))) - { - goto Exit; - } + goto Exit; + } + pLStream = &bufferLStream; - pLStream = &bufferLStream; - } - else + if( RC_BAD( rc = bufferRStream.open( (const char *)pRValue->val.str.pszStr, + pRValue->val.str.uiByteLen))) { - pLStream = pLValue->val.pIStream; - } - - if( !(pRValue->uiFlags & SQL_VAL_IS_STREAM)) - { - if( RC_BAD( rc = bufferRStream.open( (const char *)pRValue->val.str.pszStr, - pRValue->val.str.uiByteLen))) - { - goto Exit; - } - pRStream = &bufferRStream; - } - else - { - pRStream = pRValue->val.pIStream; + goto Exit; } + pRStream = &bufferRStream; for (;;) { @@ -1416,6 +1546,122 @@ FSTATIC void sqlArithOpSUMinus( } } +/*************************************************************************** +Desc: Do a comparison operator. +***************************************************************************/ +FSTATIC RCODE sqlCompareOperands( + FLMUINT uiLanguage, + SQL_VALUE * pLValue, + SQL_VALUE * pRValue, + eSQLQueryOperators eOperator, + FLMUINT uiCompareRules, + FLMBOOL bNotted, + SQLBoolType * peBool) +{ + RCODE rc = NE_SFLM_OK; + FLMINT iCmp; + + if (!pLValue || pLValue->eValType == SQL_MISSING_VAL || + !pRValue || pRValue->eValType == SQL_MISSING_VAL || + !sqlCanCompare( pLValue, pRValue)) + { + *peBool = SQL_UNKNOWN; + } + + // At this point, both operands are known to be present and are of + // types that can be compared. The comparison + // will therefore be performed according to the + // operator specified. + + else + { + switch (eOperator) + { + case SQL_EQ_OP: + case SQL_NE_OP: + if (pLValue->eValType == SQL_UTF8_VAL || + pRValue->eValType == SQL_UTF8_VAL) + { + if (RC_BAD( rc = sqlCompareText( pLValue, pRValue, + uiCompareRules, TRUE, uiLanguage, &iCmp))) + { + goto Exit; + } + } + else + { + if (RC_BAD( rc = sqlCompare( pLValue, pRValue, + uiCompareRules, uiLanguage, &iCmp))) + { + goto Exit; + } + } + if (eOperator == SQL_EQ_OP) + { + *peBool = (iCmp == 0 ? SQL_TRUE : SQL_FALSE); + } + else + { + *peBool = (iCmp != 0 ? SQL_TRUE : SQL_FALSE); + } + break; + + case SQL_APPROX_EQ_OP: + if (RC_BAD( rc = sqlApproxCompare( pLValue, pRValue, &iCmp))) + { + goto Exit; + } + *peBool = (iCmp == 0 ? SQL_TRUE : SQL_FALSE); + break; + + case SQL_LT_OP: + if (RC_BAD( rc = sqlCompare( pLValue, pRValue, + uiCompareRules, uiLanguage, &iCmp))) + { + goto Exit; + } + *peBool = (iCmp < 0 ? SQL_TRUE : SQL_FALSE); + break; + + case SQL_LE_OP: + if (RC_BAD( rc = sqlCompare( pLValue, pRValue, + uiCompareRules, uiLanguage, &iCmp))) + { + goto Exit; + } + *peBool = (iCmp <= 0 ? SQL_TRUE : SQL_FALSE); + break; + + case SQL_GT_OP: + if (RC_BAD( rc = sqlCompare( pLValue, pRValue, + uiCompareRules, uiLanguage, &iCmp))) + { + goto Exit; + } + *peBool = (iCmp > 0 ? SQL_TRUE : SQL_FALSE); + break; + + case SQL_GE_OP: + if (RC_BAD( rc = sqlCompare( pLValue, pRValue, + uiCompareRules, uiLanguage, &iCmp))) + { + goto Exit; + } + *peBool = (iCmp >= 0 ? SQL_TRUE : SQL_FALSE); + break; + + default: + *peBool = SQL_UNKNOWN; + rc = RC_SET_AND_ASSERT( NE_SFLM_QUERY_SYNTAX); + goto Exit; + } + } + +Exit: + + return( rc); +} + /*************************************************************************** Desc: Do an arithmetic operator. ***************************************************************************/ @@ -1484,3 +1730,513 @@ Exit: return( rc); } +/*************************************************************************** +Desc: Get a column's value from the passed in row. Return it in pSqlValue. +***************************************************************************/ +FSTATIC RCODE sqlGetColumnValue( + F_Db * pDb, + F_Row * pRow, + FLMUINT uiTableNum, + FLMUINT uiColumnNum, + F_Pool * pPool, + SQL_VALUE * pSqlValue) +{ + RCODE rc = NE_SFLM_OK; + F_TABLE * pTable = pDb->getDict()->getTable( uiTableNum); + F_COLUMN * pColumn = pDb->getDict()->getColumn( pTable, uiColumnNum); + FLMBOOL bNeg; + FLMUINT64 ui64Value; + FLMBOOL bIsNull; + FLMUINT uiDataLen; + const FLMBYTE * pucColumnData; + const FLMBYTE * pucEnd; + + flmAssert( pTable->uiTableNum == uiTableNum); + + pRow->getDataLen( pDb, uiColumnNum, &uiDataLen, &bIsNull); + if (bIsNull) + { + pSqlValue->eValType = SQL_MISSING_VAL; + goto Exit; + } + pucColumnData = (const FLMBYTE *)pRow->getColumnDataPtr( uiColumnNum); + switch (pColumn->eDataTyp) + { + case SFLM_STRING_TYPE: + + // Decode the number of characters directly from the column's + // data buffer. Then copy only whatever part remains after that. + + pSqlValue->eValType = SQL_UTF8_VAL; + pucEnd = pucColumnData + uiDataLen; + if (RC_BAD( rc = f_decodeSEN( &pucColumnData, pucEnd, + &pSqlValue->val.str.uiNumChars))) + { + goto Exit; + } + uiDataLen = (FLMUINT)(pucEnd - pucColumnData); + pSqlValue->val.str.uiByteLen = uiDataLen; + if (RC_BAD( rc = pPool->poolAlloc( uiDataLen, + (void **)&pSqlValue->val.str.pszStr))) + { + goto Exit; + } + f_memcpy( pSqlValue->val.str.pszStr, pucColumnData, uiDataLen); + break; + + case SFLM_NUMBER_TYPE: + if (RC_BAD( rc = flmStorageNumberToNumber( pucColumnData, uiDataLen, + &ui64Value, &bNeg))) + { + goto Exit; + } + if (!bNeg) + { + if (ui64Value <= (FLMUINT64)(FLM_MAX_UINT)) + { + pSqlValue->eValType = SQL_UINT_VAL; + pSqlValue->val.uiVal = (FLMUINT)ui64Value; + } + else + { + pSqlValue->eValType = SQL_UINT64_VAL; + pSqlValue->val.ui64Val = ui64Value; + } + } + else + { + if (-((FLMINT64)ui64Value) <= (FLMINT64)(FLM_MIN_INT)) + { + pSqlValue->eValType = SQL_INT_VAL; + pSqlValue->val.iVal = (FLMINT)(-((FLMINT64)ui64Value)); + } + else + { + pSqlValue->eValType = SQL_INT64_VAL; + pSqlValue->val.i64Val = -((FLMINT64)ui64Value); + } + } + break; + + case SFLM_BINARY_TYPE: + pSqlValue->eValType = SQL_BINARY_VAL; + if (RC_BAD( rc = pPool->poolAlloc( uiDataLen, + (void **)&pSqlValue->val.bin.pucValue))) + { + goto Exit; + } + pSqlValue->val.bin.uiByteLen = uiDataLen; + f_memcpy( pSqlValue->val.bin.pucValue, pucColumnData, uiDataLen); + break; + + default: + flmAssert( 0); + rc = RC_SET( NE_SFLM_FAILURE); + goto Exit; + } + +Exit: + + return( rc); +} + +/*************************************************************************** +Desc: Evaluate a simple operator. +***************************************************************************/ +FSTATIC RCODE sqlEvalOperator( + FLMUINT uiLanguage, + SQL_NODE * pQNode) +{ + RCODE rc = NE_SFLM_OK; + SQL_NODE * pLeftOperand; + SQL_NODE * pRightOperand; + SQLBoolType eBool; + + // Right now we are only able to do operator nodes. + + flmAssert( pQNode->eNodeType == SQL_OPERATOR_NODE); + + pLeftOperand = pQNode->pFirstChild; + pRightOperand = pQNode->pLastChild; + + pQNode->currVal.eValType = SQL_MISSING_VAL; + + switch (pQNode->nd.op.eOperator) + { + case SQL_AND_OP: + case SQL_OR_OP: + pQNode->currVal.eValType = SQL_BOOL_VAL; + + // There may be multiple operands here. We have already looked + // at all of the operands. If this is an AND we know that all + // of them were either TRUE or UNKNOWN. If this is an OR, we know + // that all of the previous operands were either FALSE or UNKNOWN. + // If we had hit a FALSE for an AND or a TRUE for an OR, we would + // not have come to this point. Now we just need to determine if + // any of the operands are UNKNOWN. If so, that is what we will + // set this node's value to. Otherwise, we will set it to TRUE for + // AND and FALSE for OR. + + while (pLeftOperand) + { + + // Get the left operand + + if (pLeftOperand->eNodeType == SQL_OPERATOR_NODE) + { + + // This operator may not have been evaluated because of missing + // column values in one or both operands, in which case + // its state will be SQL_MISSING_VALUE. If it was evaluated, + // its state should show a boolean value. + + if (pLeftOperand->currVal.eValType == SQL_MISSING_VAL) + { + eBool = (pLeftOperand->bNotted ? SQL_TRUE : SQL_FALSE); + } + else + { + flmAssert( pLeftOperand->currVal.eValType == SQL_BOOL_VAL); + eBool = pLeftOperand->currVal.val.eBool; + } + } + else if (pLeftOperand->eNodeType == SQL_COLUMN_NODE) + { + if (!pLeftOperand->bNotted) + { + eBool = (pLeftOperand->currVal.eValType != SQL_MISSING_VAL) + ? SQL_TRUE + : SQL_FALSE; + } + else + { + eBool = (pLeftOperand->currVal.eValType != SQL_MISSING_VAL) + ? SQL_FALSE + : SQL_TRUE; + } + } + else + { + flmAssert( pLeftOperand->eNodeType == SQL_VALUE_NODE); + flmAssert( pLeftOperand->currVal.eValType == SQL_BOOL_VAL); + eBool = pLeftOperand->currVal.val.eBool; + } + + // eBool better not have FALSE for an AND operator or + // TRUE for an OR operator. + + flmAssert( (pQNode->nd.op.eOperator == SQL_AND_OP && + eBool != SQL_FALSE) || + (pQNode->nd.op.eOperator == SQL_OR_OP && + eBool != SQL_TRUE)); + + + if (eBool == SQL_UNKNOWN) + { + pQNode->currVal.val.eBool = SQL_UNKNOWN; + break; + } + pLeftOperand = pLeftOperand->pNextSib; + } + + // If we didn't hit an UNKNOWN, set the node's value to TRUE for + // an AND operator and FALSE for an OR operator. + + if (!pLeftOperand) + { + pQNode->currVal.val.eBool = pQNode->nd.op.eOperator == SQL_AND_OP + ? SQL_TRUE + : SQL_FALSE; + } + break; + + case SQL_EQ_OP: + case SQL_APPROX_EQ_OP: + case SQL_NE_OP: + case SQL_LT_OP: + case SQL_LE_OP: + case SQL_GT_OP: + case SQL_GE_OP: + pQNode->currVal.eValType = SQL_BOOL_VAL; + if (RC_BAD( rc = sqlCompareOperands( uiLanguage, + &pLeftOperand->currVal, + &pRightOperand->currVal, + pQNode->nd.op.eOperator, + pQNode->nd.op.uiCompareRules, + pQNode->bNotted, + &pQNode->currVal.val.eBool))) + { + goto Exit; + } + break; + + case SQL_BITAND_OP: + case SQL_BITOR_OP: + case SQL_BITXOR_OP: + case SQL_MULT_OP: + case SQL_DIV_OP: + case SQL_MOD_OP: + case SQL_PLUS_OP: + case SQL_MINUS_OP: + case SQL_NEG_OP: + + if (RC_BAD( rc = sqlEvalArithOperator( &pLeftOperand->currVal, + &pRightOperand->currVal, + pQNode->nd.op.eOperator, + &pQNode->currVal))) + { + goto Exit; + } + break; + + default: + break; + } + +Exit: + + return( rc); +} + +/*************************************************************************** +Desc: Evaluate a query expression. +***************************************************************************/ +RCODE sqlEvalCriteria( + F_Db * pDb, + SQL_NODE * pQueryExpr, + SQL_VALUE ** ppSqlValue, + F_Pool * pPool, + F_Row * pRow, + FLMUINT uiLanguage) +{ + RCODE rc = NE_SFLM_OK; + SQL_NODE * pCurrNode; + SQL_VALUE * pSqlValue; + SQLBoolType eBoolVal; + SQLBoolType eBoolPartialEval; + + // If the query is empty, return a value of SQL_TRUE. + + if (!pQueryExpr) + { + if (RC_BAD( rc = pPool->poolAlloc( sizeof( SQL_VALUE), + (void **)ppSqlValue))) + { + goto Exit; + } + pSqlValue = *ppSqlValue; + pSqlValue->eValType = SQL_BOOL_VAL; + pSqlValue->uiFlags = SQL_VAL_IS_CONSTANT; + pSqlValue->val.eBool = SQL_TRUE; + goto Exit; + } + + // If the query is a constant, return pointer to its value. + + if (pQueryExpr->eNodeType == SQL_VALUE_NODE) + { + *ppSqlValue = &pQueryExpr->currVal; + goto Exit; + } + + // If the query is a column, get the column's value from the + // row that was passed in. + + if (pQueryExpr->eNodeType == SQL_COLUMN_NODE) + { + *ppSqlValue = &pQueryExpr->currVal; + rc = sqlGetColumnValue( pDb, pRow, + pQueryExpr->nd.column.pTable->uiTableNum, + pQueryExpr->nd.column.uiColumnNum, + pPool, *ppSqlValue); + goto Exit; + } + + // Perform the evaluation + + pCurrNode = pQueryExpr; + for (;;) + { + while (pCurrNode->pFirstChild) + { + pCurrNode = pCurrNode->pFirstChild; + } + + // We should be positioned on a leaf node that is either a + // value or a column + + if (pCurrNode->eNodeType == SQL_COLUMN_NODE) + { + if (RC_BAD( rc = sqlGetColumnValue( pDb, pRow, + pCurrNode->nd.column.pTable->uiTableNum, + pCurrNode->nd.column.uiColumnNum, + pPool, &pCurrNode->currVal))) + { + goto Exit; + } + } + else + { + + // Better be a constant + + flmAssert( pCurrNode->eNodeType == SQL_VALUE_NODE); + } + + // When we get to this point, we have at least one leaf + // level operand in hand - pCurrNode. + // See if we can evaluate the operator of pCurrNode. + // This will take care of any short-circuiting evaluation + // that can be done. + + for (;;) + { + if (pCurrNode == pQueryExpr) + { + *ppSqlValue = &pQueryExpr->currVal; + goto Exit; + } + + // If the current node's parent is an AND or OR + // operator, see if we even need to go to the next + // sibling. + + flmAssert( pCurrNode->pParent->eNodeType == SQL_OPERATOR_NODE); + if (isSQLLogicalOp( pCurrNode->pParent->nd.op.eOperator)) + { + // All NOT operators should have been weeded out of the tree + // by now. + + flmAssert( pCurrNode->pParent->nd.op.eOperator != SQL_NOT_OP); + eBoolVal = SQL_UNKNOWN; + eBoolPartialEval = pCurrNode->pParent->nd.op.eOperator == SQL_AND_OP + ? SQL_FALSE + : SQL_TRUE; + if (pCurrNode->eNodeType == SQL_OPERATOR_NODE) + { + + // It may not have been evaluated because of missing + // values in one or both operands, in which case + // its state will be SQL_MISSING_VALUE. If it was + // evaluated, its state should show a boolean value. + + if (pCurrNode->currVal.eValType == SQL_MISSING_VAL) + { + eBoolVal = (pCurrNode->bNotted ? SQL_TRUE : SQL_FALSE); + } + else + { + flmAssert( pCurrNode->currVal.eValType == SQL_BOOL_VAL); + eBoolVal = pCurrNode->currVal.val.eBool; + } + } + else if (pCurrNode->eNodeType == SQL_COLUMN_NODE) + { + if (!pCurrNode->bNotted) + { + eBoolVal = (pCurrNode->currVal.eValType == SQL_MISSING_VAL) + ? SQL_FALSE + : SQL_TRUE; + } + else + { + eBoolVal = (pCurrNode->currVal.eValType == SQL_MISSING_VAL) + ? SQL_TRUE + : SQL_FALSE; + } + } + else + { + flmAssert( pCurrNode->eNodeType == SQL_VALUE_NODE); + + // Only allowed value node underneath a logical operator is + // a boolean value that has a value of SQL_UNKNOWN. + // SQL_FALSE and SQL_TRUE will already have been weeded out. + + flmAssert( pCurrNode->currVal.eValType == SQL_BOOL_VAL && + pCurrNode->currVal.val.eBool == SQL_UNKNOWN); + + // No need to set eBoolVal to SQL_UNKNOWN, because it will never + // match eBoolPartialEval in the test below. eBoolPartialEval + // is always either SQL_FALSE or SQL_TRUE. + + // eBoolVal = SQL_UNKNOWN; + + } + if (eBoolVal == eBoolPartialEval) + { + pCurrNode = pCurrNode->pParent; + pCurrNode->currVal.eValType = SQL_BOOL_VAL; + pCurrNode->currVal.val.eBool = eBoolVal; + } + else + { + goto Check_Sibling_Operand; + } + } + else if (isSQLCompareOp( pCurrNode->pParent->nd.op.eOperator)) + { + + // We can short-circuit the comparison - avoid getting the + // sibling operand - if the current node is a missing value. + // If the value is missing, the comparison operator will + // return a boolean SQL_UNKNOWN, regardless of what the + // other operand is. + + if (pCurrNode->currVal.eValType == SQL_MISSING_VAL) + { + pCurrNode = pCurrNode->pParent; + pCurrNode->currVal.eValType = SQL_BOOL_VAL; + pCurrNode->currVal.val.eBool = SQL_UNKNOWN; + } + else + { + goto Check_Sibling_Operand; + } + } + else if (isSQLArithOp( pCurrNode->pParent->nd.op.eOperator)) + { + + // We can short-circuit the arithmetic operation - avoid getting the + // sibling operand - if the current node is a missing value. + // If the value is missing, the arithmetic operation will + // return a missing value, regardless of what the + // other operand is. + + if (pCurrNode->currVal.eValType == SQL_MISSING_VAL) + { + pCurrNode = pCurrNode->pParent; + pCurrNode->currVal.eValType = SQL_MISSING_VAL; + } + else + { + goto Check_Sibling_Operand; + } + } + else + { + +Check_Sibling_Operand: + + if (pCurrNode->pNextSib) + { + pCurrNode = pCurrNode->pNextSib; + break; + } + pCurrNode = pCurrNode->pParent; + + // All operands are now present - do evaluation + + if (RC_BAD( rc = sqlEvalOperator( uiLanguage, pCurrNode))) + { + goto Exit; + } + } + } + } + +Exit: + + return( rc); +} + diff --git a/sql/src/sqloptimize.cpp b/sql/src/sqloptimize.cpp index 9283194..5066988 100644 --- a/sql/src/sqloptimize.cpp +++ b/sql/src/sqloptimize.cpp @@ -975,13 +975,13 @@ RCODE SQLQuery::convertOperandsToPredicates( void) { pTable = pSQLNode->pFirstChild->nd.column.pTable; uiColumnNum = pSQLNode->pFirstChild->nd.column.uiColumnNum; - pValue = &pSQLNode->pLastChild->nd.value; + pValue = &pSQLNode->pLastChild->currVal; } else { - pTable = pSQLNode->pFirstChild->nd.column.pTable; - uiColumnNum = pSQLNode->pFirstChild->nd.column.uiColumnNum; - pValue = &pSQLNode->pFirstChild->nd.value; + pTable = pSQLNode->pLastChild->nd.column.pTable; + uiColumnNum = pSQLNode->pLastChild->nd.column.uiColumnNum; + pValue = &pSQLNode->pFirstChild->currVal; // Need to invert the operator in this case. @@ -1061,7 +1061,7 @@ FSTATIC SQL_NODE * sqlEvalLogicalOperands( { if (isSQLNodeBool( pChildNode)) { - eChildBoolVal = pChildNode->nd.value.val.eBool; + eChildBoolVal = pChildNode->currVal.val.eBool; } else { @@ -1209,11 +1209,14 @@ FSTATIC SQL_NODE * sqlClipNotNode( } //------------------------------------------------------------------------- -// Desc: Flatten the query tree. This coalesces AND and OR nodes so that -// they can have multiple operands. This will also strip out NOT nodes -// and resolve constant expressions to a single node. +// Desc: Reduce the query tree. This will strip out NOT nodes and +// resolve constant expressions to a single node. It also weeds +// out all boolean constants that are operands of AND or OR operators. +// Finally, if the bFlattenTree parameter is TRUE, it will coalesce +// AND and OR nodes so that they can have multiple operands. //------------------------------------------------------------------------- -RCODE SQLQuery::flattenTree( void) +RCODE SQLQuery::reduceTree( + FLMBOOL bFlattenTree) { RCODE rc = NE_SFLM_OK; SQL_NODE * pSQLNode = m_pQuery; @@ -1266,7 +1269,7 @@ RCODE SQLQuery::flattenTree( void) rc = RC_SET( NE_SFLM_Q_ILLEGAL_OPERAND); goto Exit; } - if (pParentNode->nd.op.eOperator == eOperator) + if (bFlattenTree && pParentNode->nd.op.eOperator == eOperator) { // Move all of pSQLNode's children become the immediate @@ -1401,15 +1404,15 @@ RCODE SQLQuery::flattenTree( void) // If bNotted is TRUE and we have a boolean value, change // the value: FALSE ==> TRUE, TRUE ==> FALSE. - if (bNotted && pSQLNode->nd.value.eValType == SQL_BOOL_VAL) + if (bNotted && pSQLNode->currVal.eValType == SQL_BOOL_VAL) { - if (pSQLNode->nd.value.val.eBool == SQL_TRUE) + if (pSQLNode->currVal.val.eBool == SQL_TRUE) { - pSQLNode->nd.value.val.eBool = SQL_FALSE; + pSQLNode->currVal.val.eBool = SQL_FALSE; } - else if (pSQLNode->nd.value.val.eBool == SQL_FALSE) + else if (pSQLNode->currVal.val.eBool == SQL_FALSE) { - pSQLNode->nd.value.val.eBool = SQL_TRUE; + pSQLNode->currVal.val.eBool = SQL_TRUE; } } @@ -1419,7 +1422,7 @@ RCODE SQLQuery::flattenTree( void) if (pParentNode) { - if (pSQLNode->nd.value.eValType == SQL_BOOL_VAL) + if (pSQLNode->currVal.eValType == SQL_BOOL_VAL) { if (!isSQLLogicalOp( pParentNode->nd.op.eOperator)) { @@ -1475,15 +1478,15 @@ RCODE SQLQuery::flattenTree( void) pSQLNode->pLastChild->eNodeType == SQL_VALUE_NODE) { if (RC_BAD( rc = sqlEvalArithOperator( - &pSQLNode->pFirstChild->nd.value, - &pSQLNode->pLastChild->nd.value, + &pSQLNode->pFirstChild->currVal, + &pSQLNode->pLastChild->currVal, pSQLNode->nd.op.eOperator, - &pSQLNode->nd.value))) + &pSQLNode->currVal))) { goto Exit; } pSQLNode->eNodeType = SQL_VALUE_NODE; - pSQLNode->nd.value.uiFlags = SQL_VAL_IS_CONSTANT; + pSQLNode->currVal.uiFlags = SQL_VAL_IS_CONSTANT; pSQLNode->pFirstChild = NULL; pSQLNode->pLastChild = NULL; } @@ -2668,10 +2671,6 @@ RCODE SQLQuery::optimize( void) rc = RC_SET( NE_SFLM_Q_INCOMPLETE_QUERY_EXPR); goto Exit; } - else if (m_pCurrParseState) - { - m_pQuery = m_pCurrParseState->pRootNode; - } m_uiLanguage = m_pDb->getDefaultLanguage(); @@ -2695,8 +2694,8 @@ RCODE SQLQuery::optimize( void) if (m_pQuery->eNodeType == SQL_VALUE_NODE) { - if (m_pQuery->nd.value.eValType == SQL_BOOL_VAL && - m_pQuery->nd.value.val.eBool == SQL_TRUE) + if (m_pQuery->currVal.eValType == SQL_BOOL_VAL && + m_pQuery->currVal.val.eBool == SQL_TRUE) { m_bScan = TRUE; } @@ -2720,9 +2719,11 @@ RCODE SQLQuery::optimize( void) goto Exit; } - // Flatten the AND and OR operators in the query tree. + // Flatten the AND and OR operators in the query tree. Strip out + // NOT operators, resolve constant arithmetic expressions, and + // weed out boolean constants. - if (RC_BAD( rc = flattenTree())) + if (RC_BAD( rc = reduceTree( TRUE))) { goto Exit; } diff --git a/sql/src/flaimodbc.h b/sql/src/sqlquery.h similarity index 88% rename from sql/src/flaimodbc.h rename to sql/src/sqlquery.h index 02c8fde..69012e5 100644 --- a/sql/src/flaimodbc.h +++ b/sql/src/sqlquery.h @@ -152,21 +152,18 @@ typedef struct SQL_VALUE { eSQLValTypes eValType; FLMUINT uiFlags; -#define SQL_VAL_IS_STREAM 0x0001 -#define SQL_VAL_IS_CONSTANT 0x0002 // During query evaluation, this indicates +#define SQL_VAL_IS_CONSTANT 0x0001 // During query evaluation, this indicates // that this value is a constant. If it - // is a FLM_UTF8_VAL, then asterisks will + // is a SQL_UTF8_VAL, then asterisks will // be treated as a wildcard, unless // escaped (\*). If the value is NOT // a constant, the asterisk is NEVER // treated as a wildcard, and the // backslash is NEVER treated as an // escape character. -#define SQL_VAL_HAS_WILDCARDS 0x0004 // This is only set if the value is a - // constant, FLM_UTF8_VAL, that has +#define SQL_VAL_HAS_WILDCARDS 0x0002 // This is only set if the value is a + // constant, SQL_UTF8_VAL, that has // wildcards. - FLMUINT uiDataLen; // Length in bytes if the type is text - // or binary union { SQLBoolType eBool; @@ -176,7 +173,6 @@ typedef struct SQL_VALUE FLMINT64 i64Val; SQL_STRING_VALUE str; SQL_BINARY_VALUE bin; - IF_PosIStream * pIStream; } val; // Holds or points to the atom value. } SQL_VALUE; @@ -259,8 +255,10 @@ typedef struct SQL_NODE eSQLNodeTypes eNodeType; // Type of node this is FLMUINT uiNestLevel; // Nesting level of node - only used when // setting up the query - FLMBOOL bUsedValue; // Used during evaluation - FLMBOOL bLastValue; // Used during evaluation + SQL_VALUE currVal; // Used only during evaluation to store + // temporary results thus far. This is + // also used for constant operands + // (eNodeType == SQL_VALUE_NODE) FLMBOOL bNotted; SQL_NODE * pParent; // Parent of this query node SQL_NODE * pPrevSib; // Previous sibling of this query node @@ -271,31 +269,17 @@ typedef struct SQL_NODE { SQL_OP op; SQL_COLUMN column; - SQL_VALUE value; SQL_PRED pred; } nd; } SQL_NODE; FINLINE FLMBOOL isSQLNodeBool( - SQL_NODE * pNode - ) + SQL_NODE * pNode) { return( (pNode->eNodeType == SQL_VALUE_NODE && - pNode->nd.value.eValType == SQL_BOOL_VAL) ? TRUE : FALSE); + pNode->currVal.eValType == SQL_BOOL_VAL) ? TRUE : FALSE); } -typedef struct SQL_PARSE_STATE -{ - SQL_NODE * pRootNode; - SQL_NODE * pCurOperatorNode; - SQL_NODE * pLastNode; - FLMUINT uiNestLevel; - FLMBOOL bExpectingOperator; - FLMBOOL bExpectingLParen; - SQL_PARSE_STATE * pPrev; - SQL_PARSE_STATE * pNext; -} SQL_PARSE_STATE; - typedef struct SQL_SUBQUERY { FLMUINT uiOperandCount; @@ -328,12 +312,12 @@ public: FINLINE FLMBOOL expectingOperand( void) { - return( !m_pCurrParseState->bExpectingOperator); + return( !m_bExpectingOperator); } FINLINE FLMBOOL expectingOperator( void) { - return( m_pCurrParseState->bExpectingOperator); + return( m_bExpectingOperator); } RCODE addOperator( @@ -409,17 +393,10 @@ public: { // Make sure we have a completed expression - if (m_pCurrParseState) - { - if (m_pCurrParseState->pPrev || - m_pCurrParseState->uiNestLevel || - (m_pCurrParseState->pLastNode && - m_pCurrParseState->pLastNode->eNodeType == SQL_OPERATOR_NODE)) - { - return( FALSE); - } - } - return( TRUE); + return( (m_uiNestLevel || + (m_pLastNode && m_pLastNode->eNodeType == SQL_OPERATOR_NODE)) + ? FALSE + : TRUE); } RCODE getNext( @@ -434,15 +411,11 @@ public: RCODE getLast( F_Row ** ppRow); - RCODE evalCriteria( - SQL_VALUE * pSqlValue, - F_Pool * pPool, - F_Row * pRow); - + RCODE reduceTree( + FLMBOOL bFlattenTree); + private: - RCODE allocParseState( void); - RCODE allocValueNode( FLMUINT uiValLen, eSQLValTypes eValType, @@ -477,8 +450,6 @@ private: RCODE convertOperandsToPredicates( void); - RCODE flattenTree( void); - RCODE convertToDNF( void); RCODE getPredKeys( @@ -508,13 +479,16 @@ private: F_Pool m_pool; FLMUINT m_uiLanguage; - SQL_PARSE_STATE * m_pCurrParseState; + SQL_NODE * m_pQuery; + SQL_NODE * m_pCurOperatorNode; + SQL_NODE * m_pLastNode; + FLMUINT m_uiNestLevel; + FLMBOOL m_bExpectingOperator; SQL_SUBQUERY * m_pFirstSubQuery; SQL_SUBQUERY * m_pLastSubQuery; SQL_TABLE * m_pFirstTable; SQL_TABLE * m_pLastTable; FLMBOOL m_bOptimized; - SQL_NODE * m_pQuery; F_Database * m_pDatabase; F_Db * m_pDb; FLMBOOL m_bScan; @@ -547,5 +521,13 @@ RCODE sqlEvalArithOperator( // sqleval.cpp SQL_VALUE * pRValue, eSQLQueryOperators eOperator, SQL_VALUE * pResult); + +RCODE sqlEvalCriteria( // sqleval.cpp + F_Db * pDb, + SQL_NODE * pQueryExpr, + SQL_VALUE ** ppSqlValue, + F_Pool * pPool, + F_Row * pRow, + FLMUINT uiLanguage); #endif // #ifndef FLAIMODBC_H diff --git a/sql/src/updaterow.cpp b/sql/src/updaterow.cpp index 537ea29..dc7138d 100644 --- a/sql/src/updaterow.cpp +++ b/sql/src/updaterow.cpp @@ -769,6 +769,15 @@ FSTATIC RCODE convertValueToStorageFormat( { RCODE rc = NE_SFLM_OK; + // Check for a missing value - return a NULL. + + if (pSqlValue->eValType == SQL_MISSING_VAL) + { + pColValue->uiValueLen = 0; + pColValue->pucColumnValue = NULL; + goto Exit; + } + switch (pColumn->eDataTyp) { case SFLM_STRING_TYPE: @@ -823,7 +832,7 @@ RCODE F_Db::updateSelectedRows( F_COLUMN_VALUE * pColValue; F_COLUMN_ITEM * pColItem; COLUMN_SET * pColSet; - SQL_VALUE sqlValue; + SQL_VALUE * pSqlValue; F_Pool tmpPool; FLMBOOL bValueChanged; @@ -899,14 +908,17 @@ Set_Null_Value: } else { - if (RC_BAD( rc = pColSet->pSqlQuery->evalCriteria( &sqlValue, - &tmpPool, pRow))) + if (RC_BAD( rc = sqlEvalCriteria( this, + pSqlQuery->m_pQuery, + &pSqlValue, + &tmpPool, pRow, + m_pDatabase->m_uiDefaultLanguage))) { goto Exit; } pColumn = m_pDict->getColumn( pTable, pColSet->uiColumnNum); - if (RC_BAD( rc = convertValueToStorageFormat( &sqlValue, + if (RC_BAD( rc = convertValueToStorageFormat( pSqlValue, pColumn, pColValue, &tmpPool))) { goto Exit; @@ -1125,6 +1137,15 @@ RCODE SQLStatement::parseSetColumns( { goto Exit; } + + // Strip out NOT operators, resolve constant arithmetic expressions, + // and weed out boolean constants, but do not flatten the AND + // and OR operators in the query tree. + + if (RC_BAD( rc = pSqlQuery->reduceTree( FALSE))) + { + goto Exit; + } } // Next token should either be a comma or the WHERE keyword, or we diff --git a/sql/src/whereclause.cpp b/sql/src/whereclause.cpp index 393773d..19e16b9 100644 --- a/sql/src/whereclause.cpp +++ b/sql/src/whereclause.cpp @@ -118,49 +118,6 @@ SQLQuery::~SQLQuery() } } -//------------------------------------------------------------------------- -// Desc: Allocate a structure for keeping track of the state of the -// current SQL query. -//------------------------------------------------------------------------- -RCODE SQLQuery::allocParseState( void) -{ - RCODE rc = NE_SFLM_OK; - SQL_PARSE_STATE * pParseState; - - if (!m_pCurrParseState || !m_pCurrParseState->pNext) - { - if (RC_BAD( rc = m_pool.poolCalloc( sizeof( SQL_PARSE_STATE), - (void **)&pParseState))) - { - goto Exit; - } - if ((pParseState->pPrev = m_pCurrParseState) != NULL) - { - m_pCurrParseState->pNext = pParseState; - } - m_pCurrParseState = pParseState; - } - else - { - SQL_PARSE_STATE * pSaveNext; - SQL_PARSE_STATE * pSavePrev; - - m_pCurrParseState = m_pCurrParseState->pNext; - - // Zero out everything except for the prev and next pointers - - pSaveNext = m_pCurrParseState->pNext; - pSavePrev = m_pCurrParseState->pPrev; - f_memset( m_pCurrParseState, 0, sizeof( SQL_PARSE_STATE)); - m_pCurrParseState->pNext = pSaveNext; - m_pCurrParseState->pPrev = pSavePrev; - } - -Exit: - - return( rc); -} - //------------------------------------------------------------------------- // Desc: Unlinks a node from its parent and siblings. This routine assumes // that the test has already been made that the node has a parent. @@ -235,20 +192,6 @@ RCODE SQLQuery::allocValueNode( RCODE rc = NE_SFLM_OK; SQL_NODE * pSQLNode; - if (!m_pCurrParseState) - { - if (RC_BAD( rc = allocParseState())) - { - goto Exit; - } - } - - if (m_pCurrParseState->bExpectingLParen) - { - rc = RC_SET( NE_SFLM_Q_EXPECTING_LPAREN); - goto Exit; - } - if (!expectingOperand()) { rc = RC_SET( NE_SFLM_Q_UNEXPECTED_VALUE); @@ -262,8 +205,8 @@ RCODE SQLQuery::allocValueNode( } pSQLNode = *ppSQLNode; pSQLNode->eNodeType = SQL_VALUE_NODE; - pSQLNode->nd.value.eValType = eValType; - pSQLNode->nd.value.uiFlags = SQL_VAL_IS_CONSTANT; + pSQLNode->currVal.eValType = eValType; + pSQLNode->currVal.uiFlags = SQL_VAL_IS_CONSTANT; // For string and binary data, allocate a buffer. @@ -272,33 +215,33 @@ RCODE SQLQuery::allocValueNode( if (eValType == SQL_UTF8_VAL) { if (RC_BAD( rc = m_pool.poolAlloc( uiValLen, - (void **)&pSQLNode->nd.value.val.str.pszStr))) + (void **)&pSQLNode->currVal.val.str.pszStr))) { goto Exit; } - pSQLNode->nd.value.val.str.uiByteLen = uiValLen; + pSQLNode->currVal.val.str.uiByteLen = uiValLen; } else if (eValType == SQL_BINARY_VAL) { if (RC_BAD( rc = m_pool.poolAlloc( uiValLen, - (void **)&pSQLNode->nd.value.val.bin.pucValue))) + (void **)&pSQLNode->currVal.val.bin.pucValue))) { goto Exit; } - pSQLNode->nd.value.val.bin.uiByteLen = uiValLen; + pSQLNode->currVal.val.bin.uiByteLen = uiValLen; } } - if (m_pCurrParseState->pRootNode) + if (m_pQuery) { - sqlLinkLastChild( m_pCurrParseState->pCurOperatorNode, pSQLNode); + sqlLinkLastChild( m_pCurOperatorNode, pSQLNode); } else { - m_pCurrParseState->pRootNode = pSQLNode; + m_pQuery = pSQLNode; } - m_pCurrParseState->bExpectingOperator = TRUE; - m_pCurrParseState->pLastNode = pSQLNode; + m_bExpectingOperator = TRUE; + m_pLastNode = pSQLNode; Exit: @@ -316,23 +259,6 @@ RCODE SQLQuery::addOperator( SQL_NODE * pSQLNode; SQL_NODE * pParentNode; - if (!m_pCurrParseState) - { - if (RC_BAD( rc = allocParseState())) - { - goto Exit; - } - } - - // If we are expecting a left paren (for a function), that is - // the only thing that is acceptable at this point. - - if (m_pCurrParseState->bExpectingLParen && eOperator != SQL_LPAREN_OP) - { - rc = RC_SET( NE_SFLM_Q_EXPECTING_LPAREN); - goto Exit; - } - if (eOperator == SQL_MINUS_OP && expectingOperand()) { eOperator = SQL_NEG_OP; @@ -349,8 +275,7 @@ RCODE SQLQuery::addOperator( rc = RC_SET( NE_SFLM_Q_UNEXPECTED_LPAREN); goto Exit; } - m_pCurrParseState->uiNestLevel++; - m_pCurrParseState->bExpectingLParen = FALSE; + m_uiNestLevel++; goto Exit; case SQL_RPAREN_OP: @@ -359,12 +284,12 @@ RCODE SQLQuery::addOperator( rc = RC_SET( NE_SFLM_Q_UNEXPECTED_RPAREN); goto Exit; } - if (!m_pCurrParseState->uiNestLevel) + if (!m_uiNestLevel) { rc = RC_SET( NE_SFLM_Q_UNMATCHED_RPAREN); goto Exit; } - m_pCurrParseState->uiNestLevel--; + m_uiNestLevel--; goto Exit; @@ -416,12 +341,12 @@ RCODE SQLQuery::addOperator( pSQLNode->eNodeType = SQL_OPERATOR_NODE; pSQLNode->nd.op.eOperator = eOperator; pSQLNode->nd.op.uiCompareRules = uiCompareRules; - pSQLNode->uiNestLevel = m_pCurrParseState->uiNestLevel; + pSQLNode->uiNestLevel = m_uiNestLevel; // Go up the stack until an operator whose nest level or precedence is < // this one's is encountered, then link this one in as the last child - pParentNode = m_pCurrParseState->pCurOperatorNode; + pParentNode = m_pCurOperatorNode; while (pParentNode && (pParentNode->uiNestLevel > pSQLNode->uiNestLevel || (pParentNode->uiNestLevel == pSQLNode->uiNestLevel && @@ -432,11 +357,11 @@ RCODE SQLQuery::addOperator( } if (!pParentNode) { - if (m_pCurrParseState->pRootNode) + if (m_pQuery) { - sqlLinkLastChild( pSQLNode, m_pCurrParseState->pRootNode); + sqlLinkLastChild( pSQLNode, m_pQuery); } - m_pCurrParseState->pRootNode = pSQLNode; + m_pQuery = pSQLNode; } else if (eOperator == SQL_NOT_OP || eOperator == SQL_NEG_OP) { @@ -466,7 +391,7 @@ RCODE SQLQuery::addOperator( #endif sqlLinkLastChild( pParentNode, pSQLNode); - flmAssert( !m_pCurrParseState->bExpectingOperator); + flmAssert( !m_bExpectingOperator); } else { @@ -502,9 +427,9 @@ RCODE SQLQuery::addOperator( sqlLinkLastChild( pParentNode, pSQLNode); } - m_pCurrParseState->pCurOperatorNode = pSQLNode; - m_pCurrParseState->bExpectingOperator = FALSE; - m_pCurrParseState->pLastNode = pSQLNode; + m_pCurOperatorNode = pSQLNode; + m_bExpectingOperator = FALSE; + m_pLastNode = pSQLNode; Exit: @@ -528,16 +453,16 @@ RCODE SQLQuery::allocOperandNode( } pSQLNode->eNodeType = eNodeType; - if (m_pCurrParseState->pRootNode) + if (m_pQuery) { - sqlLinkLastChild( m_pCurrParseState->pCurOperatorNode, pSQLNode); + sqlLinkLastChild( m_pCurOperatorNode, pSQLNode); } else { - m_pCurrParseState->pRootNode = pSQLNode; + m_pQuery = pSQLNode; } - m_pCurrParseState->bExpectingOperator = TRUE; - m_pCurrParseState->pLastNode = *ppSQLNode = pSQLNode; + m_bExpectingOperator = TRUE; + m_pLastNode = *ppSQLNode = pSQLNode; Exit: @@ -554,14 +479,6 @@ RCODE SQLQuery::addTable( RCODE rc = NE_SFLM_OK; SQL_TABLE * pTable; - if (!m_pCurrParseState) - { - if (RC_BAD( rc = allocParseState())) - { - goto Exit; - } - } - // Add or find the table structure for the node. pTable = m_pFirstTable; @@ -608,14 +525,6 @@ RCODE SQLQuery::addColumn( SQL_NODE * pSQLNode; SQL_TABLE * pTable; - if (!m_pCurrParseState) - { - if (RC_BAD( rc = allocParseState())) - { - goto Exit; - } - } - // Must be expecting an operand if (!expectingOperand()) @@ -652,14 +561,6 @@ RCODE SQLQuery::addUINT64( RCODE rc = NE_SFLM_OK; SQL_NODE * pSQLNode; - if (!m_pCurrParseState) - { - if (RC_BAD( rc = allocParseState())) - { - goto Exit; - } - } - // Must be expecting an operand if (!expectingOperand()) @@ -674,9 +575,9 @@ RCODE SQLQuery::addUINT64( { goto Exit; } - pSQLNode->nd.value.eValType = SQL_UINT64_VAL; - pSQLNode->nd.value.uiFlags |= SQL_VAL_IS_CONSTANT; - pSQLNode->nd.value.val.ui64Val = ui64Num; + pSQLNode->currVal.eValType = SQL_UINT64_VAL; + pSQLNode->currVal.uiFlags |= SQL_VAL_IS_CONSTANT; + pSQLNode->currVal.val.ui64Val = ui64Num; Exit: @@ -692,14 +593,6 @@ RCODE SQLQuery::addUINT( RCODE rc = NE_SFLM_OK; SQL_NODE * pSQLNode; - if (!m_pCurrParseState) - { - if (RC_BAD( rc = allocParseState())) - { - goto Exit; - } - } - // Must be expecting an operand if (!expectingOperand()) @@ -714,9 +607,9 @@ RCODE SQLQuery::addUINT( { goto Exit; } - pSQLNode->nd.value.eValType = SQL_UINT_VAL; - pSQLNode->nd.value.uiFlags |= SQL_VAL_IS_CONSTANT; - pSQLNode->nd.value.val.uiVal = uiNum; + pSQLNode->currVal.eValType = SQL_UINT_VAL; + pSQLNode->currVal.uiFlags |= SQL_VAL_IS_CONSTANT; + pSQLNode->currVal.val.uiVal = uiNum; Exit: @@ -732,14 +625,6 @@ RCODE SQLQuery::addINT64( RCODE rc = NE_SFLM_OK; SQL_NODE * pSQLNode; - if (!m_pCurrParseState) - { - if (RC_BAD( rc = allocParseState())) - { - goto Exit; - } - } - // Must be expecting an operand if (!expectingOperand()) @@ -754,9 +639,9 @@ RCODE SQLQuery::addINT64( { goto Exit; } - pSQLNode->nd.value.eValType = SQL_INT64_VAL; - pSQLNode->nd.value.uiFlags |= SQL_VAL_IS_CONSTANT; - pSQLNode->nd.value.val.i64Val = i64Num; + pSQLNode->currVal.eValType = SQL_INT64_VAL; + pSQLNode->currVal.uiFlags |= SQL_VAL_IS_CONSTANT; + pSQLNode->currVal.val.i64Val = i64Num; Exit: @@ -772,14 +657,6 @@ RCODE SQLQuery::addINT( RCODE rc = NE_SFLM_OK; SQL_NODE * pSQLNode; - if (!m_pCurrParseState) - { - if (RC_BAD( rc = allocParseState())) - { - goto Exit; - } - } - // Must be expecting an operand if (!expectingOperand()) @@ -794,9 +671,9 @@ RCODE SQLQuery::addINT( { goto Exit; } - pSQLNode->nd.value.eValType = SQL_INT_VAL; - pSQLNode->nd.value.uiFlags |= SQL_VAL_IS_CONSTANT; - pSQLNode->nd.value.val.iVal = iNum; + pSQLNode->currVal.eValType = SQL_INT_VAL; + pSQLNode->currVal.uiFlags |= SQL_VAL_IS_CONSTANT; + pSQLNode->currVal.val.iVal = iNum; Exit: @@ -813,14 +690,6 @@ RCODE SQLQuery::addBoolean( RCODE rc = NE_SFLM_OK; SQL_NODE * pSQLNode; - if (!m_pCurrParseState) - { - if (RC_BAD( rc = allocParseState())) - { - goto Exit; - } - } - // Must be expecting an operand if (!expectingOperand()) @@ -835,19 +704,19 @@ RCODE SQLQuery::addBoolean( { goto Exit; } - pSQLNode->nd.value.eValType = SQL_BOOL_VAL; - pSQLNode->nd.value.uiFlags |= SQL_VAL_IS_CONSTANT; + pSQLNode->currVal.eValType = SQL_BOOL_VAL; + pSQLNode->currVal.uiFlags |= SQL_VAL_IS_CONSTANT; if (bUnknown) { - pSQLNode->nd.value.val.eBool = SQL_UNKNOWN; + pSQLNode->currVal.val.eBool = SQL_UNKNOWN; } else if (bValue) { - pSQLNode->nd.value.val.eBool = SQL_TRUE; + pSQLNode->currVal.val.eBool = SQL_TRUE; } else { - pSQLNode->nd.value.val.eBool = SQL_FALSE; + pSQLNode->currVal.val.eBool = SQL_FALSE; } Exit: @@ -867,14 +736,6 @@ RCODE SQLQuery::addUTF8String( SQL_NODE * pSQLNode; FLMBYTE * pszTmp; - if (!m_pCurrParseState) - { - if (RC_BAD( rc = allocParseState())) - { - goto Exit; - } - } - // Must be expecting an operand if (!expectingOperand()) @@ -898,11 +759,11 @@ RCODE SQLQuery::addUTF8String( { goto Exit; } - pSQLNode->nd.value.eValType = SQL_UTF8_VAL; - pSQLNode->nd.value.uiFlags |= SQL_VAL_IS_CONSTANT; - pSQLNode->nd.value.val.str.pszStr = pszTmp; - pSQLNode->nd.value.val.str.uiByteLen = uiStrLen + 1; - pSQLNode->nd.value.val.str.uiNumChars = uiNumChars; + pSQLNode->currVal.eValType = SQL_UTF8_VAL; + pSQLNode->currVal.uiFlags |= SQL_VAL_IS_CONSTANT; + pSQLNode->currVal.val.str.pszStr = pszTmp; + pSQLNode->currVal.val.str.uiByteLen = uiStrLen + 1; + pSQLNode->currVal.val.str.uiNumChars = uiNumChars; f_memcpy( pszTmp, pszUTF8Str, uiStrLen); pszTmp [uiStrLen] = 0; @@ -912,7 +773,7 @@ RCODE SQLQuery::addUTF8String( { if (*pszTmp == '*') { - pSQLNode->nd.value.uiFlags |= SQL_VAL_HAS_WILDCARDS; + pSQLNode->currVal.uiFlags |= SQL_VAL_HAS_WILDCARDS; break; } else if (*pszTmp == '\\') @@ -946,14 +807,6 @@ RCODE SQLQuery::addBinary( SQL_NODE * pSQLNode; FLMBYTE * pucTmp; - if (!m_pCurrParseState) - { - if (RC_BAD( rc = allocParseState())) - { - goto Exit; - } - } - // Must be expecting an operand if (!expectingOperand()) @@ -972,10 +825,10 @@ RCODE SQLQuery::addBinary( { goto Exit; } - pSQLNode->nd.value.eValType = SQL_BINARY_VAL; - pSQLNode->nd.value.uiFlags |= SQL_VAL_IS_CONSTANT; - pSQLNode->nd.value.val.bin.uiByteLen = uiValueLen; - pSQLNode->nd.value.val.bin.pucValue = pucTmp; + pSQLNode->currVal.eValType = SQL_BINARY_VAL; + pSQLNode->currVal.uiFlags |= SQL_VAL_IS_CONSTANT; + pSQLNode->currVal.val.bin.uiByteLen = uiValueLen; + pSQLNode->currVal.val.bin.pucValue = pucTmp; f_memcpy( pucTmp, pucValue, uiValueLen); Exit: