Example #1
0
OGRLayer * OGRDataSource::ExecuteSQL( const char *pszStatement,
                                      OGRGeometry *poSpatialFilter,
                                      const char *pszDialect )

{
    const char *pszError;
    swq_select *psSelectInfo = NULL;

    (void) pszDialect;

/* -------------------------------------------------------------------- */
/*      Handle CREATE INDEX statements specially.                       */
/* -------------------------------------------------------------------- */
    if( EQUALN(pszStatement,"CREATE INDEX",12) )
    {
        ProcessSQLCreateIndex( pszStatement );
        return NULL;
    }
    
/* -------------------------------------------------------------------- */
/*      Handle DROP INDEX statements specially.                         */
/* -------------------------------------------------------------------- */
    if( EQUALN(pszStatement,"DROP INDEX",10) )
    {
        ProcessSQLDropIndex( pszStatement );
        return NULL;
    }
    
/* -------------------------------------------------------------------- */
/*      Preparse the SQL statement.                                     */
/* -------------------------------------------------------------------- */
    pszError = swq_select_preparse( pszStatement, &psSelectInfo );
    if( pszError != NULL )
    {
        CPLError( CE_Failure, CPLE_AppDefined, 
                  "SQL: %s", pszError );
        return NULL;
    }

/* -------------------------------------------------------------------- */
/*      Validate that all the source tables are recognised, count       */
/*      fields.                                                         */
/* -------------------------------------------------------------------- */
    int  nFieldCount = 0, iTable;

    for( iTable = 0; iTable < psSelectInfo->table_count; iTable++ )
    {
        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
        OGRLayer *poSrcLayer;
        OGRDataSource *poTableDS = this;

        if( psTableDef->data_source != NULL )
        {
            poTableDS = (OGRDataSource *) 
                OGROpenShared( psTableDef->data_source, FALSE, NULL );
            if( poTableDS == NULL )
            {
                if( strlen(CPLGetLastErrorMsg()) == 0 )
                    CPLError( CE_Failure, CPLE_AppDefined, 
                              "Unable to open secondary datasource\n"
                              "`%s' required by JOIN.",
                              psTableDef->data_source );

                swq_select_free( psSelectInfo );
                return NULL;
            }

            // This drops explicit reference, but leave it open for use by
            // code in ogr_gensql.cpp
            poTableDS->Dereference();
        }

        poSrcLayer = poTableDS->GetLayerByName( psTableDef->table_name );

        if( poSrcLayer == NULL )
        {
            CPLError( CE_Failure, CPLE_AppDefined, 
                      "SELECT from table %s failed, no such table/featureclass.",
                      psTableDef->table_name );
            swq_select_free( psSelectInfo );
            return NULL;
        }

        nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount();
    }
    
/* -------------------------------------------------------------------- */
/*      Build the field list for all indicated tables.                  */
/* -------------------------------------------------------------------- */
    swq_field_list sFieldList;
    int            nFIDIndex = 0;

    memset( &sFieldList, 0, sizeof(sFieldList) );
    sFieldList.table_count = psSelectInfo->table_count;
    sFieldList.table_defs = psSelectInfo->table_defs;

    sFieldList.count = 0;
    sFieldList.names = (char **) CPLMalloc( sizeof(char *) * (nFieldCount+1) );
    sFieldList.types = (swq_field_type *)  
        CPLMalloc( sizeof(swq_field_type) * (nFieldCount+1) );
    sFieldList.table_ids = (int *) 
        CPLMalloc( sizeof(int) * (nFieldCount+1) );
    sFieldList.ids = (int *) 
        CPLMalloc( sizeof(int) * (nFieldCount+1) );
    
    for( iTable = 0; iTable < psSelectInfo->table_count; iTable++ )
    {
        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
        OGRDataSource *poTableDS = this;
        OGRLayer *poSrcLayer;
        int      iField;

        if( psTableDef->data_source != NULL )
        {
            poTableDS = (OGRDataSource *) 
                OGROpenShared( psTableDef->data_source, FALSE, NULL );
            CPLAssert( poTableDS != NULL );
            poTableDS->Dereference();
        }

        poSrcLayer = poTableDS->GetLayerByName( psTableDef->table_name );

        for( iField = 0; 
             iField < poSrcLayer->GetLayerDefn()->GetFieldCount();
             iField++ )
        {
            OGRFieldDefn *poFDefn=poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
            int iOutField = sFieldList.count++;
            sFieldList.names[iOutField] = (char *) poFDefn->GetNameRef();
            if( poFDefn->GetType() == OFTInteger )
                sFieldList.types[iOutField] = SWQ_INTEGER;
            else if( poFDefn->GetType() == OFTReal )
                sFieldList.types[iOutField] = SWQ_FLOAT;
            else if( poFDefn->GetType() == OFTString )
                sFieldList.types[iOutField] = SWQ_STRING;
            else
                sFieldList.types[iOutField] = SWQ_OTHER;

            sFieldList.table_ids[iOutField] = iTable;
            sFieldList.ids[iOutField] = iField;
        }

        if( iTable == 0 )
            nFIDIndex = poSrcLayer->GetLayerDefn()->GetFieldCount();
    }

/* -------------------------------------------------------------------- */
/*      Expand '*' in 'SELECT *' now before we add the pseudo field     */
/*      'FID'.                                                          */
/* -------------------------------------------------------------------- */
    pszError = 
        swq_select_expand_wildcard( psSelectInfo, &sFieldList );

    if( pszError != NULL )
    {
        CPLError( CE_Failure, CPLE_AppDefined, 
                  "SQL: %s", pszError );
        return NULL;
    }

    sFieldList.names[sFieldList.count] = "FID";
    sFieldList.types[sFieldList.count] = SWQ_INTEGER;
    sFieldList.table_ids[sFieldList.count] = 0;
    sFieldList.ids[sFieldList.count] = nFIDIndex;
    
    sFieldList.count++;

/* -------------------------------------------------------------------- */
/*      Finish the parse operation.                                     */
/* -------------------------------------------------------------------- */
    
    pszError = swq_select_parse( psSelectInfo, &sFieldList, 0 );

    CPLFree( sFieldList.names );
    CPLFree( sFieldList.types );
    CPLFree( sFieldList.table_ids );
    CPLFree( sFieldList.ids );

    if( pszError != NULL )
    {
        CPLError( CE_Failure, CPLE_AppDefined, 
                  "SQL: %s", pszError );
        return NULL;
    }

/* -------------------------------------------------------------------- */
/*      Everything seems OK, try to instantiate a results layer.        */
/* -------------------------------------------------------------------- */
    OGRGenSQLResultsLayer *poResults;

    poResults = new OGRGenSQLResultsLayer( this, psSelectInfo, 
                                           poSpatialFilter );

    // Eventually, we should keep track of layers to cleanup.

    return poResults;
}
OGRLayer * OGRDataSource::ExecuteSQL( const char *pszStatement,
                                      OGRGeometry *poSpatialFilter,
                                      const char *pszDialect )

