/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_connectivity.hxx"
#include "file/fcomp.hxx"
#include <tools/debug.hxx>
#include "TConnection.hxx"
#include "connectivity/sqlparse.hxx"
#include "file/fanalyzer.hxx"
#include <com/sun/star/sdbc/XColumnLocate.hpp>
#include <com/sun/star/util/DateTime.hpp>
#include <com/sun/star/util/Date.hpp>
#include <com/sun/star/util/Time.hpp>
#include "connectivity/dbexception.hxx"
#include "connectivity/dbconversion.hxx"
#include <com/sun/star/sdb/SQLFilterOperator.hpp>
#include "resource/file_res.hrc"
#include "file/FStringFunctions.hxx"
#include "file/FDateFunctions.hxx"
#include "file/FNumericFunctions.hxx"
#include "file/FConnection.hxx"
#include <com/sun/star/sdb/SQLFilterOperator.hpp>

using namespace connectivity;
using namespace connectivity::file;
using namespace com::sun::star::uno;
using namespace com::sun::star::sdbc;
using namespace com::sun::star::sdb;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::util;

DBG_NAME(OPredicateCompiler)
//------------------------------------------------------------------
OPredicateCompiler::OPredicateCompiler(OSQLAnalyzer* pAnalyzer)//,OCursor& rCurs)
                     //	: m_rCursor(rCurs)
                     : m_pAnalyzer(pAnalyzer)
                     , m_nParamCounter(0)
                     , m_bORCondition(FALSE)
{
    DBG_CTOR(OPredicateCompiler,NULL);
}

//------------------------------------------------------------------
OPredicateCompiler::~OPredicateCompiler()
{
    Clean();
    DBG_DTOR(OPredicateCompiler,NULL);
}
// -----------------------------------------------------------------------------
void OPredicateCompiler::dispose()
{
    Clean();
    m_orgColumns		= NULL;
m_xIndexes.clear();
}
//------------------------------------------------------------------
//	inline OCursor& OPredicateCompiler::Cursor() const {return m_rCursor;}
//------------------------------------------------------------------
void OPredicateCompiler::start(OSQLParseNode* pSQLParseNode)
{
    if (!pSQLParseNode)
        return;

    m_nParamCounter = 0;
    // Parse Tree analysieren (je nach Statement-Typ)
    // und Zeiger auf WHERE-Klausel setzen:
    OSQLParseNode * pWhereClause = NULL;
    OSQLParseNode * pOrderbyClause = NULL;

    if (SQL_ISRULE(pSQLParseNode,select_statement))
    {
        DBG_ASSERT(pSQLParseNode->count() >= 4,"OFILECursor: Fehler im Parse Tree");

        OSQLParseNode * pTableExp = pSQLParseNode->getChild(3);
        DBG_ASSERT(pTableExp != NULL,"Fehler im Parse Tree");
        DBG_ASSERT(SQL_ISRULE(pTableExp,table_exp)," Fehler im Parse Tree");
        DBG_ASSERT(pTableExp->count() == 5,"Fehler im Parse Tree");

        // check that we don't use anything other than count(*) as function
        OSQLParseNode* pSelection = pSQLParseNode->getChild(2);
        if ( SQL_ISRULE(pSelection,scalar_exp_commalist) )
        {
            for (sal_uInt32 i = 0; i < pSelection->count(); i++)
            {
                OSQLParseNode *pColumnRef = pSelection->getChild(i)->getChild(0);
                if ( SQL_ISRULE(pColumnRef,general_set_fct) && pColumnRef->count() != 4 )
                {
                    m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_COMPLEX_COUNT,NULL);
                }
            }
        }


        pWhereClause	= pTableExp->getChild(1);
        pOrderbyClause	= pTableExp->getChild(4);
    }
    else if (SQL_ISRULE(pSQLParseNode,update_statement_searched))
    {
        DBG_ASSERT(pSQLParseNode->count() == 5,"OFILECursor: Fehler im Parse Tree");
        pWhereClause = pSQLParseNode->getChild(4);
    }
    else if (SQL_ISRULE(pSQLParseNode,delete_statement_searched))
    {
        DBG_ASSERT(pSQLParseNode->count() == 4,"Fehler im Parse Tree");
        pWhereClause = pSQLParseNode->getChild(3);
    }
    else
            // Anderes Statement. Keine Selektionskriterien.
        return;

    if (SQL_ISRULE(pWhereClause,where_clause))
    {
        // Wenn es aber eine where_clause ist, dann darf sie nicht leer sein:
        DBG_ASSERT(pWhereClause->count() == 2,"OFILECursor: Fehler im Parse Tree");

        OSQLParseNode * pComparisonPredicate = pWhereClause->getChild(1);
        DBG_ASSERT(pComparisonPredicate != NULL,"OFILECursor: Fehler im Parse Tree");

        execute( pComparisonPredicate );
    }
    else
    {
        // Die Where Clause ist meistens optional, d. h. es koennte sich auch
        // um "optional_where_clause" handeln.
        DBG_ASSERT(SQL_ISRULE(pWhereClause,opt_where_clause),"OPredicateCompiler: Fehler im Parse Tree");
    }
}

