Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit5433b48

Browse files
committed
Tweak sorting so that nulls appear at the front of a descending sort
(vs. at the end of a normal sort). This ensures that explicit sortsyield the same ordering as a btree index scan. To be really sure thatthat equivalence holds, we use the btree entries in pg_amop to decidewhether we are looking at a '<' or '>' operator. For a sort operatorthat has no btree association, we put the nulls at the front if theoperator is named '>' ... pretty grotty, but it does the right thing insimple ASC and DESC cases, and at least there's no possibility of gettinga different answer depending on the plan type chosen.
1 parente542036 commit5433b48

File tree

3 files changed

+144
-127
lines changed

3 files changed

+144
-127
lines changed

‎src/backend/commands/analyze.c

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.17 2001/05/07 00:43:17 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.18 2001/06/02 19:01:53 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1439,27 +1439,12 @@ compare_scalars(const void *a, const void *b)
14391439
intta= ((ScalarItem*)a)->tupno;
14401440
Datumdb= ((ScalarItem*)b)->value;
14411441
inttb= ((ScalarItem*)b)->tupno;
1442+
int32compare;
14421443

1443-
if (datumCmpFnKind==SORTFUNC_LT)
1444-
{
1445-
if (DatumGetBool(FunctionCall2(datumCmpFn,da,db)))
1446-
return-1;/* a < b */
1447-
if (DatumGetBool(FunctionCall2(datumCmpFn,db,da)))
1448-
return1;/* a > b */
1449-
}
1450-
else
1451-
{
1452-
/* sort function is CMP or REVCMP */
1453-
int32compare;
1454-
1455-
compare=DatumGetInt32(FunctionCall2(datumCmpFn,da,db));
1456-
if (compare!=0)
1457-
{
1458-
if (datumCmpFnKind==SORTFUNC_REVCMP)
1459-
compare=-compare;
1460-
returncompare;
1461-
}
1462-
}
1444+
compare=ApplySortFunction(datumCmpFn,datumCmpFnKind,
1445+
da, false,db, false);
1446+
if (compare!=0)
1447+
returncompare;
14631448

14641449
/*
14651450
* The two datums are equal, so update datumCmpTupnoLink[].

‎src/backend/utils/sort/tuplesort.c

Lines changed: 126 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
* Portions Copyright (c) 1994, Regents of the University of California
7979
*
8080
* IDENTIFICATION
81-
* $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.16 2001/05/07 00:43:24 tgl Exp $
81+
* $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.17 2001/06/02 19:01:52 tgl Exp $
8282
*
8383
*-------------------------------------------------------------------------
8484
*/
@@ -90,10 +90,12 @@
9090
#include"catalog/catname.h"
9191
#include"catalog/pg_amop.h"
9292
#include"catalog/pg_amproc.h"
93+
#include"catalog/pg_operator.h"
9394
#include"miscadmin.h"
9495
#include"utils/fmgroids.h"
9596
#include"utils/logtape.h"
9697
#include"utils/lsyscache.h"
98+
#include"utils/syscache.h"
9799
#include"utils/tuplesort.h"
98100

