Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
887afac1
Commit
887afac1
authored
Oct 17, 1999
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove now-dead sort modules.
parent
26c48b5e
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
0 additions
and
1479 deletions
+0
-1479
src/backend/utils/sort/lselect.c
src/backend/utils/sort/lselect.c
+0
-355
src/backend/utils/sort/psort.c
src/backend/utils/sort/psort.c
+0
-1025
src/include/lib/qsort.h
src/include/lib/qsort.h
+0
-22
src/include/utils/lselect.h
src/include/utils/lselect.h
+0
-51
src/include/utils/psort.h
src/include/utils/psort.h
+0
-26
No files found.
src/backend/utils/sort/lselect.c
deleted
100644 → 0
View file @
26c48b5e
/*-------------------------------------------------------------------------
*
* lselect.c
* leftist tree selection algorithm (linked priority queue--Knuth, Vol.3,
* pp.150-52)
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/lselect.c,v 1.19 1999/07/17 20:18:16 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
#include "utils/lselect.h"
/*
* lmerge - merges two leftist trees into one
*
* Note:
* Enforcing the rule that pt->lt_dist >= qt->lt_dist may
* simplifify much of the code. Removing recursion will not
* speed up code significantly.
*/
struct
leftist
*
lmerge
(
struct
leftist
*
pt
,
struct
leftist
*
qt
,
LeftistContext
context
)
{
struct
leftist
*
root
,
*
majorLeftist
,
*
minorLeftist
;
int
dist
;
if
(
tuplecmp
(
pt
->
lt_tuple
,
qt
->
lt_tuple
,
context
))
{
root
=
pt
;
majorLeftist
=
qt
;
}
else
{
root
=
qt
;
majorLeftist
=
pt
;
}
if
(
root
->
lt_left
==
NULL
)
root
->
lt_left
=
majorLeftist
;
else
{
if
((
minorLeftist
=
root
->
lt_right
)
!=
NULL
)
majorLeftist
=
lmerge
(
majorLeftist
,
minorLeftist
,
context
);
if
((
dist
=
root
->
lt_left
->
lt_dist
)
<
majorLeftist
->
lt_dist
)
{
root
->
lt_dist
=
1
+
dist
;
root
->
lt_right
=
root
->
lt_left
;
root
->
lt_left
=
majorLeftist
;
}
else
{
root
->
lt_dist
=
1
+
majorLeftist
->
lt_dist
;
root
->
lt_right
=
majorLeftist
;
}
}
return
root
;
}
static
struct
leftist
*
linsert
(
struct
leftist
*
root
,
struct
leftist
*
new1
,
LeftistContext
context
)
{
struct
leftist
*
left
,
*
right
;
if
(
!
tuplecmp
(
root
->
lt_tuple
,
new1
->
lt_tuple
,
context
))
{
new1
->
lt_left
=
root
;
return
new1
;
}
left
=
root
->
lt_left
;
right
=
root
->
lt_right
;
if
(
right
==
NULL
)
{
if
(
left
==
NULL
)
root
->
lt_left
=
new1
;
else
{
root
->
lt_right
=
new1
;
root
->
lt_dist
=
2
;
}
return
root
;
}
right
=
linsert
(
right
,
new1
,
context
);
if
(
right
->
lt_dist
<
left
->
lt_dist
)
{
root
->
lt_dist
=
1
+
left
->
lt_dist
;
root
->
lt_left
=
right
;
root
->
lt_right
=
left
;
}
else
{
root
->
lt_dist
=
1
+
right
->
lt_dist
;
root
->
lt_right
=
right
;
}
return
root
;
}
/*
* gettuple - returns tuple at top of tree (Tuples)
*
* Returns:
* tuple at top of tree, NULL if failed ALLOC()
* *devnum is set to the devnum of tuple returned
* *treep is set to the new tree
*
* Note:
* *treep must not be NULL
* NULL is currently never returned BUG
*/
HeapTuple
gettuple
(
struct
leftist
**
treep
,
short
*
devnum
,
/* device from which tuple came */
LeftistContext
context
)
{
struct
leftist
*
tp
;
HeapTuple
tup
;
tp
=
*
treep
;
tup
=
tp
->
lt_tuple
;
*
devnum
=
tp
->
lt_devnum
;
if
(
tp
->
lt_dist
==
1
)
/* lt_left == NULL */
*
treep
=
tp
->
lt_left
;
else
*
treep
=
lmerge
(
tp
->
lt_left
,
tp
->
lt_right
,
context
);
pfree
(
tp
);
return
tup
;
}
/*
* puttuple - inserts new tuple into tree
*
* Returns:
* NULL iff failed ALLOC()
*
* Note:
* Currently never returns NULL BUG
*/
void
puttuple
(
struct
leftist
**
treep
,
HeapTuple
newtuple
,
short
devnum
,
LeftistContext
context
)
{
struct
leftist
*
new1
;
struct
leftist
*
tp
;
new1
=
(
struct
leftist
*
)
palloc
((
unsigned
)
sizeof
(
struct
leftist
));
new1
->
lt_dist
=
1
;
new1
->
lt_devnum
=
devnum
;
new1
->
lt_tuple
=
newtuple
;
new1
->
lt_left
=
NULL
;
new1
->
lt_right
=
NULL
;
if
((
tp
=
*
treep
)
==
NULL
)
*
treep
=
new1
;
else
*
treep
=
linsert
(
tp
,
new1
,
context
);
return
;
}
/*
* tuplecmp - Compares two tuples with respect CmpList
*
* Returns:
* 1 if left < right ;0 otherwise
* Assumtions:
*/
int
tuplecmp
(
HeapTuple
ltup
,
HeapTuple
rtup
,
LeftistContext
context
)
{
int
nkey
;
int
result
=
0
;
if
(
ltup
==
(
HeapTuple
)
NULL
)
return
0
;
if
(
rtup
==
(
HeapTuple
)
NULL
)
return
1
;
for
(
nkey
=
0
;
nkey
<
context
->
nKeys
;
nkey
++
)
{
ScanKey
thisKey
=
&
context
->
scanKeys
[
nkey
];
Datum
lattr
,
rattr
;
bool
lisnull
,
risnull
;
lattr
=
heap_getattr
(
ltup
,
thisKey
->
sk_attno
,
context
->
tupDesc
,
&
lisnull
);
rattr
=
heap_getattr
(
rtup
,
thisKey
->
sk_attno
,
context
->
tupDesc
,
&
risnull
);
if
(
lisnull
)
{
if
(
risnull
)
continue
;
/* treat two nulls as equal */
return
0
;
/* else, a null sorts after all else */
}
if
(
risnull
)
return
1
;
if
(
thisKey
->
sk_flags
&
SK_COMMUTE
)
{
if
(
!
(
result
=
(
long
)
(
*
fmgr_faddr
(
&
thisKey
->
sk_func
))
(
rattr
,
lattr
)))
result
=
-
(
long
)
(
*
fmgr_faddr
(
&
thisKey
->
sk_func
))
(
lattr
,
rattr
);
}
else
{
if
(
!
(
result
=
(
long
)
(
*
fmgr_faddr
(
&
thisKey
->
sk_func
))
(
lattr
,
rattr
)))
result
=
-
(
long
)
(
*
fmgr_faddr
(
&
thisKey
->
sk_func
))
(
rattr
,
lattr
);
}
if
(
result
)
break
;
}
return
result
==
1
;
}
#ifdef EBUG
void
checktree
(
struct
leftist
*
tree
,
LeftistContext
context
)
{
int
lnodes
;
int
rnodes
;
if
(
tree
==
NULL
)
{
puts
(
"Null tree."
);
return
;
}
lnodes
=
checktreer
(
tree
->
lt_left
,
1
,
context
);
rnodes
=
checktreer
(
tree
->
lt_right
,
1
,
context
);
if
(
lnodes
<
0
)
{
lnodes
=
-
lnodes
;
puts
(
"0:
\t
Bad left side."
);
}
if
(
rnodes
<
0
)
{
rnodes
=
-
rnodes
;
puts
(
"0:
\t
Bad right side."
);
}
if
(
lnodes
==
0
)
{
if
(
rnodes
!=
0
)
puts
(
"0:
\t
Left and right reversed."
);
if
(
tree
->
lt_dist
!=
1
)
puts
(
"0:
\t
Distance incorrect."
);
}
else
if
(
rnodes
==
0
)
{
if
(
tree
->
lt_dist
!=
1
)
puts
(
"0:
\t
Distance incorrect."
);
}
else
if
(
tree
->
lt_left
->
lt_dist
<
tree
->
lt_right
->
lt_dist
)
{
puts
(
"0:
\t
Left and right reversed."
);
if
(
tree
->
lt_dist
!=
1
+
tree
->
lt_left
->
lt_dist
)
puts
(
"0:
\t
Distance incorrect."
);
}
else
if
(
tree
->
lt_dist
!=
1
+
tree
->
lt_right
->
lt_dist
)
puts
(
"0:
\t
Distance incorrect."
);
if
(
lnodes
>
0
)
if
(
tuplecmp
(
tree
->
lt_left
->
lt_tuple
,
tree
->
lt_tuple
,
context
))
printf
(
"%d:
\t
Left child < parent.
\n
"
);
if
(
rnodes
>
0
)
if
(
tuplecmp
(
tree
->
lt_right
->
lt_tuple
,
tree
->
lt_tuple
,
context
))
printf
(
"%d:
\t
Right child < parent.
\n
"
);
printf
(
"Tree has %d nodes
\n
"
,
1
+
lnodes
+
rnodes
);
}
int
checktreer
(
struct
leftist
*
tree
,
int
level
,
LeftistContext
context
)
{
int
lnodes
,
rnodes
;
int
error
=
0
;
if
(
tree
==
NULL
)
return
0
;
lnodes
=
checktreer
(
tree
->
lt_left
,
level
+
1
,
context
);
rnodes
=
checktreer
(
tree
->
lt_right
,
level
+
1
,
context
);
if
(
lnodes
<
0
)
{
error
=
1
;
lnodes
=
-
lnodes
;
printf
(
"%d:
\t
Bad left side.
\n
"
,
level
);
}
if
(
rnodes
<
0
)
{
error
=
1
;
rnodes
=
-
rnodes
;
printf
(
"%d:
\t
Bad right side.
\n
"
,
level
);
}
if
(
lnodes
==
0
)
{
if
(
rnodes
!=
0
)
{
error
=
1
;
printf
(
"%d:
\t
Left and right reversed.
\n
"
,
level
);
}
if
(
tree
->
lt_dist
!=
1
)
{
error
=
1
;
printf
(
"%d:
\t
Distance incorrect.
\n
"
,
level
);
}
}
else
if
(
rnodes
==
0
)
{
if
(
tree
->
lt_dist
!=
1
)
{
error
=
1
;
printf
(
"%d:
\t
Distance incorrect.
\n
"
,
level
);
}
}
else
if
(
tree
->
lt_left
->
lt_dist
<
tree
->
lt_right
->
lt_dist
)
{
error
=
1
;
printf
(
"%d:
\t
Left and right reversed.
\n
"
,
level
);
if
(
tree
->
lt_dist
!=
1
+
tree
->
lt_left
->
lt_dist
)
printf
(
"%d:
\t
Distance incorrect.
\n
"
,
level
);
}
else
if
(
tree
->
lt_dist
!=
1
+
tree
->
lt_right
->
lt_dist
)
{
error
=
1
;
printf
(
"%d:
\t
Distance incorrect.
\n
"
,
level
);
}
if
(
lnodes
>
0
)
if
(
tuplecmp
(
tree
->
lt_left
->
lt_tuple
,
tree
->
lt_tuple
,
context
))
{
error
=
1
;
printf
(
"%d:
\t
Left child < parent.
\n
"
);
}
if
(
rnodes
>
0
)
if
(
tuplecmp
(
tree
->
lt_right
->
lt_tuple
,
tree
->
lt_tuple
,
context
))
{
error
=
1
;
printf
(
"%d:
\t
Right child < parent.
\n
"
);
}
if
(
error
)
return
-
1
+
-
lnodes
+
-
rnodes
;
return
1
+
lnodes
+
rnodes
;
}
#endif
src/backend/utils/sort/psort.c
deleted
100644 → 0
View file @
26c48b5e
/*-------------------------------------------------------------------------
*
* psort.c
* Polyphase merge sort.
*
* See Knuth, volume 3, for more than you want to know about this algorithm.
*
* NOTES
*
* This needs to be generalized to handle index tuples as well as heap tuples,
* so that the near-duplicate code in nbtsort.c can be eliminated. Also,
* I think it's got memory leak problems.
*
* Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/psort.c,v 1.58 1999/10/16 19:49:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include <math.h>
#include "postgres.h"
#include "access/heapam.h"
#include "access/relscan.h"
#include "executor/execdebug.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "utils/logtape.h"
#include "utils/lselect.h"
#include "utils/psort.h"
#define MAXTAPES 7
/* See Knuth Fig. 70, p273 */
struct
tape
{
int
tp_dummy
;
/* (D) */
int
tp_fib
;
/* (A) */
int
tp_tapenum
;
/* (TAPE) */
struct
tape
*
tp_prev
;
};
/*
* Private state of a Psort operation. The "psortstate" field in a Sort node
* points to one of these. This replaces a lot of global variables that used
* to be here...
*/
typedef
struct
Psortstate
{
LeftistContextData
treeContext
;
int
TapeRange
;
/* number of tapes less 1 (T) */
int
Level
;
/* Knuth's l */
int
TotalDummy
;
/* sum of tp_dummy across all tapes */
struct
tape
Tape
[
MAXTAPES
];
LogicalTapeSet
*
tapeset
;
/* logtape.c object for tapes in a temp file */
int
BytesRead
;
/* I/O statistics (useless) */
int
BytesWritten
;
int
tupcount
;
struct
leftist
*
Tuples
;
/* current tuple tree */
int
psort_grab_tape
;
/* tape number of finished output data */
long
psort_current
;
/* array index (only used if not tape) */
/* psort_saved(_offset) holds marked position for mark and restore */
long
psort_saved
;
/* could be tape block#, or array index */
int
psort_saved_offset
;
/* lower bits of psort_saved, if tape */
bool
using_tape_files
;
bool
all_fetched
;
/* this is for cursors */
HeapTuple
*
memtuples
;
}
Psortstate
;
/*
* PS - Macro to access and cast psortstate from a Sort node
*/
#define PS(N) ((Psortstate *)(N)->psortstate)
static
bool
createfirstrun
(
Sort
*
node
);
static
bool
createrun
(
Sort
*
node
,
int
desttapenum
);
static
void
dumptuples
(
Sort
*
node
,
int
desttapenum
);
static
void
initialrun
(
Sort
*
node
);
static
void
inittapes
(
Sort
*
node
);
static
void
merge
(
Sort
*
node
,
struct
tape
*
dest
);
static
int
mergeruns
(
Sort
*
node
);
static
int
_psort_cmp
(
HeapTuple
*
ltup
,
HeapTuple
*
rtup
);
/* these are used by _psort_cmp, and are set just before calling qsort() */
static
TupleDesc
PsortTupDesc
;
static
ScanKey
PsortKeys
;
static
int
PsortNkeys
;
/*
* tlenzero is used to write a zero to delimit runs, tlendummy is used
* to read in length words that we don't care about.
*
* both vars must have the same size as HeapTuple->t_len
*/
static
unsigned
int
tlenzero
=
0
;
static
unsigned
int
tlendummy
;
/*
* psort_begin
*
* polyphase merge sort entry point. Sorts the subplan
* into memory or a temporary file. After
* this is called, calling the interface function
* psort_grabtuple iteratively will get you the sorted
* tuples. psort_end releases storage when done.
*
* Allocates and initializes sort node's psort state.
*/
bool
psort_begin
(
Sort
*
node
,
int
nkeys
,
ScanKey
key
)
{
AssertArg
(
nkeys
>=
1
);
AssertArg
(
key
[
0
].
sk_attno
!=
0
);
AssertArg
(
key
[
0
].
sk_procedure
!=
0
);
node
->
psortstate
=
(
void
*
)
palloc
(
sizeof
(
struct
Psortstate
));
PS
(
node
)
->
treeContext
.
tupDesc
=
ExecGetTupType
(
outerPlan
((
Plan
*
)
node
));
PS
(
node
)
->
treeContext
.
nKeys
=
nkeys
;
PS
(
node
)
->
treeContext
.
scanKeys
=
key
;
PS
(
node
)
->
treeContext
.
sortMem
=
SortMem
*
1024
;
PS
(
node
)
->
tapeset
=
NULL
;
PS
(
node
)
->
BytesRead
=
0
;
PS
(
node
)
->
BytesWritten
=
0
;
PS
(
node
)
->
tupcount
=
0
;
PS
(
node
)
->
Tuples
=
NULL
;
PS
(
node
)
->
using_tape_files
=
false
;
PS
(
node
)
->
all_fetched
=
false
;
PS
(
node
)
->
psort_grab_tape
=
-
1
;
PS
(
node
)
->
memtuples
=
NULL
;
initialrun
(
node
);
if
(
PS
(
node
)
->
tupcount
==
0
)
return
false
;
if
(
PS
(
node
)
->
using_tape_files
&&
PS
(
node
)
->
psort_grab_tape
==
-
1
)
PS
(
node
)
->
psort_grab_tape
=
mergeruns
(
node
);
PS
(
node
)
->
psort_current
=
0L
;
PS
(
node
)
->
psort_saved
=
0L
;
PS
(
node
)
->
psort_saved_offset
=
0
;
return
true
;
}
/*
* inittapes - initializes the tapes
* - (polyphase merge Alg.D(D1)--Knuth, Vol.3, p.270)
*
* This is called only if we have found we don't have room to sort in memory.
*/
static
void
inittapes
(
Sort
*
node
)
{
int
i
;
struct
tape
*
tp
;
Assert
(
node
!=
(
Sort
*
)
NULL
);
Assert
(
PS
(
node
)
!=
(
Psortstate
*
)
NULL
);
PS
(
node
)
->
tapeset
=
LogicalTapeSetCreate
(
MAXTAPES
);
tp
=
PS
(
node
)
->
Tape
;
for
(
i
=
0
;
i
<
MAXTAPES
;
i
++
)
{
tp
->
tp_dummy
=
1
;
tp
->
tp_fib
=
1
;
tp
->
tp_tapenum
=
i
;
tp
->
tp_prev
=
tp
-
1
;
tp
++
;
}
PS
(
node
)
->
TapeRange
=
--
tp
-
PS
(
node
)
->
Tape
;
tp
->
tp_dummy
=
0
;
tp
->
tp_fib
=
0
;
PS
(
node
)
->
Tape
[
0
].
tp_prev
=
tp
;
PS
(
node
)
->
Level
=
1
;
PS
(
node
)
->
TotalDummy
=
PS
(
node
)
->
TapeRange
;
PS
(
node
)
->
using_tape_files
=
true
;
}
/*
* PUTTUP - writes the next tuple
* ENDRUN - mark end of run
* TRYGETLEN - reads the length of the next tuple, if any
* GETLEN - reads the length of the next tuple, must be one
* ALLOCTUP - returns space for the new tuple
* GETTUP - reads the tuple
*
* Note:
* LEN field must be as HeapTuple->t_len; FP is a stream
*/
#define PUTTUP(NODE, TUP, TAPE) \
( \
(TUP)->t_len += HEAPTUPLESIZE, \
PS(NODE)->BytesWritten += (TUP)->t_len, \
LogicalTapeWrite(PS(NODE)->tapeset, (TAPE), (void*)(TUP), (TUP)->t_len), \
LogicalTapeWrite(PS(NODE)->tapeset, (TAPE), (void*)&((TUP)->t_len), sizeof(tlendummy)), \
(TUP)->t_len -= HEAPTUPLESIZE \
)
#define ENDRUN(NODE, TAPE) \
LogicalTapeWrite(PS(NODE)->tapeset, (TAPE), (void *)&tlenzero, sizeof(tlenzero))
#define TRYGETLEN(NODE, LEN, TAPE) \
(LogicalTapeRead(PS(NODE)->tapeset, (TAPE), \
(void *) &(LEN), sizeof(tlenzero)) == sizeof(tlenzero) \
&& (LEN) != 0)
#define GETLEN(NODE, LEN, TAPE) \
do { \
if (! TRYGETLEN(NODE, LEN, TAPE)) \
elog(ERROR, "psort: unexpected end of data"); \
} while(0)
static
void
GETTUP
(
Sort
*
node
,
HeapTuple
tup
,
unsigned
int
len
,
int
tape
)
{
IncrProcessed
();
PS
(
node
)
->
BytesRead
+=
len
;
if
(
LogicalTapeRead
(
PS
(
node
)
->
tapeset
,
tape
,
((
char
*
)
tup
)
+
sizeof
(
tlenzero
),
len
-
sizeof
(
tlenzero
))
!=
len
-
sizeof
(
tlenzero
))
elog
(
ERROR
,
"psort: unexpected end of data"
);
tup
->
t_len
=
len
-
HEAPTUPLESIZE
;
tup
->
t_data
=
(
HeapTupleHeader
)
((
char
*
)
tup
+
HEAPTUPLESIZE
);
if
(
LogicalTapeRead
(
PS
(
node
)
->
tapeset
,
tape
,
(
void
*
)
&
tlendummy
,
sizeof
(
tlendummy
))
!=
sizeof
(
tlendummy
))
elog
(
ERROR
,
"psort: unexpected end of data"
);
}
#define ALLOCTUP(LEN) ((HeapTuple) palloc(LEN))
#define FREE(x) pfree((char *) (x))
/*
* USEMEM - record use of memory FREEMEM - record
* freeing of memory FULLMEM - 1 iff a tuple will fit
*/
#define USEMEM(NODE,AMT) PS(node)->treeContext.sortMem -= (AMT)
#define FREEMEM(NODE,AMT) PS(node)->treeContext.sortMem += (AMT)
#define LACKMEM(NODE) (PS(node)->treeContext.sortMem <= BLCKSZ)
/* not accurate */
#define TRACEMEM(FUNC)
#define TRACEOUT(FUNC, TUP)
/*
* initialrun - distributes tuples from the relation
* - (replacement selection(R2-R3)--Knuth, Vol.3, p.257)
* - (polyphase merge Alg.D(D2-D4)--Knuth, Vol.3, p.271)
*
* Explanation:
* Tuples are distributed to the tapes as in Algorithm D.
* A "tuple" with t_size == 0 is used to mark the end of a run.
*
* Note:
* The replacement selection algorithm has been modified
* to go from R1 directly to R3 skipping R2 the first time.
*
* Maybe should use closer(rdesc) before return
* Perhaps should adjust the number of tapes if less than n.
* used--v. likely to have problems in mergeruns().
* Must know if should open/close files before each
* call to psort()? If should--messy??
*
* Possible optimization:
* put the first xxx runs in quickly--problem here since
* I (perhaps prematurely) combined the 2 algorithms.
* Also, perhaps allocate tapes when needed. Split into 2 funcs.
*/
static
void
initialrun
(
Sort
*
node
)
{
struct
tape
*
tp
;
int
baseruns
;
/* D:(a) */
int
extrapasses
;
/* EOF */
int
tapenum
;
Assert
(
node
!=
(
Sort
*
)
NULL
);
Assert
(
PS
(
node
)
!=
(
Psortstate
*
)
NULL
);
tp
=
PS
(
node
)
->
Tape
;
if
(
createfirstrun
(
node
))
{
Assert
(
PS
(
node
)
->
using_tape_files
);
extrapasses
=
0
;
}
else
{
/* all tuples fetched */
if
(
!
PS
(
node
)
->
using_tape_files
)
/* empty or sorted in
* memory */
return
;
/*
* if PS(node)->Tuples == NULL then we have single (sorted) run
* which can be used as result grab file! So, we may avoid
* mergeruns - it will just copy this run to new file.
*/
if
(
PS
(
node
)
->
Tuples
==
NULL
)
{
PS
(
node
)
->
psort_grab_tape
=
PS
(
node
)
->
Tape
[
0
].
tp_tapenum
;
/* freeze and rewind the finished output tape */
LogicalTapeFreeze
(
PS
(
node
)
->
tapeset
,
PS
(
node
)
->
psort_grab_tape
);
return
;
}
extrapasses
=
2
;
}
for
(;;)
{
tp
->
tp_dummy
--
;
PS
(
node
)
->
TotalDummy
--
;
if
(
tp
->
tp_dummy
<
(
tp
+
1
)
->
tp_dummy
)
tp
++
;
else
{
if
(
tp
->
tp_dummy
!=
0
)
tp
=
PS
(
node
)
->
Tape
;
else
{
PS
(
node
)
->
Level
++
;
baseruns
=
PS
(
node
)
->
Tape
[
0
].
tp_fib
;
for
(
tp
=
PS
(
node
)
->
Tape
;
tp
-
PS
(
node
)
->
Tape
<
PS
(
node
)
->
TapeRange
;
tp
++
)
{
PS
(
node
)
->
TotalDummy
+=
(
tp
->
tp_dummy
=
baseruns
+
(
tp
+
1
)
->
tp_fib
-
tp
->
tp_fib
);
tp
->
tp_fib
=
baseruns
+
(
tp
+
1
)
->
tp_fib
;
}
tp
=
PS
(
node
)
->
Tape
;
/* D4 */
}
/* D3 */
}
if
(
extrapasses
)
{
if
(
--
extrapasses
)
{
dumptuples
(
node
,
tp
->
tp_tapenum
);
ENDRUN
(
node
,
tp
->
tp_tapenum
);
continue
;
}
else
break
;
}
if
(
createrun
(
node
,
tp
->
tp_tapenum
)
==
false
)
extrapasses
=
1
+
(
PS
(
node
)
->
Tuples
!=
NULL
);
/* D2 */
}
/* End of step D2: rewind all output tapes to prepare for merging */
for
(
tapenum
=
0
;
tapenum
<
PS
(
node
)
->
TapeRange
;
tapenum
++
)
LogicalTapeRewind
(
PS
(
node
)
->
tapeset
,
tapenum
,
false
);
}
/*
* createfirstrun - tries to sort tuples in memory using qsort
* until LACKMEM; if not enough memory then switches
* to tape method
*
* Returns:
* FALSE iff process through end of relation
* Tuples contains the tuples for the following run upon exit
*/
static
bool
createfirstrun
(
Sort
*
node
)
{
HeapTuple
tup
;
bool
foundeor
=
false
;
HeapTuple
*
memtuples
;
int
t_last
=
-
1
;
int
t_free
=
1000
;
TupleTableSlot
*
cr_slot
;
Assert
(
node
!=
(
Sort
*
)
NULL
);
Assert
(
PS
(
node
)
!=
(
Psortstate
*
)
NULL
);
Assert
(
!
PS
(
node
)
->
using_tape_files
);
Assert
(
PS
(
node
)
->
memtuples
==
NULL
);
Assert
(
PS
(
node
)
->
tupcount
==
0
);
if
(
LACKMEM
(
node
))
elog
(
ERROR
,
"psort: LACKMEM before createfirstrun"
);
memtuples
=
palloc
(
t_free
*
sizeof
(
HeapTuple
));
for
(;;)
{
if
(
LACKMEM
(
node
))
break
;
/*
* About to call ExecProcNode, it can mess up the state if it
* eventually calls another Sort node. So must stow it away here
* for the meantime. -Rex
* 2.2.1995
*/
cr_slot
=
ExecProcNode
(
outerPlan
((
Plan
*
)
node
),
(
Plan
*
)
node
);
if
(
TupIsNull
(
cr_slot
))
{
foundeor
=
true
;
break
;
}
tup
=
heap_copytuple
(
cr_slot
->
val
);
ExecClearTuple
(
cr_slot
);
IncrProcessed
();
USEMEM
(
node
,
tup
->
t_len
);
TRACEMEM
(
createfirstrun
);
if
(
t_free
<=
0
)
{
t_free
=
1000
;
memtuples
=
repalloc
(
memtuples
,
(
t_last
+
t_free
+
1
)
*
sizeof
(
HeapTuple
));
}
t_last
++
;
t_free
--
;
memtuples
[
t_last
]
=
tup
;
}
if
(
t_last
<
0
)
/* empty */
{
Assert
(
foundeor
);
pfree
(
memtuples
);
return
false
;
}
t_last
++
;
PS
(
node
)
->
tupcount
=
t_last
;
PsortTupDesc
=
PS
(
node
)
->
treeContext
.
tupDesc
;
PsortKeys
=
PS
(
node
)
->
treeContext
.
scanKeys
;
PsortNkeys
=
PS
(
node
)
->
treeContext
.
nKeys
;
qsort
(
memtuples
,
t_last
,
sizeof
(
HeapTuple
),
(
int
(
*
)
(
const
void
*
,
const
void
*
))
_psort_cmp
);
if
(
LACKMEM
(
node
))
/* in-memory sort is impossible */
{
int
t
;
Assert
(
!
foundeor
);
inittapes
(
node
);
/* put tuples into leftist tree for createrun */
for
(
t
=
t_last
-
1
;
t
>=
0
;
t
--
)
puttuple
(
&
PS
(
node
)
->
Tuples
,
memtuples
[
t
],
0
,
&
PS
(
node
)
->
treeContext
);
pfree
(
memtuples
);
foundeor
=
!
createrun
(
node
,
PS
(
node
)
->
Tape
->
tp_tapenum
);
}
else
{
Assert
(
foundeor
);
PS
(
node
)
->
memtuples
=
memtuples
;
}
return
!
foundeor
;
}
/*
* createrun
*
* Create the next run and write it to desttapenum, grabbing the tuples by
* executing the subplan passed in
*
* Uses:
* Tuples, which should contain any tuples for this run
*
* Returns:
* FALSE iff process through end of relation
* Tuples contains the tuples for the following run upon exit
*/
static
bool
createrun
(
Sort
*
node
,
int
desttapenum
)
{
HeapTuple
lasttuple
;
HeapTuple
tup
;
TupleTableSlot
*
cr_slot
;
HeapTuple
*
memtuples
;
int
t_last
=
-
1
;
int
t_free
=
1000
;
bool
foundeor
=
false
;
short
junk
;
Assert
(
node
!=
(
Sort
*
)
NULL
);
Assert
(
PS
(
node
)
!=
(
Psortstate
*
)
NULL
);
Assert
(
PS
(
node
)
->
using_tape_files
);
lasttuple
=
NULL
;
memtuples
=
palloc
(
t_free
*
sizeof
(
HeapTuple
));
for
(;;)
{
while
(
LACKMEM
(
node
)
&&
PS
(
node
)
->
Tuples
!=
NULL
)
{
if
(
lasttuple
!=
NULL
)
{
FREEMEM
(
node
,
lasttuple
->
t_len
);
FREE
(
lasttuple
);
TRACEMEM
(
createrun
);
}
lasttuple
=
gettuple
(
&
PS
(
node
)
->
Tuples
,
&
junk
,
&
PS
(
node
)
->
treeContext
);
PUTTUP
(
node
,
lasttuple
,
desttapenum
);
TRACEOUT
(
createrun
,
lasttuple
);
}
if
(
LACKMEM
(
node
))
break
;
/*
* About to call ExecProcNode, it can mess up the state if it
* eventually calls another Sort node. So must stow it away here
* for the meantime. -Rex
* 2.2.1995
*/
cr_slot
=
ExecProcNode
(
outerPlan
((
Plan
*
)
node
),
(
Plan
*
)
node
);
if
(
TupIsNull
(
cr_slot
))
{
foundeor
=
true
;
break
;
}
else
{
tup
=
heap_copytuple
(
cr_slot
->
val
);
ExecClearTuple
(
cr_slot
);
PS
(
node
)
->
tupcount
++
;
}
IncrProcessed
();
USEMEM
(
node
,
tup
->
t_len
);
TRACEMEM
(
createrun
);
if
(
lasttuple
!=
NULL
&&
tuplecmp
(
tup
,
lasttuple
,
&
PS
(
node
)
->
treeContext
))
{
if
(
t_free
<=
0
)
{
t_free
=
1000
;
memtuples
=
repalloc
(
memtuples
,
(
t_last
+
t_free
+
1
)
*
sizeof
(
HeapTuple
));
}
t_last
++
;
t_free
--
;
memtuples
[
t_last
]
=
tup
;
}
else
puttuple
(
&
PS
(
node
)
->
Tuples
,
tup
,
0
,
&
PS
(
node
)
->
treeContext
);
}
if
(
lasttuple
!=
NULL
)
{
FREEMEM
(
node
,
lasttuple
->
t_len
);
FREE
(
lasttuple
);
TRACEMEM
(
createrun
);
}
dumptuples
(
node
,
desttapenum
);
ENDRUN
(
node
,
desttapenum
);
/* delimit the end of the run */
t_last
++
;
/* put tuples for the next run into leftist tree */
if
(
t_last
>=
1
)
{
int
t
;
PsortTupDesc
=
PS
(
node
)
->
treeContext
.
tupDesc
;
PsortKeys
=
PS
(
node
)
->
treeContext
.
scanKeys
;
PsortNkeys
=
PS
(
node
)
->
treeContext
.
nKeys
;
qsort
(
memtuples
,
t_last
,
sizeof
(
HeapTuple
),
(
int
(
*
)
(
const
void
*
,
const
void
*
))
_psort_cmp
);
for
(
t
=
t_last
-
1
;
t
>=
0
;
t
--
)
puttuple
(
&
PS
(
node
)
->
Tuples
,
memtuples
[
t
],
0
,
&
PS
(
node
)
->
treeContext
);
}
pfree
(
memtuples
);
return
!
foundeor
;
}
/*
* mergeruns - merges all runs from input tapes
* (polyphase merge Alg.D(D6)--Knuth, Vol.3, p271)
*
* Returns:
* tape number of finished tape containing all tuples in order
*/
static
int
mergeruns
(
Sort
*
node
)
{
struct
tape
*
tp
;
Assert
(
node
!=
(
Sort
*
)
NULL
);
Assert
(
PS
(
node
)
!=
(
Psortstate
*
)
NULL
);
Assert
(
PS
(
node
)
->
using_tape_files
);
tp
=
PS
(
node
)
->
Tape
+
PS
(
node
)
->
TapeRange
;
merge
(
node
,
tp
);
while
(
--
PS
(
node
)
->
Level
!=
0
)
{
/* rewind output tape to use as new input */
LogicalTapeRewind
(
PS
(
node
)
->
tapeset
,
tp
->
tp_tapenum
,
false
);
tp
=
tp
->
tp_prev
;
/* rewind new output tape and prepare it for write pass */
LogicalTapeRewind
(
PS
(
node
)
->
tapeset
,
tp
->
tp_tapenum
,
true
);
merge
(
node
,
tp
);
}
/* freeze and rewind the final output tape */
LogicalTapeFreeze
(
PS
(
node
)
->
tapeset
,
tp
->
tp_tapenum
);
return
tp
->
tp_tapenum
;
}
/*
* merge - handles a single merge of the tape
* (polyphase merge Alg.D(D5)--Knuth, Vol.3, p271)
*/
static
void
merge
(
Sort
*
node
,
struct
tape
*
dest
)
{
HeapTuple
tup
;
struct
tape
*
lasttp
;
/* (TAPE[P]) */
struct
tape
*
tp
;
struct
leftist
*
tuples
;
int
desttapenum
;
int
times
;
/* runs left to merge */
int
outdummy
;
/* complete dummy runs */
short
fromtape
;
unsigned
int
tuplen
;
Assert
(
node
!=
(
Sort
*
)
NULL
);
Assert
(
PS
(
node
)
!=
(
Psortstate
*
)
NULL
);
Assert
(
PS
(
node
)
->
using_tape_files
);
lasttp
=
dest
->
tp_prev
;
times
=
lasttp
->
tp_fib
;
for
(
tp
=
lasttp
;
tp
!=
dest
;
tp
=
tp
->
tp_prev
)
tp
->
tp_fib
-=
times
;
tp
->
tp_fib
+=
times
;
/* Tape[].tp_fib (A[]) is set to proper exit values */
if
(
PS
(
node
)
->
TotalDummy
<
PS
(
node
)
->
TapeRange
)
/* no complete dummy
* runs */
outdummy
=
0
;
else
{
outdummy
=
PS
(
node
)
->
TotalDummy
;
/* a large positive number */
for
(
tp
=
lasttp
;
tp
!=
dest
;
tp
=
tp
->
tp_prev
)
if
(
outdummy
>
tp
->
tp_dummy
)
outdummy
=
tp
->
tp_dummy
;
for
(
tp
=
lasttp
;
tp
!=
dest
;
tp
=
tp
->
tp_prev
)
tp
->
tp_dummy
-=
outdummy
;
tp
->
tp_dummy
+=
outdummy
;
PS
(
node
)
->
TotalDummy
-=
outdummy
*
PS
(
node
)
->
TapeRange
;
/* do not add the outdummy runs yet */
times
-=
outdummy
;
}
desttapenum
=
dest
->
tp_tapenum
;
while
(
times
--
!=
0
)
{
/* merge one run */
tuples
=
NULL
;
if
(
PS
(
node
)
->
TotalDummy
==
0
)
for
(
tp
=
dest
->
tp_prev
;
tp
!=
dest
;
tp
=
tp
->
tp_prev
)
{
GETLEN
(
node
,
tuplen
,
tp
->
tp_tapenum
);
tup
=
ALLOCTUP
(
tuplen
);
USEMEM
(
node
,
tuplen
);
TRACEMEM
(
merge
);
GETTUP
(
node
,
tup
,
tuplen
,
tp
->
tp_tapenum
);
puttuple
(
&
tuples
,
tup
,
tp
-
PS
(
node
)
->
Tape
,
&
PS
(
node
)
->
treeContext
);
}
else
{
for
(
tp
=
dest
->
tp_prev
;
tp
!=
dest
;
tp
=
tp
->
tp_prev
)
{
if
(
tp
->
tp_dummy
!=
0
)
{
tp
->
tp_dummy
--
;
PS
(
node
)
->
TotalDummy
--
;
}
else
{
GETLEN
(
node
,
tuplen
,
tp
->
tp_tapenum
);
tup
=
ALLOCTUP
(
tuplen
);
USEMEM
(
node
,
tuplen
);
TRACEMEM
(
merge
);
GETTUP
(
node
,
tup
,
tuplen
,
tp
->
tp_tapenum
);
puttuple
(
&
tuples
,
tup
,
tp
-
PS
(
node
)
->
Tape
,
&
PS
(
node
)
->
treeContext
);
}
}
}
while
(
tuples
!=
NULL
)
{
/* possible optimization by using count in tuples */
tup
=
gettuple
(
&
tuples
,
&
fromtape
,
&
PS
(
node
)
->
treeContext
);
PUTTUP
(
node
,
tup
,
desttapenum
);
FREEMEM
(
node
,
tup
->
t_len
);
FREE
(
tup
);
TRACEMEM
(
merge
);
if
(
TRYGETLEN
(
node
,
tuplen
,
PS
(
node
)
->
Tape
[
fromtape
].
tp_tapenum
))
{
tup
=
ALLOCTUP
(
tuplen
);
USEMEM
(
node
,
tuplen
);
TRACEMEM
(
merge
);
GETTUP
(
node
,
tup
,
tuplen
,
PS
(
node
)
->
Tape
[
fromtape
].
tp_tapenum
);
puttuple
(
&
tuples
,
tup
,
fromtape
,
&
PS
(
node
)
->
treeContext
);
}
}
ENDRUN
(
node
,
desttapenum
);
}
PS
(
node
)
->
TotalDummy
+=
outdummy
;
}
/*
* dumptuples - stores all the tuples remaining in tree to dest tape
*/
static
void
dumptuples
(
Sort
*
node
,
int
desttapenum
)
{
LeftistContext
context
=
&
PS
(
node
)
->
treeContext
;
struct
leftist
**
treep
=
&
PS
(
node
)
->
Tuples
;
struct
leftist
*
tp
;
struct
leftist
*
newp
;
HeapTuple
tup
;
Assert
(
PS
(
node
)
->
using_tape_files
);
tp
=
*
treep
;
while
(
tp
!=
NULL
)
{
tup
=
tp
->
lt_tuple
;
if
(
tp
->
lt_dist
==
1
)
/* lt_right == NULL */
newp
=
tp
->
lt_left
;
else
newp
=
lmerge
(
tp
->
lt_left
,
tp
->
lt_right
,
context
);
pfree
(
tp
);
PUTTUP
(
node
,
tup
,
desttapenum
);
FREEMEM
(
node
,
tup
->
t_len
);
FREE
(
tup
);
tp
=
newp
;
}
*
treep
=
NULL
;
}
/*
* psort_grabtuple - gets a tuple from the sorted file and returns it.
* If there are no tuples left, returns NULL.
* Should not call psort_end unless this has returned
* a NULL indicating the last tuple has been processed.
*/
HeapTuple
psort_grabtuple
(
Sort
*
node
,
bool
*
should_free
)
{
HeapTuple
tup
;
Assert
(
node
!=
(
Sort
*
)
NULL
);
Assert
(
PS
(
node
)
!=
(
Psortstate
*
)
NULL
);
if
(
PS
(
node
)
->
using_tape_files
==
true
)
{
unsigned
int
tuplen
;
*
should_free
=
true
;
if
(
ScanDirectionIsForward
(
node
->
plan
.
state
->
es_direction
))
{
if
(
PS
(
node
)
->
all_fetched
)
return
NULL
;
if
(
TRYGETLEN
(
node
,
tuplen
,
PS
(
node
)
->
psort_grab_tape
))
{
tup
=
ALLOCTUP
(
tuplen
);
GETTUP
(
node
,
tup
,
tuplen
,
PS
(
node
)
->
psort_grab_tape
);
return
tup
;
}
else
{
PS
(
node
)
->
all_fetched
=
true
;
return
NULL
;
}
}
/* Backward.
*
* if all tuples are fetched already then we return last tuple,
* else - tuple before last returned.
*/
if
(
PS
(
node
)
->
all_fetched
)
{
/*
* Assume seek position is pointing just past the zero tuplen
* at the end of file; back up and fetch last tuple's ending
* length word. If seek fails we must have a completely empty
* file.
*/
if
(
!
LogicalTapeBackspace
(
PS
(
node
)
->
tapeset
,
PS
(
node
)
->
psort_grab_tape
,
2
*
sizeof
(
tlendummy
)))
return
NULL
;
GETLEN
(
node
,
tuplen
,
PS
(
node
)
->
psort_grab_tape
);
PS
(
node
)
->
all_fetched
=
false
;
}
else
{
/*
* Back up and fetch prev tuple's ending length word.
* If seek fails, assume we are at start of file.
*/
if
(
!
LogicalTapeBackspace
(
PS
(
node
)
->
tapeset
,
PS
(
node
)
->
psort_grab_tape
,
sizeof
(
tlendummy
)))
return
NULL
;
GETLEN
(
node
,
tuplen
,
PS
(
node
)
->
psort_grab_tape
);
/*
* Back up to get ending length word of tuple before it.
*/
if
(
!
LogicalTapeBackspace
(
PS
(
node
)
->
tapeset
,
PS
(
node
)
->
psort_grab_tape
,
tuplen
+
2
*
sizeof
(
tlendummy
)))
{
/* If fail, presumably the prev tuple is the first in the file.
* Back up so that it becomes next to read in forward direction
* (not obviously right, but that is what in-memory case does)
*/
if
(
!
LogicalTapeBackspace
(
PS
(
node
)
->
tapeset
,
PS
(
node
)
->
psort_grab_tape
,
tuplen
+
sizeof
(
tlendummy
)))
elog
(
ERROR
,
"psort_grabtuple: too big last tuple len in backward scan"
);
return
NULL
;
}
GETLEN
(
node
,
tuplen
,
PS
(
node
)
->
psort_grab_tape
);
}
/*
* Now we have the length of the prior tuple, back up and read it.
* Note: GETTUP expects we are positioned after the initial length
* word of the tuple, so back up to that point.
*/
if
(
!
LogicalTapeBackspace
(
PS
(
node
)
->
tapeset
,
PS
(
node
)
->
psort_grab_tape
,
tuplen
))
elog
(
ERROR
,
"psort_grabtuple: too big tuple len in backward scan"
);
tup
=
ALLOCTUP
(
tuplen
);
GETTUP
(
node
,
tup
,
tuplen
,
PS
(
node
)
->
psort_grab_tape
);
return
tup
;
}
else
{
*
should_free
=
false
;
if
(
ScanDirectionIsForward
(
node
->
plan
.
state
->
es_direction
))
{
if
(
PS
(
node
)
->
psort_current
<
PS
(
node
)
->
tupcount
)
return
PS
(
node
)
->
memtuples
[
PS
(
node
)
->
psort_current
++
];
else
{
PS
(
node
)
->
all_fetched
=
true
;
return
NULL
;
}
}
/* Backward */
if
(
PS
(
node
)
->
psort_current
<=
0
)
return
NULL
;
/*
* if all tuples are fetched already then we return last tuple,
* else - tuple before last returned.
*/
if
(
PS
(
node
)
->
all_fetched
)
PS
(
node
)
->
all_fetched
=
false
;
else
{
PS
(
node
)
->
psort_current
--
;
/* last returned tuple */
if
(
PS
(
node
)
->
psort_current
<=
0
)
return
NULL
;
}
return
PS
(
node
)
->
memtuples
[
PS
(
node
)
->
psort_current
-
1
];
}
}
/*
* psort_markpos - saves current position in the merged sort file
*
* XXX I suspect these need to save & restore the all_fetched flag as well!
*/
void
psort_markpos
(
Sort
*
node
)
{
Assert
(
node
!=
(
Sort
*
)
NULL
);
Assert
(
PS
(
node
)
!=
(
Psortstate
*
)
NULL
);
if
(
PS
(
node
)
->
using_tape_files
==
true
)
LogicalTapeTell
(
PS
(
node
)
->
tapeset
,
PS
(
node
)
->
psort_grab_tape
,
&
PS
(
node
)
->
psort_saved
,
&
PS
(
node
)
->
psort_saved_offset
);
else
PS
(
node
)
->
psort_saved
=
PS
(
node
)
->
psort_current
;
}
/*
* psort_restorepos- restores current position in merged sort file to
* last saved position
*/
void
psort_restorepos
(
Sort
*
node
)
{
Assert
(
node
!=
(
Sort
*
)
NULL
);
Assert
(
PS
(
node
)
!=
(
Psortstate
*
)
NULL
);
if
(
PS
(
node
)
->
using_tape_files
==
true
)
{
if
(
!
LogicalTapeSeek
(
PS
(
node
)
->
tapeset
,
PS
(
node
)
->
psort_grab_tape
,
PS
(
node
)
->
psort_saved
,
PS
(
node
)
->
psort_saved_offset
))
elog
(
ERROR
,
"psort_restorepos failed"
);
}
else
PS
(
node
)
->
psort_current
=
PS
(
node
)
->
psort_saved
;
}
/*
* psort_end
*
* Release resources and clean up.
*/
void
psort_end
(
Sort
*
node
)
{
/* node->cleaned is probably redundant? */
if
(
!
node
->
cleaned
&&
PS
(
node
)
!=
(
Psortstate
*
)
NULL
)
{
if
(
PS
(
node
)
->
tapeset
)
LogicalTapeSetClose
(
PS
(
node
)
->
tapeset
);
if
(
PS
(
node
)
->
memtuples
)
pfree
(
PS
(
node
)
->
memtuples
);
/* XXX what about freeing leftist tree and tuples in memory? */
NDirectFileRead
+=
(
int
)
ceil
((
double
)
PS
(
node
)
->
BytesRead
/
BLCKSZ
);
NDirectFileWrite
+=
(
int
)
ceil
((
double
)
PS
(
node
)
->
BytesWritten
/
BLCKSZ
);
pfree
((
void
*
)
node
->
psortstate
);
node
->
psortstate
=
NULL
;
node
->
cleaned
=
TRUE
;
}
}
void
psort_rescan
(
Sort
*
node
)
{
/*
* If subnode is to be rescanned then free our previous results
*/
if
(((
Plan
*
)
node
)
->
lefttree
->
chgParam
!=
NULL
)
{
psort_end
(
node
);
node
->
cleaned
=
false
;
/* huh? */
}
else
if
(
PS
(
node
)
!=
(
Psortstate
*
)
NULL
)
{
PS
(
node
)
->
all_fetched
=
false
;
PS
(
node
)
->
psort_current
=
0
;
PS
(
node
)
->
psort_saved
=
0L
;
PS
(
node
)
->
psort_saved_offset
=
0
;
if
(
PS
(
node
)
->
using_tape_files
==
true
)
LogicalTapeRewind
(
PS
(
node
)
->
tapeset
,
PS
(
node
)
->
psort_grab_tape
,
false
);
}
}
static
int
_psort_cmp
(
HeapTuple
*
ltup
,
HeapTuple
*
rtup
)
{
Datum
lattr
,
rattr
;
int
nkey
;
int
result
=
0
;
bool
isnull1
,
isnull2
;
for
(
nkey
=
0
;
nkey
<
PsortNkeys
&&
!
result
;
nkey
++
)
{
lattr
=
heap_getattr
(
*
ltup
,
PsortKeys
[
nkey
].
sk_attno
,
PsortTupDesc
,
&
isnull1
);
rattr
=
heap_getattr
(
*
rtup
,
PsortKeys
[
nkey
].
sk_attno
,
PsortTupDesc
,
&
isnull2
);
if
(
isnull1
)
{
if
(
!
isnull2
)
result
=
1
;
}
else
if
(
isnull2
)
result
=
-
1
;
else
if
(
PsortKeys
[
nkey
].
sk_flags
&
SK_COMMUTE
)
{
if
(
!
(
result
=
-
(
long
)
(
*
fmgr_faddr
(
&
PsortKeys
[
nkey
].
sk_func
))
(
rattr
,
lattr
)))
result
=
(
long
)
(
*
fmgr_faddr
(
&
PsortKeys
[
nkey
].
sk_func
))
(
lattr
,
rattr
);
}
else
if
(
!
(
result
=
-
(
long
)
(
*
fmgr_faddr
(
&
PsortKeys
[
nkey
].
sk_func
))
(
lattr
,
rattr
)))
result
=
(
long
)
(
*
fmgr_faddr
(
&
PsortKeys
[
nkey
].
sk_func
))
(
rattr
,
lattr
);
}
return
result
;
}
src/include/lib/qsort.h
deleted
100644 → 0
View file @
26c48b5e
/*-------------------------------------------------------------------------
*
* qsort.h
*
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: qsort.h,v 1.7 1999/02/13 23:21:32 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef QSORT_H
#define QSORT_H
extern
void
pg_qsort
(
void
*
bot
,
size_t
nmemb
,
size_t
size
,
int
(
*
compar
)
(
void
*
,
void
*
));
#endif
/* QSORT_H */
src/include/utils/lselect.h
deleted
100644 → 0
View file @
26c48b5e
/*-------------------------------------------------------------------------
*
* lselect.h
* definitions for the replacement selection algorithm.
*
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: lselect.h,v 1.14 1999/07/17 20:18:36 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef LSELECT_H
#define LSELECT_H
#include "utils/syscache.h"
struct
leftist
{
short
lt_dist
;
/* distance to leaf/empty node */
short
lt_devnum
;
/* device number of tuple */
HeapTuple
lt_tuple
;
struct
leftist
*
lt_left
;
struct
leftist
*
lt_right
;
};
/* replaces global variables in lselect.c to make it reentrant */
typedef
struct
{
TupleDesc
tupDesc
;
int
nKeys
;
ScanKey
scanKeys
;
int
sortMem
;
/* needed for psort */
}
LeftistContextData
;
typedef
LeftistContextData
*
LeftistContext
;
extern
struct
leftist
*
lmerge
(
struct
leftist
*
pt
,
struct
leftist
*
qt
,
LeftistContext
context
);
extern
HeapTuple
gettuple
(
struct
leftist
**
treep
,
short
*
devnum
,
LeftistContext
context
);
extern
void
puttuple
(
struct
leftist
**
treep
,
HeapTuple
newtuple
,
short
devnum
,
LeftistContext
context
);
extern
int
tuplecmp
(
HeapTuple
ltup
,
HeapTuple
rtup
,
LeftistContext
context
);
#ifdef EBUG
extern
void
checktree
(
struct
leftist
*
tree
,
LeftistContext
context
);
extern
int
checktreer
(
struct
leftist
*
tree
,
int
level
,
LeftistContext
context
);
#endif
/* EBUG */
#endif
/* LSELECT_H */
src/include/utils/psort.h
deleted
100644 → 0
View file @
26c48b5e
/*-------------------------------------------------------------------------
*
* psort.h
* Polyphase merge sort.
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: psort.h,v 1.23 1999/10/16 19:49:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PSORT_H
#define PSORT_H
#include "access/htup.h"
#include "access/skey.h"
#include "nodes/plannodes.h"
extern
bool
psort_begin
(
Sort
*
node
,
int
nkeys
,
ScanKey
key
);
extern
HeapTuple
psort_grabtuple
(
Sort
*
node
,
bool
*
should_free
);
extern
void
psort_markpos
(
Sort
*
node
);
extern
void
psort_restorepos
(
Sort
*
node
);
extern
void
psort_end
(
Sort
*
node
);
extern
void
psort_rescan
(
Sort
*
node
);
#endif
/* PSORT_H */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment