code cleanup

This commit is contained in:
Günter Obiltschnig
2020-01-25 20:43:13 +01:00
parent 65be8b0bb6
commit 14e58b7fea
20 changed files with 209 additions and 304 deletions

View File

@@ -17,17 +17,17 @@
#ifndef SQL_PostgreSQL_Binder_INCLUDED
#define SQL_PostgreSQL_Binder_INCLUDED
#include "Poco/Data/PostgreSQL/PostgreSQL.h"
#include "Poco/Data/PostgreSQL/PostgreSQLTypes.h"
#include "Poco/Data/PostgreSQL/PostgreSQLException.h"
#include "Poco/Data/AbstractBinder.h"
#include "Poco/Data/MetaColumn.h"
#include "Poco/Data/LOB.h"
#include "Poco/Types.h"
#include <libpq-fe.h>
namespace Poco {
namespace Data {
namespace PostgreSQL {
@@ -38,11 +38,11 @@ class PostgreSQL_API Binder: public Poco::Data::AbstractBinder
/// Allows data type mapping at statement execution time.
{
public:
typedef SharedPtr<Binder> Ptr;
using Ptr = SharedPtr<Binder>;
Binder();
/// Creates the Binder.
virtual ~Binder();
/// Destroys the Binder.
@@ -244,12 +244,11 @@ private:
/// due to security risk.
{
}
void realBind(std::size_t aPosition, Poco::Data::MetaColumn::ColumnDataType aFieldType, const void* aBufferPtr, std::size_t aLength);
/// Common bind implementation
private:
InputParameterVector _bindVector;
};

View File

@@ -13,33 +13,28 @@
// SPDX-License-Identifier: BSL-1.0
//
#ifndef SQL_PostgreSQL_Connector_INCLUDED
#define SQL_PostgreSQL_Connector_INCLUDED
#include "Poco/Data/PostgreSQL/PostgreSQL.h"
#include "Poco/Data/SessionImpl.h"
#include "Poco/Data/Connector.h"
#include "Poco/AutoPtr.h"
#include <string>
// Note: to avoid static (de)initialization problems,
// during connector automatic (un)registration, it is
// best to have this as a macro.
#define POCO_DATA_POSTGRESQL_CONNECTOR_NAME "postgresql"
namespace Poco {
namespace Data {
namespace PostgreSQL {
class PostgreSQL_API Connector: public Poco::Data::Connector
/// Connector instantiates PostgreSQL SessionImpl objects.
{
public:
static std::string KEY;
static const std::string KEY;
Connector();
/// Creates the Connector.
@@ -65,55 +60,4 @@ public:
} } } // namespace Poco::Data::PostgreSQL
//
// Automatic Connector registration
//
struct PostgreSQL_API PostgreSQLConnectorRegistrator
/// Connector registering class.
/// A global instance of this class is instantiated
/// with sole purpose to automatically register the
/// PostgreSQL connector with central Poco Data registry.
{
PostgreSQLConnectorRegistrator()
/// Calls Poco::Data::PostgreSQL::registerConnector();
{
Poco::Data::PostgreSQL::Connector::registerConnector();
}
~PostgreSQLConnectorRegistrator()
/// Calls Poco::Data::PostgreSQL::unregisterConnector();
{
Poco::Data::PostgreSQL::Connector::unregisterConnector();
}
};
#if !defined(POCO_NO_AUTOMATIC_LIB_INIT)
#if defined(POCO_OS_FAMILY_WINDOWS)
extern "C" const struct PostgreSQL_API PostgreSQLConnectorRegistrator pocoPostgreSQLConnectorRegistrator;
#if defined(PostgreSQL_EXPORTS)
#if defined(_WIN64)
#define POCO_DATA_POSTGRESQL_FORCE_SYMBOL(s) __pragma(comment (linker, "/export:"#s))
#elif defined(_WIN32)
#define POCO_DATA_POSTGRESQL_FORCE_SYMBOL(s) __pragma(comment (linker, "/export:_"#s))
#endif
#else // !PostgreSQL_EXPORTS
#if defined(_WIN64)
#define POCO_DATA_POSTGRESQL_FORCE_SYMBOL(s) __pragma(comment (linker, "/include:"#s))
#elif defined(_WIN32)
#define POCO_DATA_POSTGRESQL_FORCE_SYMBOL(s) __pragma(comment (linker, "/include:_"#s))
#endif
#endif // PostgreSQL_EXPORTS
#else // !POCO_OS_FAMILY_WINDOWS
#define POCO_DATA_POSTGRESQL_FORCE_SYMBOL(s) extern "C" const struct PostgreSQLConnectorRegistrator s;
#endif // POCO_OS_FAMILY_WINDOWS
POCO_DATA_POSTGRESQL_FORCE_SYMBOL(pocoPostgreSQLConnectorRegistrator)
#endif // POCO_NO_AUTOMATIC_LIB_INIT
//
// End automatic Connector registration
//
#endif // Data_PostgreSQL_Connector_INCLUDED

View File

@@ -21,10 +21,8 @@
#include "Poco/Data/PostgreSQL/PostgreSQL.h"
#include "Poco/Data/PostgreSQL/PostgreSQLTypes.h"
#include "Poco/Data/PostgreSQL/StatementExecutor.h"
#include "Poco/Data/AbstractExtractor.h"
#include "Poco/Data/LOB.h"
#include "Poco/Types.h"
#include "Poco/Any.h"
#include "Poco/DynamicAny.h"
@@ -32,11 +30,6 @@
namespace Poco {
//namespace Dynamic {
// class Var;
//}
namespace Data {
namespace PostgreSQL {
@@ -46,7 +39,7 @@ class PostgreSQL_API Extractor: public Poco::Data::AbstractExtractor
/// If NULL is received, the incoming val value is not changed and false is returned
{
public:
typedef SharedPtr<Extractor> Ptr;
using Ptr = SharedPtr<Extractor>;
Extractor(StatementExecutor& st);
/// Creates the Extractor.
@@ -56,28 +49,28 @@ public:
virtual bool extract(std::size_t pos, Poco::Int8& val);
/// Extracts an Int8.
virtual bool extract(std::size_t pos, Poco::UInt8& val);
/// Extracts an UInt8.
virtual bool extract(std::size_t pos, Poco::Int16& val);
/// Extracts an Int16.
virtual bool extract(std::size_t pos, Poco::UInt16& val);
/// Extracts an UInt16.
virtual bool extract(std::size_t pos, Poco::Int32& val);
/// Extracts an Int32.
virtual bool extract(std::size_t pos, Poco::UInt32& val);
/// Extracts an UInt32.
virtual bool extract(std::size_t pos, Poco::Int64& val);
/// Extracts an Int64.
virtual bool extract(std::size_t pos, Poco::UInt64& val);
/// Extracts an UInt64.
#ifndef POCO_INT64_IS_LONG
virtual bool extract(std::size_t pos, long& val);
/// Extracts a long. Returns false if null was received.
@@ -88,10 +81,10 @@ public:
virtual bool extract(std::size_t pos, bool& val);
/// Extracts a boolean.
virtual bool extract(std::size_t pos, float& val);
/// Extracts a float.
virtual bool extract(std::size_t pos, double& val);
/// Extracts a double.
@@ -131,7 +124,7 @@ public:
////////////
// Not implemented extract functions
////////////
virtual bool extract(std::size_t pos, std::vector<Poco::Int8>& val);
/// Extracts an Int8 vector.
@@ -324,14 +317,12 @@ public:
/// Extracts a Dynamic::Var list.
private:
const OutputParameter& extractPreamble(std::size_t aPosition) const;
bool isColumnNull(const OutputParameter& anOutputParameter) const;
template <typename T>
bool extractStringImpl(std::size_t pos, T& val)
/// Utility function for extraction of Any and DynamicAny.
/// Utility function for extraction of Any and DynamicAny.
{
OutputParameter outputParameter = extractPreamble(pos);
@@ -357,7 +348,6 @@ private:
Extractor& operator=(const Extractor&);
private:
StatementExecutor& _statementExecutor;
};

View File

@@ -17,25 +17,23 @@
#ifndef SQL_PostgreSQL_PostgreSQLException_INCLUDED
#define SQL_PostgreSQL_PostgreSQLException_INCLUDED
#include "Poco/Data/PostgreSQL/PostgreSQL.h"
#include "Poco/Data/DataException.h"
#include <typeinfo>
#include <string>
namespace Poco {
namespace Data {
namespace PostgreSQL {
// End-user include this file and use in code ConnectionException/StatementException
// So it need not know
class PostgreSQL_API PostgreSQLException: public Poco::Data::DataException
/// Base class for all PostgreSQL exceptions
{
public:
PostgreSQLException(const std::string& aMessage);
explicit PostgreSQLException(const std::string& aMessage);
/// Creates PostgreSQLException.
PostgreSQLException(const PostgreSQLException& exc);
@@ -44,7 +42,7 @@ public:
~PostgreSQLException() noexcept;
/// Destroys PostgreSQLexception.
PostgreSQLException& operator=(const PostgreSQLException& exc);
PostgreSQLException& operator = (const PostgreSQLException& exc);
/// Assignment operator.
const char* name() const noexcept;
@@ -68,32 +66,28 @@ public:
};
class ConnectionException : public PostgreSQLException
class ConnectionException: public PostgreSQLException
/// ConnectionException
{
public:
ConnectionException(const std::string& aMessage);
/// Creates ConnectionException from string.
};
class TransactionException : public ConnectionException
class TransactionException: public ConnectionException
/// TrabsactionException
{
public:
TransactionException(const std::string& aMessage);
/// Creates TransactionException from string.
};
class StatementException : public PostgreSQLException
class StatementException: public PostgreSQLException
/// StatementException
{
public:
StatementException(const std::string& aMessage);
/// Creates StatementException from string.
};
@@ -103,9 +97,10 @@ public:
// inlines
//
inline PostgreSQLException& PostgreSQLException::operator=(const PostgreSQLException& exc)
inline PostgreSQLException& PostgreSQLException::operator = (const PostgreSQLException& exc)
{
Poco::Data::DataException::operator=(exc);
Poco::Data::DataException::operator = (exc);
return *this;
}
@@ -136,4 +131,5 @@ inline void PostgreSQLException::rethrow() const
} } } // namespace Poco::Data::PostgreSQL
#endif //SQL_PostgreSQL_PostgreSQLException_INCLUDED

View File

@@ -17,6 +17,7 @@
#ifndef SQL_PostgreSQL_PostgreSQLStatementImpl_INCLUDED
#define SQL_PostgreSQL_PostgreSQLStatementImpl_INCLUDED
#include "Poco/Data/PostgreSQL/PostgreSQL.h"
#include "Poco/Data/PostgreSQL/SessionImpl.h"
#include "Poco/Data/PostgreSQL/Binder.h"
@@ -43,7 +44,6 @@ public:
/// Destroys the PostgreSQLStatementImpl.
protected:
virtual std::size_t columnsReturned() const;
/// Returns number of columns returned by query.

View File

@@ -13,22 +13,25 @@
// SPDX-License-Identifier: BSL-1.0
//
#ifndef SQL_PostgreSQL_Types_INCLUDED
#define SQL_PostgreSQL_Types_INCLUDED
#include "Poco/Data/MetaColumn.h"
#include <vector>
#include <libpq-fe.h>
namespace Poco {
namespace Data {
namespace PostgreSQL {
/// Oid constants duplicated from PostgreSQL "include/postgresql/server/catalog/pg_type.h"
/// because PostgreSQL compile time definitions are too onerous to reproduce for this module
const Oid BOOLOID = 16;
const Oid INT2OID = 21;
@@ -59,23 +62,25 @@ const Oid CASHOID = 790;
const Oid MACADDROID = 829;
const Oid UUIDOID = 2950;
Poco::Data::MetaColumn::ColumnDataType oidToColumnDataType(const Oid anOID);
class InputParameter
/// PostgreSQL class to record values for input parameters to SQL statements
{
public:
typedef Poco::Data::MetaColumn::ColumnDataType CDT;
using CDT = Poco::Data::MetaColumn::ColumnDataType;
explicit InputParameter(CDT fieldType, const void* dataPtr, std::size_t dataLength);
explicit InputParameter();
InputParameter(CDT fieldType, const void* dataPtr, std::size_t dataLength);
InputParameter();
~InputParameter();
CDT fieldType() const;
CDT fieldType() const;
const void* pData() const;
std::size_t size() const;
bool isBinary() const;
bool isBinary() const;
void setStringVersionRepresentation(const std::string& aString);
void setNonStringVersionRepresentation(const void* aPtr, std::size_t theSize);
@@ -91,14 +96,15 @@ private:
void* _pNonStringVersionRepresentation;
};
typedef std::vector <InputParameter> InputParameterVector;
using InputParameterVector = std::vector <InputParameter>;
class OutputParameter
/// PostgreSQL class to record values for output parameters to capture the results
{
public:
typedef Poco::Data::MetaColumn::ColumnDataType CDT;
using CDT = Poco::Data::MetaColumn::ColumnDataType;
OutputParameter(CDT aFieldType, Oid internalFieldType, std::size_t rowNumber,
const char* dataPtr, std::size_t size, bool isNull);
@@ -109,16 +115,14 @@ public:
void setValues(CDT fieldType, Oid internalFieldType, std::size_t rowNumber,
const char* dataPtr, std::size_t size, bool isNull);
CDT fieldType() const;
Oid internalFieldType() const;
CDT fieldType() const;
Oid internalFieldType() const;
std::size_t rowNumber() const;
const char* pData() const;
std::size_t size() const;
bool isNull() const;
bool isNull() const;
private:
CDT _fieldType;
Oid _internalFieldType;
std::size_t _rowNumber;
@@ -127,7 +131,8 @@ private:
bool _isNull;
};
typedef std::vector <OutputParameter> OutputParameterVector;
using OutputParameterVector = std::vector <OutputParameter>;
class PQConnectionInfoOptionsFree
@@ -138,23 +143,24 @@ public:
~PQConnectionInfoOptionsFree();
private:
PQConnectionInfoOptionsFree (const PQConnectionInfoOptionsFree&);
PQConnectionInfoOptionsFree& operator= (const PQConnectionInfoOptionsFree&);
PQConnectionInfoOptionsFree(const PQConnectionInfoOptionsFree&);
PQConnectionInfoOptionsFree& operator = (const PQConnectionInfoOptionsFree&);
private:
PQconninfoOption* _pConnectionInfoOption;
};
class PQResultClear
/// PostgreSQL statement result free (RAII)
{
public:
explicit PQResultClear(PGresult * aPQResultPtr);
explicit PQResultClear(PGresult* aPQResultPtr);
~PQResultClear();
private:
PQResultClear (const PQResultClear&);
PQResultClear& operator= (const PQResultClear&);
PQResultClear(const PQResultClear&);
PQResultClear& operator = (const PQResultClear&);
private:
PGresult* _pPQResult;
@@ -165,12 +171,12 @@ class PGCancelFree
/// PostgreSQL Cancel Info Options free (RAII)
{
public:
explicit PGCancelFree(PGcancel * aStatementCancelPtr);
explicit PGCancelFree(PGcancel* aStatementCancelPtr);
~PGCancelFree();
private:
PGCancelFree (const PGCancelFree&);
PGCancelFree& operator= (const PGCancelFree&);
PGCancelFree(const PGCancelFree&);
PGCancelFree& operator = (const PGCancelFree&);
private:
PGcancel* _pPGCancel;
@@ -181,20 +187,14 @@ private:
// inlines
//
// InputParameter
inline InputParameter::InputParameter(Poco::Data::MetaColumn::ColumnDataType aFieldType,
const void* aDataPtr, std::size_t theSize): _fieldType(aFieldType),
inline InputParameter::InputParameter(Poco::Data::MetaColumn::ColumnDataType fieldType,
const void* aDataPtr, std::size_t theSize):
_fieldType(fieldType),
_pData(aDataPtr),
_size(theSize),
_isBinary(false),
_isBinary(Poco::Data::MetaColumn::FDT_BLOB == _fieldType || Poco::Data::MetaColumn::FDT_CLOB == _fieldType),
_pNonStringVersionRepresentation(0)
{
if (Poco::Data::MetaColumn::FDT_BLOB == _fieldType
|| Poco::Data::MetaColumn::FDT_CLOB == _fieldType)
{
_isBinary = true;
}
}
@@ -283,30 +283,29 @@ inline const void* InputParameter::pInternalRepresentation() const
}
// OutputParameter
inline OutputParameter::OutputParameter(Poco::Data::MetaColumn::ColumnDataType aFieldType,
Oid anInternalFieldType,
std::size_t aRowNumber,
const char* aDataPtr,
std::size_t theSize,
bool anIsNull): _fieldType(aFieldType),
_internalFieldType(anInternalFieldType),
_rowNumber(aRowNumber),
_pData(aDataPtr),
_size(theSize),
_isNull(anIsNull)
bool anIsNull):
_fieldType(aFieldType),
_internalFieldType(anInternalFieldType),
_rowNumber(aRowNumber),
_pData(aDataPtr),
_size(theSize),
_isNull(anIsNull)
{
}
inline OutputParameter::OutputParameter()
: _fieldType (Poco::Data::MetaColumn::FDT_UNKNOWN),
_internalFieldType (static_cast<Oid>(-1)),
_rowNumber (0),
_pData (0),
_size (0),
_isNull (true)
inline OutputParameter::OutputParameter():
_fieldType(Poco::Data::MetaColumn::FDT_UNKNOWN),
_internalFieldType(static_cast<Oid>(-1)),
_rowNumber(0),
_pData(0),
_size(0),
_isNull(true)
{
}
@@ -368,10 +367,8 @@ inline bool OutputParameter::isNull() const
}
// PQConnectionInfoOptionsFree
inline PQConnectionInfoOptionsFree::PQConnectionInfoOptionsFree(PQconninfoOption* aConnectionInfoOptionPtr)
: _pConnectionInfoOption(aConnectionInfoOptionPtr)
inline PQConnectionInfoOptionsFree::PQConnectionInfoOptionsFree(PQconninfoOption* aConnectionInfoOptionPtr):
_pConnectionInfoOption(aConnectionInfoOptionPtr)
{
}
@@ -386,10 +383,8 @@ inline PQConnectionInfoOptionsFree::~PQConnectionInfoOptionsFree()
}
// PQResultClear
inline PQResultClear::PQResultClear(PGresult* aPQResultPtr)
: _pPQResult(aPQResultPtr)
inline PQResultClear::PQResultClear(PGresult* aPQResultPtr):
_pPQResult(aPQResultPtr)
{
}
@@ -406,8 +401,8 @@ inline PQResultClear::~PQResultClear()
// PGCancelFree
inline PGCancelFree::PGCancelFree(PGcancel* aStatementCancelPtr)
: _pPGCancel(aStatementCancelPtr)
inline PGCancelFree::PGCancelFree(PGcancel* aStatementCancelPtr):
_pPGCancel(aStatementCancelPtr)
{
}
@@ -422,6 +417,7 @@ inline PGCancelFree::~PGCancelFree()
}
}}}
} } } // namespace Poco::Data::PostgreSQL
#endif // SQL_PostgreSQL_Types_INCLUDED

View File

@@ -13,27 +13,30 @@
// SPDX-License-Identifier: BSL-1.0
//
#ifndef SQL_PostgreSQL_SessionHandle_INCLUDED
#define SQL_PostgreSQL_SessionHandle_INCLUDED
#include "Poco/Mutex.h"
#include "Poco/Types.h"
#include <map>
#include <string>
#include <vector>
#include <libpq-fe.h>
namespace Poco {
namespace Data {
namespace PostgreSQL {
class SessionParameters
{
/// PostgreSQL session parameters
{
public:
enum HOW_TO_DISPLAY {
enum HowToDisplay
{
HTD_ASIS, // as is
HTD_HIDE, // do not display (e.g. passwords)
HID_DEBUG // debug use only
@@ -49,32 +52,32 @@ public:
~SessionParameters();
std::string keyword()const;
std::string enviromentVariable() const;
std::string compiledDefault()const;
std::string currentValue() const;
std::string displayLabel() const;
HOW_TO_DISPLAY howToDisplay() const;
int displaySize()const;
std::string keyword() const;
std::string enviromentVariable() const;
std::string compiledDefault() const;
std::string currentValue() const;
std::string displayLabel() const;
HowToDisplay howToDisplay() const;
int displaySize() const;
private:
std::string _keyword;// The keyword of the option
std::string _environmentVariable;// Fallback environment variable name
std::string _compiledDefault;// Fallback compiled in default value
std::string _currentValue; // Option's current value, or NULL
std::string _displayLabel; // Label for field in a connect dialog
HOW_TO_DISPLAY _howToDisplay; // Indicates how to display this field
int _displaySize;// Field size in characters for connect dialog
std::string _keyword; // The keyword of the option
std::string _environmentVariable; // Fallback environment variable name
std::string _compiledDefault; // Fallback compiled in default value
std::string _currentValue; // Option's current value, or NULL
std::string _displayLabel; // Label for field in a connect dialog
HowToDisplay _howToDisplay; // Indicates how to display this field
int _displaySize; // Field size in characters for connect dialog
};
typedef std::map<std::string, SessionParameters> SessionParametersMap;
using SessionParametersMap = std::map<std::string, SessionParameters>;
class SessionHandle
/// PostgreSQL connection(session) handle
{
public:
explicit SessionHandle();
/// Creates session handle
@@ -140,7 +143,7 @@ public:
void deallocatePreparedStatement(const std::string& aPreparedStatementToDeAllocate);
/// deallocates a previously prepared statement
int serverVersion() const;
/// remote server version
@@ -180,12 +183,10 @@ private:
bool isConnectedNoLock() const;
std::string lastErrorNoLock() const;
SessionHandle(const SessionHandle&);
SessionHandle& operator= (const SessionHandle&);
private:
mutable Poco::FastMutex _sessionMutex;
PGconn* _pConnection;
std::string _connectionString;
@@ -206,7 +207,6 @@ private:
// inlines
//
// SessionParameters
inline SessionParameters::SessionParameters(const std::string& aKeyword,
const std::string& anEnvironmentVariable,
@@ -269,7 +269,7 @@ inline std::string SessionParameters::displayLabel() const
}
inline SessionParameters::HOW_TO_DISPLAY SessionParameters::howToDisplay() const
inline SessionParameters::HowToDisplay SessionParameters::howToDisplay() const
{
return _howToDisplay;
}
@@ -280,8 +280,6 @@ inline int SessionParameters::displaySize() const
}
// SessionHandle
inline SessionHandle::operator PGconn * ()
{
return _pConnection;
@@ -318,7 +316,7 @@ inline bool SessionHandle::isAsynchronousCommit()
}
}}} // namespace Poco::Data::PostgreSQL
} } } // namespace Poco::Data::PostgreSQL
#endif // SQL_PostgreSQL_SessionHandle_INCLUDED

View File

@@ -22,9 +22,9 @@
#include "Poco/Data/PostgreSQL/SessionHandle.h"
#include "Poco/Data/AbstractSessionImpl.h"
#include "Poco/Data/StatementImpl.h"
#include <string>
namespace Poco {
namespace Data {
namespace PostgreSQL {
@@ -34,7 +34,6 @@ class PostgreSQL_API SessionImpl: public Poco::Data::AbstractSessionImpl<Session
/// Implements SessionImpl interface
{
public:
SessionImpl(const std::string& aConnectionString,
std::size_t aLoginTimeout = LOGIN_TIMEOUT_DEFAULT);
/// Creates the SessionImpl. Opens a connection to the database
@@ -129,6 +128,7 @@ private:
// inlines
//
inline bool SessionImpl::canTransact() const
{
return true;

View File

@@ -17,16 +17,16 @@
#ifndef SQL_PostgreSQL_StatementExecutor_INCLUDED
#define SQL_PostgreSQL_StatementExecutor_INCLUDED
#include "Poco/Data/PostgreSQL/PostgreSQLException.h"
#include "Poco/Data/PostgreSQL/PostgreSQLTypes.h"
#include "Poco/Data/PostgreSQL/SessionHandle.h"
#include "Poco/Data/MetaColumn.h"
#include <libpq-fe.h>
#include <string>
#include <vector>
namespace Poco {
namespace Data {
namespace PostgreSQL {
@@ -81,9 +81,8 @@ public:
/// Cast operator to native result handle type.
private:
void clearResults();
StatementExecutor(const StatementExecutor&);
StatementExecutor& operator= (const StatementExecutor&);
@@ -109,11 +108,14 @@ private:
// inlines
//
inline StatementExecutor::operator PGresult* ()
{
return _pResultHandle;
}
}}}
} } } // namespace Poco::Data::PostgreSQL
#endif // SQL_PostgreSQL_StatementExecutor_INCLUDED

View File

@@ -32,7 +32,6 @@ class PostgreSQL_API Utility
/// Various utility functions for PostgreSQL.
{
public:
static std::string serverInfo(SessionHandle* aHandlePtr);
/// Returns server info.