/* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you 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 .
*/ package complex.dbaccess;
/** creates a com.sun.star.sdb.RowSet to use during the test * @param command * the command to use for the RowSet * @param commandType * the command type to use for the RowSet * @param execute * determines whether the RowSet should be executed
*/ privatevoid createRowSet(String command, int commandType, boolean execute) throws com.sun.star.uno.Exception
{
createRowSet(command, commandType, execute, false);
}
/** creates a com.sun.star.sdb.RowSet to use during the test * @param command * the command to use for the RowSet * @param commandType * the command type to use for the RowSet * @param execute * determines whether the RowSet should be executed * @param limitFetchSize * determines whether the fetch size of the RowSet should be limited to MAX_FETCH_ROWS
*/ privatevoid createRowSet(String command, int commandType, boolean execute, boolean limitFetchSize) throws com.sun.star.uno.Exception
{
m_rowSet = UnoRuntime.queryInterface( XRowSet.class, getMSF().createInstance( "com.sun.star.sdb.RowSet" ) ); final XPropertySet rowSetProperties = UnoRuntime.queryInterface( XPropertySet.class, m_rowSet );
rowSetProperties.setPropertyValue("Command", command);
rowSetProperties.setPropertyValue("CommandType", Integer.valueOf(commandType));
rowSetProperties.setPropertyValue("ActiveConnection", m_database.defaultConnection().getXConnection()); if (limitFetchSize)
{
rowSetProperties.setPropertyValue("FetchSize", Integer.valueOf(MAX_FETCH_ROWS));
}
final Connection connection = m_database.defaultConnection(); final XPreparedStatement prep = connection.prepareStatement("INSERT INTO \"TEST1\" values (?,?)"); final XParameters para = UnoRuntime.queryInterface( XParameters.class, prep ); for (int i = 1; i <= MAX_TABLE_ROWS; ++i)
{
para.setInt(1, i);
para.setString(2, "Test" + i);
prep.executeUpdate();
}
connection.refreshTables();
}
void testPosition(XResultSet resultSet, XRow row, int expectedValue, String location) throws SQLException
{ finalint val = row.getInt(1); finalint pos = resultSet.getRow();
assertTrue(location + ": value/position do not match: " + pos + " (pos) != " + val + " (val)", val == pos);
assertTrue(location + ": value/position are not as expected: " + val + " (val) != " + expectedValue + " (expected)", val == expectedValue);
}
void testSequentialPositining(XResultSet _resultSet, XRow _row) throws com.sun.star.uno.Exception
{ // 1st test int i = 1; while (_resultSet.next())
{
testPosition(_resultSet, _row, i, "testSequentialPositining");
++i;
}
}
System.out.println("testing events for " + _method.getName()); finalint calling[] = _evt.getCalling(); int pos = 1;
assertTrue("Callings are not in the correct order for APPROVE_CURSOR_MOVE ",
(!_must[RowSetEventListener.APPROVE_CURSOR_MOVE] || calling[RowSetEventListener.APPROVE_CURSOR_MOVE] == -1) || calling[RowSetEventListener.APPROVE_CURSOR_MOVE] == pos++);
assertTrue("Callings are not in the correct order for APPROVE_ROW_CHANGE",
(!_must[RowSetEventListener.APPROVE_ROW_CHANGE] || calling[RowSetEventListener.APPROVE_ROW_CHANGE] == -1) || calling[RowSetEventListener.APPROVE_ROW_CHANGE] == pos++);
assertTrue("Callings are not in the correct order for COLUMN_VALUE",
(!_must[RowSetEventListener.COLUMN_VALUE] || calling[RowSetEventListener.COLUMN_VALUE] == -1) || calling[RowSetEventListener.COLUMN_VALUE] == pos++);
assertTrue("Callings are not in the correct order for CURSOR_MOVED",
(!_must[RowSetEventListener.CURSOR_MOVED] || calling[RowSetEventListener.CURSOR_MOVED] == -1) || calling[RowSetEventListener.CURSOR_MOVED] == pos++);
assertTrue("Callings are not in the correct order for ROW_CHANGED",
(!_must[RowSetEventListener.ROW_CHANGED] || calling[RowSetEventListener.ROW_CHANGED] == -1) || calling[RowSetEventListener.ROW_CHANGED] == pos++);
assertTrue("Callings are not in the correct order for IS_MODIFIED",
(!_must[RowSetEventListener.IS_MODIFIED] || calling[RowSetEventListener.IS_MODIFIED] == -1) || calling[RowSetEventListener.IS_MODIFIED] == pos++);
assertTrue("Callings are not in the correct order for IS_NEW",
(!_must[RowSetEventListener.IS_NEW] || calling[RowSetEventListener.IS_NEW] == -1) || calling[RowSetEventListener.IS_NEW] == pos++);
assertTrue("Callings are not in the correct order for ROW_COUNT",
(!_must[RowSetEventListener.ROW_COUNT] || calling[RowSetEventListener.ROW_COUNT] == -1) || calling[RowSetEventListener.ROW_COUNT] == pos++);
assertTrue("Callings are not in the correct order for IS_ROW_COUNT_FINAL",
(!_must[RowSetEventListener.IS_ROW_COUNT_FINAL] || calling[RowSetEventListener.IS_ROW_COUNT_FINAL] == -1) || calling[RowSetEventListener.IS_ROW_COUNT_FINAL] == pos);
_evt.clearCalling();
}
/** returns the current row count of the RowSet
*/ privateint currentRowCount() throws UnknownPropertyException, WrappedTargetException
{ final Integer rowCount = (Integer) m_rowSetProperties.getPropertyValue("RowCount"); return rowCount.intValue();
}
/** positions the row set at an arbitrary position between 2 and (current row count - 1)
*/ privateint positionRandom() throws SQLException, UnknownPropertyException, WrappedTargetException
{ // note: obviously this should subtract 2 but actually subtract 3 // because if we have just deleted the current row then // ORowSetBase::impl_getRowCount() will lie and currentRowCount() // returns 1 more than the actual number of rows and then // positionRandom() followed by deleteRow() deletes *last* row finalint position = (new Random()).nextInt(currentRowCount() - 3) + 2;
assertTrue("sub task failed: could not position to row no. " + (Integer.valueOf(position)).toString(),
m_resultSet.absolute(position)); return m_resultSet.getRow();
}
/** moves the result set to a random record between 2 and (current row count - 1), and deletes this record * * After returning from this method, the row set is still positioned at the deleted record * @return * the number/position of the record which has been deleted
*/ privateint deleteRandom() throws SQLException, UnknownPropertyException, WrappedTargetException
{ // check if the current position and the row count in the result set is changed by a deletion (it should not) finalint positionBefore = positionRandom(); finalint rowCountBefore = currentRowCount();
m_resultSetUpdate.deleteRow();
finalint positionAfter = m_resultSet.getRow(); finalint rowCountAfter = currentRowCount();
assertTrue("position changed during |deleteRow| (it should not)", positionAfter == positionBefore);
assertTrue("row count changed with a |deleteRow| (it should not)", rowCountBefore == rowCountAfter);
assertTrue("RowSet does not report the current row as deleted after |deleteRow|", m_resultSet.rowDeleted());
// ensure that all records are known
m_resultSet.last(); finalint initialRowCount = currentRowCount();
// delete a random row int deletedRow = deleteRandom();
// asking for the bookmark of a deleted row should fail boolean caughtException = false; try
{
m_rowLocate.getBookmark();
} catch (SQLException e)
{
caughtException = true;
}
assertTrue("asking for the bookmark of a deleted row should throw an exception", caughtException);
// isXXX methods should return |false| on a deleted row
assertTrue("one of the isFoo failed after |deleteRow|", !m_resultSet.isBeforeFirst() && !m_resultSet.isAfterLast() && !m_resultSet.isFirst() && !m_resultSet.isLast()); // note that we can assume that isFirst / isLast also return |false|, since deleteRandom did // not position on the first or last record, but inbetween
// check if moving away from this row in either direction yields the expected results
assertTrue("|previous| after |deleteRow| failed", m_resultSet.previous()); finalint positionPrevious = m_resultSet.getRow();
assertTrue("position after |previous| after |deleteRow| is not as expected", positionPrevious == deletedRow - 1);
deletedRow = deleteRandom();
assertTrue("|next| after |deleteRow| failed", m_resultSet.next()); finalint positionAfter = m_resultSet.getRow();
assertTrue("position after |next| after |deleteRow| is not as expected", positionAfter == deletedRow); // since the deleted record "vanishes" as soon as the cursor is moved away from it, the absolute position does // not change with a |next| call here
// check if the deleted rows really vanished after moving away from them
assertTrue("row count did not change as expected after two deletions", initialRowCount - 2 == currentRowCount());
// check if the deleted row vanishes after moving to the insertion row finalint rowCountBefore = currentRowCount(); finalint deletedPos = deleteRandom();
m_resultSetUpdate.moveToInsertRow();
assertTrue("moving to the insertion row immediately after |deleteRow| does not adjust the row count", rowCountBefore == currentRowCount() + 1);
m_resultSetUpdate.moveToCurrentRow();
assertTrue("|moveToCurrentRow| after |deleteRow| + |moveToInsertRow| results in unexpected position",
(m_resultSet.getRow() == deletedPos) && !m_resultSet.rowDeleted());
// the same, but this time with deleting the first row (which is not covered by deleteRandom)
m_resultSet.last();
m_resultSetUpdate.deleteRow();
m_resultSetUpdate.moveToInsertRow();
m_resultSetUpdate.moveToCurrentRow();
assertTrue("|last| + |deleteRow| + |moveToInsertRow| + |moveToCurrentRow| results in wrong state", m_resultSet.isAfterLast());
// check if deleting a deleted row fails as expected
deleteRandom();
caughtException = false; try
{
m_resultSetUpdate.deleteRow();
} catch (SQLException e)
{
caughtException = true;
}
assertTrue("deleting a deleted row succeeded - it shouldn't", caughtException);
// check if deleteRows fails if it contains the bookmark of a previously-deleted row
m_resultSet.first(); final Object firstBookmark = m_rowLocate.getBookmark();
positionRandom(); final Object deleteBookmark = m_rowLocate.getBookmark();
m_resultSetUpdate.deleteRow(); final XDeleteRows multiDelete = UnoRuntime.queryInterface( XDeleteRows.class, m_resultSet ); finalint[] deleteSuccess = multiDelete.deleteRows(new Object[]
{
firstBookmark, deleteBookmark
});
assertTrue("XDeleteRows::deleteRows with the bookmark of an already-deleted row failed",
(deleteSuccess.length == 2) && (deleteSuccess[0] != 0) && (deleteSuccess[1] == 0));
// check if refreshing a deleted row fails as expected
deleteRandom();
caughtException = false; try
{
m_resultSet.refreshRow();
} catch (SQLException e)
{
caughtException = true;
}
assertTrue("refreshing a deleted row succeeded - it shouldn't", caughtException);
// rowUpdated/rowDeleted
deleteRandom();
assertTrue("rowDeleted and/or rowUpdated are wrong on a deleted row", !m_resultSet.rowUpdated() && !m_resultSet.rowInserted());
// updating values in a deleted row should fail
deleteRandom(); final XRowUpdate rowUpdated = UnoRuntime.queryInterface( XRowUpdate.class, m_resultSet );
caughtException = false; try
{
rowUpdated.updateString(2, TEST21);
} catch (SQLException e)
{
caughtException = true;
}
assertTrue("updating values in a deleted row should not succeed", caughtException);
}
/** checks whether deletions on the main RowSet properly interfere (or don't interfere) with the movement * on a clone of the RowSet
*/
@Test publicvoid testCloneMovesPlusDeletions() throws Exception
{
createTestCase(true); // ensure that all records are known
m_resultSet.last();
final XResultSet clone = createClone(); final XRowLocate cloneRowLocate = UnoRuntime.queryInterface( XRowLocate.class, clone );
positionRandom();
// move the clone to the same record as the RowSet, and delete this record
cloneRowLocate.moveToBookmark(m_rowLocate.getBookmark()); finalint clonePosition = clone.getRow();
m_resultSetUpdate.deleteRow();
assertTrue("clone doesn't know that its current row has been deleted via the RowSet", clone.rowDeleted());
assertTrue("clone's position changed somehow during deletion", clonePosition == clone.getRow());
// move the row set away from the deleted record. This should still not touch the state of the clone
m_resultSet.previous();
assertTrue("clone doesn't know (anymore) that its current row has been deleted via the RowSet", clone.rowDeleted());
assertTrue("clone's position changed somehow during deletion and RowSet-movement", clonePosition == clone.getRow());
// move the clone away from the deleted record
clone.next();
assertTrue("clone still assumes that its row is deleted - but we already moved it", !clone.rowDeleted());
// check whether deleting the extremes (first / last) work
m_resultSet.first();
cloneRowLocate.moveToBookmark(m_rowLocate.getBookmark());
m_resultSetUpdate.deleteRow();
clone.previous();
assertTrue("deleting the first record left the clone in a strange state (after |previous|)", clone.isBeforeFirst());
clone.next();
assertTrue("deleting the first record left the clone in a strange state (after |previous| + |next|)", clone.isFirst());
m_resultSet.last();
cloneRowLocate.moveToBookmark(m_rowLocate.getBookmark());
m_resultSetUpdate.deleteRow();
clone.next();
assertTrue("deleting the last record left the clone in a strange state (after |next|)", clone.isAfterLast());
clone.previous();
assertTrue("deleting the first record left the clone in a strange state (after |next| + |previous|)", clone.isLast());
// check whether movements of the clone interfere with movements of the RowSet, if the latter is on a deleted row finalint positionBefore = positionRandom();
m_resultSetUpdate.deleteRow();
assertTrue("|deleteRow|, but no |rowDeleted| (this should have been found much earlier!)", m_resultSet.rowDeleted());
clone.beforeFirst(); while (clone.next()) {}
assertTrue("row set forgot that the current row is deleted", m_resultSet.rowDeleted());
assertTrue("moving to the next record after |deleteRow| and clone moves failed", m_resultSet.next());
assertTrue("wrong position after |deleteRow| and clone movement", !m_resultSet.isAfterLast() && !m_resultSet.isBeforeFirst());
assertTrue("wrong absolute position after |deleteRow| and clone movement", m_resultSet.getRow() == positionBefore);
}
/** checks whether insertions on the main RowSet properly interfere (or don't interfere) with the movement * on a clone of the RowSet
*/
@Test publicvoid testCloneMovesPlusInsertions() throws Exception
{
createTestCase(true); // ensure that all records are known
m_rowSetProperties.setPropertyValue("FetchSize", Integer.valueOf(10));
final XResultSet clone = createClone(); final XRow cloneRow = UnoRuntime.queryInterface( XRow.class, clone );
// first check the basic scenario without the |moveToInsertRow| |moveToCurrentRow|, to ensure that // really those are broken, if at all
m_resultSet.last();
clone.first();
clone.absolute(11);
clone.first();
finalint rowValue1 = m_row.getInt(1); finalint rowPos = m_resultSet.getRow(); finalint rowValue2 = m_row.getInt(1);
assertTrue("repeated query for the same column value delivers different values (" + rowValue1 + " and " + rowValue2 + ") on row: " + rowPos,
rowValue1 == rowValue2);
privatevoid testTableParameters() throws com.sun.star.uno.Exception
{ // for a row set simply based on a table, there should be not parameters at all
createRowSet("products", CommandType.TABLE, false);
verifyParameters(new String[]
{
}, "testTableParameters");
}
privatevoid testParametersAfterNormalExecute() throws com.sun.star.uno.Exception
{
createRowSet("SELECT * FROM \"customers\"", CommandType.COMMAND, true);
m_rowSetProperties.setPropertyValue("Command", "SELECT * FROM \"customers\" WHERE \"City\" = :city"); final XParameters rowsetParams = UnoRuntime.queryInterface( XParameters.class, m_rowSet );
rowsetParams.setString(1, "London");
m_rowSet.execute();
}
privatevoid testParametrizedQuery() throws com.sun.star.uno.Exception
{ // for a row set based on a parametrized query, those parameters should be properly // recognized
m_dataSource.createQuery("products like", "SELECT * FROM \"products\" WHERE \"Name\" LIKE :product_name");
createRowSet("products like", CommandType.QUERY, false);
verifyParameters(new String[]
{ "product_name"
}, "testParametrizedQuery");
}
// let's fill in a parameter value via XParameters, and see whether it is respected by the parameters container final XParameters rowsetParams = UnoRuntime.queryInterface(XParameters.class, m_rowSet);
rowsetParams.setString(1, "Apples");
assertTrue("XParameters and the parameters container do not properly interact", "Apples".equals(firstParamValue));
// let's see whether this also survives an execute of the row set
rowsetParams.setString(1, "Oranges");
m_rowSet.execute();
{ // TODO: the following would not be necessary if the parameters container would *survive* // the execution of the row set. It currently doesn't (though the values it represents do). // It would be nice, but not strictly necessary, if it would.
params = m_paramsSupplier.getParameters();
firstParam = UnoRuntime.queryInterface( XPropertySet.class, params.getByIndex( 0 ) );
}
firstParamValue = firstParam.getPropertyValue("Value");
assertTrue("XParameters and the parameters container do not properly interact, after the row set has been executed", "Oranges".equals(firstParamValue));
}
/** checks the XParametersSupplier functionality of a RowSet
*/
@Test publicvoid testParameters() throws Exception
{
createTestCase(false); // use an own RowSet instance, not the one which is also used for the other cases
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.18Bemerkung:
(vorverarbeitet am 2026-04-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.