text: /******************************************************************************
   * $Id$
   * 
   * Project:  OpenGIS Simple Features Reference Implementation
   * Purpose:  Implementation of simple SQL WHERE style attributes queries
   *           for OGRFeatures.  
   * Author:   Frank Warmerdam, warmerdam@pobox.com
   *
   ******************************************************************************
   * Copyright (c) 2001, Frank Warmerdam <warmerdam@pobox.com>
   * Copyright (c) 2008-2014, 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 <assert.h>
  #include "swq.h"
  #include "ogr_feature.h"
  #include "ogr_p.h"
  #include "ogr_attrind.h"
  
  CPL_CVSID("$Id$");
  
  /************************************************************************/
  /*     Support for special attributes (feature query and selection)     */
  /************************************************************************/
  
  const char* SpecialFieldNames[SPECIAL_FIELD_COUNT] 
  = {"FID", "OGR_GEOMETRY", "OGR_STYLE", "OGR_GEOM_WKT", "OGR_GEOM_AREA"};
  const swq_field_type SpecialFieldTypes[SPECIAL_FIELD_COUNT] 
  = {SWQ_INTEGER, SWQ_STRING, SWQ_STRING, SWQ_STRING, SWQ_FLOAT};
  
  /************************************************************************/
  /*                          OGRFeatureQuery()                           */
  /************************************************************************/
  
  OGRFeatureQuery::OGRFeatureQuery()
  
  {
      poTargetDefn = NULL;
      pSWQExpr = NULL;
  }
  
  /************************************************************************/
  /*                          ~OGRFeatureQuery()                          */
  /************************************************************************/
  
  OGRFeatureQuery::~OGRFeatureQuery()
  
  {
      delete (swq_expr_node *) pSWQExpr;
  }
  
  /************************************************************************/
  /*                                Parse                                 */
  /************************************************************************/
  
  OGRErr OGRFeatureQuery::Compile( OGRFeatureDefn *poDefn, 
                                   const char * pszExpression,
                                   int bCheck,
                                   swq_custom_func_registrar* poCustomFuncRegistrar )
  
  {
  /* -------------------------------------------------------------------- */
  /*      Clear any existing expression.                                  */
  /* -------------------------------------------------------------------- */
      if( pSWQExpr != NULL )
      {
          delete (swq_expr_node *) pSWQExpr;
          pSWQExpr = NULL;
      }
  
  /* -------------------------------------------------------------------- */
  /*      Build list of fields.                                           */
  /* -------------------------------------------------------------------- */
      char        **papszFieldNames;
      swq_field_type *paeFieldTypes;
      int         iField;
      int         nFieldCount = poDefn->GetFieldCount() + SPECIAL_FIELD_COUNT +
                                poDefn->GetGeomFieldCount();
  
      papszFieldNames = (char **) 
          CPLMalloc(sizeof(char *) * nFieldCount );
      paeFieldTypes = (swq_field_type *) 
          CPLMalloc(sizeof(swq_field_type) * nFieldCount );
  
      for( iField = 0; iField < poDefn->GetFieldCount(); iField++ )
      {
          OGRFieldDefn    *poField = poDefn->GetFieldDefn( iField );
  
          papszFieldNames[iField] = (char *) poField->GetNameRef();
  
          switch( poField->GetType() )
          {
            case OFTInteger:
            {
                if( poField->GetSubType() == OFSTBoolean )
                    paeFieldTypes[iField] = SWQ_BOOLEAN;
                else
                    paeFieldTypes[iField] = SWQ_INTEGER;
                break;
            }
  
            case OFTInteger64:
            {
                if( poField->GetSubType() == OFSTBoolean )
                    paeFieldTypes[iField] = SWQ_BOOLEAN;
                else
                    paeFieldTypes[iField] = SWQ_INTEGER64;
                break;
            }
  
            case OFTReal:
              paeFieldTypes[iField] = SWQ_FLOAT;
              break;
  
            case OFTString:
              paeFieldTypes[iField] = SWQ_STRING;
              break;
  
            case OFTDate:
            case OFTTime:
            case OFTDateTime:
              paeFieldTypes[iField] = SWQ_TIMESTAMP;
              break;
  
            default:
              paeFieldTypes[iField] = SWQ_OTHER;
              break;
          }
      }
  
      iField = 0;
      while (iField < SPECIAL_FIELD_COUNT)
      {
          papszFieldNames[poDefn->GetFieldCount() + iField] = (char *) SpecialFieldNames[iField];
          paeFieldTypes[poDefn->GetFieldCount() + iField] = SpecialFieldTypes[iField];
          ++iField;
      }
  
      for( iField = 0; iField < poDefn->GetGeomFieldCount(); iField++ )
      {
          OGRGeomFieldDefn    *poField = poDefn->GetGeomFieldDefn( iField );
          int iDstField = poDefn->GetFieldCount() + SPECIAL_FIELD_COUNT + iField;
  
          papszFieldNames[iDstField] = (char *) poField->GetNameRef();
          if( *papszFieldNames[iDstField] == '\0' )
              papszFieldNames[iDstField] = (char*) OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME;
          paeFieldTypes[iDstField] = SWQ_GEOMETRY;
      }
  
  /* -------------------------------------------------------------------- */
  /*      Try to parse.                                                   */
  /* -------------------------------------------------------------------- */
      OGRErr      eErr = OGRERR_NONE;
      CPLErr      eCPLErr;
  
      poTargetDefn = poDefn;
      eCPLErr = swq_expr_compile( pszExpression, nFieldCount,
                                  papszFieldNames, paeFieldTypes, 
                                  bCheck,
                                  poCustomFuncRegistrar,
                                  (swq_expr_node **) &pSWQExpr );
      if( eCPLErr != CE_None )
      {
          eErr = OGRERR_CORRUPT_DATA;
          pSWQExpr = NULL;
      }
  
      CPLFree( papszFieldNames );
      CPLFree( paeFieldTypes );
  
  
      return eErr;
  }
  
  /************************************************************************/
  /*                         OGRFeatureFetcher()                          */
  /************************************************************************/
  
  static swq_expr_node *OGRFeatureFetcher( swq_expr_node *op, void *pFeatureIn )
  
  {
      OGRFeature *poFeature = (OGRFeature *) pFeatureIn;
      swq_expr_node *poRetNode = NULL;
  
      if( op->field_type == SWQ_GEOMETRY )
      {
          int iField = op->field_index - (poFeature->GetFieldCount() + SPECIAL_FIELD_COUNT);
          poRetNode = new swq_expr_node( poFeature->GetGeomFieldRef(iField) );
          return poRetNode;
      }
  
      switch( op->field_type )
      {
        case SWQ_INTEGER:
        case SWQ_BOOLEAN:
          poRetNode = new swq_expr_node( 
              poFeature->GetFieldAsInteger(op->field_index) );
          break;
  
        case SWQ_INTEGER64:
          poRetNode = new swq_expr_node( 
              poFeature->GetFieldAsInteger64(op->field_index) );
          break;
  
        case SWQ_FLOAT:
          poRetNode = new swq_expr_node( 
              poFeature->GetFieldAsDouble(op->field_index) );
          break;
  
        default:
          poRetNode = new swq_expr_node( 
              poFeature->GetFieldAsString(op->field_index) );
          break;
      }
  
      poRetNode->is_null = !(poFeature->IsFieldSet(op->field_index));
  
      return poRetNode;
  }
  
  /************************************************************************/
  /*                              Evaluate()                              */
  /************************************************************************/
  
  int OGRFeatureQuery::Evaluate( OGRFeature *poFeature )
  
  {
      if( pSWQExpr == NULL )
          return FALSE;
  
      swq_expr_node *poResult;
  
      poResult = ((swq_expr_node *) pSWQExpr)->Evaluate( OGRFeatureFetcher,
                                                         (void *) poFeature );
  
      if( poResult == NULL )
          return FALSE;
  
      int bLogicalResult = FALSE;
      if( poResult->field_type == SWQ_INTEGER ||
          poResult->field_type == SWQ_INTEGER64 ||
          poResult->field_type == SWQ_BOOLEAN )
          bLogicalResult = (int)poResult->int_value;
  
      delete poResult;
  
      return bLogicalResult;
  }
  
  /************************************************************************/
  /*                            CanUseIndex()                             */
  /************************************************************************/
  
  int OGRFeatureQuery::CanUseIndex( OGRLayer *poLayer )
  {
      swq_expr_node *psExpr = (swq_expr_node *) pSWQExpr;
  
  /* -------------------------------------------------------------------- */
  /*      Do we have an index on the targetted layer?                     */
  /* -------------------------------------------------------------------- */
      if ( poLayer->GetIndex() == FALSE )
          return FALSE;
  
      return CanUseIndex( psExpr, poLayer );
  }
  
  int OGRFeatureQuery::CanUseIndex( swq_expr_node *psExpr,
                                    OGRLayer *poLayer )
  {
      OGRAttrIndex *poIndex;
  
  /* -------------------------------------------------------------------- */
  /*      Does the expression meet our requirements?                      */
  /* -------------------------------------------------------------------- */
      if( psExpr == NULL ||
          psExpr->eNodeType != SNT_OPERATION )
          return FALSE;
  
      if ((psExpr->nOperation == SWQ_OR || psExpr->nOperation == SWQ_AND) &&
           psExpr->nSubExprCount == 2)
      {
          return CanUseIndex( psExpr->papoSubExpr[0], poLayer ) &&
                 CanUseIndex( psExpr->papoSubExpr[1], poLayer );
      }
  
      if( !(psExpr->nOperation == SWQ_EQ || psExpr->nOperation == SWQ_IN)
          || psExpr->nSubExprCount < 2 )
          return FALSE;
  
      swq_expr_node *poColumn = psExpr->papoSubExpr[0];
      swq_expr_node *poValue = psExpr->papoSubExpr[1];
      
      if( poColumn->eNodeType != SNT_COLUMN
          || poValue->eNodeType != SNT_CONSTANT )
          return FALSE;
  
      poIndex = poLayer->GetIndex()->GetFieldIndex( poColumn->field_index );
      if( poIndex == NULL )
          return FALSE;
  
  /* -------------------------------------------------------------------- */
  /*      OK, we have an index                                            */
  /* -------------------------------------------------------------------- */
      return TRUE;
  }
  
  /************************************************************************/
  /*                       EvaluateAgainstIndices()                       */
  /*                                                                      */
  /*      Attempt to return a list of FIDs matching the given             */
  /*      attribute query conditions utilizing attribute indices.         */
  /*      Returns NULL if the result cannot be computed from the          */
  /*      available indices, or an "OGRNullFID" terminated list of        */
  /*      FIDs if it can.                                                 */
  /*                                                                      */
  /*      For now we only support equality tests on a single indexed      */
  /*      attribute field.  Eventually we should make this support        */
  /*      multi-part queries with ranges.                                 */
  /************************************************************************/
  
  static int CompareGIntBig(const void *pa, const void *pb)
  {
      GIntBig a = *((const GIntBig*)pa);
      GIntBig b = *((const GIntBig*)pb);
      if( a < b )
          return -1;
      else if( a > b )
          return 1;
      else
          return 0;
  }
  
  GIntBig *OGRFeatureQuery::EvaluateAgainstIndices( OGRLayer *poLayer, 
                                                 OGRErr *peErr )
  
  {
      swq_expr_node *psExpr = (swq_expr_node *) pSWQExpr;
  
      if( peErr != NULL )
          *peErr = OGRERR_NONE;
  
  /* -------------------------------------------------------------------- */
  /*      Do we have an index on the targetted layer?                     */
  /* -------------------------------------------------------------------- */
      if ( poLayer->GetIndex() == NULL )
          return NULL;
  
      GIntBig nFIDCount = 0;
      return EvaluateAgainstIndices(psExpr, poLayer, nFIDCount);
  }
  
  /* The input arrays must be sorted ! */
  static
  GIntBig* OGRORGIntBigArray(GIntBig panFIDList1[], GIntBig nFIDCount1,
                             GIntBig panFIDList2[], GIntBig nFIDCount2,
                             GIntBig& nFIDCount)
  {
      GIntBig nMaxCount = nFIDCount1 + nFIDCount2;
      GIntBig* panFIDList = (GIntBig*) CPLMalloc((size_t)(nMaxCount+1) * sizeof(GIntBig));
      nFIDCount = 0;
  
      GIntBig i1 = 0, i2 =0;
      for(;i1<nFIDCount1 || i2<nFIDCount2;)
      {
          if (i1 < nFIDCount1 && i2 < nFIDCount2)
          {
              GIntBig nVal1 = panFIDList1[i1];
              GIntBig nVal2 = panFIDList2[i2];
              if (nVal1 < nVal2)
              {
                  if (i1+1 < nFIDCount1 && panFIDList1[i1+1] <= nVal2)
                  {
                      panFIDList[nFIDCount ++] = nVal1;
                      i1 ++;
                  }
                  else
                  {
                      panFIDList[nFIDCount ++] = nVal1;
                      panFIDList[nFIDCount ++] = nVal2;
                      i1 ++;
                      i2 ++;
                  }
              }
              else if (nVal1 == nVal2)
              {
                  panFIDList[nFIDCount ++] = nVal1;
                  i1 ++;
                  i2 ++;
              }
              else
              {
                  if (i2+1 < nFIDCount2 && panFIDList2[i2+1] <= nVal1)
                  {
                      panFIDList[nFIDCount ++] = nVal2;
                      i2 ++;
                  }
                  else
                  {
                      panFIDList[nFIDCount ++] = nVal2;
                      panFIDList[nFIDCount ++] = nVal1;
                      i1 ++;
                      i2 ++;
                  }
              }
          }
          else if (i1 < nFIDCount1)
          {
              GIntBig nVal1 = panFIDList1[i1];
              panFIDList[nFIDCount ++] = nVal1;
              i1 ++;
          }
          else if (i2 < nFIDCount2)
          {
              GIntBig nVal2 = panFIDList2[i2];
              panFIDList[nFIDCount ++] = nVal2;
              i2 ++;
          }
      }
  
      panFIDList[nFIDCount] = OGRNullFID;
  
      return panFIDList;
  }
  
  /* The input arrays must be sorted ! */
  static
  GIntBig* OGRANDGIntBigArray(GIntBig panFIDList1[], GIntBig nFIDCount1,
                              GIntBig panFIDList2[], GIntBig nFIDCount2,
                              GIntBig& nFIDCount)
  {
      GIntBig nMaxCount = MAX(nFIDCount1, nFIDCount2);
      GIntBig* panFIDList = (GIntBig*) CPLMalloc((size_t)(nMaxCount+1) * sizeof(GIntBig));
      nFIDCount = 0;
  
      GIntBig i1 = 0, i2 =0;
      for(;i1<nFIDCount1 && i2<nFIDCount2;)
      {
          GIntBig nVal1 = panFIDList1[i1];
          GIntBig nVal2 = panFIDList2[i2];
          if (nVal1 < nVal2)
          {
              if (i1+1 < nFIDCount1 && panFIDList1[i1+1] <= nVal2)
              {
                  i1 ++;
              }
              else
              {
                  i1 ++;
                  i2 ++;
              }
          }
          else if (nVal1 == nVal2)
          {
              panFIDList[nFIDCount ++] = nVal1;
              i1 ++;
              i2 ++;
          }
          else
          {
              if (i2+1 < nFIDCount2 && panFIDList2[i2+1] <= nVal1)
              {
                  i2 ++;
              }
              else
              {
                  i1 ++;
                  i2 ++;
              }
          }
      }
  
      panFIDList[nFIDCount] = OGRNullFID;
  
      return panFIDList;
  }
  
  GIntBig *OGRFeatureQuery::EvaluateAgainstIndices( swq_expr_node *psExpr,
                                                    OGRLayer *poLayer,
                                                    GIntBig& nFIDCount )
  {
      OGRAttrIndex *poIndex;
  
  /* -------------------------------------------------------------------- */
  /*      Does the expression meet our requirements?                      */
  /* -------------------------------------------------------------------- */
      if( psExpr == NULL ||
          psExpr->eNodeType != SNT_OPERATION )
          return NULL;
  
      if ((psExpr->nOperation == SWQ_OR || psExpr->nOperation == SWQ_AND) &&
           psExpr->nSubExprCount == 2)
      {
          GIntBig nFIDCount1 = 0, nFIDCount2 = 0;
          GIntBig* panFIDList1 = EvaluateAgainstIndices( psExpr->papoSubExpr[0], poLayer, nFIDCount1 );
          GIntBig* panFIDList2 = panFIDList1 == NULL ? NULL :
                              EvaluateAgainstIndices( psExpr->papoSubExpr[1], poLayer, nFIDCount2 );
          GIntBig* panFIDList = NULL;
          if (panFIDList1 != NULL && panFIDList2 != NULL)
          {
              if (psExpr->nOperation == SWQ_OR )
                  panFIDList = OGRORGIntBigArray(panFIDList1, nFIDCount1,
                                              panFIDList2, nFIDCount2, nFIDCount);
              else if (psExpr->nOperation == SWQ_AND )
                  panFIDList = OGRANDGIntBigArray(panFIDList1, nFIDCount1,
                                              panFIDList2, nFIDCount2, nFIDCount);
  
          }
          CPLFree(panFIDList1);
          CPLFree(panFIDList2);
          return panFIDList;
      }
  
      if( !(psExpr->nOperation == SWQ_EQ || psExpr->nOperation == SWQ_IN)
          || psExpr->nSubExprCount < 2 )
          return NULL;
  
      swq_expr_node *poColumn = psExpr->papoSubExpr[0];
      swq_expr_node *poValue = psExpr->papoSubExpr[1];
      
      if( poColumn->eNodeType != SNT_COLUMN
          || poValue->eNodeType != SNT_CONSTANT )
          return NULL;
  
      poIndex = poLayer->GetIndex()->GetFieldIndex( poColumn->field_index );
      if( poIndex == NULL )
          return NULL;
  
  /* -------------------------------------------------------------------- */
  /*      OK, we have an index, now we need to query it.                  */
  /* -------------------------------------------------------------------- */
      OGRField sValue;
      OGRFieldDefn *poFieldDefn;
  
      poFieldDefn = poLayer->GetLayerDefn()->GetFieldDefn(poColumn->field_index);
  
  /* -------------------------------------------------------------------- */
  /*      Handle the case of an IN operation.                             */
  /* -------------------------------------------------------------------- */
      if (psExpr->nOperation == SWQ_IN)
      {
          int nLength;
          GIntBig *panFIDs = NULL;
          int iIN;
  
          for( iIN = 1; iIN < psExpr->nSubExprCount; iIN++ )
          {
              switch( poFieldDefn->GetType() )
              {
                case OFTInteger:
                  if (psExpr->papoSubExpr[iIN]->field_type == SWQ_FLOAT)
                      sValue.Integer = (int) psExpr->papoSubExpr[iIN]->float_value;
                  else
                      sValue.Integer = (int) psExpr->papoSubExpr[iIN]->int_value;
                  break;
  
                case OFTInteger64:
                  if (psExpr->papoSubExpr[iIN]->field_type == SWQ_FLOAT)
                      sValue.Integer64 = (GIntBig) psExpr->papoSubExpr[iIN]->float_value;
                  else
                      sValue.Integer64 = psExpr->papoSubExpr[iIN]->int_value;
                  break;
  
                case OFTReal:
                  sValue.Real = psExpr->papoSubExpr[iIN]->float_value;
                  break;
  
                case OFTString:
                  sValue.String = psExpr->papoSubExpr[iIN]->string_value;
                  break;
  
                default:
                  CPLAssert( FALSE );
                  return NULL;
              }
  
              int nFIDCount32 = 0;
              panFIDs = poIndex->GetAllMatches( &sValue, panFIDs, &nFIDCount32, &nLength );
              nFIDCount = nFIDCount32;
          }
  
          if (nFIDCount > 1)
          {
              /* the returned FIDs are expected to be in sorted order */
              qsort(panFIDs, (size_t)nFIDCount, sizeof(GIntBig), CompareGIntBig);
          }
          return panFIDs;
      }
  
  /* -------------------------------------------------------------------- */
  /*      Handle equality test.                                           */
  /* -------------------------------------------------------------------- */
      switch( poFieldDefn->GetType() )
      {
        case OFTInteger:
          if (poValue->field_type == SWQ_FLOAT)
              sValue.Integer = (int) poValue->float_value;
          else
              sValue.Integer = (int) poValue->int_value;
          break;
        
        case OFTInteger64:
          if (poValue->field_type == SWQ_FLOAT)
              sValue.Integer64 = (GIntBig) poValue->float_value;
          else
              sValue.Integer64 = poValue->int_value;
          break;
          
        case OFTReal:
          sValue.Real = poValue->float_value;
          break;
          
        case OFTString:
          sValue.String = poValue->string_value;
          break;
  
        default:
          CPLAssert( FALSE );
          return NULL;
      }
  
      int nLength = 0;
      int nFIDCount32 = 0;
      GIntBig* panFIDs = poIndex->GetAllMatches( &sValue, NULL, &nFIDCount32, &nLength );
      nFIDCount = nFIDCount32;
      if (nFIDCount > 1)
      {
          /* the returned FIDs are expected to be in sorted order */
          qsort(panFIDs, (size_t)nFIDCount, sizeof(GIntBig), CompareGIntBig);
      }
      return panFIDs;
  }
  
  /************************************************************************/
  /*                         OGRFieldCollector()                          */
  /*                                                                      */
  /*      Helper function for recursing through tree to satisfy           */
  /*      GetUsedFields().                                                */
  /************************************************************************/
  
  char **OGRFeatureQuery::FieldCollector( void *pBareOp, 
                                          char **papszList )
  
  {
      swq_expr_node *op = (swq_expr_node *) pBareOp;
  
  /* -------------------------------------------------------------------- */
  /*      References to tables other than the primarily are currently     */
  /*      unsupported. Error out.                                         */
  /* -------------------------------------------------------------------- */
      if( op->eNodeType == SNT_COLUMN )
      {
          if( op->table_index != 0 )
          {
              CSLDestroy( papszList );
              return NULL;
          }
  
  /* -------------------------------------------------------------------- */
  /*      Add the field name into our list if it is not already there.    */
  /* -------------------------------------------------------------------- */
          const char *pszFieldName;
  
          if( op->field_index >= poTargetDefn->GetFieldCount()
              && op->field_index < poTargetDefn->GetFieldCount() + SPECIAL_FIELD_COUNT)
              pszFieldName = SpecialFieldNames[op->field_index - poTargetDefn->GetFieldCount()];
          else if( op->field_index >= 0
                   && op->field_index < poTargetDefn->GetFieldCount() )
              pszFieldName = 
                  poTargetDefn->GetFieldDefn(op->field_index)->GetNameRef();
          else
          {
              CSLDestroy( papszList );
              return NULL;
          }
          
          if( CSLFindString( papszList, pszFieldName ) == -1 )
              papszList = CSLAddString( papszList, pszFieldName );
      }
  
  /* -------------------------------------------------------------------- */
  /*      Add in fields from subexpressions.                              */
  /* -------------------------------------------------------------------- */
      if( op->eNodeType == SNT_OPERATION )
      {
          for( int iSubExpr = 0; iSubExpr < op->nSubExprCount; iSubExpr++ )
          {
              papszList = FieldCollector( op->papoSubExpr[iSubExpr], papszList );
          }
      }
  
      return papszList;
  }
  
  /************************************************************************/
  /*                           GetUsedFields()                            */
  /************************************************************************/
  
  /**
   * Returns lists of fields in expression.
   *
   * All attribute fields are used in the expression of this feature
   * query are returned as a StringList of field names.  This function would
   * primarily be used within drivers to recognise special case conditions
   * depending only on attribute fields that can be very efficiently 
   * fetched. 
   *
   * NOTE: If any fields in the expression are from tables other than the
   * primary table then NULL is returned indicating an error.  In succesful
   * use, no non-empty expression should return an empty list.
   *
   * @return list of field names.  Free list with CSLDestroy() when no longer
   * required.
   */
  
  char **OGRFeatureQuery::GetUsedFields( )
  
  {
      if( pSWQExpr == NULL )
          return NULL;
  
      
      return FieldCollector( pSWQExpr, NULL );
  }
  
  
  
  