{
    const char *pszError;
    swq_select *psSelectInfo = NULL;

    (void) pszDialect;

    swq_field_list sFieldList;
    int            nFIDIndex = 0;
    OGRGenSQLResultsLayer *poResults = NULL;

    memset( &sFieldList, 0, sizeof(sFieldList) );

/* -------------------------------------------------------------------- */
/*      Handle CREATE INDEX statements specially.                       */
/* -------------------------------------------------------------------- */
    if( EQUALN(pszStatement,"CREATE INDEX",12) )
    {
        ProcessSQLCreateIndex( pszStatement );
        return NULL;
    }
    
/* -------------------------------------------------------------------- */
/*      Handle DROP INDEX statements specially.                         */
/* -------------------------------------------------------------------- */
    if( EQUALN(pszStatement,"DROP INDEX",10) )
    {
        ProcessSQLDropIndex( pszStatement );
        return NULL;
    }
    
/* -------------------------------------------------------------------- */
/*      Preparse the SQL statement.                                     */
/* -------------------------------------------------------------------- */
    pszError = swq_select_preparse( pszStatement, &psSelectInfo );
    if( pszError != NULL )
    {
        CPLError( CE_Failure, CPLE_AppDefined, 
                  "SQL: %s", pszError );
        return NULL;
    }

/* -------------------------------------------------------------------- */
/*      Validate that all the source tables are recognised, count       */
/*      fields.                                                         */
/* -------------------------------------------------------------------- */
    int  nFieldCount = 0, iTable, iField;
    int  iEDS;
    int  nExtraDSCount = 0;
    OGRDataSource** papoExtraDS = NULL;
    OGRSFDriverRegistrar *poReg=OGRSFDriverRegistrar::GetRegistrar();

    for( iTable = 0; iTable < psSelectInfo->table_count; iTable++ )
    {
        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
        OGRLayer *poSrcLayer;
        OGRDataSource *poTableDS = this;

        if( psTableDef->data_source != NULL )
        {
            poTableDS = (OGRDataSource *) 
                OGROpenShared( psTableDef->data_source, FALSE, NULL );
            if( poTableDS == NULL )
            {
                if( strlen(CPLGetLastErrorMsg()) == 0 )
                    CPLError( CE_Failure, CPLE_AppDefined, 
                              "Unable to open secondary datasource\n"
                              "`%s' required by JOIN.",
                              psTableDef->data_source );

                swq_select_free( psSelectInfo );
                goto end;
            }

            /* Keep in an array to release at the end of this function */
            papoExtraDS = (OGRDataSource** )CPLRealloc(papoExtraDS,
                               sizeof(OGRDataSource*) * (nExtraDSCount + 1));
            papoExtraDS[nExtraDSCount++] = poTableDS;
        }

        poSrcLayer = poTableDS->GetLayerByName( psTableDef->table_name );

        if( poSrcLayer == NULL )
        {
            CPLError( CE_Failure, CPLE_AppDefined, 
                      "SELECT from table %s failed, no such table/featureclass.",
                      psTableDef->table_name );
            swq_select_free( psSelectInfo );
            goto end;
        }

        nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount();
    }
    
/* -------------------------------------------------------------------- */
/*      Build the field list for all indicated tables.                  */
/* -------------------------------------------------------------------- */

    sFieldList.table_count = psSelectInfo->table_count;
    sFieldList.table_defs = psSelectInfo->table_defs;

    sFieldList.count = 0;
    sFieldList.names = (char **) CPLMalloc( sizeof(char *) * (nFieldCount+SPECIAL_FIELD_COUNT) );
    sFieldList.types = (swq_field_type *)  
        CPLMalloc( sizeof(swq_field_type) * (nFieldCount+SPECIAL_FIELD_COUNT) );
    sFieldList.table_ids = (int *) 
        CPLMalloc( sizeof(int) * (nFieldCount+SPECIAL_FIELD_COUNT) );
    sFieldList.ids = (int *) 
        CPLMalloc( sizeof(int) * (nFieldCount+SPECIAL_FIELD_COUNT) );
    
    for( iTable = 0; iTable < psSelectInfo->table_count; iTable++ )
    {
        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
        OGRDataSource *poTableDS = this;
        OGRLayer *poSrcLayer;
        
        if( psTableDef->data_source != NULL )
        {
            poTableDS = (OGRDataSource *) 
                OGROpenShared( psTableDef->data_source, FALSE, NULL );
            CPLAssert( poTableDS != NULL );
            poTableDS->Dereference();
        }

        poSrcLayer = poTableDS->GetLayerByName( psTableDef->table_name );

        for( iField = 0; 
             iField < poSrcLayer->GetLayerDefn()->GetFieldCount();
             iField++ )
        {
            OGRFieldDefn *poFDefn=poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
            int iOutField = sFieldList.count++;
            sFieldList.names[iOutField] = (char *) poFDefn->GetNameRef();
            if( poFDefn->GetType() == OFTInteger )
                sFieldList.types[iOutField] = SWQ_INTEGER;
            else if( poFDefn->GetType() == OFTReal )
                sFieldList.types[iOutField] = SWQ_FLOAT;
            else if( poFDefn->GetType() == OFTString )
                sFieldList.types[iOutField] = SWQ_STRING;
            else
                sFieldList.types[iOutField] = SWQ_OTHER;

            sFieldList.table_ids[iOutField] = iTable;
            sFieldList.ids[iOutField] = iField;
        }

        if( iTable == 0 )
            nFIDIndex = poSrcLayer->GetLayerDefn()->GetFieldCount();
    }

/* -------------------------------------------------------------------- */
/*      Expand '*' in 'SELECT *' now before we add the pseudo fields    */
/* -------------------------------------------------------------------- */
    pszError = 
        swq_select_expand_wildcard( psSelectInfo, &sFieldList );

    if( pszError != NULL )
    {
        swq_select_free( psSelectInfo );
        CPLError( CE_Failure, CPLE_AppDefined, 
                  "SQL: %s", pszError );
        goto end;
    }

    for (iField = 0; iField < SPECIAL_FIELD_COUNT; iField++)
    {
        sFieldList.names[sFieldList.count] = (char*) SpecialFieldNames[iField];
        sFieldList.types[sFieldList.count] = SpecialFieldTypes[iField];
        sFieldList.table_ids[sFieldList.count] = 0;
        sFieldList.ids[sFieldList.count] = nFIDIndex + iField;
        sFieldList.count++;
    }
    
/* -------------------------------------------------------------------- */
/*      Finish the parse operation.                                     */
/* -------------------------------------------------------------------- */
    
    pszError = swq_select_parse( psSelectInfo, &sFieldList, 0 );

    if( pszError != NULL )
    {
        swq_select_free( psSelectInfo );
        CPLError( CE_Failure, CPLE_AppDefined, 
                  "SQL: %s", pszError );
        goto end;
    }

/* -------------------------------------------------------------------- */
/*      Everything seems OK, try to instantiate a results layer.        */
/* -------------------------------------------------------------------- */

    poResults = new OGRGenSQLResultsLayer( this, psSelectInfo, 
                                           poSpatialFilter );

    // Eventually, we should keep track of layers to cleanup.

end:
    CPLFree( sFieldList.names );
    CPLFree( sFieldList.types );
    CPLFree( sFieldList.table_ids );
    CPLFree( sFieldList.ids );

    /* Release the datasets we have opened with OGROpenShared() */
    /* It is safe to do that as the 'new OGRGenSQLResultsLayer' itself */
    /* has taken a reference on them, which it will release in its */
    /* destructor */
    for(iEDS = 0; iEDS < nExtraDSCount; iEDS++)
        poReg->ReleaseDataSource( papoExtraDS[iEDS] );
    CPLFree(papoExtraDS);

    return poResults;
}