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
c7d2ce7b
Commit
c7d2ce7b
authored
Feb 14, 2001
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Repair problems with duplicate index names generated when CREATE TABLE
specifies redundant UNIQUE conditions.
parent
4a66f9dd
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
76 additions
and
73 deletions
+76
-73
src/backend/parser/analyze.c
src/backend/parser/analyze.c
+76
-73
No files found.
src/backend/parser/analyze.c
View file @
c7d2ce7b
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* $Id: analyze.c,v 1.1
79 2001/02/14 21:35:01
tgl Exp $
* $Id: analyze.c,v 1.1
80 2001/02/14 23:32:38
tgl Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -606,7 +606,8 @@ makeObjectName(char *name1, char *name2, char *typename)
...
@@ -606,7 +606,8 @@ makeObjectName(char *name1, char *name2, char *typename)
}
}
static
char
*
static
char
*
CreateIndexName
(
char
*
table_name
,
char
*
column_name
,
char
*
label
,
List
*
indices
)
CreateIndexName
(
char
*
table_name
,
char
*
column_name
,
char
*
label
,
List
*
indices
)
{
{
int
pass
=
0
;
int
pass
=
0
;
char
*
iname
=
NULL
;
char
*
iname
=
NULL
;
...
@@ -617,7 +618,8 @@ CreateIndexName(char *table_name, char *column_name, char *label, List *indices)
...
@@ -617,7 +618,8 @@ CreateIndexName(char *table_name, char *column_name, char *label, List *indices)
* The type name for makeObjectName is label, or labelN if that's
* The type name for makeObjectName is label, or labelN if that's
* necessary to prevent collisions among multiple indexes for the same
* necessary to prevent collisions among multiple indexes for the same
* table. Note there is no check for collisions with already-existing
* table. Note there is no check for collisions with already-existing
* indexes; this ought to be rethought someday.
* indexes, only among the indexes we're about to create now; this ought
* to be improved someday.
*/
*/
strcpy
(
typename
,
label
);
strcpy
(
typename
,
label
);
...
@@ -629,14 +631,15 @@ CreateIndexName(char *table_name, char *column_name, char *label, List *indices)
...
@@ -629,14 +631,15 @@ CreateIndexName(char *table_name, char *column_name, char *label, List *indices)
{
{
IndexStmt
*
index
=
lfirst
(
ilist
);
IndexStmt
*
index
=
lfirst
(
ilist
);
if
(
strcmp
(
iname
,
index
->
idxname
)
==
0
)
if
(
index
->
idxname
!=
NULL
&&
strcmp
(
iname
,
index
->
idxname
)
==
0
)
break
;
break
;
}
}
/* ran through entire list? then no name conflict found so done */
/* ran through entire list? then no name conflict found so done */
if
(
ilist
==
NIL
)
if
(
ilist
==
NIL
)
break
;
break
;
/*
the last one conflicted
, so try a new name component */
/*
found a conflict
, so try a new name component */
pfree
(
iname
);
pfree
(
iname
);
sprintf
(
typename
,
"%s%d"
,
label
,
++
pass
);
sprintf
(
typename
,
"%s%d"
,
label
,
++
pass
);
}
}
...
@@ -745,9 +748,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
...
@@ -745,9 +748,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
constraint
=
makeNode
(
Constraint
);
constraint
=
makeNode
(
Constraint
);
constraint
->
contype
=
CONSTR_UNIQUE
;
constraint
->
contype
=
CONSTR_UNIQUE
;
constraint
->
name
=
makeObjectName
(
stmt
->
relname
,
constraint
->
name
=
NULL
;
/* assign later */
column
->
colname
,
"key"
);
column
->
constraints
=
lappend
(
column
->
constraints
,
column
->
constraints
=
lappend
(
column
->
constraints
,
constraint
);
constraint
);
...
@@ -919,13 +920,9 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
...
@@ -919,13 +920,9 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
stmt
->
constraints
=
constraints
;
stmt
->
constraints
=
constraints
;
/* Now run through the "deferred list" to complete the query transformation.
/* Now run through the "deferred list" to complete the query transformation.
* For PRIMARY KEYs, mark each column as NOT NULL and create an index.
* For PRIMARY KEY, mark each column as NOT NULL and create an index.
* For UNIQUE, create an index as for PRIMARY KEYS, but do not insist on NOT NULL.
* For UNIQUE, create an index as for PRIMARY KEY, but do not insist on
*
* NOT NULL.
* Note that this code does not currently look for all possible redundant cases
* and either ignore or stop with warning. The create might fail later when
* names for indices turn out to be duplicated, or a user might have specified
* extra useless indices which might hurt performance. - thomas 1997-12-08
*/
*/
while
(
dlist
!=
NIL
)
while
(
dlist
!=
NIL
)
{
{
...
@@ -943,7 +940,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
...
@@ -943,7 +940,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
if
(
pkey
!=
NULL
)
if
(
pkey
!=
NULL
)
elog
(
ERROR
,
"CREATE TABLE/PRIMARY KEY multiple primary keys"
elog
(
ERROR
,
"CREATE TABLE/PRIMARY KEY multiple primary keys"
" for table '%s' are not allowed"
,
stmt
->
relname
);
" for table '%s' are not allowed"
,
stmt
->
relname
);
pkey
=
(
IndexStmt
*
)
index
;
pkey
=
index
;
}
}
if
(
constraint
->
name
!=
NULL
)
if
(
constraint
->
name
!=
NULL
)
...
@@ -951,7 +948,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
...
@@ -951,7 +948,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
else
if
(
constraint
->
contype
==
CONSTR_PRIMARY
)
else
if
(
constraint
->
contype
==
CONSTR_PRIMARY
)
index
->
idxname
=
makeObjectName
(
stmt
->
relname
,
NULL
,
"pkey"
);
index
->
idxname
=
makeObjectName
(
stmt
->
relname
,
NULL
,
"pkey"
);
else
else
index
->
idxname
=
NULL
;
index
->
idxname
=
NULL
;
/* will set it later */
index
->
relname
=
stmt
->
relname
;
index
->
relname
=
stmt
->
relname
;
index
->
accessMethod
=
"btree"
;
index
->
accessMethod
=
"btree"
;
...
@@ -995,10 +992,10 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
...
@@ -995,10 +992,10 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
int
count
;
int
count
;
Assert
(
IsA
(
inh
,
String
));
Assert
(
IsA
(
inh
,
String
));
rel
=
heap_openr
(
inh
->
val
.
str
,
AccessShareLock
);
rel
=
heap_openr
(
strVal
(
inh
)
,
AccessShareLock
);
if
(
rel
->
rd_rel
->
relkind
!=
RELKIND_RELATION
)
if
(
rel
->
rd_rel
->
relkind
!=
RELKIND_RELATION
)
elog
(
ERROR
,
"inherited table
\"
%s
\"
is not a relation"
,
elog
(
ERROR
,
"inherited table
\"
%s
\"
is not a relation"
,
inh
->
val
.
str
);
strVal
(
inh
)
);
for
(
count
=
0
;
count
<
rel
->
rd_att
->
natts
;
count
++
)
for
(
count
=
0
;
count
<
rel
->
rd_att
->
natts
;
count
++
)
{
{
Form_pg_attribute
inhattr
=
rel
->
rd_att
->
attrs
[
count
];
Form_pg_attribute
inhattr
=
rel
->
rd_att
->
attrs
[
count
];
...
@@ -1020,7 +1017,8 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
...
@@ -1020,7 +1017,8 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
* error if the inherited column won't be NOT NULL.
* error if the inherited column won't be NOT NULL.
* (Would a NOTICE be more reasonable?)
* (Would a NOTICE be more reasonable?)
*/
*/
if
(
!
inhattr
->
attnotnull
)
if
(
constraint
->
contype
==
CONSTR_PRIMARY
&&
!
inhattr
->
attnotnull
)
elog
(
ERROR
,
"inherited attribute
\"
%s
\"
cannot be a PRIMARY KEY because it is not marked NOT NULL"
,
elog
(
ERROR
,
"inherited attribute
\"
%s
\"
cannot be a PRIMARY KEY because it is not marked NOT NULL"
,
inhname
);
inhname
);
break
;
break
;
...
@@ -1041,78 +1039,85 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
...
@@ -1041,78 +1039,85 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
iparam
->
args
=
NIL
;
iparam
->
args
=
NIL
;
iparam
->
class
=
NULL
;
iparam
->
class
=
NULL
;
index
->
indexParams
=
lappend
(
index
->
indexParams
,
iparam
);
index
->
indexParams
=
lappend
(
index
->
indexParams
,
iparam
);
if
(
index
->
idxname
==
NULL
)
index
->
idxname
=
CreateIndexName
(
stmt
->
relname
,
iparam
->
name
,
"key"
,
ilist
);
}
}
if
(
index
->
idxname
==
NULL
)
/* should not happen */
elog
(
ERROR
,
"CREATE TABLE: failed to make implicit index name"
);
ilist
=
lappend
(
ilist
,
index
);
ilist
=
lappend
(
ilist
,
index
);
dlist
=
lnext
(
dlist
);
dlist
=
lnext
(
dlist
);
}
}
/* OK, now finally, if there is a primary key, then make sure that there aren't any redundant
/*
* unique indices defined on columns. This can arise if someone specifies UNIQUE explicitly
* Scan the index list and remove any redundant index specifications.
* or if a SERIAL column was defined along with a table PRIMARY KEY constraint.
* This can happen if, for instance, the user writes SERIAL PRIMARY KEY
* - thomas 1999-05-11
* or SERIAL UNIQUE. A strict reading of SQL92 would suggest raising
*/
* an error instead, but that strikes me as too anal-retentive.
* - tgl 2001-02-14
*/
dlist
=
ilist
;
ilist
=
NIL
;
if
(
pkey
!=
NULL
)
if
(
pkey
!=
NULL
)
{
{
dlist
=
ilist
;
/* Make sure we keep the PKEY index in preference to others... */
ilist
=
NIL
;
ilist
=
makeList1
(
pkey
);
while
(
dlist
!=
NIL
)
}
{
while
(
dlist
!=
NIL
)
List
*
pcols
,
{
*
icols
;
index
=
lfirst
(
dlist
);
int
plen
,
ilen
;
int
keep
=
TRUE
;
index
=
lfirst
(
dlist
);
pcols
=
pkey
->
indexParams
;
icols
=
index
->
indexParams
;
plen
=
length
(
pcols
);
/* if it's pkey, it's already in ilist */
ilen
=
length
(
icols
);
if
(
index
!=
pkey
)
{
bool
keep
=
true
;
List
*
priorlist
;
/* Not the same as the primary key? Then we should look... */
foreach
(
priorlist
,
ilist
)
if
((
index
!=
pkey
)
&&
(
ilen
==
plen
))
{
{
keep
=
FALSE
;
IndexStmt
*
priorindex
=
lfirst
(
priorlist
);
while
((
pcols
!=
NIL
)
&&
(
icols
!=
NIL
))
{
IndexElem
*
pcol
=
lfirst
(
pcols
);
IndexElem
*
icol
=
lfirst
(
icols
);
char
*
pname
=
pcol
->
name
;
char
*
iname
=
icol
->
name
;
/* different names? then no match... */
if
(
equal
(
index
->
indexParams
,
priorindex
->
indexParams
))
if
(
strcmp
(
iname
,
pname
)
!=
0
)
{
{
/*
keep
=
TRUE
;
* If the prior index is as yet unnamed, and this one
break
;
* is named, then transfer the name to the prior index.
}
* This ensures that if we have named and unnamed
pcols
=
lnext
(
pcols
);
* constraints, we'll use (at least one of) the names
icols
=
lnext
(
icols
);
* for the index.
*/
if
(
priorindex
->
idxname
==
NULL
)
priorindex
->
idxname
=
index
->
idxname
;
keep
=
false
;
break
;
}
}
}
}
if
(
keep
)
if
(
keep
)
ilist
=
lappend
(
ilist
,
index
);
ilist
=
lappend
(
ilist
,
index
);
dlist
=
lnext
(
dlist
);
}
}
dlist
=
lnext
(
dlist
);
}
}
/*
* Finally, select unique names for all not-previously-named indices,
* and display notice messages.
*/
dlist
=
ilist
;
dlist
=
ilist
;
while
(
dlist
!=
NIL
)
while
(
dlist
!=
NIL
)
{
{
index
=
lfirst
(
dlist
);
index
=
lfirst
(
dlist
);
if
(
index
->
idxname
==
NULL
&&
index
->
indexParams
!=
NIL
)
{
iparam
=
lfirst
(
index
->
indexParams
);
index
->
idxname
=
CreateIndexName
(
stmt
->
relname
,
iparam
->
name
,
"key"
,
ilist
);
}
if
(
index
->
idxname
==
NULL
)
/* should not happen */
elog
(
ERROR
,
"CREATE TABLE: failed to make implicit index name"
);
elog
(
NOTICE
,
"CREATE TABLE/%s will create implicit index '%s' for table '%s'"
,
elog
(
NOTICE
,
"CREATE TABLE/%s will create implicit index '%s' for table '%s'"
,
(
index
->
primary
?
"PRIMARY KEY"
:
"UNIQUE"
),
(
index
->
primary
?
"PRIMARY KEY"
:
"UNIQUE"
),
index
->
idxname
,
stmt
->
relname
);
index
->
idxname
,
stmt
->
relname
);
dlist
=
lnext
(
dlist
);
dlist
=
lnext
(
dlist
);
}
}
...
@@ -1123,7 +1128,6 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
...
@@ -1123,7 +1128,6 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
/*
/*
* Now process the FOREIGN KEY constraints and add appropriate queries
* Now process the FOREIGN KEY constraints and add appropriate queries
* to the extras_after statements list.
* to the extras_after statements list.
*
*/
*/
if
(
fkconstraints
!=
NIL
)
if
(
fkconstraints
!=
NIL
)
{
{
...
@@ -1173,16 +1177,15 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
...
@@ -1173,16 +1177,15 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
List
*
inhRelnames
=
stmt
->
inhRelnames
;
List
*
inhRelnames
=
stmt
->
inhRelnames
;
Relation
rel
;
Relation
rel
;
foreach
(
inher
,
inhRelnames
)
{
foreach
(
inher
,
inhRelnames
)
{
int
count
=
0
;
Value
*
inh
=
lfirst
(
inher
);
Value
*
inh
=
lfirst
(
inher
);
i
f
(
inh
->
type
!=
T_String
)
{
i
nt
count
;
elog
(
ERROR
,
"inherited table name list returns a non-string"
);
}
Assert
(
IsA
(
inh
,
String
));
rel
=
heap_openr
(
inh
->
val
.
str
,
AccessShareLock
);
rel
=
heap_openr
(
strVal
(
inh
)
,
AccessShareLock
);
if
(
rel
->
rd_rel
->
relkind
!=
RELKIND_RELATION
)
if
(
rel
->
rd_rel
->
relkind
!=
RELKIND_RELATION
)
elog
(
ERROR
,
"inherited table
\"
%s
\"
is not a relation"
,
elog
(
ERROR
,
"inherited table
\"
%s
\"
is not a relation"
,
inh
->
val
.
str
);
strVal
(
inh
)
);
for
(
;
count
<
rel
->
rd_att
->
natts
;
count
++
)
{
for
(
count
=
0
;
count
<
rel
->
rd_att
->
natts
;
count
++
)
{
char
*
name
=
NameStr
(
rel
->
rd_att
->
attrs
[
count
]
->
attname
);
char
*
name
=
NameStr
(
rel
->
rd_att
->
attrs
[
count
]
->
attname
);
if
(
strcmp
(
fkattr
->
name
,
name
)
==
0
)
{
if
(
strcmp
(
fkattr
->
name
,
name
)
==
0
)
{
found
=
1
;
found
=
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