// Goes through all mailboxes and sets the foldercurrentuid to the latest message uid.
   bool
   Maintenance::RecalculateFolderUID_()
   {
      AnsiString recordSQL = "SELECT messagefolderid, MAX(messageuid) as messageuid FROM hm_messages GROUP BY messagefolderid";

      std::shared_ptr<DALRecordset> pRS = Application::Instance()->GetDBManager()->OpenRecordset(SQLCommand(recordSQL));

      if (!pRS)
         return false;

      while (!pRS->IsEOF())
      {
         __int64 messageFolderID = pRS->GetInt64Value("messagefolderid");
         __int64 messageUID = pRS->GetInt64Value("messageuid");

         if (messageFolderID <= 0)
            return false;

         if (messageUID <= 0)
            return false;

         AnsiString sqlUpdate = Formatter::Format("UPDATE hm_imapfolders SET foldercurrentuid = {0} WHERE folderid = {1} AND foldercurrentuid < {0}", messageUID, messageFolderID);

         bool result = Application::Instance()->GetDBManager()->Execute(SQLCommand(sqlUpdate));
         if (result == false)
            return false;
            
         pRS->MoveNext();
      }

      return true;
   }
   void 
   MySQLConnection::LoadSupportsTransactions_(const String &database)
   {
      supports_transactions_ = false;

      if (database.GetLength() == 0)
         return;

      MySQLRecordset rec;
      if (!rec.Open(shared_from_this(), SQLCommand("SHOW TABLE STATUS in " + database)))
         return;

      int tableCount = 0;

      while (!rec.IsEOF())
      {
         String sEngine = rec.GetStringValue("Engine");
         if (sEngine.CompareNoCase(_T("InnoDB")) != 0)
         {
            return;
         }

         tableCount++;

         rec.MoveNext();
      }

      if (tableCount > 0)
      {
         // Only InnoDB tables in this database. Enable transactions.
         supports_transactions_ = true;
      }
   }
bool
MySQLMacroExpander::ProcessMacro(std::shared_ptr<DALConnection> connection, const Macro &macro, String &sErrorMessage)
{
    switch (macro.GetType())
    {
    case Macro::DropColumnKeys:
        // MySQL4 doesn't support WHERE clauses in SHOW INDEX so
        // we must manually sort the result below.
        String sql;
        sql.Format(_T("SHOW INDEX IN %s"), macro.GetTableName().c_str());

        MySQLRecordset rec;
        if (!rec.Open(connection, SQLCommand(sql)))
        {
            sErrorMessage = "It was not possible to execute the below SQL statement. Please see hMailServer error log for details.\r\n" + sql;
            return false;
        }

        while (!rec.IsEOF())
        {
            String columnName = rec.GetStringValue("Column_name");

            if (columnName.CompareNoCase(macro.GetColumnName()) != 0)
            {
                // Wrong column
                rec.MoveNext();
                continue;
            }

            String constraintName = rec.GetStringValue("Key_name");

            String sqlUpdate;
            sqlUpdate.Format(_T("ALTER TABLE %s DROP INDEX %s"), macro.GetTableName().c_str(), constraintName.c_str());

            DALConnection::ExecutionResult execResult = connection->TryExecute(SQLCommand(sqlUpdate), sErrorMessage, 0, 0);

            if (execResult != DALConnection::DALSuccess)
                return false;

            rec.MoveNext();
        }
        break;
    }

    return true;
}
   bool
   SQLScriptRunner::ExecuteScript(shared_ptr<DALConnection> connectionObject, const String &sFile, String &sErrorMessage)
   {
      SQLScriptParser oParser(connectionObject->GetSettings(), sFile);
      if (!oParser.Parse(sErrorMessage))
      {
         sErrorMessage = "Parsing of SQL script failed: " + sFile + "\r\nError:" + sErrorMessage;
         return false;
      }

      if (oParser.GetNoOfCommands() == 0)
      {
         sErrorMessage = "Found no SQL commands in file : " + sFile;
         return false;
      }

      // 30 minute timeout per statement. Should hopefully never be needed.
      connectionObject->SetTimeout(60 * 30);

      for (int i = 0; i < oParser.GetNoOfCommands(); i++)
      {
         String sCommand = oParser.GetCommand(i);

         if (sCommand.StartsWith(_T("@@@")))
         {
            // Remove leading @@@.
            sCommand = sCommand.Mid(3);

            // Remove trailing @@@
            sCommand = sCommand.Mid(0, sCommand.Find(_T("@@@")));

            MacroParser parser(sCommand);
            Macro macro = parser.Parse();

            if (macro.GetType() == Macro::Unknown)
            {
               sErrorMessage = "Parsing of SQL script failed. Unknown macro. " + sFile + "\r\nMacro:" + sCommand;
               return false;
            }

            shared_ptr<IMacroExpander> macroExpander = connectionObject->CreateMacroExpander();
            if (!macroExpander->ProcessMacro(connectionObject, macro, sErrorMessage))
               return false;
         }
         else
         {
            if (connectionObject->TryExecute(SQLCommand(sCommand), sErrorMessage, 0, 0) != DALConnection::DALSuccess)
            {
               return false;
            }
         }
      }

      connectionObject->SetTimeout(30);

      return true;
   }
   shared_ptr<SecurityRange>
   PersistentSecurityRange::ReadMatchingIP(const IPAddress &ipaddress)
   {
      shared_ptr<SecurityRange> empty;

      IPAddressSQLHelper helper;
      String sSQL;

      if (ipaddress.GetType() == IPAddress::IPV4)
      {
         shared_ptr<SecurityRange> pSR = shared_ptr<SecurityRange>(new SecurityRange());

         sSQL.Format(_T("select * from hm_securityranges where %s >= rangelowerip1 and %s <= rangeupperip1 and rangelowerip2 IS NULL and rangeupperip2 IS NULL order by rangepriorityid desc"), 
            String(helper.GetAddress1String(ipaddress)), String(helper.GetAddress1String(ipaddress)));

         if (!ReadObject(pSR, SQLCommand(sSQL)))
            return empty;

         return pSR;
      }
      else
      {
         // Read all IPv6 items.
         shared_ptr<SecurityRange> bestMatch;

         SQLCommand command(_T("select * from hm_securityranges where rangelowerip2 is not null order by rangepriorityid desc"));
         
         shared_ptr<DALRecordset> recordset = Application::Instance()->GetDBManager()->OpenRecordset(command);
         if (!recordset)
            return empty;

         while (!recordset->IsEOF())
         {
            shared_ptr<SecurityRange> securityRange = shared_ptr<SecurityRange>(new SecurityRange());

            if (ReadObject(securityRange, recordset) == false)
               return empty;

            if (ipaddress.WithinRange(securityRange->GetLowerIP(), securityRange->GetUpperIP()))
            {
               // This IP range matches the client. Does it have higher prio than the currently
               // matching?

               if (!bestMatch || securityRange->GetPriority() > bestMatch->GetPriority())
                  bestMatch = securityRange;
            }

            recordset->MoveNext();
         }

         return bestMatch;
      }


      
   }
   bool 
   MySQLConnection::BeginTransaction(String &sErrorMessage)
   {
      if (supports_transactions_)
      {
         return TryExecute(SQLCommand("BEGIN"), sErrorMessage, 0)  == DALSuccess;
      }

      return true;
   }
