Index: tck/src/java/org/apache/jdo/tck/query/api/SampleQueries.java
===================================================================
--- tck/src/java/org/apache/jdo/tck/query/api/SampleQueries.java (nonexistent)
+++ tck/src/java/org/apache/jdo/tck/query/api/SampleQueries.java (working copy)
@@ -0,0 +1,1370 @@
+package org.apache.jdo.tck.query.api;
+
+import org.apache.jdo.tck.JDO_Test;
+import org.apache.jdo.tck.pc.company.CompanyModelReader;
+import org.apache.jdo.tck.pc.company.Department;
+import org.apache.jdo.tck.pc.company.Employee;
+import org.apache.jdo.tck.pc.company.FullTimeEmployee;
+import org.apache.jdo.tck.pc.company.Person;
+import org.apache.jdo.tck.query.QueryTest;
+import org.apache.jdo.tck.util.BatchTestRunner;
+import org.apache.jdo.tck.util.EqualityHelper;
+
+import javax.jdo.Query;
+import javax.jdo.Transaction;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *Title: SampleQueries
+ *
+ *Keywords: query
+ *
+ *Assertion IDs:
+ *
+ *Assertion Description:
+ * This test class runs the example queries from the JDO specification.
+ */
+public class SampleQueries extends QueryTest {
+
+ /** */
+ private static final String ASSERTION_FAILED = "Assertion (SampleQueries) failed: ";
+
+ /** */
+ private static final String SAMPLE_QUERIES_TEST_COMPANY_TESTDATA =
+ "org/apache/jdo/tck/pc/company/companyForSampleQueriesTest.xml";
+
+ /**
+ * The main is called when the class
+ * is directly executed from the command line.
+ * @param args The arguments passed to the program.
+ */
+ public static void main(String[] args) {
+ BatchTestRunner.run(SampleQueries.class);
+ }
+
+ /**
+ * Basic query.
+ *
+ * This query selects all Employee instances from the candidate collection where
+ * the salary is greater than the constant 30000.
+ * Note that the float value for salary is unwrapped for the comparison with the
+ * literal int value, which is promoted to float using numeric promotion.
+ * If the value for the salary field in a candidate instance isnull, then it cannot
+ * be unwrapped for the comparison, and the candidate instance is rejected.
+ */
+ public void testQuery01a() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select where salary > 30000";
+ Query q = pm.newQuery(FullTimeEmployee.class, "salary > 30000");
+ List emps = (List)q.execute();
+ List expected =
+ getTransientCompanyModelInstancesAsList(new String[] {"emp1", "emp2", "emp5"});
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, emps, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Basic query.
+ *
+ * This query selects all Employee instances from the candidate collection where
+ * the salary is greater than the constant 30000.
+ * Note that the float value for salary is unwrapped for the comparison with the
+ * literal int value, which is promoted to float using numeric promotion.
+ * If the value for the salary field in a candidate instance isnull, then it cannot
+ * be unwrapped for the comparison, and the candidate instance is rejected.
+ */
+ public void testQuery01b() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select where salary > 30000";
+ Query q = pm.newQuery(FullTimeEmployee.class, "salary > 30000");
+ List emps = q.executeList();
+ List expected =
+ getTransientCompanyModelInstancesAsList(new String[] {"emp1", "emp2", "emp5"});
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, emps, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Basic query with ordering.
+ *
+ * This query selects all Employee instances from the candidate collection where the salary
+ * is greater than the constant 30000, and returns a Collection ordered based on employee salary.
+ */
+ public void testQuery02a() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select where salary > 30000 order by salary ascending";
+ Query q = pm.newQuery(FullTimeEmployee.class, "salary > 30000");
+ q.setOrdering ("salary ascending");
+ List emps = (List)q.execute();
+ List expected =
+ getTransientCompanyModelInstancesAsList(new String[] {"emp1", "emp5", "emp2"});
+ checkQueryResultWithOrder(ASSERTION_FAILED, singleStringQuery, emps, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Basic query with ordering.
+ *
+ * This query selects all Employee instances from the candidate collection where the salary
+ * is greater than the constant 30000, and returns a Collection ordered based on employee salary.
+ */
+ public void testQuery02b() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select where salary > 30000 order by salary ascending";
+ Query q = pm.newQuery(FullTimeEmployee.class, "salary > 30000");
+ q.setOrdering ("salary ascending");
+ List emps = q.executeList();
+ List expected =
+ getTransientCompanyModelInstancesAsList(new String[] {"emp1", "emp5", "emp2"});
+ checkQueryResultWithOrder(ASSERTION_FAILED, singleStringQuery, emps, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Parameter passing.
+ *
+ * This query selects all Employee instances from the candidate collection where the salary
+ * is greater than the value passed as a parameter and the name starts with the value passed
+ * as a second parameter.
+ * If the value for the salary field in a candidate instance is null, then it cannot be
+ * unwrapped for the comparison, and the candidate instance is rejected.
+ */
+ public void testQuery03a() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select where salary > :sal && firstname.startsWith(:begin)";
+ Query q =
+ pm.newQuery(FullTimeEmployee.class,"salary > sal && firstname.startsWith(begin)");
+ q.declareParameters("Double sal, String begin");
+ List emps = (List)q.execute(30000., "M");
+ List expected = getTransientCompanyModelInstancesAsList(new String[] {"emp1"});
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, emps, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Parameter passing.
+ *
+ * This query selects all Employee instances from the candidate collection where the salary
+ * is greater than the value passed as a parameter and the name starts with the value passed
+ * as a second parameter.
+ * If the value for the salary field in a candidate instance is null, then it cannot be
+ * unwrapped for the comparison, and the candidate instance is rejected.
+ */
+ public void testQuery03b() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select where salary > :sal && firstname.startsWith(:begin)";
+ Query q =
+ pm.newQuery(FullTimeEmployee.class,"salary > sal && firstname.startsWith(begin)");
+ q.declareParameters("Double sal, String begin");
+ Map paramValues = new HashMap<>();
+ paramValues.put("sal", 30000.);
+ paramValues.put("begin", "M");
+ q.setNamedParameters(paramValues);
+ List emps = q.executeList();
+ List expected = getTransientCompanyModelInstancesAsList(new String[] {"emp1"});
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, emps, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Navigation through single-valued field.
+ *
+ * This query selects all Employee instances from the candidate collection where the value
+ * of the name field in the Department instance associated with the Employee instance
+ * is equal to the value passed as a parameter.
+ * If the value for the dept field in a candidate instance is null, then it cannot be
+ * navigated for the comparison, and the candidate instance is rejected.
+ */
+ public void testQuery04a() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select where department.name == :dep";
+ Query q = pm.newQuery(Employee.class, "department.name == dep");
+ q.declareParameters("String dep");
+ List emps = (List)q.execute ("R&D");
+ List expected = getTransientCompanyModelInstancesAsList(new String[] {"emp1", "emp2", "emp3"});
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, emps, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Navigation through single-valued field.
+ *
+ * This query selects all Employee instances from the candidate collection where the value
+ * of the name field in the Department instance associated with the Employee instance
+ * is equal to the value passed as a parameter.
+ * If the value for the dept field in a candidate instance is null, then it cannot be
+ * navigated for the comparison, and the candidate instance is rejected.
+ */
+ public void testQuery04b() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select where department.name == :dep";
+ Query q = pm.newQuery (Employee.class, "department.name == dep");
+ q.declareParameters ("String dep");
+ Map paramValues = new HashMap<>();
+ paramValues.put("dep", "R&D");
+ q.setNamedParameters(paramValues);
+ List emps = q.executeList();
+ List expected = getTransientCompanyModelInstancesAsList(new String[] {"emp1", "emp2", "emp3"});
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, emps, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Navigation through multi-valued field.
+ *
+ * This query selects all Department instances from the candidate collection where
+ * the collection of Employee instances contains at least one Employee instance
+ * having a salary greater than the value passed as a parameter.
+ */
+ public void testQuery05a() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select where employees.contains(e) && e.weeklyhours > :hours";
+ String filter = "employees.contains (emp) && emp.weeklyhours > hours";
+ Query q = pm.newQuery(Department.class, filter);
+ q.declareVariables("Employee emp");
+ q.declareParameters("double hours");
+ List deps = (List)q.execute (30.);
+ List expected = getTransientCompanyModelInstancesAsList(new String[] {"dept1"});
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, deps, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Navigation through multi-valued field.
+ *
+ * This query selects all Department instances from the candidate collection where
+ * the collection of Employee instances contains at least one Employee instance
+ * having a salary greater than the value passed as a parameter.
+ */
+ public void testQuery05b() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select where employees.contains(e) && e.weeklyhours > :hours";
+ String filter = "employees.contains (emp) && emp.weeklyhours > hours";
+ Query q = pm.newQuery(Department.class, filter);
+ q.declareVariables("Employee emp");
+ q.declareParameters("double hours");
+ Map paramValues = new HashMap<>();
+ paramValues.put("hours", 30.);
+ q.setNamedParameters(paramValues);
+ List deps = q.executeList();
+ List expected = getTransientCompanyModelInstancesAsList(new String[] {"dept1"});
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, deps, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Membership in a collection.
+ *
+ * This query selects all Department instances where the name field is contained in
+ * a parameter collection, which in this example consists of three department names.
+ */
+ public void testQuery06a() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select where :depts.contains(name)";
+ String filter = "depts.contains(name)";
+ Query q = pm.newQuery(Department.class, filter);
+ q.declareParameters("java.util.Collection depts");
+ List depts = Arrays.asList("R&D", "Sales", "Marketing");
+ List deps = (List)q.execute(depts);
+ List expected =
+ getTransientCompanyModelInstancesAsList(new String[] {"dept1", "dept2", "dept3"});
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, deps, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Membership in a collection.
+ *
+ * This query selects all Department instances where the name field is contained in
+ * a parameter collection, which in this example consists of three department names.
+ */
+ public void testQuery06b() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select where :depts.contains(name)";
+ String filter = "depts.contains(name)";
+ Query q = pm.newQuery(Department.class, filter);
+ q.declareParameters("java.util.Collection depts");
+ Map paramValues = new HashMap<>();
+ paramValues.put("depts", Arrays.asList("R&D", "Sales", "Marketing"));
+ q.setNamedParameters(paramValues);
+ List deps = q.executeList();
+ List expected =
+ getTransientCompanyModelInstancesAsList(new String[] {"dept1", "dept2", "dept3"});
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, deps, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Projection of a Single Field.
+ *
+ * This query selects names of all Employees who work in the parameter department.
+ */
+ public void testQuery07a() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select firstname where department.name == :deptName";
+ Query q = pm.newQuery(Employee.class, "department.name == deptName");
+ q.setResult("firstname");
+ q.declareParameters("String deptName");
+ List names = (List)q.execute("R&D");
+ List expected = Arrays.asList("Joe", "Craig", "Michael");
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, names, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Projection of a Single Field.
+ *
+ * This query selects names of all Employees who work in the parameter department.
+ */
+ public void testQuery07b() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select firstname where department.name == :deptName";
+ Query q = pm.newQuery(Employee.class, "department.name == deptName");
+ q.setResult("firstname");
+ q.declareParameters("String deptName");
+ Map paramValues = new HashMap<>();
+ paramValues.put("deptName", "R&D");
+ q.setNamedParameters(paramValues);
+ List names = q.executeResultList(String.class);
+ List expected = Arrays.asList("Joe", "Craig", "Michael");
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, names, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Projection of Multiple Fields and Expressions.
+ *
+ * This query selects names, salaries, and bosses of Employees who work in the parameter department.
+ */
+ public void testQuery08a() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery =
+ "select firstname, salary, manager as reportsTo " +
+ "into org.apache.jdo.tck.query.api.SampleQueries$Info where department.name == :deptName";
+ Query q = pm.newQuery(FullTimeEmployee.class, "department.name == deptName");
+ q.setResult("firstname, salary, manager as reportsTo");
+ q.setResultClass(Info.class);
+ q.declareParameters("String deptName");
+ List infos = (List) q.execute("R&D");
+
+ Info info1 = new Info();
+ info1.firstname = "Michael";
+ info1.salary = 40000.;
+ info1.reportsTo = (Employee)getTransientCompanyModelInstance("emp2");
+ Info info2 = new Info();
+ info2.firstname = "Craig";
+ info2.salary = 50000.;
+ info2.reportsTo = null;
+ List expected = Arrays.asList(info1, info2);
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, infos, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Projection of Multiple Fields and Expressions.
+ *
+ * This query selects names, salaries, and bosses of Employees who work in the parameter department.
+ */
+ public void testQuery08b() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery =
+ "select firstname, salary, manager as reportsTo " +
+ "into org.apache.jdo.tck.query.api.SampleQueries$Info where department.name == :deptName";
+ Query q = pm.newQuery(FullTimeEmployee.class, "department.name == deptName");
+ q.setResult("firstname, salary, manager as reportsTo");
+ q.setResultClass(Info.class);
+ q.declareParameters("String deptName");
+ Map paramValues = new HashMap<>();
+ paramValues.put("deptName", "R&D");
+ q.setNamedParameters(paramValues);
+ List infos = q.executeResultList(Info.class);
+
+ Info info1 = new Info();
+ info1.firstname = "Michael";
+ info1.salary = 40000.;
+ info1.reportsTo = (Employee)getTransientCompanyModelInstance("emp2");
+ Info info2 = new Info();
+ info2.firstname = "Craig";
+ info2.salary = 50000.;
+ info2.reportsTo = null;
+ List expected = Arrays.asList(info1, info2);
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, infos, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Projection of Multiple Fields and Expressions into a Constructed instance.
+ *
+ * This query selects names, salaries, and bosses of Employees who work in the parameter department,
+ * and uses the constructor for the result class.
+ */
+ public void testQuery09a() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery =
+ "select new org.apache.jdo.tck.query.api.SampleQueries$Info (firstname, salary, manager) " +
+ "where department.name == :deptName";
+ Query q = pm.newQuery(FullTimeEmployee.class, "department.name == deptName");
+ q.setResult("new org.apache.jdo.tck.query.api.SampleQueries$Info(firstname, salary, manager)");
+ q.declareParameters("String deptName");
+ List infos = (List)q.execute("R&D");
+
+ List expected = Arrays.asList(
+ new Info("Michael", 40000., (Employee)getTransientCompanyModelInstance("emp2")),
+ new Info("Craig", 50000., null)
+ );
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, infos, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Projection of Multiple Fields and Expressions into a Constructed instance.
+ *
+ * This query selects names, salaries, and bosses of Employees who work in the parameter department,
+ * and uses the constructor for the result class.
+ */
+ public void testQuery09b() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery =
+ "select new org.apache.jdo.tck.query.api.SampleQueries$Info (firstname, salary, manager) " +
+ "where department.name == :deptName";
+ Query q = pm.newQuery(FullTimeEmployee.class, "department.name == deptName");
+ q.setResult("new org.apache.jdo.tck.query.api.SampleQueries$Info(firstname, salary, manager)");
+ q.declareParameters("String deptName");
+ Map paramValues = new HashMap<>();
+ paramValues.put("deptName", "R&D");
+ q.setNamedParameters(paramValues);
+ List infos = q.executeResultList(Info.class);
+
+ List expected = Arrays.asList(
+ new Info("Michael", 40000., (Employee)getTransientCompanyModelInstance("emp2")),
+ new Info("Craig", 50000., null)
+ );
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, infos, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Aggregation of a single Field.
+ *
+ * This query averages the salaries of Employees who work in the parameter department
+ * and returns a single value.
+ */
+ public void testQuery10a() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select avg(salary) where department.name == :deptName";
+ Query q = pm.newQuery(FullTimeEmployee.class, "department.name == deptName");
+ q.setResult("avg(salary)");
+ q.declareParameters("String deptName");
+ Double avgSalary = (Double) q.execute("R&D");
+
+ Double expected = 45000.;
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, avgSalary, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Aggregation of a single Field.
+ *
+ * This query averages the salaries of Employees who work in the parameter department
+ * and returns a single value.
+ */
+ public void testQuery10b() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select avg(salary) where department.name == :deptName";
+ Query q = pm.newQuery(FullTimeEmployee.class, "department.name == deptName");
+ q.setResult("avg(salary)");
+ q.declareParameters("String deptName");
+ Map paramValues = new HashMap<>();
+ paramValues.put("deptName", "R&D");
+ q.setNamedParameters(paramValues);
+ Double avgSalary = q.executeResultUnique(Double.class);
+
+ Double expected = 45000.;
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, avgSalary, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Aggregation of Multiple Fields and Expressions.
+ *
+ * This query averages and sums the salaries of Employees who work in the parameter department.
+ */
+ public void testQuery11a() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select avg(salary), sum(salary) where department.name == :deptName";
+ Query q = pm.newQuery(FullTimeEmployee.class, "department.name == deptName");
+ q.setResult("avg(salary), sum(salary)");
+ q.declareParameters("String deptName");
+ Object[] avgSum = (Object[]) q.execute("R&D");
+
+ Double[] expected = new Double[] {45000., 90000.};
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, avgSum, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Aggregation of Multiple Fields and Expressions.
+ *
+ * This query averages and sums the salaries of Employees who work in the parameter department.
+ */
+ public void testQuery11b() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery = "select avg(salary), sum(salary) where department.name == :deptName";
+ Query q = pm.newQuery(FullTimeEmployee.class, "department.name == deptName");
+ q.setResult("avg(salary), sum(salary)");
+ q.declareParameters("String deptName");
+ Map paramValues = new HashMap<>();
+ paramValues.put("deptName", "R&D");
+ q.setNamedParameters(paramValues);
+ Object[] avgSum = (Object[])q.executeResultUnique();
+
+ Double[] expected = new Double[] {45000., 90000.};
+ checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, avgSum, expected);
+ tx.commit();
+ } finally {
+ if (tx.isActive()) {
+ tx.rollback();
+ }
+ }
+ }
+
+ /**
+ * Aggregation of Multiple fields with Grouping.
+ *
+ * This query averages and sums the salaries of Employees who work in all departments having
+ * more than one employee and aggregates by department name.
+ */
+ public void testQuery12a() {
+ Transaction tx = pm.currentTransaction();
+ try {
+ tx.begin();
+ String singleStringQuery =
+ "select avg(salary), sum(salary), department.name " +
+ "from org.apache.jdo.tck.pc.company.FullTimeEmployee " +
+ "where department.name == :deptName " +
+ "group by department.name having count(department.name)";
+ Query q = pm.newQuery(FullTimeEmployee.class);
+ q.setResult("avg(salary), sum(salary), department.name");
+ q.setGrouping("department.name having count(department.name) > 1");
+ List