mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-12 13:01:09 +03:00
Calculate non-aggregate expressions in the SELECT list of an aggregate query
that does not use min() or max() once per group, instead of once per row visited. FossilOrigin-Name: dce2dfbe1590deb3ef5661230ae2d232bd492441195defbf698ac56f9629211c
This commit is contained in:
23
manifest
23
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Update\sand\scorrect\sthe\sdocumentation\son\sthe\sOP_OpenRead,\sOP_OpenWrite,\nand\sOP_ReopenIdx\sopcodes.\s\sNo\scode\schanges\sother\sthan\sthe\saddition\sof\nan\sassert().
|
C Calculate\snon-aggregate\sexpressions\sin\sthe\sSELECT\slist\sof\san\saggregate\squery\nthat\sdoes\snot\suse\smin()\sor\smax()\sonce\sper\sgroup,\sinstead\sof\sonce\sper\srow\nvisited.
|
||||||
D 2018-06-05T13:43:02.599
|
D 2018-06-05T20:04:28.586
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F Makefile.in bfc40f350586923e0419d2ea4b559c37ec10ee4b6e210e08c14401f8e340f0da
|
F Makefile.in bfc40f350586923e0419d2ea4b559c37ec10ee4b6e210e08c14401f8e340f0da
|
||||||
@@ -495,7 +495,7 @@ F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365
|
|||||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||||
F src/resolve.c 14602f46800ba182ea6a490e0f304127d29ac1f724bdadcc639e25d3223fcf6e
|
F src/resolve.c 14602f46800ba182ea6a490e0f304127d29ac1f724bdadcc639e25d3223fcf6e
|
||||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||||
F src/select.c 3291892add3a8f01dc3754e40ef9e30ad22c78e3404a388ae58f0390a1fb29eb
|
F src/select.c 8d3176c5258cc83942815ebe75b4c1f8dcf62b5e0f4d37373a14ebf23c046f9f
|
||||||
F src/shell.c.in c29cb307d6275131e6f9874e0fa73f87acf40a22c4a82faba2059a93b4d294d1
|
F src/shell.c.in c29cb307d6275131e6f9874e0fa73f87acf40a22c4a82faba2059a93b4d294d1
|
||||||
F src/sqlite.h.in 63b07f76731f2b1e55c48fdb9f0508dcc6fbe3971010b8612ffd847c3c56d9a1
|
F src/sqlite.h.in 63b07f76731f2b1e55c48fdb9f0508dcc6fbe3971010b8612ffd847c3c56d9a1
|
||||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||||
@@ -587,7 +587,7 @@ F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
|||||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||||
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
|
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
|
||||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||||
F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
|
F test/aggnested.test 18b00de006597e960a6b27ccec51474ac66cf1070a87c1933e5694dc02190ef1
|
||||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||||
F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783
|
F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783
|
||||||
F test/alter.test b820ab9dcf85f8e3a65bc8326accb2f0c7be64ef
|
F test/alter.test b820ab9dcf85f8e3a65bc8326accb2f0c7be64ef
|
||||||
@@ -778,7 +778,7 @@ F test/e_fts3.test 8cf40550bb088a6aa187c818c00fabe26ef82900a4cd5c66b427ccafe28be
|
|||||||
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
|
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
|
||||||
F test/e_reindex.test 2bebf7b393e519198b7c654407221cf171a439b8
|
F test/e_reindex.test 2bebf7b393e519198b7c654407221cf171a439b8
|
||||||
F test/e_resolve.test a61751c368b109db73df0f20fc75fb47e166b1d8
|
F test/e_resolve.test a61751c368b109db73df0f20fc75fb47e166b1d8
|
||||||
F test/e_select.test 6fd45fd4a59ec82b6dda7468699dcc0ec1a72538577750b4f90357a62c1d2723
|
F test/e_select.test c5a669b4d63217aa10094ba737ba3ddd07bd439d4bc7a5b798f6ea32511cbe7c
|
||||||
F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
|
F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
|
||||||
F test/e_totalchanges.test b12ee5809d3e63aeb83238dd501a7bca7fd72c10
|
F test/e_totalchanges.test b12ee5809d3e63aeb83238dd501a7bca7fd72c10
|
||||||
F test/e_update.test f46c2554d915c9197548681e8d8c33a267e84528
|
F test/e_update.test f46c2554d915c9197548681e8d8c33a267e84528
|
||||||
@@ -1213,7 +1213,7 @@ F test/select1.test 2e760bab8f3658b3b97debcf52860d0d2e20aa6cbe8b40e678ddb99871a1
|
|||||||
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
|
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
|
||||||
F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
|
F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
|
||||||
F test/select4.test 5389d9895968d1196c457d59b3ee6515d771d328
|
F test/select4.test 5389d9895968d1196c457d59b3ee6515d771d328
|
||||||
F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535
|
F test/select5.test df9ec0d218cedceb4fe7b63262025b547b50a55e59148c6f40b60ca25f1d4546
|
||||||
F test/select6.test 39eac4a5c03650b2b473c532882273283ee8b7a0
|
F test/select6.test 39eac4a5c03650b2b473c532882273283ee8b7a0
|
||||||
F test/select7.test f659f231489349e8c5734e610803d7654207318f
|
F test/select7.test f659f231489349e8c5734e610803d7654207318f
|
||||||
F test/select8.test 8c8f5ae43894c891efc5755ed905467d1d67ad5d
|
F test/select8.test 8c8f5ae43894c891efc5755ed905467d1d67ad5d
|
||||||
@@ -1730,7 +1730,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P c7ee0833225bfd8c5ec2f9bf62b97c4e04d03bd9566366d5221ac8fb199a87ca
|
P 8a0b730d0ea640d5cf75febe39b2162411a12eb5275765a85882158b5a085681
|
||||||
R 0277d841a9ebaf3476d82cef8e2d4609
|
R 68f88270aa2c2118664b882e11dbe18f
|
||||||
U drh
|
T *branch * exp-agg-opt
|
||||||
Z a41043871845bbfbe4b1d10a98baf884
|
T *sym-exp-agg-opt *
|
||||||
|
T -sym-trunk *
|
||||||
|
U dan
|
||||||
|
Z 491386dd047a3b3fa6ba9455da7a08ff
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
8a0b730d0ea640d5cf75febe39b2162411a12eb5275765a85882158b5a085681
|
dce2dfbe1590deb3ef5661230ae2d232bd492441195defbf698ac56f9629211c
|
||||||
37
src/select.c
37
src/select.c
@@ -5100,11 +5100,17 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Update the accumulator memory cells for an aggregate based on
|
** Update the accumulator memory cells for an aggregate based on
|
||||||
** the current cursor position.
|
** the current cursor position.
|
||||||
|
**
|
||||||
|
** If regAcc is non-zero and there are no min() or max() aggregates
|
||||||
|
** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator
|
||||||
|
** registers i register regAcc contains 0. The caller will take care
|
||||||
|
** of setting and clearing regAcc.
|
||||||
*/
|
*/
|
||||||
static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
|
||||||
Vdbe *v = pParse->pVdbe;
|
Vdbe *v = pParse->pVdbe;
|
||||||
int i;
|
int i;
|
||||||
int regHit = 0;
|
int regHit = 0;
|
||||||
@@ -5168,6 +5174,9 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
|||||||
** Another solution would be to change the OP_SCopy used to copy cached
|
** Another solution would be to change the OP_SCopy used to copy cached
|
||||||
** values to an OP_Copy.
|
** values to an OP_Copy.
|
||||||
*/
|
*/
|
||||||
|
if( regHit==0 && pAggInfo->nAccumulator ){
|
||||||
|
regHit = regAcc;
|
||||||
|
}
|
||||||
if( regHit ){
|
if( regHit ){
|
||||||
addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v);
|
addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v);
|
||||||
}
|
}
|
||||||
@@ -6021,8 +6030,6 @@ int sqlite3Select(
|
|||||||
pParse->nMem += pGroupBy->nExpr;
|
pParse->nMem += pGroupBy->nExpr;
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag);
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, iAbortFlag);
|
||||||
VdbeComment((v, "clear abort flag"));
|
VdbeComment((v, "clear abort flag"));
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
|
|
||||||
VdbeComment((v, "indicate accumulator empty"));
|
|
||||||
sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1);
|
sqlite3VdbeAddOp3(v, OP_Null, 0, iAMem, iAMem+pGroupBy->nExpr-1);
|
||||||
|
|
||||||
/* Begin a loop that will extract all source rows in GROUP BY order.
|
/* Begin a loop that will extract all source rows in GROUP BY order.
|
||||||
@@ -6155,7 +6162,7 @@ int sqlite3Select(
|
|||||||
** the current row
|
** the current row
|
||||||
*/
|
*/
|
||||||
sqlite3VdbeJumpHere(v, addr1);
|
sqlite3VdbeJumpHere(v, addr1);
|
||||||
updateAccumulator(pParse, &sAggInfo);
|
updateAccumulator(pParse, iUseFlag, &sAggInfo);
|
||||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
|
sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
|
||||||
VdbeComment((v, "indicate data in accumulator"));
|
VdbeComment((v, "indicate data in accumulator"));
|
||||||
|
|
||||||
@@ -6207,6 +6214,8 @@ int sqlite3Select(
|
|||||||
*/
|
*/
|
||||||
sqlite3VdbeResolveLabel(v, addrReset);
|
sqlite3VdbeResolveLabel(v, addrReset);
|
||||||
resetAccumulator(pParse, &sAggInfo);
|
resetAccumulator(pParse, &sAggInfo);
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
|
||||||
|
VdbeComment((v, "indicate accumulator empty"));
|
||||||
sqlite3VdbeAddOp1(v, OP_Return, regReset);
|
sqlite3VdbeAddOp1(v, OP_Return, regReset);
|
||||||
|
|
||||||
} /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
|
} /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
|
||||||
@@ -6272,6 +6281,23 @@ int sqlite3Select(
|
|||||||
}else
|
}else
|
||||||
#endif /* SQLITE_OMIT_BTREECOUNT */
|
#endif /* SQLITE_OMIT_BTREECOUNT */
|
||||||
{
|
{
|
||||||
|
int regAcc = 0; /* "populate accumulators" flag */
|
||||||
|
|
||||||
|
/* If there are accumulator registers but no min() or max() functions,
|
||||||
|
** allocate register regAcc. Register regAcc will contain 0 the first
|
||||||
|
** time the inner loop runs, and 1 thereafter. The code generated
|
||||||
|
** by updateAccumulator() only updates the accumulator registers if
|
||||||
|
** regAcc contains 0. */
|
||||||
|
if( sAggInfo.nAccumulator ){
|
||||||
|
for(i=0; i<sAggInfo.nFunc; i++){
|
||||||
|
if( sAggInfo.aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ) break;
|
||||||
|
}
|
||||||
|
if( i==sAggInfo.nFunc ){
|
||||||
|
regAcc = ++pParse->nMem;
|
||||||
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* This case runs if the aggregate has no GROUP BY clause. The
|
/* This case runs if the aggregate has no GROUP BY clause. The
|
||||||
** processing is much simpler since there is only a single row
|
** processing is much simpler since there is only a single row
|
||||||
** of output.
|
** of output.
|
||||||
@@ -6293,7 +6319,8 @@ int sqlite3Select(
|
|||||||
if( pWInfo==0 ){
|
if( pWInfo==0 ){
|
||||||
goto select_end;
|
goto select_end;
|
||||||
}
|
}
|
||||||
updateAccumulator(pParse, &sAggInfo);
|
updateAccumulator(pParse, regAcc, &sAggInfo);
|
||||||
|
if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc);
|
||||||
if( sqlite3WhereIsOrdered(pWInfo)>0 ){
|
if( sqlite3WhereIsOrdered(pWInfo)>0 ){
|
||||||
sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
|
sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
|
||||||
VdbeComment((v, "%s() by index",
|
VdbeComment((v, "%s() by index",
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ do_test aggnested-2.0 {
|
|||||||
t1.*
|
t1.*
|
||||||
FROM t1;
|
FROM t1;
|
||||||
}
|
}
|
||||||
} {A,B,B 3 33 333 3333}
|
} {A,B,B 1 11 111 1111}
|
||||||
db2 close
|
db2 close
|
||||||
|
|
||||||
##################### Test cases for ticket [bfbf38e5e9956ac69f] ############
|
##################### Test cases for ticket [bfbf38e5e9956ac69f] ############
|
||||||
|
|||||||
@@ -801,7 +801,7 @@ do_select_tests e_select-4.1 {
|
|||||||
4 "SELECT z2.* FROM z1,z2 LIMIT 1" {{} 21}
|
4 "SELECT z2.* FROM z1,z2 LIMIT 1" {{} 21}
|
||||||
5 "SELECT z2.*, z1.* FROM z1,z2 LIMIT 1" {{} 21 51.65 -59.58 belfries}
|
5 "SELECT z2.*, z1.* FROM z1,z2 LIMIT 1" {{} 21 51.65 -59.58 belfries}
|
||||||
|
|
||||||
6 "SELECT count(*), * FROM z1" {6 63 born -26}
|
6 "SELECT count(*), * FROM z1" {6 51.65 -59.58 belfries}
|
||||||
7 "SELECT max(a), * FROM z1" {63 63 born -26}
|
7 "SELECT max(a), * FROM z1" {63 63 born -26}
|
||||||
8 "SELECT *, min(a) FROM z1" {-5 {} 75 -5}
|
8 "SELECT *, min(a) FROM z1" {-5 {} 75 -5}
|
||||||
|
|
||||||
@@ -939,13 +939,13 @@ do_execsql_test e_select-4.6.0 {
|
|||||||
INSERT INTO a2 VALUES(10, 4);
|
INSERT INTO a2 VALUES(10, 4);
|
||||||
} {}
|
} {}
|
||||||
do_select_tests e_select-4.6 {
|
do_select_tests e_select-4.6 {
|
||||||
1 "SELECT one, two, count(*) FROM a1" {4 10 4}
|
1 "SELECT one, two, count(*) FROM a1" {1 1 4}
|
||||||
2 "SELECT one, two, count(*) FROM a1 WHERE one<3" {2 3 2}
|
2 "SELECT one, two, count(*) FROM a1 WHERE one<3" {1 1 2}
|
||||||
3 "SELECT one, two, count(*) FROM a1 WHERE one>3" {4 10 1}
|
3 "SELECT one, two, count(*) FROM a1 WHERE one>3" {4 10 1}
|
||||||
4 "SELECT *, count(*) FROM a1 JOIN a2" {4 10 10 4 16}
|
4 "SELECT *, count(*) FROM a1 JOIN a2" {1 1 1 1 16}
|
||||||
5 "SELECT *, sum(three) FROM a1 NATURAL JOIN a2" {3 6 2 3}
|
5 "SELECT *, sum(three) FROM a1 NATURAL JOIN a2" {1 1 1 3}
|
||||||
6 "SELECT *, sum(three) FROM a1 NATURAL JOIN a2" {3 6 2 3}
|
6 "SELECT *, sum(three) FROM a1 NATURAL JOIN a2" {1 1 1 3}
|
||||||
7 "SELECT group_concat(three, ''), a1.* FROM a1 NATURAL JOIN a2" {12 3 6}
|
7 "SELECT group_concat(three, ''), a1.* FROM a1 NATURAL JOIN a2" {12 1 1}
|
||||||
}
|
}
|
||||||
|
|
||||||
# EVIDENCE-OF: R-04486-07266 Or, if the dataset contains zero rows, then
|
# EVIDENCE-OF: R-04486-07266 Or, if the dataset contains zero rows, then
|
||||||
@@ -1128,7 +1128,7 @@ do_select_tests e_select-4.13 {
|
|||||||
2.1 "SELECT up FROM c1 GROUP BY up HAVING down>10" {y}
|
2.1 "SELECT up FROM c1 GROUP BY up HAVING down>10" {y}
|
||||||
2.2 "SELECT up FROM c1 GROUP BY up HAVING up='y'" {y}
|
2.2 "SELECT up FROM c1 GROUP BY up HAVING up='y'" {y}
|
||||||
|
|
||||||
2.3 "SELECT i, j FROM c2 GROUP BY i>4 HAVING i>6" {9 36}
|
2.3 "SELECT i, j FROM c2 GROUP BY i>4 HAVING j>6" {5 10}
|
||||||
}
|
}
|
||||||
|
|
||||||
# EVIDENCE-OF: R-23927-54081 Each expression in the result-set is then
|
# EVIDENCE-OF: R-23927-54081 Each expression in the result-set is then
|
||||||
@@ -1154,12 +1154,12 @@ do_select_tests e_select-4.15 {
|
|||||||
# for the same row.
|
# for the same row.
|
||||||
#
|
#
|
||||||
do_select_tests e_select-4.15 {
|
do_select_tests e_select-4.15 {
|
||||||
1 "SELECT i, j FROM c2 GROUP BY i%2" {8 28 9 36}
|
1 "SELECT i, j FROM c2 GROUP BY i%2" {2 1 1 0}
|
||||||
2 "SELECT i, j FROM c2 GROUP BY i%2 HAVING j<30" {8 28}
|
2 "SELECT i, j FROM c2 GROUP BY i%2 HAVING j<30" {2 1 1 0}
|
||||||
3 "SELECT i, j FROM c2 GROUP BY i%2 HAVING j>30" {9 36}
|
3 "SELECT i, j FROM c2 GROUP BY i%2 HAVING j>30" {}
|
||||||
4 "SELECT i, j FROM c2 GROUP BY i%2 HAVING j>30" {9 36}
|
4 "SELECT i, j FROM c2 GROUP BY i%2 HAVING j>30" {}
|
||||||
5 "SELECT count(*), i, k FROM c2 NATURAL JOIN c3 GROUP BY substr(k, 1, 1)"
|
5 "SELECT count(*), i, k FROM c2 NATURAL JOIN c3 GROUP BY substr(k, 1, 1)"
|
||||||
{2 5 boron 2 2 helium 1 3 lithium}
|
{2 4 beryllium 2 1 hydrogen 1 3 lithium}
|
||||||
}
|
}
|
||||||
|
|
||||||
# EVIDENCE-OF: R-19334-12811 Each group of input dataset rows
|
# EVIDENCE-OF: R-19334-12811 Each group of input dataset rows
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ do_test select5-5.5 {
|
|||||||
execsql {
|
execsql {
|
||||||
SELECT a, b FROM t2 GROUP BY a;
|
SELECT a, b FROM t2 GROUP BY a;
|
||||||
}
|
}
|
||||||
} {1 4 6 4}
|
} {1 2 6 4}
|
||||||
|
|
||||||
# Test rendering of columns for the GROUP BY clause.
|
# Test rendering of columns for the GROUP BY clause.
|
||||||
#
|
#
|
||||||
|
|||||||
Reference in New Issue
Block a user