int OGRGeoPackageDataSource::DeleteLayer( int iLayer )
{
    char *pszSQL;

    if( !m_bUpdate || iLayer < 0 || iLayer >= m_nLayers )
        return OGRERR_FAILURE;

    CPLString osLayerName = m_papoLayers[iLayer]->GetLayerDefn()->GetName();

    CPLDebug( "GPKG", "DeleteLayer(%s)", osLayerName.c_str() );

    /* Delete the layer object and remove the gap in the layers list */
    delete m_papoLayers[iLayer];
    memmove( m_papoLayers + iLayer, m_papoLayers + iLayer + 1,
             sizeof(void *) * (m_nLayers - iLayer - 1) );
    m_nLayers--;

    if (osLayerName.size() == 0)
        return OGRERR_NONE;

    pszSQL = sqlite3_mprintf(
            "DROP TABLE %s",
             osLayerName.c_str());
    
    SQLCommand(m_poDb, pszSQL);
    sqlite3_free(pszSQL);

    pszSQL = sqlite3_mprintf(
            "DELETE FROM gpkg_geometry_columns WHERE table_name = '%s'",
             osLayerName.c_str());
    
    SQLCommand(m_poDb, pszSQL);
    sqlite3_free(pszSQL);
    
    pszSQL = sqlite3_mprintf(
             "DELETE FROM gpkg_contents WHERE table_name = '%s'",
              osLayerName.c_str());

    SQLCommand(m_poDb, pszSQL);
    sqlite3_free(pszSQL);

    return OGRERR_NONE;
}
 void 
 MySQLConnection::RunCommand_(const String &sCommand) 
 //---------------------------------------------------------------------------()
 // DESCRIPTION:
 // Runs a single SQL command without any error handling.
 //---------------------------------------------------------------------------()
 {
    String sError;
    
    TryExecute(SQLCommand(sCommand), sError, 0);
 }
OGRErr OGRGeoPackageDataSource::AddColumn(const char *pszTableName, const char *pszColumnName, const char *pszColumnType)
{
    char *pszSQL;
    
    pszSQL = sqlite3_mprintf("ALTER TABLE %s ADD COLUMN %s %s", 
                             pszTableName, pszColumnName, pszColumnType);

    OGRErr err = SQLCommand(m_poDb, pszSQL);
    sqlite3_free(pszSQL);
    
    return err;
}
   void 
   MySQLConnection::SetConnectionCharacterSet_()
   {
      std::set<String> utf_character_sets;

      MySQLRecordset rec;
      if (!rec.Open(shared_from_this(), SQLCommand("SHOW CHARACTER SET LIKE 'UTF%'")))
      {
         ErrorManager::Instance()->ReportError(ErrorManager::Critical, 5008, "MySQLConnection::LoadConnectionCharacterSet_", "Unable to find appropriate MySQL character set. Command SHOW CHARACTER SET LIKE 'UTF%' failed.");
         return;
      }


      while (!rec.IsEOF())
      {
         String character_set  = rec.GetStringValue("Charset");
         utf_character_sets.insert(character_set);
         rec.MoveNext();
      }

      String character_set_to_use;

      if (utf_character_sets.find("utf8mb4") != utf_character_sets.end())
         character_set_to_use = "utf8mb4";
      else if (utf_character_sets.find("utf8") != utf_character_sets.end())
         character_set_to_use = "utf8";
      else
      {
         ErrorManager::Instance()->ReportError(ErrorManager::Critical, 5008, "MySQLConnection::LoadConnectionCharacterSet_", "Unable to find appropriate MySQL character set.");
         return;
      }

      String error_message;
      AnsiString set_names_command = Formatter::Format("SET NAMES {0}", character_set_to_use);

      if (TryExecute(SQLCommand(set_names_command), error_message, 0, 0) != DALConnection::DALSuccess)
      {
         ErrorManager::Instance()->ReportError(ErrorManager::Critical, 5008, "MySQLConnection::LoadConnectionCharacterSet_", set_names_command);
      }
   }
   bool 
   MySQLConnection::RollbackTransaction(String &sErrorMessage)
   {
      if (supports_transactions_)
      {
         return TryExecute(SQLCommand("ROLLBACK"), sErrorMessage, 0)  == DALSuccess;
      }
      else
      {
         sErrorMessage = "Rollback of MySQL statements failed. You may need to restore the latest database backup to ensure database integrity";
         ErrorManager::Instance()->ReportError(ErrorManager::Critical, 5104, "MySQLConnection::RollbackTransaction", sErrorMessage);

         return false;
      }
   }
Example #12
0
 bool 
 PGConnection::BeginTransaction(String &sErrorMessage)
 {
    return TryExecute(SQLCommand("BEGIN TRANSACTION"), sErrorMessage, 0, 0) == DALSuccess;
 }
