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
e8647c45
Commit
e8647c45
authored
Apr 02, 1997
by
Vadim B. Mikheev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Sequence numbers generators code.
parent
1a3c7371
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
554 additions
and
2 deletions
+554
-2
src/backend/commands/Makefile
src/backend/commands/Makefile
+2
-2
src/backend/commands/sequence.c
src/backend/commands/sequence.c
+552
-0
No files found.
src/backend/commands/Makefile
View file @
e8647c45
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
# Makefile for commands
# Makefile for commands
#
#
# IDENTIFICATION
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.
2 1996/11/03 23:57:17 scrappy
Exp $
# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.
3 1997/04/02 03:51:23 vadim
Exp $
#
#
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
...
@@ -19,7 +19,7 @@ CFLAGS+=$(INCLUDE_OPT)
...
@@ -19,7 +19,7 @@ CFLAGS+=$(INCLUDE_OPT)
OBJS
=
async.o creatinh.o command.o copy.o defind.o define.o
\
OBJS
=
async.o creatinh.o command.o copy.o defind.o define.o
\
purge.o remove.o rename.o vacuum.o version.o view.o cluster.o
\
purge.o remove.o rename.o vacuum.o version.o view.o cluster.o
\
recipe.o explain.o
recipe.o explain.o
sequence.o
all
:
SUBSYS.o
all
:
SUBSYS.o
...
...
src/backend/commands/sequence.c
0 → 100644
View file @
e8647c45
/*-------------------------------------------------------------------------
*
* sequence.c--
* PostgreSQL sequences support code.
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <string.h>
#include <postgres.h>
#include <storage/bufmgr.h>
#include <storage/bufpage.h>
#include <storage/lmgr.h>
#include <access/heapam.h>
#include <nodes/parsenodes.h>
#include <commands/creatinh.h>
#include <commands/sequence.h>
#include <utils/builtins.h>
#define SEQ_MAGIC 0x1717
#define SEQ_MAXVALUE ((int4)0x7FFFFFFF)
#define SEQ_MINVALUE -(SEQ_MAXVALUE)
bool
ItsSequenceCreation
=
false
;
typedef
struct
FormData_pg_sequence
{
NameData
sequence_name
;
int4
last_value
;
int4
increment_by
;
int4
max_value
;
int4
min_value
;
int4
cache_value
;
char
is_cycled
;
char
is_called
;
}
FormData_pg_sequence
;
typedef
FormData_pg_sequence
*
SequenceTupleForm
;
typedef
struct
sequence_magic
{
uint32
magic
;
}
sequence_magic
;
typedef
struct
SeqTableData
{
char
*
name
;
Oid
relid
;
Relation
rel
;
int4
cached
;
int4
last
;
int4
increment
;
struct
SeqTableData
*
next
;
}
SeqTableData
;
typedef
SeqTableData
*
SeqTable
;
static
SeqTable
seqtab
=
NULL
;
static
SeqTable
init_sequence
(
char
*
caller
,
char
*
name
);
static
SequenceTupleForm
read_info
(
char
*
caller
,
SeqTable
elm
,
Buffer
*
buf
);
static
void
init_params
(
CreateSeqStmt
*
seq
,
SequenceTupleForm
new
);
static
int
get_param
(
DefElem
*
def
);
/*
* DefineSequence --
* Creates a new sequence relation
*/
void
DefineSequence
(
CreateSeqStmt
*
seq
)
{
FormData_pg_sequence
new
;
CreateStmt
*
stmt
=
makeNode
(
CreateStmt
);
ColumnDef
*
coldef
;
TypeName
*
typnam
;
Relation
rel
;
Buffer
buf
;
PageHeader
page
;
sequence_magic
*
sm
;
HeapTuple
tuple
;
TupleDesc
tupDesc
;
Datum
value
[
SEQ_COL_LASTCOL
];
char
null
[
SEQ_COL_LASTCOL
];
int
i
;
/* Check and set values */
init_params
(
seq
,
&
new
);
/*
* Create relation (and fill null[] & value[])
*/
stmt
->
tableElts
=
NIL
;
for
(
i
=
SEQ_COL_FIRSTCOL
;
i
<=
SEQ_COL_LASTCOL
;
i
++
)
{
typnam
=
makeNode
(
TypeName
);
typnam
->
setof
=
FALSE
;
typnam
->
arrayBounds
=
NULL
;
coldef
=
makeNode
(
ColumnDef
);
coldef
->
typename
=
typnam
;
null
[
i
-
1
]
=
' '
;
switch
(
i
)
{
case
SEQ_COL_NAME
:
typnam
->
name
=
"name"
;
coldef
->
colname
=
"sequence_name"
;
value
[
i
-
1
]
=
PointerGetDatum
(
seq
->
seqname
);
break
;
case
SEQ_COL_LASTVAL
:
typnam
->
name
=
"int4"
;
coldef
->
colname
=
"last_value"
;
value
[
i
-
1
]
=
Int32GetDatum
(
new
.
last_value
);
break
;
case
SEQ_COL_INCBY
:
typnam
->
name
=
"int4"
;
coldef
->
colname
=
"increment_by"
;
value
[
i
-
1
]
=
Int32GetDatum
(
new
.
increment_by
);
break
;
case
SEQ_COL_MAXVALUE
:
typnam
->
name
=
"int4"
;
coldef
->
colname
=
"max_value"
;
value
[
i
-
1
]
=
Int32GetDatum
(
new
.
max_value
);
break
;
case
SEQ_COL_MINVALUE
:
typnam
->
name
=
"int4"
;
coldef
->
colname
=
"min_value"
;
value
[
i
-
1
]
=
Int32GetDatum
(
new
.
min_value
);
break
;
case
SEQ_COL_CACHE
:
typnam
->
name
=
"int4"
;
coldef
->
colname
=
"cache_value"
;
value
[
i
-
1
]
=
Int32GetDatum
(
new
.
cache_value
);
break
;
case
SEQ_COL_CYCLE
:
typnam
->
name
=
"char"
;
coldef
->
colname
=
"is_cycled"
;
value
[
i
-
1
]
=
CharGetDatum
(
new
.
is_cycled
);
break
;
case
SEQ_COL_CALLED
:
typnam
->
name
=
"char"
;
coldef
->
colname
=
"is_called"
;
value
[
i
-
1
]
=
CharGetDatum
(
'f'
);
break
;
}
stmt
->
tableElts
=
lappend
(
stmt
->
tableElts
,
coldef
);
}
stmt
->
relname
=
seq
->
seqname
;
stmt
->
archiveLoc
=
-
1
;
/* default */
stmt
->
archiveType
=
ARCH_NONE
;
stmt
->
inhRelnames
=
NIL
;
ItsSequenceCreation
=
true
;
/* hack */
DefineRelation
(
stmt
);
/* Xact abort calls CloseSequences, which turns ItsSequenceCreation off */
ItsSequenceCreation
=
false
;
/* hack */
rel
=
heap_openr
(
seq
->
seqname
);
Assert
(
RelationIsValid
(
rel
)
);
RelationSetLockForWrite
(
rel
);
tupDesc
=
RelationGetTupleDescriptor
(
rel
);
Assert
(
RelationGetNumberOfBlocks
(
rel
)
==
0
);
buf
=
ReadBuffer
(
rel
,
P_NEW
);
if
(
!
BufferIsValid
(
buf
)
)
elog
(
WARN
,
"DefineSequence: ReadBuffer failed"
);
page
=
(
PageHeader
)
BufferGetPage
(
buf
);
PageInit
((
Page
)
page
,
BufferGetPageSize
(
buf
),
sizeof
(
sequence_magic
));
sm
=
(
sequence_magic
*
)
PageGetSpecialPointer
(
page
);
sm
->
magic
=
SEQ_MAGIC
;
/* Now - form & insert sequence tuple */
tuple
=
heap_formtuple
(
tupDesc
,
value
,
null
);
heap_insert
(
rel
,
tuple
);
if
(
WriteBuffer
(
buf
)
==
STATUS_ERROR
)
elog
(
WARN
,
"DefineSequence: WriteBuffer failed"
);
RelationUnsetLockForWrite
(
rel
);
heap_close
(
rel
);
return
;
}
int4
nextval
(
struct
varlena
*
seqin
)
{
char
*
seqname
=
textout
(
seqin
);
SeqTable
elm
;
Buffer
buf
;
SequenceTupleForm
seq
;
ItemPointerData
iptr
;
int4
incby
,
maxv
,
minv
,
cache
;
int4
result
,
next
,
rescnt
=
0
;
/* open and WIntentLock sequence */
elm
=
init_sequence
(
"nextval"
,
seqname
);
if
(
elm
->
last
!=
elm
->
cached
)
/* some numbers were cached */
{
elm
->
last
+=
elm
->
increment
;
return
(
elm
->
last
);
}
seq
=
read_info
(
"nextval"
,
elm
,
&
buf
);
/* lock page and read tuple */
next
=
result
=
seq
->
last_value
;
incby
=
seq
->
increment_by
;
maxv
=
seq
->
max_value
;
minv
=
seq
->
min_value
;
cache
=
seq
->
cache_value
;
if
(
seq
->
is_called
!=
't'
)
rescnt
++
;
/* last_value if not called */
while
(
rescnt
<
cache
)
/* try to fetch cache numbers */
{
/*
* Check MAXVALUE for ascending sequences
* and MINVALUE for descending sequences
*/
if
(
incby
>
0
)
/* ascending sequence */
{
if
(
(
maxv
>=
0
&&
next
>
maxv
-
incby
)
||
(
maxv
<
0
&&
next
+
incby
>
maxv
)
)
{
if
(
rescnt
>
0
)
break
;
/* stop caching */
if
(
seq
->
is_cycled
!=
't'
)
elog
(
WARN
,
"%s.nextval: got MAXVALUE (%d)"
,
seqname
,
maxv
);
next
=
minv
;
}
else
next
+=
incby
;
}
else
/* descending sequence */
{
if
(
(
minv
<
0
&&
next
<
minv
-
incby
)
||
(
minv
>=
0
&&
next
+
incby
<
minv
)
)
{
if
(
rescnt
>
0
)
break
;
/* stop caching */
if
(
seq
->
is_cycled
!=
't'
)
elog
(
WARN
,
"%s.nextval: got MINVALUE (%d)"
,
seqname
,
minv
);
next
=
maxv
;
}
else
next
+=
incby
;
}
rescnt
++
;
/* got result */
if
(
rescnt
==
1
)
/* if it's first one - */
result
=
next
;
/* it's what to return */
}
/* save info in local cache */
elm
->
last
=
result
;
/* last returned number */
elm
->
cached
=
next
;
/* last cached number */
/* save info in sequence relation */
seq
->
last_value
=
next
;
/* last fetched number */
seq
->
is_called
=
't'
;
if
(
WriteBuffer
(
buf
)
==
STATUS_ERROR
)
elog
(
WARN
,
"%s.nextval: WriteBuffer failed"
,
elm
->
name
);
ItemPointerSet
(
&
iptr
,
0
,
FirstOffsetNumber
);
RelationUnsetSingleWLockPage
(
elm
->
rel
,
&
iptr
);
return
(
result
);
}
int4
currval
(
struct
varlena
*
seqin
)
{
char
*
seqname
=
textout
(
seqin
);
SeqTable
elm
;
Buffer
buf
;
SequenceTupleForm
seq
;
ItemPointerData
iptr
;
int4
result
;
/* open and WIntentLock sequence */
elm
=
init_sequence
(
"currval"
,
seqname
);
if
(
elm
->
last
!=
elm
->
cached
)
/* some numbers were cached */
{
return
(
elm
->
last
);
/* return last returned by nextval */
}
seq
=
read_info
(
"currval"
,
elm
,
&
buf
);
if
(
seq
->
is_called
!=
't'
)
{
elog
(
WARN
,
"%s.currval: yet undefined (%s.nextval never called)"
,
seqname
,
seqname
);
}
result
=
seq
->
last_value
;
if
(
ReleaseBuffer
(
buf
)
==
STATUS_ERROR
)
elog
(
WARN
,
"%s.currval: ReleaseBuffer failed"
,
seqname
);
ItemPointerSet
(
&
iptr
,
0
,
FirstOffsetNumber
);
RelationUnsetSingleWLockPage
(
elm
->
rel
,
&
iptr
);
return
(
result
);
}
static
SequenceTupleForm
read_info
(
char
*
caller
,
SeqTable
elm
,
Buffer
*
buf
)
{
ItemPointerData
iptr
;
PageHeader
page
;
ItemId
lp
;
HeapTuple
tuple
;
sequence_magic
*
sm
;
SequenceTupleForm
seq
;
ItemPointerSet
(
&
iptr
,
0
,
FirstOffsetNumber
);
RelationSetSingleWLockPage
(
elm
->
rel
,
&
iptr
);
if
(
RelationGetNumberOfBlocks
(
elm
->
rel
)
!=
1
)
elog
(
WARN
,
"%s.%s: invalid number of blocks in sequence"
,
elm
->
name
,
caller
);
*
buf
=
ReadBuffer
(
elm
->
rel
,
0
);
if
(
!
BufferIsValid
(
*
buf
)
)
elog
(
WARN
,
"%s.%s: ReadBuffer failed"
,
elm
->
name
,
caller
);
page
=
(
PageHeader
)
BufferGetPage
(
*
buf
);
sm
=
(
sequence_magic
*
)
PageGetSpecialPointer
(
page
);
if
(
sm
->
magic
!=
SEQ_MAGIC
)
elog
(
WARN
,
"%s.%s: bad magic (%08X)"
,
elm
->
name
,
caller
,
sm
->
magic
);
lp
=
PageGetItemId
(
page
,
FirstOffsetNumber
);
Assert
(
ItemIdIsUsed
(
lp
));
tuple
=
(
HeapTuple
)
PageGetItem
((
Page
)
page
,
lp
);
seq
=
(
SequenceTupleForm
)
GETSTRUCT
(
tuple
);
elm
->
increment
=
seq
->
increment_by
;
return
(
seq
);
}
static
SeqTable
init_sequence
(
char
*
caller
,
char
*
name
)
{
SeqTable
elm
,
priv
=
(
SeqTable
)
NULL
;
SeqTable
temp
;
for
(
elm
=
seqtab
;
elm
!=
(
SeqTable
)
NULL
;
)
{
if
(
strcmp
(
elm
->
name
,
name
)
==
0
)
break
;
priv
=
elm
;
elm
=
elm
->
next
;
}
if
(
elm
==
(
SeqTable
)
NULL
)
/* not found */
{
temp
=
(
SeqTable
)
malloc
(
sizeof
(
SeqTableData
));
temp
->
name
=
malloc
(
strlen
(
name
)
+
1
);
strcpy
(
temp
->
name
,
name
);
temp
->
rel
=
(
Relation
)
NULL
;
temp
->
cached
=
temp
->
last
=
temp
->
increment
=
0
;
temp
->
next
=
(
SeqTable
)
NULL
;
}
else
/* found */
{
if
(
elm
->
rel
!=
(
Relation
)
NULL
)
/* already opened */
return
(
elm
);
temp
=
elm
;
}
temp
->
rel
=
heap_openr
(
name
);
if
(
!
RelationIsValid
(
temp
->
rel
)
)
elog
(
WARN
,
"%s.%s: sequence does not exist"
,
name
,
caller
);
RelationSetWIntentLock
(
temp
->
rel
);
if
(
temp
->
rel
->
rd_rel
->
relkind
!=
RELKIND_SEQUENCE
)
elog
(
WARN
,
"%s.%s: %s is not sequence !"
,
name
,
caller
,
name
);
if
(
elm
!=
(
SeqTable
)
NULL
)
/* we opened sequence from our */
{
/* SeqTable - check relid ! */
if
(
RelationGetRelationId
(
elm
->
rel
)
!=
elm
->
relid
)
{
elog
(
NOTICE
,
"%s.%s: sequence was re-created"
,
name
,
caller
,
name
);
elm
->
cached
=
elm
->
last
=
elm
->
increment
=
0
;
elm
->
relid
=
RelationGetRelationId
(
elm
->
rel
);
}
}
else
{
elm
=
temp
;
elm
->
relid
=
RelationGetRelationId
(
elm
->
rel
);
if
(
seqtab
==
(
SeqTable
)
NULL
)
seqtab
=
elm
;
else
priv
->
next
=
elm
;
}
return
(
elm
);
}
/*
* CloseSequences --
* is calling by xact mgr at commit/abort.
*/
void
CloseSequences
(
void
)
{
SeqTable
elm
;
Relation
rel
;
ItsSequenceCreation
=
false
;
for
(
elm
=
seqtab
;
elm
!=
(
SeqTable
)
NULL
;
)
{
if
(
elm
->
rel
!=
(
Relation
)
NULL
)
/* opened in current xact */
{
rel
=
elm
->
rel
;
elm
->
rel
=
(
Relation
)
NULL
;
RelationUnsetWIntentLock
(
rel
);
heap_close
(
rel
);
}
elm
=
elm
->
next
;
}
return
;
}
static
void
init_params
(
CreateSeqStmt
*
seq
,
SequenceTupleForm
new
)
{
DefElem
*
last_value
=
NULL
;
DefElem
*
increment_by
=
NULL
;
DefElem
*
max_value
=
NULL
;
DefElem
*
min_value
=
NULL
;
DefElem
*
cache_value
=
NULL
;
List
*
option
;
new
->
is_cycled
=
'f'
;
foreach
(
option
,
seq
->
options
)
{
DefElem
*
defel
=
(
DefElem
*
)
lfirst
(
option
);
if
(
!
strcasecmp
(
defel
->
defname
,
"increment"
)
)
increment_by
=
defel
;
else
if
(
!
strcasecmp
(
defel
->
defname
,
"start"
)
)
last_value
=
defel
;
else
if
(
!
strcasecmp
(
defel
->
defname
,
"maxvalue"
)
)
max_value
=
defel
;
else
if
(
!
strcasecmp
(
defel
->
defname
,
"minvalue"
)
)
min_value
=
defel
;
else
if
(
!
strcasecmp
(
defel
->
defname
,
"cache"
)
)
cache_value
=
defel
;
else
if
(
!
strcasecmp
(
defel
->
defname
,
"cycle"
)
)
{
if
(
defel
->
arg
!=
(
Node
*
)
NULL
)
elog
(
WARN
,
"DefineSequence: CYCLE ??"
);
new
->
is_cycled
=
't'
;
}
else
elog
(
WARN
,
"DefineSequence: option
\"
%s
\"
not recognized"
,
defel
->
defname
);
}
if
(
increment_by
==
(
DefElem
*
)
NULL
)
/* INCREMENT BY */
new
->
increment_by
=
1
;
else
if
(
(
new
->
increment_by
=
get_param
(
increment_by
)
)
==
0
)
elog
(
WARN
,
"DefineSequence: can't INCREMENT by 0"
);
if
(
max_value
==
(
DefElem
*
)
NULL
)
/* MAXVALUE */
if
(
new
->
increment_by
>
0
)
new
->
max_value
=
SEQ_MAXVALUE
;
/* ascending seq */
else
new
->
max_value
=
-
1
;
/* descending seq */
else
new
->
max_value
=
get_param
(
max_value
);
if
(
min_value
==
(
DefElem
*
)
NULL
)
/* MINVALUE */
if
(
new
->
increment_by
>
0
)
new
->
min_value
=
1
;
/* ascending seq */
else
new
->
min_value
=
SEQ_MINVALUE
;
/* descending seq */
else
new
->
min_value
=
get_param
(
min_value
);
if
(
new
->
min_value
>=
new
->
max_value
)
elog
(
WARN
,
"DefineSequence: MINVALUE (%d) can't be >= MAXVALUE (%d)"
,
new
->
min_value
,
new
->
max_value
);
if
(
last_value
==
(
DefElem
*
)
NULL
)
/* START WITH */
if
(
new
->
increment_by
>
0
)
new
->
last_value
=
new
->
min_value
;
/* ascending seq */
else
new
->
last_value
=
new
->
max_value
;
/* descending seq */
else
new
->
last_value
=
get_param
(
last_value
);
if
(
new
->
last_value
<
new
->
min_value
)
elog
(
WARN
,
"DefineSequence: START value (%d) can't be < MINVALUE (%d)"
,
new
->
last_value
,
new
->
min_value
);
if
(
new
->
last_value
>
new
->
max_value
)
elog
(
WARN
,
"DefineSequence: START value (%d) can't be > MAXVALUE (%d)"
,
new
->
last_value
,
new
->
max_value
);
if
(
cache_value
==
(
DefElem
*
)
NULL
)
/* CACHE */
new
->
cache_value
=
1
;
else
if
(
(
new
->
cache_value
=
get_param
(
cache_value
)
)
<=
0
)
elog
(
WARN
,
"DefineSequence: CACHE (%d) can't be <= 0"
,
new
->
cache_value
);
}
static
int
get_param
(
DefElem
*
def
)
{
if
(
def
->
arg
==
(
Node
*
)
NULL
)
elog
(
WARN
,
"DefineSequence:
\"
%s
\"
value unspecified"
,
def
->
defname
);
if
(
nodeTag
(
def
->
arg
)
==
T_Integer
)
return
(
intVal
(
def
->
arg
));
elog
(
WARN
,
"DefineSequence:
\"
%s
\"
is to be integer"
,
def
->
defname
);
return
(
-
1
);
}
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