//------------------------------------------------------------------
OOperand* OPredicateCompiler::execute(OSQLParseNode* pPredicateNode)
{
    OOperand* pOperand = NULL;
    if (pPredicateNode->count() == 3 &&							// Ausdruck is geklammert
        SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"(") &&
        SQL_ISPUNCTUATION(pPredicateNode->getChild(2),")"))
    {
        execute(pPredicateNode->getChild(1));
    }
    else if ((SQL_ISRULE(pPredicateNode,search_condition) || (SQL_ISRULE(pPredicateNode,boolean_term)))
                            &&			// AND/OR-Verknuepfung:
                            pPredicateNode->count() == 3)
    {
        execute(pPredicateNode->getChild(0));						    // Bearbeiten des linken Zweigs
        execute(pPredicateNode->getChild(2));							// Bearbeiten des rechten Zweigs

        if (SQL_ISTOKEN(pPredicateNode->getChild(1),OR))				// OR-Operator
        {
            m_aCodeList.push_back(new OOp_OR());
            m_bORCondition = sal_True;
        }
        else if (SQL_ISTOKEN(pPredicateNode->getChild(1),AND))		// AND-Operator
            m_aCodeList.push_back(new OOp_AND());
        else
        {
            DBG_ERROR("OPredicateCompiler: Fehler im Parse Tree");
        }
    }
    else if (SQL_ISRULE(pPredicateNode,boolean_factor))
    {
        execute(pPredicateNode->getChild(1));
        m_aCodeList.push_back(new OOp_NOT());
    }
    else if (SQL_ISRULE(pPredicateNode,comparison_predicate))
    {
        execute_COMPARE(pPredicateNode);
    }
    else if (SQL_ISRULE(pPredicateNode,like_predicate))
    {
        execute_LIKE(pPredicateNode);
    }
    else if (SQL_ISRULE(pPredicateNode,between_predicate))
    {
        execute_BETWEEN(pPredicateNode);
    }
    else if (SQL_ISRULE(pPredicateNode,test_for_null))
    {
        execute_ISNULL(pPredicateNode);
    }
    else if(SQL_ISRULE(pPredicateNode,num_value_exp))
    {
        execute(pPredicateNode->getChild(0));						    // Bearbeiten des linken Zweigs
        execute(pPredicateNode->getChild(2));							// Bearbeiten des rechten Zweigs
        if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"+"))
        {
            m_aCodeList.push_back(new OOp_ADD());
        }
        else if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"-"))
            m_aCodeList.push_back(new OOp_SUB());
        else
        {
            DBG_ERROR("OPredicateCompiler: Fehler im Parse Tree num_value_exp");
        }
    }
    else if(SQL_ISRULE(pPredicateNode,term))
    {
        execute(pPredicateNode->getChild(0));						    // Bearbeiten des linken Zweigs
        execute(pPredicateNode->getChild(2));							// Bearbeiten des rechten Zweigs
        if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"*"))
        {
            m_aCodeList.push_back(new OOp_MUL());
        }
        else if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"/"))
            m_aCodeList.push_back(new OOp_DIV());
        else
        {
            DBG_ERROR("OPredicateCompiler: Fehler im Parse Tree num_value_exp");
        }
    }
    else
        pOperand = execute_Operand(pPredicateNode);						// jetzt werden nur einfache Operanden verarbeitet

    return pOperand;
}

//------------------------------------------------------------------
OOperand* OPredicateCompiler::execute_COMPARE(OSQLParseNode* pPredicateNode)  throw(SQLException, RuntimeException)
{
    DBG_ASSERT(pPredicateNode->count() == 3,"OFILECursor: Fehler im Parse Tree");

    if ( !(SQL_ISRULE(pPredicateNode->getChild(0),column_ref)				||
          pPredicateNode->getChild(2)->getNodeType() == SQL_NODE_STRING 	||
          pPredicateNode->getChild(2)->getNodeType() == SQL_NODE_INTNUM 	||
          pPredicateNode->getChild(2)->getNodeType() == SQL_NODE_APPROXNUM	||
          SQL_ISTOKEN(pPredicateNode->getChild(2),TRUE)						||
          SQL_ISTOKEN(pPredicateNode->getChild(2),FALSE)					||
          SQL_ISRULE(pPredicateNode->getChild(2),parameter)					||
          // odbc date
          SQL_ISRULE(pPredicateNode->getChild(2),set_fct_spec)				||
          SQL_ISRULE(pPredicateNode->getChild(2),position_exp)				||
          SQL_ISRULE(pPredicateNode->getChild(2),char_substring_fct)		||
          // upper, lower etc.
          SQL_ISRULE(pPredicateNode->getChild(2),fold)) )
    {
        m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,NULL);
        return NULL;
    }

    sal_Int32 ePredicateType( SQLFilterOperator::EQUAL );
    OSQLParseNode *pPrec = pPredicateNode->getChild(1);

    if (pPrec->getNodeType() == SQL_NODE_EQUAL)
        ePredicateType = SQLFilterOperator::EQUAL;
    else if (pPrec->getNodeType() == SQL_NODE_NOTEQUAL)
        ePredicateType = SQLFilterOperator::NOT_EQUAL;
    else if (pPrec->getNodeType() == SQL_NODE_LESS)
        ePredicateType = SQLFilterOperator::LESS;
    else if (pPrec->getNodeType() == SQL_NODE_LESSEQ)
        ePredicateType = SQLFilterOperator::LESS_EQUAL;
    else if (pPrec->getNodeType() == SQL_NODE_GREATEQ)
        ePredicateType = SQLFilterOperator::GREATER_EQUAL;
    else if (pPrec->getNodeType() == SQL_NODE_GREAT)
        ePredicateType = SQLFilterOperator::GREATER;
    else
        OSL_ENSURE( false, "OPredicateCompiler::execute_COMPARE: unexpected node type!" );

    execute(pPredicateNode->getChild(0));
    execute(pPredicateNode->getChild(2));
    m_aCodeList.push_back( new OOp_COMPARE(ePredicateType) );

    return NULL;
}

