46#include <rtl/ustrbuf.hxx>
50#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
51#include <com/sun/star/sdbc/ResultSetType.hpp>
52#include <com/sun/star/sdbc/SQLException.hpp>
53#include <com/sun/star/sdbc/XParameters.hpp>
55#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
56#include <com/sun/star/sdbcx/KeyType.hpp>
57#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
59#include <com/sun/star/container/XIndexAccess.hpp>
60#include <com/sun/star/container/XEnumerationAccess.hpp>
69using com::sun::star::uno::Any;
70using com::sun::star::uno::Type;
73using com::sun::star::uno::XInterface;
74using com::sun::star::uno::UNO_QUERY;
76using com::sun::star::lang::IllegalArgumentException;
78using com::sun::star::sdbc::XCloseable;
79using com::sun::star::sdbc::XStatement;
80using com::sun::star::sdbc::XPreparedStatement;
81using com::sun::star::sdbc::XParameters;
82using com::sun::star::sdbc::XRow;
83using com::sun::star::sdbc::XResultSet;
84using com::sun::star::sdbc::XConnection;
85using com::sun::star::sdbc::SQLException;
87using com::sun::star::sdbcx::XColumnsSupplier;
88using com::sun::star::sdbcx::XKeysSupplier;
90using com::sun::star::beans::Property;
91using com::sun::star::beans::XPropertySetInfo;
94using com::sun::star::container::XNameAccess;
95using com::sun::star::container::XEnumerationAccess;
96using com::sun::star::container::XEnumeration;
97using com::sun::star::container::XIndexAccess;
103 static ::cppu::OPropertyArrayHelper arrayHelper(
109 "EscapeProcessing", 1,
127 "ResultSetConcurrency", 7,
142 , m_connection( conn )
143 , m_pSettings( pSettings )
144 , m_xMutex( refMutex )
145 , m_multipleResultAvailable(false)
146 , m_multipleResultUpdateCount(0)
147 , m_lastOidInserted(InvalidOid)
152 css::sdbc::ResultSetConcurrency::READ_ONLY;
154 css::sdbc::ResultSetType::SCROLL_INSENSITIVE;
165 "pq_driver: Statement or connection has already been closed !",
166 *
this, OUString(),1,
Any());
171 Any aRet = Statement_BASE::queryInterface(rType);
172 return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType);
179 ::comphelper::concatSequences(
180 OPropertySetHelper::getTypes(),
181 Statement_BASE::getTypes()));
188 return css::uno::Sequence<sal_Int8>();
197 MutexGuard guard(
m_xMutex->GetMutex() );
213 std::u16string_view
sql,
const char * errorMsg )
215 OUString error =
"pq_driver: "
217 +
" (caused by statement '" +
sql +
"')";
218 SAL_WARN(
"connectivity.postgresql", error);
219 throw SQLException( error, *
this, OUString(), 1,
Any() );
243 std::string_view
sql,
244 const char * errorMsg,
245 const char *errorType =
nullptr )
247 OUStringBuffer buf(128);
248 buf.append(
"pq_driver: ");
252 buf.appendAscii( errorType );
257 +
" (caused by statement '"
260 OUString error = buf.makeStringAndClear();
261 SAL_WARN(
"connectivity.postgresql", error);
262 throw SQLException( error, owner, OUString(), 1,
Any() );
270 const OUString & table,
274 std::vector< OUString > ret;
278 if( tables->hasByName(
table ) )
279 tables->getByName(
table ) >>= keySupplier;
280 else if( -1 ==
table.indexOf(
'.' ) )
286 enumerationAccess->createEnumeration();
287 while( enumeration->hasMoreElements() )
290 enumeration->nextElement() >>=
set;
302 if( keySupplier.is() )
307 SAL_INFO(
"connectivity.postgresql",
"Can't offer updateable result set because table " <<
name <<
" is duplicated, add schema to resolve ambiguity");
310 keySupplier.set(
set, UNO_QUERY );
317 SAL_INFO(
"connectivity.postgresql",
"Can't offer updateable result set ( table " <<
table <<
" is unknown)");
320 if( keySupplier.is() )
324 set->getPropertyValue(
getStatics().SCHEMA_NAME ) >>= *pSchema;
329 while( enumeration->hasMoreElements() )
331 enumeration->nextElement() >>=
set;
332 sal_Int32 keyType = 0;
333 if( (
set->getPropertyValue( st.
TYPE ) >>= keyType ) &&
334 keyType == css::sdbcx::KeyType::PRIMARY )
339 int length = indexAccess->getCount();
345 indexAccess->getByIndex(
i ) >>=
set;
356 SAL_INFO(
"connectivity.postgresql",
"Can't offer updateable result set ( table " <<
table <<
" does not have a primary key)");
366 sal_Int32 duration = osl_getGlobalTimer();
368 duration = osl_getGlobalTimer() - duration;
373 ExecStatusType state = PQresultStatus(
result );
381 case PGRES_COMMAND_OK:
395 +
"), duration=" + OString::number(duration) +
"ms";
400 strOption +=
", usedOid=" + OString::number( *(data->
pLastOidInserted) ) +
", diagnosedTable="
403 SAL_INFO(
"connectivity.postgresql", strMain + strOption);
407 case PGRES_TUPLES_OK:
412 OUString
table, schema;
413 std::vector< OString > vec;
415 OUString sourceTable =
420 css::sdbc::ResultSetConcurrency::UPDATABLE )
423 if( sourceTable.getLength() )
425 std::vector< OUString > sourceTableKeys =
lookupKeys(
434 for(
i = 0 ;
i < sourceTableKeys.size() ;
i ++ )
445 if( !sourceTableKeys.empty() &&
i == sourceTableKeys.size() )
450 schema,
table, std::move(sourceTableKeys) );
452 else if( !
table.getLength() )
454 aReason =
"can't support updateable resultset, because a single table in the "
455 "WHERE part of the statement could not be identified (" + cmd +
".";
457 else if( !sourceTableKeys.empty() )
459 aReason =
"can't support updateable resultset for table "
462 +
", because resultset does not contain a part of the primary key ( column "
469 aReason =
"can't support updateable resultset for table "
472 +
", because resultset table does not have a primary key ";
477 SAL_WARN(
"connectivity.postgresql",
"can't support updateable result for selects with multiple tables (" << cmd <<
")");
481 SAL_WARN(
"connectivity.postgresql", aReason);
493 else if( sourceTable.getLength() > 0)
498 sal_Int32 returnedRows = PQntuples(
result );
507 SAL_INFO(
"connectivity.postgresql",
"executed query '" << cmd <<
"' successfully, duration=" << duration <<
"ms, returnedRows=" << returnedRows <<
".");
510 case PGRES_EMPTY_QUERY:
513 case PGRES_BAD_RESPONSE:
514 case PGRES_NONFATAL_ERROR:
515 case PGRES_FATAL_ERROR:
518 data->
owner, cmd, PQresultErrorMessage(
result ) , PQresStatus( state ) );
535 "FROM pg_constraint INNER JOIN pg_class ON conrelid = pg_class.oid "
536 "INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid "
537 "LEFT JOIN pg_class AS class2 ON confrelid = class2.oid "
538 "LEFT JOIN pg_namespace AS nmsp2 ON class2.relnamespace=nmsp2.oid "
539 "WHERE pg_class.relname = ? AND pg_namespace.nspname = ? AND pg_constraint.contype='p'" );
543 paras->setString( 2 , schemaName );
557 const OUString &schemaName,
563 "SELECT pg_attribute.attname, " + strDefaultValue +
564 "FROM pg_class, pg_namespace, pg_attribute "
565 "LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND "
566 "pg_attribute.attnum = pg_attrdef.adnum "
567 "WHERE pg_attribute.attrelid = pg_class.oid AND "
568 "pg_class.relnamespace = pg_namespace.oid AND "
569 "pg_namespace.nspname = ? AND "
572 "pg_class.relname LIKE ? AND "
573 + strDefaultValue +
" != ''"
577 paras->setString( 1 , schemaName );
593 std::u16string_view lastTableInserted,
594 const OString & lastQuery )
600 lastTableInserted, &schemaName, &
tableName );
602 if( nLastOid && lastTableInserted.size() )
604 OUStringBuffer buf( 128 );
605 buf.append(
"SELECT * FROM " );
606 if( schemaName.getLength() )
610 buf.append(
" WHERE oid = " + OUString::number(nLastOid) );
611 query = buf.makeStringAndClear();
613 else if ( lastTableInserted.size() && lastQuery.getLength() )
638 if( keyColumnNames.hasElements() )
640 OUStringBuffer buf( 128 );
641 buf.append(
"SELECT * FROM " );
643 buf.append(
" WHERE " );
644 bool bAdditionalCondition =
false;
646 for( OUString
const & columnNameUnicode : keyColumnNames )
650 bool bColumnMatchNamedValue =
false;
651 for (
auto const& namedValue : namedValues)
653 if(
columnName.equalsIgnoreAsciiCase( namedValue.first ) )
656 bColumnMatchNamedValue =
true;
662 if( !bColumnMatchNamedValue )
664 if( autoValues.empty() )
669 bool bColumnMatchAutoValue =
false;
670 for (
auto const& autoValue : autoValues)
672 if(
columnName.equalsIgnoreAsciiCase( autoValue.first ) )
675 value = OStringToOUString(autoValue.second, RTL_TEXTENCODING_ASCII_US );
678 if( autoValue.second.startsWith(
"nextval(") )
681 OUStringBuffer myBuf(128 );
682 myBuf.append(
"SELECT currval(" );
683 myBuf.appendAscii( &(autoValue.second.getStr()[8]));
686 bColumnMatchAutoValue =
true;
690 if( !bColumnMatchAutoValue )
699 if( bAdditionalCondition )
700 buf.append(
" AND " );
702 buf.append(
" = " +
value );
703 bAdditionalCondition =
true;
705 query = buf.makeStringAndClear();
709 if(
query.getLength() )
712 ret = stmt->executeQuery(
query );
721 osl::MutexGuard guard(
m_xMutex->GetMutex() );
726 if( lastResultSetHolder.is() )
727 lastResultSetHolder->close();
752 MutexGuard guard(
m_xMutex->GetMutex() );
774 ret = supplier->getMetaData();
786 Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle,
const Any& rValue )
795 bRet = ( rValue >>= val );
796 rConvertedValue <<= val;
802 bRet = ( rValue >>= val );
803 rConvertedValue <<= val;
815 bRet = ( rValue >>= val );
816 rConvertedValue <<= val;
821 throw IllegalArgumentException(
822 "pq_statement: Invalid property handle ("
823 + OUString::number(
nHandle ) +
")",
832 sal_Int32 nHandle,
const Any& rValue )
866 if( lastResultSetHolder.is() )
867 lastResultSetHolder->close();
880 osl::MutexGuard guard(
m_xMutex->GetMutex() );
necessary to avoid crashes in OOo, when an updateable result set is requested, but cannot be delivere...
virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet() override
virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type &reqType) override
virtual void SAL_CALL close() override
sal_Int32 m_multipleResultUpdateCount
virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData() override
css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
css::uno::Reference< css::sdbc::XCloseable > m_lastResultset
virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override
virtual void SAL_CALL disposing() override
virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const css::uno::Any &rValue) override
ConnectionSettings * m_pSettings
virtual ~Statement() override
::rtl::Reference< comphelper::RefCountedMutex > m_xMutex
Statement(const rtl::Reference< comphelper::RefCountedMutex > &refMutex, const css::uno::Reference< css::sdbc::XConnection > &con, struct ConnectionSettings *pSettings)
virtual void SAL_CALL clearWarnings() override
OUString m_lastTableInserted
virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getGeneratedValues() override
sal_Int32 m_lastOidInserted
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override
virtual sal_Int32 SAL_CALL getUpdateCount() override
virtual sal_Bool SAL_CALL execute(const OUString &sql) override
css::uno::Any m_props[STATEMENT_SIZE]
virtual cppu::IPropertyArrayHelper &SAL_CALL getInfoHelper() override
virtual css::uno::Any SAL_CALL getWarnings() override
virtual sal_Bool SAL_CALL convertFastPropertyValue(css::uno::Any &rConvertedValue, css::uno::Any &rOldValue, sal_Int32 nHandle, const css::uno::Any &rValue) override
void raiseSQLException(std::u16string_view sql, const char *errorMsg)
virtual sal_Int32 SAL_CALL executeUpdate(const OUString &sql) override
void SAL_CALL getFastPropertyValue(css::uno::Any &rValue, sal_Int32 nHandle) const override
virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery(const OUString &sql) override
virtual sal_Bool SAL_CALL getMoreResults() override
css::uno::Reference< css::sdbc::XConnection > m_connection
virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection() override
bool m_multipleResultAvailable
static css::uno::Reference< css::sdbc::XCloseable > createFromPGResultSet(const ::rtl::Reference< comphelper::RefCountedMutex > &mutex, const css::uno::Reference< css::uno::XInterface > &owner, ConnectionSettings **ppSettings, PGresult *result, const OUString &schema, const OUString &table, std::vector< OUString > &&primaryKey)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
void set(css::uno::UnoInterfaceReference const &value)
class SAL_NO_VTABLE XPropertySet
OString extractSingleTableFromSelect(const std::vector< OString > &vec)
const sal_Int32 STATEMENT_RESULT_SET_TYPE
const sal_Int32 STATEMENT_FETCH_SIZE
void bufferQuoteQualifiedIdentifier(OUStringBuffer &buf, std::u16string_view schema, std::u16string_view table, ConnectionSettings *settings)
OUString extractTableFromInsert(std::u16string_view sql)
static void getAutoValues(String2StringMap &result, const Reference< XConnection > &connection, const OUString &schemaName, const OUString &tableName, const ConnectionSettings *pConnectionSettings)
sal_Int32 extractIntProperty(const Reference< XPropertySet > &descriptor, const OUString &name)
const sal_Int32 STATEMENT_CURSOR_NAME
css::uno::Sequence< sal_Int32 > string2intarray(const OUString &str)
::cppu::WeakComponentImplHelper< css::sdbc::XStatement, css::sdbc::XCloseable, css::sdbc::XWarningsSupplier, css::sdbc::XMultipleResults, css::sdbc::XGeneratedResultSet, css::sdbc::XResultSetMetaDataSupplier > Statement_BASE
void tokenizeSQL(const OString &sql, std::vector< OString > &vec)
::cppu::IPropertyArrayHelper & getStatementPropertyArrayHelper()
const sal_Int32 STATEMENT_RESULT_SET_CONCURRENCY
static void raiseSQLException(const Reference< XInterface > &owner, std::string_view sql, const char *errorMsg, const char *errorType=nullptr)
const sal_Int32 STATEMENT_MAX_FIELD_SIZE
void extractNameValuePairsFromInsert(String2StringMap &map, const OString &lastQuery)
OUString querySingleValue(const css::uno::Reference< css::sdbc::XConnection > &connection, const OUString &query)
std::unordered_map< OString, OString > String2StringMap
void splitConcatenatedIdentifier(std::u16string_view source, OUString *first, OUString *second)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
OUString getColExprForDefaultSettingVal(ConnectionSettings const *settings)
static Sequence< OUString > getPrimaryKeyColumnNames(const Reference< XConnection > &connection, const OUString &schemaName, const OUString &tableName)
const sal_Int32 STATEMENT_ESCAPE_PROCESSING
static std::vector< OUString > lookupKeys(const Reference< css::container::XNameAccess > &tables, const OUString &table, OUString *pSchema, OUString *pTable)
Sequence< OUString > convertMappedIntArray2StringArray(const Int2StringMap &map, const Sequence< sal_Int32 > &intArray)
void bufferQuoteIdentifier(OUStringBuffer &buf, std::u16string_view toQuote, ConnectionSettings *settings)
const sal_Int32 STATEMENT_FETCH_DIRECTION
Reference< XResultSet > getGeneratedValuesFromLastInsert(ConnectionSettings *pConnectionSettings, const Reference< XConnection > &connection, sal_Int32 nLastOid, std::u16string_view lastTableInserted, const OString &lastQuery)
bool executePostgresCommand(const OString &cmd, struct CommandData *data)
std::unordered_map< sal_Int32, OUString > Int2StringMap
const sal_Int32 STATEMENT_QUERY_TIME_OUT
const sal_Int32 STATEMENT_MAX_ROWS
void fillAttnum2attnameMap(Int2StringMap &map, const Reference< css::sdbc::XConnection > &conn, const OUString &schema, const OUString &table)
store_handle_type *SAL_CALL query(OStoreObject *pHandle, store_handle_type *)
OUString * pLastTableInserted
css::uno::Reference< css::uno::XInterface > owner
sal_Int32 * pMultipleResultUpdateCount
css::uno::Reference< css::sdbc::XCloseable > * pLastResultset
sal_Int32 * pLastOidInserted
::rtl::Reference< comphelper::RefCountedMutex > refMutex
bool * pMultipleResultAvailable
ConnectionSettings ** ppSettings
css::uno::Reference< css::sdbcx::XTablesSupplier > tableSupplier
css::uno::Reference< css::container::XNameAccess > tables
static const rtl_TextEncoding encoding