Index: java/engine/org/apache/derby/impl/sql/compile/GroupByNode.java
===================================================================
--- java/engine/org/apache/derby/impl/sql/compile/GroupByNode.java	(revision 628228)
+++ java/engine/org/apache/derby/impl/sql/compile/GroupByNode.java	(working copy)
@@ -23,6 +23,7 @@
 
 import java.util.Iterator;
 import java.util.Vector;
+import java.util.ArrayList;
 
 import org.apache.derby.catalog.IndexDescriptor;
 import org.apache.derby.iapi.error.StandardException;
@@ -343,6 +344,7 @@
 		ResultColumnList bottomRCL  = childResult.getResultColumns();
 		ResultColumnList groupByRCL = resultColumns;
 
+		ArrayList referencesToSubstitute = new ArrayList();
 		int sz = groupingList.size();
 		for (int i = 0; i < sz; i++) 
 		{
@@ -385,12 +387,30 @@
 			// in the projection list with a virtual column node
 			// that effectively points to a result column 
 			// in the result set doing the group by
-			SubstituteExpressionVisitor se = 
-				new SubstituteExpressionVisitor(
-						gbc.getColumnExpression(),
-						vc,
+			//
+			// Note that we perform the VCN replacements
+			// for compound GROUP BY expressions inline, while
+			// we defer the VCN replacements for simple
+			// GROUP BY column references until after all
+			// the expressions have been processed. This is
+			// because a compound expression may contain a
+			// reference to a simple grouped column, but in
+			// such a case we want to process the expression
+			// as an expression, not as individual column
+			// references. E.g., if the statement was:
+			//   SELECT ... GROUP BY C1, C1 * (C2 / 100), C3
+			// then we don't want the replacement of the
+			// simple column reference C1 to affect the
+			// compound expression C1 * (C2 / 100). DERBY-3094.
+			//
+			ValueNode vn = gbc.getColumnExpression();
+			SubstituteExpressionVisitor vis =
+				new SubstituteExpressionVisitor(vn, vc,
 						AggregateNode.class);
-			parent.getResultColumns().accept(se);
+			if (vn instanceof ColumnReference)
+				referencesToSubstitute.add(vis);
+			else
+				parent.getResultColumns().accept(vis);
 			
 			// Since we always need a PR node on top of the GB 
 			// node to perform projection we can use it to perform 
@@ -423,6 +443,9 @@
 			}
 			gbc.setColumnPosition(bottomRCL.size());
 		}
+		for (int r = 0; r < referencesToSubstitute.size(); r++)
+			parent.getResultColumns().accept(
+				(SubstituteExpressionVisitor)referencesToSubstitute.get(r));
 	}
 
 	/**
Index: java/testing/org/apache/derbyTesting/functionTests/tests/lang/GroupByExpressionTest.java
===================================================================
--- java/testing/org/apache/derbyTesting/functionTests/tests/lang/GroupByExpressionTest.java	(revision 628228)
+++ java/testing/org/apache/derbyTesting/functionTests/tests/lang/GroupByExpressionTest.java	(working copy)
@@ -122,6 +122,98 @@
                         {9,13,2}});
     }
     
+    /**
+     * queries which combine compound expressions and simple column refs.
+     */
+    public void testDerby3094Expressions() throws Exception
+    {
+        verifyQueryResults(
+                "Q1",
+                "select c1+c2, sum(c3) from test group by c1+c2, c1",
+                new int[][] {
+                        {11, 100}, 
+                        {12, 100},  // c1=1, c2=11
+                        {12, 100},  // c1=2, c2=10
+                        {13, 202}});
+        verifyQueryResults(
+                "Q2",
+                "select c1+c2, sum(c3) from test group by c1, c1+c2",
+                new int[][] {
+                        {11, 100}, 
+                        {12, 100},  // c1=1, c2=11
+                        {12, 100},  // c1=2, c2=10
+                        {13, 202}});
+        verifyQueryResults(
+                "Q3",
+                "select c1, c1+c2 from test group by c1, c1+c2",
+                new int[][] {
+                        {1, 11}, 
+                        {1, 12},
+                        {2, 12},
+                        {2, 13}});
+        verifyQueryResults(
+                "Q4",
+                "select c1+c2, sum(c3) from test group by c1+c2",
+                new int[][] {
+                        {11, 100}, 
+                        {12, 200},
+                        {13, 202}});
+        verifyQueryResults(
+                "Q5",
+                "select c1,c2,c1+c2,sum(c3) from test group by c1,c2,c1+c2",
+                new int[][] {
+                        {1, 10, 11, 100},
+                        {1, 11, 12, 100},
+                        {2, 10, 12, 100},
+                        {2, 11, 13, 202}});
+        verifyQueryResults(
+                "Q6",
+                "select c1,c2,sum(c3) from test group by c2, c1",
+                new int[][] {
+                        {1, 10, 100},
+                        {2, 10, 100},
+                        {1, 11, 100},
+                        {2, 11, 202}});
+        verifyQueryResults(
+                "Q7",
+                "select c1 as c2, sum(c3) from test group by c1,c2",
+                new int[][] {
+                        {1, 100},
+                        {1, 100},
+                        {2, 100},
+                        {2, 202}});
+        verifyQueryResults(
+                "Q8",
+                "select c1 as c2, sum(c3) from test group by c1",
+                new int[][] {
+                        {1, 200},
+                        {2, 302}});
+        verifyQueryResults(
+                "Q9",
+            "select c1+c2, sum(c3) from test group by c1+c2 having c1+c2 > 11",
+                new int[][] {
+                        {12, 200},
+                        {13, 202}});
+        assertCompileError(
+                "42Y30", "select c1+c2, sum(c3) from test group by c1");
+        assertCompileError(
+                "42Y30", "select c1,c2, sum(c3) from test group by c1+c2,c1");
+        assertCompileError(
+                "42Y30", "select c1+c2, sum(c3) from test group by 1");
+        assertCompileError(
+            "42X04", "select c1+c2 as expr, sum(c3) from test group by expr");
+        assertCompileError(
+            "42X04", "select c1 as c1a, c2, sum(c3) from test group by c1a,c2");
+        assertCompileError(
+                "42Y30", "select c1 as c2, sum(c3) from test group by c2");
+        // FIXME -- The next query seems like it ought to produce:
+        // {12, 100},
+        // {12, 100},
+        // {13, 202}});
+        assertCompileError(
+            "42X24", "select c1+c2, sum(c3) from test " +
+                     "group by c1, c1+c2 having c1+c2 > 11");
+    }
     
     public void testSubSelect() throws Exception
     {
