From f5169421c013511bad3a3af3a39594fa355a4426 Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Thu, 13 Jun 2013 13:58:27 -0700 Subject: [PATCH] Remove SOCI requirement for PgPointCloud --- CMakeLists.txt | 6 +- include/pdal/drivers/pgpointcloud/Reader.hpp | 18 ++- include/pdal/drivers/pgpointcloud/Writer.hpp | 7 +- include/pdal/drivers/pgpointcloud/common.hpp | 114 +++++++++------ pdal_defines.h.in | 2 + src/CMakeLists.txt | 18 ++- src/SpatialReference.cpp | 2 +- src/StageFactory.cpp | 28 +++- src/drivers/pgpointcloud/Reader.cpp | 132 +++++++++++------ src/drivers/pgpointcloud/Writer.cpp | 144 ++++++++++--------- 10 files changed, 291 insertions(+), 180 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e5b15bf46..c696d61ddd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -338,10 +338,10 @@ set(WITH_PGPOINTCLOUD FALSE CACHE BOOL "Choose if PostgreSQL PointCloud support if (WITH_PGPOINTCLOUD) find_package(PostgreSQL) if (POSTGRESQL_FOUND) - set(PDAL_HAVE_PGPOINTCLOUD 1) - mark_as_advanced(CLEAR POSTGRESQL_INCLUDE_DIRS) + set(PDAL_HAVE_POSTGRESQL 1) + mark_as_advanced(CLEAR POSTGRESQL_INCLUDE_DIR) mark_as_advanced(CLEAR POSTGRESQL_LIBRARIES) - include_directories(${POSTGRESQL_INCLUDE_DIRS}) + include_directories(${POSTGRESQL_INCLUDE_DIR}) message(STATUS "Building with PgPointCloud") endif() endif() diff --git a/include/pdal/drivers/pgpointcloud/Reader.hpp b/include/pdal/drivers/pgpointcloud/Reader.hpp index 9c1c1db860..b33d67a41f 100644 --- a/include/pdal/drivers/pgpointcloud/Reader.hpp +++ b/include/pdal/drivers/pgpointcloud/Reader.hpp @@ -57,7 +57,7 @@ namespace pgpointcloud class PDAL_DLL Reader : public pdal::Reader { public: - SET_STAGE_NAME("drivers.pgpointcloud.reader", "PGPointcloud Reader") + SET_STAGE_NAME("drivers.pgpointcloud.reader", "PostgreSQL Pointcloud Database Reader") Reader(const Options&); ~Reader(); @@ -88,7 +88,7 @@ class PDAL_DLL Reader : public pdal::Reader boost::uint32_t fetchPcid() const; pdal::Schema fetchSchema() const; - ::soci::session* m_session; + PGconn* m_session; std::string m_connection; std::string m_table_name; std::string m_schema_name; @@ -124,8 +124,6 @@ class Iterator : public pdal::StageSequentialIterator // const pdal::drivers::pgpointcloud::Reader& getReader() const; - void setupDatabaseQuery(); - // Skip count points, return number of points skipped boost::uint64_t skipImpl(boost::uint64_t count); @@ -135,6 +133,11 @@ class Iterator : public pdal::StageSequentialIterator // True when there are no more points to read bool atEndImpl() const; + // Internal functions for managing scroll cursor + bool CursorSetup(); + bool CursorTeardown(); + bool NextBuffer(); + // // Members // @@ -143,12 +146,15 @@ class Iterator : public pdal::StageSequentialIterator pdal::PointBuffer* m_buffer; boost::uint64_t m_buffer_position; - ::soci::statement* m_statement; + bool m_cursor; std::string m_patch_hex; boost::uint32_t m_patch_npoints; - ::soci::session* m_session; + PGconn* m_session; pdal::DimensionMap* m_dimension_map; + boost::uint32_t m_cur_row; + boost::uint32_t m_cur_nrows; + PGresult* m_cur_result; }; // pdal.drivers.pgpointcloud.sequential.iterators.Iterator diff --git a/include/pdal/drivers/pgpointcloud/Writer.hpp b/include/pdal/drivers/pgpointcloud/Writer.hpp index 598f9f4de8..37c8a02a20 100644 --- a/include/pdal/drivers/pgpointcloud/Writer.hpp +++ b/include/pdal/drivers/pgpointcloud/Writer.hpp @@ -96,12 +96,7 @@ class PDAL_DLL Writer : public pdal::Writer bool WriteBlock(PointBuffer const& buffer); -#ifdef PDAL_HAVE_SOCI - ::soci::session* m_session; -#else - void* m_session; -#endif - + PGconn* m_session; const pdal::Schema &m_pdal_schema; std::string m_schema_name; std::string m_table_name; diff --git a/include/pdal/drivers/pgpointcloud/common.hpp b/include/pdal/drivers/pgpointcloud/common.hpp index e8ed0f53d6..d712dcc8ee 100644 --- a/include/pdal/drivers/pgpointcloud/common.hpp +++ b/include/pdal/drivers/pgpointcloud/common.hpp @@ -36,17 +36,7 @@ #ifndef INCLUDED_DRIVER_PGPOINTCLOUD_COMMON_HPP #define INCLUDED_DRIVER_PGPOINTCLOUD_COMMON_HPP -#ifdef PDAL_HAVE_SOCI -#include -#include -#include -#include -#include -#include -#include -#include -#endif - +#include "libpq-fe.h" #include #include @@ -57,30 +47,6 @@ namespace drivers namespace pgpointcloud { -class soci_driver_error : public pdal_error -{ -public: - soci_driver_error(std::string const& msg) - : pdal_error(msg) - {} -}; - -class connection_failed : public soci_driver_error -{ -public: - connection_failed(std::string const& msg) - : soci_driver_error(msg) - {} -}; - -class buffer_too_small : public soci_driver_error -{ -public: - buffer_too_small(std::string const& msg) - : soci_driver_error(msg) - {} -}; - enum CompressionType { @@ -104,27 +70,83 @@ inline CompressionType getCompressionType(std::string const& compression_type) return output; } -inline ::soci::session* connectToDataBase(std::string const& connection) +inline PGconn* pg_connect(std::string const& connection) { - ::soci::session* output(0); - + PGconn* conn; if ( ! connection.size() ) { - throw soci_driver_error("unable to connect to database, no connection string was given!"); + throw pdal_error("unable to connect to database, no connection string was given!"); } - try + /* Validate the connection string and get verbose error (?) */ + char *errstr; + PQconninfoOption *connOptions = PQconninfoParse(connection.c_str(), &errstr); + if ( ! connOptions ) { - output = new ::soci::session(::soci::postgresql, connection); - } catch (::soci::soci_error const& e) + throw pdal_error(errstr); + } + + /* connect to database */ + conn = PQconnectdb(connection.c_str()); + if ( (!conn) || (PQstatus(conn) != CONNECTION_OK) ) { - std::stringstream oss; - oss << "Unable to connect to database with error '" << e.what() << "'"; - throw connection_failed(oss.str()); + throw pdal_error("unable to connect to database"); } - return output; + + return conn; +} + +inline void pg_execute(PGconn* session, std::string const& sql) +{ + PGresult *result = PQexec(session, sql.c_str()); + if ( (!result) || (PQresultStatus(result) != PGRES_COMMAND_OK) ) + { + throw pdal_error(PQresultErrorMessage(result)); + } + PQclear(result); } +inline void pg_begin(PGconn* session) +{ + std::string sql = "BEGIN"; + pg_execute(session, sql); +} + +inline void pg_commit(PGconn* session) +{ + std::string sql = "COMMIT"; + pg_execute(session, sql); +} + +inline char* pg_query_once(PGconn* session, std::string const& sql) +{ + PGresult *result = PQexec(session, sql.c_str()); + + if ( (!result) || + PQresultStatus(result) != PGRES_TUPLES_OK || + PQntuples(result) == 0 ) + { + PQclear(result); + return NULL; + } + + char *str = strdup(PQgetvalue(result, 0, 0)); + PQclear(result); + return str; +} + +inline PGresult* pg_query_result(PGconn* session, std::string const& sql) +{ + PGresult *result = PQexec(session, sql.c_str()); + if ( PQresultStatus(result) != PGRES_TUPLES_OK ) + { + throw pdal_error(PQresultErrorMessage(result)); + } + return result; +} + + + } // pgpointcloud } // drivers } // pdal diff --git a/pdal_defines.h.in b/pdal_defines.h.in index 6e8fb282b0..b5fab3baf7 100644 --- a/pdal_defines.h.in +++ b/pdal_defines.h.in @@ -38,6 +38,7 @@ #cmakedefine PDAL_HAVE_P2G #cmakedefine PDAL_HAVE_PYTHON #cmakedefine PDAL_HAVE_SOCI +#cmakedefine PDAL_HAVE_POSTGRESQL /* * plugins @@ -48,6 +49,7 @@ #cmakedefine USE_PDAL_PLUGIN_OCI #cmakedefine USE_PDAL_PLUGIN_MRSID #cmakedefine USE_PDAL_PLUGIN_CARIS +#cmakedefine USE_PDAL_PLUGIN_PGPOINTCLOUD /* diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c9ee66e81d..94e7aea79f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -410,7 +410,7 @@ endif() # # drivers/pgpointcloud -# for now, we depend on soci +# we require PostgreSQL # set(PDAL_PGPOINTCLOUD_PATH drivers/pgpointcloud) set(PDAL_PGPOINTCLOUD_HEADERS ${PDAL_HEADERS_DIR}/${PDAL_PGPOINTCLOUD_PATH}) @@ -429,10 +429,12 @@ set (PDAL_DRIVERS_PGPOINTCLOUD_CPP # no provision is made for building as a plugin if (POSTGRESQL_FOUND) -# if (NOT USE_PDAL_PLUGIN_SOCI) - list (APPEND PDAL_CPP ${PDAL_DRIVERS_PGPOINTCLOUD_CPP} ) - list (APPEND PDAL_HPP ${PDAL_DRIVERS_PGPOINTCLOUD_HPP} ) -# endif() + if ( USE_PDAL_PLUGIN_PGPOINTCLOUD ) + message(FATAL_ERROR, "PgPointCloud plugin support unimplemented") + else() + list (APPEND PDAL_CPP ${PDAL_DRIVERS_PGPOINTCLOUD_CPP} ) + list (APPEND PDAL_HPP ${PDAL_DRIVERS_PGPOINTCLOUD_HPP} ) + endif() endif() @@ -613,6 +615,12 @@ target_link_libraries(${APPS_CPP_DEPENDENCIES} ${SOCI_LIBRARIES}) endif() endif() +if (WITH_PGPOINTCLOUD) +if (NOT USE_PDAL_PLUGIN_SOCI) +target_link_libraries(${APPS_CPP_DEPENDENCIES} ${POSTGRESQL_LIBRARIES}) +endif() +endif() + if (WITH_ORACLE) if (NOT USE_PDAL_PLUGIN_OCI) target_link_libraries(${APPS_CPP_DEPENDENCIES} ${ORACLE_LIBRARY}) diff --git a/src/SpatialReference.cpp b/src/SpatialReference.cpp index 7f9959b92d..98e851769a 100644 --- a/src/SpatialReference.cpp +++ b/src/SpatialReference.cpp @@ -152,7 +152,7 @@ void SpatialReference::setFromUserInput(std::string const& v) OGRErr err = srs.SetFromUserInput(const_cast(input)); if (err != OGRERR_NONE) { - throw std::invalid_argument("could not import coordinate system into OSRSpatialReference SetFromUserInput"); + throw std::invalid_argument("could not import coordinate system into OGRSpatialReference SetFromUserInput"); } srs.exportToWkt(&poWKT); diff --git a/src/StageFactory.cpp b/src/StageFactory.cpp index bd3e07bc92..a926fa76ea 100644 --- a/src/StageFactory.cpp +++ b/src/StageFactory.cpp @@ -81,12 +81,16 @@ #ifndef USE_PDAL_PLUGIN_SOCI #include #include +#endif +#endif + +#ifdef PDAL_HAVE_POSTGRESQL +#ifndef USE_PDAL_PLUGIN_PGPOINTCLOUD #include #include #endif #endif - #include #include #include @@ -141,6 +145,11 @@ MAKE_READER_CREATOR(NITFReader, pdal::drivers::nitf::Reader) #ifdef PDAL_HAVE_SOCI #ifndef USE_PDAL_PLUGIN_SOCI MAKE_READER_CREATOR(SociReader, pdal::drivers::soci::Reader) +#endif +#endif + +#ifdef PDAL_HAVE_POSTGRESQL +#ifndef USE_PDAL_PLUGIN_PGPOINTCLOUD MAKE_READER_CREATOR(PgPcReader, pdal::drivers::pgpointcloud::Reader) #endif #endif @@ -200,11 +209,16 @@ MAKE_WRITER_CREATOR(P2GWriter, pdal::drivers::p2g::Writer) #ifdef PDAL_HAVE_SOCI #ifndef USE_PDAL_PLUGIN_SOCI -MAKE_WRITER_CREATOR(PgPcWriter, pdal::drivers::pgpointcloud::Writer) MAKE_WRITER_CREATOR(SociWriter, pdal::drivers::soci::Writer) #endif #endif +#ifdef PDAL_HAVE_POSTGRESQL +#ifndef USE_PDAL_PLUGIN_PGPOINTCLOUD +MAKE_WRITER_CREATOR(PgPcWriter, pdal::drivers::pgpointcloud::Writer) +#endif +#endif + #ifdef PDAL_HAVE_NITRO #ifndef USE_PDAL_PLUGIN_NITF MAKE_WRITER_CREATOR(NitfWriter, pdal::drivers::nitf::Writer) @@ -423,6 +437,11 @@ void StageFactory::registerKnownReaders() #ifdef PDAL_HAVE_SOCI #ifndef USE_PDAL_PLUGIN_SOCI REGISTER_READER(SociReader, pdal::drivers::soci::Reader); +#endif +#endif + +#ifdef PDAL_HAVE_POSTGRESQL +#ifndef USE_PDAL_PLUGIN_PGPOINTCLOUD REGISTER_READER(PgPcReader, pdal::drivers::pgpointcloud::Reader); #endif #endif @@ -487,6 +506,11 @@ void StageFactory::registerKnownWriters() #ifdef PDAL_HAVE_SOCI #ifndef USE_PDAL_PLUGIN_SOCI REGISTER_WRITER(SociWriter, pdal::drivers::soci::Writer); +#endif +#endif + +#ifdef PDAL_HAVE_POSTGRESQL +#ifndef USE_PDAL_PLUGIN_PGPOINTCLOUD REGISTER_WRITER(PgPcWriter, pdal::drivers::pgpointcloud::Writer); #endif #endif diff --git a/src/drivers/pgpointcloud/Reader.cpp b/src/drivers/pgpointcloud/Reader.cpp index a8455ed096..3f829448ed 100644 --- a/src/drivers/pgpointcloud/Reader.cpp +++ b/src/drivers/pgpointcloud/Reader.cpp @@ -96,7 +96,7 @@ Reader::Reader(const Options& options) Reader::~Reader() { if ( m_session ) - delete m_session; + PQfinish(m_session); return; } @@ -141,7 +141,7 @@ void Reader::initialize() m_where = getOptions().getValueOrDefault("where", ""); // Database connection - m_session = connectToDataBase(m_connection); + m_session = pg_connect(m_connection); // Read schema from pointcloud_formats if possible Schema& schema = getSchemaRef(); @@ -177,8 +177,15 @@ boost::uint64_t Reader::getNumPoints() const oss << " WHERE " << m_where; } - m_session->once << oss.str(), ::soci::into(m_cached_point_count), ::soci::into(m_cached_max_points); - oss.str(""); + PGresult *result = pg_query_result(m_session, oss.str()); + + if ( PQresultStatus(result) != PGRES_TUPLES_OK ) + { + throw pdal_error("unable to get point count"); + } + m_cached_point_count = atoi(PQgetvalue(result, 0, 0)); + m_cached_max_points = atoi(PQgetvalue(result, 0, 1)); + PQclear(result); } return m_cached_point_count; @@ -227,9 +234,10 @@ boost::uint32_t Reader::fetchPcid() const oss << "WHERE c.relname = '" << m_table_name << "' "; oss << "AND a.attname = '" << m_column_name << "' "; - m_session->once << oss.str(), ::soci::into(pcid); - oss.str(""); - + char *pcid_str = pg_query_once(m_session, oss.str()); + pcid = atoi(pcid_str); + free(pcid_str); + if ( ! pcid ) throw pdal_error("Unable to fetch pcid specified column and table"); @@ -248,14 +256,9 @@ pdal::Schema Reader::fetchSchema() const std::ostringstream oss; oss << "SELECT schema FROM pointcloud_formats WHERE pcid = " << pcid; - ::soci::row r; - ::soci::statement schemas = (m_session->prepare << oss.str(), ::soci::into(r)); - schemas.execute(); - - if ( ! schemas.fetch() ) - throw pdal_error("Unable to retreive schema XML for specified column and table"); - - std::string xml = r.get("schema"); + char *xml_str = pg_query_once(m_session, oss.str()); + std::string xml = std::string(xml_str); + free(xml_str); Schema schema = Schema::from_xml(xml); @@ -297,25 +300,15 @@ pdal::SpatialReference Reader::fetchSpatialReference() const std::ostringstream oss; oss << "SELECT srid FROM pointcloud_formats WHERE pcid = " << pcid; - ::soci::row r; - ::soci::indicator ind; - ::soci::statement srids = (m_session->prepare << oss.str(), ::soci::into(r, ind)); - srids.execute(); - oss.str(""); - - if ( ! srids.fetch() ) + char *srid_str = pg_query_once(m_session, oss.str()); + if ( ! srid_str ) throw pdal_error("Unable to fetch srid for this table and column"); - boost::int32_t srid = r.get("srid"); - - if (ind == ::soci::i_null) - { - log()->get(logDEBUG) << "No SRID was selected for query" << std::endl; - return pdal::SpatialReference(); - } + boost::int32_t srid = atoi(srid_str); log()->get(logDEBUG) << " got SRID = " << srid << std::endl; + oss.str(""); oss << "EPSG:" << srid; if ( srid >= 0 ) @@ -352,26 +345,34 @@ Iterator::Iterator(const pdal::drivers::pgpointcloud::Reader& reader, PointBuffe , m_at_end(false) , m_buffer(NULL) , m_buffer_position(0) - , m_statement(NULL) + , m_cursor(false) , m_patch_hex("") , m_patch_npoints(0) , m_session(NULL) , m_dimension_map(NULL) + , m_cur_row(0) + , m_cur_nrows(0) + , m_cur_result(NULL) { pdal::Options const& options = reader.getOptions(); std::string const& connection = options.getValueOrThrow("connection"); - m_session = connectToDataBase(connection); - + m_session = pg_connect(connection); return; } Iterator::~Iterator() { - if ( m_statement ) - delete m_statement; - if ( m_session ) - delete m_session; + { + PQfinish(m_session); + m_session = NULL; + } + + if ( m_cur_result ) + { + PQclear(m_cur_result); + m_cur_result = NULL; + } if ( m_dimension_map ) delete m_dimension_map; @@ -401,6 +402,56 @@ bool Iterator::atEndImpl() const return m_at_end; } +bool Iterator::CursorSetup() +{ + std::ostringstream oss; + oss << "DECLARE cur CURSOR FOR " << getReader().getDataQuery(); + pg_begin(m_session); + pg_execute(m_session, oss.str()); + m_cursor = true; + + getReader().log()->get(logDEBUG) << "SQL cursor prepared: " << oss.str() << std::endl; + return true; +} + +bool Iterator::CursorTeardown() +{ + pg_execute(m_session, "CLOSE sur"); + pg_commit(m_session); + m_cursor = false; + getReader().log()->get(logDEBUG) << "SQL cursor closed." << std::endl; + return true; +} + +bool Iterator::NextBuffer() +{ + if ( ! m_cursor ) + CursorSetup(); + + if ( m_cur_row >= m_cur_nrows || ! m_cur_result ) + { + static std::string fetch = "FETCH 2 FROM cur"; + if ( m_cur_result ) PQclear(m_cur_result); + m_cur_result = pg_query_result(m_session, fetch); + getReader().log()->get(logDEBUG) << "SQL: " << fetch << std::endl; + if ( PQresultStatus(m_cur_result) != PGRES_TUPLES_OK || PQntuples(m_cur_result) == 0 ) + { + PQclear(m_cur_result); + m_cur_result = NULL; + CursorTeardown(); + return false; + } + + m_cur_row = 0; + m_cur_nrows = PQntuples(m_cur_result); + } + + m_patch_hex = std::string(PQgetvalue(m_cur_result, m_cur_row, 0)); + m_patch_npoints = atoi(PQgetvalue(m_cur_result, m_cur_row, 1)); + + m_cur_row++; + return true; +} boost::uint32_t Iterator::readBufferImpl(PointBuffer& user_buffer) { @@ -408,12 +459,9 @@ boost::uint32_t Iterator::readBufferImpl(PointBuffer& user_buffer) // First time through, create the SQL statement, allocate holding pens // and fire it off! - if ( ! m_statement ) + if ( ! m_cursor ) { - m_statement = new ::soci::statement(*m_session); - *m_statement = (m_session->prepare << getReader().getDataQuery(), ::soci::into(m_patch_hex), ::soci::into(m_patch_npoints)); - m_statement->execute(); - getReader().log()->get(logDEBUG) << "SQL statement prepared" << std::endl; + CursorSetup(); } // Is the cache for patches ready? @@ -450,7 +498,7 @@ boost::uint32_t Iterator::readBufferImpl(PointBuffer& user_buffer) if ( m_buffer_position >= m_buffer->getNumPoints() ) { // No more patches! We're done! - if ( ! m_statement->fetch() ) + if ( ! NextBuffer() ) { m_at_end = true; break; diff --git a/src/drivers/pgpointcloud/Writer.cpp b/src/drivers/pgpointcloud/Writer.cpp index 93fa7b059b..e0542f1b19 100644 --- a/src/drivers/pgpointcloud/Writer.cpp +++ b/src/drivers/pgpointcloud/Writer.cpp @@ -51,10 +51,13 @@ CREATE_WRITER_PLUGIN(pgpointcloud, pdal::drivers::pgpointcloud::Writer) #endif // TO DO: +// - change INSERT into COPY +// // - PCID / Schema consistency. If a PCID is specified, // must it be consistent with the buffer schema? Or should // the writer shove the data into the database schema as best // it can? +// // - Load information table. Should PDAL write into a metadata // table information about each load? If so, how to distinguish // between loads? Leave to pre/post SQL? @@ -91,6 +94,9 @@ Writer::Writer(Stage& prevStage, const Options& options) Writer::~Writer() { + if ( m_session ) + PQfinish(m_session); + return; } @@ -120,10 +126,7 @@ void Writer::initialize() std::string connection = getOptions().getValueOrThrow("connection"); // Can we connect, using this string? - m_session = connectToDataBase(connection); - - // Direct database log info to the logger - m_session->set_log_stream(&(log()->get(logDEBUG2))); + m_session = pg_connect(connection); // Read other preferences m_overwrite = getOptions().getValueOrDefault("overwrite", true); @@ -177,7 +180,7 @@ void Writer::writeBegin(boost::uint64_t /*targetNumPointsToWrite*/) { // Start up the database connection - m_session->begin(); + pg_begin(m_session); // Pre-SQL can be *either* a SQL file to execute, *or* a SQL statement // to execute. We find out which one here. @@ -192,7 +195,7 @@ void Writer::writeBegin(boost::uint64_t /*targetNumPointsToWrite*/) // filename to open, we'll use that instead. sql = pre_sql; } - m_session->once << sql; + pg_execute(m_session, sql); } bool bHaveTable = CheckTableExists(m_table_name); @@ -212,7 +215,7 @@ void Writer::writeBegin(boost::uint64_t /*targetNumPointsToWrite*/) { CreateTable(m_schema_name, m_table_name, m_column_name, m_pcid); } - + return; } @@ -236,10 +239,10 @@ void Writer::writeEnd(boost::uint64_t /*actualNumPointsWritten*/) // filename to open, we'll use that instead. sql = post_sql; } - m_session->once << sql; + pg_execute(m_session, sql); } - m_session->commit(); + pg_commit(m_session); return; } @@ -256,7 +259,9 @@ boost::uint32_t Writer::SetupSchema(Schema const& buffer_schema, boost::uint32_t if ( m_pcid ) { oss << "SELECT Count(pcid) FROM pointcloud_formats WHERE pcid = " << m_pcid; - m_session->once << oss.str(), ::soci::into(schema_count); + char *count_str = pg_query_once(m_session, oss.str()); + schema_count = atoi(count_str); + free(count_str); oss.str(""); if ( schema_count == 0 ) { @@ -267,43 +272,47 @@ boost::uint32_t Writer::SetupSchema(Schema const& buffer_schema, boost::uint32_t } // Do we have any existing schemas in the POINTCLOUD_FORMATS table? - boost::uint32_t pcid; + boost::uint32_t pcid = 0; bool bCreatePCPointSchema = true; oss << "SELECT Count(pcid) FROM pointcloud_formats"; - m_session->once << oss.str(), ::soci::into(schema_count); + char *schema_count_str = pg_query_once(m_session, oss.str()); + schema_count = atoi(schema_count_str); + free(schema_count_str); oss.str(""); // Do any of the existing schemas match the one we want to use? if (schema_count > 0) { - std::vector pg_schemas(schema_count); - std::vector pg_schema_ids(schema_count); - m_session->once << "SELECT pcid, schema FROM pointcloud_formats", ::soci::into(pg_schema_ids), ::soci::into(pg_schemas); - - for(int i=0; ionce << "SELECT Max(pcid)+1 AS pcid FROM pointcloud_formats", - ::soci::into(pcid); + char *pcid_str = pg_query_once(m_session, "SELECT Max(pcid)+1 AS pcid FROM pointcloud_formats"); + pcid = atoi(pcid_str); } /* If the writer specifies a compression, we should set that */ @@ -318,13 +327,19 @@ boost::uint32_t Writer::SetupSchema(Schema const& buffer_schema, boost::uint32_t Metadata metadata("compression", compression, ""); xml = pdal::Schema::to_xml(output_schema, &(metadata.toPTree())); - // xml = pdal::Schema::to_xml(output_schema); - oss << "INSERT INTO pointcloud_formats (pcid, srid, schema) "; - oss << "VALUES (:pcid, :srid, :xml)"; - m_session->once << oss.str(), ::soci::use(pcid, "pcid"), ::soci::use(srid, "srid"), ::soci::use(xml, "xml"); - oss.str(""); + const char** paramValues = (const char**)malloc(sizeof(char*)); + paramValues[0] = xml.c_str(); + + oss << "INSERT INTO pointcloud_formats (pcid, srid, schema) VALUES (" << pcid << "," << srid << ",$1)"; + PGresult *result = PQexecParams(m_session, oss.str().c_str(), 1, NULL, paramValues, NULL, NULL, 0); + if ( PQresultStatus(result) != PGRES_COMMAND_OK ) + { + throw pdal_error(PQresultErrorMessage(result)); + } + PQclear(result); } + m_pcid = pcid; return m_pcid; } @@ -343,8 +358,7 @@ void Writer::DeleteTable(std::string const& schema_name, } oss << table_name; - m_session->once << oss.str(); - oss.str(""); + pg_execute(m_session, oss.str()); } Schema Writer::PackSchema( Schema const& schema) const @@ -377,73 +391,68 @@ Schema Writer::PackSchema( Schema const& schema) const bool Writer::CheckPointCloudExists() { - std::ostringstream oss; - oss << "SELECT PC_Version()"; - log()->get(logDEBUG) << "checking for pointcloud existence ... " << std::endl; + std::string q = "SELECT PC_Version()"; + try { - m_session->once << oss.str(); + pg_execute(m_session, q); } - catch (::soci::soci_error const &e) + catch (pdal_error const &e) { - oss.str(""); return false; } - oss.str(""); return true; } bool Writer::CheckPostGISExists() { - std::ostringstream oss; - oss << "SELECT PostGIS_Version()"; + std::string q = "SELECT PostGIS_Version()"; log()->get(logDEBUG) << "checking for PostGIS existence ... " << std::endl; try { - m_session->once << oss.str(); + pg_execute(m_session, q); } - catch (::soci::soci_error const &e) + catch (pdal_error const &e) { - oss.str(""); return false; } - oss.str(""); return true; } bool Writer::CheckTableExists(std::string const& name) { - std::ostringstream oss; - oss << "SELECT tablename FROM pg_tables"; + oss << "SELECT count(*) FROM pg_tables WHERE tablename ILIKE '" << name << "'"; - log()->get(logDEBUG) << "checking for " << name << " existence ... " << std::endl; + log()->get(logDEBUG) << "checking for table '" << name << "' existence ... " << std::endl; - ::soci::rowset rs = (m_session->prepare << oss.str()); - - std::ostringstream debug; - for (::soci::rowset::const_iterator it = rs.begin(); it != rs.end(); ++it) + char *count_str = pg_query_once(m_session, oss.str()); + int count = atoi(count_str); + free(count_str); + + if ( count == 1 ) { - debug << ", " << *it; - if (boost::iequals(*it, name)) - { - log()->get(logDEBUG) << "it exists!" << std::endl; - return true; - } + return true; + } + else if ( count > 1 ) + { + log()->get(logDEBUG) << "found more than 1 table named '" << name << "'" << std::endl; + return false; + } + else + { + return false; } - log()->get(logDEBUG) << debug.str(); - log()->get(logDEBUG) << " -- '" << name << "' not found." << std::endl; - - return false; } + void Writer::CreateTable(std::string const& schema_name, std::string const& table_name, std::string const& column_name, @@ -463,8 +472,7 @@ void Writer::CreateTable(std::string const& schema_name, } oss << ")"; - m_session->once << oss.str(); - oss.str(""); + pg_execute(m_session, oss.str()); } // Make sure you test for the presence of PostGIS before calling this @@ -482,8 +490,7 @@ void Writer::CreateIndex(std::string const& schema_name, oss << table_name << "_pc_gix"; oss << " USING GIST (Geometry(" << column_name << "))"; - m_session->once << oss.str(); - oss.str(""); + pg_execute(m_session, oss.str()); } @@ -550,7 +557,7 @@ bool Writer::WriteBlock(PointBuffer const& buffer) boost::uint32_t compression = COMPRESSION_NONE; std::stringstream oss; - oss << "INSERT INTO " << m_table_name << " (pa) VALUES (:hex)"; + oss << "INSERT INTO " << m_table_name << " (pa) VALUES ('"; std::stringstream options; #ifdef BOOST_LITTLE_ENDIAN @@ -566,11 +573,10 @@ bool Writer::WriteBlock(PointBuffer const& buffer) options << boost::format("%08x") % compression; options << boost::format("%08x") % num_points; - std::stringstream hex; - hex << options.str() << Utils::binary_to_hex_string(block_data); - ::soci::statement st = (m_session->prepare << oss.str(), ::soci::use(hex.str(),"hex")); - st.execute(true); - oss.str(""); + oss << options.str() << Utils::binary_to_hex_string(block_data); + oss << "')"; + + pg_execute(m_session, oss.str()); return true; }