From fa5cb1783ad75d41abe1ca993f4593f207662156 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bloshchanevich Date: Wed, 28 Oct 2020 12:27:14 +0100 Subject: [PATCH 1/8] Handling for string and decimal parameters changed. Tested on MS SQL Server and MySQL. --- src/odbc/PreparedStatement.cpp | 22 ++++++----- src/odbc/ResultSet.cpp | 13 ++++--- src/odbc/Types.cpp | 38 +++++++++++++++++-- src/odbc/Types.h | 17 ++++++--- src/odbc/internal/Batch.cpp | 35 +++++------------ src/odbc/internal/Batch.h | 2 - src/odbc/internal/ParameterData.cpp | 14 ++----- src/odbc/internal/ParameterData.h | 58 ++--------------------------- 8 files changed, 82 insertions(+), 117 deletions(-) diff --git a/src/odbc/PreparedStatement.cpp b/src/odbc/PreparedStatement.cpp index 044c366..ea93c86 100644 --- a/src/odbc/PreparedStatement.cpp +++ b/src/odbc/PreparedStatement.cpp @@ -109,16 +109,12 @@ void PreparedStatement::setDecimal(unsigned short paramIndex, { if (value.isNull()) { - parameterData_[paramIndex - 1].setNull(TypeToOdbc::VALUETYPE); + parameterData_[paramIndex - 1].setNull(SQL_C_CHAR); } else { - SQL_NUMERIC_STRUCT ns; - UtilInternal::decimalToNumeric(*value, ns); - ParameterData& pd = parameterData_[paramIndex - 1]; - pd.setValue(TypeToOdbc::VALUETYPE, &ns, sizeof(ns)); - pd.setColumnSize(ns.precision); - pd.setDecimalDigits(ns.scale); + std::string val = (*value).toString(); + parameterData_[paramIndex - 1].setValue(SQL_C_CHAR, val.c_str(), val.size()); } } //------------------------------------------------------------------------------ @@ -332,20 +328,26 @@ void PreparedStatement::bindParameters() verifyAllParametersValid(); for (size_t i = 1; i <= parameterData_.size(); ++i) { + SQLSMALLINT dataType; + SQLULEN parameterSize; + SQLSMALLINT decimalDigits; + SQLSMALLINT nullable; + EXEC_STMT(SQLDescribeParam, hstmt_, (SQLUSMALLINT)i, &dataType, + ¶meterSize, &decimalDigits, &nullable); + const ParameterData& pd = parameterData_[i - 1]; if (pd.isNull()) { EXEC_STMT(SQLBindParameter, hstmt_, (SQLUSMALLINT)i, SQL_PARAM_INPUT, pd.getValueType(), - TypeInfo::getParamTypeForValueType(pd.getValueType()), + dataType, 0, 0, 0, 0, (SQLLEN*)pd.getLenIndPtr()); } else { EXEC_STMT(SQLBindParameter, hstmt_, (SQLUSMALLINT)i, SQL_PARAM_INPUT, pd.getValueType(), - TypeInfo::getParamTypeForValueType(pd.getValueType()), - pd.getColumnSize(), pd.getDecimalDigits(), + dataType, parameterSize, decimalDigits, (SQLPOINTER)pd.getData(), pd.getSize(), (SQLLEN*)pd.getLenIndPtr()); } diff --git a/src/odbc/ResultSet.cpp b/src/odbc/ResultSet.cpp index 9aacdbd..4b46c58 100644 --- a/src/odbc/ResultSet.cpp +++ b/src/odbc/ResultSet.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -151,15 +152,15 @@ ULong ResultSet::getULong(unsigned short columnIndex) //------------------------------------------------------------------------------ Decimal ResultSet::getDecimal(unsigned short columnIndex) { - SQL_NUMERIC_STRUCT num; + const int BUF_SIZE = 40; + char str[BUF_SIZE]; SQLLEN ind; - EXEC_STMT(SQLGetData, parent_->hstmt_, columnIndex, SQL_C_NUMERIC, &num, - sizeof(num), &ind); + EXEC_STMT(SQLGetData, parent_->hstmt_, columnIndex, SQL_C_CHAR, &str, + sizeof(str), &ind); if (ind == SQL_NULL_DATA) return Decimal(); - char str[64]; - odbc::UtilInternal::numericToString(num, str); - return Decimal(decimal(str, num.precision, num.scale)); + + return Decimal(decimal(str)); } //------------------------------------------------------------------------------ Float ResultSet::getFloat(unsigned short columnIndex) diff --git a/src/odbc/Types.cpp b/src/odbc/Types.cpp index 50197ec..d378103 100644 --- a/src/odbc/Types.cpp +++ b/src/odbc/Types.cpp @@ -28,6 +28,36 @@ decimal::decimal( : decimal(value.c_str(), precision, scale) { } + +decimal::decimal(const char* str) +{ + const int BUF_SIZE = 40; + + scale_ = 0; + bool pointFound = false; + std::uint8_t idx = 0; + for (; idx < BUF_SIZE && str[idx] != '\0'; ++idx) + { + if (pointFound) + { + value_.push_back(str[idx]); + ++scale_; + } + else + { + if (str[idx] == '.') + { + pointFound = true; + } + else { + value_.push_back(str[idx]); + } + } + } + ODBC_CHECK(idx <= BUF_SIZE, "input sting is too long, precision value must lie within [1,38]"); + precision_ = (uint8_t)value_.size(); +} + //------------------------------------------------------------------------------ decimal::decimal(const char* value, std::uint8_t precision, std::uint8_t scale) : precision_(precision), scale_(scale) @@ -224,7 +254,7 @@ int decimal::cmp(const decimal& other) const return 0; } //------------------------------------------------------------------------------ -ostream& operator<<(ostream& out, const decimal& d) +ODBC_EXPORT ostream& operator<<(ostream& out, const decimal& d) { out << d.toString(); return out; @@ -326,7 +356,7 @@ int date::daysInFebruary(int year) return 28; } //------------------------------------------------------------------------------ -ostream& operator<<(ostream& out, const date& d) +ODBC_EXPORT ostream& operator<<(ostream& out, const date& d) { out << d.toString(); return out; @@ -393,7 +423,7 @@ bool time::operator>=(const time& other) const return !(*this < other); } //------------------------------------------------------------------------------ -ostream& operator<<(ostream& out, const time& t) +ODBC_EXPORT ostream& operator<<(ostream& out, const time& t) { out << t.toString(); return out; @@ -458,7 +488,7 @@ bool timestamp::operator>=(const timestamp& other) const return !(*this < other); } //------------------------------------------------------------------------------ -ostream& operator<<(ostream& out, const timestamp& ts) +ODBC_EXPORT ostream& operator<<(ostream& out, const timestamp& ts) { out << ts.toString(); return out; diff --git a/src/odbc/Types.h b/src/odbc/Types.h index 7b9f4c3..c0f1a5c 100644 --- a/src/odbc/Types.h +++ b/src/odbc/Types.h @@ -182,6 +182,13 @@ class ODBC_EXPORT decimal decimal(const std::string& value, std::uint8_t precision, std::uint8_t scale = 0); + /** + * Constructs a decimal from a given char buffer. + * @param value The value. + */ + decimal(const char * value); + + /** * Constructs a decimal from a given value applying the given scale. * @@ -238,7 +245,7 @@ class ODBC_EXPORT decimal std::string toString() const; /** - * Checks whether this number is equal to another number. + * Convert. * * Only the scaled values are considered by the comparison. Hence, numbers * that have different scale and precisions can still be considered equal. @@ -318,7 +325,7 @@ class ODBC_EXPORT decimal std::uint8_t scale_; }; //------------------------------------------------------------------------------ -std::ostream& operator<<(std::ostream& out, const decimal& d); +ODBC_EXPORT std::ostream& operator <<(std::ostream& out, const decimal& d); //------------------------------------------------------------------------------ /** * Represents a date consisting of year, month and day in month. @@ -435,7 +442,7 @@ class ODBC_EXPORT date std::uint8_t day_; }; //------------------------------------------------------------------------------ -std::ostream& operator<<(std::ostream& out, const date& d); +ODBC_EXPORT std::ostream& operator<<(std::ostream& out, const date& d); //------------------------------------------------------------------------------ /** * Represents a time consisting of hour, minute and second. @@ -548,7 +555,7 @@ class ODBC_EXPORT time std::uint8_t second_; }; //------------------------------------------------------------------------------ -std::ostream& operator<<(std::ostream& out, const time& t); +ODBC_EXPORT std::ostream& operator<<(std::ostream& out, const time& t); //------------------------------------------------------------------------------ /** * Represents a timestamp consisting of year, month, day in month, hour, minute, @@ -650,7 +657,7 @@ class ODBC_EXPORT timestamp : public date, public time std::uint16_t milliseconds_; }; //------------------------------------------------------------------------------ -std::ostream& operator<<(std::ostream& out, const timestamp& ts); +ODBC_EXPORT std::ostream& operator<<(std::ostream& out, const timestamp& ts); //------------------------------------------------------------------------------ /** * Wrapper class for types that don't have a dedicated NULL value. diff --git a/src/odbc/internal/Batch.cpp b/src/odbc/internal/Batch.cpp index 6e9305b..f0c72ec 100644 --- a/src/odbc/internal/Batch.cpp +++ b/src/odbc/internal/Batch.cpp @@ -186,12 +186,18 @@ void Batch::bindBlockParameters(const char* blockData, size_t numRows, for (size_t i = 0; i < valueTypeInfos_.size(); ++i) { + SQLSMALLINT dataType; + SQLULEN parameterSize; + SQLSMALLINT decimalDigits; + SQLSMALLINT nullable; + EXEC_STMT(SQLDescribeParam, hstmt, (SQLUSMALLINT)i, &dataType, + ¶meterSize, &decimalDigits, &nullable); + const ValueTypeInfo& vti = valueTypeInfos_[i]; SQLLEN* lenInd = (SQLLEN*)(blockData + paramDataOffsets_[i]); EXEC_STMT(SQLBindParameter, hstmt, (SQLUSMALLINT)(i + 1), SQL_PARAM_INPUT, vti.type, - TypeInfo::getParamTypeForValueType(vti.type), - vti.columnSize, vti.decimalDigits, + dataType, parameterSize, decimalDigits, (SQLPOINTER)(lenInd + 1), 0, lenInd); } } @@ -273,8 +279,8 @@ void Batch::initialize() { const ParameterData& param = parameters_[i]; assert(param.isInitialized()); - valueTypeInfos_[i] = { param.getValueType(), - param.getColumnSize(), param.getDecimalDigits() }; + + valueTypeInfos_[i] = { param.getValueType() }; paramDataOffsets_[i] = rowLength_; rowLength_ += sizeof(SQLLEN); size_t valueSize = @@ -302,27 +308,6 @@ void Batch::checkAndCompleteValueTypes() << TypeInfo::getValueTypeName(valTypeInfo.type) << ", now it is " << TypeInfo::getValueTypeName( param.getValueType()) << "."); - - if (param.getValueType() == SQL_C_NUMERIC) - { - // columnSize and decimalDigits might not be set during the first - // call of addRow method. Therefore, we set their values here. - if (valTypeInfo.columnSize == 0) - { - valTypeInfo.columnSize = param.getColumnSize(); - valTypeInfo.decimalDigits = param.getDecimalDigits(); - } - - ODBC_CHECK( - param.getColumnSize() == valTypeInfo.columnSize && - param.getDecimalDigits() == valTypeInfo.decimalDigits, - "Precision and scale values of parameter " << (i + 1) << " do " - "not match the previous values used in the batch. Before it " - "was numeric(" << valTypeInfo.columnSize << "," << - valTypeInfo.decimalDigits << "), now it is numeric(" << - param.getColumnSize() << ", " << param.getDecimalDigits() << - ")."); - } } } //------------------------------------------------------------------------------ diff --git a/src/odbc/internal/Batch.h b/src/odbc/internal/Batch.h index d7ab789..40c3be0 100644 --- a/src/odbc/internal/Batch.h +++ b/src/odbc/internal/Batch.h @@ -178,8 +178,6 @@ class Batch : public RefCounted struct ValueTypeInfo { std::int16_t type; - std::uint8_t columnSize; - std::uint8_t decimalDigits; }; private: diff --git a/src/odbc/internal/ParameterData.cpp b/src/odbc/internal/ParameterData.cpp index 30efc09..703eca2 100644 --- a/src/odbc/internal/ParameterData.cpp +++ b/src/odbc/internal/ParameterData.cpp @@ -11,19 +11,15 @@ using namespace std; //------------------------------------------------------------------------------ namespace odbc { //------------------------------------------------------------------------------ -ParameterData::ParameterData() +ParameterData::ParameterData() noexcept : state_(UNINITIALIZED) , valueType_(0) - , columnSize_(0) - , decimalDigits_(0) { } //------------------------------------------------------------------------------ -ParameterData::ParameterData(ParameterData&& other) +ParameterData::ParameterData(ParameterData&& other) noexcept : state_(other.state_) , valueType_(other.valueType_) - , columnSize_(other.columnSize_) - , decimalDigits_(other.decimalDigits_) , size_(other.size_) { switch (state_) @@ -49,7 +45,7 @@ ParameterData::~ParameterData() free(heapData_); } //------------------------------------------------------------------------------ -ParameterData& ParameterData::operator=(ParameterData&& other) +ParameterData& ParameterData::operator=(ParameterData&& other) noexcept { if (this == &other) return *this; @@ -59,8 +55,6 @@ ParameterData& ParameterData::operator=(ParameterData&& other) state_ = other.state_; valueType_ = other.valueType_; - columnSize_ = other.columnSize_; - decimalDigits_ = other.decimalDigits_; size_ = other.size_; switch (state_) { @@ -91,8 +85,6 @@ void ParameterData::setValue(int16_t type, const void* value, size_t size) else setValueOnHeap(value, size); valueType_ = type; - columnSize_ = 0; - decimalDigits_ = 0; } //------------------------------------------------------------------------------ void ParameterData::setNull(int16_t type) diff --git a/src/odbc/internal/ParameterData.h b/src/odbc/internal/ParameterData.h index 05847c8..678fd96 100644 --- a/src/odbc/internal/ParameterData.h +++ b/src/odbc/internal/ParameterData.h @@ -43,7 +43,7 @@ class ParameterData /** * Creates an uninitialized instance. */ - ParameterData(); + ParameterData() noexcept; ParameterData(const ParameterData& other) = delete; @@ -53,7 +53,7 @@ class ParameterData * * @param other Another instance. */ - ParameterData(ParameterData&& other); + ParameterData(ParameterData&& other) noexcept; /** * Destructor. @@ -68,7 +68,7 @@ class ParameterData * @param other Another instance. * @return Returns a reference to this instance. */ - ParameterData& operator=(ParameterData&& other); + ParameterData& operator=(ParameterData&& other) noexcept; public: /** @@ -108,55 +108,7 @@ class ParameterData */ std::int16_t getValueType() const { return valueType_; } - /** - * Returns the size of the parameter. If the parameter type is SQL_DECIMAL, - * SQL_NUMERIC, SQL_FLOAT, SQL_REAL or SQL_DOUBLE the returned value - * represents the maximum precision of the corrresponding parameter. If the - * parameter type is SQL_CHAR, SQL_VARCHAR, SQL_LONGVARCHAR, SQL_BINARY, - * SQL_VARBINARY, SQL_LONGVARBINARY, SQL_TYPE_DATE, SQL_TYPE_TIME or - * SQL_TYPE_TIMESTAMP the returned value represents the maximum length of - * the corresponding parameter in bytes. - * - * @return The column size. - */ - std::uint8_t getColumnSize() const { return columnSize_; } - - /** - * Sets the column size of this parameter. If the parameter type is - * SQL_DECIMAL, SQL_NUMERIC, SQL_FLOAT, SQL_REAL or SQL_DOUBLE the value - * represents the maximum precision of the corrresponding parameter. If the - * parameter type is SQL_CHAR, SQL_VARCHAR, SQL_LONGVARCHAR, SQL_BINARY, - * SQL_VARBINARY, SQL_LONGVARBINARY, SQL_TYPE_DATE, SQL_TYPE_TIME or - * SQL_TYPE_TIMESTAMP the value represents the maximum length of the - * corresponding parameter in bytes. - * - * @param value The column size. - */ - void setColumnSize(std::uint8_t value) { columnSize_ = value; } - - /** - * Returns the number of decimal digits of this parameter. If the parameter - * type is SQL_DECIMAL or SQL_NUMERIC the value represents the scale of the - * corresponding parameter. If the parameter type is SQL_TYPE_TIME or - * SQL_TYPE_TIMESTAMP the value represents the precision of the - * corresponding parameter. - * - * @return The number of decimal digits. - */ - std::uint8_t getDecimalDigits() const { return decimalDigits_; } - - /** - * Sets the number of decimal digits of this parameter. If the parameter - * type is SQL_DECIMAL or SQL_NUMERIC the value represents the scale of the - * corresponding parameter. If the parameter type is SQL_TYPE_TIME or - * SQL_TYPE_TIMESTAMP the value represents the precision of the - * corresponding parameter. - * - * @param value The number of decimal digits. - */ - void setDecimalDigits(std::uint8_t value) { decimalDigits_ = value; } - - /** + /** * Checks whether the value is NULL. * * @return True if the value is NULL, false otherwise. @@ -265,8 +217,6 @@ class ParameterData // NORMAL_HEAP_OWNING or NORMAL_HEAP_NOT_OWNING State state_; std::int16_t valueType_; - std::uint8_t columnSize_; - std::uint8_t decimalDigits_; std::size_t size_; union { From b4cf6af80754883032151e2eb56a44119af13801 Mon Sep 17 00:00:00 2001 From: Maxim Rylov Date: Mon, 21 Dec 2020 12:44:51 +0100 Subject: [PATCH 2/8] Add PreparedStatement::getBatchDataSize() function --- src/odbc/PreparedStatement.cpp | 5 +++++ src/odbc/PreparedStatement.h | 9 ++++++++- src/odbc/internal/Batch.cpp | 9 +++++++++ src/odbc/internal/Batch.h | 10 ++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/odbc/PreparedStatement.cpp b/src/odbc/PreparedStatement.cpp index 28ef584..28c1898 100644 --- a/src/odbc/PreparedStatement.cpp +++ b/src/odbc/PreparedStatement.cpp @@ -344,6 +344,11 @@ void PreparedStatement::clearBatch() batch_->clear(); } //------------------------------------------------------------------------------ +size_t PreparedStatement::getBatchDataSize() const +{ + return batch_->getDataSize(); +} +//------------------------------------------------------------------------------ void PreparedStatement::bindParameters() { verifyAllParametersValid(); diff --git a/src/odbc/PreparedStatement.h b/src/odbc/PreparedStatement.h index c993689..d5e8d80 100644 --- a/src/odbc/PreparedStatement.h +++ b/src/odbc/PreparedStatement.h @@ -257,7 +257,7 @@ class ODBC_EXPORT PreparedStatement : public StatementBase * @return Returns the number of rows affected by an UPDATE, INSERT, or * DELETE statement. */ - size_t executeUpdate(); + std::size_t executeUpdate(); /** * Add the current set of parameters to the batch of commands. @@ -272,6 +272,13 @@ class ODBC_EXPORT PreparedStatement : public StatementBase */ void clearBatch(); + /** + * Retrieves the number of bytes required by the batch of commands. + * + * @return Returns the number of bytes required by the batch of commands. + */ + std::size_t getBatchDataSize() const; + private: void bindParameters(); diff --git a/src/odbc/internal/Batch.cpp b/src/odbc/internal/Batch.cpp index 9f0b1ad..108a6a5 100644 --- a/src/odbc/internal/Batch.cpp +++ b/src/odbc/internal/Batch.cpp @@ -30,6 +30,7 @@ void Batch::addRow() blockRow_ = 0; } + dataSize_ += rowLength_; Block& block = batchBlocks_.back(); char* dest = block.getData() + rowLength_ * blockRow_; for (size_t i = 0; i < parameters_.size(); ++i) @@ -53,6 +54,7 @@ void Batch::clear() // instead in a more sophisticated version. batchBlocks_.clear(); blockRow_ = 0; + dataSize_ = 0; } //------------------------------------------------------------------------------ void Batch::execute(void* hstmt) @@ -75,6 +77,11 @@ void Batch::execute(void* hstmt) nextRowInfo, hstmt); } //------------------------------------------------------------------------------ +size_t Batch::getDataSize() const +{ + return dataSize_; +} +//------------------------------------------------------------------------------ void Batch::writeParameter(char* dest, ParameterData& pd) { int16_t valueType = pd.getValueType(); @@ -108,6 +115,7 @@ void Batch::writeVariableSizeParameter(char* dest, ParameterData& pd) memcpy(dest, &data, sizeof(data)); if (pd.ownsHeapBuffer()) pd.releaseHeapBufferOwnership(); + dataSize_ += pd.getSize(); } } //------------------------------------------------------------------------------ @@ -268,6 +276,7 @@ void Batch::initialize() assert(!parameters_.empty()); valueTypeInfos_.resize(parameters_.size()); paramDataOffsets_.resize(parameters_.size()); + dataSize_ = 0; rowLength_ = 0; for (size_t i = 0; i < parameters_.size(); ++i) { diff --git a/src/odbc/internal/Batch.h b/src/odbc/internal/Batch.h index 772a558..783b309 100644 --- a/src/odbc/internal/Batch.h +++ b/src/odbc/internal/Batch.h @@ -78,6 +78,13 @@ class Batch : public RefCounted */ void execute(void* hstmt); + /** + * Retrieves the number of bytes required by the batch. + * + * @return Returns the number of bytes required by the batch. + */ + std::size_t getDataSize() const; + private: void writeParameter(char* dest, ParameterData& pd); void writeVariableSizeParameter(char* dest, ParameterData& pd); @@ -208,6 +215,9 @@ class Batch : public RefCounted /// The number of rows in the last block (in batchBlocks_.back()). std::size_t blockRow_; + + /// The number of bytes required for the batch. + std::size_t dataSize_; }; //------------------------------------------------------------------------------ } // namespace odbc From e2c1d9df7993cf1f5cd164f19f399e76e59a833a Mon Sep 17 00:00:00 2001 From: Maxim Rylov Date: Thu, 11 Mar 2021 08:19:47 +0100 Subject: [PATCH 3/8] Expose SQLSpecialColumns via DatabaseMetaData::getSpecialColumns --- src/odbc/DatabaseMetaData.cpp | 69 ++++++++++++++++++++++++++++ src/odbc/DatabaseMetaData.h | 37 ++++++++++++++- src/odbc/DatabaseMetaDataUnicode.cpp | 69 ++++++++++++++++++++++++++++ src/odbc/DatabaseMetaDataUnicode.h | 35 ++++++++++++++ src/odbc/Types.h | 59 ++++++++++++++++++++++++ 5 files changed, 268 insertions(+), 1 deletion(-) diff --git a/src/odbc/DatabaseMetaData.cpp b/src/odbc/DatabaseMetaData.cpp index 2ef2475..e54ad9e 100644 --- a/src/odbc/DatabaseMetaData.cpp +++ b/src/odbc/DatabaseMetaData.cpp @@ -96,6 +96,75 @@ ResultSetRef DatabaseMetaData::getPrimaryKeys(const char* catalogName, return ret; } //------------------------------------------------------------------------------ +ResultSetRef DatabaseMetaData::getSpecialColumns( + RowIdentifierType identifierType, + const char* catalogName, const char* schemaName, const char* tableName, + RowIdentifierScope scope, ColumnNullableValue nullable) +{ + SQLUSMALLINT fColType; + switch (identifierType) + { + case RowIdentifierType::BEST_ROWID: + fColType = SQL_BEST_ROWID; + break; + case RowIdentifierType::ROWVER: + fColType = SQL_ROWVER; + break; + default: + throw Exception("Unknown rowid type"); + } + + size_t catalogLen = catalogName ? strlen(catalogName) : 0; + size_t schemaLen = schemaName ? strlen(schemaName) : 0; + size_t tableLen = tableName ? strlen(tableName) : 0; + + size_t maxLen = (1 << 8 * sizeof(SQLSMALLINT)) - 1; + if (catalogLen > maxLen) + throw Exception("The catalog name is too long"); + if (schemaLen > maxLen) + throw Exception("The schema name is too long"); + if (tableLen > maxLen) + throw Exception("The table name is too long"); + + SQLUSMALLINT fScope; + switch (scope) + { + case RowIdentifierScope::CURRENT_ROW: + fScope = SQL_SCOPE_CURROW; + break; + case RowIdentifierScope::TRANSACTION: + fScope = SQL_SCOPE_TRANSACTION; + break; + case RowIdentifierScope::SESSION: + fScope = SQL_SCOPE_SESSION; + break; + default: + throw Exception("Unknown rowid scope"); + } + + SQLUSMALLINT fNullable; + switch (nullable) + { + case ColumnNullableValue::NO_NULLS: + fNullable = SQL_NO_NULLS; + break; + case ColumnNullableValue::NULLABLE: + fNullable = SQL_NULLABLE; + break; + default: + throw Exception("Unknown nullable value"); + } + + StatementRef stmt = createStatement(); + ResultSetRef ret(new ResultSet(stmt.get())); + EXEC_STMT(SQLSpecialColumnsA, stmt->hstmt_, fColType, + (SQLCHAR*)catalogName, (SQLSMALLINT)catalogLen, + (SQLCHAR*)schemaName, (SQLSMALLINT)schemaLen, + (SQLCHAR*)tableName, (SQLSMALLINT)tableLen, + fScope, fNullable); + return ret; +} +//------------------------------------------------------------------------------ ResultSetRef DatabaseMetaData::getTables(const char* catalogName, const char* schemaName, const char* tableName, const char* tableType) { diff --git a/src/odbc/DatabaseMetaData.h b/src/odbc/DatabaseMetaData.h index baad674..95890e8 100644 --- a/src/odbc/DatabaseMetaData.h +++ b/src/odbc/DatabaseMetaData.h @@ -112,7 +112,7 @@ class ODBC_EXPORT DatabaseMetaData : public DatabaseMetaDataBase * 5. Primary column sequence number in key (1-based) * 6. Primary key name * - * This functions uses the ODBC function SQLPrimaryKeys. Refer to its + * This function uses the ODBC function SQLPrimaryKeys. Refer to its * documentation for further details on the data in the ResultSet object. * * @param catalogName A string indicating the catalog name. @@ -126,6 +126,41 @@ class ODBC_EXPORT DatabaseMetaData : public DatabaseMetaDataBase const char* schemaName, const char* tableName); + /** + * Retrieves information about the unique row identifier of a table. + * + * The list of columns is returned as a ResultSet object, in which each + * returned row has the following columns: + * 1. Actual scope of the rowid + * 2. Column name + * 3. SQL data type + * 4. Data source-dependent data type name + * 5. The size of the column on the data source + * 6. The length in bytes of data transferred + * 7. The decimal digits of the column on the data source + * 8. Indicates whether the column is a pseudo-column + * + * This function uses the ODBC function SQLSpecialColumns. Refer to its + * documentation for further details on the data in the ResultSet object. + * + * @param identifierType Type of unique row identifier to return. + * @param catalogName A string indicating the catalog name. + * @param schemaName A string indicating the schema name. + * @param tableName A string indicating the table name. + * @param scope Minimum required scope of the rowid. + * @param nullable Determines whether to return special columns that + * can have a NULL value. + * @return Returns a ResultSet object containing the + * unique row identifier information. + */ + ResultSetRef getSpecialColumns( + RowIdentifierType identifierType, + const char* catalogName, + const char* schemaName, + const char* tableName, + RowIdentifierScope scope, + ColumnNullableValue nullable); + /** * Retrieves a description of the tables that are available in the connected * database. diff --git a/src/odbc/DatabaseMetaDataUnicode.cpp b/src/odbc/DatabaseMetaDataUnicode.cpp index 5ccdef2..c399346 100644 --- a/src/odbc/DatabaseMetaDataUnicode.cpp +++ b/src/odbc/DatabaseMetaDataUnicode.cpp @@ -108,6 +108,75 @@ ResultSetRef DatabaseMetaDataUnicode::getPrimaryKeys( return ret; } //------------------------------------------------------------------------------ +ResultSetRef DatabaseMetaDataUnicode::getSpecialColumns( + RowIdentifierType identifierType, const char16_t* catalogName, + const char16_t* schemaName, const char16_t* tableName, + RowIdentifierScope scope, ColumnNullableValue nullable) +{ + SQLUSMALLINT fColType; + switch (identifierType) + { + case RowIdentifierType::BEST_ROWID: + fColType = SQL_BEST_ROWID; + break; + case RowIdentifierType::ROWVER: + fColType = SQL_ROWVER; + break; + default: + throw Exception("Unknown rowid type"); + } + + size_t catalogLen = catalogName ? strlen16(catalogName) : 0; + size_t schemaLen = schemaName ? strlen16(schemaName) : 0; + size_t tableLen = tableName ? strlen16(tableName) : 0; + + size_t maxLen = (1 << 8 * sizeof(SQLSMALLINT)) - 1; + if (catalogLen > maxLen) + throw Exception("The catalog name is too long"); + if (schemaLen > maxLen) + throw Exception("The schema name is too long"); + if (tableLen > maxLen) + throw Exception("The table name is too long"); + + SQLUSMALLINT fScope; + switch (scope) + { + case RowIdentifierScope::CURRENT_ROW: + fScope = SQL_SCOPE_CURROW; + break; + case RowIdentifierScope::TRANSACTION: + fScope = SQL_SCOPE_TRANSACTION; + break; + case RowIdentifierScope::SESSION: + fScope = SQL_SCOPE_SESSION; + break; + default: + throw Exception("Unknown rowid scope"); + } + + SQLUSMALLINT fNullable; + switch (nullable) + { + case ColumnNullableValue::NO_NULLS: + fNullable = SQL_NO_NULLS; + break; + case ColumnNullableValue::NULLABLE: + fNullable = SQL_NULLABLE; + break; + default: + throw Exception("Unknown nullable value"); + } + + StatementRef stmt = createStatement(); + ResultSetRef ret(new ResultSet(stmt.get())); + EXEC_STMT(SQLSpecialColumnsW, stmt->hstmt_, fColType, + (SQLWCHAR*)catalogName, (SQLSMALLINT)catalogLen, + (SQLWCHAR*)schemaName, (SQLSMALLINT)schemaLen, + (SQLWCHAR*)tableName, (SQLSMALLINT)tableLen, + fScope, fNullable); + return ret; +} +//------------------------------------------------------------------------------ ResultSetRef DatabaseMetaDataUnicode::getTables(const char16_t* catalogName, const char16_t* schemaName, const char16_t* tableName, const char16_t* tableType) diff --git a/src/odbc/DatabaseMetaDataUnicode.h b/src/odbc/DatabaseMetaDataUnicode.h index dadcbf8..519e998 100644 --- a/src/odbc/DatabaseMetaDataUnicode.h +++ b/src/odbc/DatabaseMetaDataUnicode.h @@ -126,6 +126,41 @@ class ODBC_EXPORT DatabaseMetaDataUnicode : public DatabaseMetaDataBase const char16_t* schemaName, const char16_t* tableName); + /** + * Retrieves information about the unique row identifier of a table. + * + * The list of columns is returned as a ResultSet object, in which each + * returned row has the following columns: + * 1. Actual scope of the rowid + * 2. Column name + * 3. SQL data type + * 4. Data source-dependent data type name + * 5. The size of the column on the data source + * 6. The length in bytes of data transferred + * 7. The decimal digits of the column on the data source + * 8. Indicates whether the column is a pseudo-column + * + * This function uses the ODBC function SQLSpecialColumns. Refer to its + * documentation for further details on the data in the ResultSet object. + * + * @param identifierType Type of unique row identifier to return. + * @param catalogName A string indicating the catalog name. + * @param schemaName A string indicating the schema name. + * @param tableName A string indicating the table name. + * @param scope Minimum required scope of the rowid. + * @param nullable Determines whether to return special columns that + * can have a NULL value. + * @return Returns a ResultSet object containing the + * unique row identifier information. + */ + ResultSetRef getSpecialColumns( + RowIdentifierType identifierType, + const char16_t* catalogName, + const char16_t* schemaName, + const char16_t* tableName, + RowIdentifierScope scope, + ColumnNullableValue nullable); + /** * Retrieves a description of the tables that are available in the connected * database. diff --git a/src/odbc/Types.h b/src/odbc/Types.h index 7b9f4c3..29ba21e 100644 --- a/src/odbc/Types.h +++ b/src/odbc/Types.h @@ -28,6 +28,65 @@ enum class DSNType USER }; //------------------------------------------------------------------------------ +/** + * Specifies the constants that identify whether the column allows NULL values. + */ +enum class ColumnNullableValue +{ + /** + * Column does not allow NULL values. + */ + NO_NULLS, + /** + * Column allows NULL values. + */ + NULLABLE +}; +//------------------------------------------------------------------------------ +/** + * Specifies the type of unique row identifier. + */ +enum class RowIdentifierType +{ + /** + * Returns the optimal column or set of columns that, by retrieving values + * from the column or columns, allows any row in the specified table to be + * uniquely identified. A column can be either a pseudo - column + * specifically designed for this purpose (as in Oracle ROWID or Ingres TID) + * or the column or columns of any unique index for the table. + */ + BEST_ROWID, + /** + * Returns the column or columns in the specified table, if any, that are + * automatically updated by the data source when any value in the row is + * updated by any transaction (as in SQLBase ROWID or Sybase TIMESTAMP). + */ + ROWVER +}; +//------------------------------------------------------------------------------ +/** + * Specifies the required scope of the row identifier (rowid). + */ +enum class RowIdentifierScope +{ + /** + * The rowid is guaranteed to be valid only while positioned on that row. + * A later reselect using rowid may not return a row if the row was updated + * or deleted by another transaction. + */ + CURRENT_ROW, + /** + * The rowid is guaranteed to be valid for the duration of the session + * (across transaction boundaries). + */ + SESSION, + /** + * The rowid is guaranteed to be valid for the duration of the current + * transaction. + */ + TRANSACTION +}; +//------------------------------------------------------------------------------ /** * Specifies the constants that identify ODBC SQL data types. */ From c304330a6793eefbea7d661a528a34ebd90bcd5a Mon Sep 17 00:00:00 2001 From: Maxim Rylov Date: Fri, 12 Mar 2021 06:53:11 +0100 Subject: [PATCH 4/8] Expose SQLStatistics via DatabaseMetaData::getStatistics --- src/odbc/DatabaseMetaData.cpp | 52 ++++++++++++++++++++++++++++ src/odbc/DatabaseMetaData.h | 39 +++++++++++++++++++++ src/odbc/DatabaseMetaDataUnicode.cpp | 52 ++++++++++++++++++++++++++++ src/odbc/DatabaseMetaDataUnicode.h | 39 +++++++++++++++++++++ src/odbc/Types.h | 32 +++++++++++++++++ 5 files changed, 214 insertions(+) diff --git a/src/odbc/DatabaseMetaData.cpp b/src/odbc/DatabaseMetaData.cpp index e54ad9e..de26024 100644 --- a/src/odbc/DatabaseMetaData.cpp +++ b/src/odbc/DatabaseMetaData.cpp @@ -165,6 +165,58 @@ ResultSetRef DatabaseMetaData::getSpecialColumns( return ret; } //------------------------------------------------------------------------------ +ResultSetRef DatabaseMetaData::getStatistics( + const char* catalogName, const char* schemaName, const char* tableName, + IndexType indexType, StatisticsAccuracy accuracy) +{ + size_t catalogLen = catalogName ? strlen(catalogName) : 0; + size_t schemaLen = schemaName ? strlen(schemaName) : 0; + size_t tableLen = tableName ? strlen(tableName) : 0; + + size_t maxLen = (1 << 8 * sizeof(SQLSMALLINT)) - 1; + if (catalogLen > maxLen) + throw Exception("The catalog name is too long"); + if (schemaLen > maxLen) + throw Exception("The schema name is too long"); + if (tableLen > maxLen) + throw Exception("The table name is too long"); + + SQLUSMALLINT fUnique; + switch (indexType) + { + case IndexType::ALL: + fUnique = SQL_INDEX_ALL; + break; + case IndexType::UNIQUE: + fUnique = SQL_INDEX_UNIQUE; + break; + default: + throw Exception("Unknown index type"); + } + + SQLUSMALLINT fAccuracy; + switch (accuracy) + { + case StatisticsAccuracy::ENSURE: + fAccuracy = SQL_ENSURE; + break; + case StatisticsAccuracy::QUICK: + fAccuracy = SQL_QUICK; + break; + default: + throw Exception("Unknown statistics accuracy"); + } + + StatementRef stmt = createStatement(); + ResultSetRef ret(new ResultSet(stmt.get())); + EXEC_STMT(SQLStatisticsA, stmt->hstmt_, + (SQLCHAR*)catalogName, (SQLSMALLINT)catalogLen, + (SQLCHAR*)schemaName, (SQLSMALLINT)schemaLen, + (SQLCHAR*)tableName, (SQLSMALLINT)tableLen, + fUnique, fAccuracy); + return ret; +} +//------------------------------------------------------------------------------ ResultSetRef DatabaseMetaData::getTables(const char* catalogName, const char* schemaName, const char* tableName, const char* tableType) { diff --git a/src/odbc/DatabaseMetaData.h b/src/odbc/DatabaseMetaData.h index 95890e8..1decc7a 100644 --- a/src/odbc/DatabaseMetaData.h +++ b/src/odbc/DatabaseMetaData.h @@ -161,6 +161,45 @@ class ODBC_EXPORT DatabaseMetaData : public DatabaseMetaDataBase RowIdentifierScope scope, ColumnNullableValue nullable); + /** + * Retrieves the statistics about the specified table and its indexes. + * + * The list of columns is returned as a ResultSet object, in which each + * returned row has the following columns: + * 1. Catalog name of the table + * 2. Schema name of the table + * 3. Table name of the table + * 4. Indicates whether the index does not allow duplicate values + * 5. The identifier that is used to qualify the index name doing a + * DROP INDEX + * 6. Index name + * 7. Type of information being returned + * 8. Column sequence number in index (starting with 1) + * 9. Column name + * 10. Sort sequence for the column: "A" for ascending; "D" for + * descending + * 11. Cardinality of table or index + * 12. Number of pages used to store the index or table + * 13. If the index is a filtered index + * + * This function uses the ODBC function SQLStatistics. Refer to its + * documentation for further details on the data in the ResultSet object. + * + * @param catalogName A string indicating the catalog name. + * @param schemaName A string indicating the schema name. + * @param tableName A string indicating the table name. + * @param indexType Type of index. + * @param accuracy Indicates the accuracy of the returned statistics. + * @return Returns a ResultSet object containing the statistics + * about the specified table and its indexes. + */ + ResultSetRef getStatistics( + const char* catalogName, + const char* schemaName, + const char* tableName, + IndexType indexType, + StatisticsAccuracy accuracy); + /** * Retrieves a description of the tables that are available in the connected * database. diff --git a/src/odbc/DatabaseMetaDataUnicode.cpp b/src/odbc/DatabaseMetaDataUnicode.cpp index c399346..88f60a2 100644 --- a/src/odbc/DatabaseMetaDataUnicode.cpp +++ b/src/odbc/DatabaseMetaDataUnicode.cpp @@ -177,6 +177,58 @@ ResultSetRef DatabaseMetaDataUnicode::getSpecialColumns( return ret; } //------------------------------------------------------------------------------ +ResultSetRef DatabaseMetaDataUnicode::getStatistics(const char16_t* catalogName, + const char16_t* schemaName, const char16_t* tableName, + IndexType indexType, StatisticsAccuracy accuracy) +{ + size_t catalogLen = catalogName ? strlen16(catalogName) : 0; + size_t schemaLen = schemaName ? strlen16(schemaName) : 0; + size_t tableLen = tableName ? strlen16(tableName) : 0; + + size_t maxLen = (1 << 8 * sizeof(SQLSMALLINT)) - 1; + if (catalogLen > maxLen) + throw Exception("The catalog name is too long"); + if (schemaLen > maxLen) + throw Exception("The schema name is too long"); + if (tableLen > maxLen) + throw Exception("The table name is too long"); + + SQLUSMALLINT fUnique; + switch (indexType) + { + case IndexType::ALL: + fUnique = SQL_INDEX_ALL; + break; + case IndexType::UNIQUE: + fUnique = SQL_INDEX_UNIQUE; + break; + default: + throw Exception("Unknown index type"); + } + + SQLUSMALLINT fAccuracy; + switch (accuracy) + { + case StatisticsAccuracy::ENSURE: + fAccuracy = SQL_ENSURE; + break; + case StatisticsAccuracy::QUICK: + fAccuracy = SQL_QUICK; + break; + default: + throw Exception("Unknown statistics accuracy"); + } + + StatementRef stmt = createStatement(); + ResultSetRef ret(new ResultSet(stmt.get())); + EXEC_STMT(SQLStatisticsW, stmt->hstmt_, + (SQLWCHAR*)catalogName, (SQLSMALLINT)catalogLen, + (SQLWCHAR*)schemaName, (SQLSMALLINT)schemaLen, + (SQLWCHAR*)tableName, (SQLSMALLINT)tableLen, + fUnique, fAccuracy); + return ret; +} +//------------------------------------------------------------------------------ ResultSetRef DatabaseMetaDataUnicode::getTables(const char16_t* catalogName, const char16_t* schemaName, const char16_t* tableName, const char16_t* tableType) diff --git a/src/odbc/DatabaseMetaDataUnicode.h b/src/odbc/DatabaseMetaDataUnicode.h index 519e998..35de61a 100644 --- a/src/odbc/DatabaseMetaDataUnicode.h +++ b/src/odbc/DatabaseMetaDataUnicode.h @@ -161,6 +161,45 @@ class ODBC_EXPORT DatabaseMetaDataUnicode : public DatabaseMetaDataBase RowIdentifierScope scope, ColumnNullableValue nullable); + /** + * Retrieves the statistics about the specified table and its indexes. + * + * The list of columns is returned as a ResultSet object, in which each + * returned row has the following columns: + * 1. Catalog name of the table + * 2. Schema name of the table + * 3. Table name of the table + * 4. Indicates whether the index does not allow duplicate values + * 5. The identifier that is used to qualify the index name doing a + * DROP INDEX + * 6. Index name + * 7. Type of information being returned + * 8. Column sequence number in index (starting with 1) + * 9. Column name + * 10. Sort sequence for the column: "A" for ascending; "D" for + * descending + * 11. Cardinality of table or index + * 12. Number of pages used to store the index or table + * 13. If the index is a filtered index + * + * This function uses the ODBC function SQLStatistics. Refer to its + * documentation for further details on the data in the ResultSet object. + * + * @param catalogName A string indicating the catalog name. + * @param schemaName A string indicating the schema name. + * @param tableName A string indicating the table name. + * @param indexType Type of index. + * @param accuracy Indicates the type of the returned statistics. + * @return Returns a ResultSet object containing the statistics + * about the specified table and its indexes. + */ + ResultSetRef getStatistics( + const char16_t* catalogName, + const char16_t* schemaName, + const char16_t* tableName, + IndexType indexType, + StatisticsAccuracy accuracy); + /** * Retrieves a description of the tables that are available in the connected * database. diff --git a/src/odbc/Types.h b/src/odbc/Types.h index 29ba21e..d1d9465 100644 --- a/src/odbc/Types.h +++ b/src/odbc/Types.h @@ -28,6 +28,38 @@ enum class DSNType USER }; //------------------------------------------------------------------------------ +/** + * Specifies the type of the index. + */ +enum class IndexType +{ + /** + * All indexes are returned. + */ + ALL, + /** + * Only unique indexes are returned. + */ + UNIQUE +}; +//------------------------------------------------------------------------------ +/** + * Specifies the accuracy of the statistics about a single table and + * its indexes. + */ +enum class StatisticsAccuracy +{ + /** + * Requests that the driver unconditionally retrieves the statistics. + */ + ENSURE, + /** + * Requests that the driver retrieves the CARDINALITY and PAGES only if they + * are readily available from the server. + */ + QUICK +}; +//------------------------------------------------------------------------------ /** * Specifies the constants that identify whether the column allows NULL values. */ From 395ec8330033a1156b05004d445825b9bfbf9c43 Mon Sep 17 00:00:00 2001 From: Maxim Rylov Date: Thu, 25 Mar 2021 12:32:52 +0100 Subject: [PATCH 5/8] Add getBaseColumnName and getBaseTableName functions to ResultSetMetaData --- src/odbc/ResultSetMetaData.cpp | 10 ++++++++++ src/odbc/ResultSetMetaData.h | 16 ++++++++++++++++ src/odbc/ResultSetMetaDataUnicode.cpp | 12 ++++++++++++ src/odbc/ResultSetMetaDataUnicode.h | 16 ++++++++++++++++ 4 files changed, 54 insertions(+) diff --git a/src/odbc/ResultSetMetaData.cpp b/src/odbc/ResultSetMetaData.cpp index 31dca44..eb541c7 100644 --- a/src/odbc/ResultSetMetaData.cpp +++ b/src/odbc/ResultSetMetaData.cpp @@ -29,6 +29,16 @@ string ResultSetMetaData::getTableName(unsigned short columnIndex) return getStringColAttribute(columnIndex, SQL_DESC_TABLE_NAME); } //------------------------------------------------------------------------------ +string ResultSetMetaData::getBaseTableName(unsigned short columnIndex) +{ + return getStringColAttribute(columnIndex, SQL_DESC_BASE_TABLE_NAME); +} +//------------------------------------------------------------------------------ +string ResultSetMetaData::getBaseColumnName(unsigned short columnIndex) +{ + return getStringColAttribute(columnIndex, SQL_DESC_BASE_COLUMN_NAME); +} +//------------------------------------------------------------------------------ string ResultSetMetaData::getColumnLabel(unsigned short columnIndex) { return getStringColAttribute(columnIndex, SQL_DESC_LABEL); diff --git a/src/odbc/ResultSetMetaData.h b/src/odbc/ResultSetMetaData.h index 7d010ed..7b524f3 100644 --- a/src/odbc/ResultSetMetaData.h +++ b/src/odbc/ResultSetMetaData.h @@ -44,6 +44,22 @@ class ODBC_EXPORT ResultSetMetaData : public ResultSetMetaDataBase */ std::string getTableName(unsigned short columnIndex); + /** + * Returns the name of the base table that contains the column. + * + * @param columnIndex The column index starting from 1. + * @return Returns the base table name. + */ + std::string getBaseTableName(unsigned short columnIndex); + + /** + * Returns the base column name for the result set column. + * + * @param columnIndex The column index starting from 1. + * @return Returns the base column name. + */ + std::string getBaseColumnName(unsigned short columnIndex); + /** * Returns a column's label. * diff --git a/src/odbc/ResultSetMetaDataUnicode.cpp b/src/odbc/ResultSetMetaDataUnicode.cpp index b4397ff..b160489 100644 --- a/src/odbc/ResultSetMetaDataUnicode.cpp +++ b/src/odbc/ResultSetMetaDataUnicode.cpp @@ -29,6 +29,18 @@ u16string ResultSetMetaDataUnicode::getTableName(unsigned short columnIndex) return getStringColAttribute(columnIndex, SQL_DESC_TABLE_NAME); } //------------------------------------------------------------------------------ +u16string ResultSetMetaDataUnicode::getBaseTableName( + unsigned short columnIndex) +{ + return getStringColAttribute(columnIndex, SQL_DESC_BASE_TABLE_NAME); +} +//------------------------------------------------------------------------------ +u16string ResultSetMetaDataUnicode::getBaseColumnName( + unsigned short columnIndex) +{ + return getStringColAttribute(columnIndex, SQL_DESC_BASE_COLUMN_NAME); +} +//------------------------------------------------------------------------------ u16string ResultSetMetaDataUnicode::getColumnLabel(unsigned short columnIndex) { return getStringColAttribute(columnIndex, SQL_DESC_LABEL); diff --git a/src/odbc/ResultSetMetaDataUnicode.h b/src/odbc/ResultSetMetaDataUnicode.h index da1dbb6..49b1ef3 100644 --- a/src/odbc/ResultSetMetaDataUnicode.h +++ b/src/odbc/ResultSetMetaDataUnicode.h @@ -44,6 +44,22 @@ class ODBC_EXPORT ResultSetMetaDataUnicode : public ResultSetMetaDataBase */ std::u16string getTableName(unsigned short columnIndex); + /** + * Returns the name of the base table that contains the column. + * + * @param columnIndex The column index starting from 1. + * @return Returns the base table name. + */ + std::u16string getBaseTableName(unsigned short columnIndex); + + /** + * Returns the base column name for the result set column. + * + * @param columnIndex The column index starting from 1. + * @return Returns the base column name. + */ + std::u16string getBaseColumnName(unsigned short columnIndex); + /** * Returns a column's label. * From 963a1fc1e11b42be0b3c3262c17705479a127886 Mon Sep 17 00:00:00 2001 From: Sebastian Wolf Date: Thu, 19 Aug 2021 16:18:27 +0200 Subject: [PATCH 6/8] chore: Integrate REUSE tool --- .reuse/dep5 | 29 ++++++++++++++++ LICENSES/Apache-2.0.txt | 73 +++++++++++++++++++++++++++++++++++++++++ NOTICE | 1 - README.md | 6 ++-- 4 files changed, 105 insertions(+), 4 deletions(-) create mode 100755 .reuse/dep5 create mode 100644 LICENSES/Apache-2.0.txt delete mode 100644 NOTICE diff --git a/.reuse/dep5 b/.reuse/dep5 new file mode 100755 index 0000000..1f2ffcc --- /dev/null +++ b/.reuse/dep5 @@ -0,0 +1,29 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: odbc-cpp-wrapper +Upstream-Contact: Stefan Uhrig +Source: https://github.com/SAP/odbc-cpp-wrapper +Disclaimer: The code in this project may include calls to APIs (“API Calls”) of + SAP or third-party products or services developed outside of this project + (“External Products”). + “APIs” means application programming interfaces, as well as their respective + specifications and implementing code that allows software to communicate with + other software. + API Calls to External Products are not licensed under the open source license + that governs this project. The use of such API Calls and related External + Products are subject to applicable additional agreements with the relevant + provider of the External Products. In no event shall the open source license + that governs this project grant any rights in or to any External Products,or + alter, expand or supersede any terms of the applicable additional agreements. + If you have a valid license agreement with SAP for the use of a particular SAP + External Product, then you may make use of any API Calls included in this + project’s code for that SAP External Product, subject to the terms of such + license agreement. If you do not have a valid license agreement for the use of + a particular SAP External Product, then you may only make use of any API Calls + in this project for that SAP External Product for your internal, non-productive + and non-commercial test and evaluation of such API Calls. Nothing herein grants + you any rights to use or access any SAP External Product, or provide any third + parties the right to use of access any SAP External Product, through API Calls. + +Files: * +Copyright: 2019-2021 SAP SE or an SAP affiliate company and odbc-cpp-wrapper contributors +License: Apache-2.0 \ No newline at end of file diff --git a/LICENSES/Apache-2.0.txt b/LICENSES/Apache-2.0.txt new file mode 100644 index 0000000..137069b --- /dev/null +++ b/LICENSES/Apache-2.0.txt @@ -0,0 +1,73 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/NOTICE b/NOTICE deleted file mode 100644 index 21661b4..0000000 --- a/NOTICE +++ /dev/null @@ -1 +0,0 @@ -Copyright (c) 2019 SAP SE or an SAP affiliate company. All rights reserved. \ No newline at end of file diff --git a/README.md b/README.md index 39836da..9c5f885 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # C++ Wrapper for ODBC +[![REUSE status](https://api.reuse.software/badge/github.com/SAP/odbc-cpp-wrapper)](https://api.reuse.software/info/github.com/SAP/odbc-cpp-wrapper) + odbc-cpp-wrapper is an object-oriented C++-wrapper of the ODBC API. It takes care of - managing the lifetime of ODBC resources, @@ -186,6 +188,4 @@ If you experience issues with using the library, please file a report in the Git ## License -Copyright (c) 2019 SAP SE or an SAP affiliate company. All rights reserved. - -This file is licensed under the Apache Software License 2.0 except as noted otherwise in the [LICENSE](LICENSE) file. +Copyright 2019-2021 SAP SE or an SAP affiliate company and odbc-cpp-wrapper contributors. Please see our [LICENSE](LICENSE) for copyright and license information. Detailed information including third-party components and their licensing/copyright information is available [via the REUSE tool](https://api.reuse.software/info/github.com/SAP/odbc-cpp-wrapper). From 046ad1adf021902608b6a2fa5787da40b95bcec0 Mon Sep 17 00:00:00 2001 From: Sebastian Wolf Date: Thu, 19 Aug 2021 17:45:40 +0200 Subject: [PATCH 7/8] Integrate the GPLv2 exception in the REUSE/licensing info --- LICENSES/Apache-2.0.txt | 11 +++++++++++ README.md | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/LICENSES/Apache-2.0.txt b/LICENSES/Apache-2.0.txt index 137069b..bce0ca2 100644 --- a/LICENSES/Apache-2.0.txt +++ b/LICENSES/Apache-2.0.txt @@ -71,3 +71,14 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +--- Exceptions to the Apache 2.0 License --- + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision +(Section 3), the indemnity provision (Section 9) or other Section of the +License conflicts with the conditions of the GPLv2, you may retroactively +and prospectively choose to deem waived or otherwise exclude such Section(s) +of the License, but only in their entirety and only with respect to the +Combined Software. \ No newline at end of file diff --git a/README.md b/README.md index 9c5f885..0c38af7 100644 --- a/README.md +++ b/README.md @@ -188,4 +188,4 @@ If you experience issues with using the library, please file a report in the Git ## License -Copyright 2019-2021 SAP SE or an SAP affiliate company and odbc-cpp-wrapper contributors. Please see our [LICENSE](LICENSE) for copyright and license information. Detailed information including third-party components and their licensing/copyright information is available [via the REUSE tool](https://api.reuse.software/info/github.com/SAP/odbc-cpp-wrapper). +Copyright 2019-2021 SAP SE or an SAP affiliate company and odbc-cpp-wrapper contributors. Please see our [LICENSE](LICENSE) for copyright and license information. Please note the GPLv2 Combination Exception for the Apache 2 License! Detailed information including third-party components and their licensing/copyright information is available [via the REUSE tool](https://api.reuse.software/info/github.com/SAP/odbc-cpp-wrapper). From c822bc036196aa1819ccf69a88556382eeae925f Mon Sep 17 00:00:00 2001 From: Maxim Rylov Date: Wed, 27 Oct 2021 16:59:28 +0200 Subject: [PATCH 8/8] Add SQLDataTypes::Unknown type --- src/odbc/Types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/odbc/Types.h b/src/odbc/Types.h index d1d9465..1eb852b 100644 --- a/src/odbc/Types.h +++ b/src/odbc/Types.h @@ -175,6 +175,8 @@ class SQLDataTypes static constexpr int TypeTime = 92; /// Year, month, day, hour, minute, and second fields. static constexpr int TypeTimestamp = 93; + /// Unknown data type. + static constexpr int Unknown = 0; /// Variable length binary data. static constexpr int VarBinary = -3; /// Variable-length character string.