/* * 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.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.