99101
/*
@@ -1732,53 +1734,25 @@ comparetup_heap(Tuplesortstate *state, const void *a, const void *b)
17321734
for (nkey=0;nkey<state->nKeys;nkey++)
17331735
{
17341736
ScanKeyscanKey=state->scanKeys+nkey;
1735-
SortFunctionKindfnKind=state->sortFnKinds[nkey];
17361737
AttrNumberattno=scanKey->sk_attno;
1737-
Datumlattr,
1738-
rattr;
1738+
Datumdatum1,
1739+
datum2;
17391740
boolisnull1,
17401741
isnull2;
1742+
int32compare;
17411743

1742-
lattr=heap_getattr(ltup,attno,tupDesc,&isnull1);
1743-
rattr=heap_getattr(rtup,attno,tupDesc,&isnull2);
1744+
datum1=heap_getattr(ltup,attno,tupDesc,&isnull1);
1745+
datum2=heap_getattr(rtup,attno,tupDesc,&isnull2);
17441746

1745-
if (isnull1)
1746-
{
1747-
if (!isnull2)
1748-
return1;/* NULL sorts after non-NULL */
1749-
}
1750-
elseif (isnull2)
1751-
return-1;
1752-
else
1747+
compare=ApplySortFunction(&scanKey->sk_func,
1748+
state->sortFnKinds[nkey],
1749+
datum1,isnull1,datum2,isnull2);
1750+
if (compare!=0)
17531751
{
1754-
int32compare;
1755-
1756-
if (fnKind==SORTFUNC_LT)
1757-
{
1758-
if (DatumGetBool(FunctionCall2(&scanKey->sk_func,
1759-
lattr,rattr)))
1760-
compare=-1;/* a < b */
1761-
elseif (DatumGetBool(FunctionCall2(&scanKey->sk_func,
1762-
rattr,lattr)))
1763-
compare=1;/* a > b */
1764-
else
1765-
compare=0;
1766-
}
1767-
else
1768-
{
1769-
/* sort function is CMP or REVCMP */
1770-
compare=DatumGetInt32(FunctionCall2(&scanKey->sk_func,
1771-
lattr,rattr));
1772-
if (fnKind==SORTFUNC_REVCMP)
1773-
compare=-compare;
1774-
}
1775-
1776-
if (compare!=0)
1777-
{
1778-
if (scanKey->sk_flags&SK_COMMUTE)
1779-
compare=-compare;
1780-
returncompare;
1781-
}
1752+
/* dead code? SK_COMMUTE can't actually be set here, can it? */
1753+
if (scanKey->sk_flags&SK_COMMUTE)
1754+
compare=-compare;
1755+
returncompare;
17821756
}
17831757
}
17841758

@@ -1861,7 +1835,6 @@ tuplesize_heap(Tuplesortstate *state, void *tup)
18611835
staticint
18621836
comparetup_index(Tuplesortstate*state,constvoid*a,constvoid*b)
18631837
{
1864-
18651838
/*
18661839
* This is almost the same as _bt_tuplecompare(), but we need to keep
18671840
* track of whether any null fields are present.
@@ -1880,41 +1853,28 @@ comparetup_index(Tuplesortstate *state, const void *a, const void *b)
18801853
for (i=1;i <=keysz;i++)
18811854
{
18821855
ScanKeyentry=&scankey[i-1];
1883-
DatumattrDatum1,
1884-
attrDatum2;
1885-
boolisFirstNull,
1886-
isSecondNull;
1856+
Datumdatum1,
1857+
datum2;
1858+
boolisnull1,
1859+
isnull2;
18871860
int32compare;
18881861

1889-
attrDatum1=index_getattr(tuple1,i,tupDes,&isFirstNull);
1890-
attrDatum2=index_getattr(tuple2,i,tupDes,&isSecondNull);
1862+
datum1=index_getattr(tuple1,i,tupDes,&isnull1);
1863+
datum2=index_getattr(tuple2,i,tupDes,&isnull2);
18911864

18921865
/* see comments about NULLs handling in btbuild */
1893-
if (isFirstNull)/* attr in tuple1 is NULL */
1894-
{
1895-
if (isSecondNull)/* attr in tuple2 is NULL too */
1896-
{
1897-
compare=0;
1898-
equal_hasnull= true;
1899-
}
1900-
else
1901-
compare=1;/* NULL ">" not-NULL */
1902-
}
1903-
elseif (isSecondNull)/* attr in tuple1 is NOT_NULL and */
1904-
{/* attr in tuple2 is NULL */
1905-
compare=-1;/* not-NULL "<" NULL */
1906-
}
1907-
else
1908-
{
1909-
/* the comparison function is always of CMP type */
1910-
compare=DatumGetInt32(FunctionCall2(&entry->sk_func,
1911-
attrDatum1,
1912-
attrDatum2));
1913-
}
1866+
1867+
/* the comparison function is always of CMP type */
1868+
compare=ApplySortFunction(&entry->sk_func,SORTFUNC_CMP,
1869+
datum1,isnull1,datum2,isnull2);
19141870

19151871
if (compare!=0)
19161872
return (int)compare;/* done when we find unequal
19171873
* attributes */
1874+
1875+
/* they are equal, so we only need to examine one null flag */
1876+
if (isnull1)
1877+
equal_hasnull= true;
19181878
}
19191879