//------------------------------------------------------------------
OOperand* OPredicateCompiler::execute_LIKE(OSQLParseNode* pPredicateNode) throw(SQLException, RuntimeException)
{
    DBG_ASSERT(pPredicateNode->count() == 2,"OFILECursor: Fehler im Parse Tree");
    const OSQLParseNode* pPart2 = pPredicateNode->getChild(1);

    sal_Unicode cEscape = L'\0';
    const bool bNotLike = pPart2->getChild(0)->isToken();

    OSQLParseNode* pAtom		= pPart2->getChild(pPart2->count()-2);
    OSQLParseNode* pOptEscape	= pPart2->getChild(pPart2->count()-1);

    if (!(pAtom->getNodeType() == SQL_NODE_STRING || SQL_ISRULE(pAtom,parameter)))
    {
        m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_INVALID_LIKE_STRING,NULL);
    }
    if (pOptEscape->count() != 0)
    {
        if (pOptEscape->count() != 2)
        {
            m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_INVALID_LIKE_STRING,NULL);
        }
        OSQLParseNode *pEscNode = pOptEscape->getChild(1);
        if (pEscNode->getNodeType() != SQL_NODE_STRING)
        {
            m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_INVALID_LIKE_STRING,NULL);
        }
        else
            cEscape = pEscNode->getTokenValue().toChar();
    }

    execute(pPredicateNode->getChild(0));
    execute(pAtom);

    OBoolOperator* pOperator = bNotLike
                                    ? new OOp_NOTLIKE(cEscape)
                                    : new OOp_LIKE(cEscape);
    m_aCodeList.push_back(pOperator);

    return NULL;
}
//------------------------------------------------------------------
OOperand* OPredicateCompiler::execute_BETWEEN(OSQLParseNode* pPredicateNode) throw(SQLException, RuntimeException)
{
    DBG_ASSERT(pPredicateNode->count() == 2,"OFILECursor: Fehler im Parse Tree");

    OSQLParseNode* pColumn = pPredicateNode->getChild(0);
    const OSQLParseNode* pPart2 = pPredicateNode->getChild(1);
    OSQLParseNode* p1stValue = pPart2->getChild(2);
    OSQLParseNode* p2ndtValue = pPart2->getChild(4);

    if (
            !(p1stValue->getNodeType() == SQL_NODE_STRING || SQL_ISRULE(p1stValue,parameter))
        &&	!(p2ndtValue->getNodeType() == SQL_NODE_STRING || SQL_ISRULE(p2ndtValue,parameter))
        )
    {
        m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_INVALID_BETWEEN,NULL);
    }

    sal_Bool bNot = SQL_ISTOKEN(pPart2->getChild(0),NOT);

    OOperand* pColumnOp = execute(pColumn);
    OOperand* pOb1 = execute(p1stValue);
    OBoolOperator* pOperator = new OOp_COMPARE(bNot ? SQLFilterOperator::LESS_EQUAL : SQLFilterOperator::GREATER);
    m_aCodeList.push_back(pOperator);

    execute(pColumn);
    OOperand* pOb2 = execute(p2ndtValue);
    pOperator = new OOp_COMPARE(bNot ? SQLFilterOperator::GREATER_EQUAL : SQLFilterOperator::LESS);
    m_aCodeList.push_back(pOperator);

    if ( pColumnOp && pOb1 && pOb2 )
    {
        switch(pColumnOp->getDBType())
        {
            case DataType::CHAR:
            case DataType::VARCHAR:
            case DataType::LONGVARCHAR:
                pOb1->setValue(pOb1->getValue().getString());
                pOb2->setValue(pOb2->getValue().getString());
                break;
            case DataType::DECIMAL:
            case DataType::NUMERIC:
                pOb1->setValue((double)pOb1->getValue());
                pOb2->setValue((double)pOb2->getValue());
                break;
            case DataType::FLOAT:
                pOb1->setValue((float)pOb1->getValue());
                pOb2->setValue((float)pOb2->getValue());
                break;
            case DataType::DOUBLE:
            case DataType::REAL:
                pOb1->setValue((double)pOb1->getValue());
                pOb2->setValue((double)pOb2->getValue());
                break;
            case DataType::DATE:
                pOb1->setValue((Date)pOb1->getValue());
                pOb2->setValue((Date)pOb2->getValue());
                break;
            case DataType::TIME:
                pOb1->setValue((Time)pOb1->getValue());
                pOb2->setValue((Time)pOb2->getValue());
                break;
            case DataType::TIMESTAMP:
                pOb1->setValue((DateTime)pOb1->getValue());
                pOb2->setValue((DateTime)pOb2->getValue());
                break;
        }
    }



    OBoolOperator* pBoolOp = NULL;
    if ( bNot )
        pBoolOp = new OOp_OR();
    else
        pBoolOp = new OOp_AND();
    m_aCodeList.push_back(pBoolOp);

    return NULL;
}
//------------------------------------------------------------------
OOperand* OPredicateCompiler::execute_ISNULL(OSQLParseNode* pPredicateNode)	throw(SQLException, RuntimeException)
{
    DBG_ASSERT(pPredicateNode->count() == 2,"OFILECursor: Fehler im Parse Tree");
    const OSQLParseNode* pPart2 = pPredicateNode->getChild(1);
    DBG_ASSERT(SQL_ISTOKEN(pPart2->getChild(0),IS),"OFILECursor: Fehler im Parse Tree");

    sal_Int32 ePredicateType;
    if (SQL_ISTOKEN(pPart2->getChild(1),NOT))
        ePredicateType = SQLFilterOperator::NOT_SQLNULL;
    else
        ePredicateType = SQLFilterOperator::SQLNULL;

    execute(pPredicateNode->getChild(0));
    OBoolOperator* pOperator = (ePredicateType == SQLFilterOperator::SQLNULL) ?
                                new OOp_ISNULL() : new OOp_ISNOTNULL();
    m_aCodeList.push_back(pOperator);

    return NULL;
}
//------------------------------------------------------------------
OOperand* OPredicateCompiler::execute_Operand(OSQLParseNode* pPredicateNode) throw(SQLException, RuntimeException)
{
    OOperand* pOperand = NULL;

    if (SQL_ISRULE(pPredicateNode,column_ref))
    {
        ::rtl::OUString	aColumnName;
        if (pPredicateNode->count() == 1)
        {
            aColumnName = pPredicateNode->getChild(0)->getTokenValue();
        }
        else if (pPredicateNode->count() == 3)
        {
            ::rtl::OUString aTableName = pPredicateNode->getChild(0)->getTokenValue();
            if(SQL_ISRULE(pPredicateNode->getChild(2),column_val))
                aColumnName = pPredicateNode->getChild(2)->getChild(0)->getTokenValue();
            else
                aColumnName = pPredicateNode->getChild(2)->getTokenValue();
        }

        if(!m_orgColumns->hasByName(aColumnName))
        {
            const ::rtl::OUString sError( m_pAnalyzer->getConnection()->getResources().getResourceStringWithSubstitution(
                    STR_INVALID_COLUMNNAME,
                    "$columnname$", aColumnName
                 ) );
            ::dbtools::throwGenericSQLException( sError, NULL );
        }
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet> xCol;
        try
        {
            if (m_orgColumns->getByName(aColumnName) >>= xCol)
            {
                pOperand = m_pAnalyzer->createOperandAttr(Reference< XColumnLocate>(m_orgColumns,UNO_QUERY)->findColumn(aColumnName),xCol,m_xIndexes);
            }
            else
            {// Column existiert nicht im Resultset
                const ::rtl::OUString sError( m_pAnalyzer->getConnection()->getResources().getResourceStringWithSubstitution(
                    STR_INVALID_COLUMNNAME,
                    "$columnname$", aColumnName
                 ) );
                ::dbtools::throwGenericSQLException( sError, NULL );
            }
        }
        catch(Exception &)
        {
            OSL_ENSURE(0,"OPredicateCompiler::execute_Operand Exception");
        }
    }
    else if (SQL_ISRULE(pPredicateNode,parameter))
    {
        pOperand = new OOperandParam(pPredicateNode, ++m_nParamCounter);
    }
    else if (pPredicateNode->getNodeType() == SQL_NODE_STRING ||
             pPredicateNode->getNodeType() == SQL_NODE_INTNUM ||
             pPredicateNode->getNodeType() == SQL_NODE_APPROXNUM ||
             pPredicateNode->getNodeType() == SQL_NODE_NAME ||
             SQL_ISTOKEN(pPredicateNode,TRUE) ||
             SQL_ISTOKEN(pPredicateNode,FALSE) ||
             SQL_ISRULE(pPredicateNode,parameter))
    {
        pOperand = new OOperandConst(*pPredicateNode, pPredicateNode->getTokenValue());
    }
    else if((pPredicateNode->count() == 2) &&
            (SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"+") || SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"-")) &&
            pPredicateNode->getChild(1)->getNodeType() == SQL_NODE_INTNUM)
    { // falls -1 bzw. +1 vorhanden ist
        ::rtl::OUString aValue(pPredicateNode->getChild(0)->getTokenValue());
        aValue += pPredicateNode->getChild(1)->getTokenValue();
        pOperand = new OOperandConst(*pPredicateNode->getChild(1), aValue);
    }
    else if( SQL_ISRULE(pPredicateNode,set_fct_spec) && SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"{") )
    {
        const OSQLParseNode* pODBCNode = pPredicateNode->getChild(1);
        const OSQLParseNode* pODBCNodeChild = pODBCNode->getChild(0);

        // Odbc Date or time
        if (pODBCNodeChild->getNodeType() == SQL_NODE_KEYWORD && (
            SQL_ISTOKEN(pODBCNodeChild,D) ||
            SQL_ISTOKEN(pODBCNodeChild,T) ||
            SQL_ISTOKEN(pODBCNodeChild,TS) ))
        {
            ::rtl::OUString sDateTime = pODBCNode->getChild(1)->getTokenValue();
            pOperand = new OOperandConst(*pODBCNode->getChild(1), sDateTime);
            if(SQL_ISTOKEN(pODBCNodeChild,D))
            {
                pOperand->setValue(::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(sDateTime)));
            }
            else if(SQL_ISTOKEN(pODBCNodeChild,T))
            {
                pOperand->setValue(::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(sDateTime)));
            }
            else if(SQL_ISTOKEN(pODBCNodeChild,TS))
            {
                pOperand->setValue(::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDateTime(sDateTime)));
            }
        }
        else
            m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,NULL);

    }
    else if( SQL_ISRULE(pPredicateNode,fold) )
    {
        execute_Fold(pPredicateNode);
    }
    else if(	SQL_ISRULE(pPredicateNode,set_fct_spec)
            ||	SQL_ISRULE(pPredicateNode,position_exp)
            ||	SQL_ISRULE(pPredicateNode,char_substring_fct)
            )
    {
        executeFunction(pPredicateNode);
    }
    else if( SQL_ISRULE(pPredicateNode,length_exp) )
    {
        executeFunction(pPredicateNode->getChild(0));
    }
    else
    {
        m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,NULL);
    }
    if (pOperand)
        m_aCodeList.push_back(pOperand);
    return pOperand;
}

