text:
#include "ogr_carto.h"
#include "ogr_p.h"
#include "ogr_pgdump.h"
#include "ogrgeojsonreader.h"

CPL_CVSID("$Id: ogrcartotablelayer.cpp bbf71e8897edecc0956101f09fea2e6cb906ae0d 2018-08-13 11:53:00 +0200 Even Rouault $")

/************************************************************************/
/*                    OGRCARTOEscapeIdentifier( )                     */
/************************************************************************/

CPLString OGRCARTOEscapeIdentifier(const char* pszStr)
{
    CPLString osStr;

    osStr += "\"";

    char ch = '\0';
    for(int i=0; (ch = pszStr[i]) != '\0'; i++)
    {
        if (ch == '"')
            osStr.append(1, ch);
        osStr.append(1, ch);
    }

    osStr += "\"";

    return osStr;
}

/************************************************************************/
/*                    OGRCARTOEscapeLiteralCopy( )                      */
/************************************************************************/

CPLString OGRCARTOEscapeLiteralCopy(const char* pszStr)
{
    CPLString osStr;

    /* convert special characters in COPY text format */
    /* into their escaped forms, and double up the escape */
    /* character */
    char ch = '\0';
    for(int i=0; (ch = pszStr[i]) != '\0'; i++)
    {
        if (ch == '\t') // tab
            osStr += "\\t";
        else if (ch == '\n') // new line
            osStr += "\\n";
        else if (ch == '\r') // carriage return
            osStr += "\\r";
        else if (ch == '\\') // escape character
            osStr += "\\\\";
        else
            osStr.append(1, ch);
    }

    return osStr;
}

/************************************************************************/
/*                    OGRCARTOEscapeLiteral( )                        */
/************************************************************************/

CPLString OGRCARTOEscapeLiteral(const char* pszStr)
{
    CPLString osStr;

    char ch = '\0';
    for(int i=0; (ch = pszStr[i]) != '\0'; i++)
    {
        if (ch == '\'')
            osStr.append(1, ch);
        osStr.append(1, ch);
    }

    return osStr;
}

/************************************************************************/
/*                    OGRCARTOEscapeLiteral( )                          */
/************************************************************************/

char *
OGRCARTOTableLayer::OGRCARTOGetHexGeometry( OGRGeometry* poGeom, int i )
{
    OGRCartoGeomFieldDefn* poGeomFieldDefn =
        (OGRCartoGeomFieldDefn *)(poFeatureDefn->GetGeomFieldDefn(i));
    int nSRID = poGeomFieldDefn->nSRID;
    if( nSRID == 0 )
        nSRID = 4326;
    char* pszEWKB;
    if( wkbFlatten(poGeom->getGeometryType()) == wkbPolygon &&
        wkbFlatten(GetGeomType()) == wkbMultiPolygon )
    {
        OGRMultiPolygon* poNewGeom = new OGRMultiPolygon();
        poNewGeom->addGeometry(poGeom);
        pszEWKB = OGRGeometryToHexEWKB(poNewGeom, nSRID,
                                       poDS->GetPostGISMajor(),
                                       poDS->GetPostGISMinor());
        delete poNewGeom;
    }
    else
        pszEWKB = OGRGeometryToHexEWKB(poGeom, nSRID,
                                       poDS->GetPostGISMajor(),
                                       poDS->GetPostGISMinor());
    return pszEWKB;
}

/************************************************************************/
/*                        OGRCARTOTableLayer()                          */
/************************************************************************/

OGRCARTOTableLayer::OGRCARTOTableLayer(OGRCARTODataSource* poDSIn,
                                       const char* pszName) :
    OGRCARTOLayer(poDSIn),
    osName( pszName )
{
    SetDescription( osName );
    bLaunderColumnNames = true;
    bInDeferredInsert = poDS->DoBatchInsert();
    bCopyMode = poDS->DoCopyMode();
    eDeferredInsertState = INSERT_UNINIT;
    m_nNextFIDWrite = -1;
    bDeferredCreation = false;
    bCartodbfy = false;
    nMaxChunkSize = atoi(CPLGetConfigOption("CARTO_MAX_CHUNK_SIZE",
            CPLGetConfigOption("CARTODB_MAX_CHUNK_SIZE", "15"))) * 1024 * 1024;
}

/************************************************************************/
/*                    ~OGRCARTOTableLayer()                           */
/************************************************************************/

OGRCARTOTableLayer::~OGRCARTOTableLayer()

{
    if( bDeferredCreation ) RunDeferredCreationIfNecessary();
    CPL_IGNORE_RET_VAL(FlushDeferredBuffer());
    RunDeferredCartofy();
}

/************************************************************************/
/*                          GetLayerDefnInternal()                      */
/************************************************************************/

OGRFeatureDefn * OGRCARTOTableLayer::GetLayerDefnInternal(CPL_UNUSED json_object* poObjIn)
{
    if( poFeatureDefn != nullptr )
        return poFeatureDefn;

    CPLString osCommand;
    if( poDS->IsAuthenticatedConnection() )
    {
        // Get everything !
        osCommand.Printf(
                 "SELECT a.attname, t.typname, a.attlen, "
                        "format_type(a.atttypid,a.atttypmod), "
                        "a.attnum, "
                        "a.attnotnull, "
                        "i.indisprimary, "
                        "pg_get_expr(def.adbin, c.oid) AS defaultexpr, "
                        "postgis_typmod_dims(a.atttypmod) dim, "
                        "postgis_typmod_srid(a.atttypmod) srid, "
                        "postgis_typmod_type(a.atttypmod)::text geomtyp, "
                        "srtext "
                 "FROM pg_class c "
                 "JOIN pg_attribute a ON a.attnum > 0 AND "
                                        "a.attrelid = c.oid AND c.relname = '%s' "
                 "JOIN pg_type t ON a.atttypid = t.oid "
                 "JOIN pg_namespace n ON c.relnamespace=n.oid AND n.nspname= '%s' "
                 "LEFT JOIN pg_index i ON c.oid = i.indrelid AND "
                                         "i.indisprimary = 't' AND a.attnum = ANY(i.indkey) "
                 "LEFT JOIN pg_attrdef def ON def.adrelid = c.oid AND "
                                              "def.adnum = a.attnum "
                 "LEFT JOIN spatial_ref_sys srs ON srs.srid = postgis_typmod_srid(a.atttypmod) "
                 "ORDER BY a.attnum",
                 OGRCARTOEscapeLiteral(osName).c_str(),
                 OGRCARTOEscapeLiteral(poDS->GetCurrentSchema()).c_str());
    }
    else if( poDS->HasOGRMetadataFunction() != FALSE )
    {
        osCommand.Printf( "SELECT * FROM ogr_table_metadata('%s', '%s')",
                          OGRCARTOEscapeLiteral(poDS->GetCurrentSchema()).c_str(),
                          OGRCARTOEscapeLiteral(osName).c_str() );
    }

    if( !osCommand.empty() )
    {
        if( !poDS->IsAuthenticatedConnection() && poDS->HasOGRMetadataFunction() < 0 )
            CPLPushErrorHandler(CPLQuietErrorHandler);
        OGRLayer* poLyr = poDS->ExecuteSQLInternal(osCommand);
        if( !poDS->IsAuthenticatedConnection() && poDS->HasOGRMetadataFunction() < 0 )
        {
            CPLPopErrorHandler();
            if( poLyr == nullptr )
            {
                CPLDebug("CARTO", "ogr_table_metadata(text, text) not available");
                CPLErrorReset();
            }
            else if( poLyr->GetLayerDefn()->GetFieldCount() != 12 )
            {
                CPLDebug("CARTO", "ogr_table_metadata(text, text) has unexpected column count");
                poDS->ReleaseResultSet(poLyr);
                poLyr = nullptr;
            }
            poDS->SetOGRMetadataFunction(poLyr != nullptr);
        }
        if( poLyr )
        {
            OGRFeature* poFeat;
            while( (poFeat = poLyr->GetNextFeature()) != nullptr )
            {
                if( poFeatureDefn == nullptr )
                {
                    // We could do that outside of the while() loop, but
                    // by doing that here, we are somewhat robust to
                    // ogr_table_metadata() returning suddenly an empty result set
                    // for example if CDB_UserTables() no longer works
                    poFeatureDefn = new OGRFeatureDefn(osName);
                    poFeatureDefn->Reference();
                    poFeatureDefn->SetGeomType(wkbNone);
                }

                const char* pszAttname = poFeat->GetFieldAsString("attname");
                const char* pszType = poFeat->GetFieldAsString("typname");
                int nWidth = poFeat->GetFieldAsInteger("attlen");
                const char* pszFormatType = poFeat->GetFieldAsString("format_type");
                int bNotNull = poFeat->GetFieldAsInteger("attnotnull");
                int bIsPrimary = poFeat->GetFieldAsInteger("indisprimary");
                int iDefaultExpr = poLyr->GetLayerDefn()->GetFieldIndex("defaultexpr");
                const char* pszDefault = (iDefaultExpr >= 0 && poFeat->IsFieldSetAndNotNull(iDefaultExpr)) ?
                            poFeat->GetFieldAsString(iDefaultExpr) : nullptr;

                if( bIsPrimary &&
                    (EQUAL(pszType, "int2") ||
                     EQUAL(pszType, "int4") ||
                     EQUAL(pszType, "int8") ||
                     EQUAL(pszType, "serial") ||
                     EQUAL(pszType, "bigserial")) )
                {
                    osFIDColName = pszAttname;
                }
                else if( strcmp(pszAttname, "created_at") == 0 ||
                         strcmp(pszAttname, "updated_at") == 0 ||
                         strcmp(pszAttname, "the_geom_webmercator") == 0)
                {
                    /* ignored */
                }
                else
                {
                    if( EQUAL(pszType,"geometry") )
                    {
                        int nDim = poFeat->GetFieldAsInteger("dim");
                        int nSRID = poFeat->GetFieldAsInteger("srid");
                        const char* pszGeomType = poFeat->GetFieldAsString("geomtyp");
                        const char* pszSRText = (poFeat->IsFieldSetAndNotNull(
                            poLyr->GetLayerDefn()->GetFieldIndex("srtext"))) ?
                                    poFeat->GetFieldAsString("srtext") : nullptr;
                        OGRwkbGeometryType eType = OGRFromOGCGeomType(pszGeomType);
                        if( nDim == 3 )
                            eType = wkbSetZ(eType);
                        OGRCartoGeomFieldDefn *poFieldDefn =
                            new OGRCartoGeomFieldDefn(pszAttname, eType);
                        if( bNotNull )
                            poFieldDefn->SetNullable(FALSE);
                        OGRSpatialReference* l_poSRS = nullptr;
                        if( pszSRText != nullptr )
                        {
                            l_poSRS = new OGRSpatialReference();
                            if( l_poSRS->importFromWkt(pszSRText) != OGRERR_NONE )
                            {
                                delete l_poSRS;
                                l_poSRS = nullptr;
                            }
                            if( l_poSRS != nullptr )
                            {
                                poFieldDefn->SetSpatialRef(l_poSRS);
                                l_poSRS->Release();
                            }
                        }
                        poFieldDefn->nSRID = nSRID;
                        poFeatureDefn->AddGeomFieldDefn(poFieldDefn, FALSE);
                    }
                    else
                    {
                        OGRFieldDefn oField(pszAttname, OFTString);
                        if( bNotNull )
                            oField.SetNullable(FALSE);
                        OGRPGCommonLayerSetType(oField, pszType, pszFormatType, nWidth);
                        if( pszDefault )
                            OGRPGCommonLayerNormalizeDefault(&oField, pszDefault);

                        poFeatureDefn->AddFieldDefn( &oField );
                    }
                }
                delete poFeat;
            }

            poDS->ReleaseResultSet(poLyr);
        }
    }

    if( poFeatureDefn == nullptr )
    {
        osBaseSQL.Printf("SELECT * FROM %s", OGRCARTOEscapeIdentifier(osName).c_str());
        EstablishLayerDefn(osName, nullptr);
        osBaseSQL = "";
    }

    if( !osFIDColName.empty() )
    {
        osBaseSQL = "SELECT ";
        osBaseSQL += OGRCARTOEscapeIdentifier(osFIDColName);
    }
    for(int i=0; i<poFeatureDefn->GetGeomFieldCount(); i++)
    {
        if( osBaseSQL.empty() )
            osBaseSQL = "SELECT ";
        else
            osBaseSQL += ", ";
        osBaseSQL += OGRCARTOEscapeIdentifier(poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef());
    }
    for(int i=0; i<poFeatureDefn->GetFieldCount(); i++)
    {
        if( osBaseSQL.empty() )
            osBaseSQL = "SELECT ";
        else
            osBaseSQL += ", ";
        osBaseSQL += OGRCARTOEscapeIdentifier(poFeatureDefn->GetFieldDefn(i)->GetNameRef());
    }
    if( osBaseSQL.empty() )
        osBaseSQL = "SELECT *";
    osBaseSQL += " FROM ";
    osBaseSQL += OGRCARTOEscapeIdentifier(osName);

    osSELECTWithoutWHERE = osBaseSQL;

    return poFeatureDefn;
}

/************************************************************************/
/*                        FetchNewFeatures()                            */
/************************************************************************/

json_object* OGRCARTOTableLayer::FetchNewFeatures()
{
    if( !osFIDColName.empty() )
    {
        CPLString osSQL;
        osSQL.Printf("%s WHERE %s%s >= " CPL_FRMT_GIB " ORDER BY %s ASC LIMIT %d",
                     osSELECTWithoutWHERE.c_str(),
                     ( osWHERE.size() ) ? CPLSPrintf("%s AND ", osWHERE.c_str()) : "",
                     OGRCARTOEscapeIdentifier(osFIDColName).c_str(),
                     m_nNextFID,
                     OGRCARTOEscapeIdentifier(osFIDColName).c_str(),
                     GetFeaturesToFetch());
        return poDS->RunSQL(osSQL);
    }
    else
        return OGRCARTOLayer::FetchNewFeatures();
}

/************************************************************************/
/*                           GetNextRawFeature()                        */
/************************************************************************/

OGRFeature  *OGRCARTOTableLayer::GetNextRawFeature()
{
    if( bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
        return nullptr;
    if( FlushDeferredBuffer() != OGRERR_NONE )
        return nullptr;
    return OGRCARTOLayer::GetNextRawFeature();
}

/************************************************************************/
/*                         SetAttributeFilter()                         */
/************************************************************************/

OGRErr OGRCARTOTableLayer::SetAttributeFilter( const char *pszQuery )

{
    GetLayerDefn();

    if( pszQuery == nullptr )
        osQuery = "";
    else
    {
        osQuery = "(";
        osQuery += pszQuery;
        osQuery += ")";
    }

    BuildWhere();

    ResetReading();

    return OGRERR_NONE;
}

/************************************************************************/
/*                          SetSpatialFilter()                          */
/************************************************************************/

void OGRCARTOTableLayer::SetSpatialFilter( int iGeomField, OGRGeometry * poGeomIn )

{
    if( iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
        GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone )
    {
        if( iGeomField != 0 )
        {
            CPLError(CE_Failure, CPLE_AppDefined,
                     "Invalid geometry field index : %d", iGeomField);
        }
        return;
    }
    m_iGeomFieldFilter = iGeomField;

    if( InstallFilter( poGeomIn ) )
    {
        BuildWhere();

        ResetReading();
    }
}

/************************************************************************/
/*                         RunDeferredCartofy()                         */
/************************************************************************/

void OGRCARTOTableLayer::RunDeferredCartofy()

{
    if( bCartodbfy )
    {
        bCartodbfy = false;

        CPLString osSQL;
        if( poDS->GetCurrentSchema() == "public" )
            osSQL.Printf("SELECT cdb_cartodbfytable('%s')",
                                OGRCARTOEscapeLiteral(osName).c_str());
        else
            osSQL.Printf("SELECT cdb_cartodbfytable('%s', '%s')",
                                OGRCARTOEscapeLiteral(poDS->GetCurrentSchema()).c_str(),
                                OGRCARTOEscapeLiteral(osName).c_str());

        json_object* poObj = poDS->RunSQL(osSQL);
        if( poObj != nullptr )
            json_object_put(poObj);
    }
}

/************************************************************************/
/*                        CARTOGeometryType()                           */
/************************************************************************/

static CPLString OGRCARTOGeometryType(OGRCartoGeomFieldDefn *poGeomField)
{
    OGRwkbGeometryType eType = poGeomField->GetType();
    const char *pszGeometryType = OGRToOGCGeomType(eType);
    const char *suffix = "";

    if( OGR_GT_HasM(eType) && OGR_GT_HasZ(eType) )
    {
        suffix = "ZM";
    }
    else if( OGR_GT_HasM(eType) )
    {
        suffix = "M";
    }
    else if( OGR_GT_HasZ(eType) )
    {
        suffix = "Z";
    }

    CPLString osSQL;
    osSQL.Printf("Geometry(%s%s,%d)",
        pszGeometryType,
        suffix,
        poGeomField->nSRID
        );

    return osSQL;
}

/************************************************************************/
/*                         FlushDeferredBuffer()                        */
/************************************************************************/

OGRErr OGRCARTOTableLayer::FlushDeferredBuffer(bool bReset)
{
    if (bCopyMode)
        return FlushDeferredCopy(bReset);
    else
        return FlushDeferredInsert(bReset);
}

/************************************************************************/
/*                         FlushDeferredInsert()                        */
/************************************************************************/

OGRErr OGRCARTOTableLayer::FlushDeferredInsert(bool bReset)
{
    OGRErr eErr = OGRERR_NONE;
    if( bInDeferredInsert && !osDeferredBuffer.empty() )
    {
        osDeferredBuffer = "BEGIN;" + osDeferredBuffer;
        if( eDeferredInsertState == INSERT_MULTIPLE_FEATURE )
        {
            osDeferredBuffer += ";";
            eDeferredInsertState = INSERT_UNINIT;
        }
        osDeferredBuffer += "COMMIT;";

        json_object* poObj = poDS->RunSQL(osDeferredBuffer);
        if( poObj != nullptr )
        {
            json_object_put(poObj);
        }
        else
        {
            bInDeferredInsert = false;
            eErr = OGRERR_FAILURE;
        }
    }

    osDeferredBuffer = "";
    if( bReset )
    {
        bInDeferredInsert = false;
        m_nNextFIDWrite = -1;
    }
    return eErr;
}

/************************************************************************/
/*                         FlushDeferredCopy()                          */
/************************************************************************/

OGRErr OGRCARTOTableLayer::FlushDeferredCopy(bool bReset)
{
    OGRErr eErr = OGRERR_NONE;
    if( !osDeferredBuffer.empty() )
    {
        /* And end-of-file marker to data buffer */
        osDeferredBuffer += "\\.\n";

        json_object* poObj = poDS->RunCopyFrom(osCopySQL, osDeferredBuffer);
        if( poObj != nullptr )
        {
            json_object_put(poObj);
        }
        else
        {
            bInDeferredInsert = false;
            eErr = OGRERR_FAILURE;
        }
    }

    osDeferredBuffer.clear();
    if( bReset )
    {
        bInDeferredInsert = false;
        m_nNextFIDWrite = -1;
    }
    return eErr;
}

/************************************************************************/
/*                          CreateGeomField()                           */
/************************************************************************/

OGRErr OGRCARTOTableLayer::CreateGeomField( OGRGeomFieldDefn *poGeomFieldIn,
                                          CPL_UNUSED int bApproxOK )
{
    if (!poDS->IsReadWrite())
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "Operation not available in read-only mode");
        return OGRERR_FAILURE;
    }

    OGRwkbGeometryType eType = poGeomFieldIn->GetType();
    if( eType == wkbNone )
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "Cannot create geometry field of type wkbNone");
        return OGRERR_FAILURE;
    }

    const char *pszNameIn = poGeomFieldIn->GetNameRef();
    CPLString osGeomFieldName = CPLString(pszNameIn);
    if( pszNameIn == nullptr || EQUAL(pszNameIn, "") )
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "Cannot add un-named geometry field");
        return OGRERR_FAILURE;
    }

    /* Flush the write buffer before trying this. */
    if( eDeferredInsertState == INSERT_MULTIPLE_FEATURE )
    {
        if( FlushDeferredBuffer() != OGRERR_NONE )
            return OGRERR_FAILURE;
    }

    OGRCartoGeomFieldDefn *poGeomField = new OGRCartoGeomFieldDefn(pszNameIn, eType);
    if( EQUAL(poGeomField->GetNameRef(), "") )
    {
        if( poFeatureDefn->GetGeomFieldCount() == 0 )
            poGeomField->SetName( "the_geom" );
    }
    poGeomField->SetSpatialRef(poGeomFieldIn->GetSpatialRef());

    if( bLaunderColumnNames )
    {
        char *pszSafeName = OGRPGCommonLaunderName( poGeomField->GetNameRef(), "PG" );
        poGeomField->SetName( pszSafeName );
        CPLFree( pszSafeName );
    }

    OGRSpatialReference* poSRS = poGeomField->GetSpatialRef();
    int nSRID = 0;
    if( poSRS != nullptr )
        nSRID = poDS->FetchSRSId( poSRS );

    poGeomField->SetType(eType);
    poGeomField->SetNullable(poGeomFieldIn->IsNullable());
    poGeomField->nSRID = nSRID;

/* -------------------------------------------------------------------- */
/*      Create the new field.                                           */
/* -------------------------------------------------------------------- */

    if( !bDeferredCreation )
    {
        CPLString osSQL;
        osSQL.Printf( "ALTER TABLE %s ADD COLUMN %s %s",
                    OGRCARTOEscapeIdentifier(osName).c_str(),
                    OGRCARTOEscapeIdentifier(poGeomField->GetNameRef()).c_str(),
                    OGRCARTOGeometryType(poGeomField).c_str()
                    );
        if( !poGeomField->IsNullable() )
            osSQL += " NOT NULL";

        json_object *poObj = poDS->RunSQL(osSQL);
        if( poObj == nullptr )
            return OGRERR_FAILURE;
        json_object_put(poObj);
    }

    poFeatureDefn->AddGeomFieldDefn( poGeomField, FALSE );
    return OGRERR_NONE;
}

/************************************************************************/
/*                            CreateField()                             */
/************************************************************************/

OGRErr OGRCARTOTableLayer::CreateField( OGRFieldDefn *poFieldIn,
                                          CPL_UNUSED int bApproxOK )
{
    GetLayerDefn();

    if (!poDS->IsReadWrite())
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "Operation not available in read-only mode");
        return OGRERR_FAILURE;
    }

    if( eDeferredInsertState == INSERT_MULTIPLE_FEATURE )
    {
        if( FlushDeferredBuffer() != OGRERR_NONE )
            return OGRERR_FAILURE;
    }

    OGRFieldDefn oField(poFieldIn);
    if( bLaunderColumnNames )
    {
        char* pszName = OGRPGCommonLaunderName(oField.GetNameRef());
        oField.SetName(pszName);
        CPLFree(pszName);
    }

/* -------------------------------------------------------------------- */
/*      Create the new field.                                           */
/* -------------------------------------------------------------------- */

    if( !bDeferredCreation )
    {
        CPLString osSQL;
        osSQL.Printf( "ALTER TABLE %s ADD COLUMN %s %s",
                    OGRCARTOEscapeIdentifier(osName).c_str(),
                    OGRCARTOEscapeIdentifier(oField.GetNameRef()).c_str(),
                    OGRPGCommonLayerGetType(oField, false, true).c_str() );
        if( !oField.IsNullable() )
            osSQL += " NOT NULL";
        if( oField.GetDefault() != nullptr && !oField.IsDefaultDriverSpecific() )
        {
            osSQL += " DEFAULT ";
            osSQL += OGRPGCommonLayerGetPGDefault(&oField);
        }

        json_object* poObj = poDS->RunSQL(osSQL);
        if( poObj == nullptr )
            return OGRERR_FAILURE;
        json_object_put(poObj);
    }

    poFeatureDefn->AddFieldDefn( &oField );

    return OGRERR_NONE;
}

/************************************************************************/
/*                            DeleteField()                             */
/************************************************************************/

OGRErr OGRCARTOTableLayer::DeleteField( int iField )
{
    CPLString           osSQL;

    if (!poDS->IsReadWrite())
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "Operation not available in read-only mode");
        return OGRERR_FAILURE;
    }

    if (iField < 0 || iField >= poFeatureDefn->GetFieldCount())
    {
        CPLError( CE_Failure, CPLE_NotSupported,
                  "Invalid field index");
        return OGRERR_FAILURE;
    }

    if( eDeferredInsertState == INSERT_MULTIPLE_FEATURE )
    {
        if( FlushDeferredBuffer() != OGRERR_NONE )
            return OGRERR_FAILURE;
    }

/* -------------------------------------------------------------------- */
/*      Drop the field.                                                 */
/* -------------------------------------------------------------------- */

    osSQL.Printf( "ALTER TABLE %s DROP COLUMN %s",
                  OGRCARTOEscapeIdentifier(osName).c_str(),
                  OGRCARTOEscapeIdentifier(poFeatureDefn->GetFieldDefn(iField)->GetNameRef()).c_str() );

    json_object* poObj = poDS->RunSQL(osSQL);
    if( poObj == nullptr )
        return OGRERR_FAILURE;
    json_object_put(poObj);

    return poFeatureDefn->DeleteFieldDefn( iField );
}

/************************************************************************/
/*                           ICreateFeature()                            */
/************************************************************************/

OGRErr OGRCARTOTableLayer::ICreateFeature( OGRFeature *poFeature )

{
    if( bDeferredCreation )
    {
        if( RunDeferredCreationIfNecessary() != OGRERR_NONE )
            return OGRERR_FAILURE;
    }

    GetLayerDefn();
    bool bHasUserFieldMatchingFID = false;
    if( !osFIDColName.empty() )
        bHasUserFieldMatchingFID = poFeatureDefn->GetFieldIndex(osFIDColName) >= 0;

    if (!poDS->IsReadWrite())
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "Operation not available in read-only mode");
        return OGRERR_FAILURE;
    }

    CPLString osSQL;

    bool bHasJustGotNextFID = false;
    if( !bHasUserFieldMatchingFID && bInDeferredInsert && m_nNextFIDWrite < 0 && !osFIDColName.empty() )
    {
        CPLString osSeqName;
        osSQL.Printf("SELECT pg_catalog.pg_get_serial_sequence('%s', '%s') AS seq_name",
                     OGRCARTOEscapeLiteral(osName).c_str(),
                     OGRCARTOEscapeLiteral(osFIDColName).c_str());
        json_object* poObj = poDS->RunSQL(osSQL);
        json_object* poRowObj = OGRCARTOGetSingleRow(poObj);
        if( poRowObj != nullptr )
        {
            json_object* poSeqName = CPL_json_object_object_get(poRowObj, "seq_name");
            if( poSeqName != nullptr && json_object_get_type(poSeqName) == json_type_string )
            {
                osSeqName = json_object_get_string(poSeqName);
            }
        }

        if( poObj != nullptr )
            json_object_put(poObj);

        if( !osSeqName.empty() )
        {
            osSQL.Printf("SELECT nextval('%s') AS nextid",
                        OGRCARTOEscapeLiteral(osSeqName).c_str());

            poObj = poDS->RunSQL(osSQL);
            poRowObj = OGRCARTOGetSingleRow(poObj);
            if( poRowObj != nullptr )
            {
                json_object* poID = CPL_json_object_object_get(poRowObj, "nextid");
                if( poID != nullptr && json_object_get_type(poID) == json_type_int )
                {
                    m_nNextFIDWrite = json_object_get_int64(poID);
                    bHasJustGotNextFID = true;
                }
            }

            if( poObj != nullptr )
                json_object_put(poObj);
        }
    }

    if (bCopyMode)
        return ICreateFeatureCopy(poFeature, bHasUserFieldMatchingFID, bHasJustGotNextFID);
    else
        return ICreateFeatureInsert(poFeature, bHasUserFieldMatchingFID, bHasJustGotNextFID);
}

/************************************************************************/
/*                           ICreateFeatureCopy()                       */
/************************************************************************/

OGRErr OGRCARTOTableLayer::ICreateFeatureCopy( OGRFeature *poFeature,
    bool bHasUserFieldMatchingFID, bool bHasJustGotNextFID )
{
    CPLString osCopyFile;
    GetLayerDefn();

    if( eDeferredInsertState == INSERT_MULTIPLE_FEATURE )
    {
        bool bReset = false;
        if( m_abFieldSetForInsert.size() !=
                        static_cast<size_t>(poFeatureDefn->GetFieldCount()) )
        {
            bReset = true;
        }
        else
        {
            for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
            {
                if( m_abFieldSetForInsert[i] !=
                                CPL_TO_BOOL(poFeature->IsFieldSet(i)) )
                {
                    bReset = true;
                    break;
                }
            }
        }
        if( bReset )
        {
            if( FlushDeferredBuffer(false) != OGRERR_NONE )
            {
                return OGRERR_FAILURE;
            }
            eDeferredInsertState = INSERT_UNINIT;
        }
    }

    /* We are doing a new COPY for each full buffer, so we will */
    /* construct a new COPY statement here, even though we could */
    /* reuse the same one over and over if we cached it (hmm) */
    if( eDeferredInsertState == INSERT_UNINIT )
    {
        osCopySQL.clear();
        osCopySQL.Printf("COPY %s ", OGRCARTOEscapeIdentifier(osName).c_str());
        bool bMustComma = false;
        /* Non-spatial column names */
        m_abFieldSetForInsert.resize(poFeatureDefn->GetFieldCount());
        for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
        {
            /* We base the columns we attempt to COPY based on */
            /* the set pattern of the first feature we see. */
            m_abFieldSetForInsert[i] = CPL_TO_BOOL(poFeature->IsFieldSet(i));
            if( !poFeature->IsFieldSet(i) )
                continue;

            if( bMustComma )
                osCopySQL += ",";
            else
            {
                osCopySQL += "(";
                bMustComma = true;
            }

            osCopySQL += OGRCARTOEscapeIdentifier(poFeatureDefn->GetFieldDefn(i)->GetNameRef());
        }
        /* Geometry column names */
        for( int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
        {
            if( bMustComma )
                osCopySQL += ",";
            else
                bMustComma = true;

            osCopySQL += OGRCARTOEscapeIdentifier(poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef());
        }
        /* FID column */
        if( !bHasUserFieldMatchingFID &&
            !osFIDColName.empty() && (poFeature->GetFID() != OGRNullFID || (m_nNextFIDWrite >= 0 && bHasJustGotNextFID)) )
        {
            if( bMustComma )
                osCopySQL += ",";
            else
            {
                osCopySQL += "(";
                bMustComma = true;
            }

            osCopySQL += OGRCARTOEscapeIdentifier(osFIDColName);
        }
        /* No columns at all? Return an error! */
        if( !bMustComma )
            return OGRERR_FAILURE;
        else
            osCopySQL += ")";

        osCopySQL += " FROM STDIN WITH (FORMAT text, ENCODING UTF8)";
        CPLDebug( "CARTO", "ICreateFeatureCopy(%s)", osCopySQL.c_str() );

        eDeferredInsertState = INSERT_MULTIPLE_FEATURE;
    }

    /* Now write the data line into the copy file */
    bool bMustTab = false;
    for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
    {
        /* Unset fields get skipped (assuming same field set
           pattern as first input feature) */
        if( !poFeature->IsFieldSet(i) )
            continue;

        /* Tab separator for 'text' format as necessary */
        if( bMustTab )
            osCopyFile += "\t";
        else
            bMustTab = true;

        OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
        /* Null fields get a NULL marker */
        if( poFeature->IsFieldNull(i) )
        {
            osCopyFile += "\\N";
        }
        else if( eType == OFTString || eType == OFTDateTime || eType == OFTDate || eType == OFTTime )
        {
            /* Strip out tab and newline characters */
            osCopyFile += OGRCARTOEscapeLiteralCopy(poFeature->GetFieldAsString(i));
        }
        else if( (eType == OFTInteger || eType == OFTInteger64) &&
                 poFeatureDefn->GetFieldDefn(i)->GetSubType() == OFSTBoolean )
        {
            osCopyFile += poFeature->GetFieldAsInteger(i) ? "t" : "f";
        }
        else
            osCopyFile += poFeature->GetFieldAsString(i);
    }

    for( int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
    {
        if( bMustTab )
            osCopyFile += "\t";
        else
            bMustTab = true;

        OGRGeometry* poGeom = poFeature->GetGeomFieldRef(i);
        if( poGeom == nullptr )
        {
            osCopyFile += "\\N";
            continue;
        }

        char *pszEWKB = OGRCARTOGetHexGeometry(poGeom, i);
        osCopyFile += pszEWKB;
        CPLFree(pszEWKB);
    }

    if( !bHasUserFieldMatchingFID && !osFIDColName.empty() )
    {
        if( poFeature->GetFID() != OGRNullFID )
        {
            if( bMustTab )
                osCopyFile += "\t";

            osCopyFile += CPLSPrintf(CPL_FRMT_GIB, poFeature->GetFID());
        }
        else if( m_nNextFIDWrite >= 0 && bHasJustGotNextFID )
        {
            if( bMustTab )
                osCopyFile += "\t";

            osCopyFile += CPLSPrintf(CPL_FRMT_GIB, m_nNextFIDWrite);
        }
    }

    /* If we do have access to the FID (because we're incrementing it */
    /* ourselves) set it onto the incoming feature so it knows what */
    /* FID was supplied by the back-end. */
    if( !bHasUserFieldMatchingFID && !osFIDColName.empty() &&
        m_nNextFIDWrite >= 0 && poFeature->GetFID() == OGRNullFID )
    {
        poFeature->SetFID(m_nNextFIDWrite);
        m_nNextFIDWrite++;
    }

    OGRErr eRet = OGRERR_NONE;
    /* Add current record to buffer */
    osDeferredBuffer += osCopyFile;
    osDeferredBuffer += "\n";
    if( (int)osDeferredBuffer.size() > nMaxChunkSize )
    {
        eRet = FlushDeferredBuffer(false);
        eDeferredInsertState = INSERT_UNINIT;
    }

    return eRet;
}

/************************************************************************/
/*                           ICreateFeatureInsert()                      */
/************************************************************************/

OGRErr OGRCARTOTableLayer::ICreateFeatureInsert( OGRFeature *poFeature,
    bool bHasUserFieldMatchingFID, bool bHasJustGotNextFID )
{
    CPLString osSQL;
    GetLayerDefn();

    // Check if we can go on with multiple insertion mode
    if( eDeferredInsertState == INSERT_MULTIPLE_FEATURE )
    {
        if( !bHasUserFieldMatchingFID && !osFIDColName.empty() &&
            (poFeature->GetFID() != OGRNullFID || (m_nNextFIDWrite >= 0 && bHasJustGotNextFID)) )
        {
            if( FlushDeferredBuffer(false) != OGRERR_NONE )
                return OGRERR_FAILURE;
        }
    }

    bool bWriteInsertInto = (eDeferredInsertState != INSERT_MULTIPLE_FEATURE);
    bool bResetToUninitInsertStateAfterwards = false;
    if( eDeferredInsertState == INSERT_UNINIT )
    {
        if( !bInDeferredInsert )
        {
            eDeferredInsertState = INSERT_SINGLE_FEATURE;
        }
        else if( !bHasUserFieldMatchingFID && !osFIDColName.empty() &&
            (poFeature->GetFID() != OGRNullFID || (m_nNextFIDWrite >= 0 && bHasJustGotNextFID)) )
        {
            eDeferredInsertState = INSERT_SINGLE_FEATURE;
            bResetToUninitInsertStateAfterwards = true;
        }
        else
        {
            eDeferredInsertState = INSERT_MULTIPLE_FEATURE;
            for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
            {
                if( poFeatureDefn->GetFieldDefn(i)->GetDefault() != nullptr )
                    eDeferredInsertState = INSERT_SINGLE_FEATURE;
            }
        }
    }

    bool bMustComma = false;
    if( bWriteInsertInto )
    {
        osSQL.Printf("INSERT INTO %s ", OGRCARTOEscapeIdentifier(osName).c_str());
        for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
        {
            if( eDeferredInsertState != INSERT_MULTIPLE_FEATURE &&
                !poFeature->IsFieldSet(i) )
                continue;

            if( bMustComma )
                osSQL += ", ";
            else
            {
                osSQL += "(";
                bMustComma = true;
            }

            osSQL += OGRCARTOEscapeIdentifier(poFeatureDefn->GetFieldDefn(i)->GetNameRef());
        }

        for( int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
        {
            if( eDeferredInsertState != INSERT_MULTIPLE_FEATURE &&
                poFeature->GetGeomFieldRef(i) == nullptr )
                continue;

            if( bMustComma )
                osSQL += ", ";
            else
            {
                osSQL += "(";
                bMustComma = true;
            }

            osSQL += OGRCARTOEscapeIdentifier(poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef());
        }

        if( !bHasUserFieldMatchingFID &&
            !osFIDColName.empty() && (poFeature->GetFID() != OGRNullFID || (m_nNextFIDWrite >= 0 && bHasJustGotNextFID)) )
        {
            if( bMustComma )
                osSQL += ", ";
            else
            {
                osSQL += "(";
                bMustComma = true;
            }

            osSQL += OGRCARTOEscapeIdentifier(osFIDColName);
        }

        if( !bMustComma && eDeferredInsertState == INSERT_MULTIPLE_FEATURE )
            eDeferredInsertState = INSERT_SINGLE_FEATURE;
    }

    if( !bMustComma && eDeferredInsertState == INSERT_SINGLE_FEATURE )
        osSQL += "DEFAULT VALUES";
    else
    {
        if( !bWriteInsertInto && eDeferredInsertState == INSERT_MULTIPLE_FEATURE )
            osSQL += ", (";
        else
            osSQL += ") VALUES (";

        bMustComma = false;
        for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++)
        {
            if( !poFeature->IsFieldSet(i) )
            {
                if( eDeferredInsertState == INSERT_MULTIPLE_FEATURE )
                {
                    if( bMustComma )
                        osSQL += ", ";
                    else
                        bMustComma = true;
                    osSQL += "NULL";
                }
                continue;
            }

            if( bMustComma )
                osSQL += ", ";
            else
                bMustComma = true;

            OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
            if( poFeature->IsFieldNull(i) )
            {
                osSQL += "NULL";
            }
            else if( eType == OFTString || eType == OFTDateTime || eType == OFTDate || eType == OFTTime )
            {
                osSQL += "'";
                osSQL += OGRCARTOEscapeLiteral(poFeature->GetFieldAsString(i));
                osSQL += "'";
            }
            else if( (eType == OFTInteger || eType == OFTInteger64) &&
                     poFeatureDefn->GetFieldDefn(i)->GetSubType() == OFSTBoolean )
            {
                osSQL += poFeature->GetFieldAsInteger(i) ? "'t'" : "'f'";
            }
            else
                osSQL += poFeature->GetFieldAsString(i);
        }

        for( int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
        {
            OGRGeometry* poGeom = poFeature->GetGeomFieldRef(i);
            if( poGeom == nullptr )
            {
                if( eDeferredInsertState == INSERT_MULTIPLE_FEATURE )
                {
                    if( bMustComma )
                        osSQL += ", ";
                    else
                        bMustComma = true;
                    osSQL += "NULL";
                }
                continue;
            }

            if( bMustComma )
                osSQL += ", ";
            else
                bMustComma = true;

            char *pszEWKB = OGRCARTOGetHexGeometry(poGeom, i);

            osSQL += "'";
            osSQL += pszEWKB;
            osSQL += "'";
            CPLFree(pszEWKB);
        }

        if( bWriteInsertInto && !bHasUserFieldMatchingFID && !osFIDColName.empty() )
        {
            if( poFeature->GetFID() != OGRNullFID )
            {
                if( bMustComma )
                    osSQL += ", ";
                // No need to set bMustComma to true in else case
                // Not in a loop.

                osSQL += CPLSPrintf(CPL_FRMT_GIB, poFeature->GetFID());
            }
            else if( m_nNextFIDWrite >= 0 && bHasJustGotNextFID )
            {
                if( bMustComma )
                    osSQL += ", ";
                // No need to set bMustComma to true in else case.
                // Not in a loop.
                osSQL += CPLSPrintf(CPL_FRMT_GIB, m_nNextFIDWrite);
            }
        }

        osSQL += ")";
    }

    if( !bHasUserFieldMatchingFID && !osFIDColName.empty() && m_nNextFIDWrite >= 0 &&
        poFeature->GetFID() == OGRNullFID )
    {
        poFeature->SetFID(m_nNextFIDWrite);
        m_nNextFIDWrite ++;
    }

    if( bInDeferredInsert )
    {
        OGRErr eRet = OGRERR_NONE;
        // In multiple mode, this would require rebuilding the osSQL
        // buffer. Annoying.
        if( eDeferredInsertState == INSERT_SINGLE_FEATURE &&
            !osDeferredBuffer.empty() &&
            (int)osDeferredBuffer.size() + (int)osSQL.size() > nMaxChunkSize )
        {
            eRet = FlushDeferredBuffer(false);
        }

        osDeferredBuffer += osSQL;
        if( eDeferredInsertState == INSERT_SINGLE_FEATURE )
            osDeferredBuffer += ";";

        if( (int)osDeferredBuffer.size() > nMaxChunkSize )
        {
            eRet = FlushDeferredBuffer(false);
        }

        if( bResetToUninitInsertStateAfterwards )
            eDeferredInsertState = INSERT_UNINIT;

        return eRet;
    }

    if( !osFIDColName.empty() )
    {
        osSQL += " RETURNING ";
        osSQL += OGRCARTOEscapeIdentifier(osFIDColName);

        json_object* poObj = poDS->RunSQL(osSQL);
        json_object* poRowObj = OGRCARTOGetSingleRow(poObj);
        if( poRowObj == nullptr )
        {
            if( poObj != nullptr )
                json_object_put(poObj);
            return OGRERR_FAILURE;
        }

        json_object* poID = CPL_json_object_object_get(poRowObj, osFIDColName);
        if( poID != nullptr && json_object_get_type(poID) == json_type_int )
        {
            poFeature->SetFID(json_object_get_int64(poID));
        }

        if( poObj != nullptr )
            json_object_put(poObj);

        return OGRERR_NONE;
    }
    else
    {
        OGRErr eRet = OGRERR_FAILURE;
        json_object* poObj = poDS->RunSQL(osSQL);
        if( poObj != nullptr )
        {
            json_object* poTotalRows = CPL_json_object_object_get(poObj, "total_rows");
            if( poTotalRows != nullptr && json_object_get_type(poTotalRows) == json_type_int )
            {
                int nTotalRows = json_object_get_int(poTotalRows);
                if( nTotalRows == 1 )
                {
                    eRet = OGRERR_NONE;
                }
            }
            json_object_put(poObj);
        }

        return eRet;
    }
}

/************************************************************************/
/*                            ISetFeature()                              */
/************************************************************************/

OGRErr OGRCARTOTableLayer::ISetFeature( OGRFeature *poFeature )

{
    if( bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
        return OGRERR_FAILURE;
    if( FlushDeferredBuffer() != OGRERR_NONE )
        return OGRERR_FAILURE;

    GetLayerDefn();

    if (!poDS->IsReadWrite())
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "Operation not available in read-only mode");
        return OGRERR_FAILURE;
    }

    if (poFeature->GetFID() == OGRNullFID)
    {
        CPLError( CE_Failure, CPLE_AppDefined,
                  "FID required on features given to SetFeature()." );
        return OGRERR_FAILURE;
    }

    CPLString osSQL;
    osSQL.Printf("UPDATE %s SET ", OGRCARTOEscapeIdentifier(osName).c_str());
    bool bMustComma = false;
    for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
    {
        if( !poFeature->IsFieldSet(i) )
            continue;

        if( bMustComma )
            osSQL += ", ";
        else
            bMustComma = true;

        osSQL += OGRCARTOEscapeIdentifier(poFeatureDefn->GetFieldDefn(i)->GetNameRef());
        osSQL += " = ";

        if( poFeature->IsFieldNull(i) )
        {
            osSQL += "NULL";
        }
        else
        {
            OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
            if( eType == OFTString || eType == OFTDateTime || eType == OFTDate || eType == OFTTime )
            {
                osSQL += "'";
                osSQL += OGRCARTOEscapeLiteral(poFeature->GetFieldAsString(i));
                osSQL += "'";
            }
            else if( (eType == OFTInteger || eType == OFTInteger64) &&
                poFeatureDefn->GetFieldDefn(i)->GetSubType() == OFSTBoolean )
            {
                osSQL += poFeature->GetFieldAsInteger(i) ? "'t'" : "'f'";
            }
            else
                osSQL += poFeature->GetFieldAsString(i);
        }
    }

    for( int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
    {
        if( bMustComma )
            osSQL += ", ";
        else
            bMustComma = true;

        osSQL += OGRCARTOEscapeIdentifier(poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef());
        osSQL += " = ";

        OGRGeometry* poGeom = poFeature->GetGeomFieldRef(i);
        if( poGeom == nullptr )
        {
            osSQL += "NULL";
        }
        else
        {
            OGRCartoGeomFieldDefn* poGeomFieldDefn =
                (OGRCartoGeomFieldDefn *)(poFeatureDefn->GetGeomFieldDefn(i));
            int nSRID = poGeomFieldDefn->nSRID;
            if( nSRID == 0 )
                nSRID = 4326;
            char* pszEWKB = OGRGeometryToHexEWKB(poGeom, nSRID,
                                               poDS->GetPostGISMajor(),
                                               poDS->GetPostGISMinor());
            osSQL += "'";
            osSQL += pszEWKB;
            osSQL += "'";
            CPLFree(pszEWKB);
        }
    }

    if( !bMustComma ) // nothing to do
        return OGRERR_NONE;

    osSQL += CPLSPrintf(" WHERE %s = " CPL_FRMT_GIB,
                    OGRCARTOEscapeIdentifier(osFIDColName).c_str(),
                    poFeature->GetFID());

    OGRErr eRet = OGRERR_FAILURE;
    json_object* poObj = poDS->RunSQL(osSQL);
    if( poObj != nullptr )
    {
        json_object* poTotalRows = CPL_json_object_object_get(poObj, "total_rows");
        if( poTotalRows != nullptr && json_object_get_type(poTotalRows) == json_type_int )
        {
            int nTotalRows = json_object_get_int(poTotalRows);
            if( nTotalRows > 0 )
            {
                eRet = OGRERR_NONE;
            }
            else
                eRet = OGRERR_NON_EXISTING_FEATURE;
        }
        json_object_put(poObj);
    }

    return eRet;
}

/************************************************************************/
/*                          DeleteFeature()                             */
/************************************************************************/

OGRErr OGRCARTOTableLayer::DeleteFeature( GIntBig nFID )

{

    if( bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
        return OGRERR_FAILURE;
    if( FlushDeferredBuffer() != OGRERR_NONE )
        return OGRERR_FAILURE;

    GetLayerDefn();

    if (!poDS->IsReadWrite())
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "Operation not available in read-only mode");
        return OGRERR_FAILURE;
    }

    if( osFIDColName.empty() )
        return OGRERR_FAILURE;

    CPLString osSQL;
    osSQL.Printf("DELETE FROM %s WHERE %s = " CPL_FRMT_GIB,
                    OGRCARTOEscapeIdentifier(osName).c_str(),
                    OGRCARTOEscapeIdentifier(osFIDColName).c_str(),
                    nFID);

    OGRErr eRet = OGRERR_FAILURE;
    json_object* poObj = poDS->RunSQL(osSQL);
    if( poObj != nullptr )
    {
        json_object* poTotalRows = CPL_json_object_object_get(poObj, "total_rows");
        if( poTotalRows != nullptr && json_object_get_type(poTotalRows) == json_type_int )
        {
            int nTotalRows = json_object_get_int(poTotalRows);
            if( nTotalRows > 0 )
            {
                eRet = OGRERR_NONE;
            }
            else
                eRet = OGRERR_NON_EXISTING_FEATURE;
        }
        json_object_put(poObj);
    }

    return eRet;
}

/************************************************************************/
/*                             GetSRS_SQL()                             */
/************************************************************************/

CPLString OGRCARTOTableLayer::GetSRS_SQL(const char* pszGeomCol)
{
    CPLString osSQL;

    osSQL.Printf("SELECT srid, srtext FROM spatial_ref_sys WHERE srid IN "
                "(SELECT Find_SRID('%s', '%s', '%s'))",
                OGRCARTOEscapeLiteral(poDS->GetCurrentSchema()).c_str(),
                OGRCARTOEscapeLiteral(osName).c_str(),
                OGRCARTOEscapeLiteral(pszGeomCol).c_str());

    return osSQL;
}

/************************************************************************/
/*                             BuildWhere()                             */
/*                                                                      */
/*      Build the WHERE statement appropriate to the current set of     */
/*      criteria (spatial and attribute queries).                       */
/************************************************************************/

void OGRCARTOTableLayer::BuildWhere()

{
    osWHERE = "";

    if( m_poFilterGeom != nullptr &&
        m_iGeomFieldFilter >= 0 &&
        m_iGeomFieldFilter < poFeatureDefn->GetGeomFieldCount() )
    {
        OGREnvelope  sEnvelope;

        m_poFilterGeom->getEnvelope( &sEnvelope );

        CPLString osGeomColumn(poFeatureDefn->GetGeomFieldDefn(m_iGeomFieldFilter)->GetNameRef());

        char szBox3D_1[128];
        char szBox3D_2[128];
        char* pszComma;

        CPLsnprintf(szBox3D_1, sizeof(szBox3D_1), "%.18g %.18g", sEnvelope.MinX, sEnvelope.MinY);
        while((pszComma = strchr(szBox3D_1, ',')) != nullptr)
            *pszComma = '.';
        CPLsnprintf(szBox3D_2, sizeof(szBox3D_2), "%.18g %.18g", sEnvelope.MaxX, sEnvelope.MaxY);
        while((pszComma = strchr(szBox3D_2, ',')) != nullptr)
            *pszComma = '.';
        osWHERE.Printf("(%s && 'BOX3D(%s, %s)'::box3d)",
                       OGRCARTOEscapeIdentifier(osGeomColumn).c_str(),
                       szBox3D_1, szBox3D_2 );
    }

    if( !osQuery.empty() )
    {
        if( !osWHERE.empty() )
            osWHERE += " AND ";
        osWHERE += osQuery;
    }

    if( osFIDColName.empty() )
    {
        osBaseSQL = osSELECTWithoutWHERE;
        if( !osWHERE.empty() )
        {
            osBaseSQL += " WHERE ";
            osBaseSQL += osWHERE;
        }
    }
}

/************************************************************************/
/*                              GetFeature()                            */
/************************************************************************/

OGRFeature* OGRCARTOTableLayer::GetFeature( GIntBig nFeatureId )
{

    if( bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
        return nullptr;
    if( FlushDeferredBuffer() != OGRERR_NONE )
        return nullptr;

    GetLayerDefn();

    if( osFIDColName.empty() )
        return OGRCARTOLayer::GetFeature(nFeatureId);

    CPLString osSQL = osSELECTWithoutWHERE;
    osSQL += " WHERE ";
    osSQL += OGRCARTOEscapeIdentifier(osFIDColName).c_str();
    osSQL += " = ";
    osSQL += CPLSPrintf(CPL_FRMT_GIB, nFeatureId);

    json_object* poObj = poDS->RunSQL(osSQL);
    json_object* poRowObj = OGRCARTOGetSingleRow(poObj);
    if( poRowObj == nullptr )
    {
        if( poObj != nullptr )
            json_object_put(poObj);
        return OGRCARTOLayer::GetFeature(nFeatureId);
    }

    OGRFeature* poFeature = BuildFeature(poRowObj);
    json_object_put(poObj);

    return poFeature;
}

/************************************************************************/
/*                          GetFeatureCount()                           */
/************************************************************************/

GIntBig OGRCARTOTableLayer::GetFeatureCount(int bForce)
{

    if( bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
        return 0;
    if( FlushDeferredBuffer() != OGRERR_NONE )
        return 0;

    GetLayerDefn();

    CPLString osSQL(CPLSPrintf("SELECT COUNT(*) FROM %s",
                               OGRCARTOEscapeIdentifier(osName).c_str()));
    if( !osWHERE.empty() )
    {
        osSQL += " WHERE ";
        osSQL += osWHERE;
    }

    json_object* poObj = poDS->RunSQL(osSQL);
    json_object* poRowObj = OGRCARTOGetSingleRow(poObj);
    if( poRowObj == nullptr )
    {
        if( poObj != nullptr )
            json_object_put(poObj);
        return OGRCARTOLayer::GetFeatureCount(bForce);
    }

    json_object* poCount = CPL_json_object_object_get(poRowObj, "count");
    if( poCount == nullptr || json_object_get_type(poCount) != json_type_int )
    {
        json_object_put(poObj);
        return OGRCARTOLayer::GetFeatureCount(bForce);
    }

    GIntBig nRet = (GIntBig)json_object_get_int64(poCount);

    json_object_put(poObj);

    return nRet;
}

/************************************************************************/
/*                             GetExtent()                              */
/*                                                                      */
/*      For PostGIS use internal Extend(geometry) function              */
/*      in other cases we use standard OGRLayer::GetExtent()            */
/************************************************************************/

OGRErr OGRCARTOTableLayer::GetExtent( int iGeomField, OGREnvelope *psExtent, int bForce )
{
    CPLString   osSQL;

    if( bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
        return OGRERR_FAILURE;
    if( FlushDeferredBuffer() != OGRERR_NONE )
        return OGRERR_FAILURE;

    if( iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
        GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone )
    {
        if( iGeomField != 0 )
        {
            CPLError(CE_Failure, CPLE_AppDefined,
                     "Invalid geometry field index : %d", iGeomField);
        }
        return OGRERR_FAILURE;
    }

    OGRGeomFieldDefn* poGeomFieldDefn =
        poFeatureDefn->GetGeomFieldDefn(iGeomField);

    /* Do not take the spatial filter into account */
    osSQL.Printf( "SELECT ST_Extent(%s) FROM %s",
                  OGRCARTOEscapeIdentifier(poGeomFieldDefn->GetNameRef()).c_str(),
                  OGRCARTOEscapeIdentifier(osName).c_str());

    json_object* poObj = poDS->RunSQL(osSQL);
    json_object* poRowObj = OGRCARTOGetSingleRow(poObj);
    if( poRowObj != nullptr )
    {
        json_object* poExtent = CPL_json_object_object_get(poRowObj, "st_extent");
        if( poExtent != nullptr && json_object_get_type(poExtent) == json_type_string )
        {
            const char* pszBox = json_object_get_string(poExtent);
            const char * ptr, *ptrEndParenthesis;
            char szVals[64*6+6];

            ptr = strchr(pszBox, '(');
            if (ptr)
                ptr ++;
            if (ptr == nullptr ||
                (ptrEndParenthesis = strchr(ptr, ')')) == nullptr ||
                ptrEndParenthesis - ptr > (int)(sizeof(szVals) - 1))
            {
                CPLError( CE_Failure, CPLE_IllegalArg,
                            "Bad extent representation: '%s'", pszBox);

                json_object_put(poObj);
                return OGRERR_FAILURE;
            }

            strncpy(szVals,ptr,ptrEndParenthesis - ptr);
            szVals[ptrEndParenthesis - ptr] = '\0';

            char ** papszTokens = CSLTokenizeString2(szVals," ,",CSLT_HONOURSTRINGS);
            int nTokenCnt = 4;

            if ( CSLCount(papszTokens) != nTokenCnt )
            {
                CPLError( CE_Failure, CPLE_IllegalArg,
                            "Bad extent representation: '%s'", pszBox);
                CSLDestroy(papszTokens);

                json_object_put(poObj);
                return OGRERR_FAILURE;
            }

            // Take X,Y coords
            // For PostGIS ver >= 1.0.0 -> Tokens: X1 Y1 X2 Y2 (nTokenCnt = 4)
            // For PostGIS ver < 1.0.0 -> Tokens: X1 Y1 Z1 X2 Y2 Z2 (nTokenCnt = 6)
            // =>   X2 index calculated as nTokenCnt/2
            //      Y2 index calculated as nTokenCnt/2+1

            psExtent->MinX = CPLAtof( papszTokens[0] );
            psExtent->MinY = CPLAtof( papszTokens[1] );
            psExtent->MaxX = CPLAtof( papszTokens[nTokenCnt/2] );
            psExtent->MaxY = CPLAtof( papszTokens[nTokenCnt/2+1] );

            CSLDestroy(papszTokens);

            json_object_put(poObj);
            return OGRERR_NONE;
        }
    }

    if( poObj != nullptr )
        json_object_put(poObj);

    if( iGeomField == 0 )
        return OGRLayer::GetExtent( psExtent, bForce );
    else
        return OGRLayer::GetExtent( iGeomField, psExtent, bForce );
}

/************************************************************************/
/*                           TestCapability()                           */
/************************************************************************/

int OGRCARTOTableLayer::TestCapability( const char * pszCap )

{
    if( EQUAL(pszCap, OLCFastFeatureCount) )
        return TRUE;
    if( EQUAL(pszCap, OLCFastGetExtent) )
        return TRUE;
    if( EQUAL(pszCap, OLCRandomRead) )
    {
        GetLayerDefn();
        return !osFIDColName.empty();
    }

    if( EQUAL(pszCap,OLCSequentialWrite)
     || EQUAL(pszCap,OLCRandomWrite)
     || EQUAL(pszCap,OLCDeleteFeature)
     || EQUAL(pszCap,OLCCreateField)
     || EQUAL(pszCap,OLCDeleteField)
     || EQUAL(pszCap,OLCCreateGeomField) )
    {
        return poDS->IsReadWrite();
    }

    return OGRCARTOLayer::TestCapability(pszCap);
}

/************************************************************************/
/*                        SetDeferredCreation()                          */
/************************************************************************/

void OGRCARTOTableLayer::SetDeferredCreation( OGRwkbGeometryType eGType,
                                              OGRSpatialReference* poSRSIn,
                                              bool bGeomNullable,
                                              bool bCartodbfyIn )
{
    bDeferredCreation = true;
    m_nNextFIDWrite = 1;
    CPLAssert(poFeatureDefn == nullptr);
    bCartodbfy = bCartodbfyIn;
    poFeatureDefn = new OGRFeatureDefn(osName);
    poFeatureDefn->Reference();
    poFeatureDefn->SetGeomType(wkbNone);
    if( eGType == wkbPolygon )
        eGType = wkbMultiPolygon;
    else if( eGType == wkbPolygon25D )
        eGType = wkbMultiPolygon25D;
    if( eGType != wkbNone )
    {
        OGRCartoGeomFieldDefn *poFieldDefn =
            new OGRCartoGeomFieldDefn("the_geom", eGType);
        poFieldDefn->SetNullable(bGeomNullable);
        poFeatureDefn->AddGeomFieldDefn(poFieldDefn, FALSE);
        if( poSRSIn != nullptr )
        {
            poFieldDefn->nSRID = poDS->FetchSRSId( poSRSIn );
            poFeatureDefn->GetGeomFieldDefn(
                poFeatureDefn->GetGeomFieldCount() - 1)->SetSpatialRef(poSRSIn);
        }
    }
    osFIDColName = "cartodb_id";
    osBaseSQL.Printf("SELECT * FROM %s",
                     OGRCARTOEscapeIdentifier(osName).c_str());
    osSELECTWithoutWHERE = osBaseSQL;
}

/************************************************************************/
/*                      RunDeferredCreationIfNecessary()                 */
/************************************************************************/

OGRErr OGRCARTOTableLayer::RunDeferredCreationIfNecessary()
{
    if( !bDeferredCreation )
        return OGRERR_NONE;
    bDeferredCreation = false;

    CPLString osSQL;
    osSQL.Printf("CREATE TABLE %s ( %s SERIAL,",
                 OGRCARTOEscapeIdentifier(osName).c_str(),
                 osFIDColName.c_str());

    for( int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
    {
        OGRCartoGeomFieldDefn *poFieldDefn = (OGRCartoGeomFieldDefn*)(poFeatureDefn->GetGeomFieldDefn(i));
        OGRwkbGeometryType eGType = poFieldDefn->GetType();
        if( eGType == wkbNone )
            continue;

        const char *pszFieldName = "the_geom";

        if( i>0 )
            pszFieldName = poFieldDefn->GetNameRef();

        if( pszFieldName == nullptr || strlen(pszFieldName) == 0 )
            return OGRERR_FAILURE;

        osSQL += CPLSPrintf("%s %s%s,",
                    pszFieldName,
                    OGRCARTOGeometryType(poFieldDefn).c_str(),
                    (!poFieldDefn->IsNullable()) ? " NOT NULL" : ""
                    );
    }

    for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
    {
        OGRFieldDefn* poFieldDefn = poFeatureDefn->GetFieldDefn(i);
        if( strcmp(poFieldDefn->GetNameRef(), osFIDColName) != 0 )
        {
            osSQL += OGRCARTOEscapeIdentifier(poFieldDefn->GetNameRef());
            osSQL += " ";
            osSQL += OGRPGCommonLayerGetType(*poFieldDefn, false, true);
            if( !poFieldDefn->IsNullable() )
                osSQL += " NOT NULL";
            if( poFieldDefn->GetDefault() != nullptr && !poFieldDefn->IsDefaultDriverSpecific() )
            {
                osSQL += " DEFAULT ";
                osSQL += poFieldDefn->GetDefault();
            }
            osSQL += ",";
        }
    }

    osSQL += CPLSPrintf("PRIMARY KEY (%s) )", osFIDColName.c_str());

    CPLString osSeqName(OGRCARTOEscapeIdentifier(CPLSPrintf("%s_%s_seq",
                                osName.c_str(), osFIDColName.c_str())));

    osSQL += ";";
    osSQL += CPLSPrintf("DROP SEQUENCE IF EXISTS %s CASCADE", osSeqName.c_str());
    osSQL += ";";
    osSQL += CPLSPrintf("CREATE SEQUENCE %s START 1", osSeqName.c_str());
    osSQL += ";";
    osSQL += CPLSPrintf("ALTER SEQUENCE %s OWNED BY %s.%s", osSeqName.c_str(),
                        OGRCARTOEscapeIdentifier(osName).c_str(), osFIDColName.c_str());
    osSQL += ";";
    osSQL += CPLSPrintf("ALTER TABLE %s ALTER COLUMN %s SET DEFAULT nextval('%s')",
                        OGRCARTOEscapeIdentifier(osName).c_str(),
                        osFIDColName.c_str(), osSeqName.c_str());

    json_object* poObj = poDS->RunSQL(osSQL);
    if( poObj == nullptr )
        return OGRERR_FAILURE;
    json_object_put(poObj);

    return OGRERR_NONE;
}


text:
from http import HTTPStatus
import pecan
import wsme
from wsme import types as wtypes

from oslo_log import log

from cyborg.api.controllers import base
from cyborg.api.controllers import link
from cyborg.api.controllers import types
from cyborg.api.controllers.v2 import utils
from cyborg.api.controllers.v2 import versions
from cyborg.api import expose
from cyborg.common import authorize_wsgi
from cyborg.common import constants
from cyborg.common import exception
from cyborg.common.i18n import _
from cyborg import objects

LOG = log.getLogger(__name__)

class ARQ(base.APIBase):
    """API representation of an ARQ.

    This class enforces type checking and value constraints, and converts
    between the internal object model and the API representation.
    """
    uuid = types.uuid
    """The UUID of the ARQ"""

    state = wtypes.text  # obvious meanings
    device_profile_name = wtypes.text
    device_profile_group_id = wtypes.IntegerType()

    hostname = wtypes.text
    """The host name to which the ARQ is bound, if any"""

    device_rp_uuid = wtypes.text
    """The UUID of the bound device RP, if any"""

    instance_uuid = wtypes.text
    """The UUID of the instance associated with this ARQ, if any"""
    project_id = wtypes.text
    """The UUID of the instance project_id associated with this ARQ, if any"""

    attach_handle_type = wtypes.text
    attach_handle_info = {wtypes.text: wtypes.text}

    links = wsme.wsattr([link.Link], readonly=True)
    """A list containing a self link"""

    def __init__(self, **kwargs):
        super(ARQ, self).__init__(**kwargs)
        self.fields = []
        for field in objects.ARQ.fields:
            self.fields.append(field)
            setattr(self, field, kwargs.get(field, wtypes.Unset))

    @classmethod
    def convert_with_links(cls, obj_arq):
        api_arq = cls(**obj_arq.as_dict())
        api_arq.links = [
            link.Link.make_link('self', pecan.request.public_url,
                                'accelerator_requests', api_arq.uuid)
            ]
        return api_arq

class ARQCollection(base.APIBase):
    """API representation of a collection of arqs."""

    arqs = [ARQ]
    """A list containing arq objects"""

    @classmethod
    def convert_with_links(cls, obj_arqs):
        collection = cls()
        collection.arqs = [ARQ.convert_with_links(obj_arq)
                           for obj_arq in obj_arqs]
        return collection

class ARQsController(base.CyborgController):
    """REST controller for ARQs.

       For the relationship between ARQs and device profiles, see
       nova/nova/accelerator/cyborg.py.
    """

    @authorize_wsgi.authorize_wsgi("cyborg:arq", "create", False)
    @expose.expose(ARQCollection, body=types.jsontype,
                   status_code=HTTPStatus.CREATED)
    def post(self, req):
        """Create one or more ARQs for a single device profile.
           Request body:
              { 'device_profile_name': <string> }
           Future:
              { 'device_profile_name': <string> # required
                'device_profile_group_id': <integer>, # opt, default=0
                'image_uuid': <glance-image-UUID>, #optional, for future
              }
           :param req: request body.
        """
        LOG.info("[arq] post req = (%s)", req)
        context = pecan.request.context
        dp_name = req.get('device_profile_name')
        if dp_name is not None:
            try:
                devprof = objects.DeviceProfile.get_by_name(context, dp_name)
            except exception.ResourceNotFound:
                raise exception.ResourceNotFound(
                    resource='Device Profile',
                    msg='with name=%s' % dp_name)
            except Exception as e:
                raise e
        else:
            raise exception.DeviceProfileNameNeeded()
        LOG.info('[arqs] post. device profile name=%s', dp_name)

        extarq_list = []
        for group_id, group in enumerate(devprof.groups):
            accel_resources = [
                int(val) for key, val in group.items()
                if key.startswith('resources')]
            # If/when we introduce non-accelerator resources, like
            # device-local memory, the key search above needs to be
            # made specific to accelerator resources only.
            num_accels = sum(accel_resources)
            arq_fields = {
                'device_profile_name': devprof.name,
                'device_profile_group_id': group_id,
            }
            for i in range(num_accels):
                obj_arq = objects.ARQ(context, **arq_fields)
                extarq_fields = {'arq': obj_arq}
                obj_extarq = objects.ExtARQ(context, **extarq_fields)
                new_extarq = pecan.request.conductor_api.arq_create(
                    context, obj_extarq, devprof.id)
                extarq_list.append(new_extarq)

        ret = ARQCollection.convert_with_links(
            [extarq.arq for extarq in extarq_list])
        LOG.info('[arqs] post returned: %s', ret)
        return ret

    @authorize_wsgi.authorize_wsgi("cyborg:arq", "get_one")
    @expose.expose(ARQ, wtypes.text)
    def get_one(self, uuid):
        """Get a single ARQ by UUID."""
        context = pecan.request.context
        extarq = objects.ExtARQ.get(context, uuid)
        return ARQ.convert_with_links(extarq.arq)

    @authorize_wsgi.authorize_wsgi("cyborg:arq", "get_all", False)
    @expose.expose(ARQCollection, wtypes.text, types.uuid)
    def get_all(self, bind_state=None, instance=None):
        """Retrieve a list of arqs."""
        # TODO(Sundar) Need to implement 'arq=uuid1,...' query parameter
        LOG.info('[arqs] get_all. bind_state:(%s), instance:(%s)',
                 bind_state or '', instance or '')
        context = pecan.request.context
        extarqs = objects.ExtARQ.list(context)
        state_map = constants.ARQ_BIND_STATES_STATUS_MAP
        valid_bind_states = list(state_map.keys())
        arqs = [extarq.arq for extarq in extarqs]
        # TODO(Sundar): Optimize by doing the filtering in the db layer
        # Apply instance filter before state filter.
        if bind_state and bind_state != 'resolved':
            raise exception.ARQBadState(
                state=bind_state, uuid=None, expected=['resolved'])
        if instance:
            new_arqs = [arq for arq in arqs
                        if arq['instance_uuid'] == instance]
            arqs = new_arqs
            if bind_state:
                for arq in new_arqs:
                    if arq['state'] not in valid_bind_states:
                        # NOTE(Sundar) This should return HTTP code 423
                        # if any ARQ for this instance is not resolved.
                        LOG.warning('Some of ARQs for instance %s is not '
                                    'resolved', instance)
                        return wsme.api.Response(
                            None,
                            status_code=HTTPStatus.LOCKED)
        elif bind_state:
            arqs = [arq for arq in arqs
                    if arq['state'] in valid_bind_states]

        ret = ARQCollection.convert_with_links(arqs)
        LOG.info('[arqs:get_all] Returned: %s', ret)
        return ret

    @authorize_wsgi.authorize_wsgi("cyborg:arq", "delete", False)
    @expose.expose(None, wtypes.text, wtypes.text,
                   status_code=HTTPStatus.NO_CONTENT)
    def delete(self, arqs=None, instance=None):
        """Delete one or more ARQS.

        The request can be either one of these two forms:
            DELETE /v2/accelerator_requests?arqs=uuid1,uuid2,...
            DELETE /v2/accelerator_requests?instance=uuid

        The second form is idempotent, i.e., it would have the same effect
        if called repeatedly with the same instance UUID. In other words,
        it would not raise an error on the second and later attempts even if
        the first one has deleted the ARQs. Whereas the first form is not
        idempotent: if one or more of the ARQs do not exist, it would raise
        an error. Nova uses the second form: so repeated calls do not cause
        issues.

        :param arqs: List of ARQ UUIDs
        :param instance: UUID of instance whose ARQs need to be deleted
        """
        context = pecan.request.context
        if (arqs and instance) or (not arqs and not instance):
            raise exception.ObjectActionError(
                action='delete',
                reason='Provide either an ARQ uuid list or an instance UUID')
        elif arqs:
            LOG.info("[arqs] delete. arqs=(%s)", arqs)
            pecan.request.conductor_api.arq_delete_by_uuid(context, arqs)
        else:  # instance is not None
            LOG.info("[arqs] delete. instance=(%s)", instance)
            pecan.request.conductor_api.arq_delete_by_instance_uuid(
                context, instance)

    def _validate_arq_patch(self, patch):
        """Validate a single patch for an ARQ.

        :param patch: a JSON PATCH document.
            The patch must be of the form [{..}], as specified in the
            value field of arq_uuid in patch() method below.
        :returns: dict of valid fields
        """
        valid_fields = {'hostname': None,
                        'device_rp_uuid': None,
                        'instance_uuid': None}
        if utils.allow_project_id():
            valid_fields['project_id'] = None
        if ((not all(p['op'] == 'add' for p in patch)) and
           (not all(p['op'] == 'remove' for p in patch))):
            raise exception.PatchError(
                reason='Every op must be add or remove')

        for p in patch:
            path = p['path'].lstrip('/')
            if path == 'project_id' and not utils.allow_project_id():
                raise exception.NotAcceptable(_(
                    "Request not acceptable. The minimal required API "
                    "version should be %(base)s.%(opr)s") %
                    {'base': versions.BASE_VERSION,
                     'opr': versions.MINOR_1_PROJECT_ID})
            if path not in valid_fields.keys():
                reason = 'Invalid path in patch {}'.format(p['path'])
                raise exception.PatchError(reason=reason)
            if p['op'] == 'add':
                valid_fields[path] = p['value']
        not_found = [field for field, value in valid_fields.items()
                     if value is None]
        if patch[0]['op'] == 'add' and len(not_found) > 0:
            msg = ','.join(not_found)
            reason = _('Fields absent in patch {}').format(msg)
            raise exception.PatchError(reason=reason)

        return valid_fields

    @staticmethod
    def _check_if_already_bound(context, valid_fields):
        patch_fields = list(valid_fields.values())[0]
        instance_uuid = patch_fields['instance_uuid']
        extarqs = objects.ExtARQ.list(context)
        extarqs_for_instance = [
            extarq for extarq in extarqs
            if extarq.arq['instance_uuid'] == instance_uuid]
        if extarqs_for_instance:  # duplicate binding request
            msg = _('Instance {} already has accelerator requests. '
                    'Cannot bind additional ARQs.')
            reason = msg.format(instance_uuid)
            raise exception.PatchError(reason=reason)

    @authorize_wsgi.authorize_wsgi("cyborg:arq", "update", False)
    @expose.expose(None, body=types.jsontype,
                   status_code=HTTPStatus.ACCEPTED)
    def patch(self, patch_list):
        """Bind/Unbind one or more ARQs.

        Usage: curl -X PATCH .../v2/accelerator_requests
                 -d <patch_list> -H "Content-type: application/json"

        :param patch_list: A map from ARQ UUIDs to their JSON patches:
            {"$arq_uuid": [
                {"path": "/hostname", "op": ADD/RM, "value": "..."},
                {"path": "/device_rp_uuid", "op": ADD/RM, "value": "..."},
                {"path": "/instance_uuid", "op": ADD/RM, "value": "..."},
                {"path": "/project_id", "op": ADD/RM, "value": "..."},
               ],
             "$arq_uuid": [...]
            }
            In particular, all and only these 4 fields must be present,
            and only 'add' or 'remove' ops are allowed.
        """
        LOG.info('[arqs] patch. list=(%s)', patch_list)
        context = pecan.request.context
        # Validate all patches before un/binding.
        valid_fields = {}
        for arq_uuid, patch in patch_list.items():
            valid_fields[arq_uuid] = self._validate_arq_patch(patch)

        # NOTE(Sundar): In the ARQ create/bind flow, new ARQs can be created
        # for a device profile any time. However, they should not be bound to
        # an instance which already has other ARQs bound to it. In the future,
        # we may allow that for hot adds, but not now.
        # See commit message of https://review.opendev.org/712231 for details.
        #
        # So, for bind requests, we first check that no ARQs are already
        # associated with the instance specified in the binding.
        patch = list(patch_list.values())[0]
        if patch[0]['op'] == 'add':
            self._check_if_already_bound(context, valid_fields)

        pecan.request.conductor_api.arq_apply_patch(
            context, patch_list, valid_fields)

redpajama_set_name: RedPajamaGithub


text:
.dojoxFloatingPane {
	background-color:#fff;
	position:relative;
	border: 1px solid #dedede;
	overflow: hidden;
	-webkit-box-shadow: 0px 5px 10px #adadad;
}
.dojoxFloatingPaneFg {
	-webkit-box-shadow: 0px 8px 20px #525252;
}
.dojoxFloatingPaneTitle {
	background: #cccccc;
	background:#fafafa repeat-x bottom left;
	border:1px solid #bfbfbf;
	padding:4px 4px 2px 4px;
	cursor: pointer;
	white-space: nowrap;
}
.soria .dojoxFloatingPaneTitle {
	background:#fff url("../../../dijit/themes/soria/images/titleBar.png") repeat-x top left;
	border:1px solid #b1badf;
	font-size: 0.9em;
	font-weight: bold;
	line-height:1.2em;
}
.tundra .dojoxFloatingPaneTitle {
	background:#fafafa url("../../../dijit/themes/tundra/images/titleBarBg.gif") repeat-x bottom left;
	border:1px solid #bfbfbf;
	color:#000;
}
.dojoxFloatingCloseIcon {
	background:url('../../../dijit/themes/tundra/images/tabClose.png') no-repeat center center;
	width:16px;
	height:16px;
	overflow:hidden;
	float:right;
}
.dojoxFloatingMinimizeIcon {
	background:url('../../../dijit/themes/tundra/images/spriteArrows.png') no-repeat 0px center;
	width:7px;
	margin: 0px 4px;
	overflow:hidden;
	float:right;
}
.soria .dojoxFloatingMinimizeIcon {
	background:url("../../../dijit/themes/soria/images/spriteRoundedIconsSmallBl.png") no-repeat -15px top;
	width: 14px;
	margin: 0px 2px;
}
.floatingPaneMaximized .dojoxFloatingMaximizeIcon { display:none; }
.dojoxFloatingMaximizeIcon {
	background:url('../../../dijit/themes/tundra/images/spriteArrows.png') no-repeat -21px center;
	width:7px;
	margin: 0px 4px;
	overflow:hidden;
	float:right;
}
.soria .dojoxFloatingMaximizeIcon {
	background:url("../../../dijit/themes/soria/images/spriteRoundedIconsSmallBl.png") no-repeat -45px top;
}
.floatingPaneMaximized .dojoxFloatingRestoreIcon { display:inline; }
.dojoxFloatingRestoreIcon {
	background:url('../../../dijit/themes/tundra/images/spriteArrows.png') no-repeat 0px center;
	width:7px;
	margin: 0px 4px;
	float:right;
	display:none;
}
.dojoxFloatingResizeHandle {
	background:url('icons/resize.png') no-repeat bottom right;
	position:absolute;
	right:0;
	bottom:0;
	width:16px;
	height:16px;
	cursor:nw-resize;
}
.dojoxFloatingCloseIcon {
	width:15px;
	height:15px;
	overflow:hidden;
	float:right;
	cursor:pointer;
}
.soria .dojoxFloatingCloseIcon {
	background:url("../../../dijit/themes/soria/images/spriteRoundedIconsSmallBl.png") no-repeat -60px top;
}
.tundra .dojoxFloatingCloseIcon {
	background:url('../../../dijit/themes/tundra/images/tabClose.png') no-repeat center center;
}
.dojoxFloatingDockDefault {
	position:absolute;
	bottom:0px;
	left:0px;
	overflow:hidden;
	margin:0;
	margin-bottom:3px;
	padding:0px;
	width:100%;
	z-index:99;
	background:transparent;

}
.dojoxDockList {
	padding: 0px;
	margin: 0px;
}
.dojoxDockRestoreButton {
	background:url('../../../dijit/themes/tundra/images/arrowUp.png') no-repeat center center;
	width:16px; height:16px;
	overflow:hidden;
	float:left;
	margin-top:2px;
}
.soria .dojoxDockRestoreButton {
	background:url("../../../dijit/themes/soria/images/spriteRoundedIconsSmallBl.png") no-repeat -45px top;
}
.dojoxDockTitleNode {
	overflow:hidden;
}
.dojoxDock {
	display: block;
	border: 1px solid black;
	position: absolute;
	padding:0;
	margin:0;
	background:#fcfcfc;
}
.dojoxDockNode {
	border: 1px solid #adadad;
	border-radius: 2px;
	-webkit-border-radius: 2px;
	-moz-border-radius: 3px;
	cursor:pointer;
	list-style: none;
	padding: 2px;
	margin: 0px;
	height: 16px;
	width: auto;
	float: left;
	background: #fafafa url("../../../dijit/themes/tundra/images/titleBarBg.gif") repeat-x bottom left;
}
.soria .dojoxDockNode {
	background:#b7cdee url("../../../dijit/themes/soria/images/titleBar.png") repeat-x;
}
.dojoxFloatingPaneContent {
	overflow: auto;
	background-color: #fff;
	height: 100%;
	width:	100%;
}
.dojoxFloatingPaneCanvas {
	background-color:#fff;
}


text:
'use strict';

const expect = require('chai').expect;
const RSVP = require('rsvp');
const request = RSVP.denodeify(require('request'));

const AddonTestApp = require('ember-cli-addon-tests').AddonTestApp;

describe('serve assets acceptance', function() {
  this.timeout(300000);

  let app;

  before(function() {
    app = new AddonTestApp();

    return app.create('dummy')
      .then(function() {
        return app.startServer({
          command: 'serve'
        });
      });
  });

  after(function() {
    return app.stopServer();
  });

  it('/assets/vendor.js', function() {
    return request('http://localhost:49741/assets/vendor.js')
      .then(function(response) {
        expect(response.statusCode).to.equal(200);
        expect(response.headers["content-type"]).to.eq("application/javascript; charset=UTF-8");
        expect(response.body).to.contain("Ember =");
      });
  });

  it('/assets/dummy.js', function() {
    return request('http://localhost:49741/assets/dummy.js')
      .then(function(response) {
        expect(response.statusCode).to.equal(200);
        expect(response.headers["content-type"]).to.eq("application/javascript; charset=UTF-8");
        expect(response.body).to.contain("this.route('posts')");
      });
  });
});


text:
"""
Homework 3

Data Description:
    Input the training and testing data and store it in an array. Training results in 284x31
    and Testing results in 284x31. The data entries
    consist of a first entry class label('1' for malignant and '-1' for benign) followed by 30
    breast cancer diagnostic measurements.
"""

import numpy as np
import os

raw_training_data_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'knn_data/knn_train.csv')
raw_testing_data_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'knn_data/knn_test.csv')

raw_training_data = np.loadtxt(raw_training_data_path, dtype=float, delimiter=',')
raw_testing_data = np.loadtxt(raw_testing_data_path, dtype=float, delimiter=',')

def get_data_answers(input_array):
    """Split off the first column answers and put in a dummy attribute of 1's in the first
     column.
     """
    input_array_split = np.split(input_array, [1], axis=1)
    data_features = np.array(input_array_split[1])
    length = data_features.shape[0]
    data_features = np.insert(data_features, 0, np.ones((1, length)), axis=1)
    answers = np.array(input_array_split[0])
    return data_features, answers

def get_by_row(answers, input_data):
    """Takes a column of input answers and an array of arrays of data and returns each answer,
    data set pair.
    """
    for row in np.concatenate((answers, input_data), axis=1):
        split_row = np.split(row, [1])
        answer = split_row[0][0]
        features = split_row[1]
        yield answer, features

def distance(vector_one, vector_two):
    """Calculates the distance between two numpy arrays."""
    return np.linalg.norm(vector_one - vector_two)

def _get_k_nearest(test_entry, training_answers, training_data):
    yield '_', float("infinity"), '_'
    for current_answer, current_data in get_by_row(training_answers, training_data):
        yield current_data, distance(test_entry, current_data), current_answer

def get_k_nearest(k, test_entry, training_answers, training_data):
    all_nearest = list(_get_k_nearest(test_entry, training_answers, training_data))
    all_nearest.sort(key=lambda l: l[1])
    return all_nearest[:k]

def knn_classifier(k, test_entry, training_answers, training_data):
    """Classifies a test entry using k nearest neighbor classification against training data."""
    k_nearest_so_far = get_k_nearest(k, test_entry, training_answers, training_data)
    class_sum = 0
    for entry in k_nearest_so_far:
        class_sum += entry[2]

    if class_sum > 0:
        return 1
    else:
        return -1

def pull_one_out(answers, input_data):
    """Takes a column of input answers and an array of arrays of data and returns each answer,
    data set pair along with the answer, data set arrays that result from having pulled those
    single entries out.
    """
    number_of_rows = input_data.shape[0]
    for index in range(number_of_rows):
        remaining_answers = np.concatenate((answers[:index], answers[index + 1:]), axis=0)
        remaining_data = np.concatenate((input_data[:index], input_data[index + 1:]), axis=0)
        yield answers[index], input_data[index], remaining_answers, remaining_data

def testing_k_values(training_answers, training_data, testing_data, testing_answers):
    """Measures performance using percentage error on leave-one-out cross validation using k
    nearest neighbors classification.
    """
    for k in range(1, 17, 2):
        training_errors = 0
        leave_one_out_errors = 0
        test_data_errors = 0

        # Training Error
        for data, answer in zip(training_data, training_answers):
            estimation = knn_classifier(k, data, training_answers, training_data)
            if estimation != answer:
                training_errors += 1

        # Cross Validation Error
        for verify_answer, verify_data, remaining_answers, remaining_data in pull_one_out(
                training_answers, training_data):
            estimation = knn_classifier(k, verify_data, remaining_answers, remaining_data)
            if estimation != verify_answer:
                leave_one_out_errors += 1

        # Test data error
        for data, answer in zip(testing_data, testing_answers):
            estimation = knn_classifier(k, data, training_answers, training_data)
            if estimation != answer:
                test_data_errors += 1

        yield k, training_errors, leave_one_out_errors, test_data_errors

def main():
    training_data, training_answers = get_data_answers(raw_training_data)
    testing_data, testing_answers = get_data_answers(raw_testing_data)
    for line in testing_k_values(training_answers, training_data, testing_data, testing_answers):
        print("{},{},{},{}".format(*line))

if __name__ == "__main__":
    main()


text:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MLogger;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MLogger.Tests
{
    [TestClass()]
    public class MLoggerTests
    {
        const string TestMessage = "Test message: שלום Мир!";

        [TestMethod]
        public void MLoggerGeneralTests()
        {
            Console.WriteLine("MLogger.Default.LogFilePath: " + MLogger.Default.LogFilePath);
            Assert.IsNotNull(MLogger.Default.LogFilePath);
            Assert.IsTrue(!Configuration.Current.OrderEntriesByLogLevel || File.Exists(MLogger.Default.LogFilePath));
        }

        [TestMethod()]
        public void LogTest()
        {
            MLogger.Default.Log(TestMessage + " [LOG]");
            StringAssert.Contains(File.ReadAllText(MLogger.Default.LogFilePath), TestMessage);
        }

        [TestMethod]
        public void IsLogLevelEnabledTest()
        {
            Console.WriteLine("Configuration.Current.LogLevel: " + Configuration.Current.LogLevel);
            Assert.IsTrue(
                MLogger.Default.IsLogLevelEnabled(LogLevel.Critical)
                && MLogger.Default.IsLogLevelEnabled(LogLevel.Error)
                && MLogger.Default.IsLogLevelEnabled(LogLevel.Warn)
                && MLogger.Default.IsLogLevelEnabled(LogLevel.Info)
                && MLogger.Default.IsLogLevelEnabled(LogLevel.Debug));
        }

        [TestMethod()]
        public void GetLogLevelMarkerTest()
        {
            Assert.AreEqual<string>(
                Configuration.Current.OrderEntriesByLogLevel ? MLogger.LogLevelMarkerSpecialCharacter.ToString() : null,
                MLogger.Default.GetLogLevelMarker(LogLevel.Critical));
            Assert.AreEqual<string>(
                Configuration.Current.OrderEntriesByLogLevel ?
                    new string(new char[] { MLogger.LogLevelMarkerSpecialCharacter, MLogger.LogLevelMarkerSpecialCharacter }) : null,
                MLogger.Default.GetLogLevelMarker(LogLevel.Error));
        }

        [TestMethod()]
        public void GetLogLevelByMarkerTest()
        {
            LogLevel? ll = MLogger.Default.GetLogLevelByMarker("some text"); //no marker
            Assert.IsNull(ll);

            ll = MLogger.Default.GetLogLevelByMarker("some text" + MLogger.LogLevelMarkerSpecialCharacter);
            Assert.IsNotNull(ll);
            Assert.AreEqual<LogLevel>(LogLevel.Critical, ll.Value);

            ll = MLogger.Default.GetLogLevelByMarker("some text" + MLogger.LogLevelMarkerSpecialCharacter + MLogger.LogLevelMarkerSpecialCharacter);
            Assert.IsNotNull(ll);
            Assert.AreEqual<LogLevel>(LogLevel.Error, ll.Value);
        }
    }
}


text:
#ifndef SRC_BASE_TEST_GTEST_TEST_SUITE_H_
#define SRC_BASE_TEST_GTEST_TEST_SUITE_H_

#include "test/gtest_and_gmock.h"

// Define newer TEST_SUITE googletest APIs as aliases of the older APIs where
// necessary. This makes it possible to migrate Perfetto to the newer APIs and
// still use older googletest versions where necessary.
//
// TODO(costan): Remove this header after googletest is rolled in Android.

#if !defined(INSTANTIATE_TEST_SUITE_P)
#define INSTANTIATE_TEST_SUITE_P(...) INSTANTIATE_TEST_CASE_P(__VA_ARGS__)
#endif

#if !defined(INSTANTIATE_TYPED_TEST_SUITE_P)
#define INSTANTIATE_TYPED_TEST_SUITE_P(...) \
  INSTANTIATE_TYPED_TEST_CASE_P(__VA_ARGS__)
#endif

#if !defined(REGISTER_TEST_SUITE_P)
#define REGISTER_TEST_SUITE_P(...) REGISTER_TEST_CASE_P(__VA_ARGS__)
#endif

#if !defined(TYPED_TEST_SUITE)
#define TYPED_TEST_SUITE(...) TYPED_TEST_CASE(__VA_ARGS__)
#endif

#if !defined(TYPED_TEST_SUITE_P)
#define TYPED_TEST_SUITE_P(...) TYPED_TEST_CASE_P(__VA_ARGS__)
#endif

#endif  // SRC_BASE_TEST_GTEST_TEST_SUITE_H_


text:
'------------------------------------------------------------------------------
' <auto-generated>
'     This code was generated by a tool.
'
'     Changes to this file may cause incorrect behavior and will be lost if
'     the code is regenerated.
' </auto-generated>
'------------------------------------------------------------------------------

Option Strict On
Option Explicit On

Namespace Pages

    Partial Public Class ErrorPage

        '''
        '''rptError control.
        '''
        '''<remarks>
        '''Auto-generated field.
        '''To modify move field declaration from designer file to code-behind file.
        '''</remarks>
        Protected WithEvents rptError As Global.System.Web.UI.WebControls.Repeater

        '''
        '''panError control.
        '''
        '''<remarks>
        '''Auto-generated field.
        '''To modify move field declaration from designer file to code-behind file.
        '''</remarks>
        Protected WithEvents panError As Global.System.Web.UI.WebControls.Panel

        '''
        '''litMessage control.
        '''
        '''<remarks>
        '''Auto-generated field.
        '''To modify move field declaration from designer file to code-behind file.
        '''</remarks>
        Protected WithEvents litMessage As Global.System.Web.UI.WebControls.Literal

        '''
        '''panNoError control.
        '''
        '''<remarks>
        '''Auto-generated field.
        '''To modify move field declaration from designer file to code-behind file.
        '''</remarks>
        Protected WithEvents panNoError As Global.System.Web.UI.WebControls.Panel
    End Class
End Namespace


text:
import datetime
import uuid

import google.auth
from google.cloud import bigquery, datacatalog_v1
import pytest

def temp_suffix():
    now = datetime.datetime.now()
    return "{}_{}".format(now.strftime("%Y%m%d%H%M%S"), uuid.uuid4().hex[:8])

@pytest.fixture(scope="session")
def client(credentials):
    return datacatalog_v1.DataCatalogClient(credentials=credentials)

@pytest.fixture(scope="session")
def bigquery_client(credentials, project_id):
    return bigquery.Client(project=project_id, credentials=credentials)

@pytest.fixture(scope="session")
def default_credentials():
    return google.auth.default(
        scopes=["https://www.googleapis.com/auth/cloud-platform"]
    )

@pytest.fixture(scope="session")
def credentials(default_credentials):
    return default_credentials[0]

@pytest.fixture(scope="session")
def project_id(default_credentials):
    return default_credentials[1]

@pytest.fixture
def dataset_id(bigquery_client):
    dataset_id = f"python_data_catalog_sample_{temp_suffix()}"
    dataset = bigquery_client.create_dataset(dataset_id)
    yield dataset.dataset_id
    bigquery_client.delete_dataset(dataset, delete_contents=True, not_found_ok=True)

@pytest.fixture
def table_id(bigquery_client, project_id, dataset_id):
    table_id = f"python_data_catalog_sample_{temp_suffix()}"
    table = bigquery.Table("{}.{}.{}".format(project_id, dataset_id, table_id))
    table = bigquery_client.create_table(table)
    yield table.table_id
    bigquery_client.delete_table(table, not_found_ok=True)

@pytest.fixture
def random_tag_template_id():
    random_tag_template_id = f"python_sample_{temp_suffix()}"
    yield random_tag_template_id


text:
import { Meteor } from 'meteor/meteor';
import { _Settings } from './settings';

Meteor.methods({
  // eslint-disable-next-line
  'syncSettings.update': function(id, name, val, label, placeholder, category) {
    check(name, String);
    check(val, String);
    check(placeholder, String);
    check(label, String);
    check(category, String);
    if (Roles.userIsInRole(this.userId, ['admin'])) {
      _Settings.update(
        { _id: id },
        {
          $set: {
            name,
            val,
            placeholder,
            label,
            category,
          },
        },
      );
    }
    //   return something wrong in case it happens
  },
  'settings.insert': (name, val, placeholder, label, category) => {
    check(name, String);
    check(val, String);
    check(placeholder, String);
    check(label, String);
    check(category, String);
    _Settings.insert({
      name,
      val,
      placeholder,
      label,
      category,
      createdAt: new Date(),
    });
  },
  updateSetting: (id, name, val) => {
    check(id, String);
    check(name, String);
    check(val, String);
    _Settings.update(
      {
        _id: id,
      },
      {
        $set: {
          name,
          val,
        },
      },
    );
  },
});


text:
set -e

DEFAULT_INFLUXDB_VERSION="1.8"
DEFAULT_MAVEN_JAVA_VERSION="3-openjdk-17-slim"

INFLUXDB_VERSION="${INFLUXDB_VERSION:-$DEFAULT_INFLUXDB_VERSION}"
MAVEN_JAVA_VERSION="${MAVEN_JAVA_VERSION:-$DEFAULT_MAVEN_JAVA_VERSION}"

echo "Run tests with maven:${MAVEN_JAVA_VERSION} on influxdb-${INFLUXDB_VERSION}"
docker kill influxdb || true
docker rm influxdb || true
docker pull influxdb:${INFLUXDB_VERSION}-alpine || true
docker run \
       --detach \
       --name influxdb \
       --publish 8086:8086 \
       --publish 8089:8089/udp \
       --volume ${PWD}/influxdb.conf:/etc/influxdb/influxdb.conf \
       --env DOCKER_INFLUXDB_INIT_MODE=setup \
       --env DOCKER_INFLUXDB_INIT_USERNAME=my-user \
       --env DOCKER_INFLUXDB_INIT_PASSWORD=my-password \
       --env DOCKER_INFLUXDB_INIT_ORG=my-org \
       --env DOCKER_INFLUXDB_INIT_BUCKET=my-bucket \
       --env DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=my-token \
       influxdb:${INFLUXDB_VERSION}-alpine

echo "Starting Nginx"
docker kill nginx || true
docker rm  nginx || true

docker run \
       --detach \
       --name nginx \
       --publish 8080:8080 \
       --publish 8080:8080/udp \
       --volume ${PWD}/src/test/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
       --link influxdb:influxdb \
       nginx:stable-alpine nginx '-g' 'daemon off;'

echo "Running tests"
PROXY_API_URL=http://nginx:8080/influx-api/
PROXY_UDP_PORT=8080
if [[ "$INFLUXDB_VERSION" == "2."* ]]
then
    TEST_EXPRESSION="InfluxDB2Test"
    # Wait to start InfluxDB
    docker run --link influxdb:influxdb ubuntu:20.04 bash -c "apt-get update \
      && apt-get install wget --yes \
      && wget -S --spider --tries=20 --retry-connrefused --waitretry=5 http://influxdb:8086/ping"
    # Create DBRP Mapping
    BUCKET_ID=$(docker exec influxdb bash -c "influx bucket list -o my-org -n my-bucket | grep my-bucket | xargs | cut -d ' ' -f 0")
    docker exec influxdb bash -c "influx v1 dbrp create -o my-org --db mydb --rp autogen --default --bucket-id ${BUCKET_ID}"
    docker exec influxdb bash -c "influx v1 auth create -o my-org --username my-user --password my-password --read-bucket ${BUCKET_ID} --write-bucket ${BUCKET_ID}"
else
    TEST_EXPRESSION="*"
fi

docker run --rm \
       --volume ${PWD}:/usr/src/mymaven \
       --volume ${PWD}/.m2:/root/.m2 \
       --workdir /usr/src/mymaven \
       --link=influxdb \
       --link=nginx \
       --env INFLUXDB_VERSION=${INFLUXDB_VERSION} \
       --env INFLUXDB_IP=influxdb \
       --env PROXY_API_URL=${PROXY_API_URL} \
       --env PROXY_UDP_PORT=${PROXY_UDP_PORT} \
       maven:${MAVEN_JAVA_VERSION} mvn clean install -Dtest="${TEST_EXPRESSION}"

docker kill influxdb || true
docker kill nginx || true