19201880
/*
@@ -2002,35 +1962,9 @@ comparetup_datum(Tuplesortstate *state, const void *a, const void *b)
20021962
DatumTuple*ltup= (DatumTuple*)a;
20031963
DatumTuple*rtup= (DatumTuple*)b;
20041964

2005-
if (ltup->isNull)
2006-
{
2007-
if (!rtup->isNull)
2008-
return1;/* NULL sorts after non-NULL */
2009-
return0;
2010-
}
2011-
elseif (rtup->isNull)
2012-
return-1;
2013-
elseif (state->sortFnKind==SORTFUNC_LT)
2014-
{
2015-
if (DatumGetBool(FunctionCall2(&state->sortOpFn,
2016-
ltup->val,rtup->val)))
2017-
return-1;/* a < b */
2018-
if (DatumGetBool(FunctionCall2(&state->sortOpFn,
2019-
rtup->val,ltup->val)))
2020-
return1;/* a > b */
2021-
return0;
2022-
}
2023-
else
2024-
{
2025-
/* sort function is CMP or REVCMP */
2026-
int32compare;
2027-
2028-
compare=DatumGetInt32(FunctionCall2(&state->sortOpFn,
2029-
ltup->val,rtup->val));
2030-
if (state->sortFnKind==SORTFUNC_REVCMP)
2031-
compare=-compare;
2032-
returncompare;
2033-
}
1965+
returnApplySortFunction(&state->sortOpFn,state->sortFnKind,
1966+
ltup->val,ltup->isNull,
1967+
rtup->val,rtup->isNull);
20341968
}
20351969