////////////////////////////////////////////////////////////////////////////////////////
sal_Bool OPredicateInterpreter::evaluate(OCodeList& rCodeList)
{
    static sal_Bool bResult;

    OCodeList::iterator aIter = rCodeList.begin();
    if (!(*aIter))
        return sal_True;        // kein Praedikat

    for(;aIter != rCodeList.end();++aIter)
    {
        OOperand* pOperand = PTR_CAST(OOperand,(*aIter));
        if (pOperand)
            m_aStack.push(pOperand);
        else
            ((OOperator *)(*aIter))->Exec(m_aStack);
    }

    OOperand* pOperand = m_aStack.top();
    m_aStack.pop();

    DBG_ASSERT(m_aStack.size() == 0, "StackFehler");
    DBG_ASSERT(pOperand, "StackFehler");

    bResult = pOperand->isValid();
    if (IS_TYPE(OOperandResult,pOperand))
        delete pOperand;
    return bResult;
}
// -----------------------------------------------------------------------------
void OPredicateInterpreter::evaluateSelection(OCodeList& rCodeList,ORowSetValueDecoratorRef& _rVal)
{
    OCodeList::iterator aIter = rCodeList.begin();
    if (!(*aIter))
        return ;        // kein Praedikat

    for(;aIter != rCodeList.end();++aIter)
    {
        OOperand* pOperand = PTR_CAST(OOperand,(*aIter));
        if (pOperand)
            m_aStack.push(pOperand);
        else
            ((OOperator *)(*aIter))->Exec(m_aStack);
    }

    OOperand* pOperand = m_aStack.top();
    m_aStack.pop();

    DBG_ASSERT(m_aStack.size() == 0, "StackFehler");
    DBG_ASSERT(pOperand, "StackFehler");

    (*_rVal) = pOperand->getValue();
    if (IS_TYPE(OOperandResult,pOperand))
        delete pOperand;
}
// -----------------------------------------------------------------------------
OOperand* OPredicateCompiler::execute_Fold(OSQLParseNode* pPredicateNode)	throw(SQLException, RuntimeException)
{
    DBG_ASSERT(pPredicateNode->count() >= 4,"OFILECursor: Fehler im Parse Tree");

    sal_Bool bUpper = SQL_ISTOKEN(pPredicateNode->getChild(0),UPPER);

    execute(pPredicateNode->getChild(2));
    OOperator* pOperator = NULL;
    if ( bUpper )
        pOperator = new OOp_Upper();
    else
        pOperator = new OOp_Lower();

    m_aCodeList.push_back(pOperator);
    return NULL;
}
// -----------------------------------------------------------------------------
OOperand* OPredicateCompiler::executeFunction(OSQLParseNode* pPredicateNode)	throw(SQLException, RuntimeException)
{
    OOperator* pOperator = NULL;

    OSL_ENSURE(pPredicateNode->getChild(0)->isToken(),"The first one must be the name of the function!");
    sal_Int32 nTokenId = pPredicateNode->getChild(0)->getTokenID();
    switch ( nTokenId )
    {
        case SQL_TOKEN_CHAR_LENGTH:
        case SQL_TOKEN_LENGTH:
        case SQL_TOKEN_OCTET_LENGTH:
        case SQL_TOKEN_ASCII:
        case SQL_TOKEN_LCASE:
        case SQL_TOKEN_LTRIM:
        case SQL_TOKEN_RTRIM:
        case SQL_TOKEN_SPACE:
        case SQL_TOKEN_UCASE:
        case SQL_TOKEN_ABS:
        case SQL_TOKEN_ACOS:
        case SQL_TOKEN_ASIN:
        case SQL_TOKEN_ATAN:
        case SQL_TOKEN_CEILING:
        case SQL_TOKEN_COS:
        case SQL_TOKEN_DEGREES:
        case SQL_TOKEN_EXP:
        case SQL_TOKEN_FLOOR:
        case SQL_TOKEN_LOG10:
        case SQL_TOKEN_LN:
        case SQL_TOKEN_RADIANS:
        case SQL_TOKEN_SIGN:
        case SQL_TOKEN_SIN:
        case SQL_TOKEN_SQRT:
        case SQL_TOKEN_TAN:
        case SQL_TOKEN_DAYNAME:
        case SQL_TOKEN_DAYOFMONTH:
        case SQL_TOKEN_DAYOFWEEK:
        case SQL_TOKEN_DAYOFYEAR:
        case SQL_TOKEN_HOUR:
        case SQL_TOKEN_MINUTE:
        case SQL_TOKEN_MONTH:
        case SQL_TOKEN_MONTHNAME:
        case SQL_TOKEN_QUARTER:
        case SQL_TOKEN_SECOND:
        case SQL_TOKEN_YEAR:

            execute(pPredicateNode->getChild(2));

            switch( nTokenId )
            {
                case SQL_TOKEN_CHAR_LENGTH:
                case SQL_TOKEN_LENGTH:
                case SQL_TOKEN_OCTET_LENGTH:
                    pOperator = new OOp_CharLength();
                    break;
                case SQL_TOKEN_ASCII:
                    pOperator = new OOp_Ascii();
                    break;
                case SQL_TOKEN_LCASE:
                    pOperator = new OOp_Lower();
                    break;

                case SQL_TOKEN_LTRIM:
                    pOperator = new OOp_LTrim();
                    break;
                case SQL_TOKEN_RTRIM:
                    pOperator = new OOp_RTrim();
                    break;
                case SQL_TOKEN_SPACE:
                    pOperator = new OOp_Space();
                    break;
                case SQL_TOKEN_UCASE:
                    pOperator = new OOp_Upper();
                    break;
                case SQL_TOKEN_ABS:
                    pOperator = new OOp_Abs();
                    break;
                case SQL_TOKEN_ACOS:
                    pOperator = new OOp_ACos();
                    break;
                case SQL_TOKEN_ASIN:
                    pOperator = new OOp_ASin();
                    break;
                case SQL_TOKEN_ATAN:
                    pOperator = new OOp_ATan();
                    break;
                case SQL_TOKEN_CEILING:
                    pOperator = new OOp_Ceiling();
                    break;
                case SQL_TOKEN_COS:
                    pOperator = new OOp_Cos();
                    break;
                case SQL_TOKEN_DEGREES:
                    pOperator = new OOp_Degrees();
                    break;
                case SQL_TOKEN_EXP:
                    pOperator = new OOp_Exp();
                    break;
                case SQL_TOKEN_FLOOR:
                    pOperator = new OOp_Floor();
                    break;
                case SQL_TOKEN_LOG10:
                    pOperator = new OOp_Log10();
                    break;
                case SQL_TOKEN_LN:
                    pOperator = new OOp_Ln();
                    break;
                case SQL_TOKEN_RADIANS:
                    pOperator = new OOp_Radians();
                    break;
                case SQL_TOKEN_SIGN:
                    pOperator = new OOp_Sign();
                    break;
                case SQL_TOKEN_SIN:
                    pOperator = new OOp_Sin();
                    break;
                case SQL_TOKEN_SQRT:
                    pOperator = new OOp_Sqrt();
                    break;
                case SQL_TOKEN_TAN:
                    pOperator = new OOp_Tan();
                    break;
                case SQL_TOKEN_DAYOFWEEK:
                    pOperator = new OOp_DayOfWeek();
                    break;
                case SQL_TOKEN_DAYOFMONTH:
                    pOperator = new OOp_DayOfMonth();
                    break;
                case SQL_TOKEN_DAYOFYEAR:
                    pOperator = new OOp_DayOfYear();
                    break;
                case SQL_TOKEN_MONTH:
                    pOperator = new OOp_Month();
                    break;
                case SQL_TOKEN_DAYNAME:
                    pOperator = new OOp_DayName();
                    break;
                case SQL_TOKEN_MONTHNAME:
                    pOperator = new OOp_MonthName();
                    break;
                case SQL_TOKEN_QUARTER:
                    pOperator = new OOp_Quarter();
                    break;
                case SQL_TOKEN_YEAR:
                    pOperator = new OOp_Year();
                    break;
                case SQL_TOKEN_HOUR:
                    pOperator = new OOp_Hour();
                    break;
                case SQL_TOKEN_MINUTE:
                    pOperator = new OOp_Minute();
                    break;
                case SQL_TOKEN_SECOND:
                    pOperator = new OOp_Second();
                    break;
                default:
                    OSL_ENSURE(0,"Error in switch!");
            }
            break;
        case SQL_TOKEN_CHAR:
        case SQL_TOKEN_CONCAT:
        case SQL_TOKEN_INSERT:
        case SQL_TOKEN_LEFT:
        case SQL_TOKEN_LOCATE:
        case SQL_TOKEN_LOCATE_2:
        case SQL_TOKEN_REPEAT:
        case SQL_TOKEN_REPLACE:
        case SQL_TOKEN_RIGHT:
        case SQL_TOKEN_MOD:
        case SQL_TOKEN_ROUND:
        case SQL_TOKEN_LOGF:
        case SQL_TOKEN_LOG:
        case SQL_TOKEN_POWER:
        case SQL_TOKEN_ATAN2:
        case SQL_TOKEN_PI:
        case SQL_TOKEN_CURDATE:
        case SQL_TOKEN_CURTIME:
        case SQL_TOKEN_NOW:
        case SQL_TOKEN_WEEK:
            {
                m_aCodeList.push_back(new OStopOperand);
                OSQLParseNode* pList = pPredicateNode->getChild(2);
                for (sal_uInt32 i=0; i < pList->count(); ++i)
                    execute(pList->getChild(i));

                switch( nTokenId )
                {
                    case SQL_TOKEN_CHAR:
                        pOperator = new OOp_Char();
                        break;
                    case SQL_TOKEN_CONCAT:
                        pOperator = new OOp_Concat();
                        break;
                    case SQL_TOKEN_INSERT:
                        pOperator = new OOp_Insert();
                        break;
                    case SQL_TOKEN_LEFT:
                        pOperator = new OOp_Left();
                        break;
                    case SQL_TOKEN_LOCATE:
                    case SQL_TOKEN_LOCATE_2:
                        pOperator = new OOp_Locate();
                        break;
                    case SQL_TOKEN_REPEAT:
                        pOperator = new OOp_Repeat();
                        break;
                    case SQL_TOKEN_REPLACE:
                        pOperator = new OOp_Replace();
                        break;
                    case SQL_TOKEN_RIGHT:
                        pOperator = new OOp_Right();
                        break;
                    case SQL_TOKEN_MOD:
                        pOperator = new OOp_Mod();
                        break;
                    case SQL_TOKEN_ROUND:
                        pOperator = new OOp_Round();
                        break;
                    case SQL_TOKEN_LOGF:
                    case SQL_TOKEN_LOG:
                        pOperator = new OOp_Log();
                        break;
                    case SQL_TOKEN_POWER:
                        pOperator = new OOp_Pow();
                        break;
                    case SQL_TOKEN_ATAN2:
                        pOperator = new OOp_ATan2();
                        break;
                    case SQL_TOKEN_PI:
                        pOperator = new OOp_Pi();
                        break;
                    case SQL_TOKEN_CURDATE:
                        pOperator = new OOp_CurDate();
                        break;
                    case SQL_TOKEN_CURTIME:
                        pOperator = new OOp_CurTime();
                        break;
                    case SQL_TOKEN_NOW:
                        pOperator = new OOp_Now();
                        break;
                    case SQL_TOKEN_WEEK:
                        pOperator = new OOp_Week();
                        break;
                    default:
                        OSL_ENSURE(0,"Error in switch!");
                }
            }
            break;

        case SQL_TOKEN_SUBSTRING:
            m_aCodeList.push_back(new OStopOperand);
            if ( pPredicateNode->count() == 4 ) //char_substring_fct
            {
                OSQLParseNode* pList = pPredicateNode->getChild(2);
                for (sal_uInt32 i=0; i < pList->count(); ++i)
                    execute(pList->getChild(i));
            }
            else
            {
                execute(pPredicateNode->getChild(2));
                execute(pPredicateNode->getChild(4));
                execute(pPredicateNode->getChild(5)->getChild(1));
            }
            pOperator = new OOp_SubString();
            break;

        case SQL_TOKEN_POSITION:
            m_aCodeList.push_back(new OStopOperand);
            if ( pPredicateNode->count() == 4 ) //position_exp
            {
                OSQLParseNode* pList = pPredicateNode->getChild(2);
                for (sal_uInt32 i=0; i < pList->count(); ++i)
                    execute(pList->getChild(i));
            }
            else
            {
                execute(pPredicateNode->getChild(2));
                execute(pPredicateNode->getChild(4));
            }
            pOperator = new OOp_Locate();
            break;
        default:
            m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_FUNCTION_NOT_SUPPORTED,NULL);
    }

    m_aCodeList.push_back(pOperator);
    return NULL;
}
// -----------------------------------------------------------------------------


/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
