mirror of
https://github.com/LibreOffice/core.git
synced 2025-07-26 15:45:26 +00:00
Move SingleSelectQueryComposer.java tests to C++
Move the tests to SingleSelectQueryComposer_test.cxx Remove the old SingleSelectQueryComposer JUnit tests/file Add makefile for SingleSelectQueryComposer_test Remove the java test from JunitTest_dbaccess_complex.mk Add the CppUnit test to the Module_dbaccess.mk file to be run only when Java is enabled on the test machine Change-Id: I832c80e294be6cd4dced4d358bcee383ea04b0fc Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182759 Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org> Tested-by: Jenkins
This commit is contained in:

committed by
Xisco Fauli

parent
b2b4934ce8
commit
d1ec7e9077
@ -0,0 +1,51 @@
|
|||||||
|
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
|
||||||
|
#
|
||||||
|
# This file is part of the LibreOffice project.
|
||||||
|
#
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
#
|
||||||
|
|
||||||
|
$(eval $(call gb_CppunitTest_CppunitTest,dbaccess_SingleSelectQueryComposer_test))
|
||||||
|
|
||||||
|
$(eval $(call gb_CppunitTest_use_external,dbaccess_SingleSelectQueryComposer_test,boost_headers))
|
||||||
|
|
||||||
|
$(eval $(call gb_CppunitTest_add_exception_objects,dbaccess_SingleSelectQueryComposer_test, \
|
||||||
|
dbaccess/qa/unit/SingleSelectQueryComposer_test \
|
||||||
|
))
|
||||||
|
|
||||||
|
$(eval $(call gb_CppunitTest_use_libraries,dbaccess_SingleSelectQueryComposer_test, \
|
||||||
|
comphelper \
|
||||||
|
cppu \
|
||||||
|
cppuhelper \
|
||||||
|
dbaxml \
|
||||||
|
dbtools \
|
||||||
|
sal \
|
||||||
|
subsequenttest \
|
||||||
|
utl \
|
||||||
|
test \
|
||||||
|
tk \
|
||||||
|
tl \
|
||||||
|
unotest \
|
||||||
|
xo \
|
||||||
|
))
|
||||||
|
|
||||||
|
$(eval $(call gb_CppunitTest_use_api,dbaccess_SingleSelectQueryComposer_test,\
|
||||||
|
offapi \
|
||||||
|
oovbaapi \
|
||||||
|
udkapi \
|
||||||
|
))
|
||||||
|
|
||||||
|
$(eval $(call gb_CppunitTest_use_ure,dbaccess_SingleSelectQueryComposer_test))
|
||||||
|
$(eval $(call gb_CppunitTest_use_vcl,dbaccess_SingleSelectQueryComposer_test))
|
||||||
|
|
||||||
|
$(eval $(call gb_CppunitTest_use_rdb,dbaccess_SingleSelectQueryComposer_test,services))
|
||||||
|
|
||||||
|
$(eval $(call gb_CppunitTest_use_configuration,dbaccess_SingleSelectQueryComposer_test))
|
||||||
|
|
||||||
|
$(eval $(call gb_CppunitTest_use_uiconfigs,dbaccess_SingleSelectQueryComposer_test, \
|
||||||
|
dbaccess \
|
||||||
|
))
|
||||||
|
|
||||||
|
# vim: set noet sw=4 ts=4:
|
@ -41,7 +41,6 @@ $(eval $(call gb_JunitTest_add_sourcefiles,dbaccess_complex,\
|
|||||||
dbaccess/qa/complex/dbaccess/QueryInQuery \
|
dbaccess/qa/complex/dbaccess/QueryInQuery \
|
||||||
dbaccess/qa/complex/dbaccess/RowSet \
|
dbaccess/qa/complex/dbaccess/RowSet \
|
||||||
dbaccess/qa/complex/dbaccess/RowSetEventListener \
|
dbaccess/qa/complex/dbaccess/RowSetEventListener \
|
||||||
dbaccess/qa/complex/dbaccess/SingleSelectQueryComposer \
|
|
||||||
dbaccess/qa/complex/dbaccess/TestCase \
|
dbaccess/qa/complex/dbaccess/TestCase \
|
||||||
dbaccess/qa/complex/dbaccess/UISettings \
|
dbaccess/qa/complex/dbaccess/UISettings \
|
||||||
))
|
))
|
||||||
|
@ -59,6 +59,7 @@ $(eval $(call gb_Module_add_check_targets,dbaccess,\
|
|||||||
CppunitTest_dbaccess_hsqldb_test \
|
CppunitTest_dbaccess_hsqldb_test \
|
||||||
CppunitTest_dbaccess_RowSetClones \
|
CppunitTest_dbaccess_RowSetClones \
|
||||||
CppunitTest_dbaccess_CRMDatabase_test \
|
CppunitTest_dbaccess_CRMDatabase_test \
|
||||||
|
CppunitTest_dbaccess_SingleSelectQueryComposer_test \
|
||||||
))
|
))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -1,351 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the LibreOffice project.
|
|
||||||
*
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
*
|
|
||||||
* This file incorporates work covered by the following license notice:
|
|
||||||
*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed
|
|
||||||
* with this work for additional information regarding copyright
|
|
||||||
* ownership. The ASF licenses this file to you under the Apache
|
|
||||||
* License, Version 2.0 (the "License"); you may not use this file
|
|
||||||
* except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
||||||
*/
|
|
||||||
package complex.dbaccess;
|
|
||||||
|
|
||||||
import com.sun.star.beans.PropertyState;
|
|
||||||
import com.sun.star.sdb.SQLFilterOperator;
|
|
||||||
import com.sun.star.beans.PropertyAttribute;
|
|
||||||
import com.sun.star.beans.XPropertySet;
|
|
||||||
import com.sun.star.beans.XPropertyContainer;
|
|
||||||
import com.sun.star.beans.NamedValue;
|
|
||||||
import com.sun.star.container.XNameAccess;
|
|
||||||
import com.sun.star.sdbcx.XTablesSupplier;
|
|
||||||
import com.sun.star.sdb.XParametersSupplier;
|
|
||||||
import com.sun.star.beans.PropertyValue;
|
|
||||||
import com.sun.star.sdbcx.XColumnsSupplier;
|
|
||||||
import com.sun.star.container.XIndexAccess;
|
|
||||||
import com.sun.star.sdb.CommandType;
|
|
||||||
import com.sun.star.sdb.XSingleSelectQueryComposer;
|
|
||||||
import com.sun.star.uno.UnoRuntime;
|
|
||||||
import com.sun.star.sdbc.DataType;
|
|
||||||
import com.sun.star.sdbc.SQLException;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
|
|
||||||
// ---------- junit imports -----------------
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
|
|
||||||
public class SingleSelectQueryComposer extends CRMBasedTestCase
|
|
||||||
{
|
|
||||||
|
|
||||||
private XSingleSelectQueryComposer m_composer = null;
|
|
||||||
private static 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' )"
|
|
||||||
+ " OR ( NOW( ) = {d '2010-01-01' } )";
|
|
||||||
private static final String INNERPRODUCTSQUERY = "products (inner)";
|
|
||||||
|
|
||||||
|
|
||||||
private void createQueries() throws Exception
|
|
||||||
{
|
|
||||||
m_database.getDatabase().getDataSource().createQuery(INNERPRODUCTSQUERY, "SELECT * FROM \"products\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void createTestCase() throws Exception
|
|
||||||
{
|
|
||||||
super.createTestCase();
|
|
||||||
|
|
||||||
createQueries();
|
|
||||||
|
|
||||||
m_composer = createQueryComposer();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void checkAttributeAccess(String _attributeName, String _attributeValue)
|
|
||||||
{
|
|
||||||
System.out.println("setting " + _attributeName + " to " + _attributeValue);
|
|
||||||
String realValue = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
final Class<?> composerClass = m_composer.getClass();
|
|
||||||
final Method attributeGetter = composerClass.getMethod("get" + _attributeName, new Class[]
|
|
||||||
{
|
|
||||||
});
|
|
||||||
final 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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
assertTrue("set/get" + _attributeName + " not working as expected (set: " + _attributeValue + ", get: " + (realValue != null ? realValue : "null") + ")",
|
|
||||||
realValue.equals(_attributeValue));
|
|
||||||
System.out.println(" (results in " + m_composer.getQuery() + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** tests setCommand of the composer
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testSetCommand() throws Exception
|
|
||||||
{
|
|
||||||
System.out.println("testing SingleSelectQueryComposer's setCommand");
|
|
||||||
|
|
||||||
final String table = "SELECT * FROM \"customers\"";
|
|
||||||
m_composer.setCommand("customers", CommandType.TABLE);
|
|
||||||
assertTrue("setCommand/getQuery TABLE inconsistent", m_composer.getQuery().equals(table));
|
|
||||||
|
|
||||||
m_database.getDatabase().getDataSource().createQuery("set command test", "SELECT * FROM \"orders for customer\" \"a\", \"customers\" \"b\" WHERE \"a\".\"Product Name\" = \"b\".\"Name\"");
|
|
||||||
m_composer.setCommand("set command test", CommandType.QUERY);
|
|
||||||
assertTrue("setCommand/getQuery QUERY inconsistent", m_composer.getQuery().equals(m_database.getDatabase().getDataSource().getQueryDefinition("set command test").getCommand()));
|
|
||||||
|
|
||||||
final String sql = "SELECT * FROM \"orders for customer\" WHERE \"Product Name\" = 'test'";
|
|
||||||
m_composer.setCommand(sql, CommandType.COMMAND);
|
|
||||||
assertTrue("setCommand/getQuery COMMAND inconsistent", m_composer.getQuery().equals(sql));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** tests accessing attributes of the composer (order, filter, group by, having)
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testAttributes() throws Exception
|
|
||||||
{
|
|
||||||
System.out.println("testing SingleSelectQueryComposer's attributes (order, filter, group by, having)");
|
|
||||||
|
|
||||||
System.out.println("check setElementaryQuery");
|
|
||||||
|
|
||||||
final String simpleQuery2 = "SELECT * FROM \"customers\" WHERE \"Name\" = 'oranges'";
|
|
||||||
m_composer.setElementaryQuery(simpleQuery2);
|
|
||||||
assertTrue("setElementaryQuery/getQuery inconsistent", m_composer.getQuery().equals(simpleQuery2));
|
|
||||||
|
|
||||||
System.out.println("check setQuery");
|
|
||||||
final String simpleQuery = "SELECT * FROM \"customers\"";
|
|
||||||
m_composer.setQuery(simpleQuery);
|
|
||||||
assertTrue("set/getQuery inconsistent", m_composer.getQuery().equals(simpleQuery));
|
|
||||||
|
|
||||||
checkAttributeAccess("Filter", "\"Name\" = 'oranges'");
|
|
||||||
checkAttributeAccess("Group", "\"City\"");
|
|
||||||
checkAttributeAccess("Order", "\"Address\"");
|
|
||||||
checkAttributeAccess("HavingClause", "\"ID\" <> 4");
|
|
||||||
|
|
||||||
final XIndexAccess orderColumns = m_composer.getOrderColumns();
|
|
||||||
assertTrue("Order columns doesn't exist: \"Address\"",
|
|
||||||
orderColumns != null && orderColumns.getCount() == 1 && orderColumns.getByIndex(0) != null);
|
|
||||||
|
|
||||||
final XIndexAccess groupColumns = m_composer.getGroupColumns();
|
|
||||||
assertTrue("Group columns doesn't exist: \"City\"",
|
|
||||||
groupColumns != null && groupColumns.getCount() == 1 && groupColumns.getByIndex(0) != null);
|
|
||||||
|
|
||||||
// XColumnsSupplier
|
|
||||||
final XColumnsSupplier xSelectColumns = UnoRuntime.queryInterface(XColumnsSupplier.class, m_composer);
|
|
||||||
assertTrue("no select columns, or wrong number of select columns",
|
|
||||||
xSelectColumns != null && xSelectColumns.getColumns() != null && xSelectColumns.getColumns().getElementNames().length == 6);
|
|
||||||
|
|
||||||
// structured filter
|
|
||||||
m_composer.setQuery("SELECT \"ID\", \"Postal\", \"Address\" FROM \"customers\"");
|
|
||||||
m_composer.setFilter(COMPLEXFILTER);
|
|
||||||
final PropertyValue[][] aStructuredFilter = m_composer.getStructuredFilter();
|
|
||||||
m_composer.setFilter("");
|
|
||||||
m_composer.setStructuredFilter(aStructuredFilter);
|
|
||||||
if (!m_composer.getFilter().equals(COMPLEXFILTER))
|
|
||||||
{
|
|
||||||
System.out.println(COMPLEXFILTER);
|
|
||||||
System.out.println(m_composer.getFilter());
|
|
||||||
}
|
|
||||||
assertTrue("Structured Filter not identical", m_composer.getFilter().equals(COMPLEXFILTER));
|
|
||||||
|
|
||||||
// structured having clause
|
|
||||||
m_composer.setHavingClause(COMPLEXFILTER);
|
|
||||||
final PropertyValue[][] aStructuredHaving = m_composer.getStructuredHavingClause();
|
|
||||||
m_composer.setHavingClause("");
|
|
||||||
m_composer.setStructuredHavingClause(aStructuredHaving);
|
|
||||||
assertTrue("Structured Having Clause not identical", m_composer.getHavingClause().equals(COMPLEXFILTER));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** test various sub query related features ("queries in queries")
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testSubQueries() throws Exception
|
|
||||||
{
|
|
||||||
m_composer.setQuery("SELECT * from \"" + INNERPRODUCTSQUERY + "\"");
|
|
||||||
final XTablesSupplier suppTables = UnoRuntime.queryInterface(XTablesSupplier.class, m_composer);
|
|
||||||
final XNameAccess tables = suppTables.getTables();
|
|
||||||
assertTrue("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();
|
|
||||||
assertTrue("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
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testParameters() throws Exception
|
|
||||||
{
|
|
||||||
// "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());
|
|
||||||
final XParametersSupplier suppParams = UnoRuntime.queryInterface(XParametersSupplier.class, m_composer);
|
|
||||||
final XIndexAccess parameters = suppParams.getParameters();
|
|
||||||
|
|
||||||
final String expectedParamNames[] =
|
|
||||||
|
|
||||||
{
|
|
||||||
"cname",
|
|
||||||
"Product Name"
|
|
||||||
};
|
|
||||||
|
|
||||||
final int paramCount = parameters.getCount();
|
|
||||||
assertTrue("composer did find wrong number of parameters in the nested queries.",
|
|
||||||
paramCount == expectedParamNames.length);
|
|
||||||
|
|
||||||
for (int i = 0; i < paramCount; ++i)
|
|
||||||
{
|
|
||||||
final XPropertySet parameter = UnoRuntime.queryInterface(XPropertySet.class, parameters.getByIndex(i));
|
|
||||||
final String paramName = (String) parameter.getPropertyValue("Name");
|
|
||||||
assertTrue("wrong parameter name at position " + (i + 1) + " (expected: " + expectedParamNames[i] + ", found: " + paramName + ")",
|
|
||||||
paramName.equals(expectedParamNames[i]));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testConditionByColumn() throws Exception
|
|
||||||
{
|
|
||||||
m_composer.setQuery("SELECT * FROM \"customers\"");
|
|
||||||
|
|
||||||
final Object initArgs[] =
|
|
||||||
|
|
||||||
{
|
|
||||||
new NamedValue("AutomaticAddition", Boolean.TRUE)
|
|
||||||
};
|
|
||||||
final String serviceName = "com.sun.star.beans.PropertyBag";
|
|
||||||
final XPropertyContainer filter = UnoRuntime.queryInterface(XPropertyContainer.class, getMSF().createInstanceWithArguments(serviceName, initArgs));
|
|
||||||
filter.addProperty("Name", PropertyAttribute.MAYBEVOID, "Comment");
|
|
||||||
filter.addProperty("RealName", PropertyAttribute.MAYBEVOID, "Comment");
|
|
||||||
filter.addProperty("TableName", PropertyAttribute.MAYBEVOID, "customers");
|
|
||||||
filter.addProperty("Value", PropertyAttribute.MAYBEVOID, "Good one.");
|
|
||||||
filter.addProperty("Type", PropertyAttribute.MAYBEVOID, Integer.valueOf(DataType.LONGVARCHAR));
|
|
||||||
final XPropertySet column = UnoRuntime.queryInterface(XPropertySet.class, filter);
|
|
||||||
|
|
||||||
m_composer.appendFilterByColumn(column, true, SQLFilterOperator.LIKE);
|
|
||||||
assertTrue("At least one row should exist", m_database.getConnection().createStatement().executeQuery(m_composer.getQuery()).next());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void impl_testDisjunctiveNormalForm(String _query, PropertyValue[][] _expectedDNF) throws SQLException
|
|
||||||
{
|
|
||||||
m_composer.setQuery(_query);
|
|
||||||
|
|
||||||
final PropertyValue[][] disjunctiveNormalForm = m_composer.getStructuredFilter();
|
|
||||||
|
|
||||||
assertEquals("DNF: wrong number of rows", _expectedDNF.length, disjunctiveNormalForm.length);
|
|
||||||
for (int i = 0; i < _expectedDNF.length; ++i)
|
|
||||||
{
|
|
||||||
assertEquals("DNF: wrong number of columns in row " + i, _expectedDNF[i].length, disjunctiveNormalForm[i].length);
|
|
||||||
for (int j = 0; j < _expectedDNF[i].length; ++j)
|
|
||||||
{
|
|
||||||
assertEquals("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
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testDisjunctiveNormalForm() throws Exception
|
|
||||||
{
|
|
||||||
// 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, Integer.valueOf(2), PropertyState.DIRECT_VALUE)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
436
dbaccess/qa/unit/SingleSelectQueryComposer_test.cxx
Normal file
436
dbaccess/qa/unit/SingleSelectQueryComposer_test.cxx
Normal file
@ -0,0 +1,436 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||||
|
/*
|
||||||
|
* This file is part of the LibreOffice project.
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dbtest_base.cxx"
|
||||||
|
|
||||||
|
#include <com/sun/star/beans/NamedValue.hpp>
|
||||||
|
#include <com/sun/star/beans/PropertyAttribute.hpp>
|
||||||
|
#include <com/sun/star/beans/XPropertyContainer.hpp>
|
||||||
|
#include <com/sun/star/container/XNameAccess.hpp>
|
||||||
|
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
|
||||||
|
|
||||||
|
#include <com/sun/star/sdb/CommandType.hpp>
|
||||||
|
#include <com/sun/star/sdb/SQLFilterOperator.hpp>
|
||||||
|
#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
|
||||||
|
#include <com/sun/star/sdb/XQueriesSupplier.hpp>
|
||||||
|
#include <com/sun/star/sdb/XQueryDefinition.hpp>
|
||||||
|
#include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp>
|
||||||
|
#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
|
||||||
|
#include <com/sun/star/sdb/XParametersSupplier.hpp>
|
||||||
|
#include <com/sun/star/sdbc/DataType.hpp>
|
||||||
|
#include <com/sun/star/sdbc/XDataSource.hpp>
|
||||||
|
#include <com/sun/star/sdbc/XRow.hpp>
|
||||||
|
#include <com/sun/star/sdbc/XResultSet.hpp>
|
||||||
|
#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
|
||||||
|
#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
|
||||||
|
|
||||||
|
using namespace ::com::sun::star;
|
||||||
|
using namespace ::com::sun::star::uno;
|
||||||
|
|
||||||
|
class SingleSelectQueryComposerTest : public DBTestBase
|
||||||
|
{
|
||||||
|
Reference<XDataSource> m_xDataSource;
|
||||||
|
Reference<XConnection> m_xConnection;
|
||||||
|
Reference<XSingleSelectQueryComposer> m_xComposer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void setUp() override;
|
||||||
|
void testSetCommand();
|
||||||
|
void testAttributes();
|
||||||
|
void testSubQueries();
|
||||||
|
void testParameters();
|
||||||
|
void testConditionByColumn();
|
||||||
|
void testDisjunctiveNormalForm();
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE(SingleSelectQueryComposerTest);
|
||||||
|
CPPUNIT_TEST(testSetCommand);
|
||||||
|
CPPUNIT_TEST(testAttributes);
|
||||||
|
CPPUNIT_TEST(testSubQueries);
|
||||||
|
CPPUNIT_TEST(testParameters);
|
||||||
|
CPPUNIT_TEST(testConditionByColumn);
|
||||||
|
CPPUNIT_TEST(testDisjunctiveNormalForm);
|
||||||
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
};
|
||||||
|
|
||||||
|
void SingleSelectQueryComposerTest::setUp()
|
||||||
|
{
|
||||||
|
DBTestBase::setUp();
|
||||||
|
createDBDocument(u"sdbc:embedded:hsqldb"_ustr);
|
||||||
|
Reference<sdb::XOfficeDatabaseDocument> xDocument(mxComponent, UNO_QUERY_THROW);
|
||||||
|
m_xDataSource = xDocument->getDataSource();
|
||||||
|
|
||||||
|
// Create some common queries
|
||||||
|
DBTestBase::createQueries(m_xDataSource);
|
||||||
|
|
||||||
|
m_xConnection = m_xDataSource->getConnection(u""_ustr, u""_ustr);
|
||||||
|
DBTestBase::createTables(m_xConnection);
|
||||||
|
|
||||||
|
// For some reason we must close, then reopen the connection in
|
||||||
|
// order for the tables to be visible to the connection
|
||||||
|
m_xConnection->close();
|
||||||
|
m_xConnection = m_xDataSource->getConnection(u""_ustr, u""_ustr);
|
||||||
|
|
||||||
|
Reference<lang::XMultiServiceFactory> xFactory(m_xConnection, UNO_QUERY);
|
||||||
|
Reference<XSingleSelectQueryComposer> xComposer(
|
||||||
|
xFactory->createInstance(u"com.sun.star.sdb.SingleSelectQueryComposer"_ustr),
|
||||||
|
UNO_QUERY_THROW);
|
||||||
|
m_xComposer = xComposer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tests setCommand of the composer
|
||||||
|
|
||||||
|
void SingleSelectQueryComposerTest::testSetCommand()
|
||||||
|
{
|
||||||
|
// CommandType::TABLE
|
||||||
|
m_xComposer->setCommand(u"CUSTOMERS"_ustr, CommandType::TABLE);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(u"SELECT * FROM \"CUSTOMERS\""_ustr, m_xComposer->getQuery());
|
||||||
|
|
||||||
|
// CommandType::QUERY
|
||||||
|
DBTestBase::createQuery(u"SELECT * FROM \"orders for customer\" \"a\", \"customers\" "
|
||||||
|
"\"b\" WHERE \"a\".\"Product Name\" = \"b\".\"Name\""_ustr,
|
||||||
|
true, u"set command test"_ustr, m_xDataSource);
|
||||||
|
|
||||||
|
Reference<XQueriesSupplier> xQuerySupplier(m_xConnection, UNO_QUERY_THROW);
|
||||||
|
Reference<container::XNameAccess> xQueryAccess = xQuerySupplier->getQueries();
|
||||||
|
CPPUNIT_ASSERT(xQueryAccess->hasElements());
|
||||||
|
Reference<XPropertySet> xQuery(xQueryAccess->getByName(u"set command test"_ustr), UNO_QUERY);
|
||||||
|
CPPUNIT_ASSERT(xQuery.is());
|
||||||
|
|
||||||
|
m_xComposer->setCommand(u"set command test"_ustr, CommandType::QUERY);
|
||||||
|
OUString sQuery;
|
||||||
|
xQuery->getPropertyValue(u"Command"_ustr) >>= sQuery;
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT_EQUAL(sQuery, m_xComposer->getQuery());
|
||||||
|
|
||||||
|
// CommandType::COMMMAND
|
||||||
|
const OUString sCommand
|
||||||
|
= u"SELECT * FROM \"orders for customer\" WHERE \"Product Name\" = 'test'"_ustr;
|
||||||
|
m_xComposer->setCommand(sCommand, CommandType::COMMAND);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(sCommand, m_xComposer->getQuery());
|
||||||
|
}
|
||||||
|
|
||||||
|
// tests accessing attributes of the composer (order, filter, group by, having)
|
||||||
|
|
||||||
|
void SingleSelectQueryComposerTest::testAttributes()
|
||||||
|
{
|
||||||
|
const OUString sSimpleQuery2 = u"SELECT * FROM \"CUSTOMERS\" WHERE \"Name\" = 'oranges'"_ustr;
|
||||||
|
m_xComposer->setElementaryQuery(sSimpleQuery2);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(sSimpleQuery2, m_xComposer->getQuery());
|
||||||
|
|
||||||
|
const OUString sSimpleQuery = u"SELECT * FROM \"CUSTOMERS\""_ustr;
|
||||||
|
m_xComposer->setQuery(sSimpleQuery);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(sSimpleQuery, m_xComposer->getQuery());
|
||||||
|
|
||||||
|
// checkAttributeAccess "Filter"
|
||||||
|
OUString sFilter = u"\"NAME\" = 'oranges'"_ustr;
|
||||||
|
m_xComposer->setFilter(sFilter);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(sFilter, m_xComposer->getFilter());
|
||||||
|
|
||||||
|
// checkAttributeAccess "Group"
|
||||||
|
sFilter = u"\"CITY\""_ustr;
|
||||||
|
m_xComposer->setGroup(sFilter);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(sFilter, m_xComposer->getGroup());
|
||||||
|
|
||||||
|
// checkAttributeAccess "Order"
|
||||||
|
sFilter = u"\"ADDRESS\""_ustr;
|
||||||
|
m_xComposer->setOrder(sFilter);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(sFilter, m_xComposer->getOrder());
|
||||||
|
|
||||||
|
// checkAttributeAccess "HavingClause"
|
||||||
|
sFilter = u"\"ID\" <> 4"_ustr;
|
||||||
|
m_xComposer->setHavingClause(sFilter);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(sFilter, m_xComposer->getHavingClause());
|
||||||
|
|
||||||
|
// check getOrderColumns
|
||||||
|
Reference<container::XIndexAccess> orderColumns(m_xComposer->getOrderColumns(), UNO_SET_THROW);
|
||||||
|
CPPUNIT_ASSERT(orderColumns->hasElements());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), orderColumns->getCount());
|
||||||
|
|
||||||
|
const Reference<XPropertySet> xOrderColumns(orderColumns->getByIndex(0), UNO_QUERY_THROW);
|
||||||
|
OUString sColumnName;
|
||||||
|
xOrderColumns->getPropertyValue(u"Name"_ustr) >>= sColumnName;
|
||||||
|
CPPUNIT_ASSERT_EQUAL(u"ADDRESS"_ustr, sColumnName);
|
||||||
|
|
||||||
|
// check getGroupColumns
|
||||||
|
Reference<container::XIndexAccess> groupColumns(m_xComposer->getGroupColumns(), UNO_SET_THROW);
|
||||||
|
CPPUNIT_ASSERT(groupColumns->hasElements());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), groupColumns->getCount());
|
||||||
|
|
||||||
|
const Reference<XPropertySet> xGroupColumns(groupColumns->getByIndex(0), UNO_QUERY_THROW);
|
||||||
|
OUString sGroupColumnName;
|
||||||
|
xGroupColumns->getPropertyValue(u"Name"_ustr) >>= sGroupColumnName;
|
||||||
|
CPPUNIT_ASSERT_EQUAL(u"CITY"_ustr, sGroupColumnName);
|
||||||
|
|
||||||
|
// XColumnSupplier
|
||||||
|
Reference<sdbcx::XColumnsSupplier> xSelectColumns(m_xComposer, UNO_QUERY_THROW);
|
||||||
|
Reference<container::XNameAccess> xColumnAccess = xSelectColumns->getColumns();
|
||||||
|
CPPUNIT_ASSERT(xColumnAccess->hasElements());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(sal_Int32(6), xColumnAccess->getElementNames().getLength());
|
||||||
|
|
||||||
|
const OUString COMPLEXFILTER = u"( \"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' )"
|
||||||
|
" OR ( NOW( ) = {d '2010-01-01' } )"_ustr;
|
||||||
|
|
||||||
|
// structured filter
|
||||||
|
m_xComposer->setQuery(u"SELECT \"ID\", \"POSTAL\", \"ADDRESS\" FROM \"CUSTOMERS\""_ustr);
|
||||||
|
m_xComposer->setFilter(COMPLEXFILTER);
|
||||||
|
Sequence<Sequence<PropertyValue>> aStructuredFilter = m_xComposer->getStructuredFilter();
|
||||||
|
m_xComposer->setFilter(u""_ustr);
|
||||||
|
m_xComposer->setStructuredFilter(aStructuredFilter);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(COMPLEXFILTER, m_xComposer->getFilter());
|
||||||
|
|
||||||
|
// structured having clause
|
||||||
|
m_xComposer->setHavingClause(COMPLEXFILTER);
|
||||||
|
Sequence<Sequence<PropertyValue>> aStructuredHaving = m_xComposer->getStructuredHavingClause();
|
||||||
|
m_xComposer->setHavingClause("");
|
||||||
|
m_xComposer->setStructuredHavingClause(aStructuredHaving);
|
||||||
|
CPPUNIT_ASSERT_EQUAL(COMPLEXFILTER, m_xComposer->getHavingClause());
|
||||||
|
}
|
||||||
|
|
||||||
|
// test various sub query related features ("queries in queries")
|
||||||
|
|
||||||
|
void SingleSelectQueryComposerTest::testSubQueries()
|
||||||
|
{
|
||||||
|
const OUString INNERPRODUCTSQUERY = u"products (inner)"_ustr;
|
||||||
|
DBTestBase::createQuery(u"SELECT * FROM \"PRODUCTS\""_ustr, true, INNERPRODUCTSQUERY,
|
||||||
|
m_xDataSource);
|
||||||
|
|
||||||
|
m_xComposer->setQuery(u"SELECT * FROM \""_ustr + INNERPRODUCTSQUERY + u"\""_ustr);
|
||||||
|
|
||||||
|
Reference<sdbcx::XTablesSupplier> suppTables(m_xComposer, UNO_QUERY_THROW);
|
||||||
|
Reference<container::XNameAccess> tables = suppTables->getTables();
|
||||||
|
CPPUNIT_ASSERT(tables->hasElements());
|
||||||
|
CPPUNIT_ASSERT(tables->hasByName(INNERPRODUCTSQUERY));
|
||||||
|
|
||||||
|
Reference<XQueriesSupplier> xQuerySupplier(m_xConnection, UNO_QUERY_THROW);
|
||||||
|
Reference<container::XNameAccess> xQueryAccess = xQuerySupplier->getQueries();
|
||||||
|
CPPUNIT_ASSERT(xQueryAccess->hasElements());
|
||||||
|
|
||||||
|
Reference<XPropertySet> xQuery(xQueryAccess->getByName(INNERPRODUCTSQUERY), UNO_QUERY);
|
||||||
|
OUString sInnerProductsQuery;
|
||||||
|
xQuery->getPropertyValue(u"Command"_ustr) >>= sInnerProductsQuery;
|
||||||
|
|
||||||
|
const OUString sExpectedQuery = u"SELECT * FROM ( "_ustr + sInnerProductsQuery
|
||||||
|
+ u" )"
|
||||||
|
" AS \""_ustr
|
||||||
|
+ INNERPRODUCTSQUERY + u"\""_ustr;
|
||||||
|
const OUString sExecutableQuery = m_xComposer->getQueryWithSubstitution();
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT_EQUAL(sExpectedQuery, sExecutableQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
// test the XParametersSupplier functionality
|
||||||
|
|
||||||
|
void SingleSelectQueryComposerTest::testParameters()
|
||||||
|
{
|
||||||
|
// "orders for customers" is a query with a named parameter (based on another query)
|
||||||
|
DBTestBase::createQuery(
|
||||||
|
u"SELECT * FROM \"orders for customer\" WHERE \"Product Name\" LIKE ?"_ustr, true,
|
||||||
|
u"orders for customer and product"_ustr, m_xDataSource);
|
||||||
|
|
||||||
|
// "orders for customer and product" is query based on "orders for customers", adding an additional,
|
||||||
|
DBTestBase::createQuery(
|
||||||
|
u"SELECT * FROM \"all orders\" WHERE \"Customer Name\" LIKE :cname"_ustr, true,
|
||||||
|
u"orders for customer"_ustr, m_xDataSource);
|
||||||
|
|
||||||
|
Reference<XQueryDefinitionsSupplier> xQuerySupplier(m_xDataSource, UNO_QUERY);
|
||||||
|
Reference<container::XNameAccess> xQueryAccess = xQuerySupplier->getQueryDefinitions();
|
||||||
|
Reference<sdb::XQueryDefinition> xQueryDefinition(
|
||||||
|
xQueryAccess->getByName(u"orders for customer and product"_ustr), UNO_QUERY);
|
||||||
|
|
||||||
|
OUString sCustomersAndProduct;
|
||||||
|
xQueryDefinition->getPropertyValue(u"Command"_ustr) >>= sCustomersAndProduct;
|
||||||
|
|
||||||
|
m_xComposer->setQuery(sCustomersAndProduct);
|
||||||
|
|
||||||
|
Reference<XParametersSupplier> xSuppParams(m_xComposer, UNO_QUERY_THROW);
|
||||||
|
Reference<container::XIndexAccess> xParameters = xSuppParams->getParameters();
|
||||||
|
|
||||||
|
Sequence<OUString> const expectedParameters{ u"cname"_ustr, u"Product Name"_ustr };
|
||||||
|
CPPUNIT_ASSERT_EQUAL(expectedParameters.getLength(), xParameters->getCount());
|
||||||
|
|
||||||
|
for (auto i = 0; i < expectedParameters.getLength(); ++i)
|
||||||
|
{
|
||||||
|
Reference<XPropertySet> xParam(xParameters->getByIndex(i), UNO_QUERY);
|
||||||
|
OUString sParamName;
|
||||||
|
xParam->getPropertyValue(u"Name"_ustr) >>= sParamName;
|
||||||
|
CPPUNIT_ASSERT_EQUAL(expectedParameters[i], sParamName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleSelectQueryComposerTest::testConditionByColumn()
|
||||||
|
{
|
||||||
|
m_xComposer->setQuery("SELECT * FROM \"CUSTOMERS\"");
|
||||||
|
Sequence<Any> aArgs{ Any(NamedValue(u"AutomaticAddition"_ustr, Any(true))) };
|
||||||
|
Reference<beans::XPropertyContainer> filter(
|
||||||
|
m_xSFactory->createInstanceWithArguments(u"com.sun.star.beans.PropertyBag"_ustr, aArgs),
|
||||||
|
UNO_QUERY);
|
||||||
|
|
||||||
|
filter->addProperty(u"Name"_ustr, PropertyAttribute::MAYBEVOID, Any(u"COMMENT"_ustr));
|
||||||
|
filter->addProperty(u"RealName"_ustr, PropertyAttribute::MAYBEVOID, Any(u"COMMENT"_ustr));
|
||||||
|
filter->addProperty(u"TableName"_ustr, PropertyAttribute::MAYBEVOID, Any(u"CUSTOMERS"_ustr));
|
||||||
|
filter->addProperty(u"Value"_ustr, PropertyAttribute::MAYBEVOID, Any(u"Good one."_ustr));
|
||||||
|
filter->addProperty(u"Type"_ustr, PropertyAttribute::MAYBEVOID,
|
||||||
|
Any(sal_Int32(sdbc::DataType::LONGVARCHAR)));
|
||||||
|
|
||||||
|
Reference<XPropertySet> xColumn(filter, UNO_QUERY_THROW);
|
||||||
|
m_xComposer->appendFilterByColumn(xColumn, true, SQLFilterOperator::LIKE);
|
||||||
|
|
||||||
|
Reference<XStatement> xStatement = m_xConnection->createStatement();
|
||||||
|
Reference<XResultSet> xResults = xStatement->executeQuery(m_xComposer->getQuery());
|
||||||
|
CPPUNIT_ASSERT(xResults.is());
|
||||||
|
|
||||||
|
// At least one row should exist
|
||||||
|
Reference<XRow> xRow(xResults, UNO_QUERY_THROW);
|
||||||
|
CPPUNIT_ASSERT(xResults->next());
|
||||||
|
// The row returned should be the 4th, i.e. the one that
|
||||||
|
// contains the Value "Good One"
|
||||||
|
CPPUNIT_ASSERT_EQUAL(u"4"_ustr, xRow->getString(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// tests the disjunctive normal form functionality, aka the structured filter,
|
||||||
|
// of the composer
|
||||||
|
|
||||||
|
void SingleSelectQueryComposerTest::testDisjunctiveNormalForm()
|
||||||
|
{
|
||||||
|
// a simple case: WHERE clause simply is a combination of predicates knitted with AND
|
||||||
|
OUString sQuery = u"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\" "
|
||||||
|
") "_ustr;
|
||||||
|
|
||||||
|
m_xComposer->setQuery(sQuery);
|
||||||
|
|
||||||
|
{
|
||||||
|
Sequence<Sequence<PropertyValue>> disjunctiveNormalForm
|
||||||
|
= m_xComposer->getStructuredFilter();
|
||||||
|
|
||||||
|
Sequence<PropertyValue> expectedDNF(3);
|
||||||
|
PropertyValue* pExpectedDNF = expectedDNF.getArray();
|
||||||
|
|
||||||
|
pExpectedDNF[0].Name = u"CUSTOMERID"_ustr;
|
||||||
|
pExpectedDNF[0].Handle = SQLFilterOperator::EQUAL;
|
||||||
|
pExpectedDNF[0].Value <<= u"\"CUSTOMERS\".\"ID\""_ustr;
|
||||||
|
pExpectedDNF[0].State = PropertyState_DIRECT_VALUE;
|
||||||
|
|
||||||
|
pExpectedDNF[1].Name = u"ORDERID"_ustr;
|
||||||
|
pExpectedDNF[1].Handle = SQLFilterOperator::EQUAL;
|
||||||
|
pExpectedDNF[1].Value <<= u"\"ORDER\".\"ID\""_ustr;
|
||||||
|
pExpectedDNF[1].State = PropertyState_DIRECT_VALUE;
|
||||||
|
|
||||||
|
pExpectedDNF[2].Name = u"PRODUCTID"_ustr;
|
||||||
|
pExpectedDNF[2].Handle = SQLFilterOperator::EQUAL;
|
||||||
|
pExpectedDNF[2].Value <<= u"\"PRODUCT\".\"ID\""_ustr;
|
||||||
|
pExpectedDNF[2].State = PropertyState_DIRECT_VALUE;
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), disjunctiveNormalForm.getLength());
|
||||||
|
|
||||||
|
for (auto i = 0; i < expectedDNF.getLength(); ++i)
|
||||||
|
{
|
||||||
|
CPPUNIT_ASSERT_EQUAL(expectedDNF[i].Name, disjunctiveNormalForm[0][i].Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// somewhat more challenging: One of the conjunction terms is a disjunction itself
|
||||||
|
sQuery = u"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 "
|
||||||
|
")"_ustr;
|
||||||
|
|
||||||
|
m_xComposer->setQuery(sQuery);
|
||||||
|
Sequence<Sequence<PropertyValue>> disjunctiveNormalForm = m_xComposer->getStructuredFilter();
|
||||||
|
|
||||||
|
{
|
||||||
|
Sequence<PropertyValue> firstExpectedDNF(4);
|
||||||
|
PropertyValue* pFirstExpectedDNF = firstExpectedDNF.getArray();
|
||||||
|
|
||||||
|
pFirstExpectedDNF[0].Name = u"CUSTOMERID"_ustr;
|
||||||
|
pFirstExpectedDNF[0].Handle = SQLFilterOperator::EQUAL;
|
||||||
|
pFirstExpectedDNF[0].Value <<= u"\"CUSTOMERS\".\"ID\""_ustr;
|
||||||
|
pFirstExpectedDNF[0].State = PropertyState_DIRECT_VALUE;
|
||||||
|
|
||||||
|
pFirstExpectedDNF[1].Name = u"ORDERID"_ustr;
|
||||||
|
pFirstExpectedDNF[1].Handle = SQLFilterOperator::EQUAL;
|
||||||
|
pFirstExpectedDNF[1].Value <<= u"\"ORDER\".\"ID\""_ustr;
|
||||||
|
pFirstExpectedDNF[1].State = PropertyState_DIRECT_VALUE;
|
||||||
|
|
||||||
|
pFirstExpectedDNF[2].Name = u"PRODUCTID"_ustr;
|
||||||
|
pFirstExpectedDNF[2].Handle = SQLFilterOperator::EQUAL;
|
||||||
|
pFirstExpectedDNF[2].Value <<= u"\"PRODUCT\".\"ID\""_ustr;
|
||||||
|
pFirstExpectedDNF[2].State = PropertyState_DIRECT_VALUE;
|
||||||
|
|
||||||
|
pFirstExpectedDNF[3].Name = u"Name"_ustr;
|
||||||
|
pFirstExpectedDNF[3].Handle = SQLFilterOperator::EQUAL;
|
||||||
|
pFirstExpectedDNF[3].Value <<= u"\"Apples\""_ustr;
|
||||||
|
pFirstExpectedDNF[3].State = PropertyState_DIRECT_VALUE;
|
||||||
|
|
||||||
|
Sequence<PropertyValue> secondExpectedDNF(4);
|
||||||
|
PropertyValue* pSecondExpectedDNF = secondExpectedDNF.getArray();
|
||||||
|
|
||||||
|
pSecondExpectedDNF[0].Name = u"CUSTOMERID"_ustr;
|
||||||
|
pSecondExpectedDNF[0].Handle = SQLFilterOperator::EQUAL;
|
||||||
|
pSecondExpectedDNF[0].Value <<= u"\"CUSTOMERS\".\"ID\""_ustr;
|
||||||
|
pSecondExpectedDNF[0].State = PropertyState_DIRECT_VALUE;
|
||||||
|
|
||||||
|
pSecondExpectedDNF[1].Name = u"ORDERID"_ustr;
|
||||||
|
pSecondExpectedDNF[1].Handle = SQLFilterOperator::EQUAL;
|
||||||
|
pSecondExpectedDNF[1].Value <<= u"\"ORDER\".\"ID\""_ustr;
|
||||||
|
pSecondExpectedDNF[1].State = PropertyState_DIRECT_VALUE;
|
||||||
|
|
||||||
|
pSecondExpectedDNF[2].Name = u"PRODUCTID"_ustr;
|
||||||
|
pSecondExpectedDNF[2].Handle = SQLFilterOperator::EQUAL;
|
||||||
|
pSecondExpectedDNF[2].Value <<= u"\"PRODUCT\".\"ID\""_ustr;
|
||||||
|
pSecondExpectedDNF[2].State = PropertyState_DIRECT_VALUE;
|
||||||
|
|
||||||
|
pSecondExpectedDNF[3].Name = u"ID"_ustr;
|
||||||
|
pSecondExpectedDNF[3].Handle = SQLFilterOperator::EQUAL;
|
||||||
|
pSecondExpectedDNF[3].Value <<= sal_Int32(2);
|
||||||
|
pSecondExpectedDNF[3].State = PropertyState_DIRECT_VALUE;
|
||||||
|
|
||||||
|
Sequence<Sequence<PropertyValue>> expectedDNF(2);
|
||||||
|
Sequence<PropertyValue>* pExpectedDNF = expectedDNF.getArray();
|
||||||
|
pExpectedDNF[0] = firstExpectedDNF;
|
||||||
|
pExpectedDNF[1] = secondExpectedDNF;
|
||||||
|
|
||||||
|
CPPUNIT_ASSERT_EQUAL(expectedDNF.getLength(), disjunctiveNormalForm.getLength());
|
||||||
|
|
||||||
|
for (auto i = 0; i < expectedDNF.getLength(); ++i)
|
||||||
|
{
|
||||||
|
for (auto j = 0; j < expectedDNF[0].getLength(); ++j)
|
||||||
|
{
|
||||||
|
CPPUNIT_ASSERT_EQUAL(expectedDNF[i][j].Name, disjunctiveNormalForm[i][j].Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION(SingleSelectQueryComposerTest);
|
||||||
|
|
||||||
|
CPPUNIT_PLUGIN_IMPLEMENT();
|
||||||
|
|
||||||
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
Reference in New Issue
Block a user