/******************************************************************************
 *
 * Component: OGR SQL Engine
 * Purpose: Implementation of the swq_op_registrar class used to
 *          represent operations possible in an SQL expression.
 * Author: Frank Warmerdam <warmerdam@pobox.com>
 *
 ******************************************************************************
 * Copyright (C) 2010 Frank Warmerdam <warmerdam@pobox.com>
 * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 ****************************************************************************/

#include "cpl_port.h"
#include "swq.h"

#include <cstddef>

#include "cpl_conv.h"
#include "cpl_error.h"

CPL_CVSID("$Id: swq_op_registrar.cpp ba2ef4045f82fd2260f1732e9e46a927277ac93d 2018-05-06 19:07:03 +0200 Even Rouault $")

//! @cond Doxygen_Suppress
static swq_field_type SWQColumnFuncChecker(
    swq_expr_node *poNode, int bAllowMismatchTypeOnFieldComparison );

static const swq_operation swq_apsOperations[] =
{
    { "OR", SWQ_OR, SWQGeneralEvaluator, SWQGeneralChecker },
    { "AND", SWQ_AND, SWQGeneralEvaluator, SWQGeneralChecker },
    { "NOT", SWQ_NOT , SWQGeneralEvaluator, SWQGeneralChecker },
    { "=", SWQ_EQ , SWQGeneralEvaluator, SWQGeneralChecker },
    { "<>", SWQ_NE , SWQGeneralEvaluator, SWQGeneralChecker },
    { ">=", SWQ_GE , SWQGeneralEvaluator, SWQGeneralChecker },
    { "<=", SWQ_LE , SWQGeneralEvaluator, SWQGeneralChecker },
    { "<", SWQ_LT , SWQGeneralEvaluator, SWQGeneralChecker },
    { ">", SWQ_GT , SWQGeneralEvaluator, SWQGeneralChecker },
    { "LIKE", SWQ_LIKE , SWQGeneralEvaluator, SWQGeneralChecker },
    { "IS NULL", SWQ_ISNULL , SWQGeneralEvaluator, SWQGeneralChecker },
    { "IN", SWQ_IN , SWQGeneralEvaluator, SWQGeneralChecker },
    { "BETWEEN", SWQ_BETWEEN , SWQGeneralEvaluator, SWQGeneralChecker },
    { "+", SWQ_ADD , SWQGeneralEvaluator, SWQGeneralChecker },
    { "-", SWQ_SUBTRACT , SWQGeneralEvaluator, SWQGeneralChecker },
    { "*", SWQ_MULTIPLY , SWQGeneralEvaluator, SWQGeneralChecker },
    { "/", SWQ_DIVIDE , SWQGeneralEvaluator, SWQGeneralChecker },
    { "%", SWQ_MODULUS , SWQGeneralEvaluator, SWQGeneralChecker },
    { "CONCAT", SWQ_CONCAT , SWQGeneralEvaluator, SWQGeneralChecker },
    { "SUBSTR", SWQ_SUBSTR , SWQGeneralEvaluator, SWQGeneralChecker },
    { "HSTORE_GET_VALUE", SWQ_HSTORE_GET_VALUE , SWQGeneralEvaluator,
        SWQGeneralChecker },

    { "AVG", SWQ_AVG, SWQGeneralEvaluator, SWQColumnFuncChecker },
    { "MIN", SWQ_MIN, SWQGeneralEvaluator, SWQColumnFuncChecker },
    { "MAX", SWQ_MAX, SWQGeneralEvaluator, SWQColumnFuncChecker },
    { "COUNT", SWQ_COUNT, SWQGeneralEvaluator, SWQColumnFuncChecker },
    { "SUM", SWQ_SUM, SWQGeneralEvaluator, SWQColumnFuncChecker },

    { "CAST", SWQ_CAST, SWQCastEvaluator, SWQCastChecker }
};

/************************************************************************/
/*                            GetOperator()                             */
/************************************************************************/

const swq_operation *swq_op_registrar::GetOperator( const char *pszName )

{
    for( const auto& op: swq_apsOperations )
    {
        if( EQUAL(pszName, op.pszName) )
            return &op;
    }

    return nullptr;
}

/************************************************************************/
/*                            GetOperator()                             */
/************************************************************************/

const swq_operation *swq_op_registrar::GetOperator( swq_op eOperator )

{
    for( const auto& op: swq_apsOperations )
    {
        if( eOperator == op.eOperation )
            return &op;
    }

    return nullptr;
}

/************************************************************************/
/*                        SWQColumnFuncChecker()                        */
/*                                                                      */
/*      Column summary functions are not legal in any context except    */
/*      as a root operator on column definitions.  They are removed     */
/*      from this tree before checking so we just need to issue an      */
/*      error if they are used in any other context.                    */
/************************************************************************/

static swq_field_type SWQColumnFuncChecker(
    swq_expr_node *poNode, int /* bAllowMismatchTypeOnFieldComparison */ )
{
    const swq_operation *poOp =
        swq_op_registrar::GetOperator(static_cast<swq_op>(poNode->nOperation));
    CPLError( CE_Failure, CPLE_AppDefined,
              "Column Summary Function '%s' found in an inappropriate context.",
              poOp != nullptr ? poOp->pszName : "" );
    return SWQ_ERROR;
}
//! @endcond
