Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion OdbcDesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,22 @@ SQLRETURN OdbcDesc::sqlGetDescField(int recNumber, int fieldId, SQLPOINTER ptr,
DescRecord *record = NULL;

if ( bDefined == false )
return sqlReturn (SQL_ERROR, "HY091", "Invalid descriptor field identifier");
{
switch (fieldId)
{
case SQL_DESC_ALLOC_TYPE:
case SQL_DESC_ARRAY_SIZE:
case SQL_DESC_ARRAY_STATUS_PTR:
case SQL_DESC_BIND_OFFSET_PTR:
case SQL_DESC_BIND_TYPE:
case SQL_DESC_ROWS_PROCESSED_PTR:
break; // header fields do not depend on the result set
default:
if ( headType == odtImplementationRow )
return sqlReturn (SQL_ERROR, "HY007", "Associated statement is not prepared");
return sqlReturn (SQL_ERROR, "HY091", "Invalid descriptor field identifier");
}
}

if ( recNumber > headCount )
return sqlReturn (SQL_NO_DATA_FOUND, "HY021", "Inconsistent descriptor information");
Expand Down
10 changes: 10 additions & 0 deletions OdbcStatement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ OdbcStatement::OdbcStatement(OdbcConnection *connect, int statementNumber)
statement = connection->connection->createInternalStatement();
bulkInsert = NULL;
execute = &OdbcStatement::executeStatement;
keysetSize = 0;
fetchNext = &ResultSet::nextFetch;
schemaFetchData = true;
metaData = NULL;
Expand Down Expand Up @@ -2577,6 +2578,11 @@ SQLRETURN OdbcStatement::sqlGetStmtAttr(int attribute, SQLPOINTER ptr, int buffe
TRACE02(SQL_ROWSET_SIZE,value);
break;

case SQL_ATTR_KEYSET_SIZE:
value = keysetSize;
TRACE02(SQL_ATTR_KEYSET_SIZE,value);
break;

case SQL_ATTR_MAX_ROWS: // SQL_MAX_ROWS 1
value = maxRows;
TRACE02(SQL_ATTR_MAX_ROWS,value);
Expand Down Expand Up @@ -3434,6 +3440,10 @@ SQLRETURN OdbcStatement::sqlSetStmtAttr(int attribute, SQLPOINTER ptr, int lengt
break;

case SQL_ATTR_KEYSET_SIZE: // 8
keysetSize = (uintptr_t) ptr;
TRACE02(SQL_ATTR_KEYSET_SIZE,(intptr_t) ptr);
break;

case SQL_ROWSET_SIZE: // 9
applicationRowDescriptor->headArraySize = (intptr_t) ptr;
TRACE02(SQL_ROWSET_SIZE,(intptr_t) ptr);
Expand Down
1 change: 1 addition & 0 deletions OdbcStatement.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ class OdbcStatement : public OdbcObject
bool asyncEnable;
int rowNumber;
int rowNumberParamArray;
SQLULEN keysetSize;
int lastRowsetSize;
SQLLEN indicatorRowNumber;
int maxRows;
Expand Down
56 changes: 56 additions & 0 deletions tests/test_descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,3 +366,59 @@ TEST_F(CopyDescCrashTest, SetDescCountToZeroUnbindsAll) {

SQLFreeHandle(SQL_HANDLE_DESC, hDesc);
}

// ===== IRD before SQLPrepare (#307) =====
TEST_F(DescriptorTest, IrdHeaderFieldsReadableBeforePrepare) {
SQLHDESC hIrd = SQL_NULL_HDESC;
ASSERT_TRUE(SQL_SUCCEEDED(SQLGetStmtAttr(hStmt, SQL_ATTR_IMP_ROW_DESC, &hIrd, 0, NULL)));
ASSERT_NE(hIrd, (SQLHDESC)SQL_NULL_HDESC);

SQLULEN rowsFetched = 0;
SQLUSMALLINT rowStatus[4] = {};
ASSERT_TRUE(SQL_SUCCEEDED(SQLSetStmtAttr(hStmt, SQL_ATTR_ROWS_FETCHED_PTR, &rowsFetched, 0)));
ASSERT_TRUE(SQL_SUCCEEDED(SQLSetStmtAttr(hStmt, SQL_ATTR_ROW_STATUS_PTR, rowStatus, 0)));

SQLPOINTER ptr = NULL;
SQLRETURN ret = SQLGetDescField(hIrd, 0, SQL_DESC_ROWS_PROCESSED_PTR, &ptr, 0, NULL);
if (ret == SQL_ERROR && GetSqlState(SQL_HANDLE_DESC, hIrd) == "HY007") {
// unixODBC answers HY007 for an unprepared IRD before the driver sees the call
GTEST_SKIP() << "the driver manager enforces HY007 itself: " << GetOdbcError(SQL_HANDLE_DESC, hIrd);
}
ASSERT_TRUE(SQL_SUCCEEDED(ret)) << GetOdbcError(SQL_HANDLE_DESC, hIrd);
EXPECT_EQ(ptr, (SQLPOINTER)&rowsFetched);

ptr = NULL;
ret = SQLGetDescField(hIrd, 0, SQL_DESC_ARRAY_STATUS_PTR, &ptr, 0, NULL);
ASSERT_TRUE(SQL_SUCCEEDED(ret)) << GetOdbcError(SQL_HANDLE_DESC, hIrd);
EXPECT_EQ(ptr, (SQLPOINTER)rowStatus);

SQLSMALLINT allocType = 0;
ret = SQLGetDescField(hIrd, 0, SQL_DESC_ALLOC_TYPE, &allocType, 0, NULL);
ASSERT_TRUE(SQL_SUCCEEDED(ret)) << GetOdbcError(SQL_HANDLE_DESC, hIrd);
EXPECT_EQ(allocType, SQL_DESC_ALLOC_AUTO);
}

TEST_F(DescriptorTest, IrdRecordFieldsBeforePrepareAreHY007) {
SQLHDESC hIrd = SQL_NULL_HDESC;
ASSERT_TRUE(SQL_SUCCEEDED(SQLGetStmtAttr(hStmt, SQL_ATTR_IMP_ROW_DESC, &hIrd, 0, NULL)));
ASSERT_NE(hIrd, (SQLHDESC)SQL_NULL_HDESC);

SQLSMALLINT count = -1;
SQLRETURN ret = SQLGetDescField(hIrd, 0, SQL_DESC_COUNT, &count, 0, NULL);
EXPECT_EQ(ret, SQL_ERROR);
EXPECT_EQ(GetSqlState(SQL_HANDLE_DESC, hIrd), "HY007");

SQLSMALLINT type = 0;
ret = SQLGetDescField(hIrd, 1, SQL_DESC_TYPE, &type, 0, NULL);
EXPECT_EQ(ret, SQL_ERROR);
EXPECT_EQ(GetSqlState(SQL_HANDLE_DESC, hIrd), "HY007");

// Both answer once the statement is prepared
ret = SQLPrepare(hStmt, (SQLCHAR*)"SELECT 1 AS A FROM RDB$DATABASE", SQL_NTS);
ASSERT_TRUE(SQL_SUCCEEDED(ret)) << GetOdbcError(SQL_HANDLE_STMT, hStmt);
ret = SQLGetDescField(hIrd, 0, SQL_DESC_COUNT, &count, 0, NULL);
ASSERT_TRUE(SQL_SUCCEEDED(ret)) << GetOdbcError(SQL_HANDLE_DESC, hIrd);
EXPECT_EQ(count, 1);
ret = SQLGetDescField(hIrd, 1, SQL_DESC_TYPE, &type, 0, NULL);
ASSERT_TRUE(SQL_SUCCEEDED(ret)) << GetOdbcError(SQL_HANDLE_DESC, hIrd);
}
25 changes: 25 additions & 0 deletions tests/test_scrollable_cursor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,28 @@ TEST_F(ScrollableCursorTest, RewindAfterEnd) {
ASSERT_TRUE(SQL_SUCCEEDED(ret));
EXPECT_EQ(FetchID(), 1);
}

// ===== SQL_ATTR_KEYSET_SIZE is its own attribute, not the rowset size (#307) =====
TEST_F(ScrollableCursorTest, KeysetSizeDoesNotChangeRowArraySize) {
SQLULEN v = 0;
ASSERT_TRUE(SQL_SUCCEEDED(SQLGetStmtAttr(hStmt, SQL_ATTR_ROW_ARRAY_SIZE, &v, 0, NULL)));
EXPECT_EQ(v, 1u);

ASSERT_TRUE(SQL_SUCCEEDED(SQLSetStmtAttr(hStmt, SQL_ATTR_KEYSET_SIZE, (SQLPOINTER)7, 0)));
v = 0;
ASSERT_TRUE(SQL_SUCCEEDED(SQLGetStmtAttr(hStmt, SQL_ATTR_ROW_ARRAY_SIZE, &v, 0, NULL)));
EXPECT_EQ(v, 1u) << "SQL_ATTR_KEYSET_SIZE must not touch the rowset size";
v = 0;
SQLRETURN ret = SQLGetStmtAttr(hStmt, SQL_ATTR_KEYSET_SIZE, &v, 0, NULL);
ASSERT_TRUE(SQL_SUCCEEDED(ret)) << GetOdbcError(SQL_HANDLE_STMT, hStmt);
EXPECT_EQ(v, 7u);

// The ODBC 2 name of the rowset size still sets it, and leaves the keyset size alone
ASSERT_TRUE(SQL_SUCCEEDED(SQLSetStmtAttr(hStmt, SQL_ROWSET_SIZE, (SQLPOINTER)3, 0)));
v = 0;
ASSERT_TRUE(SQL_SUCCEEDED(SQLGetStmtAttr(hStmt, SQL_ATTR_ROW_ARRAY_SIZE, &v, 0, NULL)));
EXPECT_EQ(v, 3u);
v = 0;
ASSERT_TRUE(SQL_SUCCEEDED(SQLGetStmtAttr(hStmt, SQL_ATTR_KEYSET_SIZE, &v, 0, NULL)));
EXPECT_EQ(v, 7u);
}
Loading