mirror of
https://github.com/qgis/QGIS.git
synced 2025-11-22 00:14:55 -05:00
Merge pull request #48107 from elpaso/db_logger_2
Implementation of QEP: Add SQL Logging in the debugging/development panel
This commit is contained in:
commit
041e18a85c
@ -591,6 +591,7 @@
|
||||
<file>themes/default/propertyicons/attributes.svg</file>
|
||||
<file>themes/default/propertyicons/CRS.svg</file>
|
||||
<file>themes/default/propertyicons/datadefined.svg</file>
|
||||
<file>themes/default/propertyicons/database.svg</file>
|
||||
<file>themes/default/propertyicons/diagram.svg</file>
|
||||
<file>themes/default/propertyicons/digitizing.svg</file>
|
||||
<file>themes/default/propertyicons/display.svg</file>
|
||||
|
||||
1
images/themes/default/propertyicons/database.svg
Normal file
1
images/themes/default/propertyicons/database.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg height="24" viewBox="0 0 6.34992 6.34992" width="24" xmlns="http://www.w3.org/2000/svg"><g transform="scale(.99975 .99997)"><path d="m.53 1.455h5.29v4.022c-1.973.87-3.596.76-5.293 0z" fill="#6d97c4"/><path d="m.53 1.244v4.18l.53.265-.002-4.446z" fill="#bacee3"/><path d="m5.822 1.323v4.1l-1.058.398v-4.497z" fill="#55769a"/><path d="m5.822 1.19h.265v3.943h-.265zm-5.557 0h.265v3.943h-.266z" fill="#415a75"/><path d="m.53 2.46v.45c.21.146.41.226.61.288.52.158 1.256.242 2.036.242s1.47-.087 1.99-.245c.24-.082.472-.15.656-.285v-.45c0 .065-.046.164-.17.25-.124.09-.313.168-.557.242-.49.147-1.16.223-1.92.223s-1.474-.075-1.96-.223c-.246-.07-.436-.15-.56-.24-.123-.088-.126-.188-.126-.25z" fill="#415a75"/><ellipse cx="3.176" cy="1.191" fill="#bacee3" rx="2.779" ry=".794" stroke="#415a75" stroke-linecap="round" stroke-linejoin="round" stroke-width=".265"/><path d="m.265 5.133c0 .17.095.328.254.44.155.115.392.21.652.29.52.16 1.224.223 2.004.223s1.474-.062 1.998-.222c.26-.078.494-.176.653-.29.156-.113.26-.27.26-.44h-.265s-.008.155-.14.245c-.125.09-.315.17-.56.244-.49.148-1.186.197-1.946.197s-1.446-.046-1.933-.195c-.242-.072-.432-.152-.556-.245-.123-.085-.156-.184-.156-.247zm.265-1.35v.45c.21.146.41.225.612.287.52.158 1.254.243 2.034.243s1.47-.087 1.99-.245c.24-.083.472-.15.656-.285v-.45c0 .065-.046.164-.17.25-.124.09-.313.168-.557.242-.49.147-1.16.223-1.92.223s-1.473-.075-1.96-.224c-.244-.07-.434-.15-.558-.24-.124-.087-.128-.187-.128-.25z" fill="#415a75"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@ -854,6 +854,13 @@ Returns the application's bookmark manager, used for storing installation-wide b
|
||||
Returns the handler for recently used style items.
|
||||
|
||||
.. versionadded:: 3.22
|
||||
%End
|
||||
|
||||
static QgsDatabaseQueryLog *databaseQueryLog() /KeepReference/;
|
||||
%Docstring
|
||||
Returns the database query log.
|
||||
|
||||
.. versionadded:: 3.24
|
||||
%End
|
||||
|
||||
static QgsStyleModel *defaultStyleModel();
|
||||
|
||||
127
python/core/auto_generated/qgsdbquerylog.sip.in
Normal file
127
python/core/auto_generated/qgsdbquerylog.sip.in
Normal file
@ -0,0 +1,127 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/qgsdbquerylog.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
class QgsDatabaseQueryLogEntry
|
||||
{
|
||||
%Docstring(signature="appended")
|
||||
Encapsulates a logged database query.
|
||||
|
||||
.. versionadded:: 3.24
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsdbquerylog.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsDatabaseQueryLogEntry( const QString &query = QString() );
|
||||
%Docstring
|
||||
Constructor for QgsDatabaseQueryLogEntry.
|
||||
%End
|
||||
|
||||
int queryId;
|
||||
|
||||
QString uri;
|
||||
|
||||
QString provider;
|
||||
|
||||
QString query;
|
||||
|
||||
quint64 startedTime;
|
||||
|
||||
quint64 finishedTime;
|
||||
|
||||
QString initiatorClass;
|
||||
|
||||
QString origin;
|
||||
|
||||
long long fetchedRows;
|
||||
|
||||
QString error;
|
||||
|
||||
bool canceled;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class QgsDatabaseQueryLog: QObject
|
||||
{
|
||||
%Docstring(signature="appended")
|
||||
Handles logging of database queries.
|
||||
|
||||
:py:class:`QgsDatabaseQueryLog` is not usually directly created, but rather accessed through
|
||||
:py:func:`QgsApplication.databaseQueryLog()`. Generally, clients should only access the
|
||||
static :py:func:`~QgsDatabaseQueryLogEntry.log` method to register their queries.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# Log a database query
|
||||
QgsDatabaseQueryLog.log('SELECT * FROM my_table')
|
||||
|
||||
.. versionadded:: 3.24
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsdbquerylog.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsDatabaseQueryLog( QObject *parent = 0 );
|
||||
%Docstring
|
||||
Creates a new query log.
|
||||
|
||||
QgsDatabaseQueryLog is not usually directly created, but rather accessed through
|
||||
:py:func:`QgsApplication.databaseQueryLog()`.
|
||||
%End
|
||||
|
||||
|
||||
static bool enabled();
|
||||
%Docstring
|
||||
Returns ``True`` if logging is enabled.
|
||||
|
||||
.. seealso:: :py:func:`setEnabled`
|
||||
%End
|
||||
|
||||
static void log( const QgsDatabaseQueryLogEntry &query );
|
||||
%Docstring
|
||||
Logs a database ``query`` as starting.
|
||||
|
||||
This method can be safely called from any thread.
|
||||
%End
|
||||
|
||||
static void finished( const QgsDatabaseQueryLogEntry &query );
|
||||
%Docstring
|
||||
Records that the database ``query`` has finished.
|
||||
|
||||
This method can be safely called from any thread.
|
||||
%End
|
||||
|
||||
public slots:
|
||||
|
||||
|
||||
|
||||
signals:
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/qgsdbquerylog.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
@ -38,6 +38,7 @@
|
||||
%Include auto_generated/qgsdatasourceuri.sip
|
||||
%Include auto_generated/qgsdatetimestatisticalsummary.sip
|
||||
%Include auto_generated/qgsdbfilterproxymodel.sip
|
||||
%Include auto_generated/qgsdbquerylog.sip
|
||||
%Include auto_generated/qgsdefaultvalue.sip
|
||||
%Include auto_generated/qgsdiagramrenderer.sip
|
||||
%Include auto_generated/qgsdistancearea.sip
|
||||
|
||||
@ -163,12 +163,17 @@ set(QGIS_APP_SRCS
|
||||
browser/qgsinbuiltdataitemproviders.cpp
|
||||
|
||||
devtools/qgsappdevtoolutils.cpp
|
||||
devtools/qgsdevtoolsmodelnode.cpp
|
||||
devtools/networklogger/qgsnetworklogger.cpp
|
||||
devtools/networklogger/qgsnetworkloggernode.cpp
|
||||
devtools/networklogger/qgsnetworkloggerpanelwidget.cpp
|
||||
devtools/networklogger/qgsnetworkloggerwidgetfactory.cpp
|
||||
devtools/profiler/qgsprofilerpanelwidget.cpp
|
||||
devtools/profiler/qgsprofilerwidgetfactory.cpp
|
||||
devtools/querylogger/qgsappquerylogger.cpp
|
||||
devtools/querylogger/qgsdatabasequeryloggernode.cpp
|
||||
devtools/querylogger/qgsqueryloggerpanelwidget.cpp
|
||||
devtools/querylogger/qgsqueryloggerwidgetfactory.cpp
|
||||
|
||||
dwg/qgsdwgimportdialog.cpp
|
||||
dwg/qgsdwgimporter.cpp
|
||||
|
||||
@ -147,24 +147,24 @@ void QgsNetworkLogger::requestEncounteredSslErrors( int requestId, const QList<Q
|
||||
emit dataChanged( requestIndex, requestIndex );
|
||||
}
|
||||
|
||||
QgsNetworkLoggerNode *QgsNetworkLogger::index2node( const QModelIndex &index ) const
|
||||
QgsDevToolsModelNode *QgsNetworkLogger::index2node( const QModelIndex &index ) const
|
||||
{
|
||||
if ( !index.isValid() )
|
||||
return mRootNode.get();
|
||||
|
||||
return reinterpret_cast<QgsNetworkLoggerNode *>( index.internalPointer() );
|
||||
return reinterpret_cast<QgsDevToolsModelNode *>( index.internalPointer() );
|
||||
}
|
||||
|
||||
QList<QAction *> QgsNetworkLogger::actions( const QModelIndex &index, QObject *parent )
|
||||
{
|
||||
QgsNetworkLoggerNode *node = index2node( index );
|
||||
QgsDevToolsModelNode *node = index2node( index );
|
||||
if ( !node )
|
||||
return QList< QAction * >();
|
||||
|
||||
return node->actions( parent );
|
||||
}
|
||||
|
||||
QModelIndex QgsNetworkLogger::node2index( QgsNetworkLoggerNode *node ) const
|
||||
QModelIndex QgsNetworkLogger::node2index( QgsDevToolsModelNode *node ) const
|
||||
{
|
||||
if ( !node || !node->parent() )
|
||||
return QModelIndex(); // this is the only root item -> invalid index
|
||||
@ -176,11 +176,11 @@ QModelIndex QgsNetworkLogger::node2index( QgsNetworkLoggerNode *node ) const
|
||||
return index( row, 0, parentIndex );
|
||||
}
|
||||
|
||||
QModelIndex QgsNetworkLogger::indexOfParentLayerTreeNode( QgsNetworkLoggerNode *parentNode ) const
|
||||
QModelIndex QgsNetworkLogger::indexOfParentLayerTreeNode( QgsDevToolsModelNode *parentNode ) const
|
||||
{
|
||||
Q_ASSERT( parentNode );
|
||||
|
||||
QgsNetworkLoggerGroup *grandParentNode = parentNode->parent();
|
||||
QgsDevToolsModelGroup *grandParentNode = parentNode->parent();
|
||||
if ( !grandParentNode )
|
||||
return QModelIndex(); // root node -> invalid index
|
||||
|
||||
@ -197,7 +197,7 @@ void QgsNetworkLogger::removeRequestRows( const QList<int> &rows )
|
||||
|
||||
for ( int row : std::as_const( res ) )
|
||||
{
|
||||
int popId = data( index( row, 0, QModelIndex() ), QgsNetworkLoggerNode::RoleId ).toInt();
|
||||
int popId = data( index( row, 0, QModelIndex() ), QgsDevToolsModelNode::RoleId ).toInt();
|
||||
mRequestGroups.remove( popId );
|
||||
|
||||
beginRemoveRows( QModelIndex(), row, row );
|
||||
@ -213,7 +213,7 @@ QgsNetworkLoggerRootNode *QgsNetworkLogger::rootGroup()
|
||||
|
||||
int QgsNetworkLogger::rowCount( const QModelIndex &parent ) const
|
||||
{
|
||||
QgsNetworkLoggerNode *n = index2node( parent );
|
||||
QgsDevToolsModelNode *n = index2node( parent );
|
||||
if ( !n )
|
||||
return 0;
|
||||
|
||||
@ -232,7 +232,7 @@ QModelIndex QgsNetworkLogger::index( int row, int column, const QModelIndex &par
|
||||
row < 0 || row >= rowCount( parent ) )
|
||||
return QModelIndex();
|
||||
|
||||
QgsNetworkLoggerGroup *n = dynamic_cast< QgsNetworkLoggerGroup * >( index2node( parent ) );
|
||||
QgsDevToolsModelGroup *n = dynamic_cast< QgsDevToolsModelGroup * >( index2node( parent ) );
|
||||
if ( !n )
|
||||
return QModelIndex(); // have no children
|
||||
|
||||
@ -244,7 +244,7 @@ QModelIndex QgsNetworkLogger::parent( const QModelIndex &child ) const
|
||||
if ( !child.isValid() )
|
||||
return QModelIndex();
|
||||
|
||||
if ( QgsNetworkLoggerNode *n = index2node( child ) )
|
||||
if ( QgsDevToolsModelNode *n = index2node( child ) )
|
||||
{
|
||||
return indexOfParentLayerTreeNode( n->parent() ); // must not be null
|
||||
}
|
||||
@ -260,7 +260,7 @@ QVariant QgsNetworkLogger::data( const QModelIndex &index, int role ) const
|
||||
if ( !index.isValid() || index.column() > 1 )
|
||||
return QVariant();
|
||||
|
||||
QgsNetworkLoggerNode *node = index2node( index );
|
||||
QgsDevToolsModelNode *node = index2node( index );
|
||||
if ( !node )
|
||||
return QVariant();
|
||||
|
||||
@ -324,7 +324,7 @@ void QgsNetworkLoggerProxyModel::setShowCached( bool show )
|
||||
|
||||
bool QgsNetworkLoggerProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
|
||||
{
|
||||
QgsNetworkLoggerNode *node = mLogger->index2node( mLogger->index( source_row, 0, source_parent ) );
|
||||
QgsDevToolsModelNode *node = mLogger->index2node( mLogger->index( source_row, 0, source_parent ) );
|
||||
if ( QgsNetworkLoggerRequestGroup *request = dynamic_cast< QgsNetworkLoggerRequestGroup * >( node ) )
|
||||
{
|
||||
if ( ( request->status() == QgsNetworkLoggerRequestGroup::Status::Complete || request->status() == QgsNetworkLoggerRequestGroup::Status::Canceled )
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
#include <QElapsedTimer>
|
||||
#include "qgsnetworkaccessmanager.h"
|
||||
|
||||
class QgsNetworkLoggerNode;
|
||||
class QgsDevToolsModelNode;
|
||||
class QgsNetworkLoggerRequestGroup;
|
||||
class QgsNetworkLoggerRootNode;
|
||||
class QAction;
|
||||
@ -66,7 +66,7 @@ class QgsNetworkLogger : public QAbstractItemModel
|
||||
/**
|
||||
* Returns node for given index. Returns root node for invalid index.
|
||||
*/
|
||||
QgsNetworkLoggerNode *index2node( const QModelIndex &index ) const;
|
||||
QgsDevToolsModelNode *index2node( const QModelIndex &index ) const;
|
||||
|
||||
/**
|
||||
* Returns a list of actions corresponding to the item at the specified \a index.
|
||||
@ -109,8 +109,8 @@ class QgsNetworkLogger : public QAbstractItemModel
|
||||
private:
|
||||
|
||||
//! Returns index for a given node
|
||||
QModelIndex node2index( QgsNetworkLoggerNode *node ) const;
|
||||
QModelIndex indexOfParentLayerTreeNode( QgsNetworkLoggerNode *parentNode ) const;
|
||||
QModelIndex node2index( QgsDevToolsModelNode *node ) const;
|
||||
QModelIndex indexOfParentLayerTreeNode( QgsDevToolsModelNode *parentNode ) const;
|
||||
|
||||
QgsNetworkAccessManager *mNam = nullptr;
|
||||
bool mIsLogging = false;
|
||||
|
||||
@ -26,89 +26,12 @@
|
||||
#include <QClipboard>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
//
|
||||
// QgsNetworkLoggerNode
|
||||
//
|
||||
|
||||
QgsNetworkLoggerNode::QgsNetworkLoggerNode() = default;
|
||||
QgsNetworkLoggerNode::~QgsNetworkLoggerNode() = default;
|
||||
|
||||
|
||||
//
|
||||
// QgsNetworkLoggerGroup
|
||||
//
|
||||
|
||||
QgsNetworkLoggerGroup::QgsNetworkLoggerGroup( const QString &title )
|
||||
: mGroupTitle( title )
|
||||
{
|
||||
}
|
||||
|
||||
void QgsNetworkLoggerGroup::addChild( std::unique_ptr<QgsNetworkLoggerNode> child )
|
||||
{
|
||||
if ( !child )
|
||||
return;
|
||||
|
||||
Q_ASSERT( !child->mParent );
|
||||
child->mParent = this;
|
||||
|
||||
mChildren.emplace_back( std::move( child ) );
|
||||
}
|
||||
|
||||
int QgsNetworkLoggerGroup::indexOf( QgsNetworkLoggerNode *child ) const
|
||||
{
|
||||
Q_ASSERT( child->mParent == this );
|
||||
auto it = std::find_if( mChildren.begin(), mChildren.end(), [&]( const std::unique_ptr<QgsNetworkLoggerNode> &p )
|
||||
{
|
||||
return p.get() == child;
|
||||
} );
|
||||
if ( it != mChildren.end() )
|
||||
return std::distance( mChildren.begin(), it );
|
||||
return -1;
|
||||
}
|
||||
|
||||
QgsNetworkLoggerNode *QgsNetworkLoggerGroup::childAt( int index )
|
||||
{
|
||||
Q_ASSERT( static_cast< std::size_t >( index ) < mChildren.size() );
|
||||
return mChildren[ index ].get();
|
||||
}
|
||||
|
||||
void QgsNetworkLoggerGroup::clear()
|
||||
{
|
||||
mChildren.clear();
|
||||
}
|
||||
|
||||
QVariant QgsNetworkLoggerGroup::data( int role ) const
|
||||
{
|
||||
switch ( role )
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
return mGroupTitle;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant QgsNetworkLoggerGroup::toVariant() const
|
||||
{
|
||||
QVariantMap res;
|
||||
for ( const std::unique_ptr< QgsNetworkLoggerNode > &child : mChildren )
|
||||
{
|
||||
if ( const QgsNetworkLoggerValueNode *valueNode = dynamic_cast< const QgsNetworkLoggerValueNode *>( child.get() ) )
|
||||
{
|
||||
res.insert( valueNode->key(), valueNode->value() );
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//
|
||||
// QgsNetworkLoggerRootNode
|
||||
//
|
||||
|
||||
QgsNetworkLoggerRootNode::QgsNetworkLoggerRootNode()
|
||||
: QgsNetworkLoggerGroup( QString() )
|
||||
: QgsDevToolsModelGroup( QString() )
|
||||
{
|
||||
|
||||
}
|
||||
@ -126,76 +49,18 @@ void QgsNetworkLoggerRootNode::removeRow( int row )
|
||||
QVariant QgsNetworkLoggerRootNode::toVariant() const
|
||||
{
|
||||
QVariantList res;
|
||||
for ( const std::unique_ptr< QgsNetworkLoggerNode > &child : mChildren )
|
||||
for ( const std::unique_ptr< QgsDevToolsModelNode > &child : mChildren )
|
||||
res << child->toVariant();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsNetworkLoggerValueNode
|
||||
//
|
||||
QgsNetworkLoggerValueNode::QgsNetworkLoggerValueNode( const QString &key, const QString &value, const QColor &color )
|
||||
: mKey( key )
|
||||
, mValue( value )
|
||||
, mColor( color )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QVariant QgsNetworkLoggerValueNode::data( int role ) const
|
||||
{
|
||||
switch ( role )
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
case Qt::ToolTipRole:
|
||||
{
|
||||
return QStringLiteral( "%1: %2" ).arg( mKey.leftJustified( 30, ' ' ), mValue );
|
||||
}
|
||||
|
||||
case Qt::ForegroundRole:
|
||||
{
|
||||
if ( mColor.isValid() )
|
||||
return QBrush( mColor );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QList<QAction *> QgsNetworkLoggerValueNode::actions( QObject *parent )
|
||||
{
|
||||
QList< QAction * > res;
|
||||
|
||||
QAction *copyAction = new QAction( QObject::tr( "Copy" ), parent );
|
||||
QObject::connect( copyAction, &QAction::triggered, copyAction, [ = ]
|
||||
{
|
||||
QApplication::clipboard()->setText( QStringLiteral( "%1: %2" ).arg( mKey, mValue ) );
|
||||
} );
|
||||
|
||||
res << copyAction;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//
|
||||
// QgsNetworkLoggerGroup
|
||||
//
|
||||
|
||||
void QgsNetworkLoggerGroup::addKeyValueNode( const QString &key, const QString &value, const QColor &color )
|
||||
{
|
||||
addChild( std::make_unique< QgsNetworkLoggerValueNode >( key, value, color ) );
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsNetworkLoggerRequestGroup
|
||||
//
|
||||
|
||||
QgsNetworkLoggerRequestGroup::QgsNetworkLoggerRequestGroup( const QgsNetworkRequestParameters &request )
|
||||
: QgsNetworkLoggerGroup( QString() )
|
||||
: QgsDevToolsModelGroup( QString() )
|
||||
, mUrl( request.request().url() )
|
||||
, mRequestId( request.requestId() )
|
||||
, mOperation( request.operation() )
|
||||
@ -478,7 +343,7 @@ QString QgsNetworkLoggerRequestGroup::cacheControlToString( QNetworkRequest::Cac
|
||||
//
|
||||
|
||||
QgsNetworkLoggerRequestDetailsGroup::QgsNetworkLoggerRequestDetailsGroup( const QgsNetworkRequestParameters &request )
|
||||
: QgsNetworkLoggerGroup( QObject::tr( "Request" ) )
|
||||
: QgsDevToolsModelGroup( QObject::tr( "Request" ) )
|
||||
{
|
||||
addKeyValueNode( QObject::tr( "Operation" ), QgsNetworkLoggerRequestGroup::operationToString( request.operation() ) );
|
||||
addKeyValueNode( QObject::tr( "Thread" ), request.originatingThreadId() );
|
||||
@ -521,7 +386,7 @@ QgsNetworkLoggerRequestDetailsGroup::QgsNetworkLoggerRequestDetailsGroup( const
|
||||
|
||||
QVariant QgsNetworkLoggerRequestDetailsGroup::toVariant() const
|
||||
{
|
||||
QVariantMap res = QgsNetworkLoggerGroup::toVariant().toMap();
|
||||
QVariantMap res = QgsDevToolsModelGroup::toVariant().toMap();
|
||||
if ( mQueryGroup )
|
||||
res.insert( QObject::tr( "Query" ), mQueryGroup->toVariant() );
|
||||
if ( mRequestHeaders )
|
||||
@ -537,7 +402,7 @@ QVariant QgsNetworkLoggerRequestDetailsGroup::toVariant() const
|
||||
//
|
||||
|
||||
QgsNetworkLoggerRequestQueryGroup::QgsNetworkLoggerRequestQueryGroup( const QUrl &url )
|
||||
: QgsNetworkLoggerGroup( QObject::tr( "Query" ) )
|
||||
: QgsDevToolsModelGroup( QObject::tr( "Query" ) )
|
||||
{
|
||||
QUrlQuery query( url );
|
||||
const QList<QPair<QString, QString> > queryItems = query.queryItems();
|
||||
@ -553,7 +418,7 @@ QgsNetworkLoggerRequestQueryGroup::QgsNetworkLoggerRequestQueryGroup( const QUrl
|
||||
// QgsNetworkLoggerRequestHeadersGroup
|
||||
//
|
||||
QgsNetworkLoggerRequestHeadersGroup::QgsNetworkLoggerRequestHeadersGroup( const QgsNetworkRequestParameters &request )
|
||||
: QgsNetworkLoggerGroup( QObject::tr( "Headers" ) )
|
||||
: QgsDevToolsModelGroup( QObject::tr( "Headers" ) )
|
||||
{
|
||||
const QList<QByteArray> headers = request.request().rawHeaderList();
|
||||
for ( const QByteArray &header : headers )
|
||||
@ -567,7 +432,7 @@ QgsNetworkLoggerRequestHeadersGroup::QgsNetworkLoggerRequestHeadersGroup( const
|
||||
//
|
||||
|
||||
QgsNetworkLoggerPostContentGroup::QgsNetworkLoggerPostContentGroup( const QgsNetworkRequestParameters ¶meters )
|
||||
: QgsNetworkLoggerGroup( QObject::tr( "Content" ) )
|
||||
: QgsDevToolsModelGroup( QObject::tr( "Content" ) )
|
||||
{
|
||||
addKeyValueNode( QObject::tr( "Data" ), parameters.content() );
|
||||
}
|
||||
@ -578,7 +443,7 @@ QgsNetworkLoggerPostContentGroup::QgsNetworkLoggerPostContentGroup( const QgsNet
|
||||
//
|
||||
|
||||
QgsNetworkLoggerReplyGroup::QgsNetworkLoggerReplyGroup( const QgsNetworkReplyContent &reply )
|
||||
: QgsNetworkLoggerGroup( QObject::tr( "Reply" ) )
|
||||
: QgsDevToolsModelGroup( QObject::tr( "Reply" ) )
|
||||
{
|
||||
addKeyValueNode( QObject::tr( "Status" ), reply.attribute( QNetworkRequest::HttpStatusCodeAttribute ).toString() );
|
||||
if ( reply.error() != QNetworkReply::NoError )
|
||||
@ -595,7 +460,7 @@ QgsNetworkLoggerReplyGroup::QgsNetworkLoggerReplyGroup( const QgsNetworkReplyCon
|
||||
|
||||
QVariant QgsNetworkLoggerReplyGroup::toVariant() const
|
||||
{
|
||||
QVariantMap res = QgsNetworkLoggerGroup::toVariant().toMap();
|
||||
QVariantMap res = QgsDevToolsModelGroup::toVariant().toMap();
|
||||
if ( mReplyHeaders )
|
||||
{
|
||||
res.insert( QObject::tr( "Headers" ), mReplyHeaders->toVariant() );
|
||||
@ -608,7 +473,7 @@ QVariant QgsNetworkLoggerReplyGroup::toVariant() const
|
||||
// QgsNetworkLoggerReplyHeadersGroup
|
||||
//
|
||||
QgsNetworkLoggerReplyHeadersGroup::QgsNetworkLoggerReplyHeadersGroup( const QgsNetworkReplyContent &reply )
|
||||
: QgsNetworkLoggerGroup( QObject::tr( "Headers" ) )
|
||||
: QgsDevToolsModelGroup( QObject::tr( "Headers" ) )
|
||||
{
|
||||
const QList<QByteArray> headers = reply.rawHeaderList();
|
||||
for ( const QByteArray &header : headers )
|
||||
@ -621,7 +486,7 @@ QgsNetworkLoggerReplyHeadersGroup::QgsNetworkLoggerReplyHeadersGroup( const QgsN
|
||||
// QgsNetworkLoggerSslErrorGroup
|
||||
//
|
||||
QgsNetworkLoggerSslErrorGroup::QgsNetworkLoggerSslErrorGroup( const QList<QSslError> &errors )
|
||||
: QgsNetworkLoggerGroup( QObject::tr( "SSL errors" ) )
|
||||
: QgsDevToolsModelGroup( QObject::tr( "SSL errors" ) )
|
||||
{
|
||||
for ( const QSslError &error : errors )
|
||||
{
|
||||
@ -634,15 +499,5 @@ QVariant QgsNetworkLoggerSslErrorGroup::data( int role ) const
|
||||
if ( role == Qt::ForegroundRole )
|
||||
return QBrush( QColor( 180, 65, 210 ) );
|
||||
|
||||
return QgsNetworkLoggerGroup::data( role );
|
||||
}
|
||||
|
||||
QList<QAction *> QgsNetworkLoggerNode::actions( QObject * )
|
||||
{
|
||||
return QList< QAction * >();
|
||||
}
|
||||
|
||||
QVariant QgsNetworkLoggerNode::toVariant() const
|
||||
{
|
||||
return QVariant();
|
||||
return QgsDevToolsModelGroup::data( role );
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
#define QGSNETWORKLOGGERNODE_H
|
||||
|
||||
#include "qgsnetworkaccessmanager.h"
|
||||
#include "devtools/qgsdevtoolsmodelnode.h"
|
||||
#include <QElapsedTimer>
|
||||
#include <QVariant>
|
||||
#include <QColor>
|
||||
@ -24,160 +25,6 @@
|
||||
#include <deque>
|
||||
|
||||
class QAction;
|
||||
class QgsNetworkLoggerGroup;
|
||||
|
||||
/**
|
||||
* \ingroup app
|
||||
* \class QgsNetworkLoggerNode
|
||||
* \brief Base class for nodes in the network logger model.
|
||||
*
|
||||
* \since QGIS 3.14
|
||||
*/
|
||||
class QgsNetworkLoggerNode
|
||||
{
|
||||
public:
|
||||
|
||||
//! Custom node data roles
|
||||
enum Roles
|
||||
{
|
||||
RoleStatus = Qt::UserRole + 1, //!< Request status role
|
||||
RoleId, //!< Request ID role
|
||||
};
|
||||
|
||||
virtual ~QgsNetworkLoggerNode();
|
||||
|
||||
/**
|
||||
* Returns the node's parent node.
|
||||
*
|
||||
* If parent is NULLPTR, the node is a root node
|
||||
*/
|
||||
QgsNetworkLoggerGroup *parent() { return mParent; }
|
||||
|
||||
/**
|
||||
* Returns the node's data for the specified model \a role.
|
||||
*/
|
||||
virtual QVariant data( int role = Qt::DisplayRole ) const = 0;
|
||||
|
||||
/**
|
||||
* Returns the number of child nodes owned by this node.
|
||||
*/
|
||||
virtual int childCount() const = 0;
|
||||
|
||||
/**
|
||||
* Returns a list of actions relating to the node.
|
||||
*
|
||||
* The actions should be parented to \a parent.
|
||||
*/
|
||||
virtual QList< QAction * > actions( QObject *parent );
|
||||
|
||||
/**
|
||||
* Converts the node's contents to a variant.
|
||||
*/
|
||||
virtual QVariant toVariant() const;
|
||||
|
||||
protected:
|
||||
|
||||
QgsNetworkLoggerNode();
|
||||
|
||||
private:
|
||||
|
||||
QgsNetworkLoggerGroup *mParent = nullptr;
|
||||
friend class QgsNetworkLoggerGroup;
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup app
|
||||
* \class QgsNetworkLoggerGroup
|
||||
* \brief Base class for network logger model "group" nodes, which contain children of their own.
|
||||
*
|
||||
* \since QGIS 3.14
|
||||
*/
|
||||
class QgsNetworkLoggerGroup : public QgsNetworkLoggerNode
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Adds a \a child node to this node.
|
||||
*/
|
||||
void addChild( std::unique_ptr< QgsNetworkLoggerNode > child );
|
||||
|
||||
/**
|
||||
* Returns the index of the specified \a child node.
|
||||
*
|
||||
* \warning \a child must be a valid child of this node.
|
||||
*/
|
||||
int indexOf( QgsNetworkLoggerNode *child ) const;
|
||||
|
||||
/**
|
||||
* Returns the child at the specified \a index.
|
||||
*/
|
||||
QgsNetworkLoggerNode *childAt( int index );
|
||||
|
||||
/**
|
||||
* Clears the group, removing all its children.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
int childCount() const override final { return mChildren.size(); }
|
||||
QVariant data( int role = Qt::DisplayRole ) const override;
|
||||
QVariant toVariant() const override;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Constructor for a QgsNetworkLoggerGroup, with the specified \a title.
|
||||
*/
|
||||
QgsNetworkLoggerGroup( const QString &title );
|
||||
|
||||
/**
|
||||
* Adds a simple \a key: \a value node to the group.
|
||||
*/
|
||||
void addKeyValueNode( const QString &key, const QString &value, const QColor &color = QColor() );
|
||||
|
||||
private:
|
||||
|
||||
std::deque< std::unique_ptr< QgsNetworkLoggerNode > > mChildren;
|
||||
QString mGroupTitle;
|
||||
friend class QgsNetworkLoggerRootNode;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup app
|
||||
* \class QgsNetworkLoggerValueNode
|
||||
* \brief A "key: value" style node for the network logger model.
|
||||
*
|
||||
* \since QGIS 3.14
|
||||
*/
|
||||
class QgsNetworkLoggerValueNode : public QgsNetworkLoggerNode
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsNetworkLoggerValueNode, with the specified \a key (usually translated) and \a value.
|
||||
*/
|
||||
QgsNetworkLoggerValueNode( const QString &key, const QString &value, const QColor &color = QColor() );
|
||||
|
||||
/**
|
||||
* Returns the node's key.
|
||||
*/
|
||||
QString key() const { return mKey; }
|
||||
|
||||
/**
|
||||
* Returns the node's value.
|
||||
*/
|
||||
QString value() const { return mValue; }
|
||||
|
||||
QVariant data( int role = Qt::DisplayRole ) const override final;
|
||||
int childCount() const override final { return 0; }
|
||||
QList< QAction * > actions( QObject *parent ) override final;
|
||||
|
||||
private:
|
||||
|
||||
QString mKey;
|
||||
QString mValue;
|
||||
QColor mColor;
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup app
|
||||
@ -186,7 +33,7 @@ class QgsNetworkLoggerValueNode : public QgsNetworkLoggerNode
|
||||
*
|
||||
* \since QGIS 3.14
|
||||
*/
|
||||
class QgsNetworkLoggerRootNode final : public QgsNetworkLoggerGroup
|
||||
class QgsNetworkLoggerRootNode final : public QgsDevToolsModelGroup
|
||||
{
|
||||
public:
|
||||
|
||||
@ -231,7 +78,7 @@ class QgsNetworkLoggerSslErrorGroup;
|
||||
*
|
||||
* \since QGIS 3.14
|
||||
*/
|
||||
class QgsNetworkLoggerRequestGroup final : public QgsNetworkLoggerGroup
|
||||
class QgsNetworkLoggerRequestGroup final : public QgsDevToolsModelGroup
|
||||
{
|
||||
public:
|
||||
|
||||
@ -357,7 +204,7 @@ class QgsNetworkLoggerPostContentGroup;
|
||||
*
|
||||
* \since QGIS 3.14
|
||||
*/
|
||||
class QgsNetworkLoggerRequestDetailsGroup final : public QgsNetworkLoggerGroup
|
||||
class QgsNetworkLoggerRequestDetailsGroup final : public QgsDevToolsModelGroup
|
||||
{
|
||||
public:
|
||||
|
||||
@ -389,7 +236,7 @@ class QgsNetworkLoggerRequestDetailsGroup final : public QgsNetworkLoggerGroup
|
||||
*
|
||||
* \since QGIS 3.14
|
||||
*/
|
||||
class QgsNetworkLoggerRequestHeadersGroup final : public QgsNetworkLoggerGroup
|
||||
class QgsNetworkLoggerRequestHeadersGroup final : public QgsDevToolsModelGroup
|
||||
{
|
||||
public:
|
||||
|
||||
@ -415,7 +262,7 @@ class QgsNetworkLoggerRequestHeadersGroup final : public QgsNetworkLoggerGroup
|
||||
*
|
||||
* \since QGIS 3.14
|
||||
*/
|
||||
class QgsNetworkLoggerRequestQueryGroup final : public QgsNetworkLoggerGroup
|
||||
class QgsNetworkLoggerRequestQueryGroup final : public QgsDevToolsModelGroup
|
||||
{
|
||||
public:
|
||||
|
||||
@ -439,7 +286,7 @@ class QgsNetworkLoggerRequestQueryGroup final : public QgsNetworkLoggerGroup
|
||||
*
|
||||
* \since QGIS 3.14
|
||||
*/
|
||||
class QgsNetworkLoggerPostContentGroup final : public QgsNetworkLoggerGroup
|
||||
class QgsNetworkLoggerPostContentGroup final : public QgsDevToolsModelGroup
|
||||
{
|
||||
public:
|
||||
|
||||
@ -468,7 +315,7 @@ class QgsNetworkLoggerReplyHeadersGroup;
|
||||
*
|
||||
* \since QGIS 3.14
|
||||
*/
|
||||
class QgsNetworkLoggerReplyGroup final : public QgsNetworkLoggerGroup
|
||||
class QgsNetworkLoggerReplyGroup final : public QgsDevToolsModelGroup
|
||||
{
|
||||
public:
|
||||
|
||||
@ -499,7 +346,7 @@ class QgsNetworkLoggerReplyGroup final : public QgsNetworkLoggerGroup
|
||||
*
|
||||
* \since QGIS 3.14
|
||||
*/
|
||||
class QgsNetworkLoggerReplyHeadersGroup final : public QgsNetworkLoggerGroup
|
||||
class QgsNetworkLoggerReplyHeadersGroup final : public QgsDevToolsModelGroup
|
||||
{
|
||||
public:
|
||||
|
||||
@ -525,7 +372,7 @@ class QgsNetworkLoggerReplyHeadersGroup final : public QgsNetworkLoggerGroup
|
||||
*
|
||||
* \since QGIS 3.14
|
||||
*/
|
||||
class QgsNetworkLoggerSslErrorGroup final : public QgsNetworkLoggerGroup
|
||||
class QgsNetworkLoggerSslErrorGroup final : public QgsDevToolsModelGroup
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
173
src/app/devtools/qgsdevtoolsmodelnode.cpp
Normal file
173
src/app/devtools/qgsdevtoolsmodelnode.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
/***************************************************************************
|
||||
qgsdevtoolsmodelnode.cpp
|
||||
-------------------------
|
||||
begin : March 2020
|
||||
copyright : (C) 2020 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsdevtoolsmodelnode.h"
|
||||
#include "qgis.h"
|
||||
#include "qgsjsonutils.h"
|
||||
#include <QUrlQuery>
|
||||
#include <QColor>
|
||||
#include <QBrush>
|
||||
#include <QFont>
|
||||
#include <QAction>
|
||||
#include <QDesktopServices>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
//
|
||||
// QgsDevToolsModelNode
|
||||
//
|
||||
|
||||
QgsDevToolsModelNode::QgsDevToolsModelNode() = default;
|
||||
QgsDevToolsModelNode::~QgsDevToolsModelNode() = default;
|
||||
|
||||
QVariant QgsDevToolsModelNode::toVariant() const
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QList<QAction *> QgsDevToolsModelNode::actions( QObject * )
|
||||
{
|
||||
return QList< QAction * >();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsDevToolsModelGroup
|
||||
//
|
||||
|
||||
QgsDevToolsModelGroup::QgsDevToolsModelGroup( const QString &title )
|
||||
: mGroupTitle( title )
|
||||
{
|
||||
}
|
||||
|
||||
void QgsDevToolsModelGroup::addChild( std::unique_ptr<QgsDevToolsModelNode> child )
|
||||
{
|
||||
if ( !child )
|
||||
return;
|
||||
|
||||
Q_ASSERT( !child->mParent );
|
||||
child->mParent = this;
|
||||
|
||||
mChildren.emplace_back( std::move( child ) );
|
||||
}
|
||||
|
||||
int QgsDevToolsModelGroup::indexOf( QgsDevToolsModelNode *child ) const
|
||||
{
|
||||
Q_ASSERT( child->mParent == this );
|
||||
auto it = std::find_if( mChildren.begin(), mChildren.end(), [&]( const std::unique_ptr<QgsDevToolsModelNode> &p )
|
||||
{
|
||||
return p.get() == child;
|
||||
} );
|
||||
if ( it != mChildren.end() )
|
||||
return std::distance( mChildren.begin(), it );
|
||||
return -1;
|
||||
}
|
||||
|
||||
QgsDevToolsModelNode *QgsDevToolsModelGroup::childAt( int index )
|
||||
{
|
||||
Q_ASSERT( static_cast< std::size_t >( index ) < mChildren.size() );
|
||||
return mChildren[ index ].get();
|
||||
}
|
||||
|
||||
void QgsDevToolsModelGroup::clear()
|
||||
{
|
||||
mChildren.clear();
|
||||
}
|
||||
|
||||
QVariant QgsDevToolsModelGroup::data( int role ) const
|
||||
{
|
||||
switch ( role )
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
return mGroupTitle;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant QgsDevToolsModelGroup::toVariant() const
|
||||
{
|
||||
QVariantMap res;
|
||||
for ( const std::unique_ptr< QgsDevToolsModelNode > &child : mChildren )
|
||||
{
|
||||
if ( const QgsDevToolsModelValueNode *valueNode = dynamic_cast< const QgsDevToolsModelValueNode *>( child.get() ) )
|
||||
{
|
||||
res.insert( valueNode->key(), valueNode->value() );
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsDevToolsModelValueNode
|
||||
//
|
||||
QgsDevToolsModelValueNode::QgsDevToolsModelValueNode( const QString &key, const QString &value, const QColor &color )
|
||||
: mKey( key )
|
||||
, mValue( value )
|
||||
, mColor( color )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QVariant QgsDevToolsModelValueNode::data( int role ) const
|
||||
{
|
||||
switch ( role )
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
case Qt::ToolTipRole:
|
||||
{
|
||||
return QStringLiteral( "%1: %2" ).arg( mKey.leftJustified( 30, ' ' ), mValue );
|
||||
}
|
||||
|
||||
case Qt::ForegroundRole:
|
||||
{
|
||||
if ( mColor.isValid() )
|
||||
return QBrush( mColor );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QList<QAction *> QgsDevToolsModelValueNode::actions( QObject *parent )
|
||||
{
|
||||
QList< QAction * > res;
|
||||
|
||||
QAction *copyAction = new QAction( QObject::tr( "Copy" ), parent );
|
||||
QObject::connect( copyAction, &QAction::triggered, copyAction, [ = ]
|
||||
{
|
||||
QApplication::clipboard()->setText( QStringLiteral( "%1: %2" ).arg( mKey, mValue ) );
|
||||
} );
|
||||
|
||||
res << copyAction;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//
|
||||
// QgsDevToolsModelGroup
|
||||
//
|
||||
|
||||
void QgsDevToolsModelGroup::addKeyValueNode( const QString &key, const QString &value, const QColor &color )
|
||||
{
|
||||
addChild( std::make_unique< QgsDevToolsModelValueNode >( key, value, color ) );
|
||||
}
|
||||
|
||||
176
src/app/devtools/qgsdevtoolsmodelnode.h
Normal file
176
src/app/devtools/qgsdevtoolsmodelnode.h
Normal file
@ -0,0 +1,176 @@
|
||||
/***************************************************************************
|
||||
qgsdevtoolsmodelnode.h
|
||||
-------------------------
|
||||
begin : March 2020
|
||||
copyright : (C) 2020 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef QGSDEVTOOLSMODELNODE_H
|
||||
#define QGSDEVTOOLSMODELNODE_H
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <QVariant>
|
||||
#include <QColor>
|
||||
#include <QUrl>
|
||||
#include <memory>
|
||||
#include <deque>
|
||||
|
||||
class QAction;
|
||||
class QgsDevToolsModelGroup;
|
||||
|
||||
/**
|
||||
* \ingroup app
|
||||
* \class QgsDevToolsModelNode
|
||||
* \brief Base class for nodes in a dev tools model.
|
||||
*/
|
||||
class QgsDevToolsModelNode
|
||||
{
|
||||
public:
|
||||
|
||||
//! Custom node data roles
|
||||
enum Roles
|
||||
{
|
||||
RoleStatus = Qt::UserRole + 1, //!< Request status role
|
||||
RoleId, //!< Request ID role
|
||||
};
|
||||
|
||||
virtual ~QgsDevToolsModelNode();
|
||||
|
||||
/**
|
||||
* Returns the node's parent node.
|
||||
*
|
||||
* If parent is NULLPTR, the node is a root node
|
||||
*/
|
||||
QgsDevToolsModelGroup *parent() { return mParent; }
|
||||
|
||||
/**
|
||||
* Returns the node's data for the specified model \a role.
|
||||
*/
|
||||
virtual QVariant data( int role = Qt::DisplayRole ) const = 0;
|
||||
|
||||
/**
|
||||
* Returns the number of child nodes owned by this node.
|
||||
*/
|
||||
virtual int childCount() const = 0;
|
||||
|
||||
/**
|
||||
* Returns a list of actions relating to the node.
|
||||
*
|
||||
* The actions should be parented to \a parent.
|
||||
*/
|
||||
virtual QList< QAction * > actions( QObject *parent );
|
||||
|
||||
/**
|
||||
* Converts the node's contents to a variant.
|
||||
*/
|
||||
virtual QVariant toVariant() const;
|
||||
|
||||
protected:
|
||||
|
||||
QgsDevToolsModelNode();
|
||||
|
||||
private:
|
||||
|
||||
QgsDevToolsModelGroup *mParent = nullptr;
|
||||
friend class QgsDevToolsModelGroup;
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup app
|
||||
* \class QgsDevToolsModelGroup
|
||||
* \brief Base class for dev tools model "group" nodes, which contain children of their own.
|
||||
*/
|
||||
class QgsDevToolsModelGroup : public QgsDevToolsModelNode
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Adds a \a child node to this node.
|
||||
*/
|
||||
void addChild( std::unique_ptr< QgsDevToolsModelNode > child );
|
||||
|
||||
/**
|
||||
* Returns the index of the specified \a child node.
|
||||
*
|
||||
* \warning \a child must be a valid child of this node.
|
||||
*/
|
||||
int indexOf( QgsDevToolsModelNode *child ) const;
|
||||
|
||||
/**
|
||||
* Returns the child at the specified \a index.
|
||||
*/
|
||||
QgsDevToolsModelNode *childAt( int index );
|
||||
|
||||
/**
|
||||
* Clears the group, removing all its children.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
int childCount() const override final { return mChildren.size(); }
|
||||
QVariant data( int role = Qt::DisplayRole ) const override;
|
||||
QVariant toVariant() const override;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Constructor for a QgsDevToolsModelGroup, with the specified \a title.
|
||||
*/
|
||||
QgsDevToolsModelGroup( const QString &title );
|
||||
|
||||
/**
|
||||
* Adds a simple \a key: \a value node to the group.
|
||||
*/
|
||||
void addKeyValueNode( const QString &key, const QString &value, const QColor &color = QColor() );
|
||||
|
||||
protected:
|
||||
std::deque< std::unique_ptr< QgsDevToolsModelNode > > mChildren;
|
||||
|
||||
private:
|
||||
|
||||
QString mGroupTitle;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup app
|
||||
* \class QgsDevToolsModelValueNode
|
||||
* \brief A "key: value" style node for a dev tools model.
|
||||
*/
|
||||
class QgsDevToolsModelValueNode : public QgsDevToolsModelNode
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsDevToolsModelValueNode, with the specified \a key (usually translated) and \a value.
|
||||
*/
|
||||
QgsDevToolsModelValueNode( const QString &key, const QString &value, const QColor &color = QColor() );
|
||||
|
||||
/**
|
||||
* Returns the node's key.
|
||||
*/
|
||||
QString key() const { return mKey; }
|
||||
|
||||
/**
|
||||
* Returns the node's value.
|
||||
*/
|
||||
QString value() const { return mValue; }
|
||||
|
||||
QVariant data( int role = Qt::DisplayRole ) const override final;
|
||||
int childCount() const override final { return 0; }
|
||||
QList< QAction * > actions( QObject *parent ) override final;
|
||||
|
||||
private:
|
||||
|
||||
QString mKey;
|
||||
QString mValue;
|
||||
QColor mColor;
|
||||
};
|
||||
|
||||
#endif // QGSDEVTOOLSMODELNODE_H
|
||||
262
src/app/devtools/querylogger/qgsappquerylogger.cpp
Normal file
262
src/app/devtools/querylogger/qgsappquerylogger.cpp
Normal file
@ -0,0 +1,262 @@
|
||||
/***************************************************************************
|
||||
qgsappquerylogger.cpp
|
||||
-------------------------
|
||||
begin : October 2021
|
||||
copyright : (C) 2021 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsappquerylogger.h"
|
||||
#include "qgsdatabasequeryloggernode.h"
|
||||
#include "qgsapplication.h"
|
||||
#include "devtools/qgsdevtoolsmodelnode.h"
|
||||
#include "qgssettings.h"
|
||||
#include "qgis.h"
|
||||
#include <QThread>
|
||||
#include <QApplication>
|
||||
#include <QUrlQuery>
|
||||
|
||||
QgsAppQueryLogger::QgsAppQueryLogger( QObject *parent )
|
||||
: QAbstractItemModel( parent )
|
||||
, mRootNode( std::make_unique< QgsDatabaseQueryLoggerRootNode >() )
|
||||
{
|
||||
// logger must be created on the main thread
|
||||
Q_ASSERT( QThread::currentThread() == QApplication::instance()->thread() );
|
||||
|
||||
connect( QgsApplication::databaseQueryLog(), &QgsDatabaseQueryLog::queryStarted, this, &QgsAppQueryLogger::queryLogged );
|
||||
connect( QgsApplication::databaseQueryLog(), &QgsDatabaseQueryLog::queryFinished, this, &QgsAppQueryLogger::queryFinished );
|
||||
}
|
||||
|
||||
QgsAppQueryLogger::~QgsAppQueryLogger() = default;
|
||||
|
||||
void QgsAppQueryLogger::clear()
|
||||
{
|
||||
beginResetModel();
|
||||
mQueryGroups.clear();
|
||||
mRootNode->clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void QgsAppQueryLogger::queryLogged( const QgsDatabaseQueryLogEntry &query )
|
||||
{
|
||||
const int childCount = mRootNode->childCount();
|
||||
|
||||
beginInsertRows( QModelIndex(), childCount, childCount );
|
||||
|
||||
std::unique_ptr< QgsDatabaseQueryLoggerQueryGroup > group = std::make_unique< QgsDatabaseQueryLoggerQueryGroup >( query );
|
||||
mQueryGroups.insert( query.queryId, group.get() );
|
||||
mRootNode->addChild( std::move( group ) );
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void QgsAppQueryLogger::queryFinished( const QgsDatabaseQueryLogEntry &query )
|
||||
{
|
||||
QgsDatabaseQueryLoggerQueryGroup *queryGroup = mQueryGroups.value( query.queryId );
|
||||
if ( !queryGroup )
|
||||
return;
|
||||
|
||||
// find the row: the position of the request in the rootNode
|
||||
const QModelIndex requestIndex = node2index( queryGroup );
|
||||
if ( !requestIndex.isValid() )
|
||||
return;
|
||||
|
||||
if ( query.query != queryGroup->sql() )
|
||||
{
|
||||
queryGroup->setSql( query.query );
|
||||
}
|
||||
|
||||
// Calculate the number of children: if error or not fetched rows 1 row is added else 2 rows are added
|
||||
beginInsertRows( requestIndex, queryGroup->childCount(), queryGroup->childCount() + ( query.fetchedRows != -1 ? 1 : 0 ) );
|
||||
queryGroup->setFinished( query );
|
||||
endInsertRows();
|
||||
|
||||
emit dataChanged( requestIndex, requestIndex );
|
||||
}
|
||||
|
||||
QgsDevToolsModelNode *QgsAppQueryLogger::index2node( const QModelIndex &index ) const
|
||||
{
|
||||
if ( !index.isValid() )
|
||||
return mRootNode.get();
|
||||
|
||||
return reinterpret_cast<QgsDevToolsModelNode *>( index.internalPointer() );
|
||||
}
|
||||
|
||||
QList<QAction *> QgsAppQueryLogger::actions( const QModelIndex &index, QObject *parent )
|
||||
{
|
||||
QgsDevToolsModelNode *node = index2node( index );
|
||||
if ( !node )
|
||||
return QList< QAction * >();
|
||||
|
||||
return node->actions( parent );
|
||||
}
|
||||
|
||||
QModelIndex QgsAppQueryLogger::node2index( QgsDevToolsModelNode *node ) const
|
||||
{
|
||||
if ( !node || !node->parent() )
|
||||
return QModelIndex(); // this is the only root item -> invalid index
|
||||
|
||||
QModelIndex parentIndex = node2index( node->parent() );
|
||||
|
||||
int row = node->parent()->indexOf( node );
|
||||
Q_ASSERT( row >= 0 );
|
||||
return index( row, 0, parentIndex );
|
||||
}
|
||||
|
||||
QModelIndex QgsAppQueryLogger::indexOfParentLayerTreeNode( QgsDevToolsModelNode *parentNode ) const
|
||||
{
|
||||
Q_ASSERT( parentNode );
|
||||
|
||||
QgsDevToolsModelGroup *grandParentNode = parentNode->parent();
|
||||
if ( !grandParentNode )
|
||||
return QModelIndex(); // root node -> invalid index
|
||||
|
||||
int row = grandParentNode->indexOf( parentNode );
|
||||
Q_ASSERT( row >= 0 );
|
||||
|
||||
return createIndex( row, 0, parentNode );
|
||||
}
|
||||
|
||||
void QgsAppQueryLogger::removeRequestRows( const QList<int> &rows )
|
||||
{
|
||||
QList< int > res = rows;
|
||||
std::sort( res.begin(), res.end(), std::greater< int >() );
|
||||
|
||||
for ( int row : std::as_const( res ) )
|
||||
{
|
||||
int popId = data( index( row, 0, QModelIndex() ), QgsDevToolsModelNode::RoleId ).toInt();
|
||||
mQueryGroups.remove( popId );
|
||||
|
||||
beginRemoveRows( QModelIndex(), row, row );
|
||||
mRootNode->removeRow( row );
|
||||
endRemoveRows();
|
||||
}
|
||||
}
|
||||
|
||||
QgsDatabaseQueryLoggerRootNode *QgsAppQueryLogger::rootGroup()
|
||||
{
|
||||
return mRootNode.get();
|
||||
}
|
||||
|
||||
int QgsAppQueryLogger::rowCount( const QModelIndex &parent ) const
|
||||
{
|
||||
QgsDevToolsModelNode *n = index2node( parent );
|
||||
if ( !n )
|
||||
return 0;
|
||||
|
||||
return n->childCount();
|
||||
}
|
||||
|
||||
int QgsAppQueryLogger::columnCount( const QModelIndex &parent ) const
|
||||
{
|
||||
Q_UNUSED( parent )
|
||||
return 1;
|
||||
}
|
||||
|
||||
QModelIndex QgsAppQueryLogger::index( int row, int column, const QModelIndex &parent ) const
|
||||
{
|
||||
if ( column < 0 || column >= columnCount( parent ) ||
|
||||
row < 0 || row >= rowCount( parent ) )
|
||||
return QModelIndex();
|
||||
|
||||
QgsDevToolsModelGroup *n = dynamic_cast< QgsDevToolsModelGroup * >( index2node( parent ) );
|
||||
if ( !n )
|
||||
return QModelIndex(); // have no children
|
||||
|
||||
return createIndex( row, column, n->childAt( row ) );
|
||||
}
|
||||
|
||||
QModelIndex QgsAppQueryLogger::parent( const QModelIndex &child ) const
|
||||
{
|
||||
if ( !child.isValid() )
|
||||
return QModelIndex();
|
||||
|
||||
if ( QgsDevToolsModelNode *n = index2node( child ) )
|
||||
{
|
||||
return indexOfParentLayerTreeNode( n->parent() ); // must not be null
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_ASSERT( false );
|
||||
return QModelIndex();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant QgsAppQueryLogger::data( const QModelIndex &index, int role ) const
|
||||
{
|
||||
if ( !index.isValid() || index.column() > 1 )
|
||||
return QVariant();
|
||||
|
||||
QgsDevToolsModelNode *node = index2node( index );
|
||||
if ( !node )
|
||||
return QVariant();
|
||||
|
||||
return node->data( role );
|
||||
}
|
||||
|
||||
Qt::ItemFlags QgsAppQueryLogger::flags( const QModelIndex &index ) const
|
||||
{
|
||||
if ( !index.isValid() )
|
||||
{
|
||||
Qt::ItemFlags rootFlags = Qt::ItemFlags();
|
||||
return rootFlags;
|
||||
}
|
||||
|
||||
Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
return f;
|
||||
}
|
||||
|
||||
QVariant QgsAppQueryLogger::headerData( int section, Qt::Orientation orientation, int role ) const
|
||||
{
|
||||
if ( section == 0 && orientation == Qt::Horizontal && role == Qt::DisplayRole )
|
||||
return tr( "Requests" );
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsDatabaseQueryLoggerProxyModel
|
||||
//
|
||||
|
||||
QgsDatabaseQueryLoggerProxyModel::QgsDatabaseQueryLoggerProxyModel( QgsAppQueryLogger *logger, QObject *parent )
|
||||
: QSortFilterProxyModel( parent )
|
||||
, mLogger( logger )
|
||||
{
|
||||
setSourceModel( mLogger );
|
||||
}
|
||||
|
||||
void QgsDatabaseQueryLoggerProxyModel::setFilterString( const QString &string )
|
||||
{
|
||||
mFilterString = string;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
bool QgsDatabaseQueryLoggerProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const
|
||||
{
|
||||
if ( ! mFilterString.isEmpty() )
|
||||
{
|
||||
QgsDevToolsModelNode *node = mLogger->index2node( mLogger->index( source_row, 0, source_parent ) );
|
||||
if ( QgsDatabaseQueryLoggerQueryGroup *request = dynamic_cast< QgsDatabaseQueryLoggerQueryGroup * >( node ) )
|
||||
{
|
||||
if ( request->data().toString().contains( mFilterString, Qt::CaseInsensitive ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
for ( int i = 0; i < request->childCount(); i++ )
|
||||
{
|
||||
if ( QgsDevToolsModelValueNode *valueNode = static_cast<QgsDevToolsModelValueNode *>( request->childAt( i ) ); valueNode->value().contains( mFilterString, Qt::CaseInsensitive ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
137
src/app/devtools/querylogger/qgsappquerylogger.h
Normal file
137
src/app/devtools/querylogger/qgsappquerylogger.h
Normal file
@ -0,0 +1,137 @@
|
||||
/***************************************************************************
|
||||
qgsappquerylogger.h
|
||||
-------------------------
|
||||
begin : October 2021
|
||||
copyright : (C) 2021 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef QGSAPPQUERYLOGGER_H
|
||||
#define QGSAPPQUERYLOGGER_H
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QElapsedTimer>
|
||||
#include "qgsdbquerylog.h"
|
||||
#include <memory>
|
||||
|
||||
class QgsDevToolsModelNode;
|
||||
class QgsDevToolsModelGroup;
|
||||
class QgsDatabaseQueryLoggerRootNode;
|
||||
class QgsDatabaseQueryLoggerQueryGroup;
|
||||
class QAction;
|
||||
|
||||
/**
|
||||
* \ingroup app
|
||||
* \class QgsAppQueryLogger
|
||||
* \brief Logs sql queries, converting them
|
||||
* to a QAbstractItemModel representing the request and response details.
|
||||
*/
|
||||
class QgsAppQueryLogger : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsAppQueryLogger, logging requests from the specified \a manager.
|
||||
*
|
||||
* \warning QgsAppQueryLogger must be created on the main thread.
|
||||
*/
|
||||
QgsAppQueryLogger( QObject *parent );
|
||||
~QgsAppQueryLogger() override;
|
||||
|
||||
// Implementation of virtual functions from QAbstractItemModel
|
||||
|
||||
int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
|
||||
int columnCount( const QModelIndex &parent = QModelIndex() ) const override;
|
||||
QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const override;
|
||||
QModelIndex parent( const QModelIndex &child ) const override;
|
||||
QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override;
|
||||
Qt::ItemFlags flags( const QModelIndex &index ) const override;
|
||||
QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override;
|
||||
|
||||
/**
|
||||
* Returns node for given index. Returns root node for invalid index.
|
||||
*/
|
||||
QgsDevToolsModelNode *index2node( const QModelIndex &index ) const;
|
||||
|
||||
/**
|
||||
* Returns a list of actions corresponding to the item at the specified \a index.
|
||||
*
|
||||
* The actions should be parented to \a parent.
|
||||
*/
|
||||
QList< QAction * > actions( const QModelIndex &index, QObject *parent );
|
||||
|
||||
/**
|
||||
* Removes a list of request \a rows from the log.
|
||||
*/
|
||||
void removeRequestRows( const QList< int > &rows );
|
||||
|
||||
/**
|
||||
* Returns the root node of the log.
|
||||
*/
|
||||
QgsDatabaseQueryLoggerRootNode *rootGroup();
|
||||
|
||||
static constexpr int MAX_LOGGED_REQUESTS = 1000;
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* Clears all logged entries.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
private slots:
|
||||
void queryLogged( const QgsDatabaseQueryLogEntry &query );
|
||||
void queryFinished( const QgsDatabaseQueryLogEntry &query );
|
||||
|
||||
private:
|
||||
|
||||
//! Returns index for a given node
|
||||
QModelIndex node2index( QgsDevToolsModelNode *node ) const;
|
||||
QModelIndex indexOfParentLayerTreeNode( QgsDevToolsModelNode *parentNode ) const;
|
||||
|
||||
std::unique_ptr< QgsDatabaseQueryLoggerRootNode > mRootNode;
|
||||
|
||||
QHash< int, QgsDatabaseQueryLoggerQueryGroup * > mQueryGroups;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup app
|
||||
* \class QgsDatabaseQueryLoggerProxyModel
|
||||
* \brief A proxy model for filtering QgsNetworkLogger models by url string subsets
|
||||
* or request status.
|
||||
*/
|
||||
class QgsDatabaseQueryLoggerProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsDatabaseQueryLoggerProxyModel, filtering the specified network \a logger.
|
||||
*/
|
||||
QgsDatabaseQueryLoggerProxyModel( QgsAppQueryLogger *logger, QObject *parent );
|
||||
|
||||
/**
|
||||
* Sets a filter \a string to apply to request queries.
|
||||
*/
|
||||
void setFilterString( const QString &string );
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const override;
|
||||
|
||||
private:
|
||||
|
||||
QgsAppQueryLogger *mLogger = nullptr;
|
||||
|
||||
QString mFilterString;
|
||||
};
|
||||
|
||||
#endif // QGSAPPQUERYLOGGER_H
|
||||
251
src/app/devtools/querylogger/qgsdatabasequeryloggernode.cpp
Normal file
251
src/app/devtools/querylogger/qgsdatabasequeryloggernode.cpp
Normal file
@ -0,0 +1,251 @@
|
||||
/***************************************************************************
|
||||
qgsdatabasequeryloggernode.cpp
|
||||
-------------------------
|
||||
begin : October 2021
|
||||
copyright : (C) 2021 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsdatabasequeryloggernode.h"
|
||||
#include "qgis.h"
|
||||
#include "qgsjsonutils.h"
|
||||
#include <QUrlQuery>
|
||||
#include <QColor>
|
||||
#include <QBrush>
|
||||
#include <QFont>
|
||||
#include <QAction>
|
||||
#include <QDesktopServices>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
|
||||
//
|
||||
// QgsDatabaseQueryLoggerRootNode
|
||||
//
|
||||
|
||||
QgsDatabaseQueryLoggerRootNode::QgsDatabaseQueryLoggerRootNode()
|
||||
: QgsDevToolsModelGroup( QString() )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QVariant QgsDatabaseQueryLoggerRootNode::data( int ) const
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void QgsDatabaseQueryLoggerRootNode::removeRow( int row )
|
||||
{
|
||||
mChildren.erase( mChildren.begin() + row );
|
||||
}
|
||||
|
||||
QVariant QgsDatabaseQueryLoggerRootNode::toVariant() const
|
||||
{
|
||||
QVariantList res;
|
||||
for ( const std::unique_ptr< QgsDevToolsModelNode > &child : mChildren )
|
||||
res << child->toVariant();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsDatabaseQueryLoggerQueryGroup
|
||||
//
|
||||
|
||||
QgsDatabaseQueryLoggerQueryGroup::QgsDatabaseQueryLoggerQueryGroup( const QgsDatabaseQueryLogEntry &query )
|
||||
: QgsDevToolsModelGroup( QString() )
|
||||
, mSql( query.query )
|
||||
, mQueryId( query.queryId )
|
||||
{
|
||||
#if 0
|
||||
std::unique_ptr< QgsNetworkLoggerRequestDetailsGroup > detailsGroup = std::make_unique< QgsNetworkLoggerRequestDetailsGroup >( request );
|
||||
mDetailsGroup = detailsGroup.get();
|
||||
addChild( std::move( detailsGroup ) );
|
||||
#endif
|
||||
|
||||
addKeyValueNode( QObject::tr( "Provider" ), query.provider );
|
||||
addKeyValueNode( QObject::tr( "URI" ), query.uri );
|
||||
addKeyValueNode( QObject::tr( "Started at" ), QDateTime::fromMSecsSinceEpoch( query.startedTime ).toString( Qt::ISODateWithMs ) );
|
||||
#if 0
|
||||
addKeyValueNode( QObject::tr( "Thread" ), query.originatingThreadId() );
|
||||
#endif
|
||||
addKeyValueNode( QObject::tr( "Initiator" ), query.initiatorClass.isEmpty() ? QObject::tr( "unknown" ) : query.initiatorClass );
|
||||
if ( !query.origin.isEmpty() )
|
||||
addKeyValueNode( QObject::tr( "Location" ), query.origin );
|
||||
|
||||
}
|
||||
|
||||
QVariant QgsDatabaseQueryLoggerQueryGroup::data( int role ) const
|
||||
{
|
||||
switch ( role )
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
return QStringLiteral( "%1 %2" ).arg( QString::number( mQueryId ),
|
||||
mSql );
|
||||
|
||||
case Qt::ToolTipRole:
|
||||
{
|
||||
// Show no more than 255 characters
|
||||
return mSql.length() > 255 ? mSql.mid( 0, 255 ).append( QStringLiteral( "…" ) ) : mSql;
|
||||
|
||||
#if 0
|
||||
QString bytes = QObject::tr( "unknown" );
|
||||
if ( mBytesTotal != 0 )
|
||||
{
|
||||
if ( mBytesReceived > 0 && mBytesReceived < mBytesTotal )
|
||||
bytes = QStringLiteral( "%1/%2" ).arg( QString::number( mBytesReceived ), QString::number( mBytesTotal ) );
|
||||
else if ( mBytesReceived > 0 && mBytesReceived == mBytesTotal )
|
||||
bytes = QString::number( mBytesTotal );
|
||||
}
|
||||
// ?? adding <br/> instead of \n after (very long) url seems to break url up
|
||||
// COMPLETE, Status: 200 - text/xml; charset=utf-8 - 2334 bytes - 657 milliseconds
|
||||
return QStringLiteral( "%1<br/>%2 - Status: %3 - %4 - %5 bytes - %6 msec - %7 replies" )
|
||||
.arg( mUrl.url(),
|
||||
statusToString( mStatus ),
|
||||
QString::number( mHttpStatus ),
|
||||
mContentType,
|
||||
bytes,
|
||||
mStatus == Status::Pending ? QString::number( mTimer.elapsed() / 1000 ) : QString::number( mTotalTime ),
|
||||
QString::number( mReplies ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
case RoleStatus:
|
||||
return static_cast< int >( mStatus );
|
||||
|
||||
case RoleId:
|
||||
return mQueryId;
|
||||
|
||||
case Qt::ForegroundRole:
|
||||
{
|
||||
switch ( mStatus )
|
||||
{
|
||||
case QgsDatabaseQueryLoggerQueryGroup::Status::Pending:
|
||||
case QgsDatabaseQueryLoggerQueryGroup::Status::Canceled:
|
||||
return QBrush( QColor( 0, 0, 0, 100 ) );
|
||||
case QgsDatabaseQueryLoggerQueryGroup::Status::Error:
|
||||
return QBrush( QColor( 235, 10, 10 ) );
|
||||
case QgsDatabaseQueryLoggerQueryGroup::Status::TimeOut:
|
||||
return QBrush( QColor( 235, 10, 10 ) );
|
||||
case QgsDatabaseQueryLoggerQueryGroup::Status::Complete:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::FontRole:
|
||||
{
|
||||
if ( mStatus == Status::Canceled )
|
||||
{
|
||||
QFont f;
|
||||
f.setStrikeOut( true );
|
||||
return f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant( );
|
||||
}
|
||||
|
||||
QList<QAction *> QgsDatabaseQueryLoggerQueryGroup::actions( QObject *parent )
|
||||
{
|
||||
QList< QAction * > res;
|
||||
|
||||
QAction *copyUrlAction = new QAction( QObject::tr( "Copy SQL" ), parent );
|
||||
QObject::connect( copyUrlAction, &QAction::triggered, copyUrlAction, [ = ]
|
||||
{
|
||||
QApplication::clipboard()->setText( mSql );
|
||||
} );
|
||||
res << copyUrlAction;
|
||||
|
||||
QAction *copyJsonAction = new QAction( QObject::tr( "Copy as JSON" ), parent );
|
||||
QObject::connect( copyJsonAction, &QAction::triggered, copyJsonAction, [ = ]
|
||||
{
|
||||
const QVariant value = toVariant();
|
||||
const QString json = QString::fromStdString( QgsJsonUtils::jsonFromVariant( value ).dump( 2 ) );
|
||||
QApplication::clipboard()->setText( json );
|
||||
|
||||
} );
|
||||
res << copyJsonAction;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
QVariant QgsDatabaseQueryLoggerQueryGroup::toVariant() const
|
||||
{
|
||||
QVariantMap res;
|
||||
res.insert( QStringLiteral( "SQL" ), mSql );
|
||||
|
||||
for ( const auto &child : std::as_const( mChildren ) )
|
||||
{
|
||||
if ( const QgsDevToolsModelValueNode *valueNode = dynamic_cast< const QgsDevToolsModelValueNode *>( child.get() ) )
|
||||
{
|
||||
res.insert( valueNode->key(), valueNode->value() );
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void QgsDatabaseQueryLoggerQueryGroup::setFinished( const QgsDatabaseQueryLogEntry &query )
|
||||
{
|
||||
if ( query.error.isEmpty() )
|
||||
{
|
||||
mStatus = query.canceled ? Status::Canceled : Status::Complete;
|
||||
addKeyValueNode( QObject::tr( "Total time (ms)" ), QLocale().toString( query.finishedTime - query.startedTime ) );
|
||||
if ( query.fetchedRows != -1 )
|
||||
{
|
||||
addKeyValueNode( QObject::tr( "Row count" ), QLocale().toString( query.fetchedRows ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mStatus = Status::Error;
|
||||
addKeyValueNode( QObject::tr( "Error" ), query.error );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsDatabaseQueryLoggerQueryGroup::setStatus( QgsDatabaseQueryLoggerQueryGroup::Status status )
|
||||
{
|
||||
mStatus = status;
|
||||
}
|
||||
|
||||
QString QgsDatabaseQueryLoggerQueryGroup::statusToString( QgsDatabaseQueryLoggerQueryGroup::Status status )
|
||||
{
|
||||
switch ( status )
|
||||
{
|
||||
case QgsDatabaseQueryLoggerQueryGroup::Status::Pending:
|
||||
return QObject::tr( "Pending" );
|
||||
case QgsDatabaseQueryLoggerQueryGroup::Status::Complete:
|
||||
return QObject::tr( "Complete" );
|
||||
case QgsDatabaseQueryLoggerQueryGroup::Status::Error:
|
||||
return QObject::tr( "Error" );
|
||||
case QgsDatabaseQueryLoggerQueryGroup::Status::TimeOut:
|
||||
return QObject::tr( "Timeout" );
|
||||
case QgsDatabaseQueryLoggerQueryGroup::Status::Canceled:
|
||||
return QObject::tr( "Canceled" );
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void QgsDatabaseQueryLoggerQueryGroup::setSql( const QString &sql )
|
||||
{
|
||||
mSql = sql;
|
||||
}
|
||||
|
||||
const QString &QgsDatabaseQueryLoggerQueryGroup::sql() const
|
||||
{
|
||||
return mSql;
|
||||
}
|
||||
|
||||
|
||||
125
src/app/devtools/querylogger/qgsdatabasequeryloggernode.h
Normal file
125
src/app/devtools/querylogger/qgsdatabasequeryloggernode.h
Normal file
@ -0,0 +1,125 @@
|
||||
/***************************************************************************
|
||||
qgsdatabasequeryloggernode.h
|
||||
-------------------------
|
||||
begin : October 2021
|
||||
copyright : (C) 2021 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef QGSDBQUERYLOGGERNODE_H
|
||||
#define QGSDBQUERYLOGGERNODE_H
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <QVariant>
|
||||
#include <QColor>
|
||||
#include <QUrl>
|
||||
#include <memory>
|
||||
#include <deque>
|
||||
#include "devtools/qgsdevtoolsmodelnode.h"
|
||||
#include "qgsdbquerylog.h"
|
||||
|
||||
class QAction;
|
||||
|
||||
/**
|
||||
* \ingroup app
|
||||
* \class QgsDatabaseQueryLoggerRootNode
|
||||
* \brief Root node for the query logger model.
|
||||
*/
|
||||
class QgsDatabaseQueryLoggerRootNode final : public QgsDevToolsModelGroup
|
||||
{
|
||||
public:
|
||||
|
||||
QgsDatabaseQueryLoggerRootNode();
|
||||
QVariant data( int role = Qt::DisplayRole ) const override final;
|
||||
|
||||
/**
|
||||
* Removes a \a row from the root group.
|
||||
*/
|
||||
void removeRow( int row );
|
||||
|
||||
QVariant toVariant() const override;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup app
|
||||
* \class QgsDatabaseQueryLoggerQueryGroup
|
||||
* \brief Parent group for all database queries, showing the query id, SQL
|
||||
* and containing child groups with detailed query and result information.
|
||||
*
|
||||
* Visually, a QgsDatabaseQueryLoggerQueryGroup is structured by:
|
||||
*
|
||||
* |__ QgsDatabaseQueryLoggerQueryGroup (showing sql, uri,...)
|
||||
* |__ QgsDevToolsModelValueNode(key-value pairs with info)
|
||||
* ...
|
||||
*/
|
||||
class QgsDatabaseQueryLoggerQueryGroup final : public QgsDevToolsModelGroup
|
||||
{
|
||||
public:
|
||||
|
||||
//! Query status
|
||||
enum class Status
|
||||
{
|
||||
Pending, //!< Query underway
|
||||
Complete, //!< Query was successfully completed
|
||||
Error, //!< Query encountered an error
|
||||
TimeOut, //!< Query timed out
|
||||
Canceled, //!< Query was manually canceled
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor for QgsDatabaseQueryLoggerQueryGroup, populated from the
|
||||
* specified \a query details.
|
||||
*/
|
||||
QgsDatabaseQueryLoggerQueryGroup( const QgsDatabaseQueryLogEntry &query );
|
||||
QVariant data( int role = Qt::DisplayRole ) const override;
|
||||
QList< QAction * > actions( QObject *parent ) override final;
|
||||
QVariant toVariant() const override;
|
||||
|
||||
/**
|
||||
* Called when the \a query is finished.
|
||||
*
|
||||
* Will automatically create children encapsulating the completed details.
|
||||
*/
|
||||
void setFinished( const QgsDatabaseQueryLogEntry &query );
|
||||
|
||||
/**
|
||||
* Returns the query's status.
|
||||
*/
|
||||
Status status() const { return mStatus; }
|
||||
|
||||
/**
|
||||
* Set the query \a status
|
||||
*/
|
||||
void setStatus( Status status );
|
||||
|
||||
/**
|
||||
* Converts a request \a status to a translated string value.
|
||||
*/
|
||||
static QString statusToString( Status status );
|
||||
|
||||
/**
|
||||
* Sets the SQL to \a sql.
|
||||
*/
|
||||
void setSql( const QString &sql );
|
||||
|
||||
/**
|
||||
* Returns the group SQL.
|
||||
*/
|
||||
const QString &sql() const;
|
||||
|
||||
private:
|
||||
|
||||
QString mSql;
|
||||
int mQueryId = 0;
|
||||
QByteArray mData;
|
||||
Status mStatus = Status::Pending;
|
||||
};
|
||||
|
||||
#endif // QGSDBQUERYLOGGERNODE_H
|
||||
205
src/app/devtools/querylogger/qgsqueryloggerpanelwidget.cpp
Normal file
205
src/app/devtools/querylogger/qgsqueryloggerpanelwidget.cpp
Normal file
@ -0,0 +1,205 @@
|
||||
/***************************************************************************
|
||||
qgsqueryloggerpanelwidget.cpp
|
||||
-------------------------
|
||||
begin : October 2021
|
||||
copyright : (C) 2021 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsguiutils.h"
|
||||
#include "qgsjsonutils.h"
|
||||
#include "qgsqueryloggerpanelwidget.h"
|
||||
#include "qgsdatabasequeryloggernode.h"
|
||||
#include "qgsappquerylogger.h"
|
||||
#include "qgssettings.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QFontDatabase>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QScrollBar>
|
||||
#include <QToolButton>
|
||||
#include <QCheckBox>
|
||||
#include <QTextStream>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
//
|
||||
// QgsDatabaseQueryLoggerTreeView
|
||||
//
|
||||
|
||||
QgsDatabaseQueryLoggerTreeView::QgsDatabaseQueryLoggerTreeView( QgsAppQueryLogger *logger, QWidget *parent )
|
||||
: QTreeView( parent )
|
||||
, mLogger( logger )
|
||||
{
|
||||
connect( this, &QTreeView::expanded, this, &QgsDatabaseQueryLoggerTreeView::itemExpanded );
|
||||
|
||||
setFont( QFontDatabase::systemFont( QFontDatabase::FixedFont ) );
|
||||
|
||||
mProxyModel = new QgsDatabaseQueryLoggerProxyModel( mLogger, this );
|
||||
setModel( mProxyModel );
|
||||
|
||||
setContextMenuPolicy( Qt::CustomContextMenu );
|
||||
connect( this, &QgsDatabaseQueryLoggerTreeView::customContextMenuRequested, this, &QgsDatabaseQueryLoggerTreeView::contextMenu );
|
||||
|
||||
connect( verticalScrollBar(), &QAbstractSlider::sliderMoved, this, [this]( int value )
|
||||
{
|
||||
if ( value == verticalScrollBar()->maximum() )
|
||||
mAutoScroll = true;
|
||||
else
|
||||
mAutoScroll = false;
|
||||
} );
|
||||
|
||||
connect( mLogger, &QAbstractItemModel::rowsInserted, this, [ = ]
|
||||
{
|
||||
if ( mLogger->rowCount() > ( QgsAppQueryLogger::MAX_LOGGED_REQUESTS * 1.2 ) ) // 20 % more as buffer
|
||||
{
|
||||
// never trim expanded nodes
|
||||
const int toTrim = mLogger->rowCount() - QgsAppQueryLogger::MAX_LOGGED_REQUESTS;
|
||||
int trimmed = 0;
|
||||
QList< int > rowsToTrim;
|
||||
rowsToTrim.reserve( toTrim );
|
||||
for ( int i = 0; i < mLogger->rowCount(); ++i )
|
||||
{
|
||||
const QModelIndex proxyIndex = mProxyModel->mapFromSource( mLogger->index( i, 0 ) );
|
||||
if ( !proxyIndex.isValid() || !isExpanded( proxyIndex ) )
|
||||
{
|
||||
rowsToTrim << i;
|
||||
trimmed++;
|
||||
}
|
||||
if ( trimmed == toTrim )
|
||||
break;
|
||||
}
|
||||
|
||||
mLogger->removeRequestRows( rowsToTrim );
|
||||
}
|
||||
|
||||
if ( mAutoScroll )
|
||||
scrollToBottom();
|
||||
} );
|
||||
|
||||
mMenu = new QMenu( this );
|
||||
}
|
||||
|
||||
void QgsDatabaseQueryLoggerTreeView::setFilterString( const QString &string )
|
||||
{
|
||||
mProxyModel->setFilterString( string );
|
||||
}
|
||||
|
||||
void QgsDatabaseQueryLoggerTreeView::itemExpanded( const QModelIndex &index )
|
||||
{
|
||||
// if the item is a QgsNetworkLoggerRequestGroup item, open all children (show ALL info of it)
|
||||
// we want to scroll to last request
|
||||
|
||||
// only expand all children on QgsNetworkLoggerRequestGroup nodes (which don't have a valid parent!)
|
||||
if ( !index.parent().isValid() )
|
||||
expandChildren( index );
|
||||
|
||||
// make ALL request information visible by scrolling view to it
|
||||
scrollTo( index );
|
||||
}
|
||||
|
||||
void QgsDatabaseQueryLoggerTreeView::contextMenu( QPoint point )
|
||||
{
|
||||
const QModelIndex viewModelIndex = indexAt( point );
|
||||
const QModelIndex modelIndex = mProxyModel->mapToSource( viewModelIndex );
|
||||
|
||||
if ( modelIndex.isValid() )
|
||||
{
|
||||
mMenu->clear();
|
||||
|
||||
const QList< QAction * > actions = mLogger->actions( modelIndex, mMenu );
|
||||
mMenu->addActions( actions );
|
||||
if ( !mMenu->actions().empty() )
|
||||
{
|
||||
mMenu->exec( viewport()->mapToGlobal( point ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsDatabaseQueryLoggerTreeView::expandChildren( const QModelIndex &index )
|
||||
{
|
||||
if ( !index.isValid() )
|
||||
return;
|
||||
|
||||
const int count = model()->rowCount( index );
|
||||
for ( int i = 0; i < count; ++i )
|
||||
{
|
||||
const QModelIndex childIndex = model()->index( i, 0, index );
|
||||
expandChildren( childIndex );
|
||||
}
|
||||
if ( !isExpanded( index ) )
|
||||
expand( index );
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsDatabaseQueryLoggerPanelWidget
|
||||
//
|
||||
|
||||
QgsDatabaseQueryLoggerPanelWidget::QgsDatabaseQueryLoggerPanelWidget( QgsAppQueryLogger *logger, QWidget *parent )
|
||||
: QgsDevToolWidget( parent )
|
||||
, mLogger( logger )
|
||||
{
|
||||
setupUi( this );
|
||||
|
||||
mTreeView = new QgsDatabaseQueryLoggerTreeView( mLogger );
|
||||
verticalLayout->addWidget( mTreeView );
|
||||
mToolbar->setIconSize( QgsGuiUtils::iconSize( true ) );
|
||||
|
||||
mFilterLineEdit->setShowClearButton( true );
|
||||
mFilterLineEdit->setShowSearchIcon( true );
|
||||
mFilterLineEdit->setPlaceholderText( tr( "Filter queries" ) );
|
||||
|
||||
mActionRecord->setChecked( QgsApplication::databaseQueryLog()->enabled() );
|
||||
|
||||
connect( mFilterLineEdit, &QgsFilterLineEdit::textChanged, mTreeView, &QgsDatabaseQueryLoggerTreeView::setFilterString );
|
||||
connect( mActionClear, &QAction::triggered, mLogger, &QgsAppQueryLogger::clear );
|
||||
connect( mActionRecord, &QAction::toggled, this, [ = ]( bool enabled )
|
||||
{
|
||||
QgsSettings().setValue( QStringLiteral( "logDatabaseQueries" ), enabled, QgsSettings::App );
|
||||
QgsApplication::databaseQueryLog()->setEnabled( enabled );
|
||||
} );
|
||||
connect( mActionSaveLog, &QAction::triggered, this, [ = ]()
|
||||
{
|
||||
if ( QMessageBox::warning( this, tr( "Save Database Query Log" ),
|
||||
tr( "Security warning: query logs may contain sensitive data including usernames or passwords. Treat this log as confidential and be careful who you share it with. Continue?" ), QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
|
||||
return;
|
||||
|
||||
const QString saveFilePath = QFileDialog::getSaveFileName( this, tr( "Save Query Log" ), QDir::homePath(), tr( "Log files" ) + " (*.json)" );
|
||||
if ( saveFilePath.isEmpty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QFile exportFile( saveFilePath );
|
||||
if ( !exportFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
QTextStream fout( &exportFile );
|
||||
|
||||
const QVariant value = mLogger->rootGroup()->toVariant();
|
||||
const QString json = QString::fromStdString( QgsJsonUtils::jsonFromVariant( value ).dump( 2 ) );
|
||||
|
||||
fout << json;
|
||||
} );
|
||||
|
||||
|
||||
QMenu *settingsMenu = new QMenu( this );
|
||||
QToolButton *settingsButton = new QToolButton();
|
||||
settingsButton->setAutoRaise( true );
|
||||
settingsButton->setToolTip( tr( "Settings" ) );
|
||||
settingsButton->setMenu( settingsMenu );
|
||||
settingsButton->setPopupMode( QToolButton::InstantPopup );
|
||||
settingsButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionOptions.svg" ) ) );
|
||||
mToolbar->addWidget( settingsButton );
|
||||
}
|
||||
84
src/app/devtools/querylogger/qgsqueryloggerpanelwidget.h
Normal file
84
src/app/devtools/querylogger/qgsqueryloggerpanelwidget.h
Normal file
@ -0,0 +1,84 @@
|
||||
/***************************************************************************
|
||||
qgsqueryloggerpanelwidget.h
|
||||
-------------------------
|
||||
begin : October 2021
|
||||
copyright : (C) 2021 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef QGSQUERYLOGGERPANELWIDGET_H
|
||||
#define QGSQUERYLOGGERPANELWIDGET_H
|
||||
|
||||
#include "qgsdevtoolwidget.h"
|
||||
#include "ui_qgsqueryloggerpanelbase.h"
|
||||
#include <QTreeView>
|
||||
|
||||
class QgsAppQueryLogger;
|
||||
class QgsDatabaseQueryLoggerProxyModel;
|
||||
|
||||
/**
|
||||
* \ingroup app
|
||||
* \class QgsDatabaseQueryLoggerTreeView
|
||||
* \brief A custom QTreeView subclass for showing logged database queries.
|
||||
*/
|
||||
class QgsDatabaseQueryLoggerTreeView: public QTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsDatabaseQueryLoggerTreeView, attached to the specified \a logger.
|
||||
*/
|
||||
QgsDatabaseQueryLoggerTreeView( QgsAppQueryLogger *logger, QWidget *parent = nullptr );
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* Sets a filter \a string to apply to request URLs.
|
||||
*/
|
||||
void setFilterString( const QString &string );
|
||||
|
||||
private slots:
|
||||
void itemExpanded( const QModelIndex &index );
|
||||
void contextMenu( QPoint point );
|
||||
|
||||
private:
|
||||
|
||||
void expandChildren( const QModelIndex &index );
|
||||
QMenu *mMenu = nullptr;
|
||||
QgsAppQueryLogger *mLogger = nullptr;
|
||||
QgsDatabaseQueryLoggerProxyModel *mProxyModel = nullptr;
|
||||
bool mAutoScroll = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup app
|
||||
* \class QgsDatabaseQueryLoggerPanelWidget
|
||||
* \brief A panel widget showing logged network requests.
|
||||
*/
|
||||
class QgsDatabaseQueryLoggerPanelWidget : public QgsDevToolWidget, private Ui::QgsDatabaseQueryLoggerPanelBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsDatabaseQueryLoggerPanelWidget, linked with the specified \a logger.
|
||||
*/
|
||||
QgsDatabaseQueryLoggerPanelWidget( QgsAppQueryLogger *logger, QWidget *parent );
|
||||
|
||||
private:
|
||||
|
||||
QgsDatabaseQueryLoggerTreeView *mTreeView = nullptr;
|
||||
QgsAppQueryLogger *mLogger = nullptr;
|
||||
};
|
||||
|
||||
|
||||
#endif // QGSQUERYLOGGERPANELWIDGET_H
|
||||
29
src/app/devtools/querylogger/qgsqueryloggerwidgetfactory.cpp
Normal file
29
src/app/devtools/querylogger/qgsqueryloggerwidgetfactory.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
/***************************************************************************
|
||||
qgsqueryloggerwidgetfactory.cpp
|
||||
-------------------------
|
||||
begin : October 2021
|
||||
copyright : (C) 2021 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsqueryloggerwidgetfactory.h"
|
||||
#include "qgsqueryloggerpanelwidget.h"
|
||||
#include "qgsapplication.h"
|
||||
|
||||
QgsDatabaseQueryLoggerWidgetFactory::QgsDatabaseQueryLoggerWidgetFactory( QgsAppQueryLogger *logger )
|
||||
: QgsDevToolWidgetFactory( QObject::tr( "Query Logger" ), QgsApplication::getThemeIcon( QStringLiteral( "propertyicons/database.svg" ) ) )
|
||||
, mLogger( logger )
|
||||
{
|
||||
}
|
||||
|
||||
QgsDevToolWidget *QgsDatabaseQueryLoggerWidgetFactory::createWidget( QWidget *parent ) const
|
||||
{
|
||||
return new QgsDatabaseQueryLoggerPanelWidget( mLogger, parent );
|
||||
}
|
||||
35
src/app/devtools/querylogger/qgsqueryloggerwidgetfactory.h
Normal file
35
src/app/devtools/querylogger/qgsqueryloggerwidgetfactory.h
Normal file
@ -0,0 +1,35 @@
|
||||
/***************************************************************************
|
||||
qgsqueryloggerwidgetfactory.h
|
||||
-------------------------
|
||||
begin : October 2021
|
||||
copyright : (C) 2021 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef QGSQUERYLOGGERWIDGETFACTORY_H
|
||||
#define QGSQUERYLOGGERWIDGETFACTORY_H
|
||||
|
||||
#include "qgsdevtoolwidgetfactory.h"
|
||||
|
||||
class QgsAppQueryLogger;
|
||||
|
||||
class QgsDatabaseQueryLoggerWidgetFactory: public QgsDevToolWidgetFactory
|
||||
{
|
||||
public:
|
||||
|
||||
QgsDatabaseQueryLoggerWidgetFactory( QgsAppQueryLogger *logger );
|
||||
QgsDevToolWidget *createWidget( QWidget *parent = nullptr ) const override;
|
||||
|
||||
private:
|
||||
|
||||
QgsAppQueryLogger *mLogger = nullptr;
|
||||
};
|
||||
|
||||
|
||||
#endif // QGSQUERYLOGGERWIDGETFACTORY_H
|
||||
@ -437,6 +437,8 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
|
||||
#include "qgsuserprofilemanager.h"
|
||||
#include "qgsuserprofile.h"
|
||||
#include "qgsnetworkloggerwidgetfactory.h"
|
||||
#include "devtools/querylogger/qgsappquerylogger.h"
|
||||
#include "devtools/querylogger/qgsqueryloggerwidgetfactory.h"
|
||||
#include "devtools/profiler/qgsprofilerwidgetfactory.h"
|
||||
#include "qgsabstractdatabaseproviderconnection.h"
|
||||
#include "qgszipitem.h"
|
||||
@ -1034,6 +1036,10 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipBadLayers
|
||||
|
||||
QgsSettings settings;
|
||||
|
||||
startProfile( tr( "Create database query logger" ) );
|
||||
mQueryLogger = new QgsAppQueryLogger( this );
|
||||
QgsApplication::databaseQueryLog()->setEnabled( settings.value( QStringLiteral( "logDatabaseQueries" ), false, QgsSettings::App ).toBool() );
|
||||
endProfile();
|
||||
|
||||
startProfile( tr( "Building style sheet" ) );
|
||||
// set up stylesheet builder and apply saved or default style options
|
||||
@ -1831,6 +1837,7 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipBadLayers
|
||||
mBearingNumericFormat.reset( QgsLocalDefaultSettings::bearingFormat() );
|
||||
|
||||
mNetworkLoggerWidgetFactory.reset( std::make_unique< QgsNetworkLoggerWidgetFactory >( mNetworkLogger ) );
|
||||
mQueryLoggerWidgetFactory.reset( std::make_unique< QgsDatabaseQueryLoggerWidgetFactory >( mQueryLogger ) );
|
||||
|
||||
// update windows
|
||||
qApp->processEvents();
|
||||
|
||||
@ -151,6 +151,7 @@ class QgsDevToolsPanelWidget;
|
||||
class QgsDevToolWidgetFactory;
|
||||
class QgsNetworkLogger;
|
||||
class QgsNetworkLoggerWidgetFactory;
|
||||
class QgsAppQueryLogger;
|
||||
class QgsMapToolCapture;
|
||||
class QgsElevationProfileWidget;
|
||||
|
||||
@ -2742,6 +2743,8 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
|
||||
QgsNetworkLogger *mNetworkLogger = nullptr;
|
||||
QgsScopedDevToolWidgetFactory mNetworkLoggerWidgetFactory;
|
||||
QgsScopedDevToolWidgetFactory mStartupProfilerWidgetFactory;
|
||||
QgsAppQueryLogger *mQueryLogger = nullptr;
|
||||
QgsScopedDevToolWidgetFactory mQueryLoggerWidgetFactory;
|
||||
|
||||
QgsScopedOptionsWidgetFactory mCodeEditorWidgetFactory;
|
||||
QgsScopedOptionsWidgetFactory mBabelGpsDevicesWidgetFactory;
|
||||
|
||||
@ -356,6 +356,7 @@ set(QGIS_CORE_SRCS
|
||||
qgsdataprovidertemporalcapabilities.cpp
|
||||
qgsdatetimestatisticalsummary.cpp
|
||||
qgsdbfilterproxymodel.cpp
|
||||
qgsdbquerylog.cpp
|
||||
qgsdefaultvalue.cpp
|
||||
qgsdiagramrenderer.cpp
|
||||
qgsdistancearea.cpp
|
||||
@ -1005,6 +1006,7 @@ set(QGIS_CORE_HDRS
|
||||
qgsdatasourceuri.h
|
||||
qgsdatetimestatisticalsummary.h
|
||||
qgsdbfilterproxymodel.h
|
||||
qgsdbquerylog.h
|
||||
qgsdefaultvalue.h
|
||||
qgsdiagramrenderer.h
|
||||
qgsdistancearea.h
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "qgsfeedback.h"
|
||||
#include "qgsogrutils.h"
|
||||
#include "qgsfielddomain.h"
|
||||
#include "qgsdbquerylog.h"
|
||||
|
||||
#include <QTextCodec>
|
||||
#include <QRegularExpression>
|
||||
@ -351,8 +352,11 @@ void QgsGeoPackageProviderConnection::setDefaultCapabilities()
|
||||
QgsAbstractDatabaseProviderConnection::QueryResult QgsGeoPackageProviderConnection::executeGdalSqlPrivate( const QString &sql, QgsFeedback *feedback ) const
|
||||
{
|
||||
|
||||
QgsDatabaseQueryLogWrapper logWrapper( sql, uri(), providerKey(), QStringLiteral( "QgsGeoPackageProviderConnection" ), QGS_QUERY_LOG_ORIGIN );
|
||||
|
||||
if ( feedback && feedback->isCanceled() )
|
||||
{
|
||||
logWrapper.setCanceled();
|
||||
return QgsAbstractDatabaseProviderConnection::QueryResult();
|
||||
}
|
||||
|
||||
@ -363,6 +367,7 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsGeoPackageProviderConnecti
|
||||
|
||||
if ( feedback && feedback->isCanceled() )
|
||||
{
|
||||
logWrapper.setCanceled();
|
||||
return QgsAbstractDatabaseProviderConnection::QueryResult();
|
||||
}
|
||||
|
||||
@ -379,9 +384,9 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsGeoPackageProviderConnecti
|
||||
results.setQueryExecutionTime( std::chrono::duration_cast<std::chrono::milliseconds>( end - begin ).count() );
|
||||
|
||||
gdal::ogr_feature_unique_ptr fet;
|
||||
|
||||
if ( fet.reset( OGR_L_GetNextFeature( ogrLayer ) ), fet )
|
||||
{
|
||||
|
||||
// pk column name
|
||||
QString pkColumnName;
|
||||
|
||||
@ -453,11 +458,13 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsGeoPackageProviderConnecti
|
||||
|
||||
if ( ! errCause.isEmpty() )
|
||||
{
|
||||
logWrapper.setError( errCause );
|
||||
throw QgsProviderConnectionException( QObject::tr( "Error executing SQL statement %1: %2" ).arg( sql, errCause ) );
|
||||
}
|
||||
|
||||
OGR_L_ResetReading( ogrLayer );
|
||||
iterator->nextRow();
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@ -475,6 +482,7 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsGeoPackageProviderConnecti
|
||||
|
||||
if ( !errCause.isEmpty() )
|
||||
{
|
||||
logWrapper.setError( errCause );
|
||||
throw QgsProviderConnectionException( QObject::tr( "Error executing SQL %1: %2" ).arg( sql, errCause ) );
|
||||
}
|
||||
|
||||
|
||||
@ -77,6 +77,7 @@
|
||||
#include "qgslocator.h"
|
||||
#include "qgsreadwritelocker.h"
|
||||
#include "qgsbabelformatregistry.h"
|
||||
#include "qgsdbquerylog.h"
|
||||
|
||||
#include "gps/qgsgpsconnectionregistry.h"
|
||||
#include "processing/qgsprocessingregistry.h"
|
||||
@ -265,6 +266,7 @@ void QgsApplication::init( QString profileFolder )
|
||||
std::call_once( sMetaTypesRegistered, []
|
||||
{
|
||||
qRegisterMetaType<QgsGeometry::Error>( "QgsGeometry::Error" );
|
||||
qRegisterMetaType<QgsDatabaseQueryLogEntry>( "QgsDatabaseQueryLogEntry" );
|
||||
qRegisterMetaType<QgsProcessingFeatureSourceDefinition>( "QgsProcessingFeatureSourceDefinition" );
|
||||
qRegisterMetaType<QgsProcessingOutputLayerDefinition>( "QgsProcessingOutputLayerDefinition" );
|
||||
qRegisterMetaType<QgsUnitTypes::LayoutUnit>( "QgsUnitTypes::LayoutUnit" );
|
||||
@ -2433,6 +2435,11 @@ QgsRecentStyleHandler *QgsApplication::recentStyleHandler()
|
||||
return members()->mRecentStyleHandler;
|
||||
}
|
||||
|
||||
QgsDatabaseQueryLog *QgsApplication::databaseQueryLog()
|
||||
{
|
||||
return members()->mQueryLogger;
|
||||
}
|
||||
|
||||
QgsStyleModel *QgsApplication::defaultStyleModel()
|
||||
{
|
||||
return members()->mStyleModel;
|
||||
@ -2512,6 +2519,11 @@ QgsApplication::ApplicationMembers::ApplicationMembers()
|
||||
mMessageLog = new QgsMessageLog();
|
||||
QgsRuntimeProfiler *profiler = QgsRuntimeProfiler::threadLocalInstance();
|
||||
|
||||
{
|
||||
profiler->start( tr( "Create query logger" ) );
|
||||
mQueryLogger = new QgsDatabaseQueryLog();
|
||||
profiler->end();
|
||||
}
|
||||
{
|
||||
profiler->start( tr( "Setup coordinate reference system registry" ) );
|
||||
mCrsRegistry = new QgsCoordinateReferenceSystemRegistry();
|
||||
@ -2726,6 +2738,7 @@ QgsApplication::ApplicationMembers::~ApplicationMembers()
|
||||
delete mConnectionRegistry;
|
||||
delete mLocalizedDataPathRegistry;
|
||||
delete mCrsRegistry;
|
||||
delete mQueryLogger;
|
||||
delete mSettingsRegistryCore;
|
||||
}
|
||||
|
||||
|
||||
@ -72,6 +72,7 @@ class QgsPointCloudRendererRegistry;
|
||||
class QgsTileDownloadManager;
|
||||
class QgsCoordinateReferenceSystemRegistry;
|
||||
class QgsRecentStyleHandler;
|
||||
class QgsDatabaseQueryLog;
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
@ -820,6 +821,13 @@ class CORE_EXPORT QgsApplication : public QApplication
|
||||
*/
|
||||
static QgsRecentStyleHandler *recentStyleHandler() SIP_KEEPREFERENCE;
|
||||
|
||||
/**
|
||||
* Returns the database query log.
|
||||
*
|
||||
* \since QGIS 3.24
|
||||
*/
|
||||
static QgsDatabaseQueryLog *databaseQueryLog() SIP_KEEPREFERENCE;
|
||||
|
||||
/**
|
||||
* Returns a shared QgsStyleModel containing the default style library (see QgsStyle::defaultStyle()).
|
||||
*
|
||||
@ -1136,6 +1144,7 @@ class CORE_EXPORT QgsApplication : public QApplication
|
||||
QgsTileDownloadManager *mTileDownloadManager = nullptr;
|
||||
QgsStyleModel *mStyleModel = nullptr;
|
||||
QgsRecentStyleHandler *mRecentStyleHandler = nullptr;
|
||||
QgsDatabaseQueryLog *mQueryLogger = nullptr;
|
||||
QString mNullRepresentation;
|
||||
QStringList mSvgPathCache;
|
||||
bool mSvgPathCacheValid = false;
|
||||
|
||||
76
src/core/qgsdbquerylog.cpp
Normal file
76
src/core/qgsdbquerylog.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
/***************************************************************************
|
||||
qgsdbquerylog.cpp
|
||||
------------
|
||||
Date : October 2021
|
||||
Copyright : (C) 2021 by Nyall Dawson
|
||||
Email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsdbquerylog.h"
|
||||
#include "qgsapplication.h"
|
||||
#include <QDateTime>
|
||||
|
||||
//
|
||||
// QgsDatabaseQueryLogEntry
|
||||
//
|
||||
|
||||
QAtomicInt QgsDatabaseQueryLogEntry::sQueryId = 0;
|
||||
|
||||
QgsDatabaseQueryLogEntry::QgsDatabaseQueryLogEntry( const QString &query )
|
||||
: queryId( ++sQueryId )
|
||||
, query( query )
|
||||
, startedTime( QDateTime::currentMSecsSinceEpoch() )
|
||||
{}
|
||||
|
||||
|
||||
//
|
||||
// QgsDatabaseQueryLog
|
||||
//
|
||||
|
||||
bool QgsDatabaseQueryLog::sEnabled = false;
|
||||
|
||||
QgsDatabaseQueryLog::QgsDatabaseQueryLog( QObject *parent )
|
||||
: QObject( parent )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void QgsDatabaseQueryLog::log( const QgsDatabaseQueryLogEntry &query )
|
||||
{
|
||||
if ( !sEnabled )
|
||||
return;
|
||||
|
||||
QMetaObject::invokeMethod( QgsApplication::databaseQueryLog(), "queryStartedPrivate", Qt::QueuedConnection, Q_ARG( QgsDatabaseQueryLogEntry, query ) );
|
||||
}
|
||||
|
||||
void QgsDatabaseQueryLog::finished( const QgsDatabaseQueryLogEntry &query )
|
||||
{
|
||||
if ( !sEnabled )
|
||||
return;
|
||||
|
||||
// record time of completion
|
||||
QgsDatabaseQueryLogEntry finishedQuery = query;
|
||||
finishedQuery.finishedTime = QDateTime::currentMSecsSinceEpoch();
|
||||
|
||||
QMetaObject::invokeMethod( QgsApplication::databaseQueryLog(), "queryFinishedPrivate", Qt::QueuedConnection, Q_ARG( QgsDatabaseQueryLogEntry, finishedQuery ) );
|
||||
}
|
||||
|
||||
void QgsDatabaseQueryLog::queryStartedPrivate( const QgsDatabaseQueryLogEntry &query )
|
||||
{
|
||||
QgsDebugMsg( query.query );
|
||||
emit queryStarted( query );
|
||||
}
|
||||
|
||||
void QgsDatabaseQueryLog::queryFinishedPrivate( const QgsDatabaseQueryLogEntry &query )
|
||||
{
|
||||
QgsDebugMsg( query.query );
|
||||
emit queryFinished( query );
|
||||
}
|
||||
|
||||
270
src/core/qgsdbquerylog.h
Normal file
270
src/core/qgsdbquerylog.h
Normal file
@ -0,0 +1,270 @@
|
||||
/***************************************************************************
|
||||
qgsdbquerylog.h
|
||||
------------
|
||||
Date : October 2021
|
||||
Copyright : (C) 2021 by Nyall Dawson
|
||||
Email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSDBQUERYLOG_H
|
||||
#define QGSDBQUERYLOG_H
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgis.h"
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \class QgsDatabaseQueryLogEntry
|
||||
* \brief Encapsulates a logged database query.
|
||||
*
|
||||
* \since QGIS 3.24
|
||||
*/
|
||||
class CORE_EXPORT QgsDatabaseQueryLogEntry
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsDatabaseQueryLogEntry.
|
||||
*/
|
||||
QgsDatabaseQueryLogEntry( const QString &query = QString() );
|
||||
|
||||
/**
|
||||
* Unique query ID.
|
||||
*
|
||||
* This ID will automatically be set on creation of a new QgsDatabaseQueryLogEntry object.
|
||||
*/
|
||||
int queryId = 0;
|
||||
|
||||
//! Database URI
|
||||
QString uri;
|
||||
|
||||
//! Provider key
|
||||
QString provider;
|
||||
|
||||
//! The logged database query (e.g. the SQL query)
|
||||
QString query;
|
||||
|
||||
/**
|
||||
* Time when the query started (in milliseconds since epoch).
|
||||
*
|
||||
* This will be automatically recorded on creation of a new QgsDatabaseQueryLogEntry object.
|
||||
*/
|
||||
quint64 startedTime = 0;
|
||||
|
||||
/**
|
||||
* Time when the query finished (in milliseconds since epoch), if available.
|
||||
*/
|
||||
quint64 finishedTime = 0;
|
||||
|
||||
/**
|
||||
* The QGIS class which initiated the query.
|
||||
*
|
||||
* c++ code can automatically populate this through the QgsSetQueryLogClass macro.
|
||||
*/
|
||||
QString initiatorClass;
|
||||
|
||||
/**
|
||||
* Code file location for the query origin.
|
||||
*
|
||||
* c++ code can automatically populate this through the QgsSetQueryLogClass macro.
|
||||
*/
|
||||
QString origin;
|
||||
|
||||
/**
|
||||
* Number of fetched/affected rows.
|
||||
* \warning Not all providers support this information.
|
||||
*/
|
||||
long long fetchedRows = -1;
|
||||
|
||||
/**
|
||||
* Error reported by the provider, normally blank
|
||||
*/
|
||||
QString error;
|
||||
|
||||
/**
|
||||
* Canceled flag for user canceled queries.
|
||||
*/
|
||||
bool canceled = false;
|
||||
|
||||
private:
|
||||
|
||||
static QAtomicInt sQueryId;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE( QgsDatabaseQueryLogEntry );
|
||||
|
||||
#ifndef SIP_RUN
|
||||
#include "qgsconfig.h"
|
||||
constexpr int sQueryLoggerFilePrefixLength = CMAKE_SOURCE_DIR[sizeof( CMAKE_SOURCE_DIR ) - 1] == '/' ? sizeof( CMAKE_SOURCE_DIR ) + 1 : sizeof( CMAKE_SOURCE_DIR );
|
||||
#define QgsSetQueryLogClass(entry, _class) entry.initiatorClass = _class; entry.origin = QString(QString( __FILE__ ).mid( sQueryLoggerFilePrefixLength ) + ':' + QString::number( __LINE__ ) + " (" + __FUNCTION__ + ")");
|
||||
#define QGS_QUERY_LOG_ORIGIN QString(QString( __FILE__ ).mid( sQueryLoggerFilePrefixLength ) + ':' + QString::number( __LINE__ ) + " (" + __FUNCTION__ + ")")
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \class QgsDatabaseQueryLog
|
||||
* \brief Handles logging of database queries.
|
||||
*
|
||||
* QgsDatabaseQueryLog is not usually directly created, but rather accessed through
|
||||
* QgsApplication::databaseQueryLog(). Generally, clients should only access the
|
||||
* static log() method to register their queries.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* \code{.py}
|
||||
* # Log a database query
|
||||
* QgsDatabaseQueryLog.log('SELECT * FROM my_table')
|
||||
* \endcode
|
||||
*
|
||||
*
|
||||
* \since QGIS 3.24
|
||||
*/
|
||||
class CORE_EXPORT QgsDatabaseQueryLog: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a new query log.
|
||||
*
|
||||
* QgsDatabaseQueryLog is not usually directly created, but rather accessed through
|
||||
* QgsApplication::databaseQueryLog().
|
||||
*/
|
||||
QgsDatabaseQueryLog( QObject *parent = nullptr );
|
||||
|
||||
/**
|
||||
* Enables query logging.
|
||||
*
|
||||
* If disabled, no signals will be emitted by the log. By default the log is disabled,
|
||||
* and clients must manually enable it.
|
||||
*
|
||||
* \note Not available in Python bindings
|
||||
* \see enabled()
|
||||
*/
|
||||
static void setEnabled( bool enabled ) SIP_SKIP { sEnabled = enabled; }
|
||||
|
||||
/**
|
||||
* Returns TRUE if logging is enabled.
|
||||
*
|
||||
* \see setEnabled()
|
||||
*/
|
||||
static bool enabled() { return sEnabled; }
|
||||
|
||||
/**
|
||||
* Logs a database \a query as starting.
|
||||
*
|
||||
* This method can be safely called from any thread.
|
||||
*/
|
||||
static void log( const QgsDatabaseQueryLogEntry &query );
|
||||
|
||||
/**
|
||||
* Records that the database \a query has finished.
|
||||
*
|
||||
* This method can be safely called from any thread.
|
||||
*/
|
||||
static void finished( const QgsDatabaseQueryLogEntry &query );
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* Internal slot for logging queries as start.
|
||||
*
|
||||
* \note Not available in Python bindings.
|
||||
*/
|
||||
void queryStartedPrivate( const QgsDatabaseQueryLogEntry &query ) SIP_SKIP;
|
||||
|
||||
/**
|
||||
* Internal slot for logging queries as finished.
|
||||
*
|
||||
* \note Not available in Python bindings.
|
||||
*/
|
||||
void queryFinishedPrivate( const QgsDatabaseQueryLogEntry &query ) SIP_SKIP;
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
* Emitted whenever a database query is started.
|
||||
*
|
||||
* \note Not available in Python bindings
|
||||
*/
|
||||
void queryStarted( const QgsDatabaseQueryLogEntry &query ) SIP_SKIP;
|
||||
|
||||
/**
|
||||
* Emitted whenever a database query has finished executing.
|
||||
*
|
||||
* \note Not available in Python bindings
|
||||
*/
|
||||
void queryFinished( const QgsDatabaseQueryLogEntry &query ) SIP_SKIP;
|
||||
|
||||
private:
|
||||
|
||||
static bool sEnabled;
|
||||
|
||||
};
|
||||
|
||||
#ifndef SIP_RUN
|
||||
///@cond private
|
||||
|
||||
/**
|
||||
* The QgsDatabaseQueryLogWrapper class is a RIIA wrapper for the query logger.
|
||||
*/
|
||||
class QgsDatabaseQueryLogWrapper
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
QgsDatabaseQueryLogWrapper( const QString &query, const QString &uri, const QString &provider, const QString &initiatorClass, const QString &origin )
|
||||
: mEntry( query )
|
||||
{
|
||||
mEntry.uri = uri;
|
||||
mEntry.origin = origin;
|
||||
mEntry.initiatorClass = initiatorClass;
|
||||
mEntry.provider = provider;
|
||||
QgsDatabaseQueryLog::log( mEntry );
|
||||
}
|
||||
|
||||
~QgsDatabaseQueryLogWrapper( )
|
||||
{
|
||||
QgsDatabaseQueryLog::finished( mEntry );
|
||||
}
|
||||
|
||||
void setFetchedRows( long long fetchedRows )
|
||||
{
|
||||
mEntry.fetchedRows = fetchedRows;
|
||||
}
|
||||
|
||||
void setQuery( const QString &query )
|
||||
{
|
||||
mEntry.query = query;
|
||||
}
|
||||
|
||||
void setError( const QString &error )
|
||||
{
|
||||
mEntry.error = error;
|
||||
}
|
||||
|
||||
void setCanceled( )
|
||||
{
|
||||
mEntry.canceled = true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
QgsDatabaseQueryLogEntry mEntry;
|
||||
|
||||
};
|
||||
|
||||
///@endcond
|
||||
#endif
|
||||
|
||||
#endif // QGSDBQUERYLOG_H
|
||||
@ -20,6 +20,7 @@
|
||||
#include "qgsmssqlprovider.h"
|
||||
#include "qgsmssqltransaction.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsdbquerylog.h"
|
||||
#include "qgssettings.h"
|
||||
#include "qgsexception.h"
|
||||
#include "qgsmssqldatabase.h"
|
||||
@ -525,7 +526,7 @@ bool QgsMssqlFeatureIterator::fetchFeature( QgsFeature &feature )
|
||||
case PktFidMap:
|
||||
{
|
||||
QVariantList primaryKeyVals;
|
||||
for ( int idx : mSource->mPrimaryKeyAttrs )
|
||||
for ( int idx : std::as_const( mSource->mPrimaryKeyAttrs ) )
|
||||
{
|
||||
QgsField fld = mSource->mFields.at( idx );
|
||||
|
||||
@ -607,29 +608,50 @@ bool QgsMssqlFeatureIterator::rewind()
|
||||
mQuery->clear();
|
||||
mQuery->setForwardOnly( true );
|
||||
|
||||
bool result = mQuery->exec( mOrderByClause.isEmpty() ? mStatement : mStatement + mOrderByClause );
|
||||
if ( !result && !mFallbackStatement.isEmpty() )
|
||||
QString sql { mOrderByClause.isEmpty() ? mStatement : mStatement + mOrderByClause };
|
||||
std::unique_ptr<QgsDatabaseQueryLogWrapper> logWrapper = std::make_unique<QgsDatabaseQueryLogWrapper>( sql, mSource->connInfo(), QStringLiteral( "mssql" ), QStringLiteral( "QgsMssqlFeatureIterator" ), QGS_QUERY_LOG_ORIGIN );
|
||||
|
||||
bool result = mQuery->exec( sql );
|
||||
if ( !result )
|
||||
{
|
||||
//try with fallback statement
|
||||
result = mQuery->exec( mOrderByClause.isEmpty() ? mFallbackStatement : mFallbackStatement + mOrderByClause );
|
||||
if ( result )
|
||||
logWrapper->setError( mQuery->lastError().text() );
|
||||
if ( !mFallbackStatement.isEmpty() )
|
||||
{
|
||||
mExpressionCompiled = false;
|
||||
mCompileStatus = NoCompilation;
|
||||
//try with fallback statement
|
||||
sql = mOrderByClause.isEmpty() ? mFallbackStatement : mFallbackStatement + mOrderByClause;
|
||||
logWrapper.reset( new QgsDatabaseQueryLogWrapper( sql, mSource->connInfo(), QStringLiteral( "mssql" ), QStringLiteral( "QgsMssqlFeatureIterator" ), QGS_QUERY_LOG_ORIGIN ) );
|
||||
result = mQuery->exec( sql );
|
||||
if ( result )
|
||||
{
|
||||
mExpressionCompiled = false;
|
||||
mCompileStatus = NoCompilation;
|
||||
}
|
||||
else
|
||||
{
|
||||
logWrapper->setError( mQuery->lastError().text() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !result && !mOrderByClause.isEmpty() )
|
||||
{
|
||||
//try without order by clause
|
||||
logWrapper.reset( new QgsDatabaseQueryLogWrapper( mStatement, mSource->connInfo(), QStringLiteral( "mssql" ), QStringLiteral( "QgsMssqlFeatureIterator" ), QGS_QUERY_LOG_ORIGIN ) );
|
||||
result = mQuery->exec( mStatement );
|
||||
if ( result )
|
||||
{
|
||||
mOrderByCompiled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
logWrapper->setError( mQuery->lastError().text() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !result && !mFallbackStatement.isEmpty() && !mOrderByClause.isEmpty() )
|
||||
{
|
||||
//try with fallback statement and without order by clause
|
||||
logWrapper.reset( new QgsDatabaseQueryLogWrapper( mFallbackStatement, mSource->connInfo(), QStringLiteral( "mssql" ), QStringLiteral( "QgsMssqlFeatureIterator" ), QGS_QUERY_LOG_ORIGIN ) );
|
||||
result = mQuery->exec( mFallbackStatement );
|
||||
if ( result )
|
||||
{
|
||||
@ -637,6 +659,10 @@ bool QgsMssqlFeatureIterator::rewind()
|
||||
mOrderByCompiled = false;
|
||||
mCompileStatus = NoCompilation;
|
||||
}
|
||||
else
|
||||
{
|
||||
logWrapper->setError( mQuery->lastError().text() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !result )
|
||||
@ -689,9 +715,15 @@ QgsMssqlFeatureSource::QgsMssqlFeatureSource( const QgsMssqlProvider *p )
|
||||
, mDisableInvalidGeometryHandling( p->mDisableInvalidGeometryHandling )
|
||||
, mCrs( p->crs() )
|
||||
, mTransactionConn( p->transaction() ? static_cast<QgsMssqlTransaction *>( p->transaction() )->conn() : std::shared_ptr<QgsMssqlDatabase>() )
|
||||
, mConnInfo( p->uri().uri( ) )
|
||||
{}
|
||||
|
||||
QgsFeatureIterator QgsMssqlFeatureSource::getFeatures( const QgsFeatureRequest &request )
|
||||
{
|
||||
return QgsFeatureIterator( new QgsMssqlFeatureIterator( this, false, request ) );
|
||||
}
|
||||
|
||||
const QString &QgsMssqlFeatureSource::connInfo() const
|
||||
{
|
||||
return mConnInfo;
|
||||
}
|
||||
|
||||
@ -38,6 +38,8 @@ class QgsMssqlFeatureSource final: public QgsAbstractFeatureSource
|
||||
|
||||
QgsFeatureIterator getFeatures( const QgsFeatureRequest &request ) override;
|
||||
|
||||
const QString &connInfo() const;
|
||||
|
||||
private:
|
||||
QgsFields mFields;
|
||||
QgsMssqlPrimaryKeyType mPrimaryKeyType;
|
||||
@ -76,6 +78,9 @@ class QgsMssqlFeatureSource final: public QgsAbstractFeatureSource
|
||||
// Return True if this feature source has spatial attributes.
|
||||
bool isSpatial() { return !mGeometryColName.isEmpty() || !mGeometryColType.isEmpty(); }
|
||||
|
||||
// Uri information for query logger
|
||||
QString mConnInfo;
|
||||
|
||||
friend class QgsMssqlFeatureIterator;
|
||||
friend class QgsMssqlExpressionCompiler;
|
||||
};
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#include "qgsmssqldatabase.h"
|
||||
#include "qgsmssqlproviderconnection.h"
|
||||
#include "qgsfeedback.h"
|
||||
#include "qgsdbquerylog.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QFileInfo>
|
||||
@ -53,6 +54,12 @@
|
||||
#include "qgsmssqltransaction.h"
|
||||
|
||||
|
||||
#include "qgsconfig.h"
|
||||
constexpr int sMssqlConQueryLogFilePrefixLength = CMAKE_SOURCE_DIR[sizeof( CMAKE_SOURCE_DIR ) - 1] == '/' ? sizeof( CMAKE_SOURCE_DIR ) + 1 : sizeof( CMAKE_SOURCE_DIR );
|
||||
#define LoggedExec(query, sql ) execLogged( query, sql, QString(QString( __FILE__ ).mid( sMssqlConQueryLogFilePrefixLength ) + ':' + QString::number( __LINE__ ) + " (" + __FUNCTION__ + ")") )
|
||||
#define LoggedExecMetadata(query, sql, uri ) execLogged( query, sql, uri, QString(QString( __FILE__ ).mid( sMssqlConQueryLogFilePrefixLength ) + ':' + QString::number( __LINE__ ) + " (" + __FUNCTION__ + ")") )
|
||||
|
||||
|
||||
const QString QgsMssqlProvider::MSSQL_PROVIDER_KEY = QStringLiteral( "mssql" );
|
||||
const QString QgsMssqlProvider::MSSQL_PROVIDER_DESCRIPTION = QStringLiteral( "MSSQL spatial data provider" );
|
||||
int QgsMssqlProvider::sConnectionId = 0;
|
||||
@ -314,7 +321,7 @@ void QgsMssqlProvider::loadMetadata()
|
||||
|
||||
QSqlQuery query = createQuery();
|
||||
query.setForwardOnly( true );
|
||||
if ( !query.exec( QStringLiteral( "SELECT f_geometry_column, srid, geometry_type, coord_dimension FROM geometry_columns WHERE f_table_schema=%1 AND f_table_name=%2" ).arg( quotedValue( mSchemaName ), quotedValue( mTableName ) ) ) )
|
||||
if ( !LoggedExec( query, QStringLiteral( "SELECT f_geometry_column, srid, geometry_type, coord_dimension FROM geometry_columns WHERE f_table_schema=%1 AND f_table_name=%2" ).arg( quotedValue( mSchemaName ), quotedValue( mTableName ) ) ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "SQL:%1\n Error:%2" ).arg( query.lastQuery(), query.lastError().text() ) );
|
||||
}
|
||||
@ -333,6 +340,29 @@ void QgsMssqlProvider::loadMetadata()
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsMssqlProvider::execLogged( QSqlQuery &qry, const QString &sql, const QString &queryOrigin ) const
|
||||
{
|
||||
QgsDatabaseQueryLogWrapper logWrapper{ sql, uri().uri(), QStringLiteral( "mssql" ), QStringLiteral( "QgsMssqlProvider" ), queryOrigin };
|
||||
const bool res { qry.exec( sql ) };
|
||||
if ( ! res )
|
||||
{
|
||||
logWrapper.setError( qry.lastError().text() );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( qry.isSelect() )
|
||||
{
|
||||
logWrapper.setFetchedRows( qry.size() );
|
||||
}
|
||||
else
|
||||
{
|
||||
logWrapper.setFetchedRows( qry.numRowsAffected() );
|
||||
}
|
||||
}
|
||||
logWrapper.setQuery( qry.lastQuery() );
|
||||
return res;
|
||||
}
|
||||
|
||||
void QgsMssqlProvider::setLastError( const QString &error )
|
||||
{
|
||||
appendError( error );
|
||||
@ -361,8 +391,10 @@ void QgsMssqlProvider::loadFields()
|
||||
QSqlQuery query = createQuery();
|
||||
query.setForwardOnly( true );
|
||||
|
||||
const QString sql { QStringLiteral( "SELECT name FROM sys.columns WHERE is_computed = 1 AND object_id = OBJECT_ID('[%1].[%2]')" ).arg( mSchemaName, mTableName ) };
|
||||
|
||||
// Get computed columns which need to be ignored on insert or update.
|
||||
if ( !query.exec( QStringLiteral( "SELECT name FROM sys.columns WHERE is_computed = 1 AND object_id = OBJECT_ID('[%1].[%2]')" ).arg( mSchemaName, mTableName ) ) )
|
||||
if ( !LoggedExec( query, sql ) )
|
||||
{
|
||||
pushError( query.lastError().text() );
|
||||
return;
|
||||
@ -376,20 +408,24 @@ void QgsMssqlProvider::loadFields()
|
||||
// Field has unique constraint
|
||||
QSet<QString> setColumnUnique;
|
||||
{
|
||||
if ( !query.exec( QStringLiteral( "SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC"
|
||||
" INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CC ON TC.CONSTRAINT_NAME = CC.CONSTRAINT_NAME"
|
||||
" WHERE TC.CONSTRAINT_SCHEMA = '%1' AND TC.TABLE_NAME = '%2' AND TC.CONSTRAINT_TYPE = 'unique'" )
|
||||
.arg( mSchemaName, mTableName ) ) )
|
||||
const QString sql2 { QStringLiteral( "SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC"
|
||||
" INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CC ON TC.CONSTRAINT_NAME = CC.CONSTRAINT_NAME"
|
||||
" WHERE TC.CONSTRAINT_SCHEMA = '%1' AND TC.TABLE_NAME = '%2' AND TC.CONSTRAINT_TYPE = 'unique'" )
|
||||
.arg( mSchemaName, mTableName ) };
|
||||
if ( !LoggedExec( query, sql2 ) )
|
||||
{
|
||||
pushError( query.lastError().text() );
|
||||
return;
|
||||
}
|
||||
|
||||
while ( query.next() )
|
||||
{
|
||||
setColumnUnique.insert( query.value( QStringLiteral( "COLUMN_NAME" ) ).toString() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !query.exec( QStringLiteral( "exec sp_columns @table_name = N%1, @table_owner = %2" ).arg( quotedValue( mTableName ), quotedValue( mSchemaName ) ) ) )
|
||||
const QString sql3 { QStringLiteral( "exec sp_columns @table_name = N%1, @table_owner = %2" ).arg( quotedValue( mTableName ), quotedValue( mSchemaName ) ) };
|
||||
if ( !LoggedExec( query, sql3 ) )
|
||||
{
|
||||
pushError( query.lastError().text() );
|
||||
return;
|
||||
@ -504,7 +540,8 @@ void QgsMssqlProvider::loadFields()
|
||||
{
|
||||
query.clear();
|
||||
query.setForwardOnly( true );
|
||||
if ( !query.exec( QStringLiteral( "exec sp_pkeys @table_name = N%1, @table_owner = %2 " ).arg( quotedValue( mTableName ), quotedValue( mSchemaName ) ) ) )
|
||||
const QString sql4 { QStringLiteral( "exec sp_pkeys @table_name = N%1, @table_owner = %2 " ).arg( quotedValue( mTableName ), quotedValue( mSchemaName ) ) };
|
||||
if ( !LoggedExec( query, sql4 ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "SQL:%1\n Error:%2" ).arg( query.lastQuery(), query.lastError().text() ) );
|
||||
}
|
||||
@ -542,8 +579,9 @@ void QgsMssqlProvider::loadFields()
|
||||
{
|
||||
query.clear();
|
||||
query.setForwardOnly( true );
|
||||
if ( !query.exec( QStringLiteral( "select count(distinct [%1]), count([%1]) from [%2].[%3]" )
|
||||
.arg( pk, mSchemaName, mTableName ) ) )
|
||||
const QString sql5 { QStringLiteral( "select count(distinct [%1]), count([%1]) from [%2].[%3]" )
|
||||
.arg( pk, mSchemaName, mTableName ) };
|
||||
if ( !LoggedExec( query, sql5 ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "SQL:%1\n Error:%2" ).arg( query.lastQuery(), query.lastError().text() ) );
|
||||
}
|
||||
@ -636,7 +674,7 @@ QVariant QgsMssqlProvider::defaultValue( int fieldId ) const
|
||||
QSqlQuery query = createQuery();
|
||||
query.setForwardOnly( true );
|
||||
|
||||
if ( !query.exec( sql ) )
|
||||
if ( !LoggedExec( query, sql ) )
|
||||
{
|
||||
const QString errorMessage( tr( "Could not execute query: %1" ).arg( query.lastError().text() ) );
|
||||
QgsDebugMsg( errorMessage );
|
||||
@ -704,7 +742,7 @@ QVariant QgsMssqlProvider::minimumValue( int index ) const
|
||||
QSqlQuery query = createQuery();
|
||||
query.setForwardOnly( true );
|
||||
|
||||
if ( !query.exec( sql ) )
|
||||
if ( !LoggedExec( query, sql ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "SQL:%1\n Error:%2" ).arg( query.lastQuery(), query.lastError().text() ) );
|
||||
}
|
||||
@ -745,7 +783,7 @@ QVariant QgsMssqlProvider::maximumValue( int index ) const
|
||||
QSqlQuery query = createQuery();
|
||||
query.setForwardOnly( true );
|
||||
|
||||
if ( !query.exec( sql ) )
|
||||
if ( !LoggedExec( query, sql ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "SQL:%1\n Error:%2" ).arg( query.lastQuery(), query.lastError().text() ) );
|
||||
}
|
||||
@ -794,7 +832,7 @@ QSet<QVariant> QgsMssqlProvider::uniqueValues( int index, int limit ) const
|
||||
QSqlQuery query = createQuery();
|
||||
query.setForwardOnly( true );
|
||||
|
||||
if ( !query.exec( sql ) )
|
||||
if ( !LoggedExec( query, sql ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "SQL:%1\n Error:%2" ).arg( query.lastQuery(), query.lastError().text() ) );
|
||||
}
|
||||
@ -848,7 +886,7 @@ QStringList QgsMssqlProvider::uniqueStringsMatching( int index, const QString &s
|
||||
QSqlQuery query = createQuery();
|
||||
query.setForwardOnly( true );
|
||||
|
||||
if ( !query.exec( sql ) )
|
||||
if ( !LoggedExec( query, sql ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "SQL:%1\n Error:%2" ).arg( query.lastQuery(), query.lastError().text() ) );
|
||||
}
|
||||
@ -896,7 +934,7 @@ void QgsMssqlProvider::UpdateStatistics( bool estimate ) const
|
||||
|
||||
statement = QString( sql ).arg( mSchemaName, mTableName );
|
||||
|
||||
if ( query.exec( statement ) )
|
||||
if ( LoggedExec( query, statement ) )
|
||||
{
|
||||
if ( query.next() && ( !query.value( 0 ).isNull() ||
|
||||
!query.value( 1 ).isNull() ||
|
||||
@ -984,7 +1022,7 @@ void QgsMssqlProvider::UpdateStatistics( bool estimate ) const
|
||||
|
||||
const QString statementSample = statement + ( mSqlWhereClause.isEmpty() ? " WHERE " : " AND " ) + sampleFilter;
|
||||
|
||||
if ( query.exec( statementSample ) && query.next() &&
|
||||
if ( LoggedExec( query, statementSample ) && query.next() &&
|
||||
!query.value( 0 ).isNull() && query.value( 4 ).toInt() >= minSampleCount )
|
||||
{
|
||||
mExtent.setXMinimum( query.value( 0 ).toDouble() );
|
||||
@ -995,7 +1033,7 @@ void QgsMssqlProvider::UpdateStatistics( bool estimate ) const
|
||||
}
|
||||
}
|
||||
|
||||
if ( !query.exec( statement ) )
|
||||
if ( !LoggedExec( query, statement ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "SQL:%1\n Error:%2" ).arg( query.lastQuery(), query.lastError().text() ) );
|
||||
}
|
||||
@ -1074,7 +1112,7 @@ long long QgsMssqlProvider::featureCount() const
|
||||
" JOIN sys.partitions p ON t.object_id = p.object_id AND p.index_id IN (0,1)"
|
||||
" WHERE SCHEMA_NAME(t.schema_id) = %1 AND OBJECT_NAME(t.OBJECT_ID) = %2" ).arg( quotedValue( mSchemaName ), quotedValue( mTableName ) );
|
||||
|
||||
if ( query.exec( statement ) && query.next() )
|
||||
if ( LoggedExec( query, statement ) && query.next() )
|
||||
{
|
||||
return query.value( 0 ).toLongLong();
|
||||
}
|
||||
@ -1432,7 +1470,7 @@ bool QgsMssqlProvider::addAttributes( const QList<QgsField> &attributes )
|
||||
|
||||
QSqlQuery query = createQuery();
|
||||
query.setForwardOnly( true );
|
||||
if ( !query.exec( statement ) )
|
||||
if ( !LoggedExec( query, statement ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "SQL:%1\n Error:%2" ).arg( query.lastQuery(), query.lastError().text() ) );
|
||||
return false;
|
||||
@ -1465,13 +1503,14 @@ bool QgsMssqlProvider::deleteAttributes( const QgsAttributeIds &attributes )
|
||||
QSqlQuery query = createQuery();
|
||||
query.setForwardOnly( true );
|
||||
|
||||
if ( !query.exec( statement ) )
|
||||
if ( !LoggedExec( query, statement ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "SQL:%1\n Error:%2" ).arg( query.lastQuery(), query.lastError().text() ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
query.finish();
|
||||
|
||||
loadFields();
|
||||
|
||||
if ( mTransaction )
|
||||
@ -1732,7 +1771,8 @@ bool QgsMssqlProvider::deleteFeatures( const QgsFeatureIds &ids )
|
||||
query.setForwardOnly( true );
|
||||
|
||||
const QString statement = QStringLiteral( "DELETE FROM [%1].[%2] WHERE [%3] IN (%4)" ).arg( mSchemaName, mTableName, mAttributeFields.at( mPrimaryKeyAttrs[0] ).name(), featureIds );
|
||||
if ( query.exec( statement ) )
|
||||
|
||||
if ( LoggedExec( query, statement ) )
|
||||
{
|
||||
if ( query.numRowsAffected() == ids.size() )
|
||||
{
|
||||
@ -1744,7 +1784,9 @@ bool QgsMssqlProvider::deleteFeatures( const QgsFeatureIds &ids )
|
||||
pushError( tr( "Only %1 of %2 features deleted" ).arg( query.numRowsAffected() ).arg( ids.size() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
pushError( query.lastError().text() );
|
||||
}
|
||||
}
|
||||
else if ( mPrimaryKeyType == PktFidMap )
|
||||
{
|
||||
@ -1754,7 +1796,8 @@ bool QgsMssqlProvider::deleteFeatures( const QgsFeatureIds &ids )
|
||||
for ( QgsFeatureIds::const_iterator it = ids.begin(); it != ids.end(); ++it )
|
||||
{
|
||||
const QString statement = QStringLiteral( "DELETE FROM [%1].[%2] WHERE %3" ).arg( mSchemaName, mTableName, whereClauseFid( *it ) );
|
||||
if ( query.exec( statement ) )
|
||||
|
||||
if ( LoggedExec( query, statement ) )
|
||||
{
|
||||
if ( query.numRowsAffected() == 1 )
|
||||
{
|
||||
@ -1830,7 +1873,7 @@ bool QgsMssqlProvider::createSpatialIndex()
|
||||
statement += QLatin1String( " USING GEOGRAPHY_GRID" );
|
||||
}
|
||||
|
||||
if ( !query.exec( statement ) )
|
||||
if ( !LoggedExec( query, statement ) )
|
||||
{
|
||||
pushError( query.lastError().text() );
|
||||
return false;
|
||||
@ -1854,7 +1897,7 @@ bool QgsMssqlProvider::createAttributeIndex( int field )
|
||||
statement = QStringLiteral( "CREATE NONCLUSTERED INDEX [qgs_%1_idx] ON [%2].[%3] ( [%4] )" ).arg(
|
||||
mGeometryColName, mSchemaName, mTableName, mAttributeFields.at( field ).name() );
|
||||
|
||||
if ( !query.exec( statement ) )
|
||||
if ( !LoggedExec( query, statement ) )
|
||||
{
|
||||
pushError( query.lastError().text() );
|
||||
return false;
|
||||
@ -1870,7 +1913,9 @@ QgsCoordinateReferenceSystem QgsMssqlProvider::crs() const
|
||||
// try to load crs from the database tables as a fallback
|
||||
QSqlQuery query = createQuery();
|
||||
query.setForwardOnly( true );
|
||||
bool execOk = query.exec( QStringLiteral( "SELECT srtext FROM spatial_ref_sys WHERE srid=%1" ).arg( mSRId ) );
|
||||
const QString statement { QStringLiteral( "SELECT srtext FROM spatial_ref_sys WHERE srid=%1" ).arg( mSRId ) };
|
||||
|
||||
bool execOk = LoggedExec( query, statement );
|
||||
if ( execOk && query.isActive() )
|
||||
{
|
||||
if ( query.next() )
|
||||
@ -1886,7 +1931,7 @@ QgsCoordinateReferenceSystem QgsMssqlProvider::crs() const
|
||||
query.setForwardOnly( true );
|
||||
|
||||
// Look in the system reference table for the data if we can't find it yet
|
||||
execOk = query.exec( QStringLiteral( "SELECT well_known_text FROM sys.spatial_reference_systems WHERE spatial_reference_id=%1" ).arg( mSRId ) );
|
||||
execOk = LoggedExec( query, QStringLiteral( "SELECT well_known_text FROM sys.spatial_reference_systems WHERE spatial_reference_id=%1" ).arg( mSRId ) );
|
||||
if ( execOk && query.isActive() && query.next() )
|
||||
{
|
||||
mCrs = QgsCoordinateReferenceSystem::fromWkt( query.value( 0 ).toString() );
|
||||
@ -1949,7 +1994,7 @@ bool QgsMssqlProvider::setSubsetString( const QString &theSQL, bool )
|
||||
|
||||
QSqlQuery query = createQuery();
|
||||
query.setForwardOnly( true );
|
||||
if ( !query.exec( sql ) )
|
||||
if ( !LoggedExec( query, sql ) )
|
||||
{
|
||||
pushError( query.lastError().text() );
|
||||
mSqlWhereClause = prevWhere;
|
||||
@ -2202,8 +2247,12 @@ Qgis::VectorExportResult QgsMssqlProvider::createEmptyLayer( const QString &uri,
|
||||
"WHERE object_id = OBJECT_ID(N'[dbo].[spatial_ref_sys]') AND type in (N'U')) "
|
||||
"CREATE TABLE spatial_ref_sys (srid integer not null "
|
||||
"PRIMARY KEY, auth_name varchar(256), auth_srid integer, srtext varchar(2048), proj4text varchar(2048))" );
|
||||
|
||||
std::unique_ptr <QgsDatabaseQueryLogWrapper> logWrapper = std::make_unique<QgsDatabaseQueryLogWrapper>( sql, uri, QStringLiteral( "mssql" ), QStringLiteral( "QgsMssqlProvider" ), QGS_QUERY_LOG_ORIGIN );
|
||||
|
||||
if ( !q.exec( sql ) )
|
||||
{
|
||||
logWrapper->setError( q.lastError().text() );
|
||||
if ( errorMessage )
|
||||
*errorMessage = q.lastError().text();
|
||||
return Qgis::VectorExportResult::ErrorCreatingLayer;
|
||||
@ -2228,8 +2277,12 @@ Qgis::VectorExportResult QgsMssqlProvider::createEmptyLayer( const QString &uri,
|
||||
auth_srid,
|
||||
quotedValue( srs.toWkt() ),
|
||||
quotedValue( srs.toProj() ) );
|
||||
|
||||
logWrapper.reset( new QgsDatabaseQueryLogWrapper( sql, uri, QStringLiteral( "mssql" ), QStringLiteral( "QgsMssqlProvider" ), QGS_QUERY_LOG_ORIGIN ) );
|
||||
|
||||
if ( !q.exec( sql ) )
|
||||
{
|
||||
logWrapper->setError( q.lastError().text() );
|
||||
if ( errorMessage )
|
||||
*errorMessage = q.lastError().text();
|
||||
return Qgis::VectorExportResult::ErrorCreatingLayer;
|
||||
@ -2246,8 +2299,12 @@ Qgis::VectorExportResult QgsMssqlProvider::createEmptyLayer( const QString &uri,
|
||||
// remove the old table with the same name
|
||||
sql = QStringLiteral( "IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[%1].[%2]') AND type in (N'U')) BEGIN DROP TABLE [%1].[%2] DELETE FROM geometry_columns where f_table_schema='%1' and f_table_name='%2' END;" )
|
||||
.arg( schemaName, tableName );
|
||||
|
||||
logWrapper.reset( new QgsDatabaseQueryLogWrapper( sql, uri, QStringLiteral( "mssql" ), QStringLiteral( "QgsMssqlProvider" ), QGS_QUERY_LOG_ORIGIN ) );
|
||||
|
||||
if ( !q.exec( sql ) )
|
||||
{
|
||||
logWrapper->setError( q.lastError().text() );
|
||||
if ( errorMessage )
|
||||
*errorMessage = q.lastError().text();
|
||||
return Qgis::VectorExportResult::ErrorCreatingLayer;
|
||||
@ -2258,8 +2315,12 @@ Qgis::VectorExportResult QgsMssqlProvider::createEmptyLayer( const QString &uri,
|
||||
// test for existing
|
||||
sql = QStringLiteral( "SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[%1].[%2]') AND type in (N'U')" )
|
||||
.arg( schemaName, tableName );
|
||||
|
||||
logWrapper.reset( new QgsDatabaseQueryLogWrapper( sql, uri, QStringLiteral( "mssql" ), QStringLiteral( "QgsMssqlProvider" ), QGS_QUERY_LOG_ORIGIN ) );
|
||||
|
||||
if ( !q.exec( sql ) )
|
||||
{
|
||||
logWrapper->setError( q.lastError().text() );
|
||||
if ( errorMessage )
|
||||
*errorMessage = q.lastError().text();
|
||||
return Qgis::VectorExportResult::ErrorCreatingLayer;
|
||||
@ -2276,11 +2337,11 @@ Qgis::VectorExportResult QgsMssqlProvider::createEmptyLayer( const QString &uri,
|
||||
|
||||
if ( !geometryColumn.isEmpty() )
|
||||
{
|
||||
sql = QString( "IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[%1].[%2]') AND type in (N'U')) DROP TABLE [%1].[%2]\n"
|
||||
"CREATE TABLE [%1].[%2]([%3] [int] IDENTITY(1,1) NOT NULL, [%4] [geometry] NULL CONSTRAINT [PK_%2] PRIMARY KEY CLUSTERED ( [%3] ASC ))\n"
|
||||
"DELETE FROM geometry_columns WHERE f_table_schema = '%1' AND f_table_name = '%2'\n"
|
||||
"INSERT INTO [geometry_columns] ([f_table_catalog], [f_table_schema],[f_table_name], "
|
||||
"[f_geometry_column],[coord_dimension],[srid],[geometry_type]) VALUES ('%5', '%1', '%2', '%4', %6, %7, '%8')" )
|
||||
sql = QStringLiteral( "IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[%1].[%2]') AND type in (N'U')) DROP TABLE [%1].[%2]\n"
|
||||
"CREATE TABLE [%1].[%2]([%3] [int] IDENTITY(1,1) NOT NULL, [%4] [geometry] NULL CONSTRAINT [PK_%2] PRIMARY KEY CLUSTERED ( [%3] ASC ))\n"
|
||||
"DELETE FROM geometry_columns WHERE f_table_schema = '%1' AND f_table_name = '%2'\n"
|
||||
"INSERT INTO [geometry_columns] ([f_table_catalog], [f_table_schema],[f_table_name], "
|
||||
"[f_geometry_column],[coord_dimension],[srid],[geometry_type]) VALUES ('%5', '%1', '%2', '%4', %6, %7, '%8')" )
|
||||
.arg( schemaName,
|
||||
tableName,
|
||||
primaryKey,
|
||||
@ -2293,17 +2354,20 @@ Qgis::VectorExportResult QgsMssqlProvider::createEmptyLayer( const QString &uri,
|
||||
else
|
||||
{
|
||||
//geometryless table
|
||||
sql = QString( "IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[%1].[%2]') AND type in (N'U')) DROP TABLE [%1].[%2]\n"
|
||||
"CREATE TABLE [%1].[%2]([%3] [int] IDENTITY(1,1) NOT NULL CONSTRAINT [PK_%2] PRIMARY KEY CLUSTERED ( [%3] ASC ))\n"
|
||||
"DELETE FROM geometry_columns WHERE f_table_schema = '%1' AND f_table_name = '%2'\n"
|
||||
)
|
||||
sql = QStringLiteral( "IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[%1].[%2]') AND type in (N'U')) DROP TABLE [%1].[%2]\n"
|
||||
"CREATE TABLE [%1].[%2]([%3] [int] IDENTITY(1,1) NOT NULL CONSTRAINT [PK_%2] PRIMARY KEY CLUSTERED ( [%3] ASC ))\n"
|
||||
"DELETE FROM geometry_columns WHERE f_table_schema = '%1' AND f_table_name = '%2'\n"
|
||||
)
|
||||
.arg( schemaName,
|
||||
tableName,
|
||||
primaryKey );
|
||||
}
|
||||
|
||||
logWrapper.reset( new QgsDatabaseQueryLogWrapper( sql, uri, QStringLiteral( "mssql" ), QStringLiteral( "QgsMssqlProvider" ), QGS_QUERY_LOG_ORIGIN ) );
|
||||
|
||||
if ( !q.exec( sql ) )
|
||||
{
|
||||
logWrapper->setError( q.lastError().text() );
|
||||
if ( errorMessage )
|
||||
*errorMessage = q.lastError().text();
|
||||
return Qgis::VectorExportResult::ErrorCreatingLayer;
|
||||
@ -2462,7 +2526,9 @@ bool QgsMssqlProviderMetadata::styleExists( const QString &uri, const QString &s
|
||||
|
||||
QSqlQuery query = QSqlQuery( db->db() );
|
||||
query.setForwardOnly( true );
|
||||
if ( !query.exec( QStringLiteral( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'layer_styles'" ) ) )
|
||||
const QString sql { QStringLiteral( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'layer_styles'" ) };
|
||||
|
||||
if ( !LoggedExecMetadata( query, sql, uri ) )
|
||||
{
|
||||
errorCause = QObject::tr( "Could not check if layer_styles table exists: %1" ).arg( query.lastError().text() );
|
||||
return false;
|
||||
@ -2489,7 +2555,7 @@ bool QgsMssqlProviderMetadata::styleExists( const QString &uri, const QString &s
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.geometryColumn() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( styleId.isEmpty() ? dsUri.table() : styleId ) );
|
||||
|
||||
if ( !query.exec( checkQuery ) )
|
||||
if ( !LoggedExecMetadata( query, checkQuery, uri ) )
|
||||
{
|
||||
errorCause = QObject::tr( "Checking for style failed: %1" ).arg( query.lastError().text() );
|
||||
return false;
|
||||
@ -2527,7 +2593,10 @@ bool QgsMssqlProviderMetadata::saveStyle( const QString &uri,
|
||||
|
||||
QSqlQuery query = QSqlQuery( db->db() );
|
||||
query.setForwardOnly( true );
|
||||
if ( !query.exec( QStringLiteral( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= N'layer_styles'" ) ) )
|
||||
|
||||
QString sql { QStringLiteral( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= N'layer_styles'" ) };
|
||||
|
||||
if ( !LoggedExecMetadata( query, sql, uri ) )
|
||||
{
|
||||
QgsDebugMsg( query.lastError().text() );
|
||||
return false;
|
||||
@ -2535,24 +2604,28 @@ bool QgsMssqlProviderMetadata::saveStyle( const QString &uri,
|
||||
if ( query.isActive() && query.next() && query.value( 0 ).toInt() == 0 )
|
||||
{
|
||||
QgsDebugMsgLevel( QStringLiteral( "Need to create styles table" ), 2 );
|
||||
const bool execOk = query.exec( QString( "CREATE TABLE [dbo].[layer_styles]("
|
||||
"[id] int IDENTITY(1,1) PRIMARY KEY,"
|
||||
"[f_table_catalog] [varchar](1024) NULL,"
|
||||
"[f_table_schema] [varchar](1024) NULL,"
|
||||
"[f_table_name] [varchar](1024) NULL,"
|
||||
"[f_geometry_column] [varchar](1024) NULL,"
|
||||
"[styleName] [varchar](1024) NULL,"
|
||||
"[styleQML] [text] NULL,"
|
||||
"[styleSLD] [text] NULL,"
|
||||
"[useAsDefault] [int] NULL,"
|
||||
"[description] [text] NULL,"
|
||||
"[owner] [varchar](1024) NULL,"
|
||||
"[ui] [text] NULL,"
|
||||
"[update_time] [datetime] NULL"
|
||||
") ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]" ) );
|
||||
|
||||
sql = QStringLiteral( "CREATE TABLE [dbo].[layer_styles]("
|
||||
"[id] int IDENTITY(1,1) PRIMARY KEY,"
|
||||
"[f_table_catalog] [varchar](1024) NULL,"
|
||||
"[f_table_schema] [varchar](1024) NULL,"
|
||||
"[f_table_name] [varchar](1024) NULL,"
|
||||
"[f_geometry_column] [varchar](1024) NULL,"
|
||||
"[styleName] [varchar](1024) NULL,"
|
||||
"[styleQML] [text] NULL,"
|
||||
"[styleSLD] [text] NULL,"
|
||||
"[useAsDefault] [int] NULL,"
|
||||
"[description] [text] NULL,"
|
||||
"[owner] [varchar](1024) NULL,"
|
||||
"[ui] [text] NULL,"
|
||||
"[update_time] [datetime] NULL"
|
||||
") ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]" );
|
||||
|
||||
const bool execOk = LoggedExecMetadata( query, sql, uri );
|
||||
if ( !execOk )
|
||||
{
|
||||
errCause = QObject::tr( "Unable to save layer style. It's not possible to create the destination table on the database. Maybe this is due to table permissions. Please contact your database admin" );
|
||||
const QString error { QObject::tr( "Unable to save layer style. It's not possible to create the destination table on the database. Maybe this is due to table permissions. Please contact your database admin" ) };
|
||||
errCause = error;
|
||||
return false;
|
||||
}
|
||||
query.finish();
|
||||
@ -2573,38 +2646,38 @@ bool QgsMssqlProviderMetadata::saveStyle( const QString &uri,
|
||||
// replaced by the QString.arg function. To ensure that the final SQL string is not corrupt these
|
||||
// two values are both replaced in the final .arg call of the string construction.
|
||||
|
||||
QString sql = QString( "INSERT INTO layer_styles"
|
||||
"(f_table_catalog,f_table_schema,f_table_name,f_geometry_column,styleName,styleQML,styleSLD,useAsDefault,description,owner%11"
|
||||
") VALUES ("
|
||||
"%1,%2,%3,%4,%5,%6,%7,%8,%9,%10%12"
|
||||
")" )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.database() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.schema() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.table() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.geometryColumn() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( styleName.isEmpty() ? dsUri.table() : styleName ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( qmlStyle ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( sldStyle ) )
|
||||
.arg( useAsDefault ? QStringLiteral( "1" ) : QStringLiteral( "0" ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( styleDescription.isEmpty() ? QDateTime::currentDateTime().toString() : styleDescription ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.username() ) )
|
||||
.arg( uiFileColumn )
|
||||
.arg( uiFileValue );
|
||||
sql = QStringLiteral( "INSERT INTO layer_styles"
|
||||
"(f_table_catalog,f_table_schema,f_table_name,f_geometry_column,styleName,styleQML,styleSLD,useAsDefault,description,owner%11"
|
||||
") VALUES ("
|
||||
"%1,%2,%3,%4,%5,%6,%7,%8,%9,%10%12"
|
||||
")" )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.database() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.schema() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.table() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.geometryColumn() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( styleName.isEmpty() ? dsUri.table() : styleName ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( qmlStyle ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( sldStyle ) )
|
||||
.arg( useAsDefault ? QStringLiteral( "1" ) : QStringLiteral( "0" ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( styleDescription.isEmpty() ? QDateTime::currentDateTime().toString() : styleDescription ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.username() ) )
|
||||
.arg( uiFileColumn )
|
||||
.arg( uiFileValue );
|
||||
|
||||
const QString checkQuery = QString( "SELECT styleName"
|
||||
" FROM layer_styles"
|
||||
" WHERE f_table_catalog=%1"
|
||||
" AND f_table_schema=%2"
|
||||
" AND f_table_name=%3"
|
||||
" AND f_geometry_column=%4"
|
||||
" AND styleName=%5" )
|
||||
const QString checkQuery = QStringLiteral( "SELECT styleName"
|
||||
" FROM layer_styles"
|
||||
" WHERE f_table_catalog=%1"
|
||||
" AND f_table_schema=%2"
|
||||
" AND f_table_name=%3"
|
||||
" AND f_geometry_column=%4"
|
||||
" AND styleName=%5" )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.database() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.schema() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.table() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.geometryColumn() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( styleName.isEmpty() ? dsUri.table() : styleName ) );
|
||||
|
||||
if ( !query.exec( checkQuery ) )
|
||||
if ( !LoggedExecMetadata( query, checkQuery, uri ) )
|
||||
{
|
||||
QgsDebugMsg( query.lastError().text() );
|
||||
QgsDebugMsg( QStringLiteral( "Check Query failed" ) );
|
||||
@ -2652,7 +2725,8 @@ bool QgsMssqlProviderMetadata::saveStyle( const QString &uri,
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "Inserting styles" ), 2 );
|
||||
QgsDebugMsgLevel( sql, 2 );
|
||||
const bool execOk = query.exec( sql );
|
||||
|
||||
const bool execOk = LoggedExecMetadata( query, sql, uri );
|
||||
|
||||
if ( !execOk )
|
||||
{
|
||||
@ -2677,8 +2751,12 @@ QString QgsMssqlProviderMetadata::loadStyle( const QString &uri, QString &errCau
|
||||
}
|
||||
|
||||
QSqlQuery query = QSqlQuery( db->db() );
|
||||
|
||||
query.setForwardOnly( true );
|
||||
if ( !query.exec( QStringLiteral( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= N'layer_styles'" ) ) )
|
||||
|
||||
const QString sql { QStringLiteral( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= N'layer_styles'" ) };
|
||||
|
||||
if ( !LoggedExecMetadata( query, sql, uri ) )
|
||||
{
|
||||
errCause = tr( "Could not check if layer_styles table exists: %1" ).arg( query.lastError().text() );
|
||||
return QString();
|
||||
@ -2706,7 +2784,7 @@ QString QgsMssqlProviderMetadata::loadStyle( const QString &uri, QString &errCau
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.table() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.geometryColumn() ) );
|
||||
|
||||
if ( !query.exec( selectQmlQuery ) )
|
||||
if ( !LoggedExecMetadata( query, selectQmlQuery, uri ) )
|
||||
{
|
||||
QgsDebugMsgLevel( QStringLiteral( "Load of style failed" ), 2 );
|
||||
const QString msg = query.lastError().text();
|
||||
@ -2742,8 +2820,10 @@ int QgsMssqlProviderMetadata::listStyles( const QString &uri,
|
||||
QSqlQuery query = QSqlQuery( db->db() );
|
||||
query.setForwardOnly( true );
|
||||
|
||||
QString sql { QStringLiteral( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= N'layer_styles'" ) };
|
||||
|
||||
// check if layer_styles table already exist
|
||||
if ( !query.exec( QStringLiteral( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= N'layer_styles'" ) ) )
|
||||
if ( !LoggedExecMetadata( query, sql, uri ) )
|
||||
{
|
||||
const QString msg = query.lastError().text();
|
||||
errCause = msg;
|
||||
@ -2767,7 +2847,9 @@ int QgsMssqlProviderMetadata::listStyles( const QString &uri,
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.schema() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.table() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.geometryColumn() ) );
|
||||
bool queryOk = query.exec( selectRelatedQuery );
|
||||
|
||||
|
||||
bool queryOk = LoggedExecMetadata( query, selectRelatedQuery, uri );
|
||||
if ( !queryOk )
|
||||
{
|
||||
QgsDebugMsg( query.lastError().text() );
|
||||
@ -2791,7 +2873,8 @@ int QgsMssqlProviderMetadata::listStyles( const QString &uri,
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.table() ) )
|
||||
.arg( QgsMssqlProvider::quotedValue( dsUri.geometryColumn() ) );
|
||||
QgsDebugMsgLevel( selectOthersQuery, 2 );
|
||||
queryOk = query.exec( selectOthersQuery );
|
||||
|
||||
queryOk = LoggedExecMetadata( query, selectOthersQuery, uri );
|
||||
if ( !queryOk )
|
||||
{
|
||||
QgsDebugMsg( query.lastError().text() );
|
||||
@ -2828,7 +2911,9 @@ QString QgsMssqlProviderMetadata::getStyleById( const QString &uri, const QStrin
|
||||
QSqlQuery query = QSqlQuery( db->db() );
|
||||
query.setForwardOnly( true );
|
||||
|
||||
if ( !query.exec( QStringLiteral( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= N'layer_styles'" ) ) )
|
||||
const QString sql { QStringLiteral( "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME= N'layer_styles'" ) };
|
||||
|
||||
if ( !LoggedExecMetadata( query, sql, uri ) )
|
||||
{
|
||||
errCause = tr( "Could not check if layer_styles table exists: %1" ).arg( query.lastError().text() );
|
||||
return QString();
|
||||
@ -2846,7 +2931,8 @@ QString QgsMssqlProviderMetadata::getStyleById( const QString &uri, const QStrin
|
||||
|
||||
QString style;
|
||||
const QString selectQmlQuery = QStringLiteral( "SELECT styleQml FROM layer_styles WHERE id=%1" ).arg( QgsMssqlProvider::quotedValue( styleId ) );
|
||||
const bool queryOk = query.exec( selectQmlQuery );
|
||||
|
||||
const bool queryOk = LoggedExecMetadata( query, selectQmlQuery, uri );
|
||||
if ( !queryOk )
|
||||
{
|
||||
QgsDebugMsg( query.lastError().text() );
|
||||
@ -2995,6 +3081,29 @@ QString QgsMssqlProviderMetadata::encodeUri( const QVariantMap &parts ) const
|
||||
return dsUri.uri();
|
||||
}
|
||||
|
||||
bool QgsMssqlProviderMetadata::execLogged( QSqlQuery &qry, const QString &sql, const QString &uri, const QString &queryOrigin ) const
|
||||
{
|
||||
QgsDatabaseQueryLogWrapper logWrapper{ sql, uri, QStringLiteral( "mssql" ), QStringLiteral( "QgsMssqlProviderMetadata" ), queryOrigin };
|
||||
const bool res { qry.exec( sql ) };
|
||||
if ( ! res )
|
||||
{
|
||||
logWrapper.setError( qry.lastError().text() );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( qry.isSelect() )
|
||||
{
|
||||
logWrapper.setFetchedRows( qry.size() );
|
||||
}
|
||||
else
|
||||
{
|
||||
logWrapper.setFetchedRows( qry.numRowsAffected() );
|
||||
}
|
||||
}
|
||||
logWrapper.setQuery( qry.lastQuery() );
|
||||
return res;
|
||||
}
|
||||
|
||||
QGISEXTERN QgsProviderMetadata *providerMetadataFactory()
|
||||
{
|
||||
return new QgsMssqlProviderMetadata();
|
||||
@ -3156,7 +3265,8 @@ bool QgsMssqlProvider::getExtentFromGeometryColumns( QgsRectangle &extent ) cons
|
||||
"AND NOT (qgis_xmin IS NULL OR qgis_xmax IS NULL OR qgis_ymin IS NULL OR qgis_ymax IS NULL)" );
|
||||
|
||||
const QString statement = sql.arg( quotedValue( mTableName ), quotedValue( mSchemaName ) );
|
||||
if ( query.exec( statement ) && query.isActive() )
|
||||
|
||||
if ( LoggedExec( query, statement ) && query.isActive() )
|
||||
{
|
||||
query.next();
|
||||
if ( query.isValid() )
|
||||
@ -3182,7 +3292,8 @@ bool QgsMssqlProvider::getPrimaryKeyFromGeometryColumns( QStringList &primaryKey
|
||||
|
||||
const QString sql = QStringLiteral( "SELECT qgis_pkey FROM geometry_columns WHERE f_table_name = '%1' AND NOT qgis_pkey IS NULL" );
|
||||
const QString statement = sql.arg( mTableName );
|
||||
if ( query.exec( statement ) && query.isActive() )
|
||||
|
||||
if ( LoggedExec( query, statement ) && query.isActive() )
|
||||
{
|
||||
query.next();
|
||||
if ( query.isValid() )
|
||||
|
||||
@ -176,6 +176,8 @@ class QgsMssqlProvider final: public QgsVectorDataProvider
|
||||
|
||||
private:
|
||||
|
||||
bool execLogged( QSqlQuery &qry, const QString &sql, const QString &queryOrigin = QString() ) const;
|
||||
|
||||
//! Fields
|
||||
QgsFields mAttributeFields;
|
||||
QMap<int, QString> mDefaultValues;
|
||||
@ -328,6 +330,10 @@ class QgsMssqlProviderMetadata final: public QgsProviderMetadata
|
||||
QVariantMap decodeUri( const QString &uri ) const override;
|
||||
QString encodeUri( const QVariantMap &parts ) const override;
|
||||
|
||||
private:
|
||||
|
||||
bool execLogged( QSqlQuery &qry, const QString &sql, const QString &uri, const QString &queryOrigin = QString() ) const;
|
||||
|
||||
};
|
||||
|
||||
#endif // QGSMSSQLPROVIDER_H
|
||||
|
||||
@ -27,6 +27,8 @@
|
||||
#include "qgsvariantutils.h"
|
||||
|
||||
#include <QSqlError>
|
||||
#include <QSqlField>
|
||||
#include <QSqlDriver>
|
||||
|
||||
QMap<QString, QgsOracleConn *> QgsOracleConn::sConnections;
|
||||
int QgsOracleConn::snConnections = 0;
|
||||
@ -71,7 +73,8 @@ QgsOracleConn::QgsOracleConn( QgsDataSourceUri uri, bool transaction )
|
||||
{
|
||||
QgsDebugMsgLevel( QStringLiteral( "New Oracle connection for " ) + uri.connectionInfo( false ), 2 );
|
||||
|
||||
uri = QgsDataSourceUri( uri.connectionInfo( true ) );
|
||||
mConnInfo = uri.connectionInfo( true );
|
||||
uri = QgsDataSourceUri( mConnInfo );
|
||||
|
||||
QString database = databaseName( uri.database(), uri.host(), uri.port() );
|
||||
QgsDebugMsgLevel( QStringLiteral( "New Oracle database " ) + database, 2 );
|
||||
@ -226,6 +229,29 @@ void QgsOracleConn::unref()
|
||||
delete this;
|
||||
}
|
||||
|
||||
QString QgsOracleConn::getLastExecutedQuery( const QSqlQuery &query )
|
||||
{
|
||||
QString str = query.lastQuery();
|
||||
QMapIterator<QString, QVariant> it( query.boundValues() );
|
||||
while ( it.hasNext() )
|
||||
{
|
||||
it.next();
|
||||
const QVariant &var { it.value().toString() };
|
||||
QSqlField field( QString( ), var.type() );
|
||||
if ( var.isNull() )
|
||||
{
|
||||
field.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
field.setValue( var );
|
||||
}
|
||||
const QString formatV = query.driver()->formatValue( field );
|
||||
str.replace( it.key(), formatV );
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
bool QgsOracleConn::exec( QSqlQuery &qry, const QString &sql, const QVariantList ¶ms )
|
||||
{
|
||||
QgsDebugMsgLevel( QStringLiteral( "SQL: %1" ).arg( sql ), 4 );
|
||||
@ -249,6 +275,49 @@ bool QgsOracleConn::exec( QSqlQuery &qry, const QString &sql, const QVariantList
|
||||
qry.lastError().text() ) );
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
bool QgsOracleConn::execLogged( QSqlQuery &qry, const QString &sql, const QVariantList ¶ms, const QString &originatorClass, const QString &queryOrigin )
|
||||
{
|
||||
QgsDebugMsgLevel( QStringLiteral( "SQL: %1" ).arg( sql ), 4 );
|
||||
|
||||
QgsDatabaseQueryLogWrapper logWrapper { sql, mConnInfo, QStringLiteral( "oracle" ), originatorClass, queryOrigin };
|
||||
|
||||
bool res = qry.prepare( sql );
|
||||
if ( res )
|
||||
{
|
||||
for ( const auto ¶m : params )
|
||||
{
|
||||
QgsDebugMsgLevel( QStringLiteral( " ARG: %1 [%2]" ).arg( param.toString(), param.typeName() ), 4 );
|
||||
qry.addBindValue( param );
|
||||
}
|
||||
|
||||
res = qry.exec();
|
||||
}
|
||||
|
||||
logWrapper.setQuery( getLastExecutedQuery( qry ) );
|
||||
|
||||
if ( !res )
|
||||
{
|
||||
logWrapper.setError( qry.lastError().text() );
|
||||
QgsDebugMsg( QStringLiteral( "SQL: %1\nERROR: %2" )
|
||||
.arg( qry.lastQuery(),
|
||||
qry.lastError().text() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( qry.isSelect() )
|
||||
{
|
||||
logWrapper.setFetchedRows( qry.size() );
|
||||
}
|
||||
else
|
||||
{
|
||||
logWrapper.setFetchedRows( qry.numRowsAffected() );
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -257,10 +326,12 @@ QStringList QgsOracleConn::pkCandidates( const QString &ownerName, const QString
|
||||
QStringList cols;
|
||||
|
||||
QSqlQuery qry( mDatabase );
|
||||
if ( !exec( qry, QStringLiteral( "SELECT column_name FROM all_tab_columns WHERE owner=? AND table_name=? ORDER BY column_id" ),
|
||||
QVariantList() << ownerName << viewName ) )
|
||||
|
||||
if ( !LoggedExecPrivate( QStringLiteral( "QgsOracleConn" ), qry, QStringLiteral( "SELECT column_name FROM all_tab_columns WHERE owner=? AND table_name=? ORDER BY column_id" ),
|
||||
QVariantList() << ownerName << viewName ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "SQL: %1 [owner: %2 table_name: %3]\nerror: %4\n" ).arg( qry.lastQuery(), qry.lastError().text(), ownerName, viewName ), tr( "Oracle" ) );
|
||||
const QString error { tr( "SQL: %1 [owner: %2 table_name: %3]\nerror: %4\n" ).arg( qry.lastQuery(), qry.lastError().text(), ownerName, viewName ) };
|
||||
QgsMessageLog::logMessage( error, tr( "Oracle" ) );
|
||||
return cols;
|
||||
}
|
||||
|
||||
@ -308,9 +379,11 @@ bool QgsOracleConn::tableInfo( const QString &schema, bool geometryColumnsOnly,
|
||||
}
|
||||
|
||||
QSqlQuery qry( mDatabase );
|
||||
if ( !exec( qry, sql, QVariantList() ) )
|
||||
|
||||
if ( !LoggedExecPrivate( QStringLiteral( "QgsOracleConn" ), qry, sql, QVariantList() ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Querying available tables failed.\nSQL: %1\nerror: %2\n" ).arg( qry.lastQuery(), qry.lastError().text() ), tr( "Oracle" ) );
|
||||
const QString error { tr( "Querying available tables failed.\nSQL: %1\nerror: %2\n" ).arg( qry.lastQuery(), qry.lastError().text() ) };
|
||||
QgsMessageLog::logMessage( error, tr( "Oracle" ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -326,8 +399,10 @@ bool QgsOracleConn::tableInfo( const QString &schema, bool geometryColumnsOnly,
|
||||
layerProperty.pkCols.clear();
|
||||
|
||||
mLayersSupported << layerProperty;
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ( mLayersSupported.size() == 0 )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Database connection was successful, but the accessible tables could not be determined." ), tr( "Oracle" ) );
|
||||
@ -417,19 +492,22 @@ bool QgsOracleConn::exec( const QString &query, bool logError, QString *errorMes
|
||||
QgsDebugMsgLevel( QStringLiteral( "Executing SQL: %1" ).arg( query ), 3 );
|
||||
|
||||
QSqlQuery qry( mDatabase );
|
||||
|
||||
if ( !exec( qry, query, QVariantList() ) )
|
||||
{
|
||||
QString error = qry.lastError().text();
|
||||
if ( logError )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Connection error: %1 returned %2" )
|
||||
.arg( query, error ),
|
||||
const QString errorMsg { tr( "Connection error: %1 returned %2" )
|
||||
.arg( query, error ) };
|
||||
QgsMessageLog::logMessage( errorMsg,
|
||||
tr( "Oracle" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Connection error: %1 returned %2" )
|
||||
.arg( query, error ) );
|
||||
const QString errorMsg { QStringLiteral( "Connection error: %1 returned %2" )
|
||||
.arg( query, error ) };
|
||||
QgsDebugMsg( errorMsg );
|
||||
}
|
||||
if ( errorMessage )
|
||||
*errorMessage = error;
|
||||
@ -438,12 +516,62 @@ bool QgsOracleConn::exec( const QString &query, bool logError, QString *errorMes
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsOracleConn::execLogged( const QString &query, bool logError, QString *errorMessage, const QString &originatorClass, const QString &queryOrigin )
|
||||
{
|
||||
|
||||
QMutexLocker locker( &mLock );
|
||||
QgsDatabaseQueryLogWrapper logWrapper { query, mConnInfo, QStringLiteral( "oracle" ), originatorClass, queryOrigin };
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "Executing SQL: %1" ).arg( query ), 3 );
|
||||
|
||||
QSqlQuery qry( mDatabase );
|
||||
|
||||
const bool res { !exec( qry, query, QVariantList() ) };
|
||||
|
||||
logWrapper.setQuery( qry.lastQuery() );
|
||||
|
||||
if ( ! res )
|
||||
{
|
||||
const QString error = qry.lastError().text();
|
||||
logWrapper.setError( error );
|
||||
if ( logError )
|
||||
{
|
||||
const QString errorMsg { tr( "Connection error: %1 returned %2" )
|
||||
.arg( query, error ) };
|
||||
QgsMessageLog::logMessage( errorMsg,
|
||||
tr( "Oracle" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
const QString errorMsg { QStringLiteral( "Connection error: %1 returned %2" )
|
||||
.arg( query, error ) };
|
||||
QgsDebugMsg( errorMsg );
|
||||
}
|
||||
if ( errorMessage )
|
||||
*errorMessage = error;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( qry.isSelect() )
|
||||
{
|
||||
logWrapper.setFetchedRows( qry.size() );
|
||||
}
|
||||
else
|
||||
{
|
||||
logWrapper.setFetchedRows( qry.numRowsAffected() );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsOracleConn::begin( QSqlDatabase &db )
|
||||
{
|
||||
QMutexLocker locker( &mLock );
|
||||
if ( mTransaction )
|
||||
{
|
||||
return exec( QStringLiteral( "SAVEPOINT sp%1" ).arg( ++mSavePointId ) );
|
||||
return LoggedExec( QStringLiteral( "QgsOracleConn" ), QStringLiteral( "SAVEPOINT sp%1" ).arg( ++mSavePointId ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -456,7 +584,7 @@ bool QgsOracleConn::commit( QSqlDatabase &db )
|
||||
QMutexLocker locker( &mLock );
|
||||
if ( mTransaction )
|
||||
{
|
||||
return exec( QStringLiteral( "SAVEPOINT sp%1" ).arg( ++mSavePointId ) );
|
||||
return LoggedExec( QStringLiteral( "QgsOracleConn" ), QStringLiteral( "SAVEPOINT sp%1" ).arg( ++mSavePointId ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -469,7 +597,7 @@ bool QgsOracleConn::rollback( QSqlDatabase &db )
|
||||
QMutexLocker locker( &mLock );
|
||||
if ( mTransaction )
|
||||
{
|
||||
return exec( QStringLiteral( "ROLLBACK TO SAVEPOINT sp%1" ).arg( mSavePointId ) );
|
||||
return LoggedExec( QStringLiteral( "QgsOracleConn" ), QStringLiteral( "ROLLBACK TO SAVEPOINT sp%1" ).arg( mSavePointId ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -581,14 +709,15 @@ void QgsOracleConn::retrieveLayerTypes( QgsOracleLayerProperty &layerProperty, b
|
||||
|
||||
sql += QLatin1String( " FROM %2 t WHERE NOT t.%1 IS NULL%3" );
|
||||
|
||||
if ( !exec( qry, sql
|
||||
.arg( quotedIdentifier( layerProperty.geometryColName ),
|
||||
table,
|
||||
where.isEmpty() ? QString() : QStringLiteral( " AND (%1)" ).arg( where ) ), QVariantList() ) )
|
||||
if ( !LoggedExecPrivate( QStringLiteral( "QgsOracleConn" ), qry, sql
|
||||
.arg( quotedIdentifier( layerProperty.geometryColName ),
|
||||
table,
|
||||
where.isEmpty() ? QString() : QStringLiteral( " AND (%1)" ).arg( where ) ), QVariantList() ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "SQL: %1\nerror: %2\n" )
|
||||
.arg( qry.lastQuery(),
|
||||
qry.lastError().text() ),
|
||||
const QString error { tr( "SQL: %1\nerror: %2\n" )
|
||||
.arg( qry.lastQuery(),
|
||||
qry.lastError().text() ) };
|
||||
QgsMessageLog::logMessage( error,
|
||||
tr( "Oracle" ) );
|
||||
return;
|
||||
}
|
||||
@ -597,8 +726,10 @@ void QgsOracleConn::retrieveLayerTypes( QgsOracleLayerProperty &layerProperty, b
|
||||
layerProperty.srids.clear();
|
||||
|
||||
QSet<int> srids;
|
||||
long long fetchedRows { 0 };
|
||||
while ( qry.next() )
|
||||
{
|
||||
fetchedRows++;
|
||||
if ( detectedType == QgsWkbTypes::Unknown )
|
||||
{
|
||||
QgsWkbTypes::Type type = wkbTypeFromDatabase( qry.value( 0 ).toInt() );
|
||||
@ -926,7 +1057,8 @@ bool QgsOracleConn::hasSpatial()
|
||||
if ( mHasSpatial == -1 )
|
||||
{
|
||||
QSqlQuery qry( mDatabase );
|
||||
mHasSpatial = exec( qry, QStringLiteral( "SELECT 1 FROM v$option WHERE parameter='Spatial' AND value='TRUE'" ), QVariantList() ) && qry.next();
|
||||
const QString sql { QStringLiteral( "SELECT 1 FROM v$option WHERE parameter='Spatial' AND value='TRUE'" ) };
|
||||
mHasSpatial = LoggedExecPrivate( QStringLiteral( "QgsOracleConn" ), qry, sql, QVariantList() ) && qry.next();
|
||||
}
|
||||
|
||||
return mHasSpatial;
|
||||
@ -935,16 +1067,17 @@ bool QgsOracleConn::hasSpatial()
|
||||
int QgsOracleConn::version()
|
||||
{
|
||||
QSqlQuery qry( mDatabase );
|
||||
QString sql = QStringLiteral( "SELECT VERSION FROM PRODUCT_COMPONENT_VERSION" );
|
||||
if ( exec( qry, sql, QVariantList() ) && qry.next() )
|
||||
const QString sql = QStringLiteral( "SELECT VERSION FROM PRODUCT_COMPONENT_VERSION" );
|
||||
if ( LoggedExecPrivate( QStringLiteral( "QgsOracleConn" ), qry, sql, QVariantList() ) && qry.next() )
|
||||
{
|
||||
return qry.value( 0 ).toString().split( '.' ).at( 0 ).toInt();
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Unable to execute the query.\nThe error message from the database was:\n%1.\nSQL: %2" )
|
||||
.arg( qry.lastError().text() )
|
||||
.arg( qry.lastQuery() ), tr( "Oracle" ) );
|
||||
const QString error { tr( "Unable to execute the query.\nThe error message from the database was:\n%1.\nSQL: %2" )
|
||||
.arg( qry.lastError().text() )
|
||||
.arg( qry.lastQuery() ) };
|
||||
QgsMessageLog::logMessage( error, tr( "Oracle" ) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -956,7 +1089,8 @@ QString QgsOracleConn::currentUser()
|
||||
if ( mCurrentUser.isNull() )
|
||||
{
|
||||
QSqlQuery qry( mDatabase );
|
||||
if ( exec( qry, QStringLiteral( "SELECT user FROM dual" ), QVariantList() ) && qry.next() )
|
||||
const QString sql { QStringLiteral( "SELECT user FROM dual" ) };
|
||||
if ( LoggedExecPrivate( QStringLiteral( "QgsOracleConn" ), qry, sql, QVariantList() ) && qry.next() )
|
||||
{
|
||||
mCurrentUser = qry.value( 0 ).toString();
|
||||
}
|
||||
@ -993,11 +1127,12 @@ QString QgsOracleConn::getSpatialIndexName( const QString &ownerName, const QStr
|
||||
QString name;
|
||||
|
||||
QSqlQuery qry( mDatabase );
|
||||
if ( exec( qry, QString( "SELECT i.index_name,i.domidx_opstatus"
|
||||
" FROM all_indexes i"
|
||||
" JOIN all_ind_columns c ON i.owner=c.index_owner AND i.index_name=c.index_name AND c.column_name=?"
|
||||
" WHERE i.table_owner=? AND i.table_name=? AND i.ityp_owner='MDSYS' AND i.ityp_name='SPATIAL_INDEX'" ),
|
||||
QVariantList() << geometryColumn << ownerName << tableName ) )
|
||||
|
||||
if ( LoggedExecPrivate( QStringLiteral( "QgsOracleConn" ), qry, QStringLiteral( "SELECT i.index_name,i.domidx_opstatus"
|
||||
" FROM all_indexes i"
|
||||
" JOIN all_ind_columns c ON i.owner=c.index_owner AND i.index_name=c.index_name AND c.column_name=?"
|
||||
" WHERE i.table_owner=? AND i.table_name=? AND i.ityp_owner='MDSYS' AND i.ityp_name='SPATIAL_INDEX'" ),
|
||||
QVariantList() << geometryColumn << ownerName << tableName ) )
|
||||
{
|
||||
if ( qry.next() )
|
||||
{
|
||||
@ -1025,11 +1160,12 @@ QString QgsOracleConn::getSpatialIndexName( const QString &ownerName, const QStr
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Probing for spatial index on column %1.%2.%3 failed [%4]" )
|
||||
.arg( ownerName )
|
||||
.arg( tableName )
|
||||
.arg( geometryColumn )
|
||||
.arg( qry.lastError().text() ),
|
||||
const QString error { tr( "Probing for spatial index on column %1.%2.%3 failed [%4]" )
|
||||
.arg( ownerName )
|
||||
.arg( tableName )
|
||||
.arg( geometryColumn )
|
||||
.arg( qry.lastError().text() ) };
|
||||
QgsMessageLog::logMessage( error,
|
||||
tr( "Oracle" ) );
|
||||
|
||||
isValid = false;
|
||||
@ -1043,21 +1179,25 @@ QString QgsOracleConn::createSpatialIndex( const QString &ownerName, const QStri
|
||||
QSqlQuery qry( mDatabase );
|
||||
|
||||
int n = 0;
|
||||
if ( exec( qry, QString( "SELECT coalesce(substr(max(index_name),10),'0') FROM all_indexes WHERE index_name LIKE 'QGIS_IDX_%' ESCAPE '#' ORDER BY index_name" ), QVariantList() ) &&
|
||||
const QString sql { QStringLiteral( "SELECT coalesce(substr(max(index_name),10),'0') FROM all_indexes WHERE index_name LIKE 'QGIS_IDX_%' ESCAPE '#' ORDER BY index_name" ) };
|
||||
|
||||
if ( LoggedExecPrivate( QStringLiteral( "QgsOracleConn" ), qry, sql, QVariantList() ) &&
|
||||
qry.next() )
|
||||
{
|
||||
n = qry.value( 0 ).toInt() + 1;
|
||||
}
|
||||
|
||||
if ( !exec( qry, QString( "CREATE INDEX QGIS_IDX_%1 ON %2.%3(%4) INDEXTYPE IS MDSYS.SPATIAL_INDEX PARALLEL" )
|
||||
.arg( n, 10, 10, QChar( '0' ) )
|
||||
.arg( quotedIdentifier( ownerName ) )
|
||||
.arg( quotedIdentifier( tableName ) )
|
||||
.arg( quotedIdentifier( geometryColumn ) ), QVariantList() ) )
|
||||
const QString sql2 { QStringLiteral( "CREATE INDEX QGIS_IDX_%1 ON %2.%3(%4) INDEXTYPE IS MDSYS.SPATIAL_INDEX PARALLEL" )
|
||||
.arg( n, 10, 10, QChar( '0' ) )
|
||||
.arg( quotedIdentifier( ownerName ) )
|
||||
.arg( quotedIdentifier( tableName ) )
|
||||
.arg( quotedIdentifier( geometryColumn ) ) };
|
||||
if ( !LoggedExecPrivate( QStringLiteral( "QgsOracleConn" ), qry, sql2, QVariantList() ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Creation spatial index failed.\nSQL: %1\nError: %2" )
|
||||
.arg( qry.lastQuery() )
|
||||
.arg( qry.lastError().text() ),
|
||||
const QString error { tr( "Creation spatial index failed.\nSQL: %1\nError: %2" )
|
||||
.arg( qry.lastQuery() )
|
||||
.arg( qry.lastError().text() ) };
|
||||
QgsMessageLog::logMessage( error,
|
||||
tr( "Oracle" ) );
|
||||
return QString();
|
||||
}
|
||||
@ -1071,15 +1211,16 @@ QStringList QgsOracleConn::getPrimaryKeys( const QString &ownerName, const QStri
|
||||
|
||||
QStringList result;
|
||||
|
||||
if ( !exec( qry, QString( "SELECT column_name"
|
||||
" FROM all_cons_columns a"
|
||||
" JOIN all_constraints b ON a.constraint_name=b.constraint_name AND a.owner=b.owner"
|
||||
" WHERE b.constraint_type='P' AND b.owner=? AND b.table_name=?" ),
|
||||
QVariantList() << ownerName << tableName ) )
|
||||
if ( !LoggedExecPrivate( QStringLiteral( "QgsOracleConn" ), qry, QStringLiteral( "SELECT column_name"
|
||||
" FROM all_cons_columns a"
|
||||
" JOIN all_constraints b ON a.constraint_name=b.constraint_name AND a.owner=b.owner"
|
||||
" WHERE b.constraint_type='P' AND b.owner=? AND b.table_name=?" ),
|
||||
QVariantList() << ownerName << tableName ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Unable to execute the query.\nThe error message from the database was:\n%1.\nSQL: %2" )
|
||||
.arg( qry.lastError().text() )
|
||||
.arg( qry.lastQuery() ), tr( "Oracle" ) );
|
||||
const QString error { tr( "Unable to execute the query.\nThe error message from the database was:\n%1.\nSQL: %2" )
|
||||
.arg( qry.lastError().text() )
|
||||
.arg( qry.lastQuery() ) };
|
||||
QgsMessageLog::logMessage( error, tr( "Oracle" ) );
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
#include "qgslogger.h"
|
||||
#include "qgsdatasourceuri.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsdbquerylog.h"
|
||||
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
@ -112,6 +113,13 @@ struct QgsOracleLayerProperty
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#include "qgsconfig.h"
|
||||
constexpr int sOracleConQueryLogFilePrefixLength = CMAKE_SOURCE_DIR[sizeof( CMAKE_SOURCE_DIR ) - 1] == '/' ? sizeof( CMAKE_SOURCE_DIR ) + 1 : sizeof( CMAKE_SOURCE_DIR );
|
||||
#define LoggedExec(_class, query) execLogged( query, true, nullptr, _class, QString(QString( __FILE__ ).mid( sOracleConQueryLogFilePrefixLength ) + ':' + QString::number( __LINE__ ) + " (" + __FUNCTION__ + ")") )
|
||||
#define LoggedExecPrivate(_class, query, sql, params ) execLogged( query, sql, params, _class, QString(QString( __FILE__ ).mid( sOracleConQueryLogFilePrefixLength ) + ':' + QString::number( __LINE__ ) + " (" + __FUNCTION__ + ")") )
|
||||
|
||||
|
||||
/**
|
||||
* Wraps acquireConnection() and releaseConnection() from a QgsOracleConnPool.
|
||||
* This can be used to ensure a connection is correctly released when scope ends
|
||||
@ -157,6 +165,7 @@ class QgsOracleConn : public QObject
|
||||
static QString quotedValue( const QVariant &value, QVariant::Type type = QVariant::Invalid );
|
||||
|
||||
bool exec( const QString &query, bool logError = true, QString *errorMessage = nullptr );
|
||||
bool execLogged( const QString &sql, bool logError = true, QString *errorMessage = nullptr, const QString &originatorClass = QString(), const QString &queryOrigin = QString() );
|
||||
|
||||
bool begin( QSqlDatabase &db );
|
||||
bool commit( QSqlDatabase &db );
|
||||
@ -253,11 +262,14 @@ class QgsOracleConn : public QObject
|
||||
|
||||
operator QSqlDatabase() { return mDatabase; }
|
||||
|
||||
static QString getLastExecutedQuery( const QSqlQuery &query );
|
||||
|
||||
private:
|
||||
explicit QgsOracleConn( QgsDataSourceUri uri, bool transaction );
|
||||
~QgsOracleConn() override;
|
||||
|
||||
bool exec( QSqlQuery &qry, const QString &sql, const QVariantList ¶ms );
|
||||
bool execLogged( QSqlQuery &qry, const QString &sql, const QVariantList ¶ms, const QString &originatorClass = QString(), const QString &queryOrigin = QString() );
|
||||
|
||||
//! reference count
|
||||
int mRef;
|
||||
@ -280,6 +292,9 @@ class QgsOracleConn : public QObject
|
||||
static QMap<QString, QgsOracleConn *> sConnections;
|
||||
static int snConnections;
|
||||
static QMap<QString, QDateTime> sBrokenConnections;
|
||||
|
||||
// Connection URI string representation for query logger
|
||||
QString mConnInfo;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -60,10 +60,10 @@ bool deleteLayer( const QString &uri, QString &errCause )
|
||||
QSqlQuery qry( *conn );
|
||||
|
||||
// check the geometry column count
|
||||
if ( !QgsOracleProvider::exec( qry, QString( "SELECT count(*)"
|
||||
" FROM user_tab_columns"
|
||||
" WHERE table_name=? AND data_type='SDO_GEOMETRY' AND data_type_owner='MDSYS'" ),
|
||||
QVariantList() << tableName )
|
||||
if ( !QgsOracleProvider::execLoggedStatic( qry, QString( "SELECT count(*)"
|
||||
" FROM user_tab_columns"
|
||||
" WHERE table_name=? AND data_type='SDO_GEOMETRY' AND data_type_owner='MDSYS'" ),
|
||||
QVariantList() << tableName, dsUri.uri(), QStringLiteral( "QgsOracleLayerItem" ), QGS_QUERY_LOG_ORIGIN )
|
||||
|| !qry.next() )
|
||||
{
|
||||
errCause = QObject::tr( "Unable to determine number of geometry columns of layer %1.%2: \n%3" )
|
||||
@ -97,7 +97,7 @@ bool deleteLayer( const QString &uri, QString &errCause )
|
||||
args << tableName;
|
||||
}
|
||||
|
||||
if ( !QgsOracleProvider::exec( qry, dropTable, QVariantList() ) )
|
||||
if ( !QgsOracleProvider::execLoggedStatic( qry, dropTable, QVariantList(), dsUri.uri(), QStringLiteral( "QgsOracleLayerItem" ), QGS_QUERY_LOG_ORIGIN ) )
|
||||
{
|
||||
errCause = QObject::tr( "Unable to delete layer %1.%2: \n%3" )
|
||||
.arg( ownerName )
|
||||
@ -107,7 +107,7 @@ bool deleteLayer( const QString &uri, QString &errCause )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !QgsOracleProvider::exec( qry, cleanView, args ) )
|
||||
if ( !QgsOracleProvider::execLoggedStatic( qry, cleanView, args, dsUri.uri(), QStringLiteral( "QgsOracleLayerItem" ), QGS_QUERY_LOG_ORIGIN ) )
|
||||
{
|
||||
errCause = QObject::tr( "Unable to clean metadata %1.%2: \n%3" )
|
||||
.arg( ownerName )
|
||||
@ -544,7 +544,7 @@ QVector<QgsDataItem *> QgsOracleRootItem::createChildren()
|
||||
{
|
||||
QVector<QgsDataItem *> connections;
|
||||
const QStringList list = QgsOracleConn::connectionList();
|
||||
for ( QString connName : list )
|
||||
for ( const QString &connName : std::as_const( list ) )
|
||||
{
|
||||
connections << new QgsOracleConnectionItem( this, connName, mPath + '/' + connName );
|
||||
}
|
||||
|
||||
@ -296,9 +296,10 @@ bool QgsOracleFeatureIterator::fetchFeature( QgsFeature &feature )
|
||||
mRewind = false;
|
||||
if ( !execQuery( mSql, mArgs, 1 ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "Fetching features failed.\nSQL: %1\nError: %2" )
|
||||
.arg( mQry.lastQuery(),
|
||||
mQry.lastError().text() ),
|
||||
const QString error { QObject::tr( "Fetching features failed.\nSQL: %1\nError: %2" )
|
||||
.arg( mQry.lastQuery(),
|
||||
mQry.lastError().text() ) };
|
||||
QgsMessageLog::logMessage( error,
|
||||
QObject::tr( "Oracle" ) );
|
||||
return false;
|
||||
}
|
||||
@ -531,13 +532,16 @@ bool QgsOracleFeatureIterator::openQuery( const QString &whereClause, const QVar
|
||||
QgsDebugMsgLevel( QStringLiteral( "Fetch features: %1" ).arg( query ), 2 );
|
||||
mSql = query;
|
||||
mArgs = args;
|
||||
|
||||
if ( !execQuery( query, args, 1 ) )
|
||||
{
|
||||
|
||||
const QString error { QObject::tr( "Fetching features failed.\nSQL: %1\nError: %2" )
|
||||
.arg( mQry.lastQuery(),
|
||||
mQry.lastError().text() ) };
|
||||
if ( showLog )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "Fetching features failed.\nSQL: %1\nError: %2" )
|
||||
.arg( mQry.lastQuery(),
|
||||
mQry.lastError().text() ),
|
||||
QgsMessageLog::logMessage( error,
|
||||
QObject::tr( "Oracle" ) );
|
||||
}
|
||||
return false;
|
||||
@ -554,7 +558,7 @@ bool QgsOracleFeatureIterator::openQuery( const QString &whereClause, const QVar
|
||||
bool QgsOracleFeatureIterator::execQuery( const QString &query, const QVariantList &args, int retryCount )
|
||||
{
|
||||
lock();
|
||||
if ( !QgsOracleProvider::exec( mQry, query, args ) )
|
||||
if ( !QgsOracleProvider::execLoggedStatic( mQry, query, args, mSource->mUri.uri(), QStringLiteral( "QgsOracleFeatureIterator" ), QGS_QUERY_LOG_ORIGIN ) )
|
||||
{
|
||||
unlock();
|
||||
if ( retryCount != 0 )
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgsvectorlayerexporter.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsdbquerylog.h"
|
||||
|
||||
#include "qgsoracleprovider.h"
|
||||
#include "qgsoracletablemodel.h"
|
||||
@ -49,6 +50,10 @@
|
||||
|
||||
#include "ocispatial/wkbptr.h"
|
||||
|
||||
|
||||
#define LoggedExecStatic(query, sql, args, uri ) execLoggedStatic( query, sql, args, uri, QStringLiteral( "QgsOracleProvider" ), QString(QString( __FILE__ ).mid( sOracleConQueryLogFilePrefixLength ) + ':' + QString::number( __LINE__ ) + " (" + __FUNCTION__ + ")") )
|
||||
|
||||
|
||||
const QString ORACLE_KEY = "oracle";
|
||||
const QString ORACLE_DESCRIPTION = "Oracle data provider";
|
||||
|
||||
@ -279,13 +284,14 @@ QgsOracleConn *QgsOracleProvider::connectionRO() const
|
||||
return mTransaction ? mTransaction->connection() : QgsOracleConn::connectDb( mUri, false );
|
||||
}
|
||||
|
||||
bool QgsOracleProvider::exec( QSqlQuery &qry, QString sql, const QVariantList &args )
|
||||
bool QgsOracleProvider::execLoggedStatic( QSqlQuery &qry, const QString &sql, const QVariantList &args, const QString &uri, const QString &originatorClass, const QString &queryOrigin )
|
||||
{
|
||||
QgsDebugMsgLevel( QStringLiteral( "SQL: %1" ).arg( sql ), 4 );
|
||||
QgsDatabaseQueryLogWrapper logWrapper { sql, uri, QStringLiteral( "oracle" ), originatorClass, queryOrigin };
|
||||
|
||||
qry.setForwardOnly( true );
|
||||
|
||||
bool res = qry.prepare( sql );
|
||||
|
||||
if ( res )
|
||||
{
|
||||
for ( const auto &arg : args )
|
||||
@ -303,6 +309,18 @@ bool QgsOracleProvider::exec( QSqlQuery &qry, QString sql, const QVariantList &a
|
||||
.arg( qry.lastError().text() ) );
|
||||
}
|
||||
|
||||
logWrapper.setQuery( QgsOracleConn::getLastExecutedQuery( qry ) );
|
||||
logWrapper.setError( qry.lastError().text() );
|
||||
// ORACLE does not support size so this will always be -1
|
||||
// we leave it here in case this changes in the future
|
||||
if ( qry.isSelect() )
|
||||
{
|
||||
logWrapper.setFetchedRows( qry.size() );
|
||||
}
|
||||
else
|
||||
{
|
||||
logWrapper.setFetchedRows( qry.numRowsAffected() );
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -565,13 +583,13 @@ bool QgsOracleProvider::loadFields()
|
||||
{
|
||||
QgsDebugMsgLevel( QStringLiteral( "Loading fields for table %1" ).arg( mTableName ), 2 );
|
||||
|
||||
if ( exec( qry, QString( "SELECT comments FROM all_tab_comments WHERE owner=? AND table_name=?" ),
|
||||
QVariantList() << mOwnerName << mTableName ) )
|
||||
if ( LoggedExecStatic( qry, QStringLiteral( "SELECT comments FROM all_tab_comments WHERE owner=? AND table_name=?" ),
|
||||
QVariantList() << mOwnerName << mTableName, mUri.uri() ) )
|
||||
{
|
||||
if ( qry.next() )
|
||||
mDataComment = qry.value( 0 ).toString();
|
||||
else if ( exec( qry, QString( "SELECT comments FROM all_mview_comments WHERE owner=? AND mview_name=?" ),
|
||||
QVariantList() << mOwnerName << mTableName ) )
|
||||
else if ( LoggedExecStatic( qry, QStringLiteral( "SELECT comments FROM all_mview_comments WHERE owner=? AND mview_name=?" ),
|
||||
QVariantList() << mOwnerName << mTableName, mUri.uri() ) )
|
||||
{
|
||||
if ( qry.next() )
|
||||
mDataComment = qry.value( 0 ).toString();
|
||||
@ -579,28 +597,31 @@ bool QgsOracleProvider::loadFields()
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Loading comment for table %1.%2 failed [%3]" )
|
||||
.arg( mOwnerName )
|
||||
.arg( mTableName )
|
||||
.arg( qry.lastError().text() ),
|
||||
const QString error { tr( "Loading comment for table %1.%2 failed [%3]" )
|
||||
.arg( mOwnerName )
|
||||
.arg( mTableName )
|
||||
.arg( qry.lastError().text() ) };
|
||||
QgsMessageLog::logMessage( error,
|
||||
tr( "Oracle" ) );
|
||||
}
|
||||
|
||||
qry.finish();
|
||||
|
||||
if ( exec( qry, QString( "SELECT column_name,comments FROM all_col_comments t WHERE t.owner=? AND t.table_name=?" ),
|
||||
QVariantList() << mOwnerName << mTableName ) )
|
||||
if ( LoggedExecStatic( qry, QStringLiteral( "SELECT column_name,comments FROM all_col_comments t WHERE t.owner=? AND t.table_name=?" ),
|
||||
QVariantList() << mOwnerName << mTableName, mUri.uri() ) )
|
||||
{
|
||||
while ( qry.next() )
|
||||
{
|
||||
if ( qry.value( 0 ).toString() == mGeometryColumn )
|
||||
continue;
|
||||
comments.insert( qry.value( 0 ).toString(), qry.value( 1 ).toString() );
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Loading comment for columns of table %1.%2 failed [%3]" ).arg( mOwnerName ).arg( mTableName ).arg( qry.lastError().text() ), tr( "Oracle" ) );
|
||||
const QString error { tr( "Loading comment for columns of table %1.%2 failed [%3]" ).arg( mOwnerName ).arg( mTableName ).arg( qry.lastError().text() ) };
|
||||
QgsMessageLog::logMessage( error, tr( "Oracle" ) );
|
||||
}
|
||||
|
||||
qry.finish();
|
||||
@ -638,10 +659,12 @@ bool QgsOracleProvider::loadFields()
|
||||
|
||||
sql += " ORDER BY t.column_id";
|
||||
|
||||
if ( exec( qry, sql, args ) )
|
||||
if ( LoggedExecStatic( qry, sql, args, mUri.uri() ) )
|
||||
{
|
||||
long long fetchedRows { 0 };
|
||||
while ( qry.next() )
|
||||
{
|
||||
fetchedRows++;
|
||||
QString name = qry.value( 0 ).toString();
|
||||
QString type = qry.value( 1 ).toString();
|
||||
int prec = qry.value( 2 ).toInt();
|
||||
@ -678,13 +701,16 @@ bool QgsOracleProvider::loadFields()
|
||||
defvalues.insert( name, defValue );
|
||||
alwaysGenerated.insert( name, alwaysGen );
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Loading field types for table %1.%2 failed [%3]" )
|
||||
.arg( mOwnerName )
|
||||
.arg( mTableName )
|
||||
.arg( qry.lastError().text() ),
|
||||
const QString error { tr( "Loading field types for table %1.%2 failed [%3]" )
|
||||
.arg( mOwnerName )
|
||||
.arg( mTableName )
|
||||
.arg( qry.lastError().text() ) };
|
||||
|
||||
QgsMessageLog::logMessage( error,
|
||||
tr( "Oracle" ) );
|
||||
}
|
||||
|
||||
@ -698,10 +724,12 @@ bool QgsOracleProvider::loadFields()
|
||||
{
|
||||
if ( !mHasSpatialIndex )
|
||||
{
|
||||
mHasSpatialIndex = qry.exec( QString( "SELECT %2 FROM %1 WHERE sdo_filter(%2,mdsys.sdo_geometry(2003,%3,NULL,mdsys.sdo_elem_info_array(1,1003,3),mdsys.sdo_ordinate_array(-1,-1,1,1)))='TRUE'" )
|
||||
.arg( mQuery )
|
||||
.arg( quotedIdentifier( mGeometryColumn ) )
|
||||
.arg( mSrid < 1 ? "NULL" : QString::number( mSrid ) ) );
|
||||
const QString sql{ QStringLiteral( "SELECT %2 FROM %1 WHERE sdo_filter(%2,mdsys.sdo_geometry(2003,%3,NULL,mdsys.sdo_elem_info_array(1,1003,3),mdsys.sdo_ordinate_array(-1,-1,1,1)))='TRUE'" )
|
||||
.arg( mQuery )
|
||||
.arg( quotedIdentifier( mGeometryColumn ) )
|
||||
.arg( mSrid < 1 ? "NULL" : QString::number( mSrid ) ) };
|
||||
|
||||
mHasSpatialIndex = LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() );
|
||||
}
|
||||
|
||||
if ( !mHasSpatialIndex )
|
||||
@ -716,9 +744,12 @@ bool QgsOracleProvider::loadFields()
|
||||
|
||||
qry.finish();
|
||||
|
||||
if ( !exec( qry, QString( "SELECT * FROM %1 WHERE 1=0" ).arg( mQuery ), QVariantList() ) )
|
||||
const QString sql { QStringLiteral( "SELECT * FROM %1 WHERE 1=0" ).arg( mQuery ) };
|
||||
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Retrieving fields from '%1' failed [%2]" ).arg( mQuery ).arg( qry.lastError().text() ), tr( "Oracle" ) );
|
||||
const QString error { tr( "Retrieving fields from '%1' failed [%2]" ).arg( mQuery ).arg( qry.lastError().text() ) };
|
||||
QgsMessageLog::logMessage( error, tr( "Oracle" ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -763,6 +794,7 @@ bool QgsOracleProvider::hasSufficientPermsAndCapabilities()
|
||||
mEnabledCapabilities |= QgsVectorDataProvider::CircularGeometries;
|
||||
|
||||
QgsOracleConn *conn = connectionRO();
|
||||
|
||||
QSqlQuery qry( *conn );
|
||||
if ( !mIsQuery )
|
||||
{
|
||||
@ -778,58 +810,66 @@ bool QgsOracleProvider::hasSufficientPermsAndCapabilities()
|
||||
| QgsVectorDataProvider::RenameAttributes
|
||||
;
|
||||
}
|
||||
else if ( exec( qry, QString( "SELECT privilege FROM all_tab_privs WHERE table_schema=? AND table_name=? AND privilege IN ('DELETE','UPDATE','INSERT','ALTER TABLE')" ),
|
||||
QVariantList() << mOwnerName << mTableName ) )
|
||||
{
|
||||
// check grants
|
||||
while ( qry.next() )
|
||||
{
|
||||
QString priv = qry.value( 0 ).toString();
|
||||
|
||||
if ( priv == "DELETE" )
|
||||
{
|
||||
mEnabledCapabilities |= QgsVectorDataProvider::DeleteFeatures;
|
||||
}
|
||||
else if ( priv == "UPDATE" )
|
||||
{
|
||||
mEnabledCapabilities |= QgsVectorDataProvider::ChangeAttributeValues;
|
||||
}
|
||||
else if ( priv == "INSERT" )
|
||||
{
|
||||
mEnabledCapabilities |= QgsVectorDataProvider::AddFeatures;
|
||||
}
|
||||
else if ( priv == "ALTER TABLE" )
|
||||
{
|
||||
mEnabledCapabilities |= QgsVectorDataProvider::AddAttributes | QgsVectorDataProvider::DeleteAttributes | QgsVectorDataProvider::RenameAttributes;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !mGeometryColumn.isNull() )
|
||||
{
|
||||
if ( exec( qry, QString( "SELECT 1 FROM all_col_privs WHERE table_schema=? AND table_name=? AND column_name=? AND privilege='UPDATE'" ),
|
||||
QVariantList() << mOwnerName << mTableName << mGeometryColumn ) )
|
||||
{
|
||||
if ( qry.next() )
|
||||
mEnabledCapabilities |= QgsVectorDataProvider::ChangeGeometries;
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Unable to determine geometry column access privileges for column %1.%2.\nThe error message from the database was:\n%3.\nSQL: %4" )
|
||||
.arg( mQuery )
|
||||
.arg( mGeometryColumn )
|
||||
.arg( qry.lastError().text() )
|
||||
.arg( qry.lastQuery() ),
|
||||
tr( "Oracle" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Unable to determine table access privileges for the table %1.\nThe error message from the database was:\n%2.\nSQL: %3" )
|
||||
.arg( mQuery )
|
||||
.arg( qry.lastError().text() )
|
||||
.arg( qry.lastQuery() ),
|
||||
tr( "Oracle" ) );
|
||||
if ( LoggedExecStatic( qry, QStringLiteral( "SELECT privilege FROM all_tab_privs WHERE table_schema=? AND table_name=? AND privilege IN ('DELETE','UPDATE','INSERT','ALTER TABLE')" ),
|
||||
QVariantList() << mOwnerName << mTableName, mUri.uri() ) )
|
||||
{
|
||||
// check grants
|
||||
long long fetchedRows { 0 };
|
||||
while ( qry.next() )
|
||||
{
|
||||
fetchedRows++;
|
||||
QString priv = qry.value( 0 ).toString();
|
||||
|
||||
if ( priv == "DELETE" )
|
||||
{
|
||||
mEnabledCapabilities |= QgsVectorDataProvider::DeleteFeatures;
|
||||
}
|
||||
else if ( priv == "UPDATE" )
|
||||
{
|
||||
mEnabledCapabilities |= QgsVectorDataProvider::ChangeAttributeValues;
|
||||
}
|
||||
else if ( priv == "INSERT" )
|
||||
{
|
||||
mEnabledCapabilities |= QgsVectorDataProvider::AddFeatures;
|
||||
}
|
||||
else if ( priv == "ALTER TABLE" )
|
||||
{
|
||||
mEnabledCapabilities |= QgsVectorDataProvider::AddAttributes | QgsVectorDataProvider::DeleteAttributes | QgsVectorDataProvider::RenameAttributes;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !mGeometryColumn.isNull() )
|
||||
{
|
||||
|
||||
if ( LoggedExecStatic( qry, QStringLiteral( "SELECT 1 FROM all_col_privs WHERE table_schema=? AND table_name=? AND column_name=? AND privilege='UPDATE'" ),
|
||||
QVariantList() << mOwnerName << mTableName << mGeometryColumn, mUri.uri() ) )
|
||||
{
|
||||
if ( qry.next() )
|
||||
mEnabledCapabilities |= QgsVectorDataProvider::ChangeGeometries;
|
||||
}
|
||||
else
|
||||
{
|
||||
const QString error { tr( "Unable to determine geometry column access privileges for column %1.%2.\nThe error message from the database was:\n%3.\nSQL: %4" )
|
||||
.arg( mQuery )
|
||||
.arg( mGeometryColumn )
|
||||
.arg( qry.lastError().text() )
|
||||
.arg( qry.lastQuery() ) };
|
||||
QgsMessageLog::logMessage( error,
|
||||
tr( "Oracle" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const QString error { tr( "Unable to determine table access privileges for the table %1.\nThe error message from the database was:\n%2.\nSQL: %3" )
|
||||
.arg( mQuery )
|
||||
.arg( qry.lastError().text() )
|
||||
.arg( qry.lastQuery() ) };
|
||||
QgsMessageLog::logMessage( error,
|
||||
tr( "Oracle" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -841,11 +881,13 @@ bool QgsOracleProvider::hasSufficientPermsAndCapabilities()
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !exec( qry, QString( "SELECT * FROM %1 WHERE 1=0" ).arg( mQuery ), QVariantList() ) )
|
||||
const QString sql { QStringLiteral( "SELECT * FROM %1 WHERE 1=0" ).arg( mQuery ) };
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Unable to execute the query.\nThe error message from the database was:\n%1.\nSQL: %2" )
|
||||
.arg( qry.lastError().text() )
|
||||
.arg( qry.lastQuery() ), tr( "Oracle" ) );
|
||||
const QString error { tr( "Unable to execute the query.\nThe error message from the database was:\n%1.\nSQL: %2" )
|
||||
.arg( qry.lastError().text() )
|
||||
.arg( qry.lastQuery() ) };
|
||||
QgsMessageLog::logMessage( error, tr( "Oracle" ) );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -897,21 +939,25 @@ bool QgsOracleProvider::determinePrimaryKey()
|
||||
{
|
||||
mPrimaryKeyType = ( mPrimaryKeyAttrs.size() == 1 && isInt ) ? PktInt : PktFidMap;
|
||||
}
|
||||
else if ( !exec( qry, QString( "SELECT 1 FROM all_tables WHERE owner=? AND table_name=?" ), QVariantList() << mOwnerName << mTableName ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Unable to execute the query.\nThe error message from the database was:\n%1.\nSQL: %2" )
|
||||
.arg( qry.lastError().text() )
|
||||
.arg( qry.lastQuery() ), tr( "Oracle" ) );
|
||||
}
|
||||
else if ( qry.next() )
|
||||
{
|
||||
// is table
|
||||
QgsMessageLog::logMessage( tr( "No primary key found, using ROWID." ), tr( "Oracle" ) );
|
||||
mPrimaryKeyType = PktRowId;
|
||||
}
|
||||
else
|
||||
{
|
||||
determinePrimaryKeyFromUriKeyColumn();
|
||||
if ( !LoggedExecStatic( qry, QStringLiteral( "SELECT 1 FROM all_tables WHERE owner=? AND table_name=?" ), QVariantList() << mOwnerName << mTableName, mUri.uri() ) )
|
||||
{
|
||||
const QString error { tr( "Unable to execute the query.\nThe error message from the database was:\n%1.\nSQL: %2" )
|
||||
.arg( qry.lastError().text() )
|
||||
.arg( qry.lastQuery() ) };
|
||||
QgsMessageLog::logMessage( error, tr( "Oracle" ) );
|
||||
}
|
||||
else if ( qry.next() )
|
||||
{
|
||||
// is table
|
||||
QgsMessageLog::logMessage( tr( "No primary key found, using ROWID." ), tr( "Oracle" ) );
|
||||
mPrimaryKeyType = PktRowId;
|
||||
}
|
||||
else
|
||||
{
|
||||
determinePrimaryKeyFromUriKeyColumn();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -997,7 +1043,7 @@ bool QgsOracleProvider::uniqueData( QString query, QString colName )
|
||||
QString sql = QString( "SELECT (SELECT count(distinct %1) FROM %2)-(SELECT count(%1) FROM %2) FROM dual" )
|
||||
.arg( colName.startsWith( QLatin1String( "qgis_generated_uid_" ) ) ? colName : quotedIdentifier( colName ), mQuery );
|
||||
|
||||
if ( !exec( qry, sql, QVariantList() ) || !qry.next() )
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() ) || !qry.next() )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Unable to execute the query.\nThe error message from the database was:\n%1.\nSQL: %2" )
|
||||
.arg( qry.lastError().text(), qry.lastQuery() ), tr( "Oracle" ) );
|
||||
@ -1028,7 +1074,7 @@ QVariant QgsOracleProvider::minimumValue( int index ) const
|
||||
|
||||
QSqlQuery qry( *conn );
|
||||
|
||||
if ( !exec( qry, sql, QVariantList() ) )
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Unable to execute the query.\nThe error message from the database was:\n%1.\nSQL: %2" )
|
||||
.arg( qry.lastError().text(), qry.lastQuery() ), tr( "Oracle" ) );
|
||||
@ -1078,7 +1124,7 @@ QSet<QVariant> QgsOracleProvider::uniqueValues( int index, int limit ) const
|
||||
|
||||
QSqlQuery qry( *conn );
|
||||
|
||||
if ( !exec( qry, sql, QVariantList() ) )
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Unable to execute the query.\nThe error message from the database was:\n%1.\nSQL: %2" )
|
||||
.arg( qry.lastError().text(), qry.lastQuery() ), tr( "Oracle" ) );
|
||||
@ -1120,7 +1166,7 @@ QVariant QgsOracleProvider::maximumValue( int index ) const
|
||||
|
||||
QSqlQuery qry( *conn );
|
||||
|
||||
if ( !exec( qry, sql, QVariantList() ) )
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Unable to execute the query.\nThe error message from the database was:\n%1.\nSQL: %2" )
|
||||
.arg( qry.lastError().text(), qry.lastQuery() ), tr( "Oracle" ) );
|
||||
@ -1201,7 +1247,10 @@ QVariant QgsOracleProvider::evaluateDefaultExpression( const QString &value, con
|
||||
|
||||
QgsOracleConn *conn = connectionRO();
|
||||
QSqlQuery qry( *conn );
|
||||
if ( !exec( qry, QString( "SELECT %1 FROM dual" ).arg( value ), QVariantList() ) || !qry.next() )
|
||||
|
||||
const QString sql { QStringLiteral( "SELECT %1 FROM dual" ).arg( value ) };
|
||||
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() ) || !qry.next() )
|
||||
{
|
||||
throw OracleException( tr( "Evaluation of default value failed" ), qry );
|
||||
}
|
||||
@ -1317,6 +1366,7 @@ bool QgsOracleProvider::addFeatures( QgsFeatureList &flist, QgsFeatureSink::Flag
|
||||
insert += values + ")";
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "SQL prepare: %1" ).arg( insert ), 4 );
|
||||
|
||||
if ( !ins.prepare( insert ) )
|
||||
{
|
||||
throw OracleException( tr( "Could not prepare insert statement" ), ins );
|
||||
@ -1350,7 +1400,9 @@ bool QgsOracleProvider::addFeatures( QgsFeatureList &flist, QgsFeatureSink::Flag
|
||||
}
|
||||
|
||||
if ( !ins.exec() )
|
||||
{
|
||||
throw OracleException( tr( "Could not insert feature %1" ).arg( features->id() ), ins );
|
||||
}
|
||||
|
||||
if ( !( flags & QgsFeatureSink::FastInsert ) )
|
||||
{
|
||||
@ -1364,7 +1416,10 @@ bool QgsOracleProvider::addFeatures( QgsFeatureList &flist, QgsFeatureSink::Flag
|
||||
if ( ins.lastInsertId().isValid() )
|
||||
{
|
||||
getfid.addBindValue( QVariant( ins.lastInsertId() ) );
|
||||
if ( !getfid.exec() || !getfid.next() )
|
||||
|
||||
const bool result { getfid.exec() };
|
||||
|
||||
if ( !result || !getfid.next() )
|
||||
throw OracleException( tr( "Could not retrieve feature id %1" ).arg( features->id() ), getfid );
|
||||
|
||||
int col = 0;
|
||||
@ -1462,12 +1517,14 @@ bool QgsOracleProvider::deleteFeatures( const QgsFeatureIds &id )
|
||||
for ( QgsFeatureIds::const_iterator it = id.begin(); it != id.end(); ++it )
|
||||
{
|
||||
QVariantList args;
|
||||
QString sql = QString( "DELETE FROM %1 WHERE %2" )
|
||||
QString sql = QStringLiteral( "DELETE FROM %1 WHERE %2" )
|
||||
.arg( mQuery, whereClause( *it, args ) );
|
||||
QgsDebugMsgLevel( "delete sql: " + sql, 2 );
|
||||
|
||||
if ( !exec( qry, sql, args ) )
|
||||
if ( !LoggedExecStatic( qry, sql, args, mUri.uri() ) )
|
||||
{
|
||||
throw OracleException( tr( "Deletion of feature %1 failed" ).arg( *it ), qry );
|
||||
}
|
||||
|
||||
mShared->removeFid( *it );
|
||||
}
|
||||
@ -1537,15 +1594,20 @@ bool QgsOracleProvider::addAttributes( const QList<QgsField> &attributes )
|
||||
.arg( mQuery, quotedIdentifier( iter->name() ), type );
|
||||
QgsDebugMsgLevel( sql, 2 );
|
||||
|
||||
if ( !exec( qry, sql, QVariantList() ) )
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() ) )
|
||||
{
|
||||
throw OracleException( tr( "Adding attribute %1 failed" ).arg( iter->name() ), qry );
|
||||
}
|
||||
|
||||
if ( !iter->comment().isEmpty() )
|
||||
{
|
||||
sql = QString( "COMMENT ON COLUMN %1.%2 IS ?" )
|
||||
.arg( mQuery, quotedIdentifier( iter->name() ) );
|
||||
if ( !exec( qry, sql, QVariantList() << iter->comment() ) )
|
||||
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList() << iter->comment(), mUri.uri() ) )
|
||||
{
|
||||
throw OracleException( tr( "Setting comment on %1 failed" ).arg( iter->name() ), qry );
|
||||
}
|
||||
}
|
||||
|
||||
qry.finish();
|
||||
@ -1609,8 +1671,10 @@ bool QgsOracleProvider::deleteAttributes( const QgsAttributeIds &ids )
|
||||
.arg( mQuery, quotedIdentifier( fld.name() ) );
|
||||
|
||||
//send sql statement and do error handling
|
||||
if ( !exec( qry, sql, QVariantList() ) )
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() ) )
|
||||
{
|
||||
throw OracleException( tr( "Dropping column %1 failed" ).arg( fld.name() ), qry );
|
||||
}
|
||||
|
||||
//delete the attribute from mAttributeFields
|
||||
mAttributeFields.remove( id );
|
||||
@ -1685,11 +1749,12 @@ bool QgsOracleProvider::renameAttributes( const QgsFieldNameMap &renamedAttribut
|
||||
for ( renameIt = renamedAttributes.constBegin(); renameIt != renamedAttributes.constEnd(); ++renameIt )
|
||||
{
|
||||
QString src( mAttributeFields.at( renameIt.key() ).name() );
|
||||
const QString sql { QString( "ALTER TABLE %1 RENAME COLUMN %2 TO %3" )
|
||||
.arg( mQuery,
|
||||
quotedIdentifier( src ),
|
||||
quotedIdentifier( renameIt.value() ) ) };
|
||||
|
||||
if ( !exec( qry, QString( "ALTER TABLE %1 RENAME COLUMN %2 TO %3" )
|
||||
.arg( mQuery,
|
||||
quotedIdentifier( src ),
|
||||
quotedIdentifier( renameIt.value() ) ), QVariantList() ) )
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() ) )
|
||||
{
|
||||
throw OracleException( tr( "Renaming column %1 to %2 failed" )
|
||||
.arg( quotedIdentifier( src ),
|
||||
@ -1827,10 +1892,17 @@ bool QgsOracleProvider::changeAttributeValues( const QgsChangedAttributesMap &at
|
||||
for ( const auto &arg : std::as_const( args ) )
|
||||
qry.addBindValue( arg );
|
||||
|
||||
QgsDatabaseQueryLogWrapper logWrapper { sql, mUri.uri(), QStringLiteral( "oracle" ), QStringLiteral( "QgsOracleProvider" ), QGS_QUERY_LOG_ORIGIN };
|
||||
|
||||
if ( !qry.exec() )
|
||||
{
|
||||
logWrapper.setError( qry.lastError().text() );
|
||||
logWrapper.setQuery( QgsOracleConn::getLastExecutedQuery( qry ) );
|
||||
throw OracleException( tr( "Update of feature %1 failed" ).arg( iter.key() ), qry );
|
||||
}
|
||||
|
||||
qry.finish();
|
||||
logWrapper.setQuery( QgsOracleConn::getLastExecutedQuery( qry ) );
|
||||
|
||||
// update feature id map if key was changed
|
||||
if ( pkChanged && mPrimaryKeyType == PktFidMap )
|
||||
@ -2304,8 +2376,15 @@ bool QgsOracleProvider::changeGeometryValues( const QgsGeometryMap &geometry_map
|
||||
appendGeomParam( iter.value(), qry );
|
||||
appendPkParams( iter.key(), qry );
|
||||
|
||||
QgsDatabaseQueryLogWrapper logWrapper { update, mUri.uri(), QStringLiteral( "oracle" ), QStringLiteral( "QgsOracleProvider" ), QGS_QUERY_LOG_ORIGIN };
|
||||
|
||||
if ( !qry.exec() )
|
||||
{
|
||||
logWrapper.setQuery( QgsOracleConn::getLastExecutedQuery( qry ) );
|
||||
logWrapper.setError( qry.lastError().text() );
|
||||
throw OracleException( tr( "Update of feature %1 failed" ).arg( iter.key() ), qry );
|
||||
}
|
||||
logWrapper.setQuery( QgsOracleConn::getLastExecutedQuery( qry ) );
|
||||
}
|
||||
|
||||
qry.finish();
|
||||
@ -2359,7 +2438,9 @@ bool QgsOracleProvider::setSubsetString( const QString &theSQL, bool updateFeatu
|
||||
sql += "1=0";
|
||||
|
||||
QSqlQuery qry( *conn );
|
||||
if ( !exec( qry, sql, QVariantList() ) )
|
||||
|
||||
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() ) )
|
||||
{
|
||||
pushError( qry.lastError().text() );
|
||||
mSqlWhereClause = prevWhere;
|
||||
@ -2423,10 +2504,12 @@ long long QgsOracleProvider::featureCount() const
|
||||
}
|
||||
|
||||
QSqlQuery qry( *conn );
|
||||
if ( exec( qry, sql, args ) && qry.next() )
|
||||
|
||||
if ( LoggedExecStatic( qry, sql, QVariantList( ), mUri.uri() ) && qry.next() )
|
||||
{
|
||||
mFeaturesCounted = qry.value( 0 ).toLongLong();
|
||||
}
|
||||
|
||||
qry.finish();
|
||||
|
||||
QgsDebugMsgLevel( "number of features: " + QString::number( mFeaturesCounted ), 2 );
|
||||
@ -2451,15 +2534,18 @@ QgsRectangle QgsOracleProvider::extent() const
|
||||
if ( mUseEstimatedMetadata )
|
||||
{
|
||||
// TODO: make SDO_DIMNAME values configurable (#16252)
|
||||
if ( exec( qry, QStringLiteral( "SELECT sdo_lb,sdo_ub FROM mdsys.all_sdo_geom_metadata m, table(m.diminfo) WHERE owner=? AND table_name=? AND column_name=? AND sdo_dimname='X'" ),
|
||||
QVariantList() << mOwnerName << mTableName << mGeometryColumn ) &&
|
||||
|
||||
const QString sql { QStringLiteral( "SELECT sdo_lb,sdo_ub FROM mdsys.all_sdo_geom_metadata m, table(m.diminfo) WHERE owner=? AND table_name=? AND column_name=? AND sdo_dimname='X'" ) };
|
||||
|
||||
if ( LoggedExecStatic( qry, sql,
|
||||
QVariantList() << mOwnerName << mTableName << mGeometryColumn, mUri.uri() ) &&
|
||||
qry.next() )
|
||||
{
|
||||
mLayerExtent.setXMinimum( qry.value( 0 ).toDouble() );
|
||||
mLayerExtent.setXMaximum( qry.value( 1 ).toDouble() );
|
||||
|
||||
if ( exec( qry, QStringLiteral( "SELECT sdo_lb,sdo_ub FROM mdsys.all_sdo_geom_metadata m, table(m.diminfo) WHERE owner=? AND table_name=? AND column_name=? AND sdo_dimname='Y'" ),
|
||||
QVariantList() << mOwnerName << mTableName << mGeometryColumn ) &&
|
||||
if ( LoggedExecStatic( qry, QStringLiteral( "SELECT sdo_lb,sdo_ub FROM mdsys.all_sdo_geom_metadata m, table(m.diminfo) WHERE owner=? AND table_name=? AND column_name=? AND sdo_dimname='Y'" ),
|
||||
QVariantList() << mOwnerName << mTableName << mGeometryColumn, mUri.uri() ) &&
|
||||
qry.next() )
|
||||
{
|
||||
mLayerExtent.setYMinimum( qry.value( 0 ).toDouble() );
|
||||
@ -2471,9 +2557,10 @@ QgsRectangle QgsOracleProvider::extent() const
|
||||
|
||||
if ( mHasSpatialIndex && mUseEstimatedMetadata )
|
||||
{
|
||||
ok = exec( qry,
|
||||
QStringLiteral( "SELECT SDO_TUNE.EXTENT_OF(?,?) FROM dual" ),
|
||||
QVariantList() << QString( "%1.%2" ).arg( mOwnerName ).arg( mTableName ) << mGeometryColumn );
|
||||
const QString sql { QStringLiteral( "SELECT SDO_TUNE.EXTENT_OF(?,?) FROM dual" ) };
|
||||
ok = LoggedExecStatic( qry,
|
||||
sql,
|
||||
QVariantList() << QString( "%1.%2" ).arg( mOwnerName ).arg( mTableName ) << mGeometryColumn, mUri.uri() );
|
||||
}
|
||||
}
|
||||
|
||||
@ -2484,7 +2571,7 @@ QgsRectangle QgsOracleProvider::extent() const
|
||||
if ( !mSqlWhereClause.isEmpty() )
|
||||
sql += QString( " WHERE %1" ).arg( mSqlWhereClause );
|
||||
|
||||
ok = exec( qry, sql, QVariantList() );
|
||||
ok = LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() );
|
||||
}
|
||||
|
||||
if ( ok && qry.next() )
|
||||
@ -2533,7 +2620,9 @@ bool QgsOracleProvider::getGeometryDetails()
|
||||
QSqlQuery qry( *conn );
|
||||
if ( mIsQuery )
|
||||
{
|
||||
if ( !exec( qry, QString( "SELECT %1 FROM %2 WHERE 1=0" ).arg( quotedIdentifier( mGeometryColumn ) ).arg( mQuery ), QVariantList() ) )
|
||||
const QString sql { QStringLiteral( "SELECT %1 FROM %2 WHERE 1=0" ).arg( quotedIdentifier( mGeometryColumn ) ).arg( mQuery ) };
|
||||
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Could not execute query.\nThe error message from the database was:\n%1.\nSQL: %2" )
|
||||
.arg( qry.lastError().text() )
|
||||
@ -2558,32 +2647,41 @@ bool QgsOracleProvider::getGeometryDetails()
|
||||
|
||||
if ( !ownerName.isEmpty() )
|
||||
{
|
||||
if ( exec( qry, QString( "SELECT srid FROM mdsys.all_sdo_geom_metadata WHERE owner=? AND table_name=? AND column_name=?" ),
|
||||
QVariantList() << ownerName << tableName << geomCol ) )
|
||||
|
||||
{
|
||||
if ( qry.next() )
|
||||
const QString sql {QStringLiteral( "SELECT srid FROM mdsys.all_sdo_geom_metadata WHERE owner=? AND table_name=? AND column_name=?" ) };
|
||||
|
||||
if ( LoggedExecStatic( qry, sql,
|
||||
QVariantList() << ownerName << tableName << geomCol, mUri.uri() ) )
|
||||
{
|
||||
detectedSrid = qry.value( 0 ).toInt();
|
||||
if ( qry.next() )
|
||||
{
|
||||
detectedSrid = qry.value( 0 ).toInt();
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Could not retrieve SRID of %1.\nThe error message from the database was:\n%2.\nSQL: %3" )
|
||||
.arg( mQuery )
|
||||
.arg( qry.lastError().text() )
|
||||
.arg( qry.lastQuery() ), tr( "Oracle" ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Could not retrieve SRID of %1.\nThe error message from the database was:\n%2.\nSQL: %3" )
|
||||
QgsMessageLog::logMessage( tr( "Could not determine SRID of %1.\nThe error message from the database was:\n%2.\nSQL: %3" )
|
||||
.arg( mQuery )
|
||||
.arg( qry.lastError().text() )
|
||||
.arg( qry.lastQuery() ), tr( "Oracle" ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Could not determine SRID of %1.\nThe error message from the database was:\n%2.\nSQL: %3" )
|
||||
.arg( mQuery )
|
||||
.arg( qry.lastError().text() )
|
||||
.arg( qry.lastQuery() ), tr( "Oracle" ) );
|
||||
}
|
||||
|
||||
if ( exec( qry, QString( mUseEstimatedMetadata
|
||||
? "SELECT DISTINCT gtype FROM (SELECT t.%1.sdo_gtype AS gtype FROM %2 t WHERE t.%1 IS NOT NULL AND rownum<100) WHERE rownum<=2"
|
||||
: "SELECT DISTINCT t.%1.sdo_gtype FROM %2 t WHERE t.%1 IS NOT NULL AND rownum<=2" ).arg( quotedIdentifier( geomCol ) ).arg( mQuery ), QVariantList() ) )
|
||||
QString sql { mUseEstimatedMetadata ?
|
||||
QStringLiteral( "SELECT DISTINCT gtype FROM (SELECT t.%1.sdo_gtype AS gtype FROM %2 t WHERE t.%1 IS NOT NULL AND rownum<100) WHERE rownum<=2" ) :
|
||||
QStringLiteral( "SELECT DISTINCT t.%1.sdo_gtype FROM %2 t WHERE t.%1 IS NOT NULL AND rownum<=2" ) };
|
||||
|
||||
sql = sql.arg( quotedIdentifier( geomCol ), mQuery );
|
||||
|
||||
if ( LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() ) )
|
||||
{
|
||||
if ( qry.next() )
|
||||
{
|
||||
@ -2705,30 +2803,41 @@ bool QgsOracleProvider::createSpatialIndex()
|
||||
// TODO: make precision configurable
|
||||
// TODO: make SDO_DIMNAME values configurable (#16252)
|
||||
QgsRectangle r( extent() );
|
||||
if ( !exec( qry, QString( "UPDATE mdsys.user_sdo_geom_metadata SET diminfo=mdsys.sdo_dim_array("
|
||||
"mdsys.sdo_dim_element('X', ?, ?, 0.001),"
|
||||
"mdsys.sdo_dim_element('Y', ?, ?, 0.001)"
|
||||
") WHERE table_name=? AND column_name=?" ),
|
||||
QVariantList() << r.xMinimum() << r.xMaximum() << r.yMinimum() << r.yMaximum() << mTableName << mGeometryColumn )
|
||||
)
|
||||
|
||||
const QString sql { QStringLiteral( "UPDATE mdsys.user_sdo_geom_metadata SET diminfo=mdsys.sdo_dim_array("
|
||||
"mdsys.sdo_dim_element('X', ?, ?, 0.001),"
|
||||
"mdsys.sdo_dim_element('Y', ?, ?, 0.001)"
|
||||
") WHERE table_name=? AND column_name=?" ) };
|
||||
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Could not update metadata for %1.%2.\nSQL: %3\nError: %4" )
|
||||
.arg( mTableName )
|
||||
.arg( mGeometryColumn )
|
||||
.arg( qry.lastQuery() )
|
||||
.arg( qry.lastError().text() ),
|
||||
tr( "Oracle" ) );
|
||||
return false;
|
||||
|
||||
if ( !LoggedExecStatic( qry, sql,
|
||||
QVariantList() << r.xMinimum() << r.xMaximum() << r.yMinimum() << r.yMaximum() << mTableName << mGeometryColumn, mUri.uri() )
|
||||
)
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Could not update metadata for %1.%2.\nSQL: %3\nError: %4" )
|
||||
.arg( mTableName )
|
||||
.arg( mGeometryColumn )
|
||||
.arg( qry.lastQuery() )
|
||||
.arg( qry.lastError().text() ),
|
||||
tr( "Oracle" ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( qry.numRowsAffected() == 0 )
|
||||
{
|
||||
if ( !exec( qry, QString( "INSERT INTO mdsys.user_sdo_geom_metadata(table_name,column_name,srid,diminfo) VALUES (?,?,?,mdsys.sdo_dim_array("
|
||||
"mdsys.sdo_dim_element('X', ?, ?, 0.001),"
|
||||
"mdsys.sdo_dim_element('Y', ?, ?, 0.001)"
|
||||
"))" ),
|
||||
QVariantList() << mTableName << mGeometryColumn << ( mSrid < 1 ? QVariant( QVariant::Int ) : mSrid )
|
||||
<< r.xMinimum() << r.xMaximum() << r.yMinimum() << r.yMaximum() )
|
||||
|
||||
const QString sql { QStringLiteral( "INSERT INTO mdsys.user_sdo_geom_metadata(table_name,column_name,srid,diminfo) VALUES (?,?,?,mdsys.sdo_dim_array("
|
||||
"mdsys.sdo_dim_element('X', ?, ?, 0.001),"
|
||||
"mdsys.sdo_dim_element('Y', ?, ?, 0.001)"
|
||||
"))" ) };
|
||||
|
||||
|
||||
if ( !LoggedExecStatic( qry, sql,
|
||||
QVariantList() << mTableName << mGeometryColumn << ( mSrid < 1 ? QVariant( QVariant::Int ) : mSrid )
|
||||
<< r.xMinimum() << r.xMaximum() << r.yMinimum() << r.yMaximum(), mUri.uri() )
|
||||
)
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Could not insert metadata for %1.%2.\nSQL: %3\nError: %4" )
|
||||
@ -2756,7 +2865,10 @@ bool QgsOracleProvider::createSpatialIndex()
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !exec( qry, QString( "ALTER INDEX %1 REBUILD" ).arg( mSpatialIndexName ), QVariantList() ) )
|
||||
|
||||
const QString sql { QStringLiteral( "ALTER INDEX %1 REBUILD" ).arg( mSpatialIndexName ) };
|
||||
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), mUri.uri() ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Rebuild of spatial index failed.\nSQL: %1\nError: %2" )
|
||||
.arg( qry.lastQuery() )
|
||||
@ -2928,11 +3040,15 @@ Qgis::VectorExportResult QgsOracleProvider::createEmptyLayer(
|
||||
throw OracleException( tr( "Could not start transaction" ), db );
|
||||
}
|
||||
|
||||
if ( !exec( qry, QString( "SELECT 1 FROM all_tables WHERE owner=? AND table_name=?" ),
|
||||
QVariantList() << ownerName << tableName
|
||||
) )
|
||||
{
|
||||
throw OracleException( tr( "Could not determine table existence." ), qry );
|
||||
const QString sql { QStringLiteral( "SELECT 1 FROM all_tables WHERE owner=? AND table_name=?" ) };
|
||||
|
||||
if ( !LoggedExecStatic( qry, sql,
|
||||
QVariantList() << ownerName << tableName, uri ) )
|
||||
{
|
||||
throw OracleException( tr( "Could not determine table existence." ), qry );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool exists = qry.next();
|
||||
@ -2942,7 +3058,11 @@ Qgis::VectorExportResult QgsOracleProvider::createEmptyLayer(
|
||||
if ( overwrite )
|
||||
{
|
||||
// delete the table if exists, then re-create it
|
||||
if ( !exec( qry, QString( "DROP TABLE %1" ).arg( ownerTableName ), QVariantList() ) )
|
||||
|
||||
const QString sql { QStringLiteral( "DROP TABLE %1" ).arg( ownerTableName ) };
|
||||
|
||||
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), uri ) )
|
||||
{
|
||||
throw OracleException( tr( "Table %1 could not be dropped." ).arg( ownerTableName ), qry );
|
||||
}
|
||||
@ -2953,7 +3073,7 @@ Qgis::VectorExportResult QgsOracleProvider::createEmptyLayer(
|
||||
}
|
||||
}
|
||||
|
||||
QString sql = QString( "CREATE TABLE %1(" ).arg( ownerTableName );
|
||||
QString sql = QStringLiteral( "CREATE TABLE %1(" ).arg( ownerTableName );
|
||||
QString delim;
|
||||
|
||||
if ( hasPrimaryKey )
|
||||
@ -2971,7 +3091,7 @@ Qgis::VectorExportResult QgsOracleProvider::createEmptyLayer(
|
||||
|
||||
sql += ")";
|
||||
|
||||
if ( !exec( qry, sql, QVariantList() ) )
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), uri ) )
|
||||
{
|
||||
throw OracleException( tr( "Table creation failed." ), qry );
|
||||
}
|
||||
@ -2999,7 +3119,10 @@ Qgis::VectorExportResult QgsOracleProvider::createEmptyLayer(
|
||||
|
||||
if ( created )
|
||||
{
|
||||
if ( !exec( qry, QString( "DROP TABLE %1" ).arg( ownerTableName ), QVariantList() ) )
|
||||
|
||||
const QString sql { QStringLiteral( "DROP TABLE %1" ).arg( ownerTableName ) };
|
||||
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), uri ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Drop created table %1 failed.\nSQL: %2\nError: %3" )
|
||||
.arg( qry.lastQuery() )
|
||||
@ -3171,9 +3294,16 @@ void QgsOracleProvider::insertGeomMetadata( QgsOracleConn *conn, const QString &
|
||||
QgsDebugMsgLevel( QStringLiteral( "%1:%2 not found in mdsys.cs_srs - trying WKT" ).arg( parts[0] ).arg( parts[1] ), 2 );
|
||||
|
||||
QString wkt = srs.toWkt();
|
||||
if ( !exec( qry, QStringLiteral( "SELECT srid FROM mdsys.cs_srs WHERE wktext=?" ), QVariantList() << wkt ) )
|
||||
|
||||
const QString sql { QStringLiteral( "SELECT srid FROM mdsys.cs_srs WHERE wktext=?" ) };
|
||||
|
||||
{
|
||||
throw OracleException( tr( "Could not lookup WKT." ), qry );
|
||||
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList() << wkt, conn->connInfo() ) )
|
||||
{
|
||||
throw OracleException( tr( "Could not lookup WKT." ), qry );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( qry.next() )
|
||||
@ -3182,17 +3312,25 @@ void QgsOracleProvider::insertGeomMetadata( QgsOracleConn *conn, const QString &
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !exec( qry, QStringLiteral( "SELECT max(srid)+1 FROM sdo_coord_ref_system" ), QVariantList() ) || !qry.next() )
|
||||
|
||||
{
|
||||
throw OracleException( tr( "Could not determine new srid." ), qry );
|
||||
const QString sql { QStringLiteral( "SELECT max(srid)+1 FROM sdo_coord_ref_system" ) };
|
||||
|
||||
if ( !LoggedExecStatic( qry, sql, QVariantList(), conn->connInfo() ) || !qry.next() )
|
||||
{
|
||||
throw OracleException( tr( "Could not determine new srid." ), qry );
|
||||
}
|
||||
}
|
||||
|
||||
srid = qry.value( 0 ).toInt();
|
||||
|
||||
if ( !exec( qry, QStringLiteral( "INSERT"
|
||||
" INTO sdo_coord_ref_system(srid,coord_ref_sys_name,coord_ref_sys_kind,legacy_wktext,is_valid,is_legacy,information_source)"
|
||||
" VALUES (?,?,?,?,'TRUE','TRUE','GDAL/OGR via QGIS')" ),
|
||||
QVariantList() << srid << srs.description() << ( srs.isGeographic() ? "GEOGRAPHIC2D" : "PROJECTED" ) << wkt ) )
|
||||
const QString sql { QStringLiteral( "INSERT"
|
||||
" INTO sdo_coord_ref_system(srid,coord_ref_sys_name,coord_ref_sys_kind,legacy_wktext,is_valid,is_legacy,information_source)"
|
||||
" VALUES (?,?,?,?,'TRUE','TRUE','GDAL/OGR via QGIS')" ) };
|
||||
|
||||
|
||||
if ( !LoggedExecStatic( qry, sql,
|
||||
QVariantList() << srid << srs.description() << ( srs.isGeographic() ? "GEOGRAPHIC2D" : "PROJECTED" ) << wkt, conn->connInfo() ) )
|
||||
{
|
||||
throw OracleException( tr( "CRS not found and could not be created." ), qry );
|
||||
}
|
||||
@ -3203,8 +3341,10 @@ void QgsOracleProvider::insertGeomMetadata( QgsOracleConn *conn, const QString &
|
||||
throw OracleException( tr( "Cannot insert geometry metadata for table '%1' and geometry column '%2'. Both needs to be uppercase" ).arg(
|
||||
tableName, geometryColumn ), qry );
|
||||
|
||||
if ( !exec( qry, QStringLiteral( "INSERT INTO mdsys.user_sdo_geom_metadata(table_name,column_name,srid,diminfo) VALUES (?,?,?,%1)" ).arg( diminfo ),
|
||||
QVariantList() << tableName.toUpper() << geometryColumn.toUpper() << srid ) )
|
||||
const QString sql { QStringLiteral( "INSERT INTO mdsys.user_sdo_geom_metadata(table_name,column_name,srid,diminfo) VALUES (?,?,?,%1)" ).arg( diminfo ) };
|
||||
|
||||
if ( !LoggedExecStatic( qry, sql,
|
||||
QVariantList() << tableName.toUpper() << geometryColumn.toUpper() << srid, conn->connInfo() ) )
|
||||
{
|
||||
throw OracleException( tr( "Could not insert metadata." ), qry );
|
||||
}
|
||||
@ -3217,7 +3357,7 @@ QgsCoordinateReferenceSystem QgsOracleProvider::lookupCrs( QgsOracleConn *conn,
|
||||
QSqlQuery qry( *conn );
|
||||
|
||||
// apparently some EPSG codes don't have the auth_name setup in cs_srs
|
||||
if ( exec( qry, QString( "SELECT coalesce(auth_name,'EPSG'),auth_srid,wktext FROM mdsys.cs_srs WHERE srid=?" ), QVariantList() << srsid ) )
|
||||
if ( LoggedExecStatic( qry, QString( "SELECT coalesce(auth_name,'EPSG'),auth_srid,wktext FROM mdsys.cs_srs WHERE srid=?" ), QVariantList() << srsid, conn->connInfo() ) )
|
||||
{
|
||||
if ( qry.next() )
|
||||
{
|
||||
|
||||
@ -50,6 +50,7 @@ enum QgsOraclePrimaryKeyType
|
||||
PktFidMap
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \class QgsOracleProvider
|
||||
* \brief Data provider for oracle layers.
|
||||
@ -173,7 +174,7 @@ class QgsOracleProvider final: public QgsVectorDataProvider
|
||||
QString description() const override;
|
||||
QgsFeatureIterator getFeatures( const QgsFeatureRequest &request = QgsFeatureRequest() ) const override;
|
||||
|
||||
static bool exec( QSqlQuery &qry, QString sql, const QVariantList &args );
|
||||
static bool execLoggedStatic( QSqlQuery &qry, const QString &sql, const QVariantList &args, const QString &uri, const QString &originatorClass = QString(), const QString &queryOrigin = QString() );
|
||||
|
||||
bool isSaveAndLoadStyleToDatabaseSupported() const override { return true; }
|
||||
void setTransaction( QgsTransaction *transaction ) override;
|
||||
|
||||
@ -1365,15 +1365,22 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsOracleProviderConnection::
|
||||
|
||||
QSqlQuery qry( *pconn.get() );
|
||||
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
|
||||
|
||||
QgsDatabaseQueryLogWrapper logWrapper { sql, uri(), providerKey(), QStringLiteral( "QgsAbstractDatabaseProviderConnection" ), QGS_QUERY_LOG_ORIGIN };
|
||||
|
||||
if ( !qry.exec( sql ) )
|
||||
{
|
||||
logWrapper.setError( qry.lastError().text() );
|
||||
throw QgsProviderConnectionException( QObject::tr( "SQL error: %1 returned %2" )
|
||||
.arg( qry.lastQuery(),
|
||||
qry.lastError().text() ) );
|
||||
}
|
||||
|
||||
if ( feedback && feedback->isCanceled() )
|
||||
{
|
||||
logWrapper.setCanceled();
|
||||
return QgsAbstractDatabaseProviderConnection::QueryResult();
|
||||
}
|
||||
|
||||
if ( qry.isActive() )
|
||||
{
|
||||
|
||||
@ -61,6 +61,7 @@ bool QgsOracleTableModel::searchableColumn( int column ) const
|
||||
case DbtmSelectAtId:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void QgsOracleTableModel::addTableEntry( const QgsOracleLayerProperty &layerProperty )
|
||||
|
||||
@ -73,7 +73,13 @@ bool QgsOracleTransaction::executeSql( const QString &sql, QString &errorMsg, bo
|
||||
}
|
||||
|
||||
QgsDebugMsg( QStringLiteral( "Transaction sql: %1" ).arg( sql ) );
|
||||
|
||||
QgsDatabaseQueryLogWrapper logWrapper { sql, mConnString, QStringLiteral( "oracle" ), QStringLiteral( "QgsOracleConn" ), QGS_QUERY_LOG_ORIGIN };
|
||||
const bool res = mConn->exec( sql, true, &errorMsg );
|
||||
if ( ! errorMsg.isEmpty() )
|
||||
{
|
||||
logWrapper.setError( errorMsg );
|
||||
}
|
||||
if ( !res )
|
||||
{
|
||||
if ( isDirty )
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
#include "qgspostgresstringutils.h"
|
||||
#include "qgspostgresconnpool.h"
|
||||
#include "qgsvariantutils.h"
|
||||
#include "qgsdbquerylog.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QStringList>
|
||||
@ -412,8 +413,8 @@ QgsPostgresConn::QgsPostgresConn( const QString &conninfo, bool readOnly, bool s
|
||||
|
||||
if ( mPostgresqlVersion >= 90000 )
|
||||
{
|
||||
PQexecNR( QStringLiteral( "SET application_name='QGIS'" ) );
|
||||
PQexecNR( QStringLiteral( "SET extra_float_digits=3" ) );
|
||||
LoggedPQexecNR( "QgsPostgresConn", QStringLiteral( "SET application_name='QGIS'" ) );
|
||||
LoggedPQexecNR( "QgsPostgresConn", QStringLiteral( "SET extra_float_digits=3" ) );
|
||||
}
|
||||
|
||||
PQsetNoticeProcessor( mConn, noticeProcessor, nullptr );
|
||||
@ -498,7 +499,7 @@ void QgsPostgresConn::addColumnInfo( QgsPostgresLayerProperty &layerProperty, co
|
||||
.arg( quotedIdentifier( schemaName ),
|
||||
quotedIdentifier( viewName ) );
|
||||
QgsDebugMsgLevel( "getting column info: " + sql, 2 );
|
||||
QgsPostgresResult colRes( PQexec( sql ) );
|
||||
QgsPostgresResult colRes( LoggedPQexec( "QgsPostgresConn", sql ) );
|
||||
|
||||
layerProperty.pkCols.clear();
|
||||
layerProperty.nSpCols = 0;
|
||||
@ -656,7 +657,7 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
|
||||
|
||||
|
||||
QgsDebugMsgLevel( "getting table info from layer registries: " + query, 2 );
|
||||
result = PQexec( query, true );
|
||||
result = LoggedPQexec( "QgsPostgresConn", query );
|
||||
// NOTE: we intentionally continue if the query fails
|
||||
// (for example because PostGIS is not installed)
|
||||
for ( int idx = 0; idx < result.PQntuples(); idx++ )
|
||||
@ -810,14 +811,16 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
|
||||
|
||||
QgsDebugMsgLevel( "getting spatial table info from pg_catalog: " + sql, 2 );
|
||||
|
||||
result = PQexec( sql );
|
||||
|
||||
|
||||
result = LoggedPQexec( QStringLiteral( "QgsPostresConn" ), sql );
|
||||
|
||||
if ( result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Database connection was successful, but the accessible tables could not be determined. The error message from the database was:\n%1\n" )
|
||||
.arg( result.PQresultErrorMessage() ),
|
||||
tr( "PostGIS" ) );
|
||||
PQexecNR( QStringLiteral( "COMMIT" ) );
|
||||
LoggedPQexecNR( "QgsPostgresConn", QStringLiteral( "COMMIT" ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -922,7 +925,7 @@ bool QgsPostgresConn::getTableInfo( bool searchGeometryColumnsOnly, bool searchP
|
||||
|
||||
QgsDebugMsgLevel( "getting non-spatial table info: " + sql, 2 );
|
||||
|
||||
result = PQexec( sql );
|
||||
result = LoggedPQexec( QStringLiteral( "QgsPostresConn" ), sql );
|
||||
|
||||
if ( result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
@ -1018,10 +1021,10 @@ bool QgsPostgresConn::getSchemas( QList<QgsPostgresSchemaProperty> &schemas )
|
||||
|
||||
QString sql = QStringLiteral( "SELECT nspname, pg_get_userbyid(nspowner), pg_catalog.obj_description(oid) FROM pg_namespace WHERE nspname !~ '^pg_' AND nspname != 'information_schema' ORDER BY nspname" );
|
||||
|
||||
result = PQexec( sql, true );
|
||||
result = LoggedPQexec( QStringLiteral( "QgsPostresConn" ), sql );
|
||||
if ( result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
PQexecNR( QStringLiteral( "COMMIT" ) );
|
||||
LoggedPQexecNR( "QgsPostgresConn", QStringLiteral( "COMMIT" ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1084,7 +1087,7 @@ QString QgsPostgresConn::postgisVersion() const
|
||||
|
||||
mPostgresqlVersion = PQserverVersion( mConn );
|
||||
|
||||
QgsPostgresResult result( PQexec( QStringLiteral( "SELECT postgis_version()" ), false ) );
|
||||
QgsPostgresResult result( LoggedPQexecNoLogError( QStringLiteral( "QgsPostgresConn" ), QStringLiteral( "SELECT postgis_version()" ) ) );
|
||||
if ( result.PQntuples() != 1 )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "No PostGIS support in the database." ), tr( "PostGIS" ) );
|
||||
@ -1121,7 +1124,7 @@ QString QgsPostgresConn::postgisVersion() const
|
||||
// apparently PostGIS 1.5.2 doesn't report capabilities in postgis_version() anymore
|
||||
if ( mPostgisVersionMajor > 1 || ( mPostgisVersionMajor == 1 && mPostgisVersionMinor >= 5 ) )
|
||||
{
|
||||
result = PQexec( QStringLiteral( "SELECT postgis_geos_version(), postgis_proj_version()" ) );
|
||||
result = LoggedPQexec( QStringLiteral( "QgsPostresConn" ), QStringLiteral( "SELECT postgis_geos_version(), postgis_proj_version()" ) );
|
||||
mGeosAvailable = result.PQntuples() == 1 && !result.PQgetisnull( 0, 0 );
|
||||
mProjAvailable = result.PQntuples() == 1 && !result.PQgetisnull( 0, 1 );
|
||||
QgsDebugMsgLevel( QStringLiteral( "geos:%1 proj:%2" )
|
||||
@ -1146,19 +1149,18 @@ QString QgsPostgresConn::postgisVersion() const
|
||||
mTopologyAvailable = false;
|
||||
if ( mPostgisVersionMajor > 1 )
|
||||
{
|
||||
QgsPostgresResult result(
|
||||
PQexec(
|
||||
QStringLiteral(
|
||||
"SELECT has_schema_privilege(n.oid, 'usage')"
|
||||
" AND has_table_privilege(t.oid, 'select')"
|
||||
" AND has_table_privilege(l.oid, 'select')"
|
||||
" FROM pg_namespace n, pg_class t, pg_class l"
|
||||
" WHERE n.nspname = 'topology'"
|
||||
" AND t.relnamespace = n.oid"
|
||||
" AND l.relnamespace = n.oid"
|
||||
" AND t.relname = 'topology'"
|
||||
" AND l.relname = 'layer'"
|
||||
) ) );
|
||||
const QString query = QStringLiteral(
|
||||
"SELECT has_schema_privilege(n.oid, 'usage')"
|
||||
" AND has_table_privilege(t.oid, 'select')"
|
||||
" AND has_table_privilege(l.oid, 'select')"
|
||||
" FROM pg_namespace n, pg_class t, pg_class l"
|
||||
" WHERE n.nspname = 'topology'"
|
||||
" AND t.relnamespace = n.oid"
|
||||
" AND l.relnamespace = n.oid"
|
||||
" AND t.relname = 'topology'"
|
||||
" AND l.relname = 'layer'"
|
||||
);
|
||||
QgsPostgresResult result( LoggedPQexec( QStringLiteral( "QgsPostresConn" ), query ) );
|
||||
if ( result.PQntuples() >= 1 && result.PQgetvalue( 0, 0 ) == QLatin1String( "t" ) )
|
||||
{
|
||||
mTopologyAvailable = true;
|
||||
@ -1179,17 +1181,17 @@ QString QgsPostgresConn::postgisVersion() const
|
||||
if ( mPostgresqlVersion >= 90000 )
|
||||
{
|
||||
QgsDebugMsgLevel( QStringLiteral( "Checking for pointcloud support" ), 2 );
|
||||
result = PQexec( QStringLiteral(
|
||||
"SELECT has_table_privilege(c.oid, 'select')"
|
||||
" AND has_table_privilege(f.oid, 'select')"
|
||||
" FROM pg_class c, pg_class f, pg_namespace n, pg_extension e"
|
||||
" WHERE c.relnamespace = n.oid"
|
||||
" AND c.relname = 'pointcloud_columns'"
|
||||
" AND f.relnamespace = n.oid"
|
||||
" AND f.relname = 'pointcloud_formats'"
|
||||
" AND n.oid = e.extnamespace"
|
||||
" AND e.extname = 'pointcloud'"
|
||||
), false );
|
||||
result = LoggedPQexecNoLogError( QStringLiteral( "QgsPostresConn" ), QStringLiteral(
|
||||
"SELECT has_table_privilege(c.oid, 'select')"
|
||||
" AND has_table_privilege(f.oid, 'select')"
|
||||
" FROM pg_class c, pg_class f, pg_namespace n, pg_extension e"
|
||||
" WHERE c.relnamespace = n.oid"
|
||||
" AND c.relname = 'pointcloud_columns'"
|
||||
" AND f.relnamespace = n.oid"
|
||||
" AND f.relname = 'pointcloud_formats'"
|
||||
" AND n.oid = e.extnamespace"
|
||||
" AND e.extname = 'pointcloud'"
|
||||
) );
|
||||
if ( result.PQntuples() >= 1 && result.PQgetvalue( 0, 0 ) == QLatin1String( "t" ) )
|
||||
{
|
||||
mPointcloudAvailable = true;
|
||||
@ -1200,14 +1202,14 @@ QString QgsPostgresConn::postgisVersion() const
|
||||
QgsDebugMsgLevel( QStringLiteral( "Checking for raster support" ), 2 );
|
||||
if ( mPostgisVersionMajor >= 2 )
|
||||
{
|
||||
result = PQexec( QStringLiteral(
|
||||
"SELECT has_table_privilege(c.oid, 'select')"
|
||||
" FROM pg_class c, pg_namespace n, pg_type t"
|
||||
" WHERE c.relnamespace = n.oid"
|
||||
" AND n.oid = t.typnamespace"
|
||||
" AND c.relname = 'raster_columns'"
|
||||
" AND t.typname = 'raster'"
|
||||
), false );
|
||||
result = LoggedPQexecNoLogError( QStringLiteral( "QgsPostresConn" ), QStringLiteral(
|
||||
"SELECT has_table_privilege(c.oid, 'select')"
|
||||
" FROM pg_class c, pg_namespace n, pg_type t"
|
||||
" WHERE c.relnamespace = n.oid"
|
||||
" AND n.oid = t.typnamespace"
|
||||
" AND c.relname = 'raster_columns'"
|
||||
" AND t.typname = 'raster'"
|
||||
) );
|
||||
if ( result.PQntuples() >= 1 && result.PQgetvalue( 0, 0 ) == QLatin1String( "t" ) )
|
||||
{
|
||||
mRasterAvailable = true;
|
||||
@ -1327,12 +1329,14 @@ QString QgsPostgresConn::quotedJsonValue( const QVariant &value )
|
||||
return quotedString( QString::fromStdString( j.dump() ) );
|
||||
}
|
||||
|
||||
PGresult *QgsPostgresConn::PQexec( const QString &query, bool logError, bool retry ) const
|
||||
PGresult *QgsPostgresConn::PQexec( const QString &query, bool logError, bool retry, const QString &originatorClass, const QString &queryOrigin ) const
|
||||
{
|
||||
QMutexLocker locker( &mLock );
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "Executing SQL: %1" ).arg( query ), 3 );
|
||||
|
||||
std::unique_ptr<QgsDatabaseQueryLogWrapper> logWrapper = std::make_unique<QgsDatabaseQueryLogWrapper>( query, mConnInfo, QStringLiteral( "postgres" ), originatorClass, queryOrigin );
|
||||
|
||||
PGresult *res = ::PQexec( mConn, query.toUtf8() );
|
||||
|
||||
// libpq may return a non null ptr with conn status not OK so we need to check for it to allow a retry below
|
||||
@ -1341,11 +1345,13 @@ PGresult *QgsPostgresConn::PQexec( const QString &query, bool logError, bool ret
|
||||
int errorStatus = PQresultStatus( res );
|
||||
if ( errorStatus != PGRES_COMMAND_OK && errorStatus != PGRES_TUPLES_OK )
|
||||
{
|
||||
const QString error { tr( "Erroneous query: %1 returned %2 [%3]" )
|
||||
.arg( query ).arg( errorStatus ).arg( PQresultErrorMessage( res ) ) };
|
||||
logWrapper->setError( error );
|
||||
|
||||
if ( logError )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Erroneous query: %1 returned %2 [%3]" )
|
||||
.arg( query ).arg( errorStatus ).arg( PQresultErrorMessage( res ) ),
|
||||
tr( "PostGIS" ) );
|
||||
QgsMessageLog::logMessage( error, tr( "PostGIS" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1353,14 +1359,17 @@ PGresult *QgsPostgresConn::PQexec( const QString &query, bool logError, bool ret
|
||||
.arg( query ).arg( errorStatus ).arg( PQresultErrorMessage( res ) ) );
|
||||
}
|
||||
}
|
||||
logWrapper->setFetchedRows( PQntuples( res ) );
|
||||
return res;
|
||||
}
|
||||
if ( PQstatus() != CONNECTION_OK )
|
||||
{
|
||||
const QString error { tr( "Connection error: %1 returned %2 [%3]" )
|
||||
.arg( query ).arg( PQstatus() ).arg( PQerrorMessage() ) };
|
||||
logWrapper->setError( error );
|
||||
if ( logError )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Connection error: %1 returned %2 [%3]" )
|
||||
.arg( query ).arg( PQstatus() ).arg( PQerrorMessage() ),
|
||||
QgsMessageLog::logMessage( error,
|
||||
tr( "PostGIS" ) );
|
||||
}
|
||||
else
|
||||
@ -1371,9 +1380,11 @@ PGresult *QgsPostgresConn::PQexec( const QString &query, bool logError, bool ret
|
||||
}
|
||||
else
|
||||
{
|
||||
const QString error { tr( "Query failed: %1\nError: no result buffer" ).arg( query ) };
|
||||
logWrapper->setError( error );
|
||||
if ( logError )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Query failed: %1\nError: no result buffer" ).arg( query ), tr( "PostGIS" ) );
|
||||
QgsMessageLog::logMessage( error, tr( "PostGIS" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1385,6 +1396,7 @@ PGresult *QgsPostgresConn::PQexec( const QString &query, bool logError, bool ret
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "resetting bad connection." ), tr( "PostGIS" ) );
|
||||
::PQreset( mConn );
|
||||
logWrapper.reset( new QgsDatabaseQueryLogWrapper( query, mConnInfo, QStringLiteral( "postgres" ), originatorClass, queryOrigin ) );
|
||||
res = PQexec( query, logError, false );
|
||||
if ( PQstatus() == CONNECTION_OK )
|
||||
{
|
||||
@ -1395,13 +1407,17 @@ PGresult *QgsPostgresConn::PQexec( const QString &query, bool logError, bool ret
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "retry after reset failed again." ), tr( "PostGIS" ) );
|
||||
const QString error { tr( "retry after reset failed again." ) };
|
||||
logWrapper->setError( error );
|
||||
QgsMessageLog::logMessage( error, tr( "PostGIS" ) );
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "connection still bad after reset." ), tr( "PostGIS" ) );
|
||||
const QString error { tr( "connection still bad after reset." ) };
|
||||
logWrapper->setError( error );
|
||||
QgsMessageLog::logMessage( error, tr( "PostGIS" ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1442,8 +1458,8 @@ bool QgsPostgresConn::openCursor( const QString &cursorName, const QString &sql
|
||||
preStr = QStringLiteral( "BEGIN;" );
|
||||
}
|
||||
QgsDebugMsgLevel( QStringLiteral( "Binary cursor %1 for %2" ).arg( cursorName, sql ), 3 );
|
||||
return PQexecNR( QStringLiteral( "%1DECLARE %2 BINARY CURSOR%3 FOR %4" ).
|
||||
arg( preStr, cursorName, !mTransaction ? QString() : QStringLiteral( " WITH HOLD" ), sql ) );
|
||||
return LoggedPQexecNR( "QgsPostgresConn", QStringLiteral( "%1DECLARE %2 BINARY CURSOR%3 FOR %4" ).
|
||||
arg( preStr, cursorName, !mTransaction ? QString() : QStringLiteral( " WITH HOLD" ), sql ) );
|
||||
}
|
||||
|
||||
bool QgsPostgresConn::closeCursor( const QString &cursorName )
|
||||
@ -1457,7 +1473,7 @@ bool QgsPostgresConn::closeCursor( const QString &cursorName )
|
||||
postStr = QStringLiteral( ";COMMIT" );
|
||||
}
|
||||
|
||||
if ( !PQexecNR( QStringLiteral( "CLOSE %1%2" ).arg( cursorName, postStr ) ) )
|
||||
if ( !LoggedPQexecNR( QStringLiteral( "QgsPostresConn" ), QStringLiteral( "CLOSE %1%2" ).arg( cursorName, postStr ) ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -1469,11 +1485,11 @@ QString QgsPostgresConn::uniqueCursorName()
|
||||
return QStringLiteral( "qgis_%1" ).arg( ++mNextCursorId );
|
||||
}
|
||||
|
||||
bool QgsPostgresConn::PQexecNR( const QString &query )
|
||||
bool QgsPostgresConn::PQexecNR( const QString &query, const QString &originatorClass, const QString &queryOrigin )
|
||||
{
|
||||
QMutexLocker locker( &mLock ); // to protect access to mOpenCursors
|
||||
|
||||
QgsPostgresResult res( PQexec( query, false ) );
|
||||
QgsPostgresResult res( PQexec( query, false, true, originatorClass, queryOrigin ) );
|
||||
|
||||
ExecStatusType errorStatus = res.PQresultStatus();
|
||||
if ( errorStatus == PGRES_COMMAND_OK )
|
||||
@ -1495,7 +1511,7 @@ bool QgsPostgresConn::PQexecNR( const QString &query )
|
||||
|
||||
if ( PQstatus() == CONNECTION_OK )
|
||||
{
|
||||
PQexecNR( QStringLiteral( "ROLLBACK" ) );
|
||||
LoggedPQexecNR( QStringLiteral( "QgsPostresConn" ), QStringLiteral( "ROLLBACK" ) );
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -1575,11 +1591,11 @@ bool QgsPostgresConn::begin()
|
||||
QMutexLocker locker( &mLock );
|
||||
if ( mTransaction )
|
||||
{
|
||||
return PQexecNR( QStringLiteral( "SAVEPOINT transaction_savepoint" ) );
|
||||
return LoggedPQexecNR( QStringLiteral( "QgsPostresConn" ), QStringLiteral( "SAVEPOINT transaction_savepoint" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return PQexecNR( QStringLiteral( "BEGIN" ) );
|
||||
return LoggedPQexecNR( QStringLiteral( "QgsPostresConn" ), QStringLiteral( "BEGIN" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -1588,11 +1604,11 @@ bool QgsPostgresConn::commit()
|
||||
QMutexLocker locker( &mLock );
|
||||
if ( mTransaction )
|
||||
{
|
||||
return PQexecNR( QStringLiteral( "RELEASE SAVEPOINT transaction_savepoint" ) );
|
||||
return LoggedPQexecNR( QStringLiteral( "QgsPostresConn" ), QStringLiteral( "RELEASE SAVEPOINT transaction_savepoint" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return PQexecNR( QStringLiteral( "COMMIT" ) );
|
||||
return LoggedPQexecNR( QStringLiteral( "QgsPostresConn" ), QStringLiteral( "COMMIT" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -1601,12 +1617,12 @@ bool QgsPostgresConn::rollback()
|
||||
QMutexLocker locker( &mLock );
|
||||
if ( mTransaction )
|
||||
{
|
||||
return PQexecNR( QStringLiteral( "ROLLBACK TO SAVEPOINT transaction_savepoint" ) )
|
||||
&& PQexecNR( QStringLiteral( "RELEASE SAVEPOINT transaction_savepoint" ) );
|
||||
return LoggedPQexecNR( QStringLiteral( "QgsPostresConn" ), QStringLiteral( "ROLLBACK TO SAVEPOINT transaction_savepoint" ) )
|
||||
&& LoggedPQexecNR( QStringLiteral( "QgsPostresConn" ), QStringLiteral( "RELEASE SAVEPOINT transaction_savepoint" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return PQexecNR( QStringLiteral( "ROLLBACK" ) );
|
||||
return LoggedPQexecNR( QStringLiteral( "QgsPostresConn" ), QStringLiteral( "ROLLBACK" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -1892,7 +1908,7 @@ void QgsPostgresConn::deduceEndian()
|
||||
.arg( queryCounter )
|
||||
.arg( errorCounter ), 2 );
|
||||
|
||||
QgsPostgresResult res( PQexec( QStringLiteral( "select regclass('pg_class')::oid" ) ) );
|
||||
QgsPostgresResult res( LoggedPQexec( QStringLiteral( "QgsPostresConn" ), QStringLiteral( "select regclass('pg_class')::oid" ) ) );
|
||||
QString oidValue = res.PQgetvalue( 0, 0 );
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "Creating binary cursor" ), 2 );
|
||||
@ -1902,7 +1918,7 @@ void QgsPostgresConn::deduceEndian()
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "Fetching a record and attempting to get check endian-ness" ), 2 );
|
||||
|
||||
res = PQexec( QStringLiteral( "fetch forward 1 from oidcursor" ) );
|
||||
res = LoggedPQexec( QStringLiteral( "QgsPostresConn" ), QStringLiteral( "fetch forward 1 from oidcursor" ) );
|
||||
|
||||
mSwapEndian = true;
|
||||
if ( res.PQntuples() > 0 )
|
||||
@ -2084,7 +2100,7 @@ void QgsPostgresConn::retrieveLayerTypes( QVector<QgsPostgresLayerProperty *> &l
|
||||
|
||||
QgsDebugMsgLevel( "Layer types,srids and dims query: " + query, 3 );
|
||||
|
||||
QgsPostgresResult res( PQexec( query ) );
|
||||
QgsPostgresResult res( LoggedPQexec( QStringLiteral( "QgsPostresConn" ), query ) );
|
||||
if ( res.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
// TODO: print some error here ?
|
||||
@ -2678,7 +2694,7 @@ QString QgsPostgresConn::currentDatabase() const
|
||||
QMutexLocker locker( &mLock );
|
||||
QString database;
|
||||
QString sql = "SELECT current_database()";
|
||||
QgsPostgresResult res( PQexec( sql ) );
|
||||
QgsPostgresResult res( LoggedPQexec( QStringLiteral( "QgsPostresConn" ), sql ) );
|
||||
|
||||
if ( res.PQresultStatus() == PGRES_TUPLES_OK )
|
||||
{
|
||||
|
||||
@ -200,6 +200,12 @@ class QgsPoolPostgresConn
|
||||
class QgsPostgresConn *get() const { return mPgConn; }
|
||||
};
|
||||
|
||||
#include "qgsconfig.h"
|
||||
constexpr int sPostgresConQueryLogFilePrefixLength = CMAKE_SOURCE_DIR[sizeof( CMAKE_SOURCE_DIR ) - 1] == '/' ? sizeof( CMAKE_SOURCE_DIR ) + 1 : sizeof( CMAKE_SOURCE_DIR );
|
||||
#define LoggedPQexecNR(_class, query) PQexecNR( query, _class, QString(QString( __FILE__ ).mid( sPostgresConQueryLogFilePrefixLength ) + ':' + QString::number( __LINE__ ) + " (" + __FUNCTION__ + ")") )
|
||||
#define LoggedPQexec(_class, query) PQexec( query, true, true, _class, QString(QString( __FILE__ ).mid( sPostgresConQueryLogFilePrefixLength ) + ':' + QString::number( __LINE__ ) + " (" + __FUNCTION__ + ")") )
|
||||
#define LoggedPQexecNoLogError(_class, query ) PQexec( query, false, true, _class, QString(QString( __FILE__ ).mid( sPostgresConQueryLogFilePrefixLength ) + ':' + QString::number( __LINE__ ) + " (" + __FUNCTION__ + ")") )
|
||||
|
||||
class QgsPostgresConn : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -247,7 +253,7 @@ class QgsPostgresConn : public QObject
|
||||
int pgVersion() const { return mPostgresqlVersion; }
|
||||
|
||||
//! run a query and free result buffer
|
||||
bool PQexecNR( const QString &query );
|
||||
bool PQexecNR( const QString &query, const QString &originatorClass = QString(), const QString &queryOrigin = QString() );
|
||||
|
||||
//! cursor handling
|
||||
bool openCursor( const QString &cursorName, const QString &declare );
|
||||
@ -264,7 +270,7 @@ class QgsPostgresConn : public QObject
|
||||
//
|
||||
|
||||
// run a query and check for errors, thread-safe
|
||||
PGresult *PQexec( const QString &query, bool logError = true, bool retry = true ) const;
|
||||
PGresult *PQexec( const QString &query, bool logError = true, bool retry = true, const QString &originatorClass = QString(), const QString &queryOrigin = QString() ) const;
|
||||
int PQCancel();
|
||||
void PQfinish();
|
||||
QString PQerrorMessage() const;
|
||||
|
||||
@ -252,7 +252,7 @@ void QgsPostgresDataItemGuiProvider::createSchema( QgsDataItem *item, QgsDataIte
|
||||
//create the schema
|
||||
const QString sql = QStringLiteral( "CREATE SCHEMA %1" ).arg( QgsPostgresConn::quotedIdentifier( schemaName ) );
|
||||
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresDataItemGuiProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
{
|
||||
notify( tr( "New Schema" ), tr( "Unable to create schema '%1'\n%2" ).arg( schemaName,
|
||||
@ -284,7 +284,7 @@ void QgsPostgresDataItemGuiProvider::deleteSchema( QgsPGSchemaItem *schemaItem,
|
||||
}
|
||||
|
||||
const QString sql = QStringLiteral( "SELECT table_name FROM information_schema.tables WHERE table_schema='%1'" ).arg( schemaItem->name() );
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresDataItemGuiProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
notify( tr( "Delete Schema" ), tr( "Unable to delete schema." ), context, Qgis::MessageLevel::Warning );
|
||||
@ -360,7 +360,7 @@ void QgsPostgresDataItemGuiProvider::renameSchema( QgsPGSchemaItem *schemaItem,
|
||||
const QString sql = QStringLiteral( "ALTER SCHEMA %1 RENAME TO %2" )
|
||||
.arg( schemaName, QgsPostgresConn::quotedIdentifier( dlg.name() ) );
|
||||
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresDataItemGuiProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
{
|
||||
notify( tr( "Rename Schema" ), tr( "Unable to rename schema '%1'\n%2" ).arg( schemaItem->name(),
|
||||
@ -418,7 +418,7 @@ void QgsPostgresDataItemGuiProvider::renameLayer( QgsPGLayerItem *layerItem, Qgs
|
||||
sql = QStringLiteral( "ALTER TABLE %1 RENAME TO %2" ).arg( oldName, newName );
|
||||
}
|
||||
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresDataItemGuiProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
{
|
||||
notify( tr( "Rename %1" ).arg( typeName ), tr( "Unable to rename '%1' %2\n%3" ).arg( lowerTypeName, layerItem->name(),
|
||||
@ -463,7 +463,7 @@ void QgsPostgresDataItemGuiProvider::truncateTable( QgsPGLayerItem *layerItem, Q
|
||||
|
||||
const QString sql = QStringLiteral( "TRUNCATE TABLE %1" ).arg( tableRef );
|
||||
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresDataItemGuiProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
{
|
||||
notify( tr( "Truncate Table" ), tr( "Unable to truncate '%1'\n%2" ).arg( tableName,
|
||||
@ -503,7 +503,7 @@ void QgsPostgresDataItemGuiProvider::refreshMaterializedView( QgsPGLayerItem *la
|
||||
|
||||
const QString sql = QStringLiteral( "REFRESH MATERIALIZED VIEW CONCURRENTLY %1" ).arg( tableRef );
|
||||
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresDataItemGuiProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
{
|
||||
notify( tr( "Refresh View" ), tr( "Unable to refresh the view '%1'\n%2" ).arg( tableRef,
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
|
||||
bool QgsPostgresUtils::deleteLayer( const QString &uri, QString &errCause )
|
||||
{
|
||||
QgsDebugMsgLevel( "deleting layer " + uri, 2 );
|
||||
QgsDebugMsg( "deleting layer " + uri );
|
||||
|
||||
QgsDataSourceUri dsUri( uri );
|
||||
QString schemaName = dsUri.schema();
|
||||
@ -58,12 +58,12 @@ bool QgsPostgresUtils::deleteLayer( const QString &uri, QString &errCause )
|
||||
// handle deletion of views
|
||||
QString sqlViewCheck = QStringLiteral( "SELECT relkind FROM pg_class WHERE oid=regclass(%1)::oid" )
|
||||
.arg( QgsPostgresConn::quotedValue( schemaTableName ) );
|
||||
QgsPostgresResult resViewCheck( conn->PQexec( sqlViewCheck ) );
|
||||
QgsPostgresResult resViewCheck( conn->LoggedPQexec( "QgsPostgresUtils", sqlViewCheck ) );
|
||||
QString type = resViewCheck.PQgetvalue( 0, 0 );
|
||||
if ( type == QLatin1String( "v" ) || type == QLatin1String( "m" ) )
|
||||
{
|
||||
QString sql = QStringLiteral( "DROP %1VIEW %2" ).arg( type == QLatin1String( "m" ) ? QStringLiteral( "MATERIALIZED " ) : QString(), schemaTableName );
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresUtils", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
{
|
||||
errCause = QObject::tr( "Unable to delete view %1: \n%2" )
|
||||
@ -85,7 +85,7 @@ bool QgsPostgresUtils::deleteLayer( const QString &uri, QString &errCause )
|
||||
"AND f_table_schema=%1 AND f_table_name=%2" )
|
||||
.arg( QgsPostgresConn::quotedValue( schemaName ),
|
||||
QgsPostgresConn::quotedValue( tableName ) );
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresUtils", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
errCause = QObject::tr( "Unable to delete layer %1: \n%2" )
|
||||
@ -113,7 +113,7 @@ bool QgsPostgresUtils::deleteLayer( const QString &uri, QString &errCause )
|
||||
QgsPostgresConn::quotedValue( tableName ) );
|
||||
}
|
||||
|
||||
result = conn->PQexec( sql );
|
||||
result = conn->LoggedPQexec( "QgsPostgresUtils", sql );
|
||||
if ( result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
errCause = QObject::tr( "Unable to delete layer %1: \n%2" )
|
||||
@ -129,7 +129,7 @@ bool QgsPostgresUtils::deleteLayer( const QString &uri, QString &errCause )
|
||||
|
||||
bool QgsPostgresUtils::deleteSchema( const QString &schema, const QgsDataSourceUri &uri, QString &errCause, bool cascade )
|
||||
{
|
||||
QgsDebugMsgLevel( "deleting schema " + schema, 2 );
|
||||
QgsDebugMsg( "deleting schema " + schema );
|
||||
|
||||
if ( schema.isEmpty() )
|
||||
return false;
|
||||
@ -147,7 +147,7 @@ bool QgsPostgresUtils::deleteSchema( const QString &schema, const QgsDataSourceU
|
||||
QString sql = QStringLiteral( "DROP SCHEMA %1 %2" )
|
||||
.arg( schemaName, cascade ? QStringLiteral( "CASCADE" ) : QString() );
|
||||
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresUtils", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
{
|
||||
errCause = QObject::tr( "Unable to delete schema %1: \n%2" )
|
||||
@ -262,7 +262,7 @@ bool QgsPGConnectionItem::handleDrop( const QMimeData *data, const QString &toSc
|
||||
if ( srcLayer->isValid() )
|
||||
{
|
||||
uri.setDataSource( QString(), u.name, srcLayer->geometryType() != QgsWkbTypes::NullGeometry ? QStringLiteral( "geom" ) : QString() );
|
||||
QgsDebugMsgLevel( "URI " + uri.uri( false ), 2 );
|
||||
QgsDebugMsg( "URI " + uri.uri( false ) );
|
||||
|
||||
if ( !toSchema.isNull() )
|
||||
{
|
||||
@ -365,7 +365,7 @@ QString QgsPGLayerItem::createUri()
|
||||
if ( uri.wkbType() != QgsWkbTypes::NoGeometry && mLayerProperty.srids.at( 0 ) != std::numeric_limits<int>::min() )
|
||||
uri.setSrid( QString::number( mLayerProperty.srids.at( 0 ) ) );
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "layer uri: %1" ).arg( uri.uri( false ) ), 2 );
|
||||
QgsDebugMsg( QStringLiteral( "layer uri: %1" ).arg( uri.uri( false ) ) );
|
||||
return uri.uri( false );
|
||||
}
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
#include "qgspostgresprovider.h"
|
||||
#include "qgspostgrestransaction.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsdbquerylog.h"
|
||||
#include "qgsmessagelog.h"
|
||||
#include "qgssettings.h"
|
||||
#include "qgsexception.h"
|
||||
@ -292,12 +293,18 @@ bool QgsPostgresFeatureIterator::fetchFeature( QgsFeature &feature )
|
||||
QgsDebugMsgLevel( QStringLiteral( "fetching %1 features." ).arg( mFeatureQueueSize ), 4 );
|
||||
|
||||
lock();
|
||||
|
||||
QgsDatabaseQueryLogWrapper logWrapper { fetch, mSource->mConnInfo, QStringLiteral( "postgres" ), QStringLiteral( "QgsPostgresFeatureIterator" ), QGS_QUERY_LOG_ORIGIN };
|
||||
|
||||
if ( mConn->PQsendQuery( fetch ) == 0 ) // fetch features asynchronously
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "Fetching from cursor %1 failed\nDatabase error: %2" ).arg( mCursorName, mConn->PQerrorMessage() ), QObject::tr( "PostGIS" ) );
|
||||
const QString error { QObject::tr( "Fetching from cursor %1 failed\nDatabase error: %2" ).arg( mCursorName, mConn->PQerrorMessage() ) };
|
||||
QgsMessageLog::logMessage( error, QObject::tr( "PostGIS" ) );
|
||||
logWrapper.setError( error );
|
||||
}
|
||||
|
||||
QgsPostgresResult queryResult;
|
||||
long long fetchedRows { 0 };
|
||||
for ( ;; )
|
||||
{
|
||||
queryResult = mConn->PQgetResult();
|
||||
@ -313,6 +320,8 @@ bool QgsPostgresFeatureIterator::fetchFeature( QgsFeature &feature )
|
||||
int rows = queryResult.PQntuples();
|
||||
if ( rows == 0 )
|
||||
continue;
|
||||
else
|
||||
fetchedRows += rows;
|
||||
|
||||
mLastFetch = rows < mFeatureQueueSize;
|
||||
|
||||
@ -324,6 +333,11 @@ bool QgsPostgresFeatureIterator::fetchFeature( QgsFeature &feature )
|
||||
}
|
||||
unlock();
|
||||
|
||||
if ( fetchedRows > 0 )
|
||||
{
|
||||
logWrapper.setFetchedRows( fetchedRows );
|
||||
}
|
||||
|
||||
#if 0 //disabled dynamic queue size
|
||||
if ( timer.elapsed() > 500 && mFeatureQueueSize > 1 )
|
||||
{
|
||||
@ -423,7 +437,7 @@ bool QgsPostgresFeatureIterator::rewind()
|
||||
|
||||
// move cursor to first record
|
||||
|
||||
mConn->PQexecNR( QStringLiteral( "move absolute 0 in %1" ).arg( mCursorName ) );
|
||||
mConn->LoggedPQexecNR( "QgsPostgresFeatureIterator", QStringLiteral( "move absolute 0 in %1" ).arg( mCursorName ) );
|
||||
mFeatureQueue.clear();
|
||||
mFetched = 0;
|
||||
mLastFetch = false;
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
#include "qgssettings.h"
|
||||
#include "qgsstringutils.h"
|
||||
#include "qgsjsonutils.h"
|
||||
#include "qgsdbquerylog.h"
|
||||
|
||||
#include "qgspostgresprovider.h"
|
||||
#include "qgsprovidermetadata.h"
|
||||
@ -65,13 +66,13 @@ inline qint32 FID2PKINT( qint64 x )
|
||||
|
||||
static bool tableExists( QgsPostgresConn &conn, const QString &name )
|
||||
{
|
||||
QgsPostgresResult res( conn.PQexec( "SELECT EXISTS ( SELECT oid FROM pg_catalog.pg_class WHERE relname=" + QgsPostgresConn::quotedValue( name ) + ")" ) );
|
||||
QgsPostgresResult res( conn.LoggedPQexec( QStringLiteral( "tableExists" ), "SELECT EXISTS ( SELECT oid FROM pg_catalog.pg_class WHERE relname=" + QgsPostgresConn::quotedValue( name ) + ")" ) );
|
||||
return res.PQgetvalue( 0, 0 ).startsWith( 't' );
|
||||
}
|
||||
|
||||
static bool columnExists( QgsPostgresConn &conn, const QString &table, const QString &column )
|
||||
{
|
||||
QgsPostgresResult res( conn.PQexec( "SELECT COUNT(*) FROM information_schema.columns WHERE table_name=" + QgsPostgresConn::quotedValue( table ) + " and column_name=" + QgsPostgresConn::quotedValue( column ) ) );
|
||||
QgsPostgresResult res( conn.LoggedPQexec( QStringLiteral( "columnExists" ), "SELECT COUNT(*) FROM information_schema.columns WHERE table_name=" + QgsPostgresConn::quotedValue( table ) + " and column_name=" + QgsPostgresConn::quotedValue( column ) ) );
|
||||
return res.PQgetvalue( 0, 0 ).toInt() > 0;
|
||||
}
|
||||
|
||||
@ -434,7 +435,7 @@ QgsCoordinateReferenceSystem QgsPostgresProvider::sridToCrs( int srid, QgsPostgr
|
||||
{
|
||||
if ( conn )
|
||||
{
|
||||
QgsPostgresResult result( conn->PQexec( QStringLiteral( "SELECT auth_name, auth_srid, srtext, proj4text FROM spatial_ref_sys WHERE srid=%1" ).arg( srid ) ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( QStringLiteral( "QgsPostgresProvider" ), QStringLiteral( "SELECT auth_name, auth_srid, srtext, proj4text FROM spatial_ref_sys WHERE srid=%1" ).arg( srid ) ) );
|
||||
if ( result.PQresultStatus() == PGRES_TUPLES_OK )
|
||||
{
|
||||
if ( result.PQntuples() > 0 )
|
||||
@ -925,7 +926,7 @@ bool QgsPostgresProvider::loadFields()
|
||||
|
||||
// Get the table description
|
||||
sql = QStringLiteral( "SELECT description FROM pg_description WHERE objoid=regclass(%1)::oid AND objsubid=0" ).arg( quotedValue( mQuery ) );
|
||||
QgsPostgresResult tresult( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult tresult( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( tresult.PQntuples() > 0 )
|
||||
{
|
||||
mDataComment = tresult.PQgetvalue( 0, 0 );
|
||||
@ -937,7 +938,7 @@ bool QgsPostgresProvider::loadFields()
|
||||
// field name, type, length, and precision (if numeric)
|
||||
sql = QStringLiteral( "SELECT * FROM %1 LIMIT 0" ).arg( mQuery );
|
||||
|
||||
QgsPostgresResult result( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult result( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
|
||||
QMap<Oid, QMap<int, QString> > fmtFieldTypeMap, descrMap, defValMap, identityMap, generatedMap;
|
||||
QMap<Oid, QMap<int, Oid> > attTypeIdMap;
|
||||
@ -988,7 +989,7 @@ bool QgsPostgresProvider::loadFields()
|
||||
connectionRO()->pgVersion() >= 120000 ? QStringLiteral( ", attgenerated" ) : QString(),
|
||||
tableoidsFilter );
|
||||
|
||||
QgsPostgresResult fmtFieldTypeResult( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult fmtFieldTypeResult( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
for ( int i = 0; i < fmtFieldTypeResult.PQntuples(); ++i )
|
||||
{
|
||||
Oid attrelid = fmtFieldTypeResult.PQgetvalue( i, 0 ).toUInt();
|
||||
@ -1036,7 +1037,7 @@ bool QgsPostgresProvider::loadFields()
|
||||
|
||||
// Collect type info
|
||||
sql = QStringLiteral( "SELECT oid,typname,typtype,typelem,typlen FROM pg_type %1" ).arg( attroidsFilter );
|
||||
QgsPostgresResult typeResult( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult typeResult( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
|
||||
QMap<Oid, PGTypeInfo> typeMap;
|
||||
for ( int i = 0; i < typeResult.PQntuples(); ++i )
|
||||
@ -1080,7 +1081,7 @@ bool QgsPostgresProvider::loadFields()
|
||||
{
|
||||
// get correct formatted field type for domain
|
||||
sql = QStringLiteral( "SELECT format_type(%1, %2)" ).arg( fldtyp ).arg( fldMod );
|
||||
QgsPostgresResult fmtFieldModResult( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult fmtFieldModResult( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( fmtFieldModResult.PQntuples() > 0 )
|
||||
{
|
||||
formattedFieldType = fmtFieldModResult.PQgetvalue( 0, 0 );
|
||||
@ -1413,7 +1414,7 @@ void QgsPostgresProvider::setEditorWidgets()
|
||||
"AND field_name IN ( %4 )" ) .
|
||||
arg( EDITOR_WIDGET_STYLES_TABLE, quotedValue( mSchemaName ),
|
||||
quotedValue( mTableName ), quotedFnames.join( "," ) );
|
||||
QgsPostgresResult result( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult result( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
for ( int i = 0; i < result.PQntuples(); ++i )
|
||||
{
|
||||
if ( result.PQgetisnull( i, 2 ) ) continue; // config can be null and it's OK
|
||||
@ -1459,7 +1460,7 @@ bool QgsPostgresProvider::hasSufficientPermsAndCapabilities()
|
||||
{
|
||||
// Check that we can read from the table (i.e., we have select permission).
|
||||
QString sql = QStringLiteral( "SELECT * FROM %1 LIMIT 1" ).arg( mQuery );
|
||||
QgsPostgresResult testAccess( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult testAccess( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( testAccess.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Unable to access the %1 relation.\nThe error message from the database was:\n%2.\nSQL: %3" )
|
||||
@ -1473,7 +1474,7 @@ bool QgsPostgresProvider::hasSufficientPermsAndCapabilities()
|
||||
|
||||
if ( connectionRO()->pgVersion() >= 90000 )
|
||||
{
|
||||
testAccess = connectionRO()->PQexec( QStringLiteral( "SELECT pg_is_in_recovery()" ) );
|
||||
testAccess = connectionRO()->LoggedPQexec( "QgsPostgresProvider", QStringLiteral( "SELECT pg_is_in_recovery()" ) );
|
||||
if ( testAccess.PQresultStatus() != PGRES_TUPLES_OK || testAccess.PQgetvalue( 0, 0 ) == QLatin1String( "t" ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "PostgreSQL is still in recovery after a database crash\n(or you are connected to a (read-only) standby server).\nWrite accesses will be denied." ), tr( "PostGIS" ) );
|
||||
@ -1517,7 +1518,7 @@ bool QgsPostgresProvider::hasSufficientPermsAndCapabilities()
|
||||
.arg( quotedValue( mQuery ) );
|
||||
}
|
||||
|
||||
testAccess = connectionRO()->PQexec( sql );
|
||||
testAccess = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( testAccess.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Unable to determine table access privileges for the %1 relation.\nThe error message from the database was:\n%2.\nSQL: %3" )
|
||||
@ -1563,7 +1564,7 @@ bool QgsPostgresProvider::hasSufficientPermsAndCapabilities()
|
||||
.arg( quotedValue( mTableName ),
|
||||
quotedValue( mSchemaName ),
|
||||
connectionRO()->pgVersion() < 80100 ? "pg_get_userbyid(relowner)=current_user" : "pg_has_role(relowner,'MEMBER')" );
|
||||
testAccess = connectionRO()->PQexec( sql );
|
||||
testAccess = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( testAccess.PQresultStatus() == PGRES_TUPLES_OK && testAccess.PQntuples() == 1 )
|
||||
{
|
||||
mEnabledCapabilities |= QgsVectorDataProvider::AddAttributes | QgsVectorDataProvider::DeleteAttributes | QgsVectorDataProvider::RenameAttributes;
|
||||
@ -1599,7 +1600,7 @@ bool QgsPostgresProvider::hasSufficientPermsAndCapabilities()
|
||||
|
||||
QString sql = QStringLiteral( "SELECT * FROM %1 LIMIT 1" ).arg( mQuery );
|
||||
|
||||
testAccess = connectionRO()->PQexec( sql );
|
||||
testAccess = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( testAccess.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Unable to execute the query.\nThe error message from the database was:\n%1.\nSQL: %2" )
|
||||
@ -1652,13 +1653,13 @@ bool QgsPostgresProvider::determinePrimaryKey()
|
||||
{
|
||||
sql = QStringLiteral( "SELECT count(*) FROM pg_inherits WHERE inhparent=%1::regclass" ).arg( quotedValue( mQuery ) );
|
||||
QgsDebugMsgLevel( QStringLiteral( "Checking whether %1 is a parent table" ).arg( sql ), 2 );
|
||||
QgsPostgresResult res( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult res( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
bool isParentTable( res.PQntuples() == 0 || res.PQgetvalue( 0, 0 ).toInt() > 0 );
|
||||
|
||||
sql = QStringLiteral( "SELECT indexrelid FROM pg_index WHERE indrelid=%1::regclass AND (indisprimary OR indisunique) ORDER BY CASE WHEN indisprimary THEN 1 ELSE 2 END LIMIT 1" ).arg( quotedValue( mQuery ) );
|
||||
QgsDebugMsgLevel( QStringLiteral( "Retrieving first primary or unique index: %1" ).arg( sql ), 2 );
|
||||
|
||||
res = connectionRO()->PQexec( sql );
|
||||
res = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
QgsDebugMsgLevel( QStringLiteral( "Got %1 rows." ).arg( res.PQntuples() ), 2 );
|
||||
|
||||
QStringList log;
|
||||
@ -1686,7 +1687,7 @@ bool QgsPostgresProvider::determinePrimaryKey()
|
||||
{
|
||||
// If there is an generated id on the table, use that instead,
|
||||
sql = QStringLiteral( "SELECT attname FROM pg_attribute WHERE attidentity IN ('a','d') AND attrelid=regclass(%1) LIMIT 1" ).arg( quotedValue( mQuery ) );
|
||||
res = connectionRO()->PQexec( sql );
|
||||
res = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( res.PQntuples() == 1 )
|
||||
{
|
||||
// Could warn the user here that performance will suffer if
|
||||
@ -1703,7 +1704,7 @@ bool QgsPostgresProvider::determinePrimaryKey()
|
||||
// If there is an oid on the table, use that instead,
|
||||
sql = QStringLiteral( "SELECT attname FROM pg_attribute WHERE attname='oid' AND attrelid=regclass(%1)" ).arg( quotedValue( mQuery ) );
|
||||
|
||||
res = connectionRO()->PQexec( sql );
|
||||
res = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( res.PQntuples() == 1 )
|
||||
{
|
||||
// Could warn the user here that performance will suffer if
|
||||
@ -1717,7 +1718,7 @@ bool QgsPostgresProvider::determinePrimaryKey()
|
||||
{
|
||||
sql = QStringLiteral( "SELECT attname FROM pg_attribute WHERE attname='ctid' AND attrelid=regclass(%1)" ).arg( quotedValue( mQuery ) );
|
||||
|
||||
res = connectionRO()->PQexec( sql );
|
||||
res = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( res.PQntuples() == 1 )
|
||||
{
|
||||
mPrimaryKeyType = PktTid;
|
||||
@ -1750,7 +1751,7 @@ bool QgsPostgresProvider::determinePrimaryKey()
|
||||
sql = QStringLiteral( "SELECT attname,attnotnull FROM pg_index,pg_attribute WHERE indexrelid=%1 AND indrelid=attrelid AND pg_attribute.attnum=any(pg_index.indkey)" ).arg( indrelid );
|
||||
|
||||
QgsDebugMsgLevel( "Retrieving key columns: " + sql, 2 );
|
||||
res = connectionRO()->PQexec( sql );
|
||||
res = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
QgsDebugMsgLevel( QStringLiteral( "Got %1 rows." ).arg( res.PQntuples() ), 2 );
|
||||
|
||||
bool mightBeNull = false;
|
||||
@ -1934,7 +1935,7 @@ bool QgsPostgresProvider::uniqueData( const QString "edColNames )
|
||||
mQuery,
|
||||
filterWhereClause() );
|
||||
|
||||
QgsPostgresResult unique( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult unique( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
|
||||
if ( unique.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
@ -1962,7 +1963,7 @@ QVariant QgsPostgresProvider::minimumValue( int index ) const
|
||||
|
||||
sql = QStringLiteral( "SELECT %1 FROM (%2) foo" ).arg( connectionRO()->fieldExpression( fld ), sql );
|
||||
|
||||
QgsPostgresResult rmin( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult rmin( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
return convertValue( fld.type(), fld.subType(), rmin.PQgetvalue( 0, 0 ), fld.typeName() );
|
||||
}
|
||||
catch ( PGFieldNotFound )
|
||||
@ -1998,7 +1999,7 @@ QSet<QVariant> QgsPostgresProvider::uniqueValues( int index, int limit ) const
|
||||
|
||||
sql = QStringLiteral( "SELECT %1 FROM (%2) foo" ).arg( connectionRO()->fieldExpression( fld ), sql );
|
||||
|
||||
QgsPostgresResult res( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult res( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( res.PQresultStatus() == PGRES_TUPLES_OK )
|
||||
{
|
||||
for ( int i = 0; i < res.PQntuples(); i++ )
|
||||
@ -2040,7 +2041,7 @@ QStringList QgsPostgresProvider::uniqueStringsMatching( int index, const QString
|
||||
|
||||
sql = QStringLiteral( "SELECT %1 FROM (%2) foo" ).arg( connectionRO()->fieldExpression( fld ), sql );
|
||||
|
||||
QgsPostgresResult res( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult res( connectionRO()->LoggedPQexec( QStringLiteral( "QgsPostgresProvider" ), sql ) );
|
||||
if ( res.PQresultStatus() == PGRES_TUPLES_OK )
|
||||
{
|
||||
for ( int i = 0; i < res.PQntuples(); i++ )
|
||||
@ -2081,7 +2082,7 @@ void QgsPostgresProvider::enumValues( int index, QStringList &enumList ) const
|
||||
|
||||
//is type an enum?
|
||||
const QString typeSql = QStringLiteral( "SELECT typtype FROM pg_type WHERE typname=%1" ).arg( quotedValue( typeName ) );
|
||||
QgsPostgresResult typeRes( connectionRO()->PQexec( typeSql ) );
|
||||
QgsPostgresResult typeRes( connectionRO()->LoggedPQexec( QStringLiteral( "QgsPostgresProvider" ), typeSql ) );
|
||||
if ( typeRes.PQresultStatus() != PGRES_TUPLES_OK || typeRes.PQntuples() < 1 )
|
||||
{
|
||||
mShared->setFieldSupportsEnumValues( index, false );
|
||||
@ -2114,7 +2115,7 @@ bool QgsPostgresProvider::parseEnumRange( QStringList &enumValues, const QString
|
||||
QString enumRangeSql = QStringLiteral( "SELECT enumlabel FROM pg_catalog.pg_enum WHERE enumtypid=(SELECT atttypid::regclass FROM pg_attribute WHERE attrelid=%1::regclass AND attname=%2)" )
|
||||
.arg( quotedValue( mQuery ),
|
||||
quotedValue( attributeName ) );
|
||||
QgsPostgresResult enumRangeRes( connectionRO()->PQexec( enumRangeSql ) );
|
||||
QgsPostgresResult enumRangeRes( connectionRO()->LoggedPQexec( QStringLiteral( "QgsPostgresProvider" ), enumRangeSql ) );
|
||||
if ( enumRangeRes.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
return false;
|
||||
|
||||
@ -2132,7 +2133,7 @@ bool QgsPostgresProvider::parseDomainCheckConstraint( QStringList &enumValues, c
|
||||
|
||||
//is it a domain type with a check constraint?
|
||||
QString domainSql = QStringLiteral( "SELECT domain_name, domain_schema FROM information_schema.columns WHERE table_name=%1 AND column_name=%2" ).arg( quotedValue( mTableName ), quotedValue( attributeName ) );
|
||||
QgsPostgresResult domainResult( connectionRO()->PQexec( domainSql ) );
|
||||
QgsPostgresResult domainResult( connectionRO()->LoggedPQexec( QStringLiteral( "QgsPostgresProvider" ), domainSql ) );
|
||||
if ( domainResult.PQresultStatus() == PGRES_TUPLES_OK && domainResult.PQntuples() > 0 && !domainResult.PQgetvalue( 0, 0 ).isNull() )
|
||||
{
|
||||
QString domainCheckDefinitionSql;
|
||||
@ -2168,7 +2169,7 @@ bool QgsPostgresProvider::parseDomainCheckConstraint( QStringList &enumValues, c
|
||||
|
||||
}
|
||||
|
||||
QgsPostgresResult domainCheckRes( connectionRO()->PQexec( domainCheckDefinitionSql ) );
|
||||
QgsPostgresResult domainCheckRes( connectionRO()->LoggedPQexec( QStringLiteral( "QgsPostgresProvider" ), domainCheckDefinitionSql ) );
|
||||
if ( domainCheckRes.PQresultStatus() == PGRES_TUPLES_OK && domainCheckRes.PQntuples() > 0 )
|
||||
{
|
||||
QString checkDefinition = domainCheckRes.PQgetvalue( 0, 0 );
|
||||
@ -2230,7 +2231,7 @@ QVariant QgsPostgresProvider::maximumValue( int index ) const
|
||||
|
||||
sql = QStringLiteral( "SELECT %1 FROM (%2) foo" ).arg( connectionRO()->fieldExpression( fld ), sql );
|
||||
|
||||
QgsPostgresResult rmax( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult rmax( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
|
||||
return convertValue( fld.type(), fld.subType(), rmax.PQgetvalue( 0, 0 ), fld.typeName() );
|
||||
}
|
||||
@ -2278,7 +2279,7 @@ QVariant QgsPostgresProvider::defaultValue( int fieldId ) const
|
||||
{
|
||||
QgsField fld = field( fieldId );
|
||||
|
||||
QgsPostgresResult res( connectionRO()->PQexec( QStringLiteral( "SELECT %1" ).arg( defVal ) ) );
|
||||
QgsPostgresResult res( connectionRO()->LoggedPQexec( QStringLiteral( "QgsPostgresProvider" ), QStringLiteral( "SELECT %1" ).arg( defVal ) ) );
|
||||
|
||||
if ( res.result() )
|
||||
{
|
||||
@ -2315,7 +2316,7 @@ QString QgsPostgresProvider::paramValue( const QString &fieldValue, const QStrin
|
||||
|
||||
if ( fieldValue == defaultValue && !defaultValue.isNull() )
|
||||
{
|
||||
QgsPostgresResult result( connectionRO()->PQexec( QStringLiteral( "SELECT %1" ).arg( defaultValue ) ) );
|
||||
QgsPostgresResult result( connectionRO()->LoggedPQexec( QStringLiteral( "QgsPostgresProvider" ), QStringLiteral( "SELECT %1" ).arg( defaultValue ) ) );
|
||||
if ( result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
throw PGException( result );
|
||||
|
||||
@ -2336,7 +2337,7 @@ bool QgsPostgresProvider::getTopoLayerInfo()
|
||||
.arg( quotedValue( mSchemaName ),
|
||||
quotedValue( mTableName ),
|
||||
quotedValue( mGeometryColumn ) );
|
||||
QgsPostgresResult result( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult result( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
throw PGException( result ); // we should probably not do this
|
||||
@ -2369,7 +2370,7 @@ void QgsPostgresProvider::dropOrphanedTopoGeoms()
|
||||
|
||||
QgsDebugMsgLevel( "TopoGeom orphans cleanup query: " + sql, 2 );
|
||||
|
||||
connectionRW()->PQexecNR( sql );
|
||||
connectionRW()->LoggedPQexecNR( "QgsPostgresProvider", sql );
|
||||
}
|
||||
|
||||
QString QgsPostgresProvider::geomParam( int offset ) const
|
||||
@ -2748,7 +2749,7 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist, Flags flags )
|
||||
}
|
||||
}
|
||||
|
||||
conn->PQexecNR( QStringLiteral( "DEALLOCATE addfeatures" ) );
|
||||
conn->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "DEALLOCATE addfeatures" ) );
|
||||
|
||||
returnvalue &= conn->commit();
|
||||
if ( mTransaction )
|
||||
@ -2760,7 +2761,7 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist, Flags flags )
|
||||
{
|
||||
pushError( tr( "PostGIS error while adding features: %1" ).arg( e.errorMessage() ) );
|
||||
conn->rollback();
|
||||
conn->PQexecNR( QStringLiteral( "DEALLOCATE addfeatures" ) );
|
||||
conn->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "DEALLOCATE addfeatures" ) );
|
||||
returnvalue = false;
|
||||
}
|
||||
|
||||
@ -2808,7 +2809,7 @@ bool QgsPostgresProvider::deleteFeatures( const QgsFeatureIds &ids )
|
||||
QgsDebugMsgLevel( "delete sql: " + sql, 2 );
|
||||
|
||||
//send DELETE statement and do error handling
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK && result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
throw PGException( result );
|
||||
|
||||
@ -2872,7 +2873,7 @@ bool QgsPostgresProvider::truncate()
|
||||
QgsDebugMsgLevel( "truncate sql: " + sql, 2 );
|
||||
|
||||
//send truncate statement and do error handling
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK && result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
throw PGException( result );
|
||||
|
||||
@ -2947,7 +2948,7 @@ bool QgsPostgresProvider::addAttributes( const QList<QgsField> &attributes )
|
||||
}
|
||||
|
||||
//send sql statement and do error handling
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
throw PGException( result );
|
||||
|
||||
@ -2959,7 +2960,7 @@ bool QgsPostgresProvider::addAttributes( const QList<QgsField> &attributes )
|
||||
.arg( mQuery,
|
||||
quotedIdentifier( iter->name() ),
|
||||
quotedValue( iter->comment() ) );
|
||||
result = conn->PQexec( sql );
|
||||
result = conn->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
throw PGException( result );
|
||||
}
|
||||
@ -3014,7 +3015,7 @@ bool QgsPostgresProvider::deleteAttributes( const QgsAttributeIds &ids )
|
||||
quotedIdentifier( column ) );
|
||||
|
||||
//send sql statement and do error handling
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
throw PGException( result );
|
||||
|
||||
@ -3081,7 +3082,7 @@ bool QgsPostgresProvider::renameAttributes( const QgsFieldNameMap &renamedAttrib
|
||||
{
|
||||
conn->begin();
|
||||
//send sql statement and do error handling
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
throw PGException( result );
|
||||
returnvalue = conn->commit();
|
||||
@ -3208,7 +3209,7 @@ bool QgsPostgresProvider::changeAttributeValues( const QgsChangedAttributesMap &
|
||||
// or if the user only changed GENERATED fields in the form/attribute table.
|
||||
if ( numChangedFields > 0 )
|
||||
{
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK && result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
throw PGException( result );
|
||||
}
|
||||
@ -3408,7 +3409,7 @@ bool QgsPostgresProvider::changeGeometryValues( const QgsGeometryMap &geometry_m
|
||||
.arg( quotedIdentifier( mTopoLayerInfo.topologyName ) )
|
||||
.arg( mTopoLayerInfo.layerId )
|
||||
.arg( old_tg_id );
|
||||
result = conn->PQexec( replace );
|
||||
result = conn->LoggedPQexec( QStringLiteral( "QgsPostgresProvider" ), replace );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Exception thrown due to PQexec of this query returning != PGRES_COMMAND_OK (%1 != expected %2): %3" )
|
||||
@ -3423,7 +3424,7 @@ bool QgsPostgresProvider::changeGeometryValues( const QgsGeometryMap &geometry_m
|
||||
.arg( mTopoLayerInfo.layerId )
|
||||
.arg( new_tg_id );
|
||||
QgsDebugMsgLevel( "relation swap: " + replace, 2 );
|
||||
result = conn->PQexec( replace );
|
||||
result = conn->LoggedPQexec( QStringLiteral( "QgsPostgresProvider" ), replace );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Exception thrown due to PQexec of this query returning != PGRES_COMMAND_OK (%1 != expected %2): %3" )
|
||||
@ -3434,11 +3435,11 @@ bool QgsPostgresProvider::changeGeometryValues( const QgsGeometryMap &geometry_m
|
||||
|
||||
} // for each feature
|
||||
|
||||
conn->PQexecNR( QStringLiteral( "DEALLOCATE updatefeatures" ) );
|
||||
conn->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "DEALLOCATE updatefeatures" ) );
|
||||
if ( mSpatialColType == SctTopoGeometry )
|
||||
{
|
||||
connectionRO()->PQexecNR( QStringLiteral( "DEALLOCATE getid" ) );
|
||||
conn->PQexecNR( QStringLiteral( "DEALLOCATE replacetopogeom" ) );
|
||||
connectionRO()->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "DEALLOCATE getid" ) );
|
||||
conn->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "DEALLOCATE replacetopogeom" ) );
|
||||
}
|
||||
|
||||
returnvalue &= conn->commit();
|
||||
@ -3449,11 +3450,11 @@ bool QgsPostgresProvider::changeGeometryValues( const QgsGeometryMap &geometry_m
|
||||
{
|
||||
pushError( tr( "PostGIS error while changing geometry values: %1" ).arg( e.errorMessage() ) );
|
||||
conn->rollback();
|
||||
conn->PQexecNR( QStringLiteral( "DEALLOCATE updatefeatures" ) );
|
||||
conn->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "DEALLOCATE updatefeatures" ) );
|
||||
if ( mSpatialColType == SctTopoGeometry )
|
||||
{
|
||||
connectionRO()->PQexecNR( QStringLiteral( "DEALLOCATE getid" ) );
|
||||
conn->PQexecNR( QStringLiteral( "DEALLOCATE replacetopogeom" ) );
|
||||
connectionRO()->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "DEALLOCATE getid" ) );
|
||||
conn->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "DEALLOCATE replacetopogeom" ) );
|
||||
}
|
||||
returnvalue = false;
|
||||
}
|
||||
@ -3575,7 +3576,7 @@ bool QgsPostgresProvider::changeFeatures( const QgsChangedAttributesMap &attr_ma
|
||||
{
|
||||
sql += QStringLiteral( " WHERE %1" ).arg( whereClause( fid ) );
|
||||
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK && result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
throw PGException( result );
|
||||
}
|
||||
@ -3609,7 +3610,7 @@ bool QgsPostgresProvider::changeFeatures( const QgsChangedAttributesMap &attr_ma
|
||||
throw PGException( result );
|
||||
}
|
||||
|
||||
conn->PQexecNR( QStringLiteral( "DEALLOCATE updatefeature" ) );
|
||||
conn->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "DEALLOCATE updatefeature" ) );
|
||||
}
|
||||
|
||||
// update feature id map if key was changed
|
||||
@ -3694,7 +3695,7 @@ bool QgsPostgresProvider::setSubsetString( const QString &theSQL, bool updateFea
|
||||
|
||||
sql += QLatin1String( " LIMIT 0" );
|
||||
|
||||
QgsPostgresResult res( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult res( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( res.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
pushError( res.PQresultErrorMessage() );
|
||||
@ -3759,7 +3760,7 @@ long long QgsPostgresProvider::featureCount() const
|
||||
// parse explain output to estimate feature count
|
||||
// we don't use pg_class reltuples because it returns 0 for view
|
||||
sql = QStringLiteral( "EXPLAIN (FORMAT JSON) SELECT 1 FROM %1%2" ).arg( mQuery, filterWhereClause() );
|
||||
QgsPostgresResult result( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult result( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
|
||||
const QString json = result.PQgetvalue( 0, 0 );
|
||||
const QVariantList explain = QgsJsonUtils::parseJson( json ).toList();
|
||||
@ -3774,14 +3775,14 @@ long long QgsPostgresProvider::featureCount() const
|
||||
else
|
||||
{
|
||||
sql = QStringLiteral( "SELECT reltuples::bigint FROM pg_catalog.pg_class WHERE oid=regclass(%1)::oid" ).arg( quotedValue( mQuery ) );
|
||||
QgsPostgresResult result( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult result( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
num = result.PQgetvalue( 0, 0 ).toLongLong();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sql = QStringLiteral( "SELECT count(*) FROM %1%2" ).arg( mQuery, filterWhereClause() );
|
||||
QgsPostgresResult result( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult result( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
|
||||
QgsDebugMsgLevel( "number of features as text: " + result.PQgetvalue( 0, 0 ), 2 );
|
||||
|
||||
@ -3798,7 +3799,7 @@ long long QgsPostgresProvider::featureCount() const
|
||||
bool QgsPostgresProvider::empty() const
|
||||
{
|
||||
QString sql = QStringLiteral( "SELECT EXISTS (SELECT * FROM %1%2 LIMIT 1)" ).arg( mQuery, filterWhereClause() );
|
||||
QgsPostgresResult res( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult res( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( res.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
pushError( res.PQresultErrorMessage() );
|
||||
@ -3830,13 +3831,13 @@ QgsRectangle QgsPostgresProvider::extent() const
|
||||
.arg( quotedValue( mSchemaName ),
|
||||
quotedValue( mTableName ),
|
||||
quotedValue( mGeometryColumn ) );
|
||||
result = connectionRO()->PQexec( sql );
|
||||
result = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( result.PQresultStatus() == PGRES_TUPLES_OK && result.PQntuples() == 1 )
|
||||
{
|
||||
if ( result.PQgetvalue( 0, 0 ).toInt() > 0 )
|
||||
{
|
||||
sql = QStringLiteral( "SELECT reltuples::bigint FROM pg_catalog.pg_class WHERE oid=regclass(%1)::oid" ).arg( quotedValue( mQuery ) );
|
||||
result = connectionRO()->PQexec( sql );
|
||||
result = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( result.PQresultStatus() == PGRES_TUPLES_OK
|
||||
&& result.PQntuples() == 1
|
||||
&& result.PQgetvalue( 0, 0 ).toLong() > 0 )
|
||||
@ -3847,7 +3848,7 @@ QgsRectangle QgsPostgresProvider::extent() const
|
||||
quotedValue( mSchemaName ),
|
||||
quotedValue( mTableName ),
|
||||
quotedValue( mGeometryColumn ) );
|
||||
result = mConnectionRO->PQexec( sql );
|
||||
result = mConnectionRO->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( result.PQresultStatus() == PGRES_TUPLES_OK && result.PQntuples() == 1 && !result.PQgetisnull( 0, 0 ) )
|
||||
{
|
||||
ext = result.PQgetvalue( 0, 0 );
|
||||
@ -3884,9 +3885,9 @@ QgsRectangle QgsPostgresProvider::extent() const
|
||||
mQuery,
|
||||
filterWhereClause() );
|
||||
|
||||
result = connectionRO()->PQexec( sql );
|
||||
result = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
connectionRO()->PQexecNR( QStringLiteral( "ROLLBACK" ) );
|
||||
connectionRO()->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "ROLLBACK" ) );
|
||||
else if ( result.PQntuples() == 1 && !result.PQgetisnull( 0, 0 ) )
|
||||
ext = result.PQgetvalue( 0, 0 );
|
||||
}
|
||||
@ -3960,7 +3961,7 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
}
|
||||
QgsDebugMsgLevel( QStringLiteral( "Getting the spatial column type: %1" ).arg( sql ), 2 );
|
||||
|
||||
result = connectionRO()->PQexec( sql );
|
||||
result = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( PGRES_TUPLES_OK == result.PQresultStatus() )
|
||||
{
|
||||
geomColType = result.PQgetvalue( 0, 0 );
|
||||
@ -3996,17 +3997,17 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "Getting geometry column: %1" ).arg( sql ), 2 );
|
||||
|
||||
QgsPostgresResult result( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult result( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( PGRES_TUPLES_OK == result.PQresultStatus() )
|
||||
{
|
||||
Oid tableoid = result.PQftable( 0 );
|
||||
int column = result.PQftablecol( 0 );
|
||||
|
||||
result = connectionRO()->PQexec( sql );
|
||||
result = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( tableoid > 0 && PGRES_TUPLES_OK == result.PQresultStatus() )
|
||||
{
|
||||
sql = QStringLiteral( "SELECT pg_namespace.nspname,pg_class.relname FROM pg_class,pg_namespace WHERE pg_class.relnamespace=pg_namespace.oid AND pg_class.oid=%1" ).arg( tableoid );
|
||||
result = connectionRO()->PQexec( sql );
|
||||
result = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
|
||||
if ( PGRES_TUPLES_OK == result.PQresultStatus() && 1 == result.PQntuples() )
|
||||
{
|
||||
@ -4014,7 +4015,7 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
tableName = result.PQgetvalue( 0, 1 );
|
||||
|
||||
sql = QStringLiteral( "SELECT a.attname, t.typname FROM pg_attribute a, pg_type t WHERE a.attrelid=%1 AND a.attnum=%2 AND a.atttypid = t.oid" ).arg( tableoid ).arg( column );
|
||||
result = connectionRO()->PQexec( sql );
|
||||
result = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( PGRES_TUPLES_OK == result.PQresultStatus() && 1 == result.PQntuples() )
|
||||
{
|
||||
geomCol = result.PQgetvalue( 0, 0 );
|
||||
@ -4061,7 +4062,7 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
quotedValue( schemaName ) );
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "Getting geometry column: %1" ).arg( sql ), 2 );
|
||||
result = connectionRO()->PQexec( sql );
|
||||
result = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
QgsDebugMsgLevel( QStringLiteral( "Geometry column query returned %1 rows" ).arg( result.PQntuples() ), 2 );
|
||||
|
||||
if ( result.PQntuples() == 1 )
|
||||
@ -4086,7 +4087,7 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionRO()->PQexecNR( QStringLiteral( "COMMIT" ) );
|
||||
connectionRO()->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "COMMIT" ) );
|
||||
}
|
||||
|
||||
if ( detectedType.isEmpty() )
|
||||
@ -4098,7 +4099,7 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
quotedValue( schemaName ) );
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "Getting geography column: %1" ).arg( sql ), 2 );
|
||||
result = connectionRO()->PQexec( sql, false );
|
||||
result = connectionRO()->LoggedPQexecNoLogError( "QgsPostgresProvider", sql );
|
||||
QgsDebugMsgLevel( QStringLiteral( "Geography column query returned %1" ).arg( result.PQntuples() ), 2 );
|
||||
|
||||
if ( result.PQntuples() == 1 )
|
||||
@ -4111,7 +4112,7 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionRO()->PQexecNR( QStringLiteral( "COMMIT" ) );
|
||||
connectionRO()->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "COMMIT" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -4131,7 +4132,7 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
quotedValue( schemaName ) );
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "Getting TopoGeometry column: %1" ).arg( sql ), 2 );
|
||||
result = connectionRO()->PQexec( sql, false );
|
||||
result = connectionRO()->LoggedPQexecNoLogError( "QgsPostgresProvider", sql );
|
||||
QgsDebugMsgLevel( QStringLiteral( "TopoGeometry column query returned %1" ).arg( result.PQntuples() ), 2 );
|
||||
|
||||
if ( result.PQntuples() == 1 )
|
||||
@ -4142,7 +4143,7 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionRO()->PQexecNR( QStringLiteral( "COMMIT" ) );
|
||||
connectionRO()->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "COMMIT" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -4155,7 +4156,7 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
quotedValue( schemaName ) );
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "Getting pointcloud column: %1" ).arg( sql ), 2 );
|
||||
result = connectionRO()->PQexec( sql, false );
|
||||
result = connectionRO()->LoggedPQexecNoLogError( "QgsPostgresProvider", sql );
|
||||
QgsDebugMsgLevel( QStringLiteral( "Pointcloud column query returned %1" ).arg( result.PQntuples() ), 2 );
|
||||
|
||||
if ( result.PQntuples() == 1 )
|
||||
@ -4166,7 +4167,7 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionRO()->PQexecNR( QStringLiteral( "COMMIT" ) );
|
||||
connectionRO()->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "COMMIT" ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -4181,7 +4182,7 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
quotedValue( geomCol ),
|
||||
quotedValue( schemaName ) );
|
||||
QgsDebugMsgLevel( QStringLiteral( "Getting column datatype: %1" ).arg( sql ), 2 );
|
||||
result = connectionRO()->PQexec( sql, false );
|
||||
result = connectionRO()->LoggedPQexecNoLogError( "QgsPostgresProvider", sql );
|
||||
QgsDebugMsgLevel( QStringLiteral( "Column datatype query returned %1" ).arg( result.PQntuples() ), 2 );
|
||||
if ( result.PQntuples() == 1 )
|
||||
{
|
||||
@ -4197,19 +4198,19 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionRO()->PQexecNR( QStringLiteral( "COMMIT" ) );
|
||||
connectionRO()->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "COMMIT" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sql = QStringLiteral( "SELECT %1 FROM %2 LIMIT 0" ).arg( quotedIdentifier( mGeometryColumn ), mQuery );
|
||||
result = connectionRO()->PQexec( sql );
|
||||
result = connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( PGRES_TUPLES_OK == result.PQresultStatus() )
|
||||
{
|
||||
sql = QStringLiteral( "SELECT (SELECT t.typname FROM pg_type t WHERE oid = %1), upper(postgis_typmod_type(%2)), postgis_typmod_srid(%2)" )
|
||||
.arg( QString::number( result.PQftype( 0 ) ), QString::number( result.PQfmod( 0 ) ) );
|
||||
result = connectionRO()->PQexec( sql, false );
|
||||
result = connectionRO()->LoggedPQexecNoLogError( "QgsPostgresProvider", sql );
|
||||
if ( result.PQntuples() == 1 )
|
||||
{
|
||||
geomColType = result.PQgetvalue( 0, 0 );
|
||||
@ -4231,7 +4232,7 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionRO()->PQexecNR( QStringLiteral( "COMMIT" ) );
|
||||
connectionRO()->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "COMMIT" ) );
|
||||
detectedType = mRequestedGeomType == QgsWkbTypes::Unknown ? QString() : QgsPostgresConn::postgisWkbTypeName( mRequestedGeomType );
|
||||
}
|
||||
}
|
||||
@ -4587,13 +4588,13 @@ Qgis::VectorExportResult QgsPostgresProvider::createEmptyLayer( const QString &u
|
||||
|
||||
try
|
||||
{
|
||||
conn->PQexecNR( QStringLiteral( "BEGIN" ) );
|
||||
conn->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "BEGIN" ) );
|
||||
|
||||
// We want a valid schema name ...
|
||||
if ( schemaName.isEmpty() )
|
||||
{
|
||||
QString sql = QString( "SELECT current_schema" );
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
throw PGException( result );
|
||||
schemaName = result.PQgetvalue( 0, 0 );
|
||||
@ -4610,7 +4611,7 @@ Qgis::VectorExportResult QgsPostgresProvider::createEmptyLayer( const QString &u
|
||||
.arg( quotedValue( tableName ),
|
||||
quotedValue( schemaName ) );
|
||||
|
||||
QgsPostgresResult result( conn->PQexec( sql ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
throw PGException( result );
|
||||
|
||||
@ -4626,7 +4627,7 @@ Qgis::VectorExportResult QgsPostgresProvider::createEmptyLayer( const QString &u
|
||||
.arg( quotedValue( schemaName ),
|
||||
quotedValue( tableName ) );
|
||||
|
||||
result = conn->PQexec( sql );
|
||||
result = conn->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
throw PGException( result );
|
||||
}
|
||||
@ -4658,7 +4659,7 @@ Qgis::VectorExportResult QgsPostgresProvider::createEmptyLayer( const QString &u
|
||||
}
|
||||
sql += QStringLiteral( ", PRIMARY KEY (%1) )" ) .arg( pk );
|
||||
|
||||
result = conn->PQexec( sql );
|
||||
result = conn->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
throw PGException( result );
|
||||
|
||||
@ -4679,7 +4680,7 @@ Qgis::VectorExportResult QgsPostgresProvider::createEmptyLayer( const QString &u
|
||||
.arg( quotedValue( geometryType ) )
|
||||
.arg( dim );
|
||||
|
||||
result = conn->PQexec( sql );
|
||||
result = conn->LoggedPQexec( "QgsPostgresProvider", sql );
|
||||
if ( result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
throw PGException( result );
|
||||
}
|
||||
@ -4688,7 +4689,7 @@ Qgis::VectorExportResult QgsPostgresProvider::createEmptyLayer( const QString &u
|
||||
geometryColumn.clear();
|
||||
}
|
||||
|
||||
conn->PQexecNR( QStringLiteral( "COMMIT" ) );
|
||||
conn->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "COMMIT" ) );
|
||||
}
|
||||
catch ( PGException &e )
|
||||
{
|
||||
@ -4697,7 +4698,7 @@ Qgis::VectorExportResult QgsPostgresProvider::createEmptyLayer( const QString &u
|
||||
.arg( schemaTableName,
|
||||
e.errorMessage() );
|
||||
|
||||
conn->PQexecNR( QStringLiteral( "ROLLBACK" ) );
|
||||
conn->LoggedPQexecNR( "QgsPostgresProvider", QStringLiteral( "ROLLBACK" ) );
|
||||
conn->unref();
|
||||
return Qgis::VectorExportResult::ErrorCreatingLayer;
|
||||
}
|
||||
@ -4843,7 +4844,7 @@ QString QgsPostgresProvider::description() const
|
||||
QgsPostgresResult result;
|
||||
|
||||
/* TODO: expose a cached QgsPostgresConn::version() ? */
|
||||
result = lConnectionRO->PQexec( QStringLiteral( "SELECT version()" ) );
|
||||
result = lConnectionRO->LoggedPQexec( QStringLiteral( "QgsPostgresProvider" ), QStringLiteral( "SELECT version()" ) );
|
||||
if ( result.PQresultStatus() == PGRES_TUPLES_OK )
|
||||
{
|
||||
pgVersion = result.PQgetvalue( 0, 0 );
|
||||
@ -4879,7 +4880,7 @@ QString QgsPostgresProvider::getNextString( const QString &txt, int &i, const QS
|
||||
}
|
||||
i += match.captured( 1 ).length() + 2;
|
||||
jumpSpace( txt, i );
|
||||
if ( !QStringView{txt}.mid( i ).startsWith( sep ) && i < txt.length() )
|
||||
if ( !QStringView{txt} .mid( i ).startsWith( sep ) && i < txt.length() )
|
||||
{
|
||||
QgsMessageLog::logMessage( tr( "Cannot find separator: %1" ).arg( txt.mid( i ) ), tr( "PostGIS" ) );
|
||||
return QString();
|
||||
@ -4892,9 +4893,9 @@ QString QgsPostgresProvider::getNextString( const QString &txt, int &i, const QS
|
||||
int start = i;
|
||||
for ( ; i < txt.length(); i++ )
|
||||
{
|
||||
if ( QStringView{txt}.mid( i ).startsWith( sep ) )
|
||||
if ( QStringView{txt} .mid( i ).startsWith( sep ) )
|
||||
{
|
||||
QStringView v( QStringView{txt}.mid( start, i - start ) );
|
||||
QStringView v( QStringView{txt} .mid( start, i - start ) );
|
||||
i += sep.length();
|
||||
return v.trimmed().toString();
|
||||
}
|
||||
@ -5130,7 +5131,7 @@ QList<QgsRelation> QgsPostgresProvider::discoverRelations( const QgsVectorLayer
|
||||
" fk.conname ;"
|
||||
);
|
||||
|
||||
QgsPostgresResult sqlResult( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult sqlResult( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
if ( sqlResult.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
QgsLogger::warning( "Error getting the foreign keys of " + mTableName );
|
||||
@ -5224,7 +5225,7 @@ QgsPostgresProvider::Relkind QgsPostgresProvider::relkind() const
|
||||
else
|
||||
{
|
||||
QString sql = QStringLiteral( "SELECT relkind FROM pg_class WHERE oid=regclass(%1)::oid" ).arg( quotedValue( mQuery ) );
|
||||
QgsPostgresResult res( connectionRO()->PQexec( sql ) );
|
||||
QgsPostgresResult res( connectionRO()->LoggedPQexec( "QgsPostgresProvider", sql ) );
|
||||
QString type = res.PQgetvalue( 0, 0 );
|
||||
|
||||
mKind = Relkind::Unknown;
|
||||
@ -5356,7 +5357,7 @@ bool QgsPostgresProviderMetadata::styleExists( const QString &uri, const QString
|
||||
.arg( wkbTypeString )
|
||||
.arg( QgsPostgresConn::quotedValue( styleId.isEmpty() ? dsUri.table() : styleId ) );
|
||||
|
||||
QgsPostgresResult res( conn->PQexec( checkQuery ) );
|
||||
QgsPostgresResult res( conn->LoggedPQexec( QStringLiteral( "QgsPostgresProviderMetadata" ), checkQuery ) );
|
||||
if ( res.PQresultStatus() == PGRES_TUPLES_OK )
|
||||
{
|
||||
return res.PQntuples() > 0;
|
||||
@ -5389,22 +5390,23 @@ bool QgsPostgresProviderMetadata::saveStyle( const QString &uri, const QString &
|
||||
|
||||
if ( !tableExists( *conn, QStringLiteral( "layer_styles" ) ) )
|
||||
{
|
||||
QgsPostgresResult res( conn->PQexec( "CREATE TABLE layer_styles("
|
||||
"id SERIAL PRIMARY KEY"
|
||||
",f_table_catalog varchar"
|
||||
",f_table_schema varchar"
|
||||
",f_table_name varchar"
|
||||
",f_geometry_column varchar"
|
||||
",styleName text"
|
||||
",styleQML xml"
|
||||
",styleSLD xml"
|
||||
",useAsDefault boolean"
|
||||
",description text"
|
||||
",owner varchar(63) DEFAULT CURRENT_USER"
|
||||
",ui xml"
|
||||
",update_time timestamp DEFAULT CURRENT_TIMESTAMP"
|
||||
",type varchar"
|
||||
")" ) );
|
||||
QgsPostgresResult res( conn->LoggedPQexec( QStringLiteral( "QgsPostgresProviderMetadata" ),
|
||||
"CREATE TABLE layer_styles("
|
||||
"id SERIAL PRIMARY KEY"
|
||||
",f_table_catalog varchar"
|
||||
",f_table_schema varchar"
|
||||
",f_table_name varchar"
|
||||
",f_geometry_column varchar"
|
||||
",styleName text"
|
||||
",styleQML xml"
|
||||
",styleSLD xml"
|
||||
",useAsDefault boolean"
|
||||
",description text"
|
||||
",owner varchar(63) DEFAULT CURRENT_USER"
|
||||
",ui xml"
|
||||
",update_time timestamp DEFAULT CURRENT_TIMESTAMP"
|
||||
",type varchar"
|
||||
")" ) );
|
||||
if ( res.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
{
|
||||
errCause = QObject::tr( "Unable to save layer style. It's not possible to create the destination table on the database. Maybe this is due to table permissions (user=%1). Please contact your database admin" ).arg( dsUri.username() );
|
||||
@ -5416,7 +5418,7 @@ bool QgsPostgresProviderMetadata::saveStyle( const QString &uri, const QString &
|
||||
{
|
||||
if ( !columnExists( *conn, QStringLiteral( "layer_styles" ), QStringLiteral( "type" ) ) )
|
||||
{
|
||||
QgsPostgresResult res( conn->PQexec( "ALTER TABLE layer_styles ADD COLUMN type varchar NULL" ) );
|
||||
QgsPostgresResult res( conn->LoggedPQexec( QStringLiteral( "QgsPostgresProviderMetadata" ), "ALTER TABLE layer_styles ADD COLUMN type varchar NULL" ) );
|
||||
if ( res.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
{
|
||||
errCause = QObject::tr( "Unable to add column type to layer_styles table. Maybe this is due to table permissions (user=%1). Please contact your database admin" ).arg( dsUri.username() );
|
||||
@ -5481,7 +5483,7 @@ bool QgsPostgresProviderMetadata::saveStyle( const QString &uri, const QString &
|
||||
.arg( wkbTypeString )
|
||||
.arg( QgsPostgresConn::quotedValue( styleName.isEmpty() ? dsUri.table() : styleName ) );
|
||||
|
||||
QgsPostgresResult res( conn->PQexec( checkQuery ) );
|
||||
QgsPostgresResult res( conn->LoggedPQexec( "QgsPostgresProviderMetadata", checkQuery ) );
|
||||
if ( res.PQntuples() > 0 )
|
||||
{
|
||||
sql = QString( "UPDATE layer_styles"
|
||||
@ -5529,7 +5531,7 @@ bool QgsPostgresProviderMetadata::saveStyle( const QString &uri, const QString &
|
||||
sql = QStringLiteral( "BEGIN; %1; %2; COMMIT;" ).arg( removeDefaultSql, sql );
|
||||
}
|
||||
|
||||
res = conn->PQexec( sql );
|
||||
res = conn->LoggedPQexec( "QgsPostgresProviderMetadata", sql );
|
||||
|
||||
bool saved = res.PQresultStatus() == PGRES_COMMAND_OK;
|
||||
if ( !saved )
|
||||
@ -5610,7 +5612,7 @@ QString QgsPostgresProviderMetadata::loadStyle( const QString &uri, QString &err
|
||||
.arg( wkbTypeString );
|
||||
}
|
||||
|
||||
QgsPostgresResult result( conn->PQexec( selectQmlQuery ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( QStringLiteral( "QgsPostgresProviderMetadata" ), selectQmlQuery ) );
|
||||
|
||||
QString style = result.PQntuples() == 1 ? result.PQgetvalue( 0, 0 ) : QString();
|
||||
conn->unref();
|
||||
@ -5660,7 +5662,7 @@ int QgsPostgresProviderMetadata::listStyles( const QString &uri, QStringList &id
|
||||
QString( "f_geometry_column=%1" ).arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) ) )
|
||||
.arg( wkbTypeString );
|
||||
|
||||
QgsPostgresResult result( conn->PQexec( selectRelatedQuery ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( QStringLiteral( "QgsPostgresProviderMetadata" ), selectRelatedQuery ) );
|
||||
if ( result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "Error executing query: %1" ).arg( selectRelatedQuery ) );
|
||||
@ -5687,7 +5689,7 @@ int QgsPostgresProviderMetadata::listStyles( const QString &uri, QStringList &id
|
||||
.arg( QgsPostgresConn::quotedValue( dsUri.geometryColumn() ) )
|
||||
.arg( wkbTypeString );
|
||||
|
||||
result = conn->PQexec( selectOthersQuery );
|
||||
result = conn->LoggedPQexec( QStringLiteral( "QgsPostgresProviderMetadata" ), selectOthersQuery );
|
||||
if ( result.PQresultStatus() != PGRES_TUPLES_OK )
|
||||
{
|
||||
QgsMessageLog::logMessage( QObject::tr( "Error executing query: %1" ).arg( selectOthersQuery ) );
|
||||
@ -5723,7 +5725,7 @@ bool QgsPostgresProviderMetadata::deleteStyleById( const QString &uri, const QSt
|
||||
{
|
||||
QString deleteStyleQuery = QStringLiteral( "DELETE FROM layer_styles WHERE id=%1" ).arg(
|
||||
QgsPostgresConn::quotedValue( styleId ) );
|
||||
QgsPostgresResult result( conn->PQexec( deleteStyleQuery ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( QStringLiteral( "QgsPostgresProviderMetadata" ), deleteStyleQuery ) );
|
||||
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
|
||||
{
|
||||
QgsDebugMsg(
|
||||
@ -5755,7 +5757,7 @@ QString QgsPostgresProviderMetadata::getStyleById( const QString &uri, const QSt
|
||||
|
||||
QString style;
|
||||
QString selectQmlQuery = QStringLiteral( "SELECT styleQml FROM layer_styles WHERE id=%1" ).arg( QgsPostgresConn::quotedValue( styleId ) );
|
||||
QgsPostgresResult result( conn->PQexec( selectQmlQuery ) );
|
||||
QgsPostgresResult result( conn->LoggedPQexec( QStringLiteral( "QgsPostgresProviderMetadata" ), selectQmlQuery ) );
|
||||
if ( result.PQresultStatus() == PGRES_TUPLES_OK )
|
||||
{
|
||||
if ( result.PQntuples() == 1 )
|
||||
|
||||
@ -257,7 +257,7 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsPostgresProviderConnection
|
||||
}
|
||||
|
||||
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
|
||||
std::unique_ptr<QgsPostgresResult> res = std::make_unique<QgsPostgresResult>( conn->PQexec( sql ) );
|
||||
std::unique_ptr<QgsPostgresResult> res = std::make_unique<QgsPostgresResult>( conn->LoggedPQexec( "QgsPostgresProviderConnection", sql ) );
|
||||
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
|
||||
results.setQueryExecutionTime( std::chrono::duration_cast<std::chrono::milliseconds>( end - begin ).count() );
|
||||
|
||||
|
||||
@ -72,7 +72,7 @@ bool QgsPostgresTransaction::executeSql( const QString &sql, QString &errorMsg,
|
||||
}
|
||||
|
||||
QgsDebugMsg( QStringLiteral( "Transaction sql: %1" ).arg( sql ) );
|
||||
QgsPostgresResult r( mConn->PQexec( sql, true ) );
|
||||
QgsPostgresResult r( mConn->LoggedPQexec( "QgsPostgresTransaction", sql ) );
|
||||
if ( r.PQresultStatus() == PGRES_BAD_RESPONSE ||
|
||||
r.PQresultStatus() == PGRES_FATAL_ERROR )
|
||||
{
|
||||
|
||||
@ -235,6 +235,10 @@ QgsSpatiaLiteFeatureIterator::QgsSpatiaLiteFeatureIterator( QgsSpatiaLiteFeature
|
||||
sqliteStatement = nullptr;
|
||||
close();
|
||||
}
|
||||
else
|
||||
{
|
||||
mQueryLogWrapper = std::make_unique<QgsDatabaseQueryLogWrapper>( mLastSql, mSource->mSqlitePath, QStringLiteral( "spatialite" ), QStringLiteral( "QgsSpatiaLiteFeatureIterator" ), QGS_QUERY_LOG_ORIGIN );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -395,6 +399,7 @@ bool QgsSpatiaLiteFeatureIterator::prepareStatement( const QString &whereClause,
|
||||
QgsMessageLog::logMessage( QObject::tr( "SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( mSqliteHandle ) ), QObject::tr( "SpatiaLite" ) );
|
||||
return false;
|
||||
}
|
||||
mLastSql = sql;
|
||||
}
|
||||
catch ( QgsSpatiaLiteProvider::SLFieldNotFound )
|
||||
{
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include "qgsfeatureiterator.h"
|
||||
#include "qgsfields.h"
|
||||
#include "qgscoordinatetransform.h"
|
||||
#include "qgsdbquerylog.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@ -113,6 +114,11 @@ class QgsSpatiaLiteFeatureIterator final: public QgsAbstractFeatureIteratorFromS
|
||||
QgsCoordinateTransform mTransform;
|
||||
QgsGeometry mDistanceWithinGeom;
|
||||
std::unique_ptr< QgsGeometryEngine > mDistanceWithinEngine;
|
||||
|
||||
// Last prepared sql statement for logging purposes
|
||||
QString mLastSql;
|
||||
|
||||
std::unique_ptr<QgsDatabaseQueryLogWrapper> mQueryLogWrapper;
|
||||
};
|
||||
|
||||
#endif // QGSSPATIALITEFEATUREITERATOR_H
|
||||
|
||||
@ -33,6 +33,7 @@ email : a.furieri@lqt.it
|
||||
#include "qgsspatialiteconnection.h"
|
||||
#include "qgsspatialitetransaction.h"
|
||||
#include "qgsspatialiteproviderconnection.h"
|
||||
#include "qgsdbquerylog.h"
|
||||
|
||||
#include "qgsjsonutils.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
@ -225,7 +226,7 @@ Qgis::VectorExportResult QgsSpatiaLiteProvider::createEmptyLayer( const QString
|
||||
|
||||
try
|
||||
{
|
||||
int ret = sqlite3_exec( sqliteHandle, "BEGIN", nullptr, nullptr, &errMsg );
|
||||
int ret = exec_sql( sqliteHandle, "BEGIN", uri, errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
throw SLException( errMsg );
|
||||
|
||||
@ -237,14 +238,14 @@ Qgis::VectorExportResult QgsSpatiaLiteProvider::createEmptyLayer( const QString
|
||||
sql = QStringLiteral( "DROP TABLE IF EXISTS %1" )
|
||||
.arg( QgsSqliteUtils::quotedIdentifier( tableName ) );
|
||||
|
||||
ret = sqlite3_exec( sqliteHandle, sql.toUtf8().constData(), nullptr, nullptr, &errMsg );
|
||||
ret = exec_sql( sqliteHandle, sql.toUtf8().constData(), uri, errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
throw SLException( errMsg );
|
||||
|
||||
sql = QStringLiteral( "DELETE FROM geometry_columns WHERE upper(f_table_name) = upper(%1)" )
|
||||
.arg( QgsSqliteUtils::quotedString( tableName ) );
|
||||
|
||||
ret = sqlite3_exec( sqliteHandle, sql.toUtf8().constData(), nullptr, nullptr, &errMsg );
|
||||
ret = exec_sql( sqliteHandle, sql.toUtf8().constData(), uri, errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
throw SLException( errMsg );
|
||||
}
|
||||
@ -255,7 +256,7 @@ Qgis::VectorExportResult QgsSpatiaLiteProvider::createEmptyLayer( const QString
|
||||
primaryKeyType,
|
||||
primaryKeyType == QLatin1String( "INTEGER" ) ? QStringLiteral( " AUTOINCREMENT" ) : QString() );
|
||||
|
||||
ret = sqlite3_exec( sqliteHandle, sql.toUtf8().constData(), nullptr, nullptr, &errMsg );
|
||||
ret = exec_sql( sqliteHandle, sql.toUtf8().constData(), uri, errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
throw SLException( errMsg );
|
||||
|
||||
@ -333,7 +334,7 @@ Qgis::VectorExportResult QgsSpatiaLiteProvider::createEmptyLayer( const QString
|
||||
.arg( QgsSqliteUtils::quotedString( geometryType ) )
|
||||
.arg( dim );
|
||||
|
||||
ret = sqlite3_exec( sqliteHandle, sql.toUtf8().constData(), nullptr, nullptr, &errMsg );
|
||||
ret = exec_sql( sqliteHandle, sql.toUtf8().constData(), uri, errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
throw SLException( errMsg );
|
||||
}
|
||||
@ -342,7 +343,7 @@ Qgis::VectorExportResult QgsSpatiaLiteProvider::createEmptyLayer( const QString
|
||||
geometryColumn = QString();
|
||||
}
|
||||
|
||||
ret = sqlite3_exec( sqliteHandle, "COMMIT", nullptr, nullptr, &errMsg );
|
||||
ret = exec_sql( sqliteHandle, "COMMIT", uri, errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
throw SLException( errMsg );
|
||||
|
||||
@ -363,7 +364,7 @@ Qgis::VectorExportResult QgsSpatiaLiteProvider::createEmptyLayer( const QString
|
||||
if ( toCommit )
|
||||
{
|
||||
// ROLLBACK after some previous error
|
||||
sqlite3_exec( sqliteHandle, "ROLLBACK", nullptr, nullptr, nullptr );
|
||||
exec_sql( sqliteHandle, "ROLLBACK", uri, nullptr, QGS_QUERY_LOG_ORIGIN );
|
||||
}
|
||||
|
||||
QgsSqliteHandle::closeDb( handle );
|
||||
@ -486,7 +487,7 @@ QgsSpatiaLiteProvider::QgsSpatiaLiteProvider( QString const &uri, const Provider
|
||||
for ( const auto &pragma : pragmaList )
|
||||
{
|
||||
char *errMsg = nullptr;
|
||||
int ret = exec_sql( QStringLiteral( "PRAGMA %1" ).arg( pragma ), errMsg );
|
||||
int ret = exec_sql( mSqliteHandle, QStringLiteral( "PRAGMA %1" ).arg( pragma ), uri, errMsg );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "PRAGMA " ) + pragma + QString( " failed : %1" ).arg( errMsg ? errMsg : "" ) );
|
||||
@ -1143,14 +1144,15 @@ void QgsSpatiaLiteProvider::handleError( const QString &sql, char *errorMessage,
|
||||
if ( ! savepointId.isEmpty() )
|
||||
{
|
||||
// ROLLBACK after some previous error
|
||||
( void )exec_sql( QStringLiteral( "ROLLBACK TRANSACTION TO \"%1\"" ).arg( savepointId ) );
|
||||
( void )exec_sql( sqliteHandle(), QStringLiteral( "ROLLBACK TRANSACTION TO \"%1\"" ).arg( savepointId ), uri().uri(), nullptr, QGS_QUERY_LOG_ORIGIN );
|
||||
}
|
||||
}
|
||||
|
||||
int QgsSpatiaLiteProvider::exec_sql( const QString &sql, char *errMsg )
|
||||
int QgsSpatiaLiteProvider::exec_sql( sqlite3 *handle, const QString &sql, const QString &uri, char *errMsg, const QString &origin )
|
||||
{
|
||||
QgsDatabaseQueryLogWrapper logWrapper( sql, uri, QStringLiteral( "spatialite" ), QStringLiteral( "QgsSpatiaLiteProvider" ), origin );
|
||||
// Use transaction's handle (if any)
|
||||
return sqlite3_exec( sqliteHandle(), sql.toUtf8().constData(), nullptr, nullptr, &errMsg );
|
||||
return sqlite3_exec( handle, sql.toUtf8().constData(), nullptr, nullptr, &errMsg );
|
||||
}
|
||||
|
||||
sqlite3 *QgsSpatiaLiteProvider::sqliteHandle() const
|
||||
@ -1391,7 +1393,7 @@ bool QgsSpatiaLiteProvider::hasRowid()
|
||||
// table without rowid column
|
||||
QString sql = QStringLiteral( "SELECT rowid FROM %1 WHERE 0" ).arg( QgsSqliteUtils::quotedIdentifier( mTableName ) );
|
||||
char *errMsg = nullptr;
|
||||
return exec_sql( sql, errMsg ) == SQLITE_OK;
|
||||
return exec_sql( sqliteHandle( ), sql, uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN ) == SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -4154,7 +4156,7 @@ bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList &flist, Flags flags )
|
||||
|
||||
const QString savepointId { QStringLiteral( "qgis_spatialite_internal_savepoint_%1" ).arg( ++ sSavepointId ) };
|
||||
|
||||
ret = exec_sql( QStringLiteral( "SAVEPOINT \"%1\"" ).arg( savepointId ), errMsg );
|
||||
ret = exec_sql( sqliteHandle(), QStringLiteral( "SAVEPOINT \"%1\"" ).arg( savepointId ), uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret == SQLITE_OK )
|
||||
{
|
||||
toCommit = true;
|
||||
@ -4354,7 +4356,7 @@ bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList &flist, Flags flags )
|
||||
|
||||
if ( ret == SQLITE_DONE || ret == SQLITE_ROW )
|
||||
{
|
||||
ret = exec_sql( QStringLiteral( "RELEASE SAVEPOINT \"%1\"" ).arg( savepointId ), errMsg );
|
||||
ret = exec_sql( sqliteHandle(), QStringLiteral( "RELEASE SAVEPOINT \"%1\"" ).arg( savepointId ), uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
}
|
||||
|
||||
} // BEGIN statement
|
||||
@ -4370,7 +4372,7 @@ bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList &flist, Flags flags )
|
||||
if ( toCommit )
|
||||
{
|
||||
// ROLLBACK after some previous error
|
||||
( void )exec_sql( QStringLiteral( "ROLLBACK TRANSACTION TO SAVEPOINT \"%1\"" ).arg( savepointId ) );
|
||||
( void )exec_sql( sqliteHandle(), QStringLiteral( "ROLLBACK TRANSACTION TO SAVEPOINT \"%1\"" ).arg( savepointId ), uri().uri(), nullptr, QGS_QUERY_LOG_ORIGIN );
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -4402,7 +4404,7 @@ bool QgsSpatiaLiteProvider::createAttributeIndex( int field )
|
||||
|
||||
const QString savepointId { QStringLiteral( "qgis_spatialite_internal_savepoint_%1" ).arg( ++ sSavepointId ) };
|
||||
|
||||
int ret = exec_sql( QStringLiteral( "SAVEPOINT \"%1\"" ).arg( savepointId ), errMsg );
|
||||
int ret = exec_sql( sqliteHandle(), QStringLiteral( "SAVEPOINT \"%1\"" ).arg( savepointId ), uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
handleError( sql, errMsg, QString() );
|
||||
@ -4415,14 +4417,14 @@ bool QgsSpatiaLiteProvider::createAttributeIndex( int field )
|
||||
.arg( createIndexName( mTableName, fieldName ),
|
||||
mTableName,
|
||||
QgsSqliteUtils::quotedIdentifier( fieldName ) );
|
||||
ret = exec_sql( sql, errMsg );
|
||||
ret = exec_sql( sqliteHandle(), sql, uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
handleError( sql, errMsg, savepointId );
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = exec_sql( QStringLiteral( "RELEASE SAVEPOINT \"%1\"" ).arg( savepointId ), errMsg );
|
||||
ret = exec_sql( sqliteHandle(), QStringLiteral( "RELEASE SAVEPOINT \"%1\"" ).arg( savepointId ), uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
handleError( sql, errMsg, savepointId );
|
||||
@ -4457,7 +4459,7 @@ bool QgsSpatiaLiteProvider::deleteFeatures( const QgsFeatureIds &id )
|
||||
|
||||
const QString savepointId { QStringLiteral( "qgis_spatialite_internal_savepoint_%1" ).arg( ++ sSavepointId ) };
|
||||
|
||||
int ret = exec_sql( QStringLiteral( "SAVEPOINT \"%1\"" ).arg( savepointId ), errMsg );
|
||||
int ret = exec_sql( sqliteHandle(), QStringLiteral( "SAVEPOINT \"%1\"" ).arg( savepointId ), uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
handleError( sql, errMsg, QString() );
|
||||
@ -4506,7 +4508,7 @@ bool QgsSpatiaLiteProvider::deleteFeatures( const QgsFeatureIds &id )
|
||||
|
||||
sqlite3_finalize( stmt );
|
||||
|
||||
ret = exec_sql( QStringLiteral( "RELEASE SAVEPOINT \"%1\"" ).arg( savepointId ), errMsg );
|
||||
ret = exec_sql( sqliteHandle( ), QStringLiteral( "RELEASE SAVEPOINT \"%1\"" ).arg( savepointId ), uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
handleError( sql, errMsg, savepointId );
|
||||
@ -4526,7 +4528,7 @@ bool QgsSpatiaLiteProvider::truncate()
|
||||
|
||||
const QString savepointId { QStringLiteral( "qgis_spatialite_internal_savepoint_%1" ).arg( ++ sSavepointId ) };
|
||||
|
||||
int ret = exec_sql( QStringLiteral( "SAVEPOINT \"%1\"" ).arg( savepointId ), errMsg );
|
||||
int ret = exec_sql( sqliteHandle( ), QStringLiteral( "SAVEPOINT \"%1\"" ).arg( savepointId ), uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
handleError( sql, errMsg, QString() );
|
||||
@ -4534,14 +4536,14 @@ bool QgsSpatiaLiteProvider::truncate()
|
||||
}
|
||||
|
||||
sql = QStringLiteral( "DELETE FROM %1" ).arg( QgsSqliteUtils::quotedIdentifier( mTableName ) );
|
||||
ret = exec_sql( sql, errMsg );
|
||||
ret = exec_sql( sqliteHandle( ), sql, uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
handleError( sql, errMsg, savepointId );
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = exec_sql( QStringLiteral( "RELEASE SAVEPOINT \"%1\"" ).arg( savepointId ), errMsg );
|
||||
ret = exec_sql( sqliteHandle( ), QStringLiteral( "RELEASE SAVEPOINT \"%1\"" ).arg( savepointId ), uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
handleError( sql, errMsg, savepointId );
|
||||
@ -4564,7 +4566,7 @@ bool QgsSpatiaLiteProvider::addAttributes( const QList<QgsField> &attributes )
|
||||
|
||||
const QString savepointId { QStringLiteral( "qgis_spatialite_internal_savepoint_%1" ).arg( ++ sSavepointId ) };
|
||||
|
||||
int ret = exec_sql( QStringLiteral( "SAVEPOINT \"%1\"" ).arg( savepointId ), errMsg );
|
||||
int ret = exec_sql( sqliteHandle( ), QStringLiteral( "SAVEPOINT \"%1\"" ).arg( savepointId ), uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
handleError( sql, errMsg, QString() );
|
||||
@ -4577,7 +4579,7 @@ bool QgsSpatiaLiteProvider::addAttributes( const QList<QgsField> &attributes )
|
||||
.arg( mTableName,
|
||||
iter->name(),
|
||||
iter->typeName() );
|
||||
ret = exec_sql( sql, errMsg );
|
||||
ret = exec_sql( sqliteHandle( ), sql, uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
handleError( sql, errMsg, savepointId );
|
||||
@ -4585,7 +4587,7 @@ bool QgsSpatiaLiteProvider::addAttributes( const QList<QgsField> &attributes )
|
||||
}
|
||||
}
|
||||
|
||||
ret = exec_sql( QStringLiteral( "RELEASE SAVEPOINT \"%1\"" ).arg( savepointId ), errMsg );
|
||||
ret = exec_sql( sqliteHandle( ), QStringLiteral( "RELEASE SAVEPOINT \"%1\"" ).arg( savepointId ), uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
handleError( sql, errMsg, savepointId );
|
||||
@ -4614,7 +4616,7 @@ bool QgsSpatiaLiteProvider::changeAttributeValues( const QgsChangedAttributesMap
|
||||
|
||||
const QString savepointId { QStringLiteral( "qgis_spatialite_internal_savepoint_%1" ).arg( ++ sSavepointId ) };
|
||||
|
||||
int ret = exec_sql( QStringLiteral( "SAVEPOINT \"%1\"" ).arg( savepointId ), errMsg );
|
||||
int ret = exec_sql( sqliteHandle( ), QStringLiteral( "SAVEPOINT \"%1\"" ).arg( savepointId ), uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
handleError( sql, errMsg, QString() );
|
||||
@ -4781,7 +4783,7 @@ bool QgsSpatiaLiteProvider::changeAttributeValues( const QgsChangedAttributesMap
|
||||
}
|
||||
}
|
||||
|
||||
ret = exec_sql( QStringLiteral( "RELEASE SAVEPOINT \"%1\"" ).arg( savepointId ), errMsg );
|
||||
ret = exec_sql( sqliteHandle(), QStringLiteral( "RELEASE SAVEPOINT \"%1\"" ).arg( savepointId ), uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
handleError( sql, errMsg, savepointId );
|
||||
@ -4802,7 +4804,7 @@ bool QgsSpatiaLiteProvider::changeGeometryValues( const QgsGeometryMap &geometry
|
||||
|
||||
const QString savepointId { QStringLiteral( "qgis_spatialite_internal_savepoint_%1" ).arg( ++ sSavepointId ) };
|
||||
|
||||
int ret = exec_sql( QStringLiteral( "SAVEPOINT \"%1\"" ).arg( savepointId ), errMsg );
|
||||
int ret = exec_sql( sqliteHandle(), QStringLiteral( "SAVEPOINT \"%1\"" ).arg( savepointId ), uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
handleError( sql, errMsg, QString() );
|
||||
@ -4860,7 +4862,7 @@ bool QgsSpatiaLiteProvider::changeGeometryValues( const QgsGeometryMap &geometry
|
||||
|
||||
sqlite3_finalize( stmt );
|
||||
|
||||
ret = exec_sql( QStringLiteral( "RELEASE SAVEPOINT \"%1\"" ).arg( savepointId ), errMsg );
|
||||
ret = exec_sql( sqliteHandle(), QStringLiteral( "RELEASE SAVEPOINT \"%1\"" ).arg( savepointId ), uri().uri(), errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( ret != SQLITE_OK )
|
||||
{
|
||||
handleError( sql, errMsg, savepointId );
|
||||
@ -6177,7 +6179,7 @@ bool QgsSpatiaLiteProviderMetadata::saveStyle( const QString &uri, const QString
|
||||
",ui text"
|
||||
",update_time timestamp DEFAULT CURRENT_TIMESTAMP"
|
||||
")" );
|
||||
ret = sqlite3_exec( sqliteHandle, createQuery.toUtf8().constData(), nullptr, nullptr, &errMsg );
|
||||
ret = QgsSpatiaLiteProvider::exec_sql( sqliteHandle, createQuery.toUtf8().constData(), uri, errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( SQLITE_OK != ret )
|
||||
{
|
||||
QgsSqliteHandle::closeDb( handle );
|
||||
@ -6269,7 +6271,7 @@ bool QgsSpatiaLiteProviderMetadata::saveStyle( const QString &uri, const QString
|
||||
sql = QStringLiteral( "BEGIN; %1; %2; COMMIT;" ).arg( removeDefaultSql, sql );
|
||||
}
|
||||
|
||||
ret = sqlite3_exec( sqliteHandle, sql.toUtf8().constData(), nullptr, nullptr, &errMsg );
|
||||
ret = QgsSpatiaLiteProvider::exec_sql( sqliteHandle, sql.toUtf8().constData(), uri, errMsg, QGS_QUERY_LOG_ORIGIN );
|
||||
if ( SQLITE_OK != ret )
|
||||
{
|
||||
QgsSqliteHandle::closeDb( handle );
|
||||
|
||||
@ -193,6 +193,11 @@ class QgsSpatiaLiteProvider final: public QgsVectorDataProvider
|
||||
*/
|
||||
QgsSqliteHandle *mHandle = nullptr;
|
||||
|
||||
/**
|
||||
* Sqlite exec sql wrapper for SQL logging
|
||||
*/
|
||||
static int exec_sql( sqlite3 *handle, const QString &sql, const QString &uri, char *errMsg = nullptr, const QString &origin = QString() );
|
||||
|
||||
private:
|
||||
|
||||
//! Loads fields from input file to member mAttributeFields
|
||||
@ -397,11 +402,6 @@ class QgsSpatiaLiteProvider final: public QgsVectorDataProvider
|
||||
*/
|
||||
void handleError( const QString &sql, char *errorMessage, const QString &savepointId );
|
||||
|
||||
/**
|
||||
* Sqlite exec sql wrapper for SQL logging
|
||||
*/
|
||||
int exec_sql( const QString &sql, char *errMsg = nullptr );
|
||||
|
||||
/**
|
||||
* Returns the sqlite handle to be used, if we are inside a transaction it will be the transaction's handle
|
||||
*/
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsfeedback.h"
|
||||
#include "qgsdbquerylog.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QTextCodec>
|
||||
@ -466,8 +467,11 @@ void QgsSpatiaLiteProviderConnection::setDefaultCapabilities()
|
||||
QgsAbstractDatabaseProviderConnection::QueryResult QgsSpatiaLiteProviderConnection::executeSqlPrivate( const QString &sql, QgsFeedback *feedback ) const
|
||||
{
|
||||
|
||||
QgsDatabaseQueryLogWrapper logWrapper( sql, uri(), providerKey(), QStringLiteral( "QgsSpatiaLiteProviderConnection" ), QGS_QUERY_LOG_ORIGIN );
|
||||
|
||||
if ( feedback && feedback->isCanceled() )
|
||||
{
|
||||
logWrapper.setCanceled();
|
||||
return QgsAbstractDatabaseProviderConnection::QueryResult();
|
||||
}
|
||||
|
||||
@ -478,6 +482,7 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsSpatiaLiteProviderConnecti
|
||||
|
||||
if ( feedback && feedback->isCanceled() )
|
||||
{
|
||||
logWrapper.setCanceled();
|
||||
return QgsAbstractDatabaseProviderConnection::QueryResult();
|
||||
}
|
||||
|
||||
@ -540,6 +545,7 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsSpatiaLiteProviderConnecti
|
||||
|
||||
if ( ! errCause.isEmpty() )
|
||||
{
|
||||
logWrapper.setError( errCause );
|
||||
throw QgsProviderConnectionException( QObject::tr( "Error executing SQL statement %1: %2" ).arg( sql, errCause ) );
|
||||
}
|
||||
|
||||
@ -562,6 +568,7 @@ QgsAbstractDatabaseProviderConnection::QueryResult QgsSpatiaLiteProviderConnecti
|
||||
|
||||
if ( !errCause.isEmpty() )
|
||||
{
|
||||
logWrapper.setError( errCause );
|
||||
throw QgsProviderConnectionException( QObject::tr( "Error executing SQL %1: %2" ).arg( sql, errCause ) );
|
||||
}
|
||||
|
||||
|
||||
117
src/ui/qgsqueryloggerpanelbase.ui
Normal file
117
src/ui/qgsqueryloggerpanelbase.ui
Normal file
@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QgsDatabaseQueryLoggerPanelBase</class>
|
||||
<widget class="QgsPanelWidget" name="QgsDatabaseQueryLoggerPanelBase">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>700</width>
|
||||
<height>629</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolBar" name="mToolbar">
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="floatable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<addaction name="mActionRecord"/>
|
||||
<addaction name="mActionClear"/>
|
||||
<addaction name="mActionSaveLog"/>
|
||||
<addaction name="separator"/>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QgsFilterLineEdit" name="mFilterLineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>6</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
<action name="mActionClear">
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/mActionDeleteSelected.svg</normaloff>:/images/themes/default/mActionDeleteSelected.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Clear Log</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="mActionRecord">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/mActionRecord.svg</normaloff>:/images/themes/default/mActionRecord.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Record Log</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="mActionSaveLog">
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/mActionFileSave.svg</normaloff>:/images/themes/default/mActionFileSave.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save Log…</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QgsPanelWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qgspanelwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QgsFilterLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>qgsfilterlineedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../images/images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
Loading…
x
Reference in New Issue
Block a user