From 9453d93d99becc606526e01c149d44f7d3835aaa Mon Sep 17 00:00:00 2001 From: Lawrin Novitsky Date: Sun, 10 May 2020 23:17:59 +0200 Subject: [PATCH] CONCPP-10 Fix of failing tests(mostly bugs causing them) The commit contains too many fixes to remember all of them, really. May resultset navigation fixes. Crashes, caused by not initializing of some properties in some classes, etc. --- include/Connection.h | 6 + include/DatabaseMetaData.h | 12 + include/Driver.h | 2 +- include/ResultSetMetaData.h | 2 + include/SQLString.h | 1 + src/ColumnDefinition.h | 2 + src/ExceptionFactory.cpp | 2 + src/ExceptionFactory.h | 5 + src/MariaDbConnection.cpp | 20 ++ src/MariaDbConnection.h | 4 + src/MariaDbDatabaseMetaData.cpp | 53 +++- src/MariaDbDatabaseMetaData.h | 13 + src/MariaDbDriver.cpp | 93 ++++++- src/MariaDbDriver.h | 2 +- src/MariaDbResultSetMetaData.cpp | 33 ++- src/MariaDbResultSetMetaData.h | 2 + src/MariaDbStatement.cpp | 3 +- src/SQLString.cpp | 24 +- src/ServerSidePreparedStatement.cpp | 39 ++- src/UrlParser.cpp | 58 +---- src/com/RowProtocol.h | 2 +- src/com/capi/ColumnDefinitionCapi.cpp | 15 ++ src/com/capi/ColumnDefinitionCapi.h | 2 + src/com/capi/SelectResultSetCapi.cpp | 66 +++-- src/options/DefaultOptions.cpp | 3 +- src/protocol/capi/BinRowProtocolCapi.cpp | 12 +- src/protocol/capi/BinRowProtocolCapi.h | 2 +- src/protocol/capi/ConnectProtocol.cpp | 15 +- src/protocol/capi/QueryProtocol.cpp | 18 +- src/protocol/capi/QueryProtocol.h | 1 - src/protocol/capi/TextRowProtocolCapi.cpp | 10 +- src/protocol/capi/TextRowProtocolCapi.h | 2 +- src/util/ServerPrepareResult.cpp | 7 +- src/util/ServerPrepareStatementCache.cpp | 2 +- test/CMakeLists.txt | 1 + test/framework/test_suite.cpp | 7 + test/unit/bugs/bugs.cpp | 8 +- test/unit/classes/CMakeLists.txt | 54 ++-- test/unit/classes/connection.cpp | 230 ++++++++--------- test/unit/classes/connectionmetadata.cpp | 188 +++++++------- test/unit/classes/preparedstatement.cpp | 52 ++-- test/unit/classes/resultsetmetadata.cpp | 298 +++++++--------------- test/unit/unit_fixture.cpp | 2 +- test/unit/unit_fixture.h | 4 +- 44 files changed, 776 insertions(+), 601 deletions(-) diff --git a/include/Connection.h b/include/Connection.h index cc7fc5d..f5a45eb 100644 --- a/include/Connection.h +++ b/include/Connection.h @@ -84,6 +84,8 @@ public: virtual void releaseSavepoint(const Savepoint* savepoint)=0; virtual bool isValid(int32_t timeout)=0; + virtual bool isValid()=0; + virtual void setClientInfo(const SQLString& name,const SQLString& value)=0; virtual void setClientInfo(const Properties& properties)=0; virtual Properties getClientInfo()=0; @@ -97,8 +99,12 @@ public: virtual void setSchema(const SQLString& arg0)=0; virtual void reset()=0; + virtual bool reconnect()=0; + virtual Connection* setClientOption(const SQLString& name, void* value)=0; virtual Connection* setClientOption(const SQLString& name, const SQLString& value)=0; + virtual void getClientOption(const SQLString& n, void* v)=0; + virtual SQLString getClientOption(const SQLString& n)=0; virtual Clob* createClob()=0; virtual Blob* createBlob()=0; diff --git a/include/DatabaseMetaData.h b/include/DatabaseMetaData.h index 7ee3216..b412998 100644 --- a/include/DatabaseMetaData.h +++ b/include/DatabaseMetaData.h @@ -156,6 +156,7 @@ public: virtual SQLString getDriverVersion()=0; virtual int32_t getDriverMajorVersion()=0; virtual int32_t getDriverMinorVersion()=0; + virtual int32_t getDriverPatchVersion()=0; virtual bool usesLocalFiles()=0; virtual bool usesLocalFilePerTable()=0; virtual bool supportsMixedCaseIdentifiers()=0; @@ -311,7 +312,18 @@ public: virtual ResultSet* getFunctions(const SQLString& catalog, const SQLString& schemaPattern, const SQLString& functionNamePattern)=0; virtual int64_t getMaxLogicalLobSize()=0; virtual bool supportsRefCursors()=0; + + virtual bool supportsTypeConversion()=0; + virtual ResultSet* getSchemaObjectTypes()=0; + virtual ResultSet* getSchemaObjects()=0; + virtual ResultSet* getSchemaObjects(const SQLString& c, const SQLString& s, const SQLString& t)=0; + virtual int32_t getCDBCMajorVersion()=0; + virtual int32_t getCDBCMinorVersion()=0; + virtual ResultSet* getSchemaCollation(const SQLString& c, const SQLString& s)=0; + virtual ResultSet* getSchemaCharset(const SQLString& c, const SQLString& s)=0; + virtual ResultSet* getTableCollation(const SQLString& c, const SQLString& s, const SQLString& t)=0; + virtual ResultSet* getTableCharset(const SQLString& c, const SQLString& s, const SQLString& t)=0; }; } #endif diff --git a/include/Driver.h b/include/Driver.h index fcd51a3..fb96316 100644 --- a/include/Driver.h +++ b/include/Driver.h @@ -38,7 +38,7 @@ public: virtual Connection* connect(const SQLString& url, Properties& props)=0; virtual Connection* connect(const SQLString& host, const SQLString& user, const SQLString& pwd)=0; - virtual Connection* connect(Properties& props)=0; + virtual Connection* connect(const Properties& props)=0; virtual bool acceptsURL(const SQLString& url)=0; virtual int getMajorVersion()=0; virtual int getMinorVersion()=0; diff --git a/include/ResultSetMetaData.h b/include/ResultSetMetaData.h index 89cd4e7..c347960 100644 --- a/include/ResultSetMetaData.h +++ b/include/ResultSetMetaData.h @@ -60,6 +60,8 @@ public: virtual bool isWritable(uint32_t column)=0; virtual bool isDefinitelyWritable(uint32_t column)=0; virtual SQLString getColumnClassName(uint32_t column)=0; + virtual bool isZerofill(uint32_t column)=0; + virtual SQLString getColumnCollation(uint32_t column)=0; }; } diff --git a/include/SQLString.h b/include/SQLString.h index 556077f..f1d76b9 100644 --- a/include/SQLString.h +++ b/include/SQLString.h @@ -55,6 +55,7 @@ public: inline bool empty() const { return theString.empty(); } int compare(const SQLString& str) const; + int caseCompare(const SQLString& other) const; SQLString & append(const SQLString& addition); SQLString & append(const char * const addition); SQLString & append(char c); diff --git a/src/ColumnDefinition.h b/src/ColumnDefinition.h index 31ee354..ea55b74 100644 --- a/src/ColumnDefinition.h +++ b/src/ColumnDefinition.h @@ -46,6 +46,7 @@ public: virtual SQLString getName() const=0; virtual SQLString getOriginalName() const=0; virtual short getCharsetNumber() const=0; + virtual SQLString getCollation() const=0; virtual int64_t getLength() const=0; virtual int64_t getPrecision() const=0; virtual int32_t getDisplaySize() const=0; @@ -60,6 +61,7 @@ public: virtual bool isBlob() const=0; virtual bool isZeroFill() const=0; virtual bool isBinary() const=0; + virtual bool isReadonly() const=0; }; } diff --git a/src/ExceptionFactory.cpp b/src/ExceptionFactory.cpp index 726ccff..fea1d6c 100644 --- a/src/ExceptionFactory.cpp +++ b/src/ExceptionFactory.cpp @@ -43,6 +43,8 @@ namespace mariadb ExceptionFactory::ExceptionFactory(int64_t _threadId, Shared::Options _options) : threadId(_threadId) , options(_options) + , connection(nullptr) + , statement(nullptr) { } diff --git a/src/ExceptionFactory.h b/src/ExceptionFactory.h index 4fca67f..e478af6 100644 --- a/src/ExceptionFactory.h +++ b/src/ExceptionFactory.h @@ -28,6 +28,11 @@ namespace sql { namespace mariadb { +namespace capi +{ +#include "mysql.h" +void throwStmtError(MYSQL_STMT* stmt); +} class ExceptionFactory final { diff --git a/src/MariaDbConnection.cpp b/src/MariaDbConnection.cpp index 5d6f24e..82f7a2f 100644 --- a/src/MariaDbConnection.cpp +++ b/src/MariaDbConnection.cpp @@ -1045,6 +1045,14 @@ namespace mariadb } + void MariaDbConnection::getClientOption(const SQLString& n, void* v) { + throw SQLFeatureNotSupportedException("getClientOption is not supported"); + } + + + SQLString MariaDbConnection::getClientOption(const SQLString& n) { + throw SQLFeatureNotSupportedException("getClientOption is not supported"); + } /** * Constructs an object that implements the Clob interface. The object returned * initially contains no data. The setAsciiStream, setCharacterStream @@ -1122,6 +1130,10 @@ namespace mariadb } + bool MariaDbConnection::isValid() { + return protocol->ping(); + } + void MariaDbConnection::checkClientClose(const SQLString& name) { if (protocol->isExplicitClosed()) @@ -1686,6 +1698,14 @@ namespace mariadb } warningsCleared= true; } + + bool MariaDbConnection::reconnect() { + checkClientReconnect("reconnect"); + // checkClientReconnect would throw, if reconnect was not successful + return true; + } + + bool MariaDbConnection::includeDeadLockInfo() { return options->includeInnodbStatusInDeadlockExceptions; } diff --git a/src/MariaDbConnection.h b/src/MariaDbConnection.h index 7ff0ff7..7ddbcf8 100644 --- a/src/MariaDbConnection.h +++ b/src/MariaDbConnection.h @@ -162,6 +162,8 @@ public: sql::Connection* setClientOption(const SQLString& name, void* value); sql::Connection* setClientOption(const SQLString& name, const SQLString& value); + void getClientOption(const SQLString& n, void* v); + SQLString getClientOption(const SQLString& n); Clob* createClob(); Blob* createBlob(); @@ -173,6 +175,7 @@ public: #endif bool isValid(int32_t timeout); + bool isValid(); private: void checkClientClose(const SQLString& name); @@ -210,6 +213,7 @@ public: bool canUseServerTimeout(); void setDefaultTransactionIsolation(int32_t defaultTransactionIsolation); void reset(); + bool reconnect(); bool includeDeadLockInfo(); bool includeThreadsTraces(); }; diff --git a/src/MariaDbDatabaseMetaData.cpp b/src/MariaDbDatabaseMetaData.cpp index 67cdf6c..4344ecf 100644 --- a/src/MariaDbDatabaseMetaData.cpp +++ b/src/MariaDbDatabaseMetaData.cpp @@ -1228,22 +1228,28 @@ ResultSet* MariaDbDatabaseMetaData::getTables(const SQLString& catalog, const SQ return connection->getProtocol()->getServerVersion(); } - SQLString MariaDbDatabaseMetaData::getDriverName(){ + SQLString MariaDbDatabaseMetaData::getDriverName() { return DRIVER_NAME; } - SQLString MariaDbDatabaseMetaData::getDriverVersion(){ + SQLString MariaDbDatabaseMetaData::getDriverVersion() { return Version::version; } - int32_t MariaDbDatabaseMetaData::getDriverMajorVersion(){ + int32_t MariaDbDatabaseMetaData::getDriverMajorVersion() { return Version::majorVersion; } - int32_t MariaDbDatabaseMetaData::getDriverMinorVersion(){ + int32_t MariaDbDatabaseMetaData::getDriverMinorVersion() { return Version::minorVersion; } + + int32_t MariaDbDatabaseMetaData::getDriverPatchVersion() { + return Version::patchVersion; + } + + bool MariaDbDatabaseMetaData::usesLocalFiles(){ return false; } @@ -3849,12 +3855,45 @@ ResultSet* MariaDbDatabaseMetaData::getTables(const SQLString& catalog, const SQ return 4294967295L; } - bool MariaDbDatabaseMetaData::supportsRefCursors(){ + bool MariaDbDatabaseMetaData::supportsRefCursors() { return false; } - ResultSet* MariaDbDatabaseMetaData::getSchemaObjectTypes() - { + + bool MariaDbDatabaseMetaData::supportsTypeConversion() { + return true; + } + + /* Group of not supported methods */ + ResultSet* MariaDbDatabaseMetaData::getSchemaObjectTypes() { throw SQLFeatureNotImplementedException("getSchemaObjectTypes is not implemented"); } + + ResultSet* MariaDbDatabaseMetaData::getSchemaObjects(const SQLString& c, const SQLString& s, const SQLString& t) { + throw SQLFeatureNotImplementedException("getSchemaObjects is not implemented"); + } + + ResultSet* MariaDbDatabaseMetaData::getSchemaObjects() { + throw SQLFeatureNotImplementedException("getSchemaObjects is not implemented"); + } + int32_t MariaDbDatabaseMetaData::getCDBCMajorVersion() { + throw SQLFeatureNotSupportedException("getCDBCMajorVersion is not supported"); + } + int32_t MariaDbDatabaseMetaData::getCDBCMinorVersion() { + throw SQLFeatureNotSupportedException("getCDBCMinorVersion is not supported"); + } + ResultSet* MariaDbDatabaseMetaData::getSchemaCollation(const SQLString& c, const SQLString& s) { + throw SQLFeatureNotImplementedException("getSchemaCollation is not implemented"); + } + ResultSet* MariaDbDatabaseMetaData::getSchemaCharset(const SQLString& c, const SQLString& s) { + throw SQLFeatureNotImplementedException("getSchemaCharset is not implemented"); + } + ResultSet* MariaDbDatabaseMetaData::getTableCollation(const SQLString& c, const SQLString& s, const SQLString& t) { + throw SQLFeatureNotImplementedException("getTableCollation is not implemented"); + } + ResultSet* MariaDbDatabaseMetaData::getTableCharset(const SQLString& c, const SQLString& s, const SQLString& t) { + throw SQLFeatureNotImplementedException("getTableCharset is not implemented"); + + } + } /* namespace mariadb */ } /* namespace sql */ diff --git a/src/MariaDbDatabaseMetaData.h b/src/MariaDbDatabaseMetaData.h index 1d15a97..b9febd9 100644 --- a/src/MariaDbDatabaseMetaData.h +++ b/src/MariaDbDatabaseMetaData.h @@ -99,6 +99,7 @@ public: SQLString getDriverVersion(); int32_t getDriverMajorVersion(); int32_t getDriverMinorVersion(); + int32_t getDriverPatchVersion(); bool usesLocalFiles(); bool usesLocalFilePerTable(); bool supportsMixedCaseIdentifiers(); @@ -262,7 +263,19 @@ public: //public: bool isWrapperFor(const Classiface); int64_t getMaxLogicalLobSize(); bool supportsRefCursors(); + + bool supportsTypeConversion(); + /* Group of not supported methods */ ResultSet* getSchemaObjectTypes(); + ResultSet* getSchemaObjects(const SQLString& c, const SQLString& s, const SQLString& t); + ResultSet* getSchemaObjects(); + int32_t getCDBCMajorVersion(); + int32_t getCDBCMinorVersion(); + ResultSet* getSchemaCollation(const SQLString& c, const SQLString& s); + ResultSet* getSchemaCharset(const SQLString& c, const SQLString& s); + ResultSet* getTableCollation(const SQLString& c, const SQLString& s, const SQLString& t); + ResultSet* getTableCharset(const SQLString& c, const SQLString& s, const SQLString& t); + }; } diff --git a/src/MariaDbDriver.cpp b/src/MariaDbDriver.cpp index 62fd1a8..1d00b41 100644 --- a/src/MariaDbDriver.cpp +++ b/src/MariaDbDriver.cpp @@ -33,6 +33,25 @@ namespace sql namespace mariadb { static MariaDbDriver theInstance; + static const Properties legacyPropKeyMapping{ {"userName", "user"}, + {"socket", "localSocket"} }; + extern const SQLString mysqlTcp, mysqlSocket, mysqlPipe; + + void mapLegacyProps(Properties& props) + { + auto it = props.begin(); + while (it != props.end()) { + auto cit = legacyPropKeyMapping.find(it->first); + if (cit != legacyPropKeyMapping.end()) { + props.emplace(cit->second, it->second); + it = props.erase(it); + } + else { + ++it; + } + } + } + MARIADB_EXPORTED Driver* get_driver_instance() { @@ -55,16 +74,79 @@ namespace mariadb } + void normalizeLegacyUri(SQLString& url, Properties* prop= nullptr) { + + //Making TCP default with legacy uri + if (url.find_first_of("://") == std::string::npos) { + url= "tcp://" + url; + } + + if (prop != nullptr) + { + std::string key; + std::size_t offset; + + mapLegacyProps(*prop); + + if (url.startsWith(mysqlTcp)) + { + auto cit= prop->find("port"); + if (cit != prop->end()) { + SQLString host(url.substr(mysqlTcp.length())); + size_t colon= host.find_first_of(':'); + size_t schemaSlash= schemaSlash= host.find_first_of('/'); + SQLString schema(schemaSlash != std::string::npos ? url.substr(schemaSlash + 1) : emptyStr); + + if (colon != std::string::npos) { + host= host.substr(0, colon); + } + url= mysqlTcp + host + ":" + cit->second + "/" + schema; + } + } + else if (url.startsWith(mysqlPipe)) { + offset = mysqlPipe.length(); + key = "pipe"; + } + else if (url.startsWith(mysqlSocket)) { + key = "localSocket"; + offset = mysqlSocket.length(); + } + else { + return; + } + + if (prop != nullptr) { + std::string name(url.substr(offset)); + std::size_t slashPos = name.find_first_of('/'); + + if (slashPos != std::string::npos) { + name = name.substr(0, slashPos); + } + + (*prop)[key] = name; + mapLegacyProps(*prop); + } + } + } + + Connection * MariaDbDriver::connect(const SQLString& host, const SQLString& user, const SQLString& pwd) { Properties props{ {"user", user}, {"password", pwd} }; - return connect(host, props); + SQLString localCopy(host); + + normalizeLegacyUri(localCopy); + + return connect(localCopy, props); } - Connection * MariaDbDriver::connect(Properties & props) + + Connection * MariaDbDriver::connect(const Properties &initProps) { SQLString uri; + Properties props(initProps); auto cit= props.find("hostName"); + if (cit != props.end()) { @@ -73,10 +155,6 @@ namespace mariadb } uri.append(cit->second); props.erase(cit); - if ((cit= props.find("port")) != props.end()) { - uri.append(':'); - uri.append(cit->second); - } } else if ((cit= props.find("pipe")) != props.end()) { @@ -101,6 +179,9 @@ namespace mariadb uri.append('/'); uri.append(cit->second); } + + mapLegacyProps(props); + return connect(uri, props); } diff --git a/src/MariaDbDriver.h b/src/MariaDbDriver.h index 33175d1..13af4e3 100644 --- a/src/MariaDbDriver.h +++ b/src/MariaDbDriver.h @@ -35,7 +35,7 @@ namespace mariadb public: Connection* connect(const SQLString& url, Properties& props); Connection* connect(const SQLString& host, const SQLString& user, const SQLString& pwd); - Connection* connect(Properties& props); + Connection* connect(const Properties& props); bool acceptsURL(const SQLString& url); std::unique_ptr> getPropertyInfo(SQLString& url, Properties& info); diff --git a/src/MariaDbResultSetMetaData.cpp b/src/MariaDbResultSetMetaData.cpp index f57faa8..ad9e334 100644 --- a/src/MariaDbResultSetMetaData.cpp +++ b/src/MariaDbResultSetMetaData.cpp @@ -34,10 +34,10 @@ namespace mariadb * @param options connection options * @param forceAlias force table and column name alias as original data */ - MariaDbResultSetMetaData::MariaDbResultSetMetaData(const std::vector& fieldPackets, const Shared::Options& options, bool forceAlias) - : fieldPackets(fieldPackets) - , options(options) - , forceAlias(forceAlias) + MariaDbResultSetMetaData::MariaDbResultSetMetaData(const std::vector& _fieldPackets, const Shared::Options& _options, bool _forceAlias) + : fieldPackets(_fieldPackets) + , options(_options) + , forceAlias(_forceAlias) { } @@ -83,6 +83,8 @@ namespace mariadb */ bool MariaDbResultSetMetaData::isSearchable(uint32_t column) { + // Just to check that valid column index requested + getColumnDefinition(column); return true; } @@ -94,6 +96,8 @@ namespace mariadb */ bool MariaDbResultSetMetaData::isCurrency(uint32_t column) { + // Just to check that valid column index requested + getColumnDefinition(column); return false; } @@ -179,7 +183,9 @@ namespace mariadb */ SQLString MariaDbResultSetMetaData::getCatalogName(uint32_t column) { - return getColumnDefinition(column).getDatabase(); + // Just to check that valid column index requested + getColumnDefinition(column); + return ""; } /** @@ -237,7 +243,7 @@ namespace mariadb SQLString MariaDbResultSetMetaData::getSchemaName(uint32_t column) { - return ""; + return getColumnDefinition(column).getDatabase(); } /** @@ -320,7 +326,7 @@ namespace mariadb */ bool MariaDbResultSetMetaData::isReadOnly(uint32_t column) { - return false; + return getColumnDefinition(column).isReadonly(); } /** @@ -368,9 +374,20 @@ namespace mariadb if (column >=1 &&column <= fieldPackets.size()) { return *fieldPackets[column -1]; } - throw *ExceptionFactory::INSTANCE.create("No such column"); + throw InvalidArgumentException("No such column", "42000");//*ExceptionFactory::INSTANCE.create("No such column"); } + + bool MariaDbResultSetMetaData::isZerofill(uint32_t column) + { + return getColumnDefinition(column).isZeroFill(); + } + + + SQLString MariaDbResultSetMetaData::getColumnCollation(uint32_t column) + { + return getColumnDefinition(column).getCollation(); + } /** * Returns true if this either implements the interface argument or is directly or indirectly a * wrapper for an object that does. Returns false otherwise. If this implements the interface then diff --git a/src/MariaDbResultSetMetaData.h b/src/MariaDbResultSetMetaData.h index 6dcc721..ed1969e 100644 --- a/src/MariaDbResultSetMetaData.h +++ b/src/MariaDbResultSetMetaData.h @@ -59,6 +59,8 @@ public: bool isWritable(uint32_t column); bool isDefinitelyWritable(uint32_t column); SQLString getColumnClassName(uint32_t column); + bool isZerofill(uint32_t column); + SQLString getColumnCollation(uint32_t column); private: const ColumnDefinition& getColumnDefinition(uint32_t column); diff --git a/src/MariaDbStatement.cpp b/src/MariaDbStatement.cpp index 4d21fad..e0a7e3f 100644 --- a/src/MariaDbStatement.cpp +++ b/src/MariaDbStatement.cpp @@ -74,7 +74,8 @@ namespace mariadb warningsCleared(true), maxRows(0), maxFieldSize(0), - exceptionFactory(factory) + exceptionFactory(factory), + isTimedout(false) { } diff --git a/src/SQLString.cpp b/src/SQLString.cpp index fc9dd63..43827f7 100644 --- a/src/SQLString.cpp +++ b/src/SQLString.cpp @@ -44,8 +44,8 @@ namespace sql { }*/ - - SQLString::SQLString(const char* str) : theString(str) + //TODO: not sure if it's not better to throw on null pointer + SQLString::SQLString(const char* str) : theString(str != nullptr ? str : "") { } @@ -277,10 +277,16 @@ namespace sql SQLString & SQLString::operator=(const char * right) { - theString= right; + theString= (right != nullptr ? right : ""); return *this; } + + int SQLString::caseCompare(const SQLString& other) const + { + SQLString lcThis(theString), lsThat(other); + return lcThis.toLowerCase().compare(lsThat.toLowerCase()); + } ////////////////////// Standalone util functions ///////////////////////////// namespace mariadb @@ -294,10 +300,18 @@ namespace mariadb while ((offset= theString.find_first_of(delimiter, prevOffset)) != std::string::npos) { - std::string tmp(it, it + offset - prevOffset); + std::string tmp(it, it + (offset - prevOffset)); result->emplace_back(tmp); prevOffset= ++offset; - it+= offset; + + if (it < theString.cend() - offset) + { + it += offset; + } + else + { + break; + } } std::string tmp(it, theString.cend()); diff --git a/src/ServerSidePreparedStatement.cpp b/src/ServerSidePreparedStatement.cpp index e49aaa2..8f36d8c 100644 --- a/src/ServerSidePreparedStatement.cpp +++ b/src/ServerSidePreparedStatement.cpp @@ -126,13 +126,42 @@ namespace sql void ServerSidePreparedStatement::setParameter(int32_t parameterIndex, ParameterHolder* holder) { // TODO: does it really has to be map? can be, actually - auto it= currentParameterHolder.find(parameterIndex - 1); - if (it == currentParameterHolder.end()) { - Shared::ParameterHolder paramHolder(holder); - currentParameterHolder.emplace(parameterIndex - 1, paramHolder); + if (parameterIndex > 0 && parameterIndex < serverPrepareResult->getParamCount() + 1) { + auto it= currentParameterHolder.find(parameterIndex - 1); + if (it == currentParameterHolder.end()) { + Shared::ParameterHolder paramHolder(holder); + currentParameterHolder.emplace(parameterIndex - 1, paramHolder); + } + else { + it->second.reset(holder); + } } else { - it->second.reset(holder); + SQLString error("Could not set parameter at position "); + + error.append(std::to_string(parameterIndex)).append(" (values was ").append(holder->toString()).append(")\nQuery - conn:"); + + // A bit ugly - index validity is checked after parameter holder objects have been created. + delete holder; + + error.append(std::to_string(getServerThreadId())).append(connection->getProtocol()->isMasterConnection() ? "(M)" : "(S)"); + error.append(" - \""); + + int32_t maxQuerySizeToLog= connection->getProtocol()->getOptions()->maxQuerySizeToLog; + if (maxQuerySizeToLog > 0) { + if (sql.size() < maxQuerySizeToLog) { + error.append(sql); + } + else { + error.append(sql.substr(0, maxQuerySizeToLog - 3) + "..."); + } + } + else { + error.append(sql); + } + error.append(" - \""); + logger->error(error); + throw *ExceptionFactory::INSTANCE.create(error); } } diff --git a/src/UrlParser.cpp b/src/UrlParser.cpp index c3dbf71..d58eb8e 100644 --- a/src/UrlParser.cpp +++ b/src/UrlParser.cpp @@ -36,61 +36,21 @@ namespace mariadb const SQLString mysqlTcp("tcp://"), mysqlSocket("unix://"), mysqlPipe("pipe://"); - static const Properties mysqlPropKeyMapping{ {"userName", "user"}, - {"socket", "localSocket"} }; - void mapMySqlProps(Properties& props) + bool isLegacyUriFormat(const SQLString& url) { - auto it= props.begin(); - while (it != props.end()) { - auto cit= mysqlPropKeyMapping.find(it->first); - if (cit != mysqlPropKeyMapping.end()) { - props.emplace(cit->second, it->second); - it= props.erase(it); - } - else { - ++it; - } - } - } - - bool isMySqlCppUri(const SQLString& url, Properties* prop= nullptr) - { - std::string key; - std::size_t offset; - - if (url.empty() || url.startsWith(mysqlTcp)) { - //name= localSocketAddress; - //offset= mysqlTcp.length(); - if (prop != nullptr) { - mapMySqlProps(*prop); - } + if (url.empty() || url.startsWith(mysqlTcp)) + { return true; } else if (url.startsWith(mysqlPipe)) { - offset= mysqlPipe.length(); - key= "pipe"; + return true; } else if (url.startsWith(mysqlSocket)) { - key= "localSocket"; - offset= mysqlSocket.length(); - } - else { - return false; + return true; } - if (prop != nullptr) { - std::string name(url.substr(offset)); - std::size_t slashPos= name.find_first_of('/'); - - if (slashPos != std::string::npos) { - name= name.substr(0, slashPos); - } - - (*prop)[key]= name; - mapMySqlProps(*prop); - } - return true; + return false; } @@ -125,7 +85,7 @@ namespace mariadb bool UrlParser::acceptsUrl(const SQLString& url) { - return (url.startsWith("jdbc:mariadb:") || (url.startsWith("jdbc:mysql:") && !(url.find_first_of(DISABLE_MYSQL_URL) != std::string::npos)) || isMySqlCppUri(url)); + return (url.startsWith("jdbc:mariadb:") || (url.startsWith("jdbc:mysql:") && !(url.find_first_of(DISABLE_MYSQL_URL) != std::string::npos)) || isLegacyUriFormat(url)); } @@ -139,7 +99,7 @@ namespace mariadb { if ((url.startsWith("jdbc:mariadb:") || url.startsWith("jdbc:mysql:") && url.find_first_of(DISABLE_MYSQL_URL) == std::string::npos) - || isMySqlCppUri(url, &prop)) + || isLegacyUriFormat(url)) { UrlParser *urlParser= new UrlParser(); @@ -196,7 +156,7 @@ namespace mariadb } catch (std::exception &i) { - throw std::runtime_error(std::string("error parsing url: ") + i.what()); + throw SQLException(std::string("Error parsing url: ") + i.what()); } } diff --git a/src/com/RowProtocol.h b/src/com/RowProtocol.h index 1ab7591..34b4029 100644 --- a/src/com/RowProtocol.h +++ b/src/com/RowProtocol.h @@ -116,7 +116,7 @@ public: void rangeCheck(const sql::SQLString& className, int64_t minValue, int64_t maxValue, int64_t value, ColumnDefinition* columnInfo); #endif virtual int32_t fetchNext()=0; - virtual void fetchAtPosition(int32_t rowPtr)=0; + virtual void installCursorAtPosition(int32_t rowPtr)=0; virtual Date getInternalDate(ColumnDefinition* columnInfo, Calendar* cal=nullptr, TimeZone* timeZone=nullptr)=0; virtual std::unique_ptr