20361970
staticvoid*
@@ -2123,6 +2057,7 @@ SelectSortFunction(Oid sortOperator,
21232057
HeapScanDescscan;
21242058
ScanKeyDataskey[3];
21252059
HeapTupletuple;
2060+
Form_pg_operatoroptup;
21262061
Oidopclass=InvalidOid;
21272062

21282063
/*
@@ -2207,11 +2142,97 @@ SelectSortFunction(Oid sortOperator,
22072142
return;
22082143
}
22092144

2210-
/* Can't find a comparator, so use the operator as-is */
2211-
2212-
*kind=SORTFUNC_LT;
2213-
*sortFunction=get_opcode(sortOperator);
2214-
if (!RegProcedureIsValid(*sortFunction))
2215-
elog(ERROR,"SelectSortFunction: operator %u has no implementation",
2145+
/*
2146+
* Can't find a comparator, so use the operator as-is. Decide whether
2147+
* it is forward or reverse sort by looking at its name (grotty, but
2148+
* this only matters for deciding which end NULLs should get sorted to).
2149+
*/
2150+
tuple=SearchSysCache(OPEROID,
2151+
ObjectIdGetDatum(sortOperator),
2152+
0,0,0);
2153+
if (!HeapTupleIsValid(tuple))
2154+
elog(ERROR,"SelectSortFunction: cache lookup failed for operator %u",
22162155
sortOperator);
2156+
optup= (Form_pg_operator)GETSTRUCT(tuple);
2157+
if (strcmp(NameStr(optup->oprname),">")==0)
2158+
*kind=SORTFUNC_REVLT;
2159+
else
2160+
*kind=SORTFUNC_LT;
2161+
*sortFunction=optup->oprcode;
2162+
ReleaseSysCache(tuple);
2163+
2164+
Assert(RegProcedureIsValid(*sortFunction));
2165+
}
2166+
2167+
/*
2168+
* Apply a sort function (by now converted to fmgr lookup form)
2169+
* and return a 3-way comparison result. This takes care of handling
2170+
* NULLs and sort ordering direction properly.
2171+
*/
2172+
int32
2173+
ApplySortFunction(FmgrInfo*sortFunction,SortFunctionKindkind,
2174+
Datumdatum1,boolisNull1,
2175+
Datumdatum2,boolisNull2)
2176+
{
2177+
switch (kind)
2178+
{
2179+
caseSORTFUNC_LT:
2180+
if (isNull1)
2181+
{
2182+
if (isNull2)
2183+
return0;
2184+
return1;/* NULL sorts after non-NULL */
2185+
}
2186+
if (isNull2)
2187+
return-1;
2188+
if (DatumGetBool(FunctionCall2(sortFunction,datum1,datum2)))
2189+
return-1;/* a < b */
2190+
if (DatumGetBool(FunctionCall2(sortFunction,datum2,datum1)))
2191+
return1;/* a > b */
2192+
return0;
2193+
2194+
caseSORTFUNC_REVLT:
2195+
/* We reverse the ordering of NULLs, but not the operator */
2196+
if (isNull1)
2197+
{
2198+
if (isNull2)
2199+
return0;
2200+
return-1;/* NULL sorts before non-NULL */
2201+
}
2202+
if (isNull2)
2203+
return1;
2204+
if (DatumGetBool(FunctionCall2(sortFunction,datum1,datum2)))
2205+
return-1;/* a < b */
2206+
if (DatumGetBool(FunctionCall2(sortFunction,datum2,datum1)))
2207+
return1;/* a > b */
2208+
return0;
2209+
2210+
caseSORTFUNC_CMP:
2211+
if (isNull1)
2212+
{
2213+
if (isNull2)
2214+
return0;
2215+
return1;/* NULL sorts after non-NULL */
2216+
}
2217+
if (isNull2)
2218+
return-1;
2219+
returnDatumGetInt32(FunctionCall2(sortFunction,
2220+
datum1,datum2));
2221+
2222+
caseSORTFUNC_REVCMP:
2223+
if (isNull1)
2224+
{
2225+
if (isNull2)
2226+
return0;
2227+
return-1;/* NULL sorts before non-NULL */
2228+
}
2229+
if (isNull2)
2230+
return1;
2231+
return-DatumGetInt32(FunctionCall2(sortFunction,
2232+
datum1,datum2));
2233+
2234+
default:
2235+
elog(ERROR,"Invalid SortFunctionKind %d", (int)kind);
2236+
return0;/* can't get here, but keep compiler quiet */
2237+
}
22172238
}

‎src/include/utils/tuplesort.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
1414
* Portions Copyright (c) 1994, Regents of the University of California
1515
*
16-
* $Id: tuplesort.h,v 1.7 2001/05/07 00:43:26 tgl Exp $
16+
* $Id: tuplesort.h,v 1.8 2001/06/02 19:01:52 tgl Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -22,6 +22,7 @@
2222

2323
#include"access/htup.h"
2424
#include"access/itup.h"
25+
#include"fmgr.h"
2526

2627
/* Tuplesortstate is an opaque type whose details are not known outside tuplesort.c. */
2728

@@ -83,6 +84,7 @@ extern void tuplesort_restorepos(Tuplesortstate *state);
8384
typedefenum
8485
{
8586
SORTFUNC_LT,/* raw "<" operator */
87+
SORTFUNC_REVLT,/* raw "<" operator, but reverse NULLs */
8688
SORTFUNC_CMP,/* -1 / 0 / 1 three-way comparator */
8789
SORTFUNC_REVCMP/* 1 / 0 / -1 (reversed) 3-way comparator */
8890
}SortFunctionKind;
@@ -91,4 +93,13 @@ extern void SelectSortFunction(Oid sortOperator,
9193
RegProcedure*sortFunction,
9294
SortFunctionKind*kind);
9395

96+
/*
97+
* Apply a sort function (by now converted to fmgr lookup form)
98+
* and return a 3-way comparison result. This takes care of handling
99+
* NULLs and sort ordering direction properly.
100+
*/
101+
externint32ApplySortFunction(FmgrInfo*sortFunction,SortFunctionKindkind,
102+
Datumdatum1,boolisNull1,
103+
Datumdatum2,boolisNull2);
104+
94105
#endif/* TUPLESORT_H */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp