summaryrefslogtreecommitdiff
path: root/dbaccess/qa/complex
diff options
context:
space:
mode:
Diffstat (limited to 'dbaccess/qa/complex')
-rw-r--r--dbaccess/qa/complex/dbaccess/ApplicationController.java203
-rw-r--r--dbaccess/qa/complex/dbaccess/CRMBasedTestCase.java86
-rw-r--r--dbaccess/qa/complex/dbaccess/CRMDatabase.java236
-rw-r--r--dbaccess/qa/complex/dbaccess/DataSource.java109
-rw-r--r--dbaccess/qa/complex/dbaccess/DatabaseDocument.java847
-rw-r--r--dbaccess/qa/complex/dbaccess/FileHelper.java46
-rw-r--r--dbaccess/qa/complex/dbaccess/Parser.java160
-rw-r--r--dbaccess/qa/complex/dbaccess/PropertyBag.java296
-rw-r--r--dbaccess/qa/complex/dbaccess/Query.java130
-rw-r--r--dbaccess/qa/complex/dbaccess/QueryInQuery.java194
-rw-r--r--dbaccess/qa/complex/dbaccess/RowSet.java955
-rw-r--r--dbaccess/qa/complex/dbaccess/RowSetEventListener.java116
-rwxr-xr-xdbaccess/qa/complex/dbaccess/SingleSelectQueryComposer.java314
-rw-r--r--dbaccess/qa/complex/dbaccess/TestCase.java149
-rw-r--r--dbaccess/qa/complex/dbaccess/UISettings.java133
-rw-r--r--dbaccess/qa/complex/dbaccess/dbaccess.sce10
-rwxr-xr-xdbaccess/qa/complex/dbaccess/makefile.mk85
17 files changed, 4069 insertions, 0 deletions
diff --git a/dbaccess/qa/complex/dbaccess/ApplicationController.java b/dbaccess/qa/complex/dbaccess/ApplicationController.java
new file mode 100644
index 000000000000..41bf379f7a91
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/ApplicationController.java
@@ -0,0 +1,203 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: ApplicationController.java,v $
+ * $Revision: 1.1.2.1 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package complex.dbaccess;
+
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.container.XNameAccess;
+import com.sun.star.frame.FrameSearchFlag;
+import com.sun.star.frame.XComponentLoader;
+import com.sun.star.frame.XModel;
+import com.sun.star.frame.XStorable;
+import com.sun.star.lang.XComponent;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.sdb.XOfficeDatabaseDocument;
+import com.sun.star.sdb.application.XDatabaseDocumentUI;
+import com.sun.star.sdbcx.XTablesSupplier;
+import com.sun.star.uno.Exception;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+import connectivity.tools.HsqlColumnDescriptor;
+import connectivity.tools.HsqlDatabase;
+import connectivity.tools.HsqlTableDescriptor;
+import helper.URLHelper;
+import java.io.File;
+import java.io.IOException;
+
+/** complex test case for Base's application UI
+ */
+public class ApplicationController extends complexlib.ComplexTestCase
+{
+ private HsqlDatabase m_database;
+ private XOfficeDatabaseDocument m_databaseDocument;
+ private XDatabaseDocumentUI m_documentUI;
+
+ public ApplicationController()
+ {
+ super();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public String[] getTestMethodNames()
+ {
+ return new String[] {
+ "checkSaveAs"
+ };
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public String getTestObjectName()
+ {
+ return getClass().getName();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ protected final XMultiServiceFactory getORB()
+ {
+ return (XMultiServiceFactory)param.getMSF();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ protected final XComponentContext getComponentContext()
+ {
+ XComponentContext context = null;
+ try
+ {
+ XPropertySet orbProps = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, getORB() );
+ context = (XComponentContext)UnoRuntime.queryInterface( XComponentContext.class,
+ orbProps.getPropertyValue( "DefaultContext" ) );
+ }
+ catch ( Exception ex )
+ {
+ failed( "could not retrieve the ComponentContext" );
+ }
+ return context;
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void impl_closeDocument()
+ {
+ if ( m_database != null )
+ {
+ m_database.close();
+ m_database = null;
+ m_databaseDocument = null;
+ m_documentUI = null;
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void impl_switchToDocument( String _documentURL ) throws java.lang.Exception
+ {
+ // close previous database document
+ impl_closeDocument();
+
+ // create/load the new database document
+ m_database = ( _documentURL == null )
+ ? new HsqlDatabase( getORB() )
+ : new HsqlDatabase( getORB(), _documentURL );
+ m_databaseDocument = m_database.getDatabaseDocument();
+
+ // load it into a frame
+ Object object = getORB().createInstance( "com.sun.star.frame.Desktop" );
+ XComponentLoader xComponentLoader = (XComponentLoader)UnoRuntime.queryInterface( XComponentLoader.class, object );
+ XComponent loadedComponent = xComponentLoader.loadComponentFromURL( m_database.getDocumentURL(), "_blank", FrameSearchFlag.ALL, new PropertyValue[0] );
+
+ assure( "too many document instances!",
+ UnoRuntime.areSame( loadedComponent, m_databaseDocument ) );
+
+ // get the controller, which provides access to various UI operations
+ XModel docModel = (XModel)UnoRuntime.queryInterface( XModel.class,
+ loadedComponent );
+ m_documentUI = (XDatabaseDocumentUI)UnoRuntime.queryInterface( XDatabaseDocumentUI.class,
+ docModel.getCurrentController() );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void before() throws Exception, java.lang.Exception
+ {
+ impl_switchToDocument( null );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void after()
+ {
+ impl_closeDocument();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void checkSaveAs() throws Exception, IOException, java.lang.Exception
+ {
+ // issue 93737 describes the problem that when you save-as a database document, and do changes to it,
+ // then those changes are saved in the old document, actually
+ String oldDocumentURL = m_database.getDocumentURL();
+
+ File documentFile = java.io.File.createTempFile( getTestObjectName(), ".odb" );
+ documentFile.deleteOnExit();
+ String newDocumentURL = URLHelper.getFileURLFromSystemPath( documentFile.getAbsoluteFile() );
+
+ // store the doc in a new location
+ XStorable storeDoc = (XStorable)UnoRuntime.queryInterface( XStorable.class,
+ m_databaseDocument );
+ storeDoc.storeAsURL( newDocumentURL, new PropertyValue[] {} );
+
+ // connect
+ m_documentUI.connect();
+ assure( "could not connect to " + m_database.getDocumentURL(), m_documentUI.isConnected() );
+
+ // create a table in the database
+ m_database.createTable( new HsqlTableDescriptor( "abc", new HsqlColumnDescriptor[] {
+ new HsqlColumnDescriptor( "a", "VARCHAR(50)" ),
+ new HsqlColumnDescriptor( "b", "VARCHAR(50)" ),
+ new HsqlColumnDescriptor( "c", "VARCHAR(50)" )
+ }
+ ) );
+
+ // load the old document, and verify there is *no* table therein
+ impl_switchToDocument( oldDocumentURL );
+ m_documentUI.connect();
+ assure( "could not connect to " + m_database.getDocumentURL(), m_documentUI.isConnected() );
+ XTablesSupplier suppTables = (XTablesSupplier)UnoRuntime.queryInterface( XTablesSupplier.class,
+ m_documentUI.getActiveConnection() );
+ XNameAccess tables = suppTables.getTables();
+ assure( "the table was created in the wrong database", !tables.hasByName( "abc" ) );
+
+ // load the new document, and verify there *is* a table therein
+ impl_switchToDocument( newDocumentURL );
+ m_documentUI.connect();
+ assure( "could not connect to " + m_database.getDocumentURL(), m_documentUI.isConnected() );
+
+ suppTables = (XTablesSupplier)UnoRuntime.queryInterface( XTablesSupplier.class,
+ m_documentUI.getActiveConnection() );
+ tables = suppTables.getTables();
+ assure( "the newly created table has not been written", tables.hasByName( "abc" ) );
+ }
+}
diff --git a/dbaccess/qa/complex/dbaccess/CRMBasedTestCase.java b/dbaccess/qa/complex/dbaccess/CRMBasedTestCase.java
new file mode 100644
index 000000000000..edcb62579aac
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/CRMBasedTestCase.java
@@ -0,0 +1,86 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: CRMBasedTestCase.java,v $
+ * $Revision: 1.1.6.6 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+package complex.dbaccess;
+
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.sdb.XSingleSelectQueryComposer;
+import com.sun.star.uno.UnoRuntime;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public abstract class CRMBasedTestCase extends TestCase
+{
+ protected CRMDatabase m_database;
+
+ // --------------------------------------------------------------------------------------------------------
+ protected void createTestCase()
+ {
+ try
+ {
+ m_database = new CRMDatabase( getORB() );
+ }
+ catch ( Exception e )
+ {
+ e.printStackTrace( System.err );
+ assure( "caught an exception (" + e.getMessage() + ") while creating the test case", false );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void before()
+ {
+ createTestCase();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void after()
+ {
+ try
+ {
+ if ( m_database != null )
+ m_database.close();
+ }
+ catch ( Exception ex )
+ {
+ Logger.getLogger( this.getClass().getName() ).log( Level.SEVERE, null, ex );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ /** creates a SingleSelectQueryComposer for our connection
+ */
+ protected final XSingleSelectQueryComposer createQueryComposer() throws com.sun.star.uno.Exception
+ {
+ XMultiServiceFactory connectionFactory = (XMultiServiceFactory)UnoRuntime.queryInterface(
+ XMultiServiceFactory.class, m_database.getConnection() );
+ return (XSingleSelectQueryComposer)UnoRuntime.queryInterface(
+ XSingleSelectQueryComposer.class, connectionFactory.createInstance( "com.sun.star.sdb.SingleSelectQueryComposer" ) );
+ }
+}
diff --git a/dbaccess/qa/complex/dbaccess/CRMDatabase.java b/dbaccess/qa/complex/dbaccess/CRMDatabase.java
new file mode 100644
index 000000000000..ca28c1c769e7
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/CRMDatabase.java
@@ -0,0 +1,236 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: CRMDatabase.java,v $
+ * $Revision: 1.6.2.1 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+package complex.dbaccess;
+
+import com.sun.star.container.ElementExistException;
+import com.sun.star.io.IOException;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.sdb.XSingleSelectQueryComposer;
+import com.sun.star.sdbc.SQLException;
+import com.sun.star.sdbc.XConnection;
+import com.sun.star.sdbcx.XTablesSupplier;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.XRefreshable;
+import connectivity.tools.DataSource;
+import connectivity.tools.HsqlColumnDescriptor;
+import connectivity.tools.HsqlDatabase;
+import connectivity.tools.HsqlTableDescriptor;
+import connectivity.tools.QueryDefinition;
+
+/** implements a small Customer Relationship Management database
+ *
+ * Not finished, by far. Feel free to add features as you need them.
+ */
+public class CRMDatabase
+{
+ private XMultiServiceFactory m_orb;
+ private HsqlDatabase m_database;
+ private DataSource m_dataSource;
+ private XConnection m_connection;
+
+ /** constructs the CRM database
+ */
+ public CRMDatabase( XMultiServiceFactory _orb ) throws Exception
+ {
+ m_orb = _orb;
+
+ m_database = new HsqlDatabase( m_orb );
+ m_dataSource = m_database.getDataSource();
+ m_connection = m_database.defaultConnection();
+ createTables();
+ createQueries();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ /** returns the database document underlying the CRM database
+ */
+ public final HsqlDatabase getDatabase()
+ {
+ return m_database;
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ /** returns the default connection to the database
+ */
+ public final XConnection getConnection()
+ {
+ return m_connection;
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void close() throws SQLException, IOException
+ {
+ m_database.store();
+ m_database.close();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void createTables() throws SQLException
+ {
+ HsqlTableDescriptor table = new HsqlTableDescriptor( "categories",
+ new HsqlColumnDescriptor[] {
+ new HsqlColumnDescriptor( "ID", "INTEGER", HsqlColumnDescriptor.PRIMARY ),
+ new HsqlColumnDescriptor( "Name", "VARCHAR(50)" ),
+ new HsqlColumnDescriptor( "Description", "VARCHAR(1024)" ),
+ new HsqlColumnDescriptor( "Image", "LONGVARBINARY" ) } );
+ m_database.createTable( table, true );
+
+ m_database.executeSQL( "INSERT INTO \"categories\" ( \"ID\", \"Name\" ) VALUES ( 1, 'Food' )" );
+ m_database.executeSQL( "INSERT INTO \"categories\" ( \"ID\", \"Name\" ) VALUES ( 2, 'Furniture' )" );
+
+ table = new HsqlTableDescriptor( "products",
+ new HsqlColumnDescriptor[] {
+ new HsqlColumnDescriptor( "ID", "INTEGER", HsqlColumnDescriptor.PRIMARY ),
+ new HsqlColumnDescriptor( "Name", "VARCHAR(50)" ),
+ new HsqlColumnDescriptor( "CategoryID", "INTEGER", HsqlColumnDescriptor.REQUIRED, "categories", "ID" ) } );
+ m_database.createTable( table, true );
+
+ m_database.executeSQL( "INSERT INTO \"products\" VALUES ( 1, 'Oranges', 1 )" );
+ m_database.executeSQL( "INSERT INTO \"products\" VALUES ( 2, 'Apples', 1 )" );
+ m_database.executeSQL( "INSERT INTO \"products\" VALUES ( 3, 'Pears', 1 )" );
+ m_database.executeSQL( "INSERT INTO \"products\" VALUES ( 4, 'Strawberries', 1 )" );
+
+ table = new HsqlTableDescriptor( "customers",
+ new HsqlColumnDescriptor[] {
+ new HsqlColumnDescriptor( "ID", "INTEGER", HsqlColumnDescriptor.PRIMARY ),
+ new HsqlColumnDescriptor( "Name", "VARCHAR(50)" ),
+ new HsqlColumnDescriptor( "Address", "VARCHAR(50)" ),
+ new HsqlColumnDescriptor( "City", "VARCHAR(50)" ),
+ new HsqlColumnDescriptor( "Postal", "VARCHAR(50)" ) } );
+ m_database.createTable( table, true );
+
+ m_database.executeSQL( "INSERT INTO \"customers\" VALUES(1,'Food, Inc.','Down Under','Melbourne','509') " );
+ m_database.executeSQL( "INSERT INTO \"customers\" VALUES(2,'Simply Delicious','Down Under','Melbourne','518') " );
+ m_database.executeSQL( "INSERT INTO \"customers\" VALUES(3,'Pure Health','10 Fish St.','San Francisco','94107') " );
+ m_database.executeSQL( "INSERT INTO \"customers\" VALUES(4,'Milk And More','Arlington Road 21','Dublin','31021') " );
+
+ table = new HsqlTableDescriptor( "orders",
+ new HsqlColumnDescriptor[] {
+ new HsqlColumnDescriptor( "ID", "INTEGER", HsqlColumnDescriptor.PRIMARY ),
+ new HsqlColumnDescriptor( "CustomerID", "INTEGER", HsqlColumnDescriptor.REQUIRED, "customers", "ID" ),
+ new HsqlColumnDescriptor( "OrderDate", "DATE" ),
+ new HsqlColumnDescriptor( "ShipDate", "DATE" ) } );
+ m_database.createTable( table, true );
+
+ m_database.executeSQL( "INSERT INTO \"orders\" (\"ID\", \"CustomerID\", \"OrderDate\") VALUES(1, 1, {D '2009-01-01'})" );
+ m_database.executeSQL( "INSERT INTO \"orders\" VALUES(2, 2, {D '2009-01-01'}, {D '2009-01-23'})" );
+
+ table = new HsqlTableDescriptor( "orders_details",
+ new HsqlColumnDescriptor[] {
+ new HsqlColumnDescriptor( "OrderID", "INTEGER", HsqlColumnDescriptor.PRIMARY, "orders", "ID" ),
+ new HsqlColumnDescriptor( "ProductID", "INTEGER", HsqlColumnDescriptor.PRIMARY, "products", "ID" ),
+ new HsqlColumnDescriptor( "Quantity", "INTEGER" ) } );
+ m_database.createTable( table, true );
+
+ m_database.executeSQL( "INSERT INTO \"orders_details\" VALUES(1, 1, 100)" );
+ m_database.executeSQL( "INSERT INTO \"orders_details\" VALUES(1, 2, 100)" );
+ m_database.executeSQL( "INSERT INTO \"orders_details\" VALUES(2, 2, 2000)" );
+ m_database.executeSQL( "INSERT INTO \"orders_details\" VALUES(2, 3, 2000)" );
+ m_database.executeSQL( "INSERT INTO \"orders_details\" VALUES(2, 4, 2000)" );
+
+ // since we created the tables by directly executing the SQL statements, we need to refresh
+ // the tables container
+ XTablesSupplier suppTables = (XTablesSupplier)UnoRuntime.queryInterface(
+ XTablesSupplier.class, m_connection );
+ XRefreshable refreshTables = (XRefreshable)UnoRuntime.queryInterface(
+ XRefreshable.class, suppTables.getTables() );
+ refreshTables.refresh();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void validateUnparseable()
+ {
+ // The "unparseable" query should be indeed be unparseable by OOo (though a valid HSQL query)
+ XSingleSelectQueryComposer composer = null;
+ QueryDefinition unparseableQuery = null;
+ try
+ {
+ XMultiServiceFactory factory = (XMultiServiceFactory)UnoRuntime.queryInterface(
+ XMultiServiceFactory.class, m_database.defaultConnection() );
+ composer = (XSingleSelectQueryComposer)UnoRuntime.queryInterface(
+ XSingleSelectQueryComposer.class, factory.createInstance( "com.sun.star.sdb.SingleSelectQueryComposer" ) );
+ unparseableQuery = m_dataSource.getQueryDefinition( "unparseable" );
+ }
+ catch( Exception e )
+ {
+ throw new RuntimeException( "caught an unexpected exception: " + e.getMessage() );
+ }
+
+ boolean caughtExpected = false;
+ try
+ {
+ composer.setQuery( unparseableQuery.getCommand() );
+ }
+ catch (WrappedTargetException e) { }
+ catch( SQLException e )
+ {
+ caughtExpected = true;
+ }
+
+ if ( !caughtExpected )
+ throw new RuntimeException( "Somebody improved the parser! This is bad :), since we need an unparsable query here!" );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void createQueries() throws ElementExistException, WrappedTargetException, com.sun.star.lang.IllegalArgumentException
+ {
+ m_database.getDataSource().createQuery(
+ "all orders",
+ "SELECT \"orders\".\"ID\" AS \"Order No.\", " +
+ "\"customers\".\"Name\" AS \"Customer Name\", " +
+ "\"orders\".\"OrderDate\" AS \"Order Date\", " +
+ "\"orders\".\"ShipDate\" AS \"Ship Date\", " +
+ "\"orders_details\".\"Quantity\", " +
+ "\"products\".\"Name\" AS \"Product Name\" " +
+ "FROM \"orders_details\" AS \"orders_details\", " +
+ "\"orders\" AS \"orders\", " +
+ "\"products\" AS \"products\", " +
+ "\"customers\" AS \"customers\" " +
+ "WHERE ( \"orders_details\".\"OrderID\" = \"orders\".\"ID\" " +
+ "AND \"orders_details\".\"ProductID\" = \"products\".\"ID\" " +
+ "AND \"orders\".\"CustomerID\" = \"customers\".\"ID\" )"
+ );
+
+ m_database.getDataSource().createQuery(
+ "unshipped orders",
+ "SELECT * " +
+ "FROM \"all orders\"" +
+ "WHERE ( \"ShipDate\" IS NULL )"
+ );
+
+ m_database.getDataSource().createQuery( "parseable", "SELECT * FROM \"customers\"" );
+ m_database.getDataSource().createQuery( "parseable native", "SELECT * FROM INFORMATION_SCHEMA.SYSTEM_VIEWS", false );
+ m_database.getDataSource().createQuery( "unparseable",
+ "SELECT CAST( \"ID\" AS VARCHAR(3) ) AS \"ID_VARCHAR\" FROM \"products\"", false );
+
+ validateUnparseable();
+ }
+}
diff --git a/dbaccess/qa/complex/dbaccess/DataSource.java b/dbaccess/qa/complex/dbaccess/DataSource.java
new file mode 100644
index 000000000000..cb19a1f85d53
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/DataSource.java
@@ -0,0 +1,109 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: DataSource.java,v $
+ * $Revision: 1.2 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+package complex.dbaccess;
+
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XNamingService;
+
+public class DataSource extends complexlib.ComplexTestCase {
+
+ connectivity.tools.HsqlDatabase m_database;
+ connectivity.tools.DataSource m_dataSource;
+
+ // --------------------------------------------------------------------------------------------------------
+ public String[] getTestMethodNames()
+ {
+ return new String[]
+ {
+ "testRegistrationName"
+ };
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public String getTestObjectName()
+ {
+ return "DataSource";
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void createTestCase()
+ {
+ try
+ {
+ if ( m_database == null )
+ {
+ CRMDatabase database = new CRMDatabase( getFactory() );
+ m_database = database.getDatabase();
+ m_dataSource = m_database.getDataSource();
+ }
+ }
+ catch( Exception e )
+ {
+ failed( "could not create the test case, error message:\n" + e.getMessage() );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private XMultiServiceFactory getFactory()
+ {
+ return (XMultiServiceFactory)param.getMSF();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void testRegistrationName()
+ {
+ createTestCase();
+
+ try
+ {
+ // 1. check the existing "Bibliography" data source whether it has the proper name
+ String dataSourceName = "Bibliography";
+ connectivity.tools.DataSource bibliography = new connectivity.tools.DataSource( getFactory(), dataSourceName );
+ assureEquals( "pre-registered database has a wrong name!",
+ dataSourceName, bibliography.getName() );
+
+ // 2. register a newly created data source, and verify it has the proper name
+ dataSourceName = "someDataSource";
+
+ XNamingService dataSourceRegistrations = (XNamingService)UnoRuntime.queryInterface(
+ XNamingService.class, getFactory().createInstance("com.sun.star.sdb.DatabaseContext"));
+ dataSourceRegistrations.registerObject("someDataSource", m_dataSource.getXDataSource());
+
+ assureEquals( "registration name of a newly registered data source is wrong",
+ dataSourceName, m_dataSource.getName() );
+ }
+ catch ( AssureException e ) { throw e; }
+ catch ( Exception e )
+ {
+ failed( "caught an unexpected exception: " + e.getMessage() );
+ }
+ }
+}
diff --git a/dbaccess/qa/complex/dbaccess/DatabaseDocument.java b/dbaccess/qa/complex/dbaccess/DatabaseDocument.java
new file mode 100644
index 000000000000..145ef40515ae
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/DatabaseDocument.java
@@ -0,0 +1,847 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: DatabaseDocument.java,v $
+ * $Revision: 1.1.2.9 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+package complex.dbaccess;
+
+import com.sun.star.awt.XTopWindow;
+import com.sun.star.beans.PropertyState;
+import com.sun.star.document.DocumentEvent;
+import com.sun.star.lang.XEventListener;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.script.XStorageBasedLibraryContainer;
+import com.sun.star.task.XInteractionRequest;
+import com.sun.star.uno.Exception;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.frame.XStorable;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.container.XNameContainer;
+import com.sun.star.container.XSet;
+import com.sun.star.document.XDocumentEventBroadcaster;
+import com.sun.star.document.XDocumentEventListener;
+import com.sun.star.document.XEmbeddedScripts;
+import com.sun.star.document.XEventsSupplier;
+import com.sun.star.document.XScriptInvocationContext;
+import com.sun.star.frame.DoubleInitializationException;
+import com.sun.star.lang.XComponent;
+import com.sun.star.frame.XComponentLoader;
+import com.sun.star.frame.XDispatch;
+import com.sun.star.frame.XDispatchProvider;
+import com.sun.star.frame.XFrame;
+import com.sun.star.frame.XLoadable;
+import com.sun.star.frame.XModel;
+import com.sun.star.frame.XModel2;
+import com.sun.star.frame.XTitle;
+import com.sun.star.lang.EventObject;
+import com.sun.star.lang.NotInitializedException;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lang.XSingleComponentFactory;
+import com.sun.star.lang.XTypeProvider;
+import com.sun.star.script.provider.XScriptProviderSupplier;
+import com.sun.star.sdb.XFormDocumentsSupplier;
+import com.sun.star.sdb.XOfficeDatabaseDocument;
+import com.sun.star.sdb.XReportDocumentsSupplier;
+import com.sun.star.task.DocumentMacroConfirmationRequest;
+import com.sun.star.task.XInteractionApprove;
+import com.sun.star.task.XInteractionContinuation;
+import com.sun.star.task.XInteractionHandler;
+import com.sun.star.uno.XComponentContext;
+import com.sun.star.util.CloseVetoException;
+import com.sun.star.util.URL;
+import com.sun.star.util.XChangesBatch;
+import com.sun.star.util.XCloseable;
+import com.sun.star.util.XModifiable;
+import com.sun.star.util.XURLTransformer;
+import connectivity.tools.*;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class DatabaseDocument extends TestCase implements com.sun.star.document.XDocumentEventListener
+{
+ private XComponent m_callbackFactory = null;
+ private Vector m_documentEvents = new Vector();
+ private Vector m_globalEvents = new Vector();
+
+ // for those states, see testDocumentEvents
+ private static short STATE_NOT_STARTED = 0;
+ private static short STATE_LOADING_DOC = 1;
+ private static short STATE_MACRO_EXEC_APPROVED = 2;
+ private static short STATE_ON_LOAD_RECEIVED = 3;
+ private short m_loadDocState = STATE_NOT_STARTED;
+
+ // ========================================================================================================
+ /** a helper class which can be used by the Basic scripts in our test documents
+ * to notify us of events in this document
+ */
+ private class CallbackComponent implements XDocumentEventListener, XTypeProvider
+ {
+ public void documentEventOccured( DocumentEvent _event )
+ {
+ onDocumentEvent( _event );
+ }
+
+ public void disposing( com.sun.star.lang.EventObject _Event )
+ {
+ // not interested in
+ }
+
+ public Type[] getTypes()
+ {
+ Class interfaces[] = getClass().getInterfaces();
+ Type types[] = new Type[interfaces.length];
+ for(int i = 0; i < interfaces.length; ++ i)
+ {
+ types[i] = new Type(interfaces[i]);
+ }
+ return types;
+ }
+
+ public byte[] getImplementationId()
+ {
+ return getClass().toString().getBytes();
+ }
+ };
+
+ // ========================================================================================================
+ private static String getCallbackComponentServiceName()
+ {
+ return "org.openoffice.complex.dbaccess.EventCallback";
+ }
+
+ // ========================================================================================================
+ /** a factory for a CallbackComponent
+ */
+ private class CallbackComponentFactory implements XSingleComponentFactory, XServiceInfo, XComponent
+ {
+ private Vector m_eventListeners = new Vector();
+
+ public Object createInstanceWithContext( XComponentContext _context ) throws Exception
+ {
+ return new CallbackComponent();
+ }
+
+ public Object createInstanceWithArgumentsAndContext( Object[] arg0, XComponentContext _context ) throws Exception
+ {
+ return createInstanceWithContext( _context );
+ }
+
+ public String getImplementationName()
+ {
+ return "org.openoffice.complex.dbaccess.CallbackComponent";
+ }
+
+ public boolean supportsService( String _service )
+ {
+ return _service.equals( getCallbackComponentServiceName() );
+ }
+
+ public String[] getSupportedServiceNames()
+ {
+ return new String[] { getCallbackComponentServiceName() };
+ }
+
+ public void dispose()
+ {
+ EventObject event = new EventObject( this );
+
+ Vector eventListenersCopy = (Vector)m_eventListeners.clone();
+ Iterator iter = eventListenersCopy.iterator();
+ while ( iter.hasNext() )
+ {
+ ((XEventListener)iter.next()).disposing( event );
+ }
+ }
+
+ public void addEventListener( XEventListener _listener )
+ {
+ if ( _listener != null )
+ m_eventListeners.add( _listener );
+ }
+
+ public void removeEventListener( XEventListener _listener )
+ {
+ m_eventListeners.remove( _listener );
+ }
+ };
+
+ // ========================================================================================================
+ private class MacroExecutionApprove implements XInteractionHandler
+ {
+ private XInteractionHandler m_defaultHandler = null;
+
+ MacroExecutionApprove( XMultiServiceFactory _factory )
+ {
+ try
+ {
+ m_defaultHandler = (XInteractionHandler)UnoRuntime.queryInterface( XInteractionHandler.class,
+ _factory.createInstance( "com.sun.star.sdb.InteractionHandler" ) );
+ }
+ catch ( Exception ex )
+ {
+ Logger.getLogger( DatabaseDocument.class.getName() ).log( Level.SEVERE, null, ex );
+ }
+ }
+
+ public void handle( XInteractionRequest _request )
+ {
+ Object request = _request.getRequest();
+ if ( !( request instanceof DocumentMacroConfirmationRequest ) && ( m_defaultHandler != null ) )
+ {
+ m_defaultHandler.handle( _request );
+ return;
+ }
+
+ assureEquals( "interaction handleer called in wrong state", STATE_LOADING_DOC, m_loadDocState );
+
+ // auto-approve
+ XInteractionContinuation continuations[] = _request.getContinuations();
+ for ( int i=0; i<continuations.length; ++i )
+ {
+ XInteractionApprove approve = (XInteractionApprove)UnoRuntime.queryInterface( XInteractionApprove.class,
+ continuations[i] );
+ if ( approve != null )
+ {
+ approve.select();
+ m_loadDocState = STATE_MACRO_EXEC_APPROVED;
+ break;
+ }
+ }
+ }
+ };
+
+ // ========================================================================================================
+ // --------------------------------------------------------------------------------------------------------
+ public String[] getTestMethodNames()
+ {
+ return new String[]
+ {
+ "testLoadable",
+ "testDocumentEvents",
+ "testGlobalEvents"
+ };
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public String getTestObjectName()
+ {
+ return "DatabaseDocument";
+ }
+
+ public void before()
+ {
+ super.before();
+
+ try
+ {
+ // at our service factory, insert a new factory for our CallbackComponent
+ // this will allow the Basic code in our test documents to call back into this test case
+ // here, by just instantiating this service
+ XSet globalFactory = (XSet)UnoRuntime.queryInterface(
+ XSet.class, getORB() );
+ m_callbackFactory = new CallbackComponentFactory();
+ globalFactory.insert( m_callbackFactory );
+
+ // register ourself as listener at the global event broadcaster
+ XDocumentEventBroadcaster broadcaster = (XDocumentEventBroadcaster)UnoRuntime.queryInterface(
+ XDocumentEventBroadcaster.class, getORB().createInstance( "com.sun.star.frame.GlobalEventBroadcaster" ) );
+ broadcaster.addDocumentEventListener( this );
+ }
+ catch( Exception e )
+ {
+ System.err.println( "could not create the test case, error message:\n" + e.getMessage() );
+ e.printStackTrace( System.err );
+ failed( "failed to create the test case" );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void after()
+ {
+ super.after();
+
+ try
+ {
+ // dispose our callback factory. This will automatically remove it from our service
+ // factory
+ m_callbackFactory.dispose();
+
+ // revoke ourself as listener at the global event broadcaster
+ XDocumentEventBroadcaster broadcaster = (XDocumentEventBroadcaster) UnoRuntime.queryInterface(
+ XDocumentEventBroadcaster.class, getORB().createInstance( "com.sun.star.frame.GlobalEventBroadcaster" ) );
+ broadcaster.removeDocumentEventListener( this );
+ }
+ catch ( Exception e )
+ {
+ System.err.println( "could not close the test case, error message:\n" + e.getMessage() );
+ e.printStackTrace( System.err );
+ failed( "failed to close the test case" );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private class UnoMethodDescriptor
+ {
+ public Class unoInterfaceClass = null;
+ public String methodName = null;
+
+ public UnoMethodDescriptor( Class _class, String _method )
+ {
+ unoInterfaceClass = _class;
+ methodName = _method;
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void impl_checkDocumentInitState( Object _document, boolean _isInitialized )
+ {
+ // things you cannot do with an uninitialized document:
+ UnoMethodDescriptor[] unsupportedMethods = new UnoMethodDescriptor[] {
+ new UnoMethodDescriptor( XStorable.class, "store" ),
+ new UnoMethodDescriptor( XFormDocumentsSupplier.class, "getFormDocuments" ),
+ new UnoMethodDescriptor( XReportDocumentsSupplier.class, "getReportDocuments" ),
+ new UnoMethodDescriptor( XScriptProviderSupplier.class, "getScriptProvider" ),
+ new UnoMethodDescriptor( XEventsSupplier.class, "getEvents" ),
+ new UnoMethodDescriptor( XTitle.class, "getTitle" ),
+ new UnoMethodDescriptor( XModel2.class, "getControllers" )
+ // (there's much more than this, but we cannot list all methods here, can we ...)
+ };
+
+ for ( int i=0; i<unsupportedMethods.length; ++i)
+ {
+ verifyExpectedException( _document, unsupportedMethods[i].unoInterfaceClass,
+ unsupportedMethods[i].methodName, new Object[]{}, _isInitialized ? null : NotInitializedException.class );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private XModel impl_createDocument( ) throws Exception
+ {
+ XModel databaseDoc = (XModel)UnoRuntime.queryInterface( XModel.class,
+ getORB().createInstance( "com.sun.star.sdb.OfficeDatabaseDocument" ) );
+
+ // should not be initialized here - we did neither initNew nor load nor storeAsURL it
+ impl_checkDocumentInitState( databaseDoc, false );
+
+ return databaseDoc;
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void impl_closeDocument( XModel _databaseDoc ) throws CloseVetoException, IOException, Exception
+ {
+ XCloseable closeDoc = (XCloseable)UnoRuntime.queryInterface( XCloseable.class,
+ _databaseDoc );
+ closeDoc.close( true );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private XModel impl_createEmptyEmbeddedHSQLDocument() throws Exception, IOException
+ {
+ XModel databaseDoc = (XModel)UnoRuntime.queryInterface( XModel.class,
+ getORB().createInstance( "com.sun.star.sdb.OfficeDatabaseDocument" ) );
+ XStorable storeDoc = (XStorable)UnoRuntime.queryInterface( XStorable.class, databaseDoc );
+
+ // verify the document rejects API calls which require it to be initialized
+ impl_checkDocumentInitState( databaseDoc, false );
+
+ // though the document is not initialized, you can ask for the location, the URL, and the args
+ String location = storeDoc.getLocation();
+ String url = databaseDoc.getURL();
+ PropertyValue[] args = databaseDoc.getArgs();
+ // they should be all empty at this time
+ assureEquals( "location is expected to be empty here", "", location );
+ assureEquals( "URL is expected to be empty here", "", url );
+ assureEquals( "Args are expected to be empty here", 0, args.length );
+
+ // and, you should be able to set properties at the data source
+ XOfficeDatabaseDocument dataSourceAccess = (XOfficeDatabaseDocument)UnoRuntime.queryInterface(
+ XOfficeDatabaseDocument.class, databaseDoc );
+ XPropertySet dsProperties = (XPropertySet)UnoRuntime.queryInterface(
+ XPropertySet.class, dataSourceAccess.getDataSource() );
+ dsProperties.setPropertyValue( "URL", "sdbc:embedded:hsqldb" );
+
+ String documentURL = createTempFileURL();
+ storeDoc.storeAsURL( documentURL, new PropertyValue[0] );
+
+ // now that the document is stored, ...
+ // ... its URL should be correct
+ assureEquals( "wrong URL after storing the document", documentURL, databaseDoc.getURL() );
+ // ... it should be initialized
+ impl_checkDocumentInitState( databaseDoc, true );
+
+ return databaseDoc;
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void testLoadable() throws Exception, IOException
+ {
+ XModel databaseDoc = impl_createEmptyEmbeddedHSQLDocument();
+ String documentURL = databaseDoc.getURL();
+
+ // there's three methods how you can initialize a database document:
+
+ // ....................................................................
+ // 1. XStorable::storeAsURL
+ // (this is for compatibility reasons, to not break existing code)
+ // this test is already made in impl_createEmptyEmbeddedHSQLDocument
+
+ // ....................................................................
+ // 2. XLoadable::load
+ databaseDoc = (XModel)UnoRuntime.queryInterface( XModel.class,
+ getORB().createInstance( "com.sun.star.sdb.OfficeDatabaseDocument" ) );
+ documentURL = copyToTempFile( documentURL );
+ // load the doc, and verify it's initialized then, and has the proper URL
+ XLoadable loadDoc = (XLoadable)UnoRuntime.queryInterface( XLoadable.class, databaseDoc );
+ loadDoc.load( new PropertyValue[] { new PropertyValue( "URL", 0, documentURL, PropertyState.DIRECT_VALUE ) } );
+ databaseDoc.attachResource( documentURL, new PropertyValue[0] );
+
+ assureEquals( "wrong URL after loading the document", documentURL, databaseDoc.getURL() );
+ impl_checkDocumentInitState( databaseDoc, true );
+
+ // and while we are here ... initilizing the same document again should not be possible
+ verifyExpectedException( databaseDoc, XLoadable.class, "initNew", new Object[0],
+ DoubleInitializationException.class );
+ verifyExpectedException( databaseDoc, XLoadable.class, "load", new Object[] { new PropertyValue[0] },
+ DoubleInitializationException.class );
+
+ // ....................................................................
+ // 3. XLoadable::initNew
+ impl_closeDocument( databaseDoc );
+ databaseDoc = impl_createDocument();
+ loadDoc = (XLoadable)UnoRuntime.queryInterface( XLoadable.class, databaseDoc );
+ loadDoc.initNew();
+ assureEquals( "wrong URL after initializing the document", "", databaseDoc.getURL() );
+ impl_checkDocumentInitState( databaseDoc, true );
+
+ // same as above - initializing the document a second time must fail
+ verifyExpectedException( databaseDoc, XLoadable.class, "initNew", new Object[0],
+ DoubleInitializationException.class );
+ verifyExpectedException( databaseDoc, XLoadable.class, "load", new Object[] { new PropertyValue[0] },
+ DoubleInitializationException.class );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private PropertyValue[] impl_getDefaultLoadArgs()
+ {
+ return new PropertyValue[] {
+ new PropertyValue( "PickListEntry", 0, false, PropertyState.DIRECT_VALUE )
+ };
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private PropertyValue[] impl_getMacroExecLoadArgs()
+ {
+ return new PropertyValue[] {
+ new PropertyValue( "PickListEntry", 0, false, PropertyState.DIRECT_VALUE ),
+ new PropertyValue( "MacroExecutionMode", 0, com.sun.star.document.MacroExecMode.USE_CONFIG, PropertyState.DIRECT_VALUE ),
+ new PropertyValue( "InteractionHandler", 0, new MacroExecutionApprove(( getORB() )), PropertyState.DIRECT_VALUE )
+ };
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private int impl_setMacroSecurityLevel( int _level ) throws Exception
+ {
+ XMultiServiceFactory configProvider = (XMultiServiceFactory)UnoRuntime.queryInterface( XMultiServiceFactory.class,
+ getORB().createInstance( "com.sun.star.configuration.ConfigurationProvider" ) );
+
+ PropertyValue[] args = new PropertyValue[] {
+ new PropertyValue( "nodepath", 0, "/org.openoffice.Office.Common/Security/Scripting", PropertyState.DIRECT_VALUE )
+ };
+
+ XPropertySet securitySettings = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class,
+ configProvider.createInstanceWithArguments( "com.sun.star.configuration.ConfigurationUpdateAccess", args ) );
+ int oldValue = ((Integer)securitySettings.getPropertyValue( "MacroSecurityLevel" )).intValue();
+ securitySettings.setPropertyValue( "MacroSecurityLevel", new Integer( _level ) );
+
+ XChangesBatch committer = (XChangesBatch)UnoRuntime.queryInterface( XChangesBatch.class,
+ securitySettings );
+ committer.commitChanges();
+
+ return oldValue;
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void testDocumentEvents() throws Exception, IOException
+ {
+ // create an empty document
+ XModel databaseDoc = impl_createEmptyEmbeddedHSQLDocument();
+
+ // create Basic library/module therein
+ XEmbeddedScripts embeddedScripts = (XEmbeddedScripts) UnoRuntime.queryInterface( XEmbeddedScripts.class,
+ databaseDoc );
+ XStorageBasedLibraryContainer basicLibs = embeddedScripts.getBasicLibraries();
+ XNameContainer newLib = basicLibs.createLibrary( "EventHandlers" );
+ String eventHandlerCode =
+ "Option Explicit\n" +
+ "\n" +
+ "Sub OnLoad\n" +
+ " Dim oCallback as Object\n" +
+ " oCallback = createUnoService( \"" + getCallbackComponentServiceName() + "\" )\n" +
+ "\n" +
+ " ' as long as the Document is not passed to the Basic callbacks, we need to create\n" +
+ " ' one ourself\n" +
+ " Dim oEvent as new com.sun.star.document.DocumentEvent\n" +
+ " oEvent.EventName = \"OnLoad\"\n" +
+ " oEvent.Source = ThisComponent\n" +
+ "\n" +
+ " oCallback.documentEventOccured( oEvent )\n" +
+ "End Sub\n";
+ newLib.insertByName( "all", eventHandlerCode );
+
+ // bind the macro to the OnLoad event
+ String macroURI = "vnd.sun.star.script:EventHandlers.all.OnLoad?language=Basic&location=document";
+ XEventsSupplier eventsSupplier = (XEventsSupplier)UnoRuntime.queryInterface( XEventsSupplier.class,
+ databaseDoc );
+ eventsSupplier.getEvents().replaceByName( "OnLoad", new PropertyValue[] {
+ new PropertyValue( "EventType", 0, "Script", PropertyState.DIRECT_VALUE ),
+ new PropertyValue( "Script", 0, macroURI, PropertyState.DIRECT_VALUE )
+ } );
+
+ // store the document, and close it
+ String documentURL = databaseDoc.getURL();
+ documentURL = FileHelper.getOOoCompatibleFileURL( documentURL );
+ XStorable storeDoc = (XStorable) UnoRuntime.queryInterface( XStorable.class,
+ databaseDoc );
+ storeDoc.store();
+ impl_closeDocument( databaseDoc );
+
+ // ensure the macro security configuration is "ask the user for document macro execution"
+ int oldSecurityLevel = impl_setMacroSecurityLevel( 1 );
+
+ // load it, again
+ XComponentLoader loader = (XComponentLoader)UnoRuntime.queryInterface( XComponentLoader.class,
+ getORB().createInstance( "com.sun.star.frame.Desktop" ) );
+
+ m_loadDocState = STATE_LOADING_DOC;
+ // expected order of states is:
+ // STATE_LOADING_DOC - initialized here
+ // STATE_MACRO_EXEC_APPROVED - done in our interaction handler, which auto-approves the execution of macros
+ // STATE_ON_LOAD_RECEIVED - done in our callback for the document events
+ //
+ // In particular, it is important that the interaction handler (which plays the role of the user confirmation
+ // here) is called before the OnLoad notification is received - since the latter happens from within
+ // a Basic macro which is bound to the OnLoad event of the document.
+
+ String context = "OnLoad";
+ impl_startObservingEvents( context );
+ databaseDoc = (XModel)UnoRuntime.queryInterface( XModel.class,
+ loader.loadComponentFromURL( documentURL, "_blank", 0, impl_getMacroExecLoadArgs() ) );
+ impl_stopObservingEvents( m_documentEvents, new String[] { "OnLoad" }, context );
+
+ assureEquals( "our provided interaction handler was not called", STATE_ON_LOAD_RECEIVED, m_loadDocState );
+
+ // restore macro security level
+ impl_setMacroSecurityLevel( oldSecurityLevel );
+
+ // close the document
+ impl_closeDocument( databaseDoc );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void testGlobalEvents() throws Exception, IOException
+ {
+ XModel databaseDoc = impl_createEmptyEmbeddedHSQLDocument();
+ XStorable storeDoc = (XStorable) UnoRuntime.queryInterface( XStorable.class,
+ databaseDoc );
+
+ String oldURL = null, newURL = null, context = null;
+
+ // XStorable.store
+ oldURL = databaseDoc.getURL();
+ context = "store";
+ impl_startObservingEvents( context );
+ storeDoc.store();
+ assureEquals( "store is not expected to change the document URL", databaseDoc.getURL(), oldURL );
+ impl_stopObservingEvents( m_globalEvents, new String[] { "OnSave", "OnSaveDone" }, context );
+
+ // XStorable.storeToURL
+ context = "storeToURL";
+ impl_startObservingEvents( context );
+ storeDoc.storeToURL( createTempFileURL(), new PropertyValue[0] );
+ assureEquals( "storetoURL is not expected to change the document URL", databaseDoc.getURL(), oldURL );
+ impl_stopObservingEvents( m_globalEvents, new String[] { "OnSaveTo", "OnSaveToDone" }, context );
+
+ // XStorable.storeAsURL
+ newURL = createTempFileURL();
+ context = "storeAsURL";
+ impl_startObservingEvents( context );
+ storeDoc.storeAsURL( newURL, new PropertyValue[0] );
+ assureEquals( "storeAsURL is expected to change the document URL", databaseDoc.getURL(), newURL );
+ impl_stopObservingEvents( m_globalEvents, new String[] { "OnSaveAs", "OnSaveAsDone" }, context );
+
+ // XModifiable.setModified
+ XModifiable modifyDoc = (XModifiable) UnoRuntime.queryInterface( XModifiable.class,
+ databaseDoc );
+ context = "setModified";
+ impl_startObservingEvents( context );
+ modifyDoc.setModified( true );
+ assureEquals( "setModified didn't work", modifyDoc.isModified(), true );
+ impl_stopObservingEvents( m_globalEvents, new String[] { "OnModifyChanged" }, context );
+
+ // XStorable.store, with implicit reset of the "Modified" flag
+ context = "store (2)";
+ impl_startObservingEvents( context );
+ storeDoc.store();
+ assureEquals( "'store' should implicitly reset the modified flag", modifyDoc.isModified(), false );
+ impl_stopObservingEvents( m_globalEvents, new String[] { "OnSave", "OnSaveDone", "OnModifyChanged" }, context );
+
+ // XComponentLoader.loadComponentFromURL
+ newURL = copyToTempFile( databaseDoc.getURL() );
+ XComponentLoader loader = (XComponentLoader)UnoRuntime.queryInterface( XComponentLoader.class,
+ getORB().createInstance( "com.sun.star.frame.Desktop" ) );
+ context = "loadComponentFromURL";
+ impl_startObservingEvents( context );
+ databaseDoc = (XModel) UnoRuntime.queryInterface( XModel.class,
+ loader.loadComponentFromURL( newURL, "_blank", 0, impl_getDefaultLoadArgs() ) );
+ impl_stopObservingEvents( m_globalEvents,
+ new String[] { "OnLoadFinished", "OnViewCreated", "OnFocus", "OnLoad" }, context );
+
+ // closing a document by API
+ XCloseable closeDoc = (XCloseable) UnoRuntime.queryInterface( XCloseable.class,
+ databaseDoc );
+ context = "close (API)";
+ impl_startObservingEvents( context );
+ closeDoc.close( true );
+ impl_stopObservingEvents( m_globalEvents,
+ new String[] { "OnPrepareUnload", "OnViewClosed", "OnUnload" }, context );
+
+ // closing a document via UI
+ context = "close (UI)";
+ impl_startObservingEvents( "prepare for '" + context + "'" );
+ databaseDoc = (XModel)UnoRuntime.queryInterface( XModel.class,
+ loader.loadComponentFromURL( newURL, "_blank", 0, impl_getDefaultLoadArgs() ) );
+ impl_waitForEvent( m_globalEvents, "OnLoad", 5000 );
+ // wait for all events to arrive - OnLoad should be the last one
+
+ XDispatchProvider dispatchProvider = (XDispatchProvider) UnoRuntime.queryInterface( XDispatchProvider.class,
+ databaseDoc.getCurrentController().getFrame() );
+ URL url = impl_getURL( ".uno:CloseDoc" );
+ XDispatch dispatcher = dispatchProvider.queryDispatch( url, "", 0 );
+ impl_startObservingEvents( context );
+ dispatcher.dispatch( url, new PropertyValue[0] );
+ impl_stopObservingEvents( m_globalEvents,
+ new String[] { "OnPrepareViewClosing", "OnViewClosed", "OnPrepareUnload", "OnUnload" }, context );
+
+ // creating a new document
+ databaseDoc = impl_createDocument();
+ XLoadable loadDoc = (XLoadable) UnoRuntime.queryInterface( XLoadable.class,
+ databaseDoc );
+ context = "initNew";
+ impl_startObservingEvents( context );
+ loadDoc.initNew();
+ impl_stopObservingEvents( m_globalEvents, new String[] { "OnCreate" }, context );
+
+ impl_startObservingEvents( context + " (cleanup)" );
+ impl_closeDocument( databaseDoc );
+ impl_waitForEvent( m_globalEvents, "OnUnload", 5000 );
+
+ // focus changes
+ context = "activation";
+ // for this, load a database document ...
+ impl_startObservingEvents( "prepare for '" + context + "'" );
+ databaseDoc = (XModel)UnoRuntime.queryInterface( XModel.class,
+ loader.loadComponentFromURL( newURL, "_blank", 0, impl_getDefaultLoadArgs() ) );
+ int previousOnLoadEventPos = impl_waitForEvent( m_globalEvents, "OnLoad", 5000 );
+ // ... and another document ...
+ String otherURL = copyToTempFile( databaseDoc.getURL() );
+ XModel otherDoc = (XModel)UnoRuntime.queryInterface( XModel.class,
+ loader.loadComponentFromURL( otherURL, "_blank", 0, impl_getDefaultLoadArgs() ) );
+ impl_waitForEvent( m_globalEvents, "OnLoad", 5000, previousOnLoadEventPos + 1 );
+ impl_raise( otherDoc );
+
+ // ... and switch between the two
+ impl_startObservingEvents( context );
+ impl_raise( databaseDoc );
+ impl_stopObservingEvents( m_globalEvents, new String[] { "OnUnfocus", "OnFocus" }, context );
+
+ // cleanup
+ impl_startObservingEvents( "cleanup after '" + context + "'" );
+ impl_closeDocument( databaseDoc );
+ impl_closeDocument( otherDoc );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private URL impl_getURL( String _completeURL ) throws Exception
+ {
+ URL[] url = { new URL() };
+ url[0].Complete = _completeURL;
+ XURLTransformer urlTransformer = (XURLTransformer) UnoRuntime.queryInterface( XURLTransformer.class,
+ getORB().createInstance( "com.sun.star.util.URLTransformer" ) );
+ urlTransformer.parseStrict( url );
+ return url[0];
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void impl_raise( XModel _document )
+ {
+ XFrame frame = _document.getCurrentController().getFrame();
+ XTopWindow topWindow = (XTopWindow) UnoRuntime.queryInterface( XTopWindow.class,
+ frame.getContainerWindow() );
+ topWindow.toFront();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void impl_startObservingEvents( String _context )
+ {
+ log.println( " " + _context );
+ synchronized ( m_documentEvents )
+ {
+ m_documentEvents.clear();
+ }
+ synchronized ( m_globalEvents )
+ {
+ m_globalEvents.clear();
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void impl_stopObservingEvents( Vector _actualEvents, String[] _expectedEvents, String _context )
+ {
+ synchronized ( _actualEvents )
+ {
+ int actualEventCount = _actualEvents.size();
+ while ( actualEventCount < _expectedEvents.length )
+ {
+ // well, it's possible not all events already arrived, yet - finally, some of them
+ // are notified asynchronously
+ // So, wait a few seconds.
+ try
+ {
+ _actualEvents.wait( 5000 );
+ }
+ catch ( InterruptedException ex ) { }
+
+ if ( actualEventCount == _actualEvents.size() )
+ // the above wait was left because of the timeout, *not* because an event
+ // arrived. Okay, we won't wait any longer, this is a failure.
+ break;
+ actualEventCount = _actualEvents.size();
+ }
+
+ assureEquals( "wrong event count for '" + _context + "'",
+ _expectedEvents.length, _actualEvents.size() );
+
+ for ( int i=0; i<_expectedEvents.length; ++i )
+ {
+ assureEquals( "wrong event at positon " + ( i + 1 ) + " for '" + _context + "'",
+ _expectedEvents[i], _actualEvents.get(i) );
+ }
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ int impl_waitForEvent( Vector _eventQueue, String _expectedEvent, int _maxMilliseconds )
+ {
+ return impl_waitForEvent( _eventQueue, _expectedEvent, _maxMilliseconds, 0 );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ int impl_waitForEvent( Vector _eventQueue, String _expectedEvent, int _maxMilliseconds, int _firstQueueElementToCheck )
+ {
+ synchronized ( _eventQueue )
+ {
+ int waitedMilliseconds = 0;
+
+ while ( waitedMilliseconds < _maxMilliseconds )
+ {
+ for ( int i=_firstQueueElementToCheck; i<_eventQueue.size(); ++i )
+ {
+ if ( _expectedEvent.equals( _eventQueue.get(i) ) )
+ // found the event in the queue
+ return i;
+ }
+
+ // wait a little, perhaps the event will still arrive
+ try
+ {
+ _eventQueue.wait( 500 );
+ waitedMilliseconds += 500;
+ }
+ catch ( InterruptedException e ) { }
+ }
+ }
+
+ failed( "expected event '" + _expectedEvent + "' did not arrive after " + _maxMilliseconds + " milliseconds" );
+ return -1;
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ void onDocumentEvent( DocumentEvent _Event )
+ {
+ if ( _Event.EventName.equals( "OnTitleChanged" ) )
+ // OnTitleChanged events are notified too often. This is known, and accepted.
+ // (the deeper reason is that it's diffult to determine, in the DatabaseDocument implementatin,
+ // when the title actually changed. In particular, when we do a saveAsURL, and then ask for a
+ // title *before* the TitleHelper got the document's OnSaveAsDone event, then the wrong (old)
+ // title is obtained.
+ return;
+
+ if ( ( _Event.EventName.equals( "OnLoad" ) )
+ && ( m_loadDocState != STATE_NOT_STARTED )
+ )
+ {
+ assureEquals( "OnLoad event must come *after* invocation of the interaction handler / user!",
+ m_loadDocState, STATE_MACRO_EXEC_APPROVED );
+ m_loadDocState = STATE_ON_LOAD_RECEIVED;
+ }
+
+ synchronized ( m_documentEvents )
+ {
+ m_documentEvents.add( _Event.EventName );
+ m_documentEvents.notifyAll();
+ }
+
+ log.println( " document event: " + _Event.EventName );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void documentEventOccured( DocumentEvent _Event )
+ {
+ if ( _Event.EventName.equals( "OnTitleChanged" ) )
+ // ignore. See onDocumentEvent for a justification
+ return;
+
+ synchronized ( m_globalEvents )
+ {
+ m_globalEvents.add( _Event.EventName );
+ m_globalEvents.notifyAll();
+ }
+
+ log.println( " global event: " + _Event.EventName );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void disposing( EventObject _Event )
+ {
+ // not interested in
+ }
+}
diff --git a/dbaccess/qa/complex/dbaccess/FileHelper.java b/dbaccess/qa/complex/dbaccess/FileHelper.java
new file mode 100644
index 000000000000..fbe5f330b24d
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/FileHelper.java
@@ -0,0 +1,46 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: Parser.java,v $
+ * $Revision: 1.1.6.2 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package complex.dbaccess;
+
+public class FileHelper
+{
+ static public String getOOoCompatibleFileURL( String _javaFileURL )
+ {
+ String returnURL = _javaFileURL;
+ if ( ( returnURL.indexOf( "file:/" ) == 0 ) && ( returnURL.indexOf( "file:///" ) == -1 ) )
+ {
+ // for some reason, the URLs here in Java start with "file:/" only, instead of "file:///"
+ // Some of the office code doesn't like this ...
+ returnURL = "file:///" + returnURL.substring( 6 );
+ }
+ return returnURL;
+ }
+}
diff --git a/dbaccess/qa/complex/dbaccess/Parser.java b/dbaccess/qa/complex/dbaccess/Parser.java
new file mode 100644
index 000000000000..a4305c031e1b
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/Parser.java
@@ -0,0 +1,160 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: Parser.java,v $
+ * $Revision: 1.1.6.2 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+package complex.dbaccess;
+
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.container.XIndexAccess;
+import com.sun.star.container.XNameAccess;
+import com.sun.star.sdb.XParametersSupplier;
+import com.sun.star.sdb.XSingleSelectQueryComposer;
+import com.sun.star.sdbc.DataType;
+import com.sun.star.sdbc.SQLException;
+import com.sun.star.uno.Exception;
+import com.sun.star.uno.UnoRuntime;
+
+public class Parser extends CRMBasedTestCase
+{
+ // --------------------------------------------------------------------------------------------------------
+ public String[] getTestMethodNames()
+ {
+ return new String[] {
+ "checkJoinSyntax",
+ "checkParameterTypes"
+ };
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public String getTestObjectName()
+ {
+ return "Parser";
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ protected void createTestCase()
+ {
+ try
+ {
+ super.createTestCase();
+ m_database.getDatabase().getDataSource().createQuery( "query products", "SELECT * FROM \"products\"" );
+ }
+ catch ( Exception e )
+ {
+ e.printStackTrace( System.err );
+ assure( "caught an exception (" + e.getMessage() + ") while creating the test case", false );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ /** verifies that aliases for inner queries work as expected
+ */
+ public void checkJoinSyntax() throws Exception
+ {
+ XSingleSelectQueryComposer composer = createQueryComposer();
+
+ // feed the composer with some statements. If any of those cannot be parsed, the composer
+ // will throw an exception - which is a regression then
+ composer.setQuery(
+ "SELECT \"categories\".\"Name\", " +
+ "\"products\".\"Name\" " +
+ "FROM \"products\" RIGHT OUTER JOIN \"categories\" AS \"categories\" ON \"products\".\"CategoryID\" = \"categories\".\"ID\"" );
+
+ // just to be sure the composer *really* parses upon setting the query: feed it with
+ // an unparseable statement
+ boolean caughtExpected = false;
+ try
+ {
+ composer.setQuery( "NONSENSE" );
+ }
+ catch( SQLException e )
+ {
+ caughtExpected = true;
+ }
+ assure( "pre-condition not met: parser should except on unparseable statements, else the complete" +
+ "test is bogus!", caughtExpected );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void impl_checkParameters( final String _statement, final String[] _expectedParameterNames, final int[] _expectedParameterTypes, String _context ) throws Exception
+ {
+ XSingleSelectQueryComposer composer = createQueryComposer();
+ composer.setQuery( _statement );
+
+ assureEquals( "checkParameterTypes: internal error", _expectedParameterNames.length, _expectedParameterTypes.length );
+
+ XParametersSupplier paramSupp = (XParametersSupplier)UnoRuntime.queryInterface(
+ XParametersSupplier.class, composer );
+ XIndexAccess parameters = paramSupp.getParameters();
+
+ assureEquals( "(ctx: " + _context + ") unexpected parameter count", _expectedParameterNames.length, parameters.getCount() );
+ for ( int i=0; i<parameters.getCount(); ++i )
+ {
+ XPropertySet parameter = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class,
+ parameters.getByIndex(i) );
+
+ String name = (String)parameter.getPropertyValue( "Name" );
+ assureEquals( "(ctx: " + _context + ") unexpected parameter name for parameter number " + ( i + 1 ), _expectedParameterNames[i], name );
+
+ int type = ((Integer)parameter.getPropertyValue( "Type" )).intValue();
+ assureEquals( "(ctx: " + _context + ") unexpected data type for parameter number " + ( i + 1 ), _expectedParameterTypes[i], type );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ /** verifies that the parser properly recognizes the types of parameters
+ */
+ public void checkParameterTypes() throws Exception
+ {
+ impl_checkParameters(
+ "SELECT * FROM \"all orders\" " +
+ "WHERE ( \"Order Date\" >= :order_date ) " +
+ " AND ( ( \"Customer Name\" LIKE :customer ) " +
+ " OR ( \"Product Name\" LIKE ? ) " +
+ " )",
+ new String[] { "order_date", "customer", "Product Name" },
+ new int[] { DataType.DATE, DataType.VARCHAR, DataType.VARCHAR },
+ ">= && LIKE"
+ );
+
+ impl_checkParameters(
+ "SELECT * FROM \"categories\" " +
+ "WHERE \"ID\" BETWEEN :id_lo AND :id_hi",
+ new String[] { "id_lo", "id_hi" },
+ new int[] { DataType.INTEGER, DataType.INTEGER },
+ "BETWEEN"
+ );
+
+ impl_checkParameters(
+ "SELECT CONCAT( :prefix, CONCAT( \"Name\", :suffix ) ) FROM \"customers\"",
+ new String[] { "prefix", "suffix" },
+ new int[] { DataType.VARCHAR, DataType.VARCHAR },
+ "CONCAT"
+ );
+ }
+}
diff --git a/dbaccess/qa/complex/dbaccess/PropertyBag.java b/dbaccess/qa/complex/dbaccess/PropertyBag.java
new file mode 100644
index 000000000000..5f1747fd94bc
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/PropertyBag.java
@@ -0,0 +1,296 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: PropertyBag.java,v $
+ * $Revision: 1.5 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package complex.dbaccess;
+
+import complexlib.ComplexTestCase;
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XInterface;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.beans.*;
+
+public class PropertyBag extends ComplexTestCase
+{
+ private XPropertyContainer m_bag;
+ private XPropertySet m_set;
+ private XPropertyAccess m_access;
+ private XMultiServiceFactory m_orb;
+
+ public String[] getTestMethodNames()
+ {
+ return new String[]
+ {
+ "checkBasics",
+ "checkSequenceAccess",
+ "checkDynamicSet"
+ };
+ }
+
+ public String getTestObjectName()
+ {
+ return "PropertyBag";
+ }
+
+ public void before()
+ {
+ m_orb = (XMultiServiceFactory)param.getMSF();
+ }
+
+ public void checkBasics()
+ {
+ createEmptyBag();
+ log.println("testing the basics");
+
+ // check whether empty property names are rejected
+ boolean caughtExpected = false;
+ try
+ {
+ m_bag.addProperty( "", PropertyAttribute.BOUND, new Integer( 3 ) );
+ }
+ catch(com.sun.star.lang.IllegalArgumentException e) { caughtExpected = true; }
+ catch(com.sun.star.uno.Exception e) { }
+ if ( !caughtExpected )
+ failed( "empty property names are not rejected by XPropertyContainer::addProperty" );
+
+ // check whether duplicate insertions are rejected
+ caughtExpected = false;
+ try
+ {
+ m_bag.addProperty( "Value", PropertyAttribute.BOUND, new String( "" ) );
+ m_bag.addProperty( "Value", PropertyAttribute.BOUND, new String( "" ) );
+ }
+ catch(com.sun.star.beans.PropertyExistException e) { caughtExpected = true; }
+ catch(com.sun.star.uno.Exception e) { }
+ if ( !caughtExpected )
+ failed( "insertion of duplicate property names is not rejected" );
+
+ // try removing the property we just added - this should fail, as it does not have
+ // the REMOVEABLE attribute
+ caughtExpected = false;
+ try
+ {
+ m_bag.removeProperty( "Value" );
+ }
+ catch(com.sun.star.beans.NotRemoveableException e) { caughtExpected = true; }
+ catch(com.sun.star.uno.Exception e) { }
+ if ( !caughtExpected )
+ failed( "removing non-removeable properties is expected to fail - but it didn't" );
+
+ // try removing a non-existent property
+ caughtExpected = false;
+ try
+ {
+ m_bag.removeProperty( "NonExistent" );
+ }
+ catch(com.sun.star.beans.UnknownPropertyException e) { caughtExpected = true; }
+ catch(com.sun.star.uno.Exception e) { }
+ if ( !caughtExpected )
+ failed( "removing non-existent properties is expected to fail - but it didn't" );
+
+ // try writing and reading a value for the one property we have so far
+ try
+ {
+ final String testValue = "someArbitraryValue";
+ m_set.setPropertyValue( "Value", testValue );
+ String currentValue = (String)m_set.getPropertyValue( "Value" );
+ if ( !currentValue.equals( testValue ) )
+ failed( "set property is not remembered" );
+ }
+ catch(com.sun.star.uno.Exception e)
+ {
+ failed( "setting or getting a property value failed" );
+ }
+
+ // try setting an illegal value for the property
+ caughtExpected = false;
+ try
+ {
+ m_set.setPropertyValue( "Value", new Integer( 3 ) );
+ }
+ catch(com.sun.star.lang.IllegalArgumentException e) { caughtExpected = true; }
+ catch(com.sun.star.uno.Exception e) { }
+ if ( !caughtExpected )
+ failed( "the bag does not respect the property type we declared for the property" );
+ }
+
+ public void checkSequenceAccess() throws com.sun.star.uno.Exception
+ {
+ log.println( "checking PropertySetAccess via sequences" );
+ createStandardBag( false );
+
+ // ---------------------------------
+ // XPropertyAccess.setPropertyValues
+ final PropertyValue expectedValues[] =
+ {
+ new PropertyValue( "BoolValue", -1, new Boolean( false ), PropertyState.DIRECT_VALUE ),
+ new PropertyValue( "StringValue", -1, "some text", PropertyState.DIRECT_VALUE ),
+ new PropertyValue( "IntegerValue", -1, new Integer( 3 ), PropertyState.DIRECT_VALUE ),
+ new PropertyValue( "InterfaceValue", -1, m_bag, PropertyState.DIRECT_VALUE )
+ };
+ m_access.setPropertyValues( expectedValues );
+
+ for ( int i=0; i<expectedValues.length; ++i )
+ {
+ Object value = m_set.getPropertyValue( expectedValues[i].Name );
+ if ( !value.equals( expectedValues[i].Value ) )
+ {
+ log.println( "property name : " + expectedValues[i].Name );
+ log.println( "expected value: " + expectedValues[i].Value.toString() );
+ log.println( "current value : " + value.toString() );
+ failed( "retrieving a previously set property (" + expectedValues[i].Value.getClass().toString() + ") failed" );
+ }
+ }
+
+ // ---------------------------------
+ // XPropertyAccess.getPropertyValues
+ PropertyValue currentValues[] = m_access.getPropertyValues();
+ for ( int i=0; i<currentValues.length; ++i )
+ {
+ String name = currentValues[i].Name;
+ Object value = currentValues[i].Value;
+ for ( int j=0; j<expectedValues.length; ++j )
+ {
+ if ( expectedValues[j].Name.equals( name ) )
+ {
+ if ( !expectedValues[j].Value.equals( value ) )
+ {
+ log.println( "property name : " + expectedValues[j].Name );
+ log.println( "expected value: " + expectedValues[j].Value.toString() );
+ log.println( "current value : " + value.toString() );
+ failed( "getPropertyValues failed for property '" + name + "' failed" );
+ }
+ break;
+ }
+ }
+
+ if ( !m_set.getPropertyValue( name ).equals( value ) )
+ failed( "XPropertyAccess::getPropertyValues() and XPropertyset::getPropertyValue results are inconsistent" );
+ }
+ }
+
+ public void checkDynamicSet() throws com.sun.star.uno.Exception
+ {
+ log.println( "checking proper dynamic of the set" );
+ createStandardBag( false );
+
+ PropertyValue props[] =
+ {
+ new PropertyValue( "BoolValue", -1, new Boolean( false ), PropertyState.DIRECT_VALUE),
+ new PropertyValue( "StringValue", -1, "test", PropertyState.DIRECT_VALUE ),
+ new PropertyValue( "SomeOtherStringValue", -1, "string value", PropertyState.DIRECT_VALUE )
+ };
+
+ // try setting some property values which are not existent
+ boolean caughtExpected = false;
+ try
+ {
+ m_access.setPropertyValues( props );
+ }
+ catch( com.sun.star.beans.UnknownPropertyException e ) { caughtExpected = true; }
+ catch( com.sun.star.uno.Exception e ) { }
+ if ( !caughtExpected )
+ failed( "the set shouldn't accept unknown property values, if not explicitly told to do so" );
+
+ // re-create the bag, this time allow it to implicitly add properties
+ createStandardBag( true );
+ boolean success = false;
+ try { m_access.setPropertyValues( props ); success = true; }
+ catch( com.sun.star.uno.Exception e ) { }
+ if ( !success )
+ failed( "property bag failed to implicitly add unknown properties" );
+
+ // see whether this property was really added, and not just ignored
+ PropertyValue newlyAdded = props[ props.length - 1 ];
+ try
+ {
+ if ( !m_set.getPropertyValue( newlyAdded.Name ).equals( newlyAdded.Value ) )
+ failed( "the new property was not really added, or not added with the proper value" );
+ }
+ catch( com.sun.star.uno.Exception e ) { }
+ }
+
+ private void createEmptyBag()
+ {
+ try
+ {
+ m_bag = null;
+ final String serviceName = "com.sun.star.beans.PropertyBag";
+ m_bag = (XPropertyContainer)UnoRuntime.queryInterface( XPropertyContainer.class,
+ m_orb.createInstance( serviceName )
+ );
+ if ( m_bag == null )
+ failed( "could not create a " + serviceName + " instance" );
+ m_set = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class, m_bag );
+ m_access = (XPropertyAccess)UnoRuntime.queryInterface( XPropertyAccess.class, m_bag );
+ }
+ catch( com.sun.star.uno.Exception e )
+ {
+ }
+ }
+
+ private void createStandardBag( boolean allowLazyAdding )
+ {
+ try
+ {
+ m_bag = null;
+
+ Object initArgs[] = { new NamedValue( "AutomaticAddition", new Boolean( allowLazyAdding ) ) };
+
+ final String serviceName = "com.sun.star.beans.PropertyBag";
+ m_bag = (XPropertyContainer)UnoRuntime.queryInterface( XPropertyContainer.class,
+ m_orb.createInstanceWithArguments( serviceName, initArgs )
+ );
+ if ( m_bag == null )
+ failed( "could not create a " + serviceName + " instance" );
+ m_set = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class, m_bag );
+ m_access = (XPropertyAccess)UnoRuntime.queryInterface( XPropertyAccess.class, m_bag );
+
+ Object properties[][] =
+ {
+ { "BoolValue", new Boolean( true ) },
+ { "StringValue", new String( "" ) },
+ { "IntegerValue", new Integer( 3 ) },
+ { "InterfaceValue", (XInterface)m_bag }
+ };
+ for ( int i=0; i<properties.length; ++i )
+ {
+ m_bag.addProperty(
+ (String)properties[i][0],
+ PropertyAttribute.MAYBEVOID,
+ properties[i][1]
+ );
+ }
+ }
+ catch( com.sun.star.uno.Exception e )
+ {
+ }
+ }
+}
diff --git a/dbaccess/qa/complex/dbaccess/Query.java b/dbaccess/qa/complex/dbaccess/Query.java
new file mode 100644
index 000000000000..d64e1a7c972e
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/Query.java
@@ -0,0 +1,130 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: Query.java,v $
+ * $Revision: 1.7 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+package complex.dbaccess;
+
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.container.XIndexAccess;
+import com.sun.star.container.XNameAccess;
+import com.sun.star.container.XNamed;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.sdb.XQueriesSupplier;
+import com.sun.star.sdbcx.XColumnsSupplier;
+import com.sun.star.uno.UnoRuntime;
+
+public class Query extends complexlib.ComplexTestCase {
+
+ connectivity.tools.HsqlDatabase m_database;
+ connectivity.tools.DataSource m_dataSource;
+
+ // --------------------------------------------------------------------------------------------------------
+ public String[] getTestMethodNames() {
+ return new String[]
+ {
+ "testQueryColumns"
+ };
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public String getTestObjectName() {
+ return "Query";
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void createTestCase()
+ {
+ try
+ {
+ if ( m_database == null )
+ {
+ CRMDatabase database = new CRMDatabase( getFactory() );
+ m_database = database.getDatabase();
+ m_dataSource = m_database.getDataSource();
+ }
+ }
+ catch( Exception e )
+ {
+ System.err.println( "could not create the test case, error message:\n" + e.getMessage() );
+ e.printStackTrace( System.err );
+ assure( "failed to created the test case", false );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private XMultiServiceFactory getFactory()
+ {
+ return (XMultiServiceFactory)param.getMSF();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void testQueryColumns()
+ {
+ createTestCase();
+
+ try
+ {
+ XQueriesSupplier suppQueries = (XQueriesSupplier)UnoRuntime.queryInterface(
+ XQueriesSupplier.class, m_database.defaultConnection());
+ XNameAccess queries = suppQueries.getQueries();
+
+ String[] queryNames = new String[] { "parseable", "parseable native", "unparseable" };
+ String[][] expectedColumnNames = new String[][] {
+ new String[] { "ID", "Name", "Address", "City", "Postal" },
+ new String[] { "TABLE_CATALOG", "TABLE_SCHEMA", "TABLE_NAME", "VIEW_DEFINITION", "CHECK_OPTION", "IS_UPDATABLE", "VALID" },
+ new String[] { "ID_VARCHAR" }
+ };
+
+ for ( int i = 0; i < queryNames.length; ++i )
+ {
+ XPropertySet query = (XPropertySet)UnoRuntime.queryInterface(
+ XPropertySet.class, queries.getByName( queryNames[i] ) );
+
+ XColumnsSupplier suppCols = (XColumnsSupplier)UnoRuntime.queryInterface(
+ XColumnsSupplier.class, query);
+ XIndexAccess columns = (XIndexAccess)UnoRuntime.queryInterface(
+ XIndexAccess.class, suppCols.getColumns());
+
+ // check whether the columns supplied by the query match what we expected
+ assure( "invalid column count (found " + columns.getCount() + ", expected: " + expectedColumnNames[i].length + ") for query \"" + queryNames[i] + "\"",
+ columns.getCount() == expectedColumnNames[i].length );
+ for ( int col = 0; col < columns.getCount(); ++col )
+ {
+ XNamed columnName = (XNamed)UnoRuntime.queryInterface(
+ XNamed.class, columns.getByIndex(col) );
+ assure( "column no. " + col + " of query \"" + queryNames[i] + "\" not matching",
+ columnName.getName().equals( expectedColumnNames[i][col] ) );
+ }
+ }
+ }
+ catch ( Exception e )
+ {
+ assure( "caught an unexpected exception: " + e.getMessage(), false );
+ }
+ }
+}
diff --git a/dbaccess/qa/complex/dbaccess/QueryInQuery.java b/dbaccess/qa/complex/dbaccess/QueryInQuery.java
new file mode 100644
index 000000000000..b06d57d05c59
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/QueryInQuery.java
@@ -0,0 +1,194 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: QueryInQuery.java,v $
+ * $Revision: 1.6.2.1 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+package complex.dbaccess;
+
+import com.sun.star.container.ElementExistException;
+import com.sun.star.lang.IllegalArgumentException;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.sdb.CommandType;
+import com.sun.star.sdbc.SQLException;
+import connectivity.tools.HsqlColumnDescriptor;
+import connectivity.tools.HsqlTableDescriptor;
+import connectivity.tools.RowSet;
+import com.sun.star.sdbc.XStatement;
+import com.sun.star.sdbc.XResultSet;
+
+public class QueryInQuery extends CRMBasedTestCase
+{
+ // --------------------------------------------------------------------------------------------------------
+ public String[] getTestMethodNames()
+ {
+ return new String[] {
+ "executeSimpleSelect",
+ "executeAliasedSelect",
+ "checkNameCollisions",
+ "checkCyclicReferences",
+ "checkStatementQiQSupport"
+ };
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public String getTestObjectName()
+ {
+ return "QueryInQuery";
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ protected void createTestCase()
+ {
+ try
+ {
+ super.createTestCase();
+ m_database.getDatabase().getDataSource().createQuery( "query products", "SELECT * FROM \"products\"" );
+ }
+ catch ( Exception e )
+ {
+ e.printStackTrace( System.err );
+ assure( "caught an exception (" + e.getMessage() + ") while creating the test case", false );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void verifyEqualRowSetContent( int _outerCommandType, String _outerCommand, int _innerCommandType, String _innerCommand ) throws SQLException
+ {
+ RowSet outerRowSet = m_database.getDatabase().createRowSet( _outerCommandType, _outerCommand );
+ outerRowSet.execute();
+
+ RowSet innerRowSet = m_database.getDatabase().createRowSet( _innerCommandType, _innerCommand );
+ innerRowSet.execute();
+
+ outerRowSet.last();
+ innerRowSet.last();
+ assure( "wrong record counts", outerRowSet.getRow() == innerRowSet.getRow() );
+
+ outerRowSet.beforeFirst();
+ innerRowSet.beforeFirst();
+ assure( "wrong column counts", outerRowSet.getColumnCount() == innerRowSet.getColumnCount() );
+
+ while ( outerRowSet.next() && innerRowSet.next() )
+ {
+ for ( int i=1; i <= outerRowSet.getColumnCount(); ++i )
+ {
+ assure( "content of column " + i + " of row " + outerRowSet.getRow() + " not identical",
+ innerRowSet.getString(i).equals( outerRowSet.getString(i) ) );
+ }
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ /** executes a SQL statement simply selecting all columns from a query
+ */
+ public void executeSimpleSelect() throws SQLException
+ {
+ verifyEqualRowSetContent(
+ CommandType.COMMAND, "SELECT * FROM \"query products\"",
+ CommandType.QUERY, "query products" );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ /** verifies that aliases for inner queries work as expected
+ */
+ public void executeAliasedSelect() throws SQLException
+ {
+ verifyEqualRowSetContent(
+ CommandType.COMMAND, "SELECT \"PROD\".\"ID\" FROM \"query products\" AS \"PROD\"",
+ CommandType.COMMAND, "SELECT \"ID\" FROM \"products\"" );
+ verifyEqualRowSetContent(
+ CommandType.COMMAND, "SELECT \"PROD\".* FROM \"query products\" AS \"PROD\"",
+ CommandType.QUERY, "query products" );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ /** verifies that aliases for inner queries work as expected
+ */
+ public void checkNameCollisions()
+ {
+ // create a query with a name which is used by a table
+ boolean caughtExpected = false;
+ try
+ {
+ m_database.getDatabase().getDataSource().createQuery( "products", "SELECT * FROM \"products\"" );
+ }
+ catch ( WrappedTargetException e ) { caughtExpected = true; }
+ catch ( IllegalArgumentException e ) {}
+ catch ( ElementExistException e ) { caughtExpected = true; }
+ assure( "creating queries with the name of an existing table should not be possible",
+ caughtExpected );
+
+ // create a table with a name which is used by a query
+ HsqlTableDescriptor table = new HsqlTableDescriptor( "query products",
+ new HsqlColumnDescriptor[] {
+ new HsqlColumnDescriptor( "ID", "INTEGER" ),
+ new HsqlColumnDescriptor( "Name", "VARCHAR(50)" ) } );
+
+ caughtExpected = false;
+ try
+ {
+ m_database.getDatabase().createTableInSDBCX( table );
+ }
+ catch ( SQLException e ) { caughtExpected = true; }
+ catch ( ElementExistException ex ) { }
+ assure( "creating tables with the name of an existing query should not be possible",
+ caughtExpected );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void checkCyclicReferences() throws ElementExistException, WrappedTargetException, IllegalArgumentException
+ {
+ // some queries which create a cycle in the sub query tree
+ m_database.getDatabase().getDataSource().createQuery( "orders level 1", "SELECT * FROM \"orders level 0\"" );
+ m_database.getDatabase().getDataSource().createQuery( "orders level 2", "SELECT * FROM \"orders level 1\"" );
+ m_database.getDatabase().getDataSource().createQuery( "orders level 3", "SELECT * FROM \"orders level 2\"" );
+ m_database.getDatabase().getDataSource().createQuery( "orders level 0", "SELECT * FROM \"orders level 3\"" );
+
+ RowSet rowSet = m_database.getDatabase().createRowSet( CommandType.QUERY, "orders level 0" );
+
+ boolean caughtExpected = false;
+ try { rowSet.execute(); }
+ catch ( SQLException e ) { caughtExpected = ( e.ErrorCode == -com.sun.star.sdb.ErrorCondition.PARSER_CYCLIC_SUB_QUERIES ); }
+
+ assure( "executing a query with cyclic nested sub queries should fail!", caughtExpected );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void checkStatementQiQSupport()
+ {
+ try
+ {
+ XStatement statement = m_database.getConnection().createStatement();
+ XResultSet resultSet = statement.executeQuery( "SELECT * FROM \"query products\"" );
+ }
+ catch( SQLException e )
+ {
+ assure( "SDB level statements do not allow for queries in queries", false );
+ }
+ }
+}
diff --git a/dbaccess/qa/complex/dbaccess/RowSet.java b/dbaccess/qa/complex/dbaccess/RowSet.java
new file mode 100644
index 000000000000..8e0161187c3e
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/RowSet.java
@@ -0,0 +1,955 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: RowSet.java,v $
+ * $Revision: 1.12 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+package complex.dbaccess;
+
+import com.sun.star.container.XIndexAccess;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.beans.*;
+import com.sun.star.lang.*;
+import com.sun.star.sdbcx.*;
+import com.sun.star.sdbc.*;
+import com.sun.star.sdb.*;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.util.XRefreshable;
+import connectivity.tools.HsqlDatabase;
+
+import complexlib.ComplexTestCase;
+import complexlib.Assurance.AssureException;
+
+
+public class RowSet extends ComplexTestCase {
+
+ static final int MAX_TABLE_ROWS = 100;
+ static final int MAX_FETCH_ROWS = 10;
+
+ HsqlDatabase m_database;
+ connectivity.tools.DataSource
+ m_dataSource;
+ XRowSet m_rowSet;
+ XResultSet m_resultSet;
+ XResultSetUpdate m_resultSetUpdate;
+ XRow m_row;
+ XRowLocate m_rowLocate;
+ XPropertySet m_rowSetProperties;
+ XParametersSupplier m_paramsSupplier;
+
+ // --------------------------------------------------------------------------------------------------------
+ class ResultSetMovementStress implements Runnable
+ {
+ XResultSet m_resultSet;
+ XRow m_row;
+ int m_id;
+ public ResultSetMovementStress(XResultSet _resultSet,int _id) throws java.lang.Exception {
+ m_resultSet = _resultSet;
+ m_row = (XRow)UnoRuntime.queryInterface(XRow.class,m_resultSet);
+ m_id = _id;
+ }
+ public void run()
+ {
+ try
+ {
+ m_resultSet.beforeFirst();
+ for ( int i = 0; m_resultSet.next(); ++i )
+ {
+ int pos = m_resultSet.getRow();
+ int val = m_row.getInt(1);
+// log.println("Clone Move(" + m_id +") before i: " + (i+1) + " Pos: " + pos + " Val: " + val);
+ testPosition( m_resultSet, m_row, i + 1, "clone move(" + m_id +")" );
+// val = m_row.getInt(1);
+// log.println("Clone Move(" + m_id +") after i: " + (i+1) + " Pos: " + pos + " Val: " + val);
+ int pos2 = m_resultSet.getRow();
+ assure("ResultSetMovementStress wrong position: " + i + " Pos1: " + pos + " Pos2: " + pos2,pos == pos2);
+ }
+ }catch(AssureException e){
+ }catch(Exception e){
+ assure("ResultSetMovementStress(" + m_id + ") failed: " + e,false);
+ }
+ }
+ }
+ // --------------------------------------------------------------------------------------------------------
+ public String[] getTestMethodNames() {
+ return new String[]
+ {
+ "testRowSet",
+ "testRowSetEvents",
+ "testDeleteBehavior",
+ "testCloneMovesPlusDeletions",
+ "testCloneMovesPlusInsertions",
+ "testParameters"
+ };
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public String getTestObjectName() {
+ return "RowSet";
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void createTestCase( boolean _defaultRowSet )
+ {
+ if ( m_database == null )
+ {
+ try
+ {
+ CRMDatabase database = new CRMDatabase( getFactory() );
+ m_database = database.getDatabase();
+ m_dataSource = m_database.getDataSource();
+ }
+ catch(Exception e)
+ {
+ assure( "could not create the embedded HSQL database: " + e.getMessage(), false );
+ }
+ }
+
+ try
+ {
+ createStruture();
+ }
+ catch( SQLException e )
+ {
+ assure( "could not connect to the database/table structure, error message:\n" + e.getMessage(), false );
+ }
+
+ if ( _defaultRowSet )
+ createRowSet( "TEST1", CommandType.TABLE, true, true );
+ }
+
+
+ // --------------------------------------------------------------------------------------------------------
+ private XMultiServiceFactory getFactory()
+ {
+ return (XMultiServiceFactory)param.getMSF();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ /** 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
+ */
+ private void createRowSet( String command, int commandType, boolean execute )
+ {
+ 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 limitFetchSize
+ * determines whether the fetch size of the RowSet should be limited to MAX_FETCH_ROWS
+ * @param execute
+ * determines whether the RowSet should be executed
+ */
+ private void createRowSet( String command, int commandType, boolean execute, boolean limitFetchSize )
+ {
+ try
+ {
+ m_rowSet = (XRowSet)UnoRuntime.queryInterface(XRowSet.class,
+ getFactory().createInstance("com.sun.star.sdb.RowSet"));
+ XPropertySet rowSetProperties = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class, m_rowSet );
+ rowSetProperties.setPropertyValue( "Command", command );
+ rowSetProperties.setPropertyValue( "CommandType", new Integer( commandType ) );
+ rowSetProperties.setPropertyValue( "ActiveConnection",m_database.defaultConnection() );
+ if ( limitFetchSize )
+ rowSetProperties.setPropertyValue( "FetchSize", new Integer( MAX_FETCH_ROWS ) );
+
+ m_resultSet = (XResultSet)UnoRuntime.queryInterface( XResultSet.class, m_rowSet );
+ m_resultSetUpdate = (XResultSetUpdate)UnoRuntime.queryInterface( XResultSetUpdate.class, m_rowSet );
+ m_row = (XRow)UnoRuntime.queryInterface( XRow.class, m_rowSet );
+ m_rowLocate = (XRowLocate)UnoRuntime.queryInterface( XRowLocate.class, m_resultSet );
+ m_rowSetProperties = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class, m_rowSet );
+ m_paramsSupplier = (XParametersSupplier)UnoRuntime.queryInterface( XParametersSupplier.class, m_rowSet );
+
+ if ( execute )
+ m_rowSet.execute();
+ }
+ catch ( java.lang.Exception e )
+ {
+ assure( "caught an exception while creating the RowSet. Type:\n" + e.getClass().toString() + "\nMessage:\n" + e.getMessage(), false );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void testRowSet() throws java.lang.Exception {
+
+ log.println("testing testRowSet");
+ createTestCase( true );
+
+ // sequential postioning
+ m_resultSet.beforeFirst();
+ testSequentialPositining(m_resultSet,m_row);
+
+ // absolute positioning
+ testAbsolutePositioning(m_resultSet,m_row);
+
+ // 3rd test
+ test3(createClone(),m_resultSet);
+ // 4th test
+ test4(m_resultSet);
+
+ // concurrent (multi threaded) access to the row set and its clones
+ testConcurrentAccess(m_resultSet);
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ XResultSet createClone() throws SQLException
+ {
+ XResultSetAccess rowAcc = (XResultSetAccess)UnoRuntime.queryInterface( XResultSetAccess.class, m_rowSet );
+ return rowAcc.createResultSet();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ void createStruture() throws SQLException
+ {
+ m_database.executeSQL( "DROP TABLE \"TEST1\" IF EXISTS" );
+ m_database.executeSQL( "CREATE TABLE \"TEST1\" (\"ID\" integer not null primary key, \"col2\" varchar(50) )" );
+
+ XConnection connection = m_database.defaultConnection();
+ XPreparedStatement prep = connection.prepareStatement("INSERT INTO \"TEST1\" values (?,?)");
+ XParameters para = (XParameters)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();
+ }
+
+ XTablesSupplier suppTables = (XTablesSupplier)UnoRuntime.queryInterface( XTablesSupplier.class, connection );
+ XRefreshable refresh = (XRefreshable)UnoRuntime.queryInterface( XRefreshable.class, suppTables.getTables() );
+ refresh.refresh();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ void testPosition(XResultSet m_resultSet,XRow m_row,int expectedValue,String location) throws SQLException
+ {
+ int val = m_row.getInt(1);
+ int pos = m_resultSet.getRow();
+ assure( location + ": value/position do not match: " + pos + " (pos) != " + val + " (val)", val == pos );
+ assure( location + ": value/position are not as expected: " + val + " (val) != " + expectedValue + " (expected)", val == expectedValue );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ void testSequentialPositining(XResultSet _resultSet,XRow _row)
+ {
+ try
+ {
+ // 1st test
+ int i=1;
+ while(_resultSet.next())
+ {
+ testPosition( _resultSet, _row, i, "testSequentialPositining" );
+ ++i;
+ }
+ }
+ catch(AssureException e)
+ {
+ }
+ catch(Exception e)
+ {
+ assure("testSequentialPositining failed: " + e,false);
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ void testAbsolutePositioning(XResultSet _resultSet,XRow _row){
+ try{
+ for(int i = 1 ; i <= MAX_FETCH_ROWS ; ++i){
+ int calcPos = (MAX_TABLE_ROWS % i) + 1;
+ assure( "testAbsolutePositioning failed", _resultSet.absolute(calcPos) );
+ testPosition( _resultSet, _row, calcPos, "testAbsolutePositioning" );
+ }
+ }catch(AssureException e){
+ }catch(Exception e){
+ assure("testAbsolutePositioning failed: " + e,false);
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ void test3(XResultSet clone,XResultSet _resultSet){
+ try{
+ XRow _row = (XRow)UnoRuntime.queryInterface(XRow.class,_resultSet);
+ XRow cloneRow = (XRow)UnoRuntime.queryInterface(XRow.class,clone);
+ for(int i = 1 ; i <= MAX_FETCH_ROWS ; ++i){
+ int calcPos = (MAX_TABLE_ROWS % i) + 1;
+ if ( clone.absolute(calcPos) )
+ {
+ testPosition( clone, cloneRow, calcPos, "test3" );
+ testAbsolutePositioning(_resultSet,_row);
+ testAbsolutePositioning(clone,cloneRow);
+ }
+ }
+ }catch(AssureException e){
+ }catch(Exception e){
+ assure("test3 failed: " + e,false);
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ void test4(XResultSet _resultSet){
+ try{
+ XRow _row = (XRow)UnoRuntime.queryInterface(XRow.class,_resultSet);
+ _resultSet.beforeFirst();
+
+ for(int i = 1 ; i <= MAX_TABLE_ROWS ; ++i){
+ _resultSet.next();
+ XResultSet clone = createClone();
+ XRow cloneRow = (XRow)UnoRuntime.queryInterface(XRow.class,clone);
+ int calcPos = MAX_TABLE_ROWS - 1;
+ if ( calcPos != 0 && clone.absolute(calcPos) )
+ {
+ testPosition( clone, cloneRow, calcPos, "test4: clone" );
+ testPosition( _resultSet, _row, i, "test4: rowset" );
+ }
+ }
+ }catch(AssureException e){
+ }catch(Exception e){
+ assure("test4 failed: " + e,false);
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ void testConcurrentAccess(XResultSet _resultSet)
+ {
+ log.println("testing Thread");
+ try
+ {
+ XRow _row = (XRow)UnoRuntime.queryInterface(XRow.class,_resultSet);
+ _resultSet.beforeFirst();
+
+ final int numberOfThreads = 10;
+
+ Thread threads[] = new Thread[numberOfThreads];
+ for ( int i=0; i<numberOfThreads; ++i )
+ {
+ threads[i] = new Thread( new ResultSetMovementStress( createClone(), i ) );
+ System.out.println( "starting thread " + String.valueOf(i+1) + " of " + String.valueOf( numberOfThreads ) );
+ threads[i].start();
+ }
+
+ for ( int i=0; i<numberOfThreads; ++i )
+ threads[i].join();
+ }
+ catch(AssureException e)
+ {
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ assure("testConcurrentAccess failed: " + e,false);
+ }
+ }
+ // --------------------------------------------------------------------------------------------------------
+ public void testRowSetEvents() throws java.lang.Exception {
+ log.println("testing RowSet Events");
+ createTestCase( true );
+
+ // first we create our RowSet object
+ RowSetEventListener pRow = new RowSetEventListener(this);
+
+ XColumnsSupplier colSup = (XColumnsSupplier)UnoRuntime.queryInterface(XColumnsSupplier.class,m_rowSet);
+ XPropertySet col = (XPropertySet)UnoRuntime.queryInterface(XPropertySet.class,colSup.getColumns().getByName("ID"));
+ col.addPropertyChangeListener("Value", pRow);
+ m_rowSetProperties.addPropertyChangeListener("IsModified", pRow);
+ m_rowSetProperties.addPropertyChangeListener("IsNew", pRow);
+ m_rowSetProperties.addPropertyChangeListener("IsRowCountFinal", pRow);
+ m_rowSetProperties.addPropertyChangeListener("RowCount", pRow);
+
+ XRowSetApproveBroadcaster xApBroad = (XRowSetApproveBroadcaster)UnoRuntime.queryInterface(XRowSetApproveBroadcaster.class,m_resultSet);
+ xApBroad.addRowSetApproveListener(pRow);
+ m_rowSet.addRowSetListener(pRow);
+
+ // do some movements to check if we got all notifications
+ Class cResSet = java.lang.Class.forName("com.sun.star.sdbc.XResultSet");
+ boolean moves[] = new boolean[9];
+ for( int i = 0; i < moves.length; ++i)
+ moves[i] = false;
+ moves[RowSetEventListener.APPROVE_CURSOR_MOVE] = true;
+ moves[RowSetEventListener.COLUMN_VALUE] = true;
+ moves[RowSetEventListener.CURSOR_MOVED] = true;
+ moves[RowSetEventListener.IS_ROW_COUNT_FINAL] = true;
+ moves[RowSetEventListener.ROW_COUNT] = true;
+
+ testCursorMove(m_resultSet,cResSet.getMethod("afterLast",(Class[])null),pRow,moves,null);
+
+ moves[RowSetEventListener.IS_ROW_COUNT_FINAL] = false;
+ moves[RowSetEventListener.ROW_COUNT] = false;
+ testCursorMove(m_resultSet,cResSet.getMethod("next",(Class[])null),pRow,moves,null);
+ testCursorMove(m_resultSet,cResSet.getMethod("next",(Class[])null),pRow,moves,null);
+ testCursorMove(m_resultSet,cResSet.getMethod("next",(Class[])null),pRow,moves,null);
+ testCursorMove(m_resultSet,cResSet.getMethod("last",(Class[])null),pRow,moves,null);
+ testCursorMove(m_resultSet,cResSet.getMethod("next",(Class[])null),pRow,moves,null);
+ testCursorMove(m_resultSet,cResSet.getMethod("first",(Class[])null),pRow,moves,null);
+ testCursorMove(m_resultSet,cResSet.getMethod("previous",(Class[])null),pRow,moves,null);
+ testCursorMove(m_resultSet,cResSet.getMethod("next",(Class[])null),pRow,moves,null);
+ moves[RowSetEventListener.IS_MODIFIED] = true;
+ XRowUpdate updRow = (XRowUpdate)UnoRuntime.queryInterface(XRowUpdate.class,m_resultSet);
+ updRow.updateString(2,"Test21");
+ testCursorMove(m_resultSet,cResSet.getMethod("next",(Class[])null),pRow,moves,null);
+
+ moves[RowSetEventListener.IS_MODIFIED] = false;
+ Class cupd = java.lang.Class.forName("com.sun.star.sdbc.XResultSetUpdate");
+ XResultSetUpdate upd = (XResultSetUpdate)UnoRuntime.queryInterface(XResultSetUpdate.class,m_resultSet);
+ testCursorMove(upd,cupd.getMethod("moveToInsertRow",(Class[])null),pRow,moves,null);
+
+ updRow.updateInt(1, MAX_TABLE_ROWS + 2);
+ updRow.updateString(2, "HHHH");
+ moves[RowSetEventListener.APPROVE_CURSOR_MOVE] = false;
+ moves[RowSetEventListener.CURSOR_MOVED] = false;
+ moves[RowSetEventListener.IS_MODIFIED] = true;
+ moves[RowSetEventListener.IS_NEW] = true;
+ moves[RowSetEventListener.ROW_COUNT] = true;
+ moves[RowSetEventListener.APPROVE_ROW_CHANGE] = true;
+ moves[RowSetEventListener.ROW_CHANGED] = true;
+ testCursorMove(upd,cupd.getMethod("insertRow",(Class[])null),pRow,moves,null);
+
+ moves[RowSetEventListener.IS_NEW] = false;
+ moves[RowSetEventListener.ROW_COUNT] = false;
+ m_resultSet.first();
+ updRow.updateInt(1, MAX_TABLE_ROWS + 3);
+ updRow.updateString(2, "__");
+ testCursorMove(upd,cupd.getMethod("updateRow",(Class[])null),pRow,moves,null);
+
+ moves[RowSetEventListener.IS_NEW] = true;
+ moves[RowSetEventListener.ROW_COUNT] = true;
+ m_resultSet.first();
+ testCursorMove(upd,cupd.getMethod("deleteRow",(Class[])null),pRow,moves,null);
+
+ moves[RowSetEventListener.IS_NEW] = false;
+ moves[RowSetEventListener.COLUMN_VALUE] = true;
+ moves[RowSetEventListener.ROW_COUNT] = false;
+ m_resultSet.first();
+ updRow.updateString(2,"Test21");
+ testCursorMove(m_resultSet,cResSet.getMethod("refreshRow",(Class[])null),pRow,moves,null);
+
+ m_resultSet.first();
+ updRow.updateString(2,"Test21");
+ testCursorMove(upd,cupd.getMethod("cancelRowUpdates",(Class[])null),pRow,moves,null);
+
+ for( int i = 0; i < moves.length; ++i)
+ moves[i] = false;
+ moves[RowSetEventListener.APPROVE_CURSOR_MOVE] = true;
+ moves[RowSetEventListener.COLUMN_VALUE] = true;
+ moves[RowSetEventListener.CURSOR_MOVED] = true;
+
+ Class cloc = java.lang.Class.forName("com.sun.star.sdbcx.XRowLocate");
+ m_resultSet.first();
+ Object bookmark = m_rowLocate.getBookmark();
+ m_resultSet.next();
+ Object temp[] = new Object[1];
+ temp[0] = bookmark;
+ Class ctemp[] = new Class[1];
+ ctemp[0] = Object.class;
+ testCursorMove(m_rowLocate,cloc.getMethod("moveToBookmark",ctemp),pRow,moves,temp);
+
+ Object temp2[] = new Object[2];
+ temp2[0] = bookmark;
+ temp2[1] = new Integer(1);
+ Class ctemp2[] = new Class[2];
+ ctemp2[0] = Object.class;
+ ctemp2[1] = int.class;
+ testCursorMove(m_rowLocate,cloc.getMethod("moveRelativeToBookmark",ctemp2),pRow,moves,temp2);
+
+ for( int i = 0; i < moves.length; ++i)
+ moves[i] = false;
+ moves[RowSetEventListener.APPROVE_ROW_CHANGE] = true;
+ moves[RowSetEventListener.ROW_CHANGED] = true;
+ moves[RowSetEventListener.ROW_COUNT] = true;
+ Class cdelRows = java.lang.Class.forName("com.sun.star.sdbcx.XDeleteRows");
+ ctemp[0] = Object[].class;
+ XDeleteRows delRows = (XDeleteRows)UnoRuntime.queryInterface(XDeleteRows.class,m_resultSet);
+ Object bookmarks[] = new Object[5];
+ m_resultSet.first();
+ for ( int i = 0; i < bookmarks.length ; ++i ){
+ m_resultSet.next();
+ bookmarks[i] = m_rowLocate.getBookmark();
+ }
+
+ temp[0] = bookmarks;
+ testCursorMove(delRows,cdelRows.getMethod("deleteRows",ctemp),pRow,moves,temp);
+
+ // now destroy the RowSet
+ XComponent xComp = (XComponent)UnoRuntime.queryInterface(XComponent.class,m_resultSet);
+ xComp.dispose();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void testCursorMove(Object res
+ ,java.lang.reflect.Method _method
+ , RowSetEventListener _evt
+ , boolean _must[]
+ , Object args[]) throws java.lang.Exception {
+ _evt.clearCalling();
+ _method.invoke(res,args);
+
+ log.println("testing events for " + _method.getName());
+ int calling[] = _evt.getCalling();
+ int pos = 1;
+ assure("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++ );
+ assure("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++);
+ assure("Callings are not in the correct order for COLUMN_VALUE" ,
+ ( !_must[RowSetEventListener.COLUMN_VALUE] || calling[RowSetEventListener.COLUMN_VALUE] == -1) || calling[RowSetEventListener.COLUMN_VALUE] == pos++);
+ assure("Callings are not in the correct order for CURSOR_MOVED" ,
+ ( !_must[RowSetEventListener.CURSOR_MOVED] || calling[RowSetEventListener.CURSOR_MOVED] == -1) || calling[RowSetEventListener.CURSOR_MOVED] == pos++);
+ assure("Callings are not in the correct order for ROW_CHANGED" ,
+ ( !_must[ RowSetEventListener.ROW_CHANGED] || calling[RowSetEventListener.ROW_CHANGED] == -1) || calling[RowSetEventListener.ROW_CHANGED] == pos++);
+ assure("Callings are not in the correct order for IS_MODIFIED" ,
+ ( !_must[ RowSetEventListener.IS_MODIFIED] || calling[RowSetEventListener.IS_MODIFIED] == -1) || calling[RowSetEventListener.IS_MODIFIED] == pos++);
+ assure("Callings are not in the correct order for IS_NEW" ,
+ ( !_must[ RowSetEventListener.IS_NEW] || calling[RowSetEventListener.IS_NEW] == -1) || calling[RowSetEventListener.IS_NEW] == pos++);
+ assure("Callings are not in the correct order for ROW_COUNT" ,
+ ( !_must[ RowSetEventListener.ROW_COUNT] || calling[RowSetEventListener.ROW_COUNT] == -1) || calling[RowSetEventListener.ROW_COUNT] == pos++);
+ assure("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
+ */
+ private int currentRowCount() throws UnknownPropertyException, WrappedTargetException
+ {
+ 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)
+ */
+ private int positionRandom() throws SQLException, UnknownPropertyException, WrappedTargetException
+ {
+ int position = (new java.util.Random()).nextInt( currentRowCount() - 2 ) + 2;
+ assure( "sub task failed: could not position to row no. " + (new Integer( 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
+ */
+ private int 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)
+ int positionBefore = positionRandom();
+ int rowCountBefore = currentRowCount();
+
+ m_resultSetUpdate.deleteRow();
+
+ int positionAfter = m_resultSet.getRow();
+ int rowCountAfter = currentRowCount();
+ assure( "position changed during |deleteRow| (it should not)", positionAfter == positionBefore );
+ assure( "row count changed with a |deleteRow| (it should not)", rowCountBefore == rowCountAfter );
+ assure( "RowSet does not report the current row as deleted after |deleteRow|", m_resultSet.rowDeleted() );
+
+ return positionBefore;
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void testDeleteBehavior() throws Exception
+ {
+ createTestCase( true );
+
+ // ensure that all records are known
+ m_resultSet.last();
+ int 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; }
+ assure( "asking for the bookmark of a deleted row should throw an exception", caughtException );
+
+ // .....................................................................................................
+ // isXXX methods should return |false| on a deleted row
+ assure( "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
+ assure( "|previous| after |deleteRow| failed", m_resultSet.previous() );
+ int positionPrevious = m_resultSet.getRow();
+ assure( "position after |previous| after |deleteRow| is not as expected", positionPrevious == deletedRow - 1 );
+
+ deletedRow = deleteRandom();
+ assure( "|next| after |deleteRow| failed", m_resultSet.next() );
+ int positionAfter = m_resultSet.getRow();
+ assure( "position after |next| after |deleteRow| is not as expected", positionAfter == deletedRow );
+ // since the deleted record "vanishs" 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
+ assure( "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
+ int rowCountBefore = currentRowCount();
+ int deletedPos = deleteRandom();
+ m_resultSetUpdate.moveToInsertRow();
+ assure( "moving to the insertion row immediately after |deleteRow| does not adjust the row count", rowCountBefore == currentRowCount() + 1 );
+
+ m_resultSetUpdate.moveToCurrentRow();
+ assure( "|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();
+ assure( "|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; }
+ assure( "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();
+ Object firstBookmark = m_rowLocate.getBookmark();
+ positionRandom();
+ Object deleteBookmark = m_rowLocate.getBookmark();
+ m_resultSetUpdate.deleteRow();
+ XDeleteRows multiDelete = (XDeleteRows)UnoRuntime.queryInterface( XDeleteRows.class, m_resultSet );
+ int[] deleteSuccess = multiDelete.deleteRows(new Object[]{firstBookmark, deleteBookmark});
+ assure( "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; }
+ assure( "refreshing a deleted row succeeded - it shouldn't", caughtException );
+
+ // .....................................................................................................
+ // rowUpdated/rowDeleted
+ deleteRandom();
+ assure( "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();
+ XRowUpdate rowUpdated = (XRowUpdate)UnoRuntime.queryInterface( XRowUpdate.class, m_resultSet );
+ caughtException = false;
+ try { rowUpdated.updateString( 2, "Test21" ); }
+ catch( SQLException e ) { caughtException = true; }
+ assure( "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
+ */
+ public void testCloneMovesPlusDeletions() throws SQLException, UnknownPropertyException, WrappedTargetException
+ {
+ createTestCase( true );
+ // ensure that all records are known
+ m_resultSet.last();
+
+ XResultSet clone = createClone();
+ XRowLocate cloneRowLocate = (XRowLocate)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() );
+ int clonePosition = clone.getRow();
+ m_resultSetUpdate.deleteRow();
+
+ assure( "clone doesn't know that its current row has been deleted via the RowSet", clone.rowDeleted() );
+ assure( "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();
+
+ assure( "clone doesn't know (anymore) that its current row has been deleted via the RowSet", clone.rowDeleted() );
+ assure( "clone's position changed somehow during deletion and RowSet-movement", clonePosition == clone.getRow() );
+
+ // .....................................................................................................
+ // move the clone away from the deleted record
+ clone.next();
+ assure( "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();
+ assure( "deleting the first record left the clone in a strange state (after |previous|)", clone.isBeforeFirst() );
+ clone.next();
+ assure( "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();
+ assure( "deleting the last record left the clone in a strange state (after |next|)", clone.isAfterLast() );
+ clone.previous();
+ assure( "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
+ int positionBefore = positionRandom();
+ m_resultSetUpdate.deleteRow();
+ assure( "|deleteRow|, but no |rowDeleted| (this should have been found much earlier!)", m_resultSet.rowDeleted() );
+ clone.beforeFirst();
+ while ( clone.next() )
+ ;
+ assure( "row set forgot that the current row is deleted", m_resultSet.rowDeleted() );
+
+ assure( "moving to the next record after |deleteRow| and clone moves failed", m_resultSet.next() );
+ assure( "wrong position after |deleteRow| and clone movement", !m_resultSet.isAfterLast() && !m_resultSet.isBeforeFirst() );
+ assure( "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
+ */
+ public void testCloneMovesPlusInsertions() throws SQLException, UnknownPropertyException, WrappedTargetException, PropertyVetoException, com.sun.star.lang.IllegalArgumentException
+ {
+ createTestCase( true );
+ // ensure that all records are known
+ m_rowSetProperties.setPropertyValue( "FetchSize", new Integer( 10 ) );
+
+ XResultSet clone = createClone();
+ XRow cloneRow = (XRow)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();
+
+ int rowValue1 = m_row.getInt(1);
+ int rowPos = m_resultSet.getRow();
+ int rowValue2 = m_row.getInt(1);
+ assure( "repeated query for the same column value delivers different values (" + rowValue1 + " and " + rowValue2 + ") on row: " + rowPos,
+ rowValue1 == rowValue2 );
+
+ testPosition( clone, cloneRow, 1, "mixed clone/rowset move: clone check" );
+ testPosition( m_resultSet, m_row, MAX_TABLE_ROWS, "mixed clone/rowset move: rowset check" );
+
+ // .....................................................................................................
+ // now the complete scenario
+ m_resultSet.last();
+ m_resultSetUpdate.moveToInsertRow();
+ clone.first();
+ clone.absolute( 11 );
+ clone.first();
+ m_resultSetUpdate.moveToCurrentRow();
+
+ testPosition( clone, cloneRow, 1, "mixed clone/rowset move/insertion: clone check" );
+ testPosition( m_resultSet, m_row, 100, "mixed clone/rowset move/insertion: rowset check" );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void testTableParameters()
+ {
+ // for a row set simply based on a table, there should be not parameters at all
+ createRowSet( "products", CommandType.TABLE, false );
+ try
+ {
+ verifyParameters( new String[] {}, "testTableParameters" );
+ }
+ catch( AssureException e ) { throw e; }
+ catch( Exception e )
+ {
+ assure( "testing the parameters of a table failed" + e.getMessage(), false );
+ }
+ }
+ // --------------------------------------------------------------------------------------------------------
+ private void testParametersAfterNormalExecute()
+ {
+ try
+ {
+ createRowSet( "SELECT * FROM \"customers\"", CommandType.COMMAND, true );
+ m_rowSetProperties.setPropertyValue( "Command", "SELECT * FROM \"customers\" WHERE \"City\" = :city");
+ XParameters rowsetParams = (XParameters)UnoRuntime.queryInterface( XParameters.class,
+ m_rowSet );
+ rowsetParams.setString( 1, "London" );
+ m_rowSet.execute();
+ }
+ catch( AssureException e ) { throw e; }
+ catch( Exception e )
+ {
+ assure( "testing the parameters of a table failed" + e.getMessage(), false );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void verifyParameters( String[] _paramNames, String _context ) throws com.sun.star.uno.Exception
+ {
+ XIndexAccess params = m_paramsSupplier.getParameters();
+ int expected = _paramNames.length;
+ int found = params != null ? params.getCount() : 0;
+
+ assure( "wrong number of parameters (expected: " + expected + ", found: " + found + ") in " + _context,
+ found == expected );
+
+ if ( found == 0 )
+ return;
+
+ for ( int i=0; i<expected; ++i )
+ {
+ XPropertySet parameter = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class,
+ params.getByIndex(i) );
+
+ String expectedName = _paramNames[i];
+ String foundName = (String)parameter.getPropertyValue( "Name" );
+ assure( "wrong parameter name (expected: " + expectedName + ", found: " + foundName + ") in" + _context,
+ expectedName.equals( foundName ) );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void testParametrizedQuery()
+ {
+ try
+ {
+ // 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" );
+ }
+ catch( AssureException e ) { throw e; }
+ catch( Exception e )
+ {
+ assure( "testing the parameters of a parametrized query failed" + e.getMessage(), false );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void testParametersInteraction()
+ {
+ try
+ {
+ createRowSet( "products like", CommandType.QUERY, false );
+
+ // let's fill in a parameter value via XParameters, and see whether it is respected by the parameters container
+ XParameters rowsetParams = (XParameters)UnoRuntime.queryInterface( XParameters.class,
+ m_rowSet );
+ rowsetParams.setString( 1, "Apples" );
+
+ XIndexAccess params = m_paramsSupplier.getParameters();
+ XPropertySet firstParam = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class, params.getByIndex(0) );
+ Object firstParamValue = firstParam.getPropertyValue( "Value" );
+
+ assure( "XParameters and the parameters container do not properly interact",
+ firstParamValue.equals( "Apples" ) );
+
+ // let's see whether this also survices 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 = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class, params.getByIndex(0) );
+ }
+ firstParamValue = firstParam.getPropertyValue( "Value" );
+ assure( "XParameters and the parameters container do not properly interact, after the row set has been executed",
+ firstParamValue.equals( "Oranges" ) );
+ }
+ catch( AssureException e ) { throw e; }
+ catch( Exception e )
+ {
+ assure( "could not text the relationship between XParameters and XParametersSupplier" + e.getMessage(), false );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void testParametersInFilter()
+ {
+ try
+ {
+ createRowSet( "SELECT * FROM \"customers\"", CommandType.COMMAND, false );
+ m_rowSetProperties.setPropertyValue( "Filter", "\"City\" = :city" );
+
+ m_rowSetProperties.setPropertyValue( "ApplyFilter", new Boolean( true ) );
+ verifyParameters( new String[] { "city" }, "testParametersInFilter" );
+
+ m_rowSetProperties.setPropertyValue( "ApplyFilter", new Boolean( false ) );
+ verifyParameters( new String[] {}, "testParametersInFilter" );
+ }
+ catch( AssureException e ) { throw e; }
+ catch( Exception e )
+ {
+ assure( "testing the parameters within a WHERE clause failed" + e.getMessage(), false );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ /** checks the XParametersSupplier functionality of a RowSet
+ */
+ public void testParameters()
+ {
+ createTestCase( false );
+ // use an own RowSet instance, not the one which is also used for the other cases
+
+ testTableParameters();
+ testParametrizedQuery();
+ testParametersInFilter();
+
+ testParametersAfterNormalExecute();
+
+ testParametersInteraction();
+ }
+}
+
diff --git a/dbaccess/qa/complex/dbaccess/RowSetEventListener.java b/dbaccess/qa/complex/dbaccess/RowSetEventListener.java
new file mode 100644
index 000000000000..774947ecc2dc
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/RowSetEventListener.java
@@ -0,0 +1,116 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: RowSetEventListener.java,v $
+ * $Revision: 1.4 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+package complex.dbaccess;
+
+import com.sun.star.sdb.XRowSetApproveListener;
+import com.sun.star.sdbc.XRowSetListener;
+import com.sun.star.sdb.RowChangeEvent;
+import com.sun.star.lang.EventObject;
+import com.sun.star.beans.XPropertyChangeListener;
+
+public class RowSetEventListener implements XRowSetApproveListener,XRowSetListener,XPropertyChangeListener
+{
+ public static final int APPROVE_CURSOR_MOVE = 0;
+ public static final int APPROVE_ROW_CHANGE = 1;
+ public static final int COLUMN_VALUE = 2;
+ public static final int CURSOR_MOVED = 3;
+ public static final int ROW_CHANGED = 4;
+ public static final int IS_MODIFIED = 5;
+ public static final int IS_NEW = 6;
+ public static final int ROW_COUNT = 7;
+ public static final int IS_ROW_COUNT_FINAL = 8;
+
+ RowSet rowset;
+ int callPos = 1;
+ int calling [];
+
+ RowSetEventListener(RowSet _rowset){
+ rowset = _rowset;
+ calling = new int [9];
+ clearCalling();
+ }
+ public int[] getCalling(){
+ return calling;
+ }
+ public void clearCalling(){
+ for(int i = 0 ; i < calling.length; ++i){
+ calling[i] = -1;
+ }
+ callPos = 1;
+ }
+ // XEventListener
+ public void disposing(com.sun.star.lang.EventObject event)
+ {
+ }
+ // XRowSetApproveBroadcaster
+ public boolean approveCursorMove(EventObject event)
+ {
+ calling[APPROVE_CURSOR_MOVE] = callPos++;
+ return true;
+ }
+ public boolean approveRowChange(RowChangeEvent event)
+ {
+ calling[APPROVE_ROW_CHANGE] = callPos++;
+ return true;
+ }
+ public boolean approveRowSetChange(EventObject event)
+ {
+ return true;
+ }
+
+ // XRowSetListener
+ public void cursorMoved(com.sun.star.lang.EventObject event)
+ {
+ calling[CURSOR_MOVED] = callPos++;
+ }
+ public void rowChanged(com.sun.star.lang.EventObject event)
+ {
+ calling[ROW_CHANGED] = callPos++;
+ }
+ public void rowSetChanged(com.sun.star.lang.EventObject event)
+ {
+ }
+
+ public void propertyChange(com.sun.star.beans.PropertyChangeEvent propertyChangeEvent) {
+ if ( propertyChangeEvent.PropertyName.equals("Value") ){
+ calling[COLUMN_VALUE] = callPos++;
+ } else if ( propertyChangeEvent.PropertyName.equals("IsModified") ){
+ calling[IS_MODIFIED] = callPos++;
+ } else if ( propertyChangeEvent.PropertyName.equals("IsNew") ){
+ calling[IS_NEW] = callPos++;
+ } else if ( propertyChangeEvent.PropertyName.equals("RowCount") ){
+ calling[ROW_COUNT] = callPos++;
+ } else if ( propertyChangeEvent.PropertyName.equals("IsRowCountFinal") ){
+ calling[IS_ROW_COUNT_FINAL] = callPos++;
+ }
+ }
+
+}
diff --git a/dbaccess/qa/complex/dbaccess/SingleSelectQueryComposer.java b/dbaccess/qa/complex/dbaccess/SingleSelectQueryComposer.java
new file mode 100755
index 000000000000..c73ce6496c88
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/SingleSelectQueryComposer.java
@@ -0,0 +1,314 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: SingleSelectQueryComposer.java,v $
+ * $Revision: 1.8.14.1 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+package complex.dbaccess;
+
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.beans.*;
+import com.sun.star.sdbcx.*;
+import com.sun.star.sdbc.*;
+import com.sun.star.sdb.*;
+import com.sun.star.container.*;
+import com.sun.star.lang.XMultiServiceFactory;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class SingleSelectQueryComposer extends CRMBasedTestCase
+{
+ private XSingleSelectQueryComposer m_composer;
+
+ private final String complexFilter = "( \"ID\" = 1 AND \"Postal\" = '4' )" +
+ " OR ( \"ID\" = 2 AND \"Postal\" = '5' )" +
+ " OR ( \"ID\" = '3' AND \"Postal\" = '6' AND \"Address\" = '7' )" +
+ " OR ( \"Address\" = '8' )" +
+ " OR ( \"Postal\" = '9' )";
+ private final String innerProductsQuery = "products (inner)";
+
+ // --------------------------------------------------------------------------------------------------------
+ public String[] getTestMethodNames()
+ {
+ return new String[] {
+ "testAttributes",
+ "testSubQueries",
+ "testParameters",
+ "testDisjunctiveNormalForm"
+ };
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public String getTestObjectName()
+ {
+ return "SingleSelectQueryComposer";
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void createQueries() throws Exception
+ {
+ m_database.getDatabase().getDataSource().createQuery( innerProductsQuery, "SELECT * FROM \"products\"" );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ protected void createTestCase()
+ {
+ try
+ {
+ super.createTestCase();
+
+ createQueries();
+
+ m_composer = createQueryComposer();
+
+ }
+ catch ( Exception e )
+ {
+ assure( "caught an exception (" + e.getMessage() + ") while creating the test case", false );
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ private void checkAttributeAccess( String _attributeName, String _attributeValue )
+ {
+ log.println( "setting " + _attributeName + " to " + _attributeValue );
+ String realValue = null;
+ try
+ {
+ Class composerClass = m_composer.getClass();
+ Method attributeGetter = composerClass.getMethod( "get" + _attributeName, new Class[] {} );
+ Method attributeSetter = composerClass.getMethod( "set" + _attributeName, new Class[] { String.class } );
+
+ attributeSetter.invoke( m_composer, new Object[] { _attributeValue } );
+ realValue = (String)attributeGetter.invoke( m_composer, new Object[] {} );
+ }
+ catch ( NoSuchMethodException e ) { }
+ catch ( IllegalAccessException e ) { }
+ catch ( InvocationTargetException e ) { }
+ assure( "set/get" + _attributeName + " not working as expected (set: " + _attributeValue + ", get: " + ( realValue != null ? realValue : "null" ) + ")",
+ realValue.equals( _attributeValue ) );
+ log.println( " (results in " + (String)m_composer.getQuery() + ")" );
+ }
+
+ /** tests accessing attributes of the composer (order, filter, group by, having)
+ */
+ public void testAttributes()
+ {
+ log.println("testing SingleSelectQueryComposer's attributes (order, filter, group by, having)");
+
+ try
+ {
+ log.println("check setQuery");
+ final String simpleQuery = "SELECT * FROM \"customers\"";
+ m_composer.setQuery( simpleQuery );
+ assure( "set/getQuery inconsistent", m_composer.getQuery().equals( simpleQuery ) );
+
+ checkAttributeAccess( "Filter", "\"Name\" = 'oranges'" );
+ checkAttributeAccess( "Group", "\"City\"" );
+ checkAttributeAccess( "Order", "\"Address\"" );
+ checkAttributeAccess( "HavingClause", "\"ID\" <> 4" );
+
+ XIndexAccess orderColumns = m_composer.getOrderColumns();
+ assure( "Order columns doesn't exist: \"Address\"",
+ orderColumns != null && orderColumns.getCount() == 1 && orderColumns.getByIndex(0) != null );
+
+ XIndexAccess groupColumns = m_composer.getGroupColumns();
+ assure( "Group columns doesn't exist: \"City\"",
+ groupColumns != null && groupColumns.getCount() == 1 && groupColumns.getByIndex(0) != null );
+
+ // XColumnsSupplier
+ XColumnsSupplier xSelectColumns = (XColumnsSupplier)
+ UnoRuntime.queryInterface(XColumnsSupplier.class,m_composer);
+ assure( "no select columns, or wrong number of select columns",
+ xSelectColumns != null && xSelectColumns.getColumns() != null && xSelectColumns.getColumns().getElementNames().length == 5 );
+
+ // structured filter
+ m_composer.setQuery("SELECT \"ID\", \"Postal\", \"Address\" FROM \"customers\"");
+ m_composer.setFilter(complexFilter);
+ PropertyValue[][] aStructuredFilter = m_composer.getStructuredFilter();
+ m_composer.setFilter("");
+ m_composer.setStructuredFilter(aStructuredFilter);
+ assure("Structured Filter not identical" , m_composer.getFilter().equals(complexFilter));
+
+ // structured having clause
+ m_composer.setHavingClause(complexFilter);
+ PropertyValue[][] aStructuredHaving = m_composer.getStructuredHavingClause();
+ m_composer.setHavingClause("");
+ m_composer.setStructuredHavingClause(aStructuredHaving);
+ assure("Structured Having Clause not identical" , m_composer.getHavingClause().equals(complexFilter));
+ }
+ catch(Exception e)
+ {
+ assure("Exception caught: " + e,false);
+ }
+ }
+
+ /** test various sub query related features ("queries in queries")
+ */
+ public void testSubQueries() throws Exception
+ {
+ m_composer.setQuery( "SELECT * from \"" + innerProductsQuery + "\"" );
+ final XTablesSupplier suppTables = (XTablesSupplier)UnoRuntime.queryInterface(
+ XTablesSupplier.class, m_composer );
+ final XNameAccess tables = suppTables.getTables();
+ assure( "a simple SELECT * FROM <query> could not be parsed",
+ tables != null && tables.hasByName( innerProductsQuery ) );
+
+ final String sInnerCommand = m_database.getDatabase().getDataSource().getQueryDefinition( innerProductsQuery ).getCommand();
+ final String sExecutableQuery = m_composer.getQueryWithSubstitution();
+ assure( "simple query containing a sub query improperly parsed to SDBC level statement: \n1. " + sExecutableQuery
+ + "\n2. " + "SELECT * FROM ( " + sInnerCommand + " ) AS \"" + innerProductsQuery + "\"",
+ sExecutableQuery.equals( "SELECT * FROM ( " + sInnerCommand + " ) AS \"" + innerProductsQuery + "\"") );
+ }
+
+ /** tests the XParametersSupplier functionality
+ */
+ public void testParameters()
+ {
+ try
+ {
+ // "orders for customers" is a query with a named parameter (based on another query)
+ m_database.getDatabase().getDataSource().createQuery( "orders for customer", "SELECT * FROM \"all orders\" WHERE \"Customer Name\" LIKE :cname" );
+ // "orders for customer and product" is query based on "orders for customers", adding an additional,
+ // anonymous parameter
+ m_database.getDatabase().getDataSource().createQuery( "orders for customer and product", "SELECT * FROM \"orders for customer\" WHERE \"Product Name\" LIKE ?" );
+
+ m_composer.setQuery( m_database.getDatabase().getDataSource().getQueryDefinition( "orders for customer and product" ).getCommand() );
+ XParametersSupplier suppParams = (XParametersSupplier)UnoRuntime.queryInterface(
+ XParametersSupplier.class, m_composer );
+ XIndexAccess parameters = suppParams.getParameters();
+
+ String expectedParamNames[] = {
+ "cname",
+ "Product Name"
+ };
+
+ int paramCount = parameters.getCount();
+ assure( "composer did find wrong number of parameters in the nested queries.",
+ paramCount == expectedParamNames.length );
+
+ for ( int i = 0; i < paramCount; ++i )
+ {
+ XPropertySet parameter = (XPropertySet)UnoRuntime.queryInterface(
+ XPropertySet.class, parameters.getByIndex(i) );
+ String paramName = (String)parameter.getPropertyValue( "Name" );
+ assure( "wrong parameter name at position " + ( i + 1 ) + " (expected: " + expectedParamNames[i] + ", found: " + paramName + ")",
+ paramName.equals( expectedParamNames[i] ) );
+
+ }
+ }
+ catch( Exception e )
+ {
+ assure( "caught an exception: " + e, false );
+ }
+ }
+
+ private void impl_testDisjunctiveNormalForm( String _query, PropertyValue[][] _expectedDNF )
+ {
+ try { m_composer.setQuery( _query ); }
+ catch ( Exception e )
+ {
+ // this is an error: the query is expected to be parseable
+ assure( "caught an exception: " + e, false );
+ }
+
+ PropertyValue[][] disjunctiveNormalForm = m_composer.getStructuredFilter();
+
+ assureEquals( "DNF: wrong number of rows", _expectedDNF.length, disjunctiveNormalForm.length );
+ for ( int i=0; i<_expectedDNF.length; ++i )
+ {
+ assureEquals( "DNF: wrong number of columns in row " + i, _expectedDNF[i].length, disjunctiveNormalForm[i].length );
+ for ( int j=0; j<_expectedDNF[i].length; ++j )
+ {
+ assureEquals( "DNF: wrong content in column " + j + ", row " + i,
+ _expectedDNF[i][j].Name, disjunctiveNormalForm[i][j].Name );
+ }
+ }
+ }
+
+ /** tests the disjunctive normal form functionality, aka the structured filter,
+ * of the composer
+ */
+ public void testDisjunctiveNormalForm()
+ {
+ // a simple case: WHERE clause simply is a combination of predicates knitted with AND
+ String query =
+ "SELECT \"customers\".\"Name\", " +
+ "\"customers\".\"Address\", " +
+ "\"customers\".\"City\", " +
+ "\"customers\".\"Postal\", " +
+ "\"products\".\"Name\" " +
+ "FROM \"orders\", \"customers\", \"orders_details\", \"products\" " +
+ "WHERE ( \"orders\".\"CustomerID\" = \"customers\".\"ID\" " +
+ "AND \"orders_details\".\"OrderID\" = \"orders\".\"ID\" " +
+ "AND \"orders_details\".\"ProductID\" = \"products\".\"ID\" " +
+ ") ";
+
+ impl_testDisjunctiveNormalForm( query, new PropertyValue[][] {
+ new PropertyValue[] {
+ new PropertyValue( "CustomerID", SQLFilterOperator.EQUAL, "\"customers\".\"ID\"", PropertyState.DIRECT_VALUE ),
+ new PropertyValue( "OrderID", SQLFilterOperator.EQUAL, "\"orders\".\"ID\"", PropertyState.DIRECT_VALUE ),
+ new PropertyValue( "ProductID", SQLFilterOperator.EQUAL, "\"products\".\"ID\"", PropertyState.DIRECT_VALUE )
+ } }
+ );
+
+ // somewhat more challenging: One of the conjunction terms is a disjunction itself
+ query =
+ "SELECT \"customers\".\"Name\", " +
+ "\"customers\".\"Address\", " +
+ "\"customers\".\"City\", " +
+ "\"customers\".\"Postal\", " +
+ "\"products\".\"Name\" " +
+ "FROM \"orders\", \"customers\", \"orders_details\", \"products\" " +
+ "WHERE ( \"orders\".\"CustomerID\" = \"customers\".\"ID\" " +
+ "AND \"orders_details\".\"OrderID\" = \"orders\".\"ID\" " +
+ "AND \"orders_details\".\"ProductID\" = \"products\".\"ID\" " +
+ ") " +
+ "AND " +
+ "( \"products\".\"Name\" = 'Apples' " +
+ "OR \"products\".\"ID\" = 2 " +
+ ")";
+
+ impl_testDisjunctiveNormalForm( query, new PropertyValue[][] {
+ new PropertyValue[] {
+ new PropertyValue( "CustomerID", SQLFilterOperator.EQUAL, "\"customers\".\"ID\"", PropertyState.DIRECT_VALUE ),
+ new PropertyValue( "OrderID", SQLFilterOperator.EQUAL, "\"orders\".\"ID\"", PropertyState.DIRECT_VALUE ),
+ new PropertyValue( "ProductID", SQLFilterOperator.EQUAL, "\"products\".\"ID\"", PropertyState.DIRECT_VALUE ),
+ new PropertyValue( "Name", SQLFilterOperator.EQUAL, "Apples", PropertyState.DIRECT_VALUE )
+ },
+ new PropertyValue[] {
+ new PropertyValue( "CustomerID", SQLFilterOperator.EQUAL, "\"customers\".\"ID\"", PropertyState.DIRECT_VALUE ),
+ new PropertyValue( "OrderID", SQLFilterOperator.EQUAL, "\"orders\".\"ID\"", PropertyState.DIRECT_VALUE ),
+ new PropertyValue( "ProductID", SQLFilterOperator.EQUAL, "\"products\".\"ID\"", PropertyState.DIRECT_VALUE ),
+ new PropertyValue( "ID", SQLFilterOperator.EQUAL, new Integer(2), PropertyState.DIRECT_VALUE )
+ } }
+ );
+
+ }
+}
diff --git a/dbaccess/qa/complex/dbaccess/TestCase.java b/dbaccess/qa/complex/dbaccess/TestCase.java
new file mode 100644
index 000000000000..7fdc2c3d886b
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/TestCase.java
@@ -0,0 +1,149 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: TestCase.java,v $
+ * $Revision: 1.1.2.1 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+package complex.dbaccess;
+
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.lang.XMultiServiceFactory;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+import helper.FileTools;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+public abstract class TestCase extends complexlib.ComplexTestCase
+{
+ // --------------------------------------------------------------------------------------------------------
+ protected final XMultiServiceFactory getORB()
+ {
+ return (XMultiServiceFactory)param.getMSF();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ protected final XComponentContext getComponentContext()
+ {
+ XComponentContext context = null;
+ try
+ {
+ XPropertySet orbProps = (XPropertySet) UnoRuntime.queryInterface( XPropertySet.class, getORB() );
+ context = (XComponentContext)UnoRuntime.queryInterface( XComponentContext.class,
+ orbProps.getPropertyValue( "DefaultContext" ) );
+ }
+ catch ( Exception ex )
+ {
+ failed( "could not retrieve the ComponentContext" );
+ }
+ return context;
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void before()
+ {
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public void after()
+ {
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ /** returns the URL of a temporary file which can be used during the test.
+ *
+ * The file will be deleted when the process exits
+ * @return the URL of a temporary file
+ */
+ protected final String createTempFileURL() throws IOException
+ {
+ File documentFile = java.io.File.createTempFile( getTestObjectName(), ".odb" );
+ documentFile.deleteOnExit();
+ return documentFile.getAbsoluteFile().toURL().toString();
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ /**
+ * copies the file given by URL to a temporary file
+ * @return
+ * the URL of the new file
+ */
+ protected final String copyToTempFile( String _sourceURL ) throws IOException
+ {
+ String targetURL = createTempFileURL();
+ try
+ {
+ FileTools.copyFile( new File( new URI( _sourceURL ) ), new File( new URI( targetURL ) ) );
+ }
+ catch ( URISyntaxException e ) { }
+
+ return FileHelper.getOOoCompatibleFileURL( targetURL );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ protected void verifyExpectedException( Object _object, Class _unoInterfaceClass, String _methodName, Object[] _methodArgs,
+ Class _expectedExceptionClass )
+ {
+ verifyExpectedException( UnoRuntime.queryInterface( _unoInterfaceClass, _object ), _methodName,
+ _methodArgs, _expectedExceptionClass );
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ protected void verifyExpectedException( Object _object, String _methodName, Object[] _methodArgs,
+ Class _expectedExceptionClass )
+ {
+ Class objectClass = _object.getClass();
+ Class[] methodArgsClasses = new Class[ _methodArgs.length ];
+ for ( int i=0; i<_methodArgs.length; ++i )
+ methodArgsClasses[i] = _methodArgs[i].getClass();
+
+ boolean noExceptionAllowed = _expectedExceptionClass == null;
+
+ boolean caughtExpected = noExceptionAllowed ? true : false;
+ try
+ {
+ Method method = objectClass.getMethod( _methodName, methodArgsClasses );
+ method.invoke(_object, _methodArgs );
+ }
+ catch ( InvocationTargetException e )
+ {
+ caughtExpected = noExceptionAllowed
+ ? false
+ : ( e.getTargetException().getClass().equals( _expectedExceptionClass ) );
+ }
+ catch( Exception e )
+ {
+ caughtExpected = false;
+ }
+ assure( "did not catch the expected exception (" +
+ ( noExceptionAllowed ? "none" : _expectedExceptionClass.getName() ) +
+ ") while calling " + _object.getClass().getName() + "." + _methodName, caughtExpected );
+ }
+}
diff --git a/dbaccess/qa/complex/dbaccess/UISettings.java b/dbaccess/qa/complex/dbaccess/UISettings.java
new file mode 100644
index 000000000000..a755b39aa63c
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/UISettings.java
@@ -0,0 +1,133 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: Parser.java,v $
+ * $Revision: 1.1.6.2 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+package complex.dbaccess;
+
+import com.sun.star.awt.FontSlant;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.form.XFormController;
+import com.sun.star.frame.XComponentLoader;
+import com.sun.star.frame.XModel;
+import com.sun.star.lang.XComponent;
+import com.sun.star.sdb.application.XDatabaseDocumentUI;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.XCloseable;
+import helper.URLHelper;
+import java.io.File;
+import java.net.URI;
+
+public class UISettings extends TestCase
+{
+ // --------------------------------------------------------------------------------------------------------
+ public String[] getTestMethodNames()
+ {
+ return new String[] {
+ "checkTableFormattingPersistence"
+ };
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ public String getTestObjectName()
+ {
+ return "UISettings";
+ }
+
+ // --------------------------------------------------------------------------------------------------------
+ /** verifies that aliases for inner queries work as expected
+ */
+ public void checkTableFormattingPersistence() throws java.lang.Exception
+ {
+ CRMDatabase database = new CRMDatabase( getORB() );
+
+ // load the document
+ String docURL = database.getDatabase().getDocumentURL();
+ XComponentLoader loader = (XComponentLoader)UnoRuntime.queryInterface( XComponentLoader.class,
+ getORB().createInstance( "com.sun.star.frame.Desktop" ) );
+ XModel doc = (XModel)UnoRuntime.queryInterface( XModel.class,
+ loader.loadComponentFromURL( docURL, "_blank", 0, new PropertyValue[] {} ) );
+
+ // establish the connection
+ XDatabaseDocumentUI docUI = (XDatabaseDocumentUI)UnoRuntime.queryInterface( XDatabaseDocumentUI.class,
+ doc.getCurrentController() );
+ docUI.connect();
+
+ // display the table
+ XComponent tableViewComp = docUI.loadComponent( com.sun.star.sdb.application.DatabaseObject.TABLE, "customers", false );
+ XFormController tableViewController = (XFormController)UnoRuntime.queryInterface( XFormController.class,
+ tableViewComp );
+ XPropertySet tableControlModel = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class,
+ tableViewController.getCurrentControl().getModel() );
+
+ // change the table's formatting
+ tableControlModel.setPropertyValue( "FontName", "Andale Sans UI" );
+ tableControlModel.setPropertyValue( "FontHeight", new Float( 20 ) );
+ tableControlModel.setPropertyValue( "FontSlant", FontSlant.ITALIC );
+
+ // close the table
+ docUI.closeSubComponents();
+
+ // save and close the database document
+ database.getDatabase().store();
+ database.close();
+
+ // load a copy of the document
+ // normally, it should be sufficient to load the same doc. However, there might be objects in the Java VM
+ // which are not yet freed, and which effectively hold the document alive. More precise: The document (|doc|)
+ // is certainly disposed, but other objects might hold a reference to one of the many other components
+ // around the database document, the data source, the connection, etc. As long as those objects are
+ // not cleaned up, the "database model impl" - the structure holding all document data - will
+ // stay alive, and subsequent requests to load the doc will just reuse it, without really loading it.
+ docURL = copyToTempFile( docURL );
+ doc = (XModel)UnoRuntime.queryInterface( XModel.class,
+ loader.loadComponentFromURL( docURL, "_blank", 0, new PropertyValue[] {} ) );
+
+ docUI = (XDatabaseDocumentUI)UnoRuntime.queryInterface( XDatabaseDocumentUI.class,
+ doc.getCurrentController() );
+ docUI.connect();
+
+ // display the table, again
+ tableViewComp = docUI.loadComponent( com.sun.star.sdb.application.DatabaseObject.TABLE, "customers", false );
+ tableViewController = (XFormController)UnoRuntime.queryInterface( XFormController.class,
+ tableViewComp );
+ tableControlModel = (XPropertySet)UnoRuntime.queryInterface( XPropertySet.class,
+ tableViewController.getCurrentControl().getModel() );
+
+ // verify the properties
+ assureEquals( "wrong font name", "Andale Sans UI", (String)tableControlModel.getPropertyValue( "FontName" ) );
+ assureEquals( "wrong font height", (float)20, ((Float)tableControlModel.getPropertyValue( "FontHeight" )).floatValue() );
+ assureEquals( "wrong font slant", FontSlant.ITALIC, (FontSlant)tableControlModel.getPropertyValue( "FontSlant" ) );
+
+ // close the doc
+ docUI.closeSubComponents();
+ XCloseable closeDoc = (XCloseable)UnoRuntime.queryInterface( XCloseable.class,
+ doc );
+ closeDoc.close( true );
+ }
+}
diff --git a/dbaccess/qa/complex/dbaccess/dbaccess.sce b/dbaccess/qa/complex/dbaccess/dbaccess.sce
new file mode 100644
index 000000000000..9b17f0cd9f84
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/dbaccess.sce
@@ -0,0 +1,10 @@
+-o complex.dbaccess.SingleSelectQueryComposer
+-o complex.dbaccess.RowSet
+-o complex.dbaccess.PropertyBag
+-o complex.dbaccess.Query
+-o complex.dbaccess.QueryInQuery
+-o complex.dbaccess.DatabaseDocument
+-o complex.dbaccess.DataSource
+-o complex.dbaccess.Parser
+-o complex.dbaccess.ApplicationController
+-o complex.dbaccess.UISettings
diff --git a/dbaccess/qa/complex/dbaccess/makefile.mk b/dbaccess/qa/complex/dbaccess/makefile.mk
new file mode 100755
index 000000000000..fa820f3dbeb3
--- /dev/null
+++ b/dbaccess/qa/complex/dbaccess/makefile.mk
@@ -0,0 +1,85 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2008 by Sun Microsystems, Inc.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# $RCSfile: makefile.mk,v $
+#
+# $Revision: 1.13.76.1 $
+#
+# This file is part of OpenOffice.org.
+#
+# OpenOffice.org is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License version 3
+# only, as published by the Free Software Foundation.
+#
+# OpenOffice.org is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License version 3 for more details
+# (a copy is included in the LICENSE file that accompanied this code).
+#
+# You should have received a copy of the GNU Lesser General Public License
+# version 3 along with OpenOffice.org. If not, see
+# <http://www.openoffice.org/license.html>
+# for a copy of the LGPLv3 License.
+#
+#*************************************************************************
+
+PRJ = ..$/..$/..
+TARGET = DbaComplexTests
+PRJNAME = $(TARGET)
+PACKAGE = complex$/dbaccess
+
+# --- Settings -----------------------------------------------------
+.INCLUDE: settings.mk
+
+.IF "$(SOLAR_JAVA)" == ""
+all:
+ @echo "Java not available. Build skipped"
+
+.INCLUDE : target.mk
+.ELSE
+
+.IF "$(BUILD_QADEVOOO)" == "YES"
+#----- compile .java files -----------------------------------------
+
+JARFILES = ridl.jar unoil.jar jurt.jar juh.jar java_uno.jar OOoRunner.jar ConnectivityTools.jar
+JAVAFILES := $(shell @$(FIND) ./*.java)
+JAVACLASSFILES = $(foreach,i,$(JAVAFILES) $(CLASSDIR)$/$(PACKAGE)$/$(i:b).class)
+
+#----- make a jar from compiled files ------------------------------
+
+MAXLINELENGTH = 100000
+
+JARCLASSDIRS = $(PACKAGE)
+JARTARGET = $(TARGET).jar
+JARCOMPRESS = TRUE
+
+RUNNER_ARGS = -cp $(CLASSPATH)$(PATH_SEPERATOR)$(SOLARBINDIR)$/OOoRunner.jar org.openoffice.Runner -TestBase java_complex
+
+# --- Targets ------------------------------------------------------
+
+.IF "$(depend)" == ""
+ALL : ALLTAR
+.ELSE
+ALL: ALLDEP
+.ENDIF
+
+.INCLUDE : target.mk
+
+
+run: $(CLASSDIR)$/$(JARTARGET)
+ +java $(RUNNER_ARGS) -sce dbaccess.sce
+
+run_%: $(CLASSDIR)$/$(JARTARGET)
+ +java $(RUNNER_ARGS) -o complex.dbaccess.$(@:s/run_//)
+
+.ELSE
+.INCLUDE : target.mk
+.ENDIF # "$(BUILD_QADEVOOO)" == "YES"
+
+.ENDIF # "$(SOLAR_JAVA)" == ""