mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-19 14:15:21 -06:00
1409 lines
47 KiB
C++
1409 lines
47 KiB
C++
/******************************************************************************
|
|
*
|
|
* Component: OGR SQL Engine
|
|
* Purpose: Implementation of SWQGeneralEvaluator and SWQGeneralChecker
|
|
* functions used to represent functions during evaluation and
|
|
* parsing.
|
|
* 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 "swq.h"
|
|
#include "ogr_geometry.h"
|
|
|
|
/************************************************************************/
|
|
/* swq_test_like() */
|
|
/* */
|
|
/* Does input match pattern? */
|
|
/************************************************************************/
|
|
|
|
int swq_test_like( const char *input, const char *pattern, char chEscape )
|
|
|
|
{
|
|
if( input == NULL || pattern == NULL )
|
|
return 0;
|
|
|
|
while( *input != '\0' )
|
|
{
|
|
if( *pattern == '\0' )
|
|
return 0;
|
|
|
|
else if( *pattern == chEscape )
|
|
{
|
|
pattern++;
|
|
if( *pattern == '\0' )
|
|
return 0;
|
|
if( tolower(*pattern) != tolower(*input) )
|
|
return 0;
|
|
else
|
|
{
|
|
input++;
|
|
pattern++;
|
|
}
|
|
}
|
|
|
|
else if( *pattern == '_' )
|
|
{
|
|
input++;
|
|
pattern++;
|
|
}
|
|
else if( *pattern == '%' )
|
|
{
|
|
int eat;
|
|
|
|
if( pattern[1] == '\0' )
|
|
return 1;
|
|
|
|
/* try eating varying amounts of the input till we get a positive*/
|
|
for( eat = 0; input[eat] != '\0'; eat++ )
|
|
{
|
|
if( swq_test_like(input+eat,pattern+1, chEscape) )
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if( tolower(*pattern) != tolower(*input) )
|
|
return 0;
|
|
else
|
|
{
|
|
input++;
|
|
pattern++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( *pattern != '\0' && strcmp(pattern,"%") != 0 )
|
|
return 0;
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* OGRHStoreGetValue() */
|
|
/************************************************************************/
|
|
|
|
static char* OGRHStoreCheckEnd(char* pszIter, int bIsKey)
|
|
{
|
|
pszIter ++;
|
|
for( ; *pszIter != '\0'; pszIter ++ )
|
|
{
|
|
if( bIsKey )
|
|
{
|
|
if( *pszIter == ' ' )
|
|
;
|
|
else if( *pszIter == '=' && pszIter[1] == '>' )
|
|
return pszIter + 2;
|
|
else
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
if( *pszIter == ' ' )
|
|
;
|
|
else if( *pszIter == ',' )
|
|
return pszIter + 1;
|
|
else
|
|
return NULL;
|
|
}
|
|
}
|
|
return pszIter;
|
|
}
|
|
|
|
static char* OGRHStoreGetNextString(char* pszIter,
|
|
char** ppszOut,
|
|
int bIsKey)
|
|
{
|
|
char ch;
|
|
int bInString = FALSE;
|
|
char* pszOut = NULL;
|
|
*ppszOut = NULL;
|
|
for( ; (ch = *pszIter) != '\0'; pszIter ++ )
|
|
{
|
|
if( bInString )
|
|
{
|
|
if( ch == '"' )
|
|
{
|
|
*pszOut = '\0';
|
|
return OGRHStoreCheckEnd(pszIter, bIsKey);
|
|
}
|
|
else if( ch == '\\')
|
|
{
|
|
pszIter ++;
|
|
if( (ch = *pszIter) == '\0' )
|
|
return NULL;
|
|
}
|
|
*pszOut = ch;
|
|
pszOut ++;
|
|
}
|
|
else
|
|
{
|
|
if( ch == ' ' )
|
|
{
|
|
if( pszOut != NULL )
|
|
{
|
|
*pszIter = '\0';
|
|
return OGRHStoreCheckEnd(pszIter, bIsKey);
|
|
}
|
|
}
|
|
else if( bIsKey && ch == '=' && pszIter[1] == '>' )
|
|
{
|
|
if( pszOut != NULL )
|
|
{
|
|
*pszIter = '\0';
|
|
return pszIter + 2;
|
|
}
|
|
}
|
|
else if( !bIsKey && ch == ',' )
|
|
{
|
|
if( pszOut != NULL )
|
|
{
|
|
*pszIter = '\0';
|
|
return pszIter + 1;
|
|
}
|
|
}
|
|
else if( ch == '"' )
|
|
{
|
|
pszOut = *ppszOut = pszIter + 1;
|
|
bInString = TRUE;
|
|
}
|
|
else if( pszOut == NULL )
|
|
pszOut = *ppszOut = pszIter;
|
|
}
|
|
}
|
|
|
|
if( !bInString && pszOut != NULL )
|
|
{
|
|
return pszIter;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static char* OGRHStoreGetNextKeyValue(char* pszHStore,
|
|
char** ppszKey,
|
|
char** ppszValue)
|
|
{
|
|
char* pszNext = OGRHStoreGetNextString(pszHStore, ppszKey, TRUE);
|
|
if( pszNext == NULL || *pszNext == '\0' )
|
|
return NULL;
|
|
return OGRHStoreGetNextString(pszNext, ppszValue, FALSE);
|
|
}
|
|
|
|
char* OGRHStoreGetValue(const char* pszHStore, const char* pszSearchedKey)
|
|
{
|
|
char* pszHStoreDup = CPLStrdup(pszHStore);
|
|
char* pszHStoreIter = pszHStoreDup;
|
|
char* pszRet = NULL;
|
|
|
|
while( TRUE )
|
|
{
|
|
char* pszKey, *pszValue;
|
|
pszHStoreIter = OGRHStoreGetNextKeyValue(pszHStoreIter, &pszKey, &pszValue);
|
|
if( pszHStoreIter == NULL )
|
|
{
|
|
break;
|
|
}
|
|
if( strcmp(pszKey, pszSearchedKey) == 0 )
|
|
{
|
|
pszRet = CPLStrdup(pszValue);
|
|
break;
|
|
}
|
|
if( *pszHStoreIter == '\0' )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
CPLFree(pszHStoreDup);
|
|
return pszRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SWQGeneralEvaluator() */
|
|
/************************************************************************/
|
|
|
|
swq_expr_node *SWQGeneralEvaluator( swq_expr_node *node,
|
|
swq_expr_node **sub_node_values )
|
|
|
|
{
|
|
swq_expr_node *poRet = NULL;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Floating point operations. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( sub_node_values[0]->field_type == SWQ_FLOAT
|
|
|| (node->nSubExprCount > 1
|
|
&& sub_node_values[1]->field_type == SWQ_FLOAT) )
|
|
|
|
{
|
|
poRet = new swq_expr_node(0);
|
|
poRet->field_type = node->field_type;
|
|
|
|
if( SWQ_IS_INTEGER(sub_node_values[0]->field_type) )
|
|
sub_node_values[0]->float_value = (double) sub_node_values[0]->int_value;
|
|
if( node->nSubExprCount > 1 &&
|
|
SWQ_IS_INTEGER(sub_node_values[1]->field_type) )
|
|
sub_node_values[1]->float_value = (double)sub_node_values[1]->int_value;
|
|
|
|
if( node->nOperation != SWQ_ISNULL )
|
|
{
|
|
for( int i = 0; i < node->nSubExprCount; i++ )
|
|
{
|
|
if( sub_node_values[i]->is_null )
|
|
{
|
|
if( poRet->field_type == SWQ_BOOLEAN )
|
|
{
|
|
poRet->int_value = FALSE;
|
|
return poRet;
|
|
}
|
|
else if( poRet->field_type == SWQ_FLOAT )
|
|
{
|
|
poRet->float_value = 0;
|
|
poRet->is_null = 1;
|
|
return poRet;
|
|
}
|
|
else if( SWQ_IS_INTEGER(poRet->field_type) ||
|
|
node->nOperation == SWQ_MODULUS )
|
|
{
|
|
poRet->field_type = SWQ_INTEGER;
|
|
poRet->int_value = 0;
|
|
poRet->is_null = 1;
|
|
return poRet;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
switch( (swq_op) node->nOperation )
|
|
{
|
|
case SWQ_EQ:
|
|
poRet->int_value = sub_node_values[0]->float_value
|
|
== sub_node_values[1]->float_value;
|
|
break;
|
|
|
|
case SWQ_NE:
|
|
poRet->int_value = sub_node_values[0]->float_value
|
|
!= sub_node_values[1]->float_value;
|
|
break;
|
|
|
|
case SWQ_GT:
|
|
poRet->int_value = sub_node_values[0]->float_value
|
|
> sub_node_values[1]->float_value;
|
|
break;
|
|
|
|
case SWQ_LT:
|
|
poRet->int_value = sub_node_values[0]->float_value
|
|
< sub_node_values[1]->float_value;
|
|
break;
|
|
|
|
case SWQ_GE:
|
|
poRet->int_value = sub_node_values[0]->float_value
|
|
>= sub_node_values[1]->float_value;
|
|
break;
|
|
|
|
case SWQ_LE:
|
|
poRet->int_value = sub_node_values[0]->float_value
|
|
<= sub_node_values[1]->float_value;
|
|
break;
|
|
|
|
case SWQ_IN:
|
|
{
|
|
int i;
|
|
poRet->int_value = 0;
|
|
for( i = 1; i < node->nSubExprCount; i++ )
|
|
{
|
|
if( sub_node_values[0]->float_value
|
|
== sub_node_values[i]->float_value )
|
|
{
|
|
poRet->int_value = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SWQ_BETWEEN:
|
|
poRet->int_value = sub_node_values[0]->float_value
|
|
>= sub_node_values[1]->float_value &&
|
|
sub_node_values[0]->float_value
|
|
<= sub_node_values[2]->float_value;
|
|
break;
|
|
|
|
case SWQ_ISNULL:
|
|
poRet->int_value = sub_node_values[0]->is_null;
|
|
break;
|
|
|
|
case SWQ_ADD:
|
|
poRet->float_value = sub_node_values[0]->float_value
|
|
+ sub_node_values[1]->float_value;
|
|
break;
|
|
|
|
case SWQ_SUBTRACT:
|
|
poRet->float_value = sub_node_values[0]->float_value
|
|
- sub_node_values[1]->float_value;
|
|
break;
|
|
|
|
case SWQ_MULTIPLY:
|
|
poRet->float_value = sub_node_values[0]->float_value
|
|
* sub_node_values[1]->float_value;
|
|
break;
|
|
|
|
case SWQ_DIVIDE:
|
|
if( sub_node_values[1]->float_value == 0 )
|
|
poRet->float_value = INT_MAX;
|
|
else
|
|
poRet->float_value = sub_node_values[0]->float_value
|
|
/ sub_node_values[1]->float_value;
|
|
break;
|
|
|
|
case SWQ_MODULUS:
|
|
{
|
|
GIntBig nRight = (GIntBig) sub_node_values[1]->float_value;
|
|
poRet->field_type = SWQ_INTEGER;
|
|
if (nRight == 0)
|
|
poRet->int_value = INT_MAX;
|
|
else
|
|
poRet->int_value = ((GIntBig) sub_node_values[0]->float_value)
|
|
% nRight;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
CPLAssert( FALSE );
|
|
delete poRet;
|
|
poRet = NULL;
|
|
break;
|
|
}
|
|
}
|
|
/* -------------------------------------------------------------------- */
|
|
/* integer/boolean operations. */
|
|
/* -------------------------------------------------------------------- */
|
|
else if( SWQ_IS_INTEGER(sub_node_values[0]->field_type)
|
|
|| sub_node_values[0]->field_type == SWQ_BOOLEAN )
|
|
{
|
|
poRet = new swq_expr_node(0);
|
|
poRet->field_type = node->field_type;
|
|
|
|
if( node->nOperation != SWQ_ISNULL )
|
|
{
|
|
for( int i = 0; i < node->nSubExprCount; i++ )
|
|
{
|
|
if( sub_node_values[i]->is_null )
|
|
{
|
|
if( poRet->field_type == SWQ_BOOLEAN )
|
|
{
|
|
poRet->int_value = FALSE;
|
|
return poRet;
|
|
}
|
|
else if( SWQ_IS_INTEGER(poRet->field_type) )
|
|
{
|
|
poRet->int_value = 0;
|
|
poRet->is_null = 1;
|
|
return poRet;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
switch( (swq_op) node->nOperation )
|
|
{
|
|
case SWQ_AND:
|
|
poRet->int_value = sub_node_values[0]->int_value
|
|
&& sub_node_values[1]->int_value;
|
|
break;
|
|
|
|
case SWQ_OR:
|
|
poRet->int_value = sub_node_values[0]->int_value
|
|
|| sub_node_values[1]->int_value;
|
|
break;
|
|
|
|
case SWQ_NOT:
|
|
poRet->int_value = !sub_node_values[0]->int_value;
|
|
break;
|
|
|
|
case SWQ_EQ:
|
|
poRet->int_value = sub_node_values[0]->int_value
|
|
== sub_node_values[1]->int_value;
|
|
break;
|
|
|
|
case SWQ_NE:
|
|
poRet->int_value = sub_node_values[0]->int_value
|
|
!= sub_node_values[1]->int_value;
|
|
break;
|
|
|
|
case SWQ_GT:
|
|
poRet->int_value = sub_node_values[0]->int_value
|
|
> sub_node_values[1]->int_value;
|
|
break;
|
|
|
|
case SWQ_LT:
|
|
poRet->int_value = sub_node_values[0]->int_value
|
|
< sub_node_values[1]->int_value;
|
|
break;
|
|
|
|
case SWQ_GE:
|
|
poRet->int_value = sub_node_values[0]->int_value
|
|
>= sub_node_values[1]->int_value;
|
|
break;
|
|
|
|
case SWQ_LE:
|
|
poRet->int_value = sub_node_values[0]->int_value
|
|
<= sub_node_values[1]->int_value;
|
|
break;
|
|
|
|
case SWQ_IN:
|
|
{
|
|
int i;
|
|
poRet->int_value = 0;
|
|
for( i = 1; i < node->nSubExprCount; i++ )
|
|
{
|
|
if( sub_node_values[0]->int_value
|
|
== sub_node_values[i]->int_value )
|
|
{
|
|
poRet->int_value = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SWQ_BETWEEN:
|
|
poRet->int_value = sub_node_values[0]->int_value
|
|
>= sub_node_values[1]->int_value &&
|
|
sub_node_values[0]->int_value
|
|
<= sub_node_values[2]->int_value;
|
|
break;
|
|
|
|
case SWQ_ISNULL:
|
|
poRet->int_value = sub_node_values[0]->is_null;
|
|
break;
|
|
|
|
case SWQ_ADD:
|
|
poRet->int_value = sub_node_values[0]->int_value
|
|
+ sub_node_values[1]->int_value;
|
|
break;
|
|
|
|
case SWQ_SUBTRACT:
|
|
poRet->int_value = sub_node_values[0]->int_value
|
|
- sub_node_values[1]->int_value;
|
|
break;
|
|
|
|
case SWQ_MULTIPLY:
|
|
poRet->int_value = sub_node_values[0]->int_value
|
|
* sub_node_values[1]->int_value;
|
|
break;
|
|
|
|
case SWQ_DIVIDE:
|
|
if( sub_node_values[1]->int_value == 0 )
|
|
poRet->int_value = INT_MAX;
|
|
else
|
|
poRet->int_value = sub_node_values[0]->int_value
|
|
/ sub_node_values[1]->int_value;
|
|
break;
|
|
|
|
case SWQ_MODULUS:
|
|
if( sub_node_values[1]->int_value == 0 )
|
|
poRet->int_value = INT_MAX;
|
|
else
|
|
poRet->int_value = sub_node_values[0]->int_value
|
|
% sub_node_values[1]->int_value;
|
|
break;
|
|
|
|
default:
|
|
CPLAssert( FALSE );
|
|
delete poRet;
|
|
poRet = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* String operations. */
|
|
/* -------------------------------------------------------------------- */
|
|
else
|
|
{
|
|
poRet = new swq_expr_node(0);
|
|
poRet->field_type = node->field_type;
|
|
|
|
if( node->nOperation != SWQ_ISNULL )
|
|
{
|
|
for( int i = 0; i < node->nSubExprCount; i++ )
|
|
{
|
|
if( sub_node_values[i]->is_null )
|
|
{
|
|
if( poRet->field_type == SWQ_BOOLEAN )
|
|
{
|
|
poRet->int_value = FALSE;
|
|
return poRet;
|
|
}
|
|
else if( poRet->field_type == SWQ_STRING )
|
|
{
|
|
poRet->string_value = CPLStrdup("");
|
|
poRet->is_null = 1;
|
|
return poRet;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
switch( (swq_op) node->nOperation )
|
|
{
|
|
case SWQ_EQ:
|
|
{
|
|
/* When comparing timestamps, the +00 at the end might be discarded */
|
|
/* if the other member has no explicit timezone */
|
|
if( (sub_node_values[0]->field_type == SWQ_TIMESTAMP ||
|
|
sub_node_values[0]->field_type == SWQ_STRING) &&
|
|
(sub_node_values[1]->field_type == SWQ_TIMESTAMP ||
|
|
sub_node_values[1]->field_type == SWQ_STRING) &&
|
|
strlen(sub_node_values[0]->string_value) > 3 &&
|
|
strlen(sub_node_values[1]->string_value) > 3 &&
|
|
(strcmp(sub_node_values[0]->string_value + strlen(sub_node_values[0]->string_value)-3, "+00") == 0 &&
|
|
sub_node_values[1]->string_value[strlen(sub_node_values[1]->string_value)-3] == ':') )
|
|
{
|
|
poRet->int_value =
|
|
EQUALN(sub_node_values[0]->string_value,
|
|
sub_node_values[1]->string_value,
|
|
strlen(sub_node_values[1]->string_value));
|
|
}
|
|
else if( (sub_node_values[0]->field_type == SWQ_TIMESTAMP ||
|
|
sub_node_values[0]->field_type == SWQ_STRING) &&
|
|
(sub_node_values[1]->field_type == SWQ_TIMESTAMP ||
|
|
sub_node_values[1]->field_type == SWQ_STRING) &&
|
|
strlen(sub_node_values[0]->string_value) > 3 &&
|
|
strlen(sub_node_values[1]->string_value) > 3 &&
|
|
(sub_node_values[0]->string_value[strlen(sub_node_values[0]->string_value)-3] == ':') &&
|
|
strcmp(sub_node_values[1]->string_value + strlen(sub_node_values[1]->string_value)-3, "+00") == 0)
|
|
{
|
|
poRet->int_value =
|
|
EQUALN(sub_node_values[0]->string_value,
|
|
sub_node_values[1]->string_value,
|
|
strlen(sub_node_values[0]->string_value));
|
|
}
|
|
else
|
|
{
|
|
poRet->int_value =
|
|
strcasecmp(sub_node_values[0]->string_value,
|
|
sub_node_values[1]->string_value) == 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SWQ_NE:
|
|
poRet->int_value =
|
|
strcasecmp(sub_node_values[0]->string_value,
|
|
sub_node_values[1]->string_value) != 0;
|
|
break;
|
|
|
|
case SWQ_GT:
|
|
poRet->int_value =
|
|
strcasecmp(sub_node_values[0]->string_value,
|
|
sub_node_values[1]->string_value) > 0;
|
|
break;
|
|
|
|
case SWQ_LT:
|
|
poRet->int_value =
|
|
strcasecmp(sub_node_values[0]->string_value,
|
|
sub_node_values[1]->string_value) < 0;
|
|
break;
|
|
|
|
case SWQ_GE:
|
|
poRet->int_value =
|
|
strcasecmp(sub_node_values[0]->string_value,
|
|
sub_node_values[1]->string_value) >= 0;
|
|
break;
|
|
|
|
case SWQ_LE:
|
|
poRet->int_value =
|
|
strcasecmp(sub_node_values[0]->string_value,
|
|
sub_node_values[1]->string_value) <= 0;
|
|
break;
|
|
|
|
case SWQ_IN:
|
|
{
|
|
int i;
|
|
poRet->int_value = 0;
|
|
for( i = 1; i < node->nSubExprCount; i++ )
|
|
{
|
|
if( strcasecmp(sub_node_values[0]->string_value,
|
|
sub_node_values[i]->string_value) == 0 )
|
|
{
|
|
poRet->int_value = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SWQ_BETWEEN:
|
|
poRet->int_value =
|
|
strcasecmp(sub_node_values[0]->string_value,
|
|
sub_node_values[1]->string_value) >= 0 &&
|
|
strcasecmp(sub_node_values[0]->string_value,
|
|
sub_node_values[2]->string_value) <= 0;
|
|
break;
|
|
|
|
case SWQ_LIKE:
|
|
{
|
|
char chEscape = '\0';
|
|
if( node->nSubExprCount == 3 )
|
|
chEscape = sub_node_values[2]->string_value[0];
|
|
poRet->int_value = swq_test_like(sub_node_values[0]->string_value,
|
|
sub_node_values[1]->string_value,
|
|
chEscape);
|
|
break;
|
|
}
|
|
|
|
case SWQ_ISNULL:
|
|
poRet->int_value = sub_node_values[0]->is_null;
|
|
break;
|
|
|
|
case SWQ_CONCAT:
|
|
case SWQ_ADD:
|
|
{
|
|
CPLString osResult = sub_node_values[0]->string_value;
|
|
int i;
|
|
|
|
for( i = 1; i < node->nSubExprCount; i++ )
|
|
osResult += sub_node_values[i]->string_value;
|
|
|
|
poRet->string_value = CPLStrdup(osResult);
|
|
poRet->is_null = sub_node_values[0]->is_null;
|
|
break;
|
|
}
|
|
|
|
case SWQ_SUBSTR:
|
|
{
|
|
int nOffset, nSize;
|
|
const char *pszSrcStr = sub_node_values[0]->string_value;
|
|
|
|
if( SWQ_IS_INTEGER(sub_node_values[1]->field_type) )
|
|
nOffset = (int)sub_node_values[1]->int_value;
|
|
else if( sub_node_values[1]->field_type == SWQ_FLOAT )
|
|
nOffset = (int) sub_node_values[1]->float_value;
|
|
else
|
|
nOffset = 0;
|
|
|
|
if( node->nSubExprCount < 3 )
|
|
nSize = 100000;
|
|
else if( SWQ_IS_INTEGER(sub_node_values[2]->field_type) )
|
|
nSize = (int)sub_node_values[2]->int_value;
|
|
else if( sub_node_values[2]->field_type == SWQ_FLOAT )
|
|
nSize = (int) sub_node_values[2]->float_value;
|
|
else
|
|
nSize = 0;
|
|
|
|
int nSrcStrLen = (int)strlen(pszSrcStr);
|
|
|
|
|
|
/* In SQL, the first character is at offset 1 */
|
|
/* And 0 is considered as 1 */
|
|
if (nOffset > 0)
|
|
nOffset --;
|
|
/* Some implementations allow negative offsets, to start */
|
|
/* from the end of the string */
|
|
else if( nOffset < 0 )
|
|
{
|
|
if( nSrcStrLen + nOffset >= 0 )
|
|
nOffset = nSrcStrLen + nOffset;
|
|
else
|
|
nOffset = 0;
|
|
}
|
|
|
|
if( nSize < 0 || nOffset > nSrcStrLen )
|
|
{
|
|
nOffset = 0;
|
|
nSize = 0;
|
|
}
|
|
else if( nOffset + nSize > nSrcStrLen )
|
|
nSize = nSrcStrLen - nOffset;
|
|
|
|
CPLString osResult = pszSrcStr + nOffset;
|
|
if( (int)osResult.size() > nSize )
|
|
osResult.resize( nSize );
|
|
|
|
poRet->string_value = CPLStrdup(osResult);
|
|
poRet->is_null = sub_node_values[0]->is_null;
|
|
break;
|
|
}
|
|
|
|
case SWQ_HSTORE_GET_VALUE:
|
|
{
|
|
const char *pszHStore = sub_node_values[0]->string_value;
|
|
const char *pszSearchedKey = sub_node_values[1]->string_value;
|
|
char* pszRet = OGRHStoreGetValue(pszHStore, pszSearchedKey);
|
|
poRet->string_value = pszRet ? pszRet : CPLStrdup("");
|
|
poRet->is_null = (pszRet == NULL);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
CPLAssert( FALSE );
|
|
delete poRet;
|
|
poRet = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return poRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SWQAutoPromoteIntegerToInteger64OrFloat() */
|
|
/************************************************************************/
|
|
|
|
static void SWQAutoPromoteIntegerToInteger64OrFloat( swq_expr_node *poNode )
|
|
|
|
{
|
|
if( poNode->nSubExprCount < 2 )
|
|
return;
|
|
|
|
swq_field_type eArgType = poNode->papoSubExpr[0]->field_type;
|
|
int i;
|
|
|
|
// We allow mixes of integer, integer64 and float, and string and dates.
|
|
// When encountered, we promote integers/integer64 to floats,
|
|
// integer to integer64 and strings to dates. We do that now.
|
|
for( i = 1; i < poNode->nSubExprCount; i++ )
|
|
{
|
|
swq_expr_node *poSubNode = poNode->papoSubExpr[i];
|
|
if( SWQ_IS_INTEGER(eArgType)
|
|
&& poSubNode->field_type == SWQ_FLOAT )
|
|
eArgType = SWQ_FLOAT;
|
|
else if( eArgType == SWQ_INTEGER
|
|
&& poSubNode->field_type == SWQ_INTEGER64 )
|
|
eArgType = SWQ_INTEGER64;
|
|
}
|
|
|
|
for( i = 0; i < poNode->nSubExprCount; i++ )
|
|
{
|
|
swq_expr_node *poSubNode = poNode->papoSubExpr[i];
|
|
|
|
if( eArgType == SWQ_FLOAT
|
|
&& SWQ_IS_INTEGER(poSubNode->field_type) )
|
|
{
|
|
if( poSubNode->eNodeType == SNT_CONSTANT )
|
|
{
|
|
poSubNode->float_value = (double) poSubNode->int_value;
|
|
poSubNode->field_type = SWQ_FLOAT;
|
|
}
|
|
}
|
|
else if( eArgType == SWQ_INTEGER64 && poSubNode->field_type == SWQ_INTEGER )
|
|
{
|
|
if( poSubNode->eNodeType == SNT_CONSTANT )
|
|
{
|
|
poSubNode->field_type = SWQ_INTEGER64;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SWQAutoPromoteStringToDateTime() */
|
|
/************************************************************************/
|
|
|
|
static void SWQAutoPromoteStringToDateTime( swq_expr_node *poNode )
|
|
|
|
{
|
|
if( poNode->nSubExprCount < 2 )
|
|
return;
|
|
|
|
swq_field_type eArgType = poNode->papoSubExpr[0]->field_type;
|
|
int i;
|
|
|
|
// We allow mixes of integer and float, and string and dates.
|
|
// When encountered, we promote integers to floats, and strings to
|
|
// dates. We do that now.
|
|
for( i = 1; i < poNode->nSubExprCount; i++ )
|
|
{
|
|
swq_expr_node *poSubNode = poNode->papoSubExpr[i];
|
|
|
|
if( eArgType == SWQ_STRING
|
|
&& (poSubNode->field_type == SWQ_DATE
|
|
|| poSubNode->field_type == SWQ_TIME
|
|
|| poSubNode->field_type == SWQ_TIMESTAMP) )
|
|
eArgType = SWQ_TIMESTAMP;
|
|
}
|
|
|
|
for( i = 0; i < poNode->nSubExprCount; i++ )
|
|
{
|
|
swq_expr_node *poSubNode = poNode->papoSubExpr[i];
|
|
|
|
if( eArgType == SWQ_TIMESTAMP
|
|
&& (poSubNode->field_type == SWQ_STRING
|
|
|| poSubNode->field_type == SWQ_DATE
|
|
|| poSubNode->field_type == SWQ_TIME) )
|
|
{
|
|
if( poSubNode->eNodeType == SNT_CONSTANT )
|
|
{
|
|
poSubNode->field_type = SWQ_TIMESTAMP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SWQAutoConvertStringToNumeric() */
|
|
/* */
|
|
/* Convert string constants to integer or float constants */
|
|
/* when there is a mix of arguments of type numeric and string */
|
|
/************************************************************************/
|
|
|
|
static void SWQAutoConvertStringToNumeric( swq_expr_node *poNode )
|
|
|
|
{
|
|
if( poNode->nSubExprCount < 2 )
|
|
return;
|
|
|
|
swq_field_type eArgType = poNode->papoSubExpr[0]->field_type;
|
|
int i;
|
|
|
|
for( i = 1; i < poNode->nSubExprCount; i++ )
|
|
{
|
|
swq_expr_node *poSubNode = poNode->papoSubExpr[i];
|
|
|
|
/* identify the mixture of the argument type */
|
|
if( (eArgType == SWQ_STRING
|
|
&& (SWQ_IS_INTEGER(poSubNode->field_type)
|
|
|| poSubNode->field_type == SWQ_FLOAT)) ||
|
|
(SWQ_IS_INTEGER(eArgType)
|
|
&& poSubNode->field_type == SWQ_STRING) )
|
|
{
|
|
eArgType = SWQ_FLOAT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for( i = 0; i < poNode->nSubExprCount; i++ )
|
|
{
|
|
swq_expr_node *poSubNode = poNode->papoSubExpr[i];
|
|
|
|
if( eArgType == SWQ_FLOAT
|
|
&& poSubNode->field_type == SWQ_STRING )
|
|
{
|
|
if( poSubNode->eNodeType == SNT_CONSTANT )
|
|
{
|
|
/* apply the string to numeric conversion */
|
|
char* endPtr = NULL;
|
|
poSubNode->float_value = CPLStrtod(poSubNode->string_value, &endPtr);
|
|
if ( !(endPtr == NULL || *endPtr == '\0') )
|
|
{
|
|
CPLError(CE_Warning, CPLE_NotSupported,
|
|
"Conversion failed when converting the string value '%s' to data type float.",
|
|
poSubNode->string_value);
|
|
continue;
|
|
}
|
|
|
|
/* we should also fill the integer value in this case */
|
|
poSubNode->int_value = (GIntBig)poSubNode->float_value;
|
|
poSubNode->field_type = SWQ_FLOAT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SWQCheckSubExprAreNotGeometries() */
|
|
/************************************************************************/
|
|
|
|
static int SWQCheckSubExprAreNotGeometries( swq_expr_node *poNode )
|
|
{
|
|
for( int i = 0; i < poNode->nSubExprCount; i++ )
|
|
{
|
|
if( poNode->papoSubExpr[i]->field_type == SWQ_GEOMETRY )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Cannot use geometry field in this operation." );
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SWQGeneralChecker() */
|
|
/* */
|
|
/* Check the general purpose functions have appropriate types, */
|
|
/* and count and indicate the function return type under the */
|
|
/* circumstances. */
|
|
/************************************************************************/
|
|
|
|
swq_field_type SWQGeneralChecker( swq_expr_node *poNode,
|
|
int bAllowMismatchTypeOnFieldComparison )
|
|
|
|
{
|
|
swq_field_type eRetType = SWQ_ERROR;
|
|
swq_field_type eArgType = SWQ_OTHER;
|
|
int nArgCount = -1;
|
|
|
|
switch( (swq_op) poNode->nOperation )
|
|
{
|
|
case SWQ_AND:
|
|
case SWQ_OR:
|
|
case SWQ_NOT:
|
|
if( !SWQCheckSubExprAreNotGeometries(poNode) )
|
|
return SWQ_ERROR;
|
|
eRetType = SWQ_BOOLEAN;
|
|
break;
|
|
|
|
case SWQ_EQ:
|
|
case SWQ_NE:
|
|
case SWQ_GT:
|
|
case SWQ_LT:
|
|
case SWQ_GE:
|
|
case SWQ_LE:
|
|
case SWQ_IN:
|
|
case SWQ_BETWEEN:
|
|
if( !SWQCheckSubExprAreNotGeometries(poNode) )
|
|
return SWQ_ERROR;
|
|
eRetType = SWQ_BOOLEAN;
|
|
SWQAutoConvertStringToNumeric( poNode );
|
|
SWQAutoPromoteIntegerToInteger64OrFloat( poNode );
|
|
SWQAutoPromoteStringToDateTime( poNode );
|
|
eArgType = poNode->papoSubExpr[0]->field_type;
|
|
break;
|
|
|
|
case SWQ_ISNULL:
|
|
eRetType = SWQ_BOOLEAN;
|
|
break;
|
|
|
|
case SWQ_LIKE:
|
|
if( !SWQCheckSubExprAreNotGeometries(poNode) )
|
|
return SWQ_ERROR;
|
|
eRetType = SWQ_BOOLEAN;
|
|
eArgType = SWQ_STRING;
|
|
break;
|
|
|
|
case SWQ_MODULUS:
|
|
if( !SWQCheckSubExprAreNotGeometries(poNode) )
|
|
return SWQ_ERROR;
|
|
eRetType = SWQ_INTEGER;
|
|
eArgType = SWQ_INTEGER;
|
|
break;
|
|
|
|
case SWQ_ADD:
|
|
if( !SWQCheckSubExprAreNotGeometries(poNode) )
|
|
return SWQ_ERROR;
|
|
SWQAutoPromoteIntegerToInteger64OrFloat( poNode );
|
|
if( poNode->papoSubExpr[0]->field_type == SWQ_STRING )
|
|
eRetType = eArgType = SWQ_STRING;
|
|
else if( poNode->papoSubExpr[0]->field_type == SWQ_FLOAT )
|
|
eRetType = eArgType = SWQ_FLOAT;
|
|
else if( poNode->papoSubExpr[0]->field_type == SWQ_INTEGER64 )
|
|
eRetType = eArgType = SWQ_INTEGER64;
|
|
else
|
|
eRetType = eArgType = SWQ_INTEGER;
|
|
break;
|
|
|
|
case SWQ_SUBTRACT:
|
|
case SWQ_MULTIPLY:
|
|
case SWQ_DIVIDE:
|
|
if( !SWQCheckSubExprAreNotGeometries(poNode) )
|
|
return SWQ_ERROR;
|
|
SWQAutoPromoteIntegerToInteger64OrFloat( poNode );
|
|
if( poNode->papoSubExpr[0]->field_type == SWQ_FLOAT )
|
|
eRetType = eArgType = SWQ_FLOAT;
|
|
else if( poNode->papoSubExpr[0]->field_type == SWQ_INTEGER64 )
|
|
eRetType = eArgType = SWQ_INTEGER64;
|
|
else
|
|
eRetType = eArgType = SWQ_INTEGER;
|
|
break;
|
|
|
|
case SWQ_CONCAT:
|
|
if( !SWQCheckSubExprAreNotGeometries(poNode) )
|
|
return SWQ_ERROR;
|
|
eRetType = SWQ_STRING;
|
|
eArgType = SWQ_STRING;
|
|
break;
|
|
|
|
case SWQ_SUBSTR:
|
|
if( !SWQCheckSubExprAreNotGeometries(poNode) )
|
|
return SWQ_ERROR;
|
|
eRetType = SWQ_STRING;
|
|
if( poNode->nSubExprCount > 3 || poNode->nSubExprCount < 2 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Expected 2 or 3 arguments to SUBSTR(), but got %d.",
|
|
poNode->nSubExprCount );
|
|
return SWQ_ERROR;
|
|
}
|
|
if( poNode->papoSubExpr[0]->field_type != SWQ_STRING
|
|
|| poNode->papoSubExpr[1]->field_type != SWQ_INTEGER
|
|
|| (poNode->nSubExprCount > 2
|
|
&& poNode->papoSubExpr[2]->field_type != SWQ_INTEGER) )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Wrong argument type for SUBSTR(), expected SUBSTR(string,int,int) or SUBSTR(string,int)." );
|
|
return SWQ_ERROR;
|
|
}
|
|
break;
|
|
|
|
case SWQ_HSTORE_GET_VALUE:
|
|
if( !SWQCheckSubExprAreNotGeometries(poNode) )
|
|
return SWQ_ERROR;
|
|
eRetType = SWQ_STRING;
|
|
if( poNode->nSubExprCount != 2 )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Expected 2 arguments to hstore_get_value(), but got %d.",
|
|
poNode->nSubExprCount );
|
|
return SWQ_ERROR;
|
|
}
|
|
if( poNode->papoSubExpr[0]->field_type != SWQ_STRING
|
|
|| poNode->papoSubExpr[1]->field_type != SWQ_STRING )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Wrong argument type for hstore_get_value(), expected hstore_get_value(string,string)." );
|
|
return SWQ_ERROR;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
const swq_operation *poOp =
|
|
swq_op_registrar::GetOperator((swq_op)poNode->nOperation);
|
|
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"SWQGeneralChecker() called on unsupported operation %s.",
|
|
poOp->pszName);
|
|
return SWQ_ERROR;
|
|
}
|
|
}
|
|
/* -------------------------------------------------------------------- */
|
|
/* Check argument types. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( eArgType != SWQ_OTHER )
|
|
{
|
|
int i;
|
|
|
|
if( SWQ_IS_INTEGER(eArgType) || eArgType == SWQ_BOOLEAN )
|
|
eArgType = SWQ_FLOAT;
|
|
|
|
for( i = 0; i < poNode->nSubExprCount; i++ )
|
|
{
|
|
swq_field_type eThisArgType = poNode->papoSubExpr[i]->field_type;
|
|
if( SWQ_IS_INTEGER(eThisArgType) || eThisArgType == SWQ_BOOLEAN )
|
|
eThisArgType = SWQ_FLOAT;
|
|
|
|
if( eArgType != eThisArgType )
|
|
{
|
|
// Conveniency for join. We allow comparing numeric columns
|
|
// and string columns, by casting string columns to numeric
|
|
if( bAllowMismatchTypeOnFieldComparison &&
|
|
poNode->nSubExprCount == 2 &&
|
|
poNode->nOperation == SWQ_EQ &&
|
|
poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
|
|
poNode->papoSubExpr[i]->eNodeType == SNT_COLUMN &&
|
|
eArgType == SWQ_FLOAT && eThisArgType == SWQ_STRING )
|
|
{
|
|
swq_expr_node* poNewNode = new swq_expr_node(SWQ_CAST);
|
|
poNewNode->PushSubExpression(poNode->papoSubExpr[i]);
|
|
poNewNode->PushSubExpression(new swq_expr_node("FLOAT"));
|
|
SWQCastChecker(poNewNode, FALSE);
|
|
poNode->papoSubExpr[i] = poNewNode;
|
|
break;
|
|
}
|
|
if( bAllowMismatchTypeOnFieldComparison &&
|
|
poNode->nSubExprCount == 2 &&
|
|
poNode->nOperation == SWQ_EQ &&
|
|
poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
|
|
poNode->papoSubExpr[i]->eNodeType == SNT_COLUMN &&
|
|
eThisArgType == SWQ_FLOAT && eArgType == SWQ_STRING )
|
|
{
|
|
swq_expr_node* poNewNode = new swq_expr_node(SWQ_CAST);
|
|
poNewNode->PushSubExpression(poNode->papoSubExpr[0]);
|
|
poNewNode->PushSubExpression(new swq_expr_node("FLOAT"));
|
|
SWQCastChecker(poNewNode, FALSE);
|
|
poNode->papoSubExpr[0] = poNewNode;
|
|
break;
|
|
}
|
|
|
|
const swq_operation *poOp =
|
|
swq_op_registrar::GetOperator((swq_op)poNode->nOperation);
|
|
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Type mismatch or improper type of arguments to %s operator.",
|
|
poOp->pszName );
|
|
return SWQ_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Validate the arg count if requested. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( nArgCount != -1
|
|
&& nArgCount != poNode->nSubExprCount )
|
|
{
|
|
const swq_operation *poOp =
|
|
swq_op_registrar::GetOperator((swq_op)poNode->nOperation);
|
|
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Expected %d arguments to %s, but got %d arguments.",
|
|
nArgCount,
|
|
poOp->pszName,
|
|
poNode->nSubExprCount );
|
|
return SWQ_ERROR;
|
|
}
|
|
|
|
return eRetType;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SWQCastEvaluator() */
|
|
/************************************************************************/
|
|
|
|
swq_expr_node *SWQCastEvaluator( swq_expr_node *node,
|
|
swq_expr_node **sub_node_values )
|
|
|
|
{
|
|
swq_expr_node *poRetNode = NULL;
|
|
swq_expr_node *poSrcNode = sub_node_values[0];
|
|
|
|
switch( node->field_type )
|
|
{
|
|
case SWQ_INTEGER:
|
|
{
|
|
poRetNode = new swq_expr_node( 0 );
|
|
poRetNode->is_null = poSrcNode->is_null;
|
|
|
|
switch( poSrcNode->field_type )
|
|
{
|
|
case SWQ_INTEGER:
|
|
case SWQ_BOOLEAN:
|
|
poRetNode->int_value = poSrcNode->int_value;
|
|
break;
|
|
|
|
case SWQ_INTEGER64:
|
|
// TODO: warn in case of overflow ?
|
|
poRetNode->int_value = (int) poSrcNode->int_value;
|
|
break;
|
|
|
|
case SWQ_FLOAT:
|
|
poRetNode->int_value = (int) poSrcNode->float_value;
|
|
break;
|
|
|
|
default:
|
|
poRetNode->int_value = atoi(poSrcNode->string_value);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SWQ_INTEGER64:
|
|
{
|
|
poRetNode = new swq_expr_node( 0 );
|
|
poRetNode->is_null = poSrcNode->is_null;
|
|
|
|
switch( poSrcNode->field_type )
|
|
{
|
|
case SWQ_INTEGER:
|
|
case SWQ_INTEGER64:
|
|
case SWQ_BOOLEAN:
|
|
poRetNode->int_value = poSrcNode->int_value;
|
|
break;
|
|
|
|
case SWQ_FLOAT:
|
|
poRetNode->int_value = (GIntBig) poSrcNode->float_value;
|
|
break;
|
|
|
|
default:
|
|
poRetNode->int_value = CPLAtoGIntBig(poSrcNode->string_value);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SWQ_FLOAT:
|
|
{
|
|
poRetNode = new swq_expr_node( 0.0 );
|
|
poRetNode->is_null = poSrcNode->is_null;
|
|
|
|
switch( poSrcNode->field_type )
|
|
{
|
|
case SWQ_INTEGER:
|
|
case SWQ_INTEGER64:
|
|
case SWQ_BOOLEAN:
|
|
poRetNode->float_value = (double) poSrcNode->int_value;
|
|
break;
|
|
|
|
case SWQ_FLOAT:
|
|
poRetNode->float_value = poSrcNode->float_value;
|
|
break;
|
|
|
|
default:
|
|
poRetNode->float_value = CPLAtof(poSrcNode->string_value);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SWQ_GEOMETRY:
|
|
{
|
|
poRetNode = new swq_expr_node( (OGRGeometry*) NULL );
|
|
if( !poSrcNode->is_null )
|
|
{
|
|
switch( poSrcNode->field_type )
|
|
{
|
|
case SWQ_GEOMETRY:
|
|
{
|
|
poRetNode->geometry_value =
|
|
poSrcNode->geometry_value->clone();
|
|
poRetNode->is_null = FALSE;
|
|
break;
|
|
}
|
|
|
|
case SWQ_STRING:
|
|
{
|
|
char* pszTmp = poSrcNode->string_value;
|
|
OGRGeometryFactory::createFromWkt(&pszTmp, NULL,
|
|
&(poRetNode->geometry_value));
|
|
if( poRetNode->geometry_value != NULL )
|
|
poRetNode->is_null = FALSE;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// everything else is a string.
|
|
default:
|
|
{
|
|
CPLString osRet;
|
|
|
|
switch( poSrcNode->field_type )
|
|
{
|
|
case SWQ_INTEGER:
|
|
case SWQ_BOOLEAN:
|
|
case SWQ_INTEGER64:
|
|
osRet.Printf( CPL_FRMT_GIB, poSrcNode->int_value );
|
|
break;
|
|
|
|
case SWQ_FLOAT:
|
|
osRet.Printf( "%.15g", poSrcNode->float_value );
|
|
break;
|
|
|
|
case SWQ_GEOMETRY:
|
|
{
|
|
if( poSrcNode->geometry_value != NULL )
|
|
{
|
|
char* pszWKT;
|
|
poSrcNode->geometry_value->exportToWkt(&pszWKT);
|
|
osRet = pszWKT;
|
|
CPLFree(pszWKT);
|
|
}
|
|
else
|
|
osRet = "";
|
|
break;
|
|
}
|
|
|
|
default:
|
|
osRet = poSrcNode->string_value;
|
|
break;
|
|
}
|
|
|
|
if( node->nSubExprCount > 2 )
|
|
{
|
|
int nWidth;
|
|
|
|
nWidth = (int) sub_node_values[2]->int_value;
|
|
if( nWidth > 0 && (int) strlen(osRet) > nWidth )
|
|
osRet.resize(nWidth);
|
|
}
|
|
|
|
poRetNode = new swq_expr_node( osRet.c_str() );
|
|
poRetNode->is_null = poSrcNode->is_null;
|
|
}
|
|
}
|
|
|
|
return poRetNode;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SWQCastChecker() */
|
|
/************************************************************************/
|
|
|
|
swq_field_type SWQCastChecker( swq_expr_node *poNode,
|
|
CPL_UNUSED int bAllowMismatchTypeOnFieldComparison )
|
|
|
|
{
|
|
swq_field_type eType = SWQ_ERROR;
|
|
const char *pszTypeName = poNode->papoSubExpr[1]->string_value;
|
|
|
|
if( poNode->papoSubExpr[0]->field_type == SWQ_GEOMETRY &&
|
|
!(EQUAL(pszTypeName,"character") ||
|
|
EQUAL(pszTypeName,"geometry")) )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined, "Cannot cast geometry to %s",
|
|
pszTypeName );
|
|
}
|
|
|
|
else if( EQUAL(pszTypeName,"boolean") )
|
|
eType = SWQ_BOOLEAN;
|
|
else if( EQUAL(pszTypeName,"character") )
|
|
eType = SWQ_STRING;
|
|
else if( EQUAL(pszTypeName,"integer") )
|
|
eType = SWQ_INTEGER;
|
|
else if( EQUAL(pszTypeName,"bigint") )
|
|
eType = SWQ_INTEGER64;
|
|
else if( EQUAL(pszTypeName,"smallint") )
|
|
eType = SWQ_INTEGER;
|
|
else if( EQUAL(pszTypeName,"float") )
|
|
eType = SWQ_FLOAT;
|
|
else if( EQUAL(pszTypeName,"numeric") )
|
|
eType = SWQ_FLOAT;
|
|
else if( EQUAL(pszTypeName,"timestamp") )
|
|
eType = SWQ_TIMESTAMP;
|
|
else if( EQUAL(pszTypeName,"date") )
|
|
eType = SWQ_DATE;
|
|
else if( EQUAL(pszTypeName,"time") )
|
|
eType = SWQ_TIME;
|
|
else if( EQUAL(pszTypeName,"geometry") )
|
|
{
|
|
if( !(poNode->papoSubExpr[0]->field_type == SWQ_GEOMETRY ||
|
|
poNode->papoSubExpr[0]->field_type == SWQ_STRING) )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined, "Cannot cast %s to geometry",
|
|
SWQFieldTypeToString(poNode->papoSubExpr[0]->field_type) );
|
|
}
|
|
else
|
|
eType = SWQ_GEOMETRY;
|
|
}
|
|
else
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Unrecognized typename %s in CAST operator.",
|
|
pszTypeName );
|
|
}
|
|
|
|
poNode->field_type = eType;
|
|
|
|
return eType;
|
|
}
|