Example #13
0
   bool
   SQLCEMacroExpander::ProcessMacro(shared_ptr<DALConnection> connection, const Macro &macro, String &sErrorMessage)
   {
      switch (macro.GetType())
      {
      case Macro::DropColumnKeys:
         {
            /// DROP KEYS

            SQLCommand command("select DISTINCT CONSTRAINT_NAME from INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME = @TABLE_NAME AND COLUMN_NAME = @COLUMN_NAME");
            command.AddParameter("@TABLE_NAME", macro.GetTableName());
            command.AddParameter("@COLUMN_NAME", macro.GetColumnName());

            SQLCERecordset rec;
            if (!rec.Open(connection, command))
            {
               sErrorMessage = "It was not possible to execute the below SQL statement. Please see hMailServer error log for details.\r\n" + command.GetQueryString();
               return false;
            }

            while (!rec.IsEOF())
            {
               String constraintName = rec.GetStringValue("CONSTRAINT_NAME");

               String sqlUpdate;
               sqlUpdate.Format(_T("ALTER TABLE %s DROP %s"), macro.GetTableName(), constraintName);

               DALConnection::ExecutionResult execResult = connection->TryExecute(SQLCommand(sqlUpdate), sErrorMessage, 0, 0);

               if (execResult != DALConnection::DALSuccess)
                  return false;

               rec.MoveNext();
            }

            /// DROP Indexes
            SQLCommand dropCommand ("SELECT DISTINCT INDEX_NAME FROM INFORMATION_SCHEMA.INDEXES WHERE TABLE_NAME = @TABLE_NAME AND COLUMN_NAME = @COLUMN_NAME");
            dropCommand.AddParameter("@TABLE_NAME", macro.GetTableName());
            dropCommand.AddParameter("@COLUMN_NAME", macro.GetColumnName());

            SQLCERecordset indexRecordset;
            if (!indexRecordset.Open(connection, dropCommand))
            {
               sErrorMessage = "It was not possible to execute the below SQL statement. Please see hMailServer error log for details.\r\n" + dropCommand.GetQueryString();
               return false;
            }

            while (!indexRecordset.IsEOF())
            {
               String indexName = indexRecordset.GetStringValue("INDEX_NAME");

               String sqlUpdate;
               sqlUpdate.Format(_T("DROP INDEX %s.%s"), macro.GetTableName(), indexName);

               DALConnection::ExecutionResult execResult = connection->TryExecute(SQLCommand(sqlUpdate), sErrorMessage, 0, 0);

               if (execResult != DALConnection::DALSuccess)
                  return false;

               indexRecordset.MoveNext();
            }
         }
         break;
      case Macro::SQLCEUPDATE_MESSAGES_SET_FOLDER_INBOX:
         {
            /*
            Short varant. UPDATE ... FROM is not supported in SQL CE 3.5
            update hm_messages set messagefolderid = 
            (select max(folderid) from hm_imapfolders where foldername = 'Inbox' and folderaccountid = messageaccountid and folderparentid = -1)
            where messagefolderid = 0 and messagetype = 2

            Updates all messages currently pointing at folder ID 0 (old inbox) so that they point at
            the actual Inbox folder ID instead.
            */

            // Retrieve a list of inboxes for all messages.
            SQLCommand recordSQL("SELECT folderaccountid, folderid FROM hm_imapfolders WHERE foldername = 'Inbox' AND folderparentid = -1");

            SQLCERecordset rec;
            if (!rec.Open(connection, recordSQL))
            {
               sErrorMessage = "It was not possible to execute the below SQL statement. Please see hMailServer error log for details.\r\n" + recordSQL.GetQueryString();
               return false;
            }

            while (!rec.IsEOF())
            {
               unsigned int folderAccountID = (unsigned int) rec.GetInt64Value("folderaccountid");
               unsigned int folderID = (unsigned int) rec.GetInt64Value("folderid");

               SQLCommand command("UPDATE hm_messages SET messagefolderid = @FOLDERID WHERE messageaccountid = @ACCOUNTID and messagefolderid = 0");
               command.AddParameter("@FOLDERID", folderID);
               command.AddParameter("@ACCOUNTID", folderAccountID);

               DALConnection::ExecutionResult execResult = connection->TryExecute(command, sErrorMessage, 0, 0);

               if (execResult != DALConnection::DALSuccess)
                  return false;

               rec.MoveNext();
            }
            break;
         }
      case Macro::SQLCEUPDATE_FOLDERS_SET_CURRENT_UID:
         {
            /*
            Short varant. UPDATE ... FROM is not supported in SQL CE 3.5
            update hm_imapfolders set foldercurrentuid = (select max(messageid) from hm_messages where folderid = messagefolderid)

            Updates the hm_imapfolders table to contain up-to-date foldercurrentuid's.
            */
            SQLCommand recordSQL("SELECT messagefolderid, MAX(messageid) messageid FROM hm_messages GROUP BY messagefolderid");

            SQLCERecordset rec;
            if (!rec.Open(connection, recordSQL))
            {
               sErrorMessage = "It was not possible to execute the below SQL statement. Please see hMailServer error log for details.\r\n" + recordSQL.GetQueryString();
               return false;
            }

            while (!rec.IsEOF())
            {
               unsigned int messageFolderID = (unsigned int) rec.GetInt64Value("messagefolderid");
               unsigned int messageID = (unsigned int) rec.GetInt64Value("messageid");

               SQLCommand updateCommand("UPDATE hm_imapfolders SET foldercurrentuid = @FOLDERCURRENTUID WHERE folderid = @FOLDERID");
               updateCommand.AddParameter("@FOLDERCURRENTUID", messageID);
               updateCommand.AddParameter("@FOLDERID", messageFolderID);

               DALConnection::ExecutionResult execResult = connection->TryExecute(updateCommand, sErrorMessage, 0, 0);

               if (execResult != DALConnection::DALSuccess)
                  return false;

               rec.MoveNext();
            }
            break;
         }
      case Macro::SQLCEUPDATE_FOLDERS_SET_NEW_PARENTFOLDERID_WHERE_ZERO:
         {
            /*
            Short varant:

            update hm_imapfolders set folderparentid = 
            (select folderid from hm_imapfolders folderinner where foldername = 'Inbox' and folderinner.folderaccountid = hm_imapfolders.folderaccountid)
            where folderparentid = 0

            Updates the hm_imapfolders to set the folderparentid to the new Inbox ID in the cases
            where folderparentid is zero.

            */
            SQLCommand recordSQL("select folderaccountid, folderid from hm_imapfolders where foldername = 'Inbox' and folderparentid = -1");

            SQLCERecordset rec;
            if (!rec.Open(connection, recordSQL))
            {
              sErrorMessage = "It was not possible to execute the below SQL statement. Please see hMailServer error log for details.\r\n" + recordSQL.GetQueryString();
               return false;
            }

            while (!rec.IsEOF())
            {
               unsigned int accountID = (unsigned int) rec.GetInt64Value("folderaccountid");
               unsigned int inboxFolderID = (unsigned int) rec.GetInt64Value("folderid");

               SQLCommand updateCommand ("update hm_imapfolders set folderparentid = @PARENTID where folderaccountid = @ACCOUNTID and folderparentid = 0");
               updateCommand.AddParameter("@PARENTID", inboxFolderID);
               updateCommand.AddParameter("@ACCOUNTID", accountID);

               DALConnection::ExecutionResult execResult = connection->TryExecute(updateCommand, sErrorMessage, 0, 0);

               if (execResult != DALConnection::DALSuccess)
                  return false;

               rec.MoveNext();
            }

            break;
         }

      case Macro::SQLCE_UPDATE_IMAP_HIERARCHY_DELIMITER:
         {
            /*
            Short varant:

            declare @delimiter varchar(10)
            select @delimiter = settingstring from hm_settings where settingname = 'IMAPHierarchyDelimiter'
            update hm_rule_actions set actionimapfolder = REPLACE(actionimapfolder, '\', @delimiter)
            update hm_rule_actions set actionimapfolder = REPLACE(actionimapfolder, '/', @delimiter)
            update hm_rule_actions set actionimapfolder = REPLACE(actionimapfolder, '.', @delimiter)

            */
            SQLCommand recordSQL("select settingstring from hm_settings where settingname = 'IMAPHierarchyDelimiter'");

            SQLCERecordset rec;
            if (!rec.Open(connection, recordSQL))
            {
               sErrorMessage = "It was not possible to execute the below SQL statement. Please see hMailServer error log for details.\r\n" + recordSQL.GetQueryString();
               return false;
            }

            if (rec.IsEOF())
            {
               sErrorMessage = "It was not possible to retrieve the value for the setting IMAPHierarchyDelimiter";
               return false;
            }

            String delimiter = rec.GetStringValue("settingstring");

            String sqlUpdate;
            sqlUpdate.Format(_T("update hm_rule_actions set actionimapfolder = REPLACE(actionimapfolder, '\', '%s')"), delimiter);
            DALConnection::ExecutionResult execResult = connection->TryExecute(SQLCommand(sqlUpdate), sErrorMessage, 0, 0);
            if (execResult != DALConnection::DALSuccess)
               return false;

            sqlUpdate.Format(_T("update hm_rule_actions set actionimapfolder = REPLACE(actionimapfolder, '/', '%s')"), delimiter);
            execResult = connection->TryExecute(SQLCommand(sqlUpdate), sErrorMessage, 0, 0);
            if (execResult != DALConnection::DALSuccess)
               return false;

            sqlUpdate.Format(_T("update hm_rule_actions set actionimapfolder = REPLACE(actionimapfolder, '.', '%s')"), delimiter);
            execResult = connection->TryExecute(SQLCommand(sqlUpdate), sErrorMessage, 0, 0);
            if (execResult != DALConnection::DALSuccess)
               return false;
            
            break;
         }

      }

      return true;
   }
OGRLayer * OGRGeoPackageDataSource::ExecuteSQL( const char *pszSQLCommand,
                                          OGRGeometry *poSpatialFilter,
                                          const char *pszDialect )

{
    if( EQUALN(pszSQLCommand, "SELECT ", 7) ||
        (pszDialect != NULL && EQUAL(pszDialect,"OGRSQL")) )
        return OGRDataSource::ExecuteSQL( pszSQLCommand, 
                                          poSpatialFilter, 
                                          pszDialect );

/* -------------------------------------------------------------------- */
/*      Prepare statement.                                              */
/* -------------------------------------------------------------------- */
    int rc;
    sqlite3_stmt *hSQLStmt = NULL;

    CPLString osSQLCommand = pszSQLCommand;

#if 0
    /* This will speed-up layer creation */
    /* ORDER BY are costly to evaluate and are not necessary to establish */
    /* the layer definition. */
    int bUseStatementForGetNextFeature = TRUE;
    int bEmptyLayer = FALSE;

    if( osSQLCommand.ifind("SELECT ") == 0 &&
        osSQLCommand.ifind(" UNION ") == std::string::npos &&
        osSQLCommand.ifind(" INTERSECT ") == std::string::npos &&
        osSQLCommand.ifind(" EXCEPT ") == std::string::npos )
    {
        size_t nOrderByPos = osSQLCommand.ifind(" ORDER BY ");
        if( nOrderByPos != std::string::npos )
        {
            osSQLCommand.resize(nOrderByPos);
            bUseStatementForGetNextFeature = FALSE;
        }
    }
#endif

    rc = sqlite3_prepare( m_poDb, osSQLCommand.c_str(), osSQLCommand.size(),
                          &hSQLStmt, NULL );

    if( rc != SQLITE_OK )
    {
        CPLError( CE_Failure, CPLE_AppDefined, 
                "In ExecuteSQL(): sqlite3_prepare(%s):\n  %s", 
                pszSQLCommand, sqlite3_errmsg(m_poDb) );

        if( hSQLStmt != NULL )
        {
            sqlite3_finalize( hSQLStmt );
        }

        return NULL;
    }

/* -------------------------------------------------------------------- */
/*      Do we get a resultset?                                          */
/* -------------------------------------------------------------------- */
    rc = sqlite3_step( hSQLStmt );
    if( rc != SQLITE_ROW )
    {
        if ( rc != SQLITE_DONE )
        {
            CPLError( CE_Failure, CPLE_AppDefined, 
                  "In ExecuteSQL(): sqlite3_step(%s):\n  %s", 
                  pszSQLCommand, sqlite3_errmsg(m_poDb) );

            sqlite3_finalize( hSQLStmt );
            return NULL;
        }
        
        if( EQUAL(pszSQLCommand, "VACUUM") )
        {
            sqlite3_finalize( hSQLStmt );
            /* VACUUM rewrites the DB, so we need to reset the application id */
            SetApplicationId();
            return NULL;
        }
        
        if( EQUALN(pszSQLCommand, "ALTER TABLE ", strlen("ALTER TABLE ")) )
        {
            char **papszTokens = CSLTokenizeString( pszSQLCommand );
            /* ALTER TABLE src_table RENAME TO dst_table */
            if( CSLCount(papszTokens) == 6 && EQUAL(papszTokens[3], "RENAME") &&
                EQUAL(papszTokens[4], "TO") )
            {
                const char* pszSrcTableName = papszTokens[2];
                const char* pszDstTableName = papszTokens[5];
                OGRLayer* poSrcLayer = GetLayerByName(pszSrcTableName);
                if( poSrcLayer )
                {
                    /* We also need to update GeoPackage metadata tables */
                    char* pszSQL;
                    pszSQL = sqlite3_mprintf(
                            "UPDATE gpkg_geometry_columns SET table_name = '%s' WHERE table_name = '%s'",
                            pszDstTableName, pszSrcTableName);
                    
                    SQLCommand(m_poDb, pszSQL);
                    sqlite3_free(pszSQL);
                    
                    pszSQL = sqlite3_mprintf(
                            "UPDATE gpkg_contents SET table_name = '%s' WHERE table_name = '%s'",
                            pszDstTableName, pszSrcTableName);

                    SQLCommand(m_poDb, pszSQL);
                    sqlite3_free(pszSQL);
                }
            }
            CSLDestroy(papszTokens);
        }

        if( !EQUALN(pszSQLCommand, "SELECT ", 7) )
        {
            sqlite3_finalize( hSQLStmt );
            return NULL;
        }
#if 0
        bUseStatementForGetNextFeature = FALSE;
        bEmptyLayer = TRUE;
#endif
    }

/* -------------------------------------------------------------------- */
/*      Create layer.                                                   */
/* -------------------------------------------------------------------- */
#if 0
    OGRSQLiteSelectLayer *poLayer = NULL;
        
    CPLString osSQL = pszSQLCommand;
    poLayer = new OGRGeopackageSelectLayer( this, osSQL, hSQLStmt,
                                        bUseStatementForGetNextFeature, bEmptyLayer, TRUE );

    if( poSpatialFilter != NULL )
        poLayer->SetSpatialFilter( 0, poSpatialFilter );
    
    return poLayer;
#else
    return OGRDataSource::ExecuteSQL( pszSQLCommand, 
                                          poSpatialFilter, 
                                          pszDialect );
#endif
}
OGRLayer* OGRGeoPackageDataSource::CreateLayer( const char * pszLayerName,
                                      OGRSpatialReference * poSpatialRef,
                                      OGRwkbGeometryType eGType,
                                      char **papszOptions )
{
    int iLayer;
    OGRErr err;
    
    if( !m_bUpdate )
        return NULL;

    /* Read GEOMETRY_COLUMN option */
    const char* pszGeomColumnName = CSLFetchNameValue(papszOptions, "GEOMETRY_COLUMN");
    if (pszGeomColumnName == NULL)
        pszGeomColumnName = "geom";
    
    /* Read FID option */
    const char* pszFIDColumnName = CSLFetchNameValue(papszOptions, "FID");
    if (pszFIDColumnName == NULL)
        pszFIDColumnName = "fid";

    if ( strspn(pszFIDColumnName, "`~!@#$%^&*()+-={}|[]\\:\";'<>?,./") > 0 )
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "The primary key (%s) name may not contain special characters or spaces", 
                 pszFIDColumnName);
        return NULL;
    }

    /* Avoiding gpkg prefixes is not an official requirement, but seems wise */
    if (strncmp(pszLayerName, "gpkg", 4) == 0)
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "The layer name may not begin with 'gpkg' as it is a reserved geopackage prefix");
        return NULL;
    }

    /* Pre-emptively try and avoid sqlite3 syntax errors due to  */
    /* illegal characters */
    if ( strspn(pszLayerName, "`~!@#$%^&*()+-={}|[]\\:\";'<>?,./") > 0 )
    {
        CPLError(CE_Failure, CPLE_AppDefined,
                 "The layer name may not contain special characters or spaces");
        return NULL;
    }

    /* Check for any existing layers that already use this name */
    for( iLayer = 0; iLayer < m_nLayers; iLayer++ )
    {
        if( EQUAL(pszLayerName, m_papoLayers[iLayer]->GetName()) )
        {
            const char *pszOverwrite = CSLFetchNameValue(papszOptions,"OVERWRITE");
            if( pszOverwrite != NULL && CSLTestBoolean(pszOverwrite) )
            {
                DeleteLayer( iLayer );
            }
            else
            {
                CPLError( CE_Failure, CPLE_AppDefined,
                          "Layer %s already exists, CreateLayer failed.\n"
                          "Use the layer creation option OVERWRITE=YES to "
                          "replace it.",
                          pszLayerName );
                return NULL;
            }
        }
    }

    /* Read our SRS_ID from the OGRSpatialReference */
    int nSRSId = UNDEFINED_SRID;
    if( poSpatialRef != NULL )
        nSRSId = GetSrsId( poSpatialRef );
        
    /* Requirement 25: The geometry_type_name value in a gpkg_geometry_columns */
    /* row SHALL be one of the uppercase geometry type names specified in */
    /* Geometry Types (Normative). */
    const char *pszGeometryType = OGRToOGCGeomType(eGType);
    
    /* Create the table! */
    char *pszSQL = NULL;
    if ( eGType != wkbNone )
    {
        pszSQL = sqlite3_mprintf(
            "CREATE TABLE %s ( "
            "%s INTEGER PRIMARY KEY AUTOINCREMENT, "
            "%s %s )",
             pszLayerName, pszFIDColumnName, pszGeomColumnName, pszGeometryType);
    }
    else
    {
        pszSQL = sqlite3_mprintf(
            "CREATE TABLE %s ( "
            "%s INTEGER PRIMARY KEY AUTOINCREMENT )",
             pszLayerName, pszFIDColumnName);
    }
    
    err = SQLCommand(m_poDb, pszSQL);
    sqlite3_free(pszSQL);
    if ( OGRERR_NONE != err )
        return NULL;

    /* Only spatial tables need to be registered in the metadata (hmmm) */
    if ( eGType != wkbNone )
    {
        /* Requirement 27: The z value in a gpkg_geometry_columns table row */
        /* SHALL be one of 0 (none), 1 (mandatory), or 2 (optional) */
        int bGeometryTypeHasZ = (wkb25DBit & eGType) != 0;

        /* Update gpkg_geometry_columns with the table info */
        pszSQL = sqlite3_mprintf(
            "INSERT INTO gpkg_geometry_columns "
            "(table_name,column_name,geometry_type_name,srs_id,z,m)"
            " VALUES "
            "('%q','%q','%q',%d,%d,%d)",
            pszLayerName,pszGeomColumnName,pszGeometryType,
            nSRSId,bGeometryTypeHasZ,0);
    
        err = SQLCommand(m_poDb, pszSQL);
        sqlite3_free(pszSQL);
        if ( err != OGRERR_NONE )
            return NULL;

        /* Update gpkg_contents with the table info */
        pszSQL = sqlite3_mprintf(
            "INSERT INTO gpkg_contents "
            "(table_name,data_type,identifier,last_change,srs_id)"
            " VALUES "
            "('%q','features','%q',strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ',CURRENT_TIMESTAMP),%d)",
            pszLayerName, pszLayerName, nSRSId);
    
        err = SQLCommand(m_poDb, pszSQL);
        sqlite3_free(pszSQL);
        if ( err != OGRERR_NONE )
            return NULL;

    }

    /* This is where spatial index logic will go in the future */
    const char *pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" );
    int bCreateSpatialIndex = ( pszSI == NULL || CSLTestBoolean(pszSI) );
    if( eGType != wkbNone && bCreateSpatialIndex )
    {
        /* This is where spatial index logic will go in the future */
    }
    
    /* The database is now all set up, so create a blank layer and read in the */
    /* info from the database. */
    OGRGeoPackageLayer *poLayer = new OGRGeoPackageLayer(this, pszLayerName);
    
    if( OGRERR_NONE != poLayer->ReadTableDefinition() )
    {
        delete poLayer;
        return NULL;
    }

    m_papoLayers = (OGRLayer**)CPLRealloc(m_papoLayers,  sizeof(OGRGeoPackageLayer*) * (m_nLayers+1));
    m_papoLayers[m_nLayers++] = poLayer;
    return poLayer;
}
Example #16
0
 bool 
 PGConnection::CommitTransaction(String &sErrorMessage)
 {
    return TryExecute(SQLCommand("COMMIT TRANSACTION"), sErrorMessage, 0, 0) == DALSuccess;
 }
   DALConnection::ConnectionResult
   MySQLConnection::Connect(String &sErrorMessage)
   {
      if (!MySQLInterface::Instance()->IsLoaded())
      {
         // Load the MySQL interface.
         if (!MySQLInterface::Instance()->Load(sErrorMessage))
         {
            // Loading failed
            return FatalError;
         }
      }

      try
      {
         String sUsername = database_settings_->GetUsername();
         String sPassword = database_settings_->GetPassword();
         String sServer = database_settings_->GetServer();
         String sDatabase = database_settings_->GetDatabaseName();
         long lDBPort = database_settings_->GetPort();

         if (lDBPort == 0)
            lDBPort = 3306;
         
         

         dbconn_ = MySQLInterface::Instance()->p_mysql_init(NULL);

         //MYSQL *pResult = mysql_real_connect(
         hm_MYSQL *pResult = MySQLInterface::Instance()->p_mysql_real_connect(
                     dbconn_, 
                     Unicode::ToANSI(sServer), 
                     Unicode::ToANSI(sUsername), 
                     Unicode::ToANSI(sPassword), 
                     Unicode::ToANSI(sDatabase), lDBPort, 0, 0);

         if (pResult == 0)
         {
            // From MySQL manual:
            // 
            // Return Values:
            //
            // A MYSQL* connection handle if the connection was successful, NULL if the connection was 
            // unsuccessful. For a successful connection, the return value is the same as the value 
            // of the first parameter.

            const char *pError = MySQLInterface::Instance()->p_mysql_error(dbconn_);
            sErrorMessage = pError;

            return TemporaryFailure;
         }

         if (CheckError(pResult, "mysql_real_connect()", sErrorMessage) != DALConnection::DALSuccess)
            return TemporaryFailure;

         SetConnectionCharacterSet_();

         if (!sDatabase.IsEmpty())
         {
            String switch_db_command = "use " + sDatabase;

            if (TryExecute(SQLCommand(switch_db_command), sErrorMessage, 0, 0) != DALConnection::DALSuccess)
            {
               return TemporaryFailure;
            }
         }

         LoadSupportsTransactions_(sDatabase);

         is_connected_ = true;
      }
      catch (...)
      {
         ErrorManager::Instance()->ReportError(ErrorManager::Critical, 5008, "MySQLConnection::Connect", "An unhandled error occurred when connecting to the database.");
         return TemporaryFailure;
      }
          
      return Connected;
   }
Example #18
0
 bool 
 PGConnection::RollbackTransaction(String &sErrorMessage)
 {
    return TryExecute(SQLCommand("ROLLBACK TRANSACTION"), sErrorMessage, 0, 0) == DALSuccess;
 }
int OGRGeoPackageDataSource::GetSrsId(const OGRSpatialReference * cpoSRS)
{
    char *pszWKT = NULL;
    char *pszSQL = NULL;
    int nSRSId = UNDEFINED_SRID;
    const char* pszAuthorityName;
    int nAuthorityCode = 0;
    OGRErr err;
    OGRBoolean bCanUseAuthorityCode = FALSE;

    if( cpoSRS == NULL )
        return UNDEFINED_SRID;

    OGRSpatialReference *poSRS = cpoSRS->Clone();

    poSRS->morphFromESRI();
    pszAuthorityName = poSRS->GetAuthorityName(NULL);

    if ( pszAuthorityName == NULL || strlen(pszAuthorityName) == 0 )
    {
        // Try to force identify an EPSG code                                    
        poSRS->AutoIdentifyEPSG();

        pszAuthorityName = poSRS->GetAuthorityName(NULL);
        if (pszAuthorityName != NULL && EQUAL(pszAuthorityName, "EPSG"))
        {
            const char* pszAuthorityCode = poSRS->GetAuthorityCode(NULL);
            if ( pszAuthorityCode != NULL && strlen(pszAuthorityCode) > 0 )
            {
                /* Import 'clean' SRS */
                poSRS->importFromEPSG( atoi(pszAuthorityCode) );

                pszAuthorityName = poSRS->GetAuthorityName(NULL);
            }
        }
    }
    // Check whether the EPSG authority code is already mapped to a
    // SRS ID.                                                         
    if ( pszAuthorityName != NULL && strlen(pszAuthorityName) > 0 )
    {
        // For the root authority name 'EPSG', the authority code
        // should always be integral
        nAuthorityCode = atoi( poSRS->GetAuthorityCode(NULL) );

        pszSQL = sqlite3_mprintf(
                         "SELECT srs_id FROM gpkg_spatial_ref_sys WHERE "
                         "upper(organization) = upper('%q') AND organization_coordsys_id = %d",
                         pszAuthorityName, nAuthorityCode );
        
        nSRSId = SQLGetInteger(m_poDb, pszSQL, &err);
        sqlite3_free(pszSQL);
        
        // Got a match? Return it!
        if ( OGRERR_NONE == err )
        {
            delete poSRS;
            return nSRSId;
        }
        
        // No match, but maybe we can use the nAuthorityCode as the nSRSId?
        pszSQL = sqlite3_mprintf(
                         "SELECT Count(*) FROM gpkg_spatial_ref_sys WHERE "
                         "srs_id = %d", nAuthorityCode );
        
        // Yep, we can!
        if ( ! SQLGetInteger(m_poDb, pszSQL, &err) && err == OGRERR_NONE )
            bCanUseAuthorityCode = TRUE;
    }

    // Translate SRS to WKT.                                           
    if( poSRS->exportToWkt( &pszWKT ) != OGRERR_NONE )
    {
        delete poSRS;
        CPLFree(pszWKT);
        return UNDEFINED_SRID;
    }

    // Reuse the authority code number as SRS_ID if we can
    if ( bCanUseAuthorityCode )
    {
        nSRSId = nAuthorityCode;
    }
    // Otherwise, generate a new SRS_ID number (max + 1)
    else
    {
        // Get the current maximum srid in the srs table.                  
        int nMaxSRSId = SQLGetInteger(m_poDb, "SELECT MAX(srs_id) FROM gpkg_spatial_ref_sys", &err);
        if ( OGRERR_NONE != err )
        {
            CPLFree(pszWKT);
            delete poSRS;
            return UNDEFINED_SRID;        
        }

        nSRSId = nMaxSRSId + 1;
    }
    
    // Add new SRS row to gpkg_spatial_ref_sys
    if( pszAuthorityName != NULL && nAuthorityCode > 0 )
    {
        pszSQL = sqlite3_mprintf(
                 "INSERT INTO gpkg_spatial_ref_sys "
                 "(srs_name,srs_id,organization,organization_coordsys_id,definition) "
                 "VALUES ('%s', %d, upper('%s'), %d, '%q')",
                 GetSrsName(poSRS), nSRSId, pszAuthorityName, nAuthorityCode, pszWKT
                 );
    }
    else
    {
        pszSQL = sqlite3_mprintf(
                 "INSERT INTO gpkg_spatial_ref_sys "
                 "(srs_name,srs_id,organization,organization_coordsys_id,definition) "
                 "VALUES ('%s', %d, upper('%s'), %d, '%q')",
                 GetSrsName(poSRS), nSRSId, "NONE", nSRSId, pszWKT
                 );
    }

    // Add new row to gpkg_spatial_ref_sys
    err = SQLCommand(m_poDb, pszSQL);

    // Free everything that was allocated.
    CPLFree(pszWKT);    
    sqlite3_free(pszSQL);
    delete poSRS;
    
    return nSRSId;
}
Example #20
0
int main( int argc, char **argv )
{
	FILE *input = stdin;
	PVARTEXT pvt_cmd;
	TEXTCHAR readbuf[4096];
	TEXTCHAR *buf;
	int offset = 0;
	int no_headers = 0;
	PODBC default_odbc = NULL;
	CTEXTSTR select_into;
	PLIST output = NULL;
	PLIST outputs = NULL;
	int arg_ofs = 0;
	SQLSetFeedbackHandler( ShowSQLStates );
	//SetAllocateDebug( TRUE );
	//SetAllocateLogging( TRUE );
	if( argc < 2 )
		Usage( 1 );
	else
	{
		while( argv[1+arg_ofs] && ( argv[1+arg_ofs][0] == '-' ) )
		{
			TEXTSTR tmp;
			switch( argv[1+arg_ofs][1] )
			{
			case 'n':
				no_headers = 1;
				break;
			case 'f':
				arg_ofs++;
				input = sack_fopen( 0, tmp = DupCharToText( argv[1+arg_ofs] ), WIDE("rt") );
				if( input )
					SQLSetFeedbackHandler( LogSQLStates );
				break;
			}
			if( tmp )
			{
				Deallocate( TEXTSTR, tmp );
				tmp = NULL;
			}
			arg_ofs++;
		}
		if( argv[1+arg_ofs] )
			default_odbc = ConnectToDatabase( DupCharToText( argv[1 + arg_ofs] ) );
	}
	SetHeapUnit( 4096 * 1024 ); // 4 megs expansion if needed...
	pvt_cmd = VarTextCreateExx( 10000, 50000 );


	while( (buf = readbuf), fgets( readbuf + offset
					, sizeof( readbuf ) - offset
					, input ) )
	{
		CTEXTSTR *result = NULL;
		size_t len;
		while( buf[0] == WIDE(' ') || buf[0] == WIDE('\t') )
         buf++;
		len = strlen( buf );
		if( buf[0] == WIDE('#') )
			continue;
		if( ( len > 0 ) && buf[len-1] == WIDE('\n') )
		{
			len--;
			buf[len] = 0;
		}

		if( strcmp( buf, WIDE("\\q") ) == 0 )
			break;

		if( !buf[0] && VarTextLength( pvt_cmd ) == 0 )
			continue;

		if( ( len > 0 ) && buf[len-1] == WIDE('\\') )
		{
			buf[len-1] = 0;
			len--;
			vtprintf( pvt_cmd, WIDE("%s"), buf );
			offset = 0;
			//offset = (len - 1); // read over the slash
			continue;
		}
		else
		{
			if( len > 0 )
				vtprintf( pvt_cmd, WIDE("%s"), buf );
			offset = 0;
		}

		buf = GetText( VarTextPeek( pvt_cmd ) );

		if( buf[0] == WIDE('?') )
		{
			int fields;
			int replace = 0;
			int ofs = 1;
			CTEXTSTR *columns;
			TEXTSTR *_columns;
			PVARTEXT pvt = NULL;
			if( buf[1] == WIDE('!') )
			{
				replace = 1;
				ofs = 2;
			}
			if( output )
			{
				if( !select_into || !select_into[0] )
				{
					printf( WIDE("Table name was invalid to insert into on the destination side...\'%s\'"), select_into );
					VarTextEmpty( pvt_cmd );
					continue;
				}
				pvt = VarTextCreateExx( 10000, 50000 );
			}
			if( SQLRecordQuery( default_odbc, buf + ofs, &fields, &result, &columns ) )
			{
				int count = 0;
				int first = 1;
				_columns = NewArray( TEXTSTR, fields );
				if( !no_headers )
				{
					{
						int n;
						for( n = 0; n < fields; n++ )
						{
							_columns[n] = StrDup( columns[n] );
							if( !pvt )
								fprintf( stdout, WIDE("%s%s"), n?WIDE(","):WIDE(""), columns[n] );
						}
					}
					if( !pvt )
						fprintf( stdout, WIDE("\n") );
				}
				for( ; result; FetchSQLRecord( default_odbc, &result ) )
				{
					if( pvt && first )
					{
						vtprintf( pvt, WIDE("%s into `%s` ("), replace?WIDE("replace"):WIDE("insert ignore"), select_into );
						{
							int first = 1;
							int n;
							for( n = 0; n < fields; n++ )
							{
								vtprintf( pvt, WIDE("%s`%s`"), first?WIDE(""):WIDE(","), _columns[n] );
								first = 0;
							}
						}
						vtprintf( pvt, WIDE(") values ") );
					}
					if( pvt )
					{
						vtprintf( pvt, WIDE("%s("), first?WIDE(""):WIDE(",") );
						{
							int first = 1; // private first, sorry :) parse that, Visual studio can.
							int n;
							for( n = 0; n < fields; n++ )
							{
								TEXTSTR tmp;
								vtprintf( pvt, WIDE("%s%s")
										  , first?WIDE(""):WIDE(",")
										  , result[n]?(tmp=EscapeStringOpt( result[n], TRUE)):((tmp=NULL),WIDE("NULL"))
										  );
								Release( tmp );
								first = 0;
							}
						}
						vtprintf( pvt, WIDE(")") );
					}
					else
					{
						int n;
						int first = 1;
						for( n = 0; n < fields; n++ )
						{

							fprintf( stdout, WIDE("%s%s"), first?WIDE(""):WIDE(","),result[n]?result[n]:WIDE("NULL") );
							first = 0;
						}
						fprintf( stdout, WIDE("\n") );
					}
					first = 0;
					count++;
					if( ( VarTextLength( pvt ) ) > 100000 )
					{
						PTEXT cmd;
						first = 1; // reset first to rebuild the beginning of the insert.
						printf( WIDE("Flushing at 100k characters...%d records\n"), count );
						if( pvt )
						{
							cmd = VarTextGet( pvt );
							if( cmd )
							{
								INDEX idx;
								PODBC odbc;
								LIST_FORALL( output, idx, PODBC, odbc )
								{
									if( !SQLCommand( odbc, GetText( cmd ) ) )
										printf( WIDE("Failed command to:%s\n"), (CTEXTSTR)GetLink( &outputs, idx ) );
								}
								LineRelease( cmd );
							}
						}
					}
				}
				if( !no_headers )
				{
					int n;
					for( n = 0; n < fields; n++ )
					{
						Release( _columns[n] );
					}
				}
				Release( _columns );
			}
int OGRGeoPackageDataSource::Create( const char * pszFilename,
                                     CPL_UNUSED char **papszOptions )
{
    CPLString osCommand;
    const char *pszSpatialRefSysRecord;

	/* The OGRGeoPackageDriver has already confirmed that the pszFilename */
	/* is not already in use, so try to create the file */
    int rc = sqlite3_open( pszFilename, &m_poDb );
    if ( rc != SQLITE_OK )
    {
        m_poDb = NULL;
        CPLError( CE_Failure, CPLE_OpenFailed, "sqlite3_open(%s) failed: %s",
                  pszFilename, sqlite3_errmsg( m_poDb ) );
        return FALSE;
    }

    m_pszFileName = CPLStrdup(pszFilename);
    m_bUpdate = TRUE;

    /* OGR UTF-8 support. If we set the UTF-8 Pragma early on, it */
    /* will be written into the main file and supported henceforth */
    SQLCommand(m_poDb, "PRAGMA encoding = \"UTF-8\"");

    /* Requirement 2: A GeoPackage SHALL contain 0x47503130 ("GP10" in ASCII) in the application id */
    /* http://opengis.github.io/geopackage/#_file_format */
    const char *pszPragma = CPLSPrintf("PRAGMA application_id = %d", GPKG_APPLICATION_ID);
    
    if ( OGRERR_NONE != SQLCommand(m_poDb, pszPragma) )
        return FALSE;
        
    /* Requirement 10: A GeoPackage SHALL include a gpkg_spatial_ref_sys table */
    /* http://opengis.github.io/geopackage/#spatial_ref_sys */
    const char *pszSpatialRefSys = 
        "CREATE TABLE gpkg_spatial_ref_sys ("
        "srs_name TEXT NOT NULL,"
        "srs_id INTEGER NOT NULL PRIMARY KEY,"
        "organization TEXT NOT NULL,"
        "organization_coordsys_id INTEGER NOT NULL,"
        "definition  TEXT NOT NULL,"
        "description TEXT"
        ")";
        
    if ( OGRERR_NONE != SQLCommand(m_poDb, pszSpatialRefSys) )
        return FALSE;

    /* Requirement 11: The gpkg_spatial_ref_sys table in a GeoPackage SHALL */
    /* contain a record for EPSG:4326, the geodetic WGS84 SRS */
    /* http://opengis.github.io/geopackage/#spatial_ref_sys */
    pszSpatialRefSysRecord = 
        "INSERT INTO gpkg_spatial_ref_sys ("
        "srs_name, srs_id, organization, organization_coordsys_id, definition, description"
        ") VALUES ("
        "'WGS 84 geodetic', 4326, 'EPSG', 4326, '"
        "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]"
        "', 'longitude/latitude coordinates in decimal degrees on the WGS 84 spheroid'"
        ")";  
          
    if ( OGRERR_NONE != SQLCommand(m_poDb, pszSpatialRefSysRecord) )
        return FALSE;

    /* Requirement 11: The gpkg_spatial_ref_sys table in a GeoPackage SHALL */
    /* contain a record with an srs_id of -1, an organization of “NONE”, */
    /* an organization_coordsys_id of -1, and definition “undefined” */
    /* for undefined Cartesian coordinate reference systems */
    /* http://opengis.github.io/geopackage/#spatial_ref_sys */
    pszSpatialRefSysRecord = 
        "INSERT INTO gpkg_spatial_ref_sys ("
        "srs_name, srs_id, organization, organization_coordsys_id, definition, description"
        ") VALUES ("
        "'Undefined cartesian SRS', -1, 'NONE', -1, 'undefined', 'undefined cartesian coordinate reference system'"
        ")"; 
           
    if ( OGRERR_NONE != SQLCommand(m_poDb, pszSpatialRefSysRecord) )
        return FALSE;

    /* Requirement 11: The gpkg_spatial_ref_sys table in a GeoPackage SHALL */
    /* contain a record with an srs_id of 0, an organization of “NONE”, */
    /* an organization_coordsys_id of 0, and definition “undefined” */
    /* for undefined geographic coordinate reference systems */
    /* http://opengis.github.io/geopackage/#spatial_ref_sys */
    pszSpatialRefSysRecord = 
        "INSERT INTO gpkg_spatial_ref_sys ("
        "srs_name, srs_id, organization, organization_coordsys_id, definition, description"
        ") VALUES ("
        "'Undefined geographic SRS', 0, 'NONE', 0, 'undefined', 'undefined geographic coordinate reference system'"
        ")"; 
           
    if ( OGRERR_NONE != SQLCommand(m_poDb, pszSpatialRefSysRecord) )
        return FALSE;
    
    /* Requirement 13: A GeoPackage file SHALL include a gpkg_contents table */
    /* http://opengis.github.io/geopackage/#_contents */
    const char *pszContents =
        "CREATE TABLE gpkg_contents ("
        "table_name TEXT NOT NULL PRIMARY KEY,"
        "data_type TEXT NOT NULL,"
        "identifier TEXT UNIQUE,"
        "description TEXT DEFAULT '',"
        "last_change DATETIME NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ',CURRENT_TIMESTAMP)),"
        "min_x DOUBLE, min_y DOUBLE,"
        "max_x DOUBLE, max_y DOUBLE,"
        "srs_id INTEGER,"
        "CONSTRAINT fk_gc_r_srs_id FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys(srs_id)"
        ")";
        
    if ( OGRERR_NONE != SQLCommand(m_poDb, pszContents) )
        return FALSE;

    /* Requirement 21: A GeoPackage with a gpkg_contents table row with a “features” */
    /* data_type SHALL contain a gpkg_geometry_columns table or updateable view */
    /* http://opengis.github.io/geopackage/#_geometry_columns */
    const char *pszGeometryColumns =        
        "CREATE TABLE gpkg_geometry_columns ("
        "table_name TEXT NOT NULL,"
        "column_name TEXT NOT NULL,"
        "geometry_type_name TEXT NOT NULL,"
        "srs_id INTEGER NOT NULL,"
        "z TINYINT NOT NULL,"
        "m TINYINT NOT NULL,"
        "CONSTRAINT pk_geom_cols PRIMARY KEY (table_name, column_name),"
        "CONSTRAINT uk_gc_table_name UNIQUE (table_name),"
        "CONSTRAINT fk_gc_tn FOREIGN KEY (table_name) REFERENCES gpkg_contents(table_name),"
        "CONSTRAINT fk_gc_srs FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys (srs_id)"
        ")";
        
    if ( OGRERR_NONE != SQLCommand(m_poDb, pszGeometryColumns) )
        return FALSE;

    /* Requirement 2: A GeoPackage SHALL contain 0x47503130 ("GP10" in ASCII) */
    /* in the application id field of the SQLite database header */
    /* We have to do this after there's some content so the database file */
    /* is not zero length */
    SetApplicationId();


    return TRUE;
}