Beispiel #1
0
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;
            }
        }
    }
}
Beispiel #2
0
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;
            }
        }
    }
}
Beispiel #3
0
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 )
    {
        if( SWQ_IS_INTEGER(eArgType) || eArgType == SWQ_BOOLEAN )
            eArgType = SWQ_FLOAT;

        for( int 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 )
            {
                // Convenience 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 0
    // nArgCount was always -1, so this block was never executed.
    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;
    }
#endif

    return eRetType;
}
Beispiel #4
0
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:
          {
              poRet->int_value = 0;
              for( int 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:
          {
              poRet->int_value = 0;
              for( int 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:
          {
              poRet->int_value = 0;
              for( int 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;

              for( int 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;
}