ultimatepp/bazaar/plugin/gdal/ogr/swq_expr_node.cpp
cxl 23ff1e7e82 .gdal moved to bazaar
git-svn-id: svn://ultimatepp.org/upp/trunk@9273 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2015-12-07 13:36:24 +00:00

829 lines
27 KiB
C++

/******************************************************************************
*
* Component: OGR SQL Engine
* Purpose: Implementation of the swq_expr_node class used to represent a
* node 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_conv.h"
#include "cpl_multiproc.h"
#include "swq.h"
#include "ogr_geometry.h"
#include <vector>
/************************************************************************/
/* swq_expr_node() */
/************************************************************************/
swq_expr_node::swq_expr_node()
{
Initialize();
}
/************************************************************************/
/* swq_expr_node(int) */
/************************************************************************/
swq_expr_node::swq_expr_node( int nValueIn )
{
Initialize();
int_value = nValueIn;
}
/************************************************************************/
/* swq_expr_node(GIntBig) */
/************************************************************************/
swq_expr_node::swq_expr_node( GIntBig nValueIn )
{
Initialize();
field_type = SWQ_INTEGER64;
int_value = nValueIn;
}
/************************************************************************/
/* swq_expr_node(double) */
/************************************************************************/
swq_expr_node::swq_expr_node( double dfValueIn )
{
Initialize();
field_type = SWQ_FLOAT;
float_value = dfValueIn;
}
/************************************************************************/
/* swq_expr_node(const char*) */
/************************************************************************/
swq_expr_node::swq_expr_node( const char *pszValueIn )
{
Initialize();
field_type = SWQ_STRING;
string_value = CPLStrdup( pszValueIn ? pszValueIn : "" );
is_null = pszValueIn == NULL;
}
/************************************************************************/
/* swq_expr_node(OGRGeometry *) */
/************************************************************************/
swq_expr_node::swq_expr_node( OGRGeometry *poGeomIn )
{
Initialize();
field_type = SWQ_GEOMETRY;
geometry_value = poGeomIn ? poGeomIn->clone() : NULL;
is_null = poGeomIn == NULL;
}
/************************************************************************/
/* swq_expr_node(swq_op) */
/************************************************************************/
swq_expr_node::swq_expr_node( swq_op eOp )
{
Initialize();
eNodeType = SNT_OPERATION;
nOperation = (int) eOp;
nSubExprCount = 0;
papoSubExpr = NULL;
}
/************************************************************************/
/* Initialize() */
/************************************************************************/
void swq_expr_node::Initialize()
{
eNodeType = SNT_CONSTANT;
field_type = SWQ_INTEGER;
int_value = 0;
is_null = FALSE;
table_name = NULL;
string_value = NULL;
geometry_value = NULL;
papoSubExpr = NULL;
nSubExprCount = 0;
}
/************************************************************************/
/* ~swq_expr_node() */
/************************************************************************/
swq_expr_node::~swq_expr_node()
{
CPLFree( table_name );
CPLFree( string_value );
int i;
for( i = 0; i < nSubExprCount; i++ )
delete papoSubExpr[i];
CPLFree( papoSubExpr );
delete geometry_value;
}
/************************************************************************/
/* PushSubExpression() */
/************************************************************************/
void swq_expr_node::PushSubExpression( swq_expr_node *child )
{
nSubExprCount++;
papoSubExpr = (swq_expr_node **)
CPLRealloc( papoSubExpr, sizeof(void*) * nSubExprCount );
papoSubExpr[nSubExprCount-1] = child;
}
/************************************************************************/
/* ReverseSubExpressions() */
/************************************************************************/
void swq_expr_node::ReverseSubExpressions()
{
int i;
for( i = 0; i < nSubExprCount / 2; i++ )
{
swq_expr_node *temp;
temp = papoSubExpr[i];
papoSubExpr[i] = papoSubExpr[nSubExprCount - i - 1];
papoSubExpr[nSubExprCount - i - 1] = temp;
}
}
/************************************************************************/
/* Check() */
/* */
/* Check argument types, etc. */
/************************************************************************/
swq_field_type swq_expr_node::Check( swq_field_list *poFieldList,
int bAllowFieldsInSecondaryTables,
int bAllowMismatchTypeOnFieldComparison,
swq_custom_func_registrar* poCustomFuncRegistrar )
{
/* -------------------------------------------------------------------- */
/* Otherwise we take constants literally. */
/* -------------------------------------------------------------------- */
if( eNodeType == SNT_CONSTANT )
return field_type;
/* -------------------------------------------------------------------- */
/* If this is intended to be a field definition, but has not */
/* yet been looked up, we do so now. */
/* -------------------------------------------------------------------- */
if( eNodeType == SNT_COLUMN && field_index == -1 )
{
field_index =
swq_identify_field( table_name, string_value, poFieldList,
&field_type, &table_index );
if( field_index < 0 )
{
if( table_name )
CPLError( CE_Failure, CPLE_AppDefined,
"\"%s\".\"%s\" not recognised as an available field.",
table_name, string_value );
else
CPLError( CE_Failure, CPLE_AppDefined,
"\"%s\" not recognised as an available field.",
string_value );
return SWQ_ERROR;
}
if( !bAllowFieldsInSecondaryTables && table_index != 0 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Cannot use field '%s' of a secondary table in this context",
string_value );
return SWQ_ERROR;
}
}
if( eNodeType == SNT_COLUMN )
return field_type;
/* -------------------------------------------------------------------- */
/* We are dealing with an operation - fetch the definition. */
/* -------------------------------------------------------------------- */
const swq_operation *poOp =
(nOperation == SWQ_CUSTOM_FUNC && poCustomFuncRegistrar != NULL ) ?
poCustomFuncRegistrar->GetOperator(string_value) :
swq_op_registrar::GetOperator((swq_op)nOperation);
if( poOp == NULL )
{
if( nOperation == SWQ_CUSTOM_FUNC )
CPLError( CE_Failure, CPLE_AppDefined,
"Check(): Unable to find definition for operator %s.",
string_value );
else
CPLError( CE_Failure, CPLE_AppDefined,
"Check(): Unable to find definition for operator %d.",
nOperation );
return SWQ_ERROR;
}
/* -------------------------------------------------------------------- */
/* Check subexpressions first. */
/* -------------------------------------------------------------------- */
int i;
for( i = 0; i < nSubExprCount; i++ )
{
if( papoSubExpr[i]->Check(poFieldList, bAllowFieldsInSecondaryTables,
bAllowMismatchTypeOnFieldComparison,
poCustomFuncRegistrar) == SWQ_ERROR )
return SWQ_ERROR;
}
/* -------------------------------------------------------------------- */
/* Check this node. */
/* -------------------------------------------------------------------- */
field_type = poOp->pfnChecker( this, bAllowMismatchTypeOnFieldComparison );
return field_type;
}
/************************************************************************/
/* Dump() */
/************************************************************************/
void swq_expr_node::Dump( FILE * fp, int depth )
{
char spaces[60];
int i;
for( i = 0; i < depth*2 && i < (int) sizeof(spaces) - 1; i++ )
spaces[i] = ' ';
spaces[i] = '\0';
if( eNodeType == SNT_COLUMN )
{
fprintf( fp, "%s Field %d\n", spaces, field_index );
return;
}
if( eNodeType == SNT_CONSTANT )
{
if( field_type == SWQ_INTEGER || field_type == SWQ_INTEGER64 ||
field_type == SWQ_BOOLEAN )
fprintf( fp, "%s " CPL_FRMT_GIB "\n", spaces, int_value );
else if( field_type == SWQ_FLOAT )
fprintf( fp, "%s %.15g\n", spaces, float_value );
else if( field_type == SWQ_GEOMETRY )
{
if( geometry_value == NULL )
fprintf( fp, "%s (null)\n", spaces );
else
{
char* pszWKT = NULL;
geometry_value->exportToWkt(&pszWKT);
fprintf( fp, "%s %s\n", spaces, pszWKT );
CPLFree(pszWKT);
}
}
else
fprintf( fp, "%s %s\n", spaces, string_value );
return;
}
CPLAssert( eNodeType == SNT_OPERATION );
const swq_operation *op_def =
swq_op_registrar::GetOperator( (swq_op) nOperation );
if( op_def )
fprintf( fp, "%s%s\n", spaces, op_def->pszName );
else
fprintf( fp, "%s%s\n", spaces, string_value );
for( i = 0; i < nSubExprCount; i++ )
papoSubExpr[i]->Dump( fp, depth+1 );
}
/************************************************************************/
/* QuoteIfNecessary() */
/* */
/* Add quoting if necessary to unparse a string. */
/************************************************************************/
CPLString swq_expr_node::QuoteIfNecessary( const CPLString &osExpr, char chQuote )
{
if( osExpr[0] == '_' )
return Quote(osExpr, chQuote);
if( osExpr == "*" )
return osExpr;
for( int i = 0; i < (int) osExpr.size(); i++ )
{
char ch = osExpr[i];
if ((!(isalnum((int)ch) || ch == '_')) || ch == '.')
{
return Quote(osExpr, chQuote);
}
}
if (swq_is_reserved_keyword(osExpr))
{
return Quote(osExpr, chQuote);
}
return osExpr;
}
/************************************************************************/
/* Quote() */
/* */
/* Add quoting necessary to unparse a string. */
/************************************************************************/
CPLString swq_expr_node::Quote( const CPLString &osTarget, char chQuote )
{
CPLString osNew;
int i;
osNew += chQuote;
for( i = 0; i < (int) osTarget.size(); i++ )
{
if( osTarget[i] == chQuote )
{
osNew += chQuote;
osNew += chQuote;
}
else
osNew += osTarget[i];
}
osNew += chQuote;
return osNew;
}
/************************************************************************/
/* Unparse() */
/************************************************************************/
char *swq_expr_node::Unparse( swq_field_list *field_list, char chColumnQuote )
{
CPLString osExpr;
/* -------------------------------------------------------------------- */
/* Handle constants. */
/* -------------------------------------------------------------------- */
if( eNodeType == SNT_CONSTANT )
{
if (is_null)
return CPLStrdup("NULL");
if( field_type == SWQ_INTEGER || field_type == SWQ_INTEGER64 ||
field_type == SWQ_BOOLEAN )
osExpr.Printf( CPL_FRMT_GIB, int_value );
else if( field_type == SWQ_FLOAT )
{
osExpr.Printf( "%.15g", float_value );
/* Make sure this is interpreted as a floating point value */
/* and not as an integer later */
if (strchr(osExpr, '.') == NULL && strchr(osExpr, 'e') == NULL &&
strchr(osExpr, 'E') == NULL)
osExpr += '.';
}
else
{
osExpr = Quote( string_value );
}
return CPLStrdup(osExpr);
}
/* -------------------------------------------------------------------- */
/* Handle columns. */
/* -------------------------------------------------------------------- */
if( eNodeType == SNT_COLUMN )
{
if( field_list == NULL )
{
if( table_name )
osExpr.Printf( "%s.%s",
QuoteIfNecessary(table_name, chColumnQuote).c_str(),
QuoteIfNecessary(string_value, chColumnQuote).c_str() );
else
osExpr.Printf( "%s",
QuoteIfNecessary(string_value, chColumnQuote).c_str() );
}
else if( field_index != -1
&& table_index < field_list->table_count
&& table_index > 0 )
{
for(int i = 0; i < field_list->count; i++ )
{
if( field_list->table_ids[i] == table_index &&
field_list->ids[i] == field_index )
{
osExpr.Printf( "%s.%s",
QuoteIfNecessary(field_list->table_defs[table_index].table_name, chColumnQuote).c_str(),
QuoteIfNecessary(field_list->names[i], chColumnQuote).c_str() );
break;
}
}
}
else if( field_index != -1 )
{
for(int i = 0; i < field_list->count; i++ )
{
if( field_list->table_ids[i] == table_index &&
field_list->ids[i] == field_index )
{
osExpr.Printf( "%s", QuoteIfNecessary(field_list->names[i], chColumnQuote).c_str() );
break;
}
}
}
if( osExpr.size() == 0 )
{
return CPLStrdup(CPLSPrintf("%c%c", chColumnQuote, chColumnQuote));
}
/* The string is just alphanum and not a reserved SQL keyword, no needs to quote and escape */
return CPLStrdup(osExpr.c_str());
}
/* -------------------------------------------------------------------- */
/* Operation - start by unparsing all the subexpressions. */
/* -------------------------------------------------------------------- */
std::vector<char*> apszSubExpr;
int i;
for( i = 0; i < nSubExprCount; i++ )
apszSubExpr.push_back( papoSubExpr[i]->Unparse(field_list, chColumnQuote) );
osExpr = UnparseOperationFromUnparsedSubExpr(&apszSubExpr[0]);
/* -------------------------------------------------------------------- */
/* cleanup subexpressions. */
/* -------------------------------------------------------------------- */
for( i = 0; i < nSubExprCount; i++ )
CPLFree( apszSubExpr[i] );
return CPLStrdup( osExpr.c_str() );
}
/************************************************************************/
/* UnparseOperationFromUnparsedSubExpr() */
/************************************************************************/
CPLString swq_expr_node::UnparseOperationFromUnparsedSubExpr(char** apszSubExpr)
{
int i;
CPLString osExpr;
/* -------------------------------------------------------------------- */
/* Put things together in a fashion depending on the operator. */
/* -------------------------------------------------------------------- */
const swq_operation *poOp =
swq_op_registrar::GetOperator( (swq_op) nOperation );
if( poOp == NULL && nOperation != SWQ_CUSTOM_FUNC )
{
CPLAssert( FALSE );
return osExpr;
}
switch( nOperation )
{
// binary infix operators.
case SWQ_OR:
case SWQ_AND:
case SWQ_EQ:
case SWQ_NE:
case SWQ_GT:
case SWQ_LT:
case SWQ_GE:
case SWQ_LE:
case SWQ_LIKE:
case SWQ_ADD:
case SWQ_SUBTRACT:
case SWQ_MULTIPLY:
case SWQ_DIVIDE:
case SWQ_MODULUS:
CPLAssert( nSubExprCount >= 2 );
if (papoSubExpr[0]->eNodeType == SNT_COLUMN ||
papoSubExpr[0]->eNodeType == SNT_CONSTANT)
{
osExpr += apszSubExpr[0];
}
else
{
osExpr += "(";
osExpr += apszSubExpr[0];
osExpr += ")";
}
osExpr += " ";
osExpr += poOp->pszName;
osExpr += " ";
if (papoSubExpr[1]->eNodeType == SNT_COLUMN ||
papoSubExpr[1]->eNodeType == SNT_CONSTANT)
{
osExpr += apszSubExpr[1];
}
else
{
osExpr += "(";
osExpr += apszSubExpr[1];
osExpr += ")";
}
if( nOperation == SWQ_LIKE && nSubExprCount == 3 )
osExpr += CPLSPrintf( " ESCAPE (%s)", apszSubExpr[2] );
break;
case SWQ_NOT:
CPLAssert( nSubExprCount == 1 );
osExpr.Printf( "NOT (%s)", apszSubExpr[0] );
break;
case SWQ_ISNULL:
CPLAssert( nSubExprCount == 1 );
osExpr.Printf( "%s IS NULL", apszSubExpr[0] );
break;
case SWQ_IN:
osExpr.Printf( "%s IN (", apszSubExpr[0] );
for( i = 1; i < nSubExprCount; i++ )
{
if( i > 1 )
osExpr += ",";
osExpr += "(";
osExpr += apszSubExpr[i];
osExpr += ")";
}
osExpr += ")";
break;
case SWQ_BETWEEN:
CPLAssert( nSubExprCount == 3 );
osExpr.Printf( "%s %s (%s) AND (%s)",
apszSubExpr[0],
poOp->pszName,
apszSubExpr[1],
apszSubExpr[2] );
break;
case SWQ_CAST:
osExpr = "CAST(";
for( i = 0; i < nSubExprCount; i++ )
{
if( i == 1 )
osExpr += " AS ";
else if( i > 2 )
osExpr += ", ";
int nLen = (int)strlen(apszSubExpr[i]);
if( (i == 1 &&
(apszSubExpr[i][0] == '\'' && nLen > 2 && apszSubExpr[i][nLen-1] == '\'')) ||
(i == 2 && EQUAL(apszSubExpr[1], "'GEOMETRY")) )
{
apszSubExpr[i][nLen-1] = '\0';
osExpr += apszSubExpr[i] + 1;
}
else
osExpr += apszSubExpr[i];
if( i == 1 && nSubExprCount > 2)
osExpr += "(";
else if (i > 1 && i == nSubExprCount - 1)
osExpr += ")";
}
osExpr += ")";
break;
default: // function style.
if( nOperation != SWQ_CUSTOM_FUNC )
osExpr.Printf( "%s(", poOp->pszName );
else
osExpr.Printf( "%s(", string_value );
for( i = 0; i < nSubExprCount; i++ )
{
if( i > 0 )
osExpr += ",";
osExpr += "(";
osExpr += apszSubExpr[i];
osExpr += ")";
}
osExpr += ")";
break;
}
return osExpr;
}
/************************************************************************/
/* Clone() */
/************************************************************************/
swq_expr_node *swq_expr_node::Clone()
{
swq_expr_node* poRetNode = new swq_expr_node();
poRetNode->eNodeType = eNodeType;
poRetNode->field_type = field_type;
if( eNodeType == SNT_OPERATION )
{
poRetNode->nOperation = nOperation;
poRetNode->nSubExprCount = nSubExprCount;
poRetNode->papoSubExpr = (swq_expr_node **)
CPLMalloc( sizeof(void*) * nSubExprCount );
for(int i=0;i<nSubExprCount;i++)
poRetNode->papoSubExpr[i] = papoSubExpr[i]->Clone();
}
else if( eNodeType == SNT_COLUMN )
{
poRetNode->field_index = field_index;
poRetNode->table_index = table_index;
poRetNode->table_name = table_name ? CPLStrdup(table_name) : NULL;
}
else if( eNodeType == SNT_CONSTANT )
{
poRetNode->is_null = is_null;
poRetNode->int_value = int_value;
poRetNode->float_value = float_value;
if( geometry_value )
poRetNode->geometry_value = geometry_value->clone();
else
poRetNode->geometry_value = NULL;
}
poRetNode->string_value = string_value ? CPLStrdup(string_value) : NULL;
return poRetNode;
}
/************************************************************************/
/* Evaluate() */
/************************************************************************/
swq_expr_node *swq_expr_node::Evaluate( swq_field_fetcher pfnFetcher,
void *pRecord )
{
swq_expr_node *poRetNode = NULL;
/* -------------------------------------------------------------------- */
/* Duplicate ourselves if we are already a constant. */
/* -------------------------------------------------------------------- */
if( eNodeType == SNT_CONSTANT )
{
return Clone();
}
/* -------------------------------------------------------------------- */
/* If this is a field value from a record, fetch and return it. */
/* -------------------------------------------------------------------- */
if( eNodeType == SNT_COLUMN )
{
return pfnFetcher( this, pRecord );
}
/* -------------------------------------------------------------------- */
/* This is an operation, collect the arguments keeping track of */
/* which we will need to free. */
/* -------------------------------------------------------------------- */
std::vector<swq_expr_node*> apoValues;
std::vector<int> anValueNeedsFree;
int i, bError = FALSE;
for( i = 0; i < nSubExprCount && !bError; i++ )
{
if( papoSubExpr[i]->eNodeType == SNT_CONSTANT )
{
// avoid duplication.
apoValues.push_back( papoSubExpr[i] );
anValueNeedsFree.push_back( FALSE );
}
else
{
swq_expr_node* poSubExprVal = papoSubExpr[i]->Evaluate(pfnFetcher,pRecord);
if( poSubExprVal == NULL )
bError = TRUE;
else
{
apoValues.push_back(poSubExprVal);
anValueNeedsFree.push_back( TRUE );
}
}
}
/* -------------------------------------------------------------------- */
/* Fetch the operator definition and function. */
/* -------------------------------------------------------------------- */
if( !bError )
{
const swq_operation *poOp =
swq_op_registrar::GetOperator( (swq_op) nOperation );
if( poOp == NULL )
{
if( nOperation == SWQ_CUSTOM_FUNC )
CPLError( CE_Failure, CPLE_AppDefined,
"Evaluate(): Unable to find definition for operator %s.",
string_value );
else
CPLError( CE_Failure, CPLE_AppDefined,
"Evaluate(): Unable to find definition for operator %d.",
nOperation );
poRetNode = NULL;
}
else
poRetNode = poOp->pfnEvaluator( this, &(apoValues[0]) );
}
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
for( i = 0; i < (int) apoValues.size(); i++ )
{
if( anValueNeedsFree[i] )
delete apoValues[i];
}
return poRetNode;
}
/************************************************************************/
/* ReplaceBetweenByGEAndLERecurse() */
/************************************************************************/
void swq_expr_node::ReplaceBetweenByGEAndLERecurse()
{
if( eNodeType != SNT_OPERATION )
return;
if( nOperation != SWQ_BETWEEN )
{
for(int i=0;i<nSubExprCount;i++)
papoSubExpr[i]->ReplaceBetweenByGEAndLERecurse();
return;
}
if( nSubExprCount != 3 )
return;
swq_expr_node* poExpr0 = papoSubExpr[0];
swq_expr_node* poExpr1 = papoSubExpr[1];
swq_expr_node* poExpr2 = papoSubExpr[2];
nSubExprCount = 2;
nOperation = SWQ_AND;
papoSubExpr[0] = new swq_expr_node(SWQ_GE);
papoSubExpr[0]->PushSubExpression(poExpr0);
papoSubExpr[0]->PushSubExpression(poExpr1);
papoSubExpr[1] = new swq_expr_node(SWQ_LE);
papoSubExpr[1]->PushSubExpression(poExpr0->Clone());
papoSubExpr[1]->PushSubExpression(poExpr2);
}