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
bedd04a5
Commit
bedd04a5
authored
Dec 04, 1998
by
Thomas G. Lockhart
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement CASE expression.
parent
19740e2f
Changes
17
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
777 additions
and
108 deletions
+777
-108
src/backend/executor/execQual.c
src/backend/executor/execQual.c
+83
-4
src/backend/nodes/copyfuncs.c
src/backend/nodes/copyfuncs.c
+48
-1
src/backend/nodes/outfuncs.c
src/backend/nodes/outfuncs.c
+86
-1
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/createplan.c
+7
-2
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/clauses.c
+37
-4
src/backend/optimizer/util/tlist.c
src/backend/optimizer/util/tlist.c
+23
-7
src/backend/optimizer/util/var.c
src/backend/optimizer/util/var.c
+28
-1
src/backend/parser/analyze.c
src/backend/parser/analyze.c
+12
-13
src/backend/parser/gram.y
src/backend/parser/gram.y
+118
-19
src/backend/parser/keywords.c
src/backend/parser/keywords.c
+7
-1
src/backend/parser/parse_coerce.c
src/backend/parser/parse_coerce.c
+2
-2
src/backend/parser/parse_expr.c
src/backend/parser/parse_expr.c
+154
-2
src/backend/parser/parse_target.c
src/backend/parser/parse_target.c
+62
-28
src/backend/rewrite/rewriteHandler.c
src/backend/rewrite/rewriteHandler.c
+74
-13
src/include/nodes/nodes.h
src/include/nodes/nodes.h
+5
-3
src/include/nodes/parsenodes.h
src/include/nodes/parsenodes.h
+28
-6
src/include/optimizer/clauses.h
src/include/optimizer/clauses.h
+3
-1
No files found.
src/backend/executor/execQual.c
View file @
bedd04a5
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.3
8 1998/11/27 19:52:00 vadim
Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.3
9 1998/12/04 15:33:19 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -20,7 +20,7 @@
* NOTES
* ExecEvalExpr() and ExecEvalVar() are hotspots. making these faster
* will speed up the entire system. Unfortunately they are currently
* implemented recursively.
.
Eliminating the recursion is bound to
* implemented recursively. Eliminating the recursion is bound to
* improve the speed of the executor.
*
* ExecTargetList() is used to make tuple projections. Rather then
...
...
@@ -205,7 +205,7 @@ ExecEvalAggreg(Aggreg *agg, ExprContext *econtext, bool *isNull)
* variable with respect to given expression context.
*
*
* As an entry condition, we expect that the
the
datatype the
* As an entry condition, we expect that the datatype the
* plan expects to get (as told by our "variable" argument) is in
* fact the datatype of the attribute the plan says to fetch (as
* seen in the current context, identified by our "econtext"
...
...
@@ -1124,6 +1124,79 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
return
const_value
;
}
/* ----------------------------------------------------------------
* ExecEvalCase
*
* Evaluate a CASE clause. Will have boolean expressions
* inside the WHEN clauses, and will have constants
* for results.
* - thomas 1998-11-09
* ----------------------------------------------------------------
*/
static
Datum
ExecEvalCase
(
CaseExpr
*
caseExpr
,
ExprContext
*
econtext
,
bool
*
isNull
)
{
List
*
clauses
;
List
*
clause
;
CaseWhen
*
wclause
;
Datum
const_value
=
0
;
bool
isDone
;
clauses
=
caseExpr
->
args
;
/******************
* we evaluate each of the WHEN clauses in turn,
* as soon as one is true we return the corresponding
* result. If none are true then we return the value
* of the default clause, or NULL.
******************
*/
foreach
(
clause
,
clauses
)
{
/******************
* We don't iterate over sets in the quals, so pass in an isDone
* flag, but ignore it.
******************
*/
wclause
=
lfirst
(
clause
);
const_value
=
ExecEvalExpr
((
Node
*
)
wclause
->
expr
,
econtext
,
isNull
,
&
isDone
);
/******************
* if we have a true test, then we return the result,
* since the case statement is satisfied.
******************
*/
if
(
DatumGetInt32
(
const_value
)
!=
0
)
{
const_value
=
ExecEvalExpr
((
Node
*
)
wclause
->
result
,
econtext
,
isNull
,
&
isDone
);
return
(
Datum
)
const_value
;
}
}
if
(
caseExpr
->
defresult
)
{
const_value
=
ExecEvalExpr
((
Node
*
)
caseExpr
->
defresult
,
econtext
,
isNull
,
&
isDone
);
}
else
{
*
isNull
=
true
;
}
return
const_value
;
}
/* ----------------------------------------------------------------
* ExecEvalExpr
*
...
...
@@ -1236,13 +1309,18 @@ ExecEvalExpr(Node *expression,
}
break
;
}
case
T_CaseExpr
:
retDatum
=
(
Datum
)
ExecEvalCase
((
CaseExpr
*
)
expression
,
econtext
,
isNull
);
break
;
default:
elog
(
ERROR
,
"ExecEvalExpr: unknown expression type %d"
,
nodeTag
(
expression
));
break
;
}
return
retDatum
;
}
}
/* ExecEvalExpr() */
/* ----------------------------------------------------------------
* ExecQual / ExecTargetList
...
...
@@ -1642,3 +1720,4 @@ ExecProject(ProjectionInfo *projInfo, bool *isDone)
InvalidBuffer
,
/* tuple has no buffer */
true
);
}
src/backend/nodes/copyfuncs.c
View file @
bedd04a5
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.5
0 1998/11/22 10:48:38 vadim
Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.5
1 1998/12/04 15:33:33 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -943,6 +943,47 @@ _copySubLink(SubLink *from)
return
newnode
;
}
/* ----------------
* _copyCaseExpr
* ----------------
*/
static
CaseExpr
*
_copyCaseExpr
(
CaseExpr
*
from
)
{
CaseExpr
*
newnode
=
makeNode
(
CaseExpr
);
/* ----------------
* copy remainder of node
* ----------------
*/
newnode
->
casetype
=
from
->
casetype
;
Node_Copy
(
from
,
newnode
,
arg
);
Node_Copy
(
from
,
newnode
,
args
);
Node_Copy
(
from
,
newnode
,
defresult
);
return
newnode
;
}
/* ----------------
* _copyCaseWhen
* ----------------
*/
static
CaseWhen
*
_copyCaseWhen
(
CaseWhen
*
from
)
{
CaseWhen
*
newnode
=
makeNode
(
CaseWhen
);
/* ----------------
* copy remainder of node
* ----------------
*/
Node_Copy
(
from
,
newnode
,
expr
);
Node_Copy
(
from
,
newnode
,
result
);
return
newnode
;
}
static
Array
*
_copyArray
(
Array
*
from
)
{
...
...
@@ -1734,6 +1775,12 @@ copyObject(void *from)
case
T_SubLink
:
retval
=
_copySubLink
(
from
);
break
;
case
T_CaseExpr
:
retval
=
_copyCaseExpr
(
from
);
break
;
case
T_CaseWhen
:
retval
=
_copyCaseWhen
(
from
);
break
;
/*
* RELATION NODES
...
...
src/backend/nodes/outfuncs.c
View file @
bedd04a5
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.4
8 1998/11/22 10:48:39 vadim
Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.4
9 1998/12/04 15:33:33 thomas
Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
...
...
@@ -1635,6 +1635,82 @@ _outAConst(StringInfo str, A_Const *node)
return
;
}
static
void
_outConstraint
(
StringInfo
str
,
Constraint
*
node
)
{
char
buf
[
500
];
sprintf
(
buf
,
" %s :type"
,
((
node
->
name
!=
NULL
)
?
node
->
name
:
"<>"
));
appendStringInfo
(
str
,
buf
);
switch
(
node
->
contype
)
{
case
CONSTR_PRIMARY
:
sprintf
(
buf
,
" PRIMARY KEY "
);
appendStringInfo
(
str
,
buf
);
_outNode
(
str
,
node
->
keys
);
break
;
case
CONSTR_CHECK
:
sprintf
(
buf
,
" CHECK "
);
appendStringInfo
(
str
,
buf
);
appendStringInfo
(
str
,
node
->
def
);
break
;
case
CONSTR_DEFAULT
:
sprintf
(
buf
,
" DEFAULT "
);
appendStringInfo
(
str
,
buf
);
appendStringInfo
(
str
,
node
->
def
);
break
;
case
CONSTR_NOTNULL
:
sprintf
(
buf
,
" NOT NULL "
);
appendStringInfo
(
str
,
buf
);
break
;
case
CONSTR_UNIQUE
:
sprintf
(
buf
,
" UNIQUE "
);
appendStringInfo
(
str
,
buf
);
_outNode
(
str
,
node
->
keys
);
break
;
default:
sprintf
(
buf
,
"<unrecognized constraint>"
);
appendStringInfo
(
str
,
buf
);
break
;
}
return
;
}
static
void
_outCaseExpr
(
StringInfo
str
,
CaseExpr
*
node
)
{
char
buf
[
500
];
sprintf
(
buf
,
"CASE "
);
appendStringInfo
(
str
,
buf
);
_outNode
(
str
,
node
->
args
);
sprintf
(
buf
,
" :default "
);
appendStringInfo
(
str
,
buf
);
_outNode
(
str
,
node
->
defresult
);
return
;
}
static
void
_outCaseWhen
(
StringInfo
str
,
CaseWhen
*
node
)
{
char
buf
[
500
];
sprintf
(
buf
,
" :when "
);
appendStringInfo
(
str
,
buf
);
_outNode
(
str
,
node
->
expr
);
sprintf
(
buf
,
" :then "
);
appendStringInfo
(
str
,
buf
);
_outNode
(
str
,
node
->
result
);
return
;
}
/*
* _outNode -
* converts a Node into ascii string and append it to 'str'
...
...
@@ -1861,6 +1937,15 @@ _outNode(StringInfo str, void *obj)
case
T_A_Const
:
_outAConst
(
str
,
obj
);
break
;
case
T_Constraint
:
_outConstraint
(
str
,
obj
);
break
;
case
T_CaseExpr
:
_outCaseExpr
(
str
,
obj
);
break
;
case
T_CaseWhen
:
_outCaseWhen
(
str
,
obj
);
break
;
default:
elog
(
NOTICE
,
"_outNode: don't know how to print type %d "
,
nodeTag
(
obj
));
...
...
src/backend/optimizer/plan/createplan.c
View file @
bedd04a5
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.3
3 1998/11/22 10:48:43 vadim
Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.3
4 1998/12/04 15:34:05 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -437,7 +437,7 @@ create_nestloop_node(JoinPath *best_path,
* used in the inner scan path, so we need only consider the first
* set of qualifications in indxqual.
*
* But there may be more than one clause
s
in this "first set" in the
* But there may be more than one clause in this "first set" in the
* case of multi-column indices. - vadim 03/18/97
*/
...
...
@@ -735,6 +735,11 @@ fix_indxqual_references(Node *clause, Path *index_path)
else
return
clause
;
}
else
if
(
IsA
(
clause
,
CaseExpr
))
{
elog
(
NOTICE
,
"optimizer: fix_indxqual_references sees CaseExpr"
);
return
clause
;
}
else
{
List
*
oldclauses
=
(
List
*
)
clause
;
...
...
src/backend/optimizer/util/clauses.c
View file @
bedd04a5
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.2
5 1998/11/27 19:52:07 vadim
Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.2
6 1998/12/04 15:34:14 thomas
Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
...
...
@@ -306,6 +306,26 @@ make_andclause(List *andclauses)
return
expr
;
}
/*****************************************************************************
* CASE clause functions
*****************************************************************************/
/*
* case_clause--
*
* Returns t iff its argument is a 'case' clause: (CASE { expr }).
*
*/
bool
case_clause
(
Node
*
clause
)
{
return
(
clause
!=
NULL
&&
nodeTag
(
clause
)
==
T_CaseExpr
);
}
/*****************************************************************************
* *
* *
...
...
@@ -540,6 +560,19 @@ fix_opid(Node *clause)
fix_opid
((
Node
*
)
get_leftop
((
Expr
*
)
lfirst
(
lst
)));
}
}
else
if
(
case_clause
(
clause
))
{
List
*
lst
;
fix_opid
(((
CaseExpr
*
)
clause
)
->
defresult
);
/* Run through the WHEN clauses... */
foreach
(
lst
,
((
CaseExpr
*
)
clause
)
->
args
)
{
fix_opid
(((
CaseWhen
*
)
lfirst
(
lst
))
->
expr
);
fix_opid
(((
CaseWhen
*
)
lfirst
(
lst
))
->
result
);
}
}
}
...
...
@@ -577,13 +610,12 @@ fix_opids(List *clauses)
* returned for the value if it is unknown or null.
* END OF OLD OBSOLETE COMMENT.
* NEW COMMENT:
* when defining rules one of the attibutes of the operator can
* when defining rules one of the att
r
ibutes of the operator can
* be a Param node (which is supposed to be treated as a constant).
* However as there is no value specified for a parameter until run time
* this routine used to return "" as value, which
made
'compute_selec'
* this routine used to return "" as value, which
caused
'compute_selec'
* to bomb (because it was expecting a lisp integer and got back a lisp
* string). Now the code returns a plain old good "lispInteger(0)".
*
*/
void
get_relattval
(
Node
*
clause
,
...
...
@@ -787,3 +819,4 @@ CommuteClause(Node *clause)
lfirst
(((
Expr
*
)
clause
)
->
args
)
=
lsecond
(((
Expr
*
)
clause
)
->
args
);
lsecond
(((
Expr
*
)
clause
)
->
args
)
=
temp
;
}
src/backend/optimizer/util/tlist.c
View file @
bedd04a5
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.2
0 1998/09/22 21:48:27 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.2
1 1998/12/04 15:34:15 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -482,7 +482,6 @@ flatten_tlistentry(Node *tlistentry, List *flat_tlist)
flatten_tlistentry
(
lfirst
(
elt
),
flat_tlist
));
return
((
Node
*
)
make_funcclause
((
Func
*
)
expr
->
oper
,
temp_result
));
}
else
if
(
IsA
(
tlistentry
,
Aggreg
))
{
...
...
@@ -509,19 +508,36 @@ flatten_tlistentry(Node *tlistentry, List *flat_tlist)
return
tlistentry
;
}
else
if
(
case_clause
(
tlistentry
))
{
CaseExpr
*
cexpr
=
(
CaseExpr
*
)
tlistentry
;
CaseWhen
*
cwhen
;
List
*
elt
=
NIL
;
foreach
(
elt
,
cexpr
->
args
)
cwhen
=
(
CaseWhen
*
)
lfirst
(
elt
);
cwhen
->
result
=
flatten_tlistentry
(
cwhen
->
result
,
flat_tlist
);
cexpr
->
defresult
=
flatten_tlistentry
(
cexpr
->
defresult
,
flat_tlist
);
return
((
Node
*
)
cexpr
);
}
else
{
Expr
*
expr
=
(
Expr
*
)
tlistentry
;
Expr
*
expr
,
*
final
;
Var
*
left
,
*
right
;
Assert
(
IsA
(
tlistentry
,
Expr
));
Var
*
left
=
(
Var
*
)
flatten_tlistentry
((
Node
*
)
get_leftop
(
expr
),
expr
=
(
Expr
*
)
tlistentry
;
left
=
(
Var
*
)
flatten_tlistentry
((
Node
*
)
get_leftop
(
expr
),
flat_tlist
);
Var
*
right
=
(
Var
*
)
flatten_tlistentry
((
Node
*
)
get_rightop
(
expr
),
right
=
(
Var
*
)
flatten_tlistentry
((
Node
*
)
get_rightop
(
expr
),
flat_tlist
);
Expr
*
final
=
make_opclause
((
Oper
*
)
expr
->
oper
,
left
,
right
);
Assert
(
IsA
(
tlistentry
,
Expr
)
);
final
=
make_opclause
((
Oper
*
)
expr
->
oper
,
left
,
right
);
final
->
opType
=
expr
->
opType
;
final
->
typeOid
=
expr
->
typeOid
;
return
(
Node
*
)
final
;
}
}
...
...
src/backend/optimizer/util/var.c
View file @
bedd04a5
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.1
3 1998/09/01 03:24:00 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.1
4 1998/12/04 15:34:15 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -137,6 +137,21 @@ contain_var_clause(Node *clause)
else
if
(
is_opclause
(
clause
))
return
(
contain_var_clause
((
Node
*
)
get_leftop
((
Expr
*
)
clause
))
||
contain_var_clause
((
Node
*
)
get_rightop
((
Expr
*
)
clause
)));
else
if
(
case_clause
(
clause
))
{
List
*
args
;
CaseWhen
*
when
;
foreach
(
args
,
((
CaseExpr
*
)
clause
)
->
args
)
{
when
=
lfirst
(
args
);
if
(
contain_var_clause
(
when
->
expr
))
return
TRUE
;
if
(
contain_var_clause
(
when
->
result
))
return
TRUE
;
}
return
(
contain_var_clause
(((
CaseExpr
*
)
clause
)
->
defresult
));
}
return
FALSE
;
}
...
...
@@ -199,6 +214,18 @@ pull_var_clause(Node *clause)
else
if
(
is_opclause
(
clause
))
retval
=
nconc
(
pull_var_clause
((
Node
*
)
get_leftop
((
Expr
*
)
clause
)),
pull_var_clause
((
Node
*
)
get_rightop
((
Expr
*
)
clause
)));
else
if
(
case_clause
(
clause
))
{
List
*
temp
;
foreach
(
temp
,
((
CaseExpr
*
)
clause
)
->
args
)
{
retval
=
nconc
(
retval
,
pull_var_clause
(((
CaseWhen
*
)
lfirst
(
temp
))
->
expr
));
retval
=
nconc
(
retval
,
pull_var_clause
(((
CaseWhen
*
)
lfirst
(
temp
))
->
result
));
}
retval
=
nconc
(
retval
,
pull_var_clause
(((
CaseExpr
*
)
clause
)
->
defresult
));
}
else
retval
=
NIL
;
...
...
src/backend/parser/analyze.c
View file @
bedd04a5
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.
89 1998/10/28 16:06:54 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.
90 1998/12/04 15:34:28 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -396,7 +396,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
*/
if
((
qry
->
hasAggs
==
false
)
&&
(
qry
->
havingQual
!=
NULL
))
{
elog
(
ERROR
,
"
This is not a valid having query!
"
);
elog
(
ERROR
,
"
SELECT/HAVING requires aggregates to be valid
"
);
return
(
Query
*
)
NIL
;
}
...
...
@@ -621,7 +621,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
break
;
default:
elog
(
ERROR
,
"parser:
internal error; unrecognized constraint
"
,
NULL
);
elog
(
ERROR
,
"parser:
unrecognized constraint (internal error)
"
,
NULL
);
break
;
}
clist
=
lnext
(
clist
);
...
...
@@ -653,16 +653,16 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
case
CONSTR_NOTNULL
:
case
CONSTR_DEFAULT
:
elog
(
ERROR
,
"parser: i
nternal error; illegal context for constraint
"
,
NULL
);
elog
(
ERROR
,
"parser: i
llegal context for constraint (internal error)
"
,
NULL
);
break
;
default:
elog
(
ERROR
,
"parser:
internal error; unrecognized constraint
"
,
NULL
);
elog
(
ERROR
,
"parser:
unrecognized constraint (internal error)
"
,
NULL
);
break
;
}
break
;
default:
elog
(
ERROR
,
"parser:
internal error; unrecognized node
"
,
NULL
);
elog
(
ERROR
,
"parser:
unrecognized node (internal error)
"
,
NULL
);
}
elements
=
lnext
(
elements
);
...
...
@@ -684,7 +684,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
{
constraint
=
lfirst
(
dlist
);
if
(
nodeTag
(
constraint
)
!=
T_Constraint
)
elog
(
ERROR
,
"parser:
internal error; unrecognized deferred node
"
,
NULL
);
elog
(
ERROR
,
"parser:
unrecognized deferred node (internal error)
"
,
NULL
);
if
(
constraint
->
contype
==
CONSTR_PRIMARY
)
{
...
...
@@ -695,7 +695,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
have_pkey
=
TRUE
;
}
else
if
(
constraint
->
contype
!=
CONSTR_UNIQUE
)
elog
(
ERROR
,
"parser:
internal error; unrecognized deferred constraint
"
,
NULL
);
elog
(
ERROR
,
"parser:
unrecognized deferred constraint (internal error)
"
,
NULL
);
index
=
makeNode
(
IndexStmt
);
...
...
@@ -735,7 +735,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
columns
=
lnext
(
columns
);
}
if
(
column
==
NULL
)
elog
(
ERROR
,
"
parser:
column '%s' in key does not exist"
,
key
->
name
);
elog
(
ERROR
,
"
CREATE TABLE
column '%s' in key does not exist"
,
key
->
name
);
if
(
constraint
->
contype
==
CONSTR_PRIMARY
)
column
->
is_not_null
=
TRUE
;
...
...
@@ -753,7 +753,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
}
if
(
index
->
idxname
==
NULL
)
elog
(
ERROR
,
"
parser:
unable to construct implicit index for table %s"
elog
(
ERROR
,
"
CREATE TABLE
unable to construct implicit index for table %s"
"; name too long"
,
stmt
->
relname
);
else
elog
(
NOTICE
,
"CREATE TABLE/%s will create implicit index %s for table %s"
,
...
...
@@ -918,8 +918,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
/*
* The havingQual has a similar meaning as "qual" in the where
* statement. So we can easily use the code from the "where clause"
* with some additional traversals done in
* .../optimizer/plan/planner.c
* with some additional traversals done in optimizer/plan/planner.c
*/
qry
->
havingQual
=
transformWhereClause
(
pstate
,
stmt
->
havingClause
);
...
...
@@ -955,7 +954,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
*/
if
((
qry
->
hasAggs
==
false
)
&&
(
qry
->
havingQual
!=
NULL
))
{
elog
(
ERROR
,
"
This is not a valid having query!
"
);
elog
(
ERROR
,
"
SELECT/HAVING requires aggregates to be valid
"
);
return
(
Query
*
)
NIL
;
}
...
...
src/backend/parser/gram.y
View file @
bedd04a5
...
...
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.3
7 1998/10/14 15:56:43
thomas Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.3
8 1998/12/04 15:34:29
thomas Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
...
...
@@ -208,6 +208,8 @@ Oid param_type(int t); /* used in parse_expr.c */
%type <list> row_descriptor, row_list, c_list, c_expr
%type <node> row_expr
%type <str> row_op
%type <node> case_expr, case_arg, when_clause, case_default
%type <list> when_clause_list
%type <ival> sub_type
%type <list> OptCreateAs, CreateAsList
%type <node> CreateAsElement
...
...
@@ -259,26 +261,27 @@ Oid param_type(int t); /* used in parse_expr.c */
/* Keywords (in SQL92 reserved words) */
%token ABSOLUTE, ACTION, ADD, ALL, ALTER, AND, ANY, AS, ASC,
BEGIN_TRANS, BETWEEN, BOTH, BY,
CASCADE, CAST, CHAR, CHARACTER, CHECK, CLOSE, COLLATE, COLUMN, COMMIT,
CASCADE, CASE, CAST, CHAR, CHARACTER, CHECK, CLOSE,
COALESCE, COLLATE, COLUMN, COMMIT,
CONSTRAINT, CREATE, CROSS, CURRENT, CURRENT_DATE, CURRENT_TIME,
CURRENT_TIMESTAMP, CURRENT_USER, CURSOR,
DAY_P, DECIMAL, DECLARE, DEFAULT, DELETE, DESC, DISTINCT, DOUBLE, DROP,
END_TRANS, EXECUTE, EXISTS, EXTRACT,
E
LSE, E
ND_TRANS, EXECUTE, EXISTS, EXTRACT,
FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
GRANT, GROUP, HAVING, HOUR_P,
IN, INNER_P, INSENSITIVE, INSERT, INTERVAL, INTO, IS,
JOIN, KEY, LANGUAGE, LEADING, LEFT, LIKE, LOCAL,
MATCH, MINUTE_P, MONTH_P, NAMES,
NATIONAL, NATURAL, NCHAR, NEXT, NO, NOT, NULL_P, NUMERIC,
NATIONAL, NATURAL, NCHAR, NEXT, NO, NOT, NULL
IF, NULL
_P, NUMERIC,
OF, ON, ONLY, OPTION, OR, ORDER, OUTER_P,
PARTIAL, POSITION, PRECISION, PRIMARY, PRIOR, PRIVILEGES, PROCEDURE, PUBLIC,
READ, REFERENCES, RELATIVE, REVOKE, RIGHT, ROLLBACK,
SCROLL, SECOND_P, SELECT, SET, SUBSTRING,
TABLE, TIME, TIMESTAMP, TIMEZONE_HOUR, TIMEZONE_MINUTE,
TABLE, T
HEN, T
IME, TIMESTAMP, TIMEZONE_HOUR, TIMEZONE_MINUTE,
TO, TRAILING, TRANSACTION, TRIM, TRUE_P,
UNION, UNIQUE, UPDATE, USER, USING,
VALUES, VARCHAR, VARYING, VIEW,
WHERE, WITH, WORK, YEAR_P, ZONE
WHE
N, WHE
RE, WITH, WORK, YEAR_P, ZONE
/* Keywords (in SQL3 reserved words) */
%token TRIGGER
...
...
@@ -2861,7 +2864,7 @@ opt_array_bounds: '[' ']' nest_array_bounds
{ $$ = lcons(makeInteger(-1), $3); }
| '[' Iconst ']' nest_array_bounds
{ $$ = lcons(makeInteger($2), $4); }
| /*
EMPTY
*/
| /*
EMPTY
*/
{ $$ = NIL; }
;
...
...
@@ -3276,14 +3279,14 @@ sub_type: ANY { $$ = ANY_SUBLINK; }
| ALL { $$ = ALL_SUBLINK; }
;
/*
/*
General expressions
* This is the heart of the expression syntax.
* Note that the BETWEEN clause looks similar to a boolean expression
* and so we must define b_expr which is almost the same as a_expr
* but without the boolean expressions.
* All operations are allowed in a BETWEEN clause if surrounded by parens.
* All operations/expressions are allowed in a BETWEEN clause
* if surrounded by parens.
*/
a_expr: attr opt_indirection
{
$1->indirection = $2;
...
...
@@ -3895,14 +3898,15 @@ a_expr: attr opt_indirection
{ $$ = makeA_Expr(OR, NULL, $1, $3); }
| NOT a_expr
{ $$ = makeA_Expr(NOT, NULL, NULL, $2); }
| case_expr
{ $$ = $1; }
;
/*
/*
Restricted expressions
* b_expr is a subset of the complete expression syntax
* defined by a_expr. b_expr is used in BETWEEN clauses
* to eliminate parser ambiguities stemming from the AND keyword.
*/
b_expr: attr opt_indirection
{
$1->indirection = $2;
...
...
@@ -4150,7 +4154,7 @@ opt_indirection: '[' a_expr ']' opt_indirection
ai->uidx = $4;
$$ = lcons(ai, $6);
}
| /*
EMPTY
*/
| /*
EMPTY
*/
{ $$ = NIL; }
;
...
...
@@ -4169,7 +4173,7 @@ extract_list: extract_arg FROM a_expr
n->val.val.str = $1;
$$ = lappend(lcons((Node *)n,NIL), $3);
}
| /*
EMPTY
*/
| /*
EMPTY
*/
{ $$ = NIL; }
;
...
...
@@ -4180,7 +4184,7 @@ extract_arg: datetime { $$ = $1; }
position_list: position_expr IN position_expr
{ $$ = makeList($3, $1, -1); }
| /*
EMPTY
*/
| /*
EMPTY
*/
{ $$ = NIL; }
;
...
...
@@ -4314,13 +4318,13 @@ substr_list: expr_list substr_from substr_for
{
$$ = nconc(nconc($1,$2),$3);
}
| /*
EMPTY
*/
| /*
EMPTY
*/
{ $$ = NIL; }
;
substr_from: FROM expr_list
{ $$ = $2; }
| /*
EMPTY
*/
| /*
EMPTY
*/
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Integer;
...
...
@@ -4331,7 +4335,7 @@ substr_from: FROM expr_list
substr_for: FOR expr_list
{ $$ = $2; }
| /*
EMPTY
*/
| /*
EMPTY
*/
{ $$ = NIL; }
;
...
...
@@ -4379,6 +4383,94 @@ not_in_expr_nodes: AexprConst
}
;
/* Case clause
* Define SQL92-style case clause.
* Allow all four forms described in the standard:
* - Full specification
* CASE WHEN a = b THEN c ... ELSE d END
* - Implicit argument
* CASE a WHEN b THEN c ... ELSE d END
* - Conditional NULL
* NULLIF(x,y)
* same as CASE WHEN x = y THEN NULL ELSE x END
* - Conditional substitution from list, use first non-null argument
* COALESCE(a,b,...)
* same as CASE WHEN a IS NOT NULL THEN a WHEN b IS NOT NULL THEN b ... END
* - thomas 1998-11-09
*/
case_expr: CASE case_arg when_clause_list case_default END_TRANS
{
CaseExpr *c = makeNode(CaseExpr);
c->arg = $2;
c->args = $3;
c->defresult = $4;
$$ = (Node *)c;
}
| NULLIF '(' a_expr ',' a_expr ')'
{
CaseExpr *c = makeNode(CaseExpr);
CaseWhen *w = makeNode(CaseWhen);
c->args = lcons(w, NIL);
c->defresult = $3;
w->expr = makeA_Expr(OP, "=", $3, $5);
$$ = (Node *)c;
elog(NOTICE,"NULLIF() not yet fully implemented");
}
| COALESCE '(' expr_list ')'
{
CaseExpr *c = makeNode(CaseExpr);
CaseWhen *w;
List *l;
foreach (l,$3)
{
w = makeNode(CaseWhen);
w->expr = makeA_Expr(NOTNULL, NULL, lfirst(l), NULL);
w->result = lfirst(l);
c->args = lappend(c->args, w);
}
$$ = (Node *)c;
elog(NOTICE,"COALESCE() not yet fully implemented");
}
;
when_clause_list: when_clause_list when_clause
{ $$ = lappend($1, $2); }
| when_clause
{ $$ = lcons($1, NIL); }
;
when_clause: WHEN a_expr THEN a_expr_or_null
{
CaseWhen *w = makeNode(CaseWhen);
w->expr = $2;
w->result = $4;
$$ = (Node *)w;
}
;
case_default: ELSE a_expr_or_null { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; }
;
case_arg: attr opt_indirection
{
$1->indirection = $2;
$$ = (Node *)$1;
}
| ColId
{
/* could be a column name or a relation_name */
Ident *n = makeNode(Ident);
n->name = $1;
n->indirection = NULL;
$$ = (Node *)n;
}
| /*EMPTY*/
{ $$ = NULL; }
;
attr: relation_name '.' attrs
{
$$ = makeNode(Attr);
...
...
@@ -4512,7 +4604,7 @@ res_target_el2: a_expr_or_null AS ColLabel
;
opt_id: ColId { $$ = $1; }
| /*
EMPTY */
{ $$ = NULL; }
| /*
EMPTY*/
{ $$ = NULL; }
;
relation_name: SpecialRuleRelation
...
...
@@ -4723,12 +4815,16 @@ ColLabel: ColId { $$ = $1; }
| ABORT_TRANS { $$ = "abort"; }
| ANALYZE { $$ = "analyze"; }
| BINARY { $$ = "binary"; }
| CASE { $$ = "case"; }
| CLUSTER { $$ = "cluster"; }
| COALESCE { $$ = "coalesce"; }
| CONSTRAINT { $$ = "constraint"; }
| COPY { $$ = "copy"; }
| CROSS { $$ = "cross"; }
| CURRENT { $$ = "current"; }
| DO { $$ = "do"; }
| ELSE { $$ = "else"; }
| END_TRANS { $$ = "end"; }
| EXPLAIN { $$ = "explain"; }
| EXTEND { $$ = "extend"; }
| FALSE_P { $$ = "false"; }
...
...
@@ -4740,6 +4836,7 @@ ColLabel: ColId { $$ = $1; }
| MOVE { $$ = "move"; }
| NEW { $$ = "new"; }
| NONE { $$ = "none"; }
| NULLIF { $$ = "nullif"; }
| ORDER { $$ = "order"; }
| POSITION { $$ = "position"; }
| PRECISION { $$ = "precision"; }
...
...
@@ -4747,10 +4844,12 @@ ColLabel: ColId { $$ = $1; }
| SETOF { $$ = "setof"; }
| SHOW { $$ = "show"; }
| TABLE { $$ = "table"; }
| THEN { $$ = "then"; }
| TRANSACTION { $$ = "transaction"; }
| TRUE_P { $$ = "true"; }
| VACUUM { $$ = "vacuum"; }
| VERBOSE { $$ = "verbose"; }
| WHEN { $$ = "when"; }
;
SpecialRuleRelation: CURRENT
...
...
src/backend/parser/keywords.c
View file @
bedd04a5
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.4
8 1998/10/18 23:30:17 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.4
9 1998/12/04 15:34:29 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -51,12 +51,14 @@ static ScanKeyword ScanKeywords[] = {
{
"by"
,
BY
},
{
"cache"
,
CACHE
},
{
"cascade"
,
CASCADE
},
{
"case"
,
CASE
},
{
"cast"
,
CAST
},
{
"char"
,
CHAR
},
{
"character"
,
CHARACTER
},
{
"check"
,
CHECK
},
{
"close"
,
CLOSE
},
{
"cluster"
,
CLUSTER
},
{
"coalesce"
,
COALESCE
},
{
"collate"
,
COLLATE
},
{
"column"
,
COLUMN
},
{
"commit"
,
COMMIT
},
...
...
@@ -88,6 +90,7 @@ static ScanKeyword ScanKeywords[] = {
{
"double"
,
DOUBLE
},
{
"drop"
,
DROP
},
{
"each"
,
EACH
},
{
"else"
,
ELSE
},
{
"encoding"
,
ENCODING
},
{
"end"
,
END_TRANS
},
{
"execute"
,
EXECUTE
},
...
...
@@ -154,6 +157,7 @@ static ScanKeyword ScanKeywords[] = {
{
"notify"
,
NOTIFY
},
{
"notnull"
,
NOTNULL
},
{
"null"
,
NULL_P
},
{
"nullif"
,
NULLIF
},
{
"numeric"
,
NUMERIC
},
{
"of"
,
OF
},
{
"oids"
,
OIDS
},
...
...
@@ -201,6 +205,7 @@ static ScanKeyword ScanKeywords[] = {
{
"stdout"
,
STDOUT
},
{
"substring"
,
SUBSTRING
},
{
"table"
,
TABLE
},
{
"then"
,
THEN
},
{
"time"
,
TIME
},
{
"timestamp"
,
TIMESTAMP
},
{
"timezone_hour"
,
TIMEZONE_HOUR
},
...
...
@@ -228,6 +233,7 @@ static ScanKeyword ScanKeywords[] = {
{
"verbose"
,
VERBOSE
},
{
"version"
,
VERSION
},
{
"view"
,
VIEW
},
{
"when"
,
WHEN
},
{
"where"
,
WHERE
},
{
"with"
,
WITH
},
{
"work"
,
WORK
},
...
...
src/backend/parser/parse_coerce.c
View file @
bedd04a5
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.
9 1998/10/22 13:50:54 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.
10 1998/12/04 15:34:30 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -342,7 +342,7 @@ TypeCategory(Oid inType)
/* IsPreferredType()
*
Assign a category to the specified OID
.
*
Check if this type is a preferred type
.
*/
bool
IsPreferredType
(
CATEGORY
category
,
Oid
type
)
...
...
src/backend/parser/parse_expr.c
View file @
bedd04a5
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.3
6 1998/10/02 16:23:05 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.3
7 1998/12/04 15:34:30 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -29,6 +29,7 @@
#include "parser/parse_node.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
#include "parser/parse_coerce.h"
#include "utils/builtins.h"
static
Node
*
parser_typecast
(
Value
*
expr
,
TypeName
*
typename
,
int32
atttypmod
);
...
...
@@ -265,7 +266,9 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
foreach
(
args
,
fn
->
args
)
lfirst
(
args
)
=
transformExpr
(
pstate
,
(
Node
*
)
lfirst
(
args
),
precedence
);
result
=
ParseFuncOrColumn
(
pstate
,
fn
->
funcname
,
fn
->
args
,
&
pstate
->
p_last_resno
,
fn
->
funcname
,
fn
->
args
,
&
pstate
->
p_last_resno
,
precedence
);
break
;
}
...
...
@@ -332,6 +335,146 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
break
;
}
case
T_CaseExpr
:
{
CaseExpr
*
c
=
(
CaseExpr
*
)
expr
;
CaseWhen
*
w
;
List
*
args
;
Oid
ptype
;
CATEGORY
pcategory
;
/* transform the list of arguments */
foreach
(
args
,
c
->
args
)
{
w
=
lfirst
(
args
);
/* shorthand form was specified, so expand... */
if
(
c
->
arg
!=
NULL
)
{
A_Expr
*
a
=
makeNode
(
A_Expr
);
a
->
oper
=
OP
;
a
->
opname
=
"="
;
a
->
lexpr
=
c
->
arg
;
a
->
rexpr
=
w
->
expr
;
w
->
expr
=
(
Node
*
)
a
;
}
lfirst
(
args
)
=
transformExpr
(
pstate
,
(
Node
*
)
w
,
precedence
);
if
(
w
->
result
==
NULL
)
{
A_Const
*
n
=
makeNode
(
A_Const
);
n
->
val
.
type
=
T_Null
;
w
->
result
=
(
Node
*
)
n
;
}
}
if
(
c
->
defresult
==
NULL
)
{
A_Const
*
n
=
makeNode
(
A_Const
);
n
->
val
.
type
=
T_Null
;
c
->
defresult
=
(
Node
*
)
n
;
}
c
->
defresult
=
transformExpr
(
pstate
,
(
Node
*
)
c
->
defresult
,
precedence
);
c
->
casetype
=
exprType
(
c
->
defresult
);
/* now check types across result clauses... */
ptype
=
c
->
casetype
;
pcategory
=
TypeCategory
(
ptype
);
foreach
(
args
,
c
->
args
)
{
Oid
wtype
;
w
=
lfirst
(
args
);
wtype
=
exprType
(
w
->
result
);
/* move on to next one if no new information... */
if
(
wtype
&&
(
wtype
!=
UNKNOWNOID
)
&&
(
wtype
!=
ptype
))
{
/* so far, only nulls so take anything... */
if
(
!
ptype
)
{
ptype
=
wtype
;
pcategory
=
TypeCategory
(
ptype
);
}
/* both types in different categories? then not much hope... */
else
if
((
TypeCategory
(
wtype
)
!=
pcategory
)
||
((
TypeCategory
(
wtype
)
==
USER_TYPE
)
&&
(
TypeCategory
(
c
->
casetype
)
==
USER_TYPE
)))
{
elog
(
ERROR
,
"CASE/WHEN types '%s' and '%s' not matched"
,
typeidTypeName
(
c
->
casetype
),
typeidTypeName
(
wtype
));
}
/* new one is preferred and can convert? then take it... */
else
if
(
IsPreferredType
(
pcategory
,
wtype
)
&&
can_coerce_type
(
1
,
&
ptype
,
&
wtype
))
{
ptype
=
wtype
;
pcategory
=
TypeCategory
(
ptype
);
}
}
}
/* Convert default clause, if necessary */
if
(
c
->
casetype
!=
ptype
)
{
if
(
!
c
->
casetype
)
{
/* default clause is NULL,
* so assign preferred type from WHEN clauses... */
c
->
casetype
=
ptype
;
}
else
if
(
can_coerce_type
(
1
,
&
c
->
casetype
,
&
ptype
))
{
c
->
defresult
=
coerce_type
(
pstate
,
c
->
defresult
,
c
->
casetype
,
ptype
);
c
->
casetype
=
ptype
;
}
else
{
elog
(
ERROR
,
"CASE/ELSE unable to convert to type %s"
,
typeidTypeName
(
ptype
));
}
}
/* Convert when clauses, if not null and if necessary */
foreach
(
args
,
c
->
args
)
{
Oid
wtype
;
w
=
lfirst
(
args
);
wtype
=
exprType
(
w
->
result
);
/* only bother with conversion if not NULL and different type... */
if
(
wtype
&&
(
wtype
!=
ptype
))
{
if
(
can_coerce_type
(
1
,
&
wtype
,
&
ptype
))
{
w
->
result
=
coerce_type
(
pstate
,
w
->
result
,
wtype
,
ptype
);
}
else
{
elog
(
ERROR
,
"CASE/WHEN unable to convert to type %s"
,
typeidTypeName
(
ptype
));
}
}
}
result
=
expr
;
break
;
}
case
T_CaseWhen
:
{
CaseWhen
*
w
=
(
CaseWhen
*
)
expr
;
w
->
expr
=
transformExpr
(
pstate
,
(
Node
*
)
w
->
expr
,
precedence
);
if
(
exprType
(
w
->
expr
)
!=
BOOLOID
)
elog
(
ERROR
,
"WHEN clause must have a boolean result"
);
/* result is NULL for NULLIF() construct - thomas 1998-11-11 */
if
(
w
->
result
!=
NULL
)
w
->
result
=
transformExpr
(
pstate
,
(
Node
*
)
w
->
result
,
precedence
);
result
=
expr
;
break
;
}
/* Some nodes do _not_ come from the original parse tree,
* but result from parser transformation in this phase.
* At least one construct (BETWEEN/AND) puts the same nodes
...
...
@@ -423,6 +566,9 @@ exprType(Node *expr)
{
Oid
type
=
(
Oid
)
0
;
if
(
!
expr
)
return
type
;
switch
(
nodeTag
(
expr
))
{
case
T_Func
:
...
...
@@ -452,6 +598,12 @@ exprType(Node *expr)
case
T_SubLink
:
type
=
BOOLOID
;
break
;
case
T_CaseExpr
:
type
=
((
CaseExpr
*
)
expr
)
->
casetype
;
break
;
case
T_CaseWhen
:
type
=
exprType
(((
CaseWhen
*
)
expr
)
->
result
);
break
;
case
T_Ident
:
/* is this right? */
type
=
UNKNOWNOID
;
...
...
src/backend/parser/parse_target.c
View file @
bedd04a5
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.3
0 1998/10/08 18:29:47 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.3
1 1998/12/04 15:34:30 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -39,6 +39,9 @@ static Node *SizeTargetExpr(ParseState *pstate,
Oid
attrtype
,
int32
attrtypmod
);
static
TargetEntry
*
MakeTargetEntryCase
(
ParseState
*
pstate
,
ResTarget
*
res
);
/* MakeTargetEntryIdent()
* Transforms an Ident Node to a Target Entry
...
...
@@ -53,11 +56,7 @@ static Node *SizeTargetExpr(ParseState *pstate,
*/
TargetEntry
*
MakeTargetEntryIdent
(
ParseState
*
pstate
,
#if FALSE
Ident
*
ident
,
#else
Node
*
node
,
#endif
char
**
resname
,
char
*
refname
,
char
*
colname
,
...
...
@@ -77,7 +76,7 @@ MakeTargetEntryIdent(ParseState *pstate,
pstate
->
p_insert_columns
=
lnext
(
pstate
->
p_insert_columns
);
}
else
elog
(
ERROR
,
"
insert:
more expressions than target columns"
);
elog
(
ERROR
,
"
INSERT has
more expressions than target columns"
);
}
if
(
pstate
->
p_is_insert
||
pstate
->
p_is_update
)
...
...
@@ -105,7 +104,7 @@ MakeTargetEntryIdent(ParseState *pstate,
{
rte
=
colnameRangeTableEntry
(
pstate
,
colname
);
if
(
rte
==
(
RangeTblEntry
*
)
NULL
)
elog
(
ERROR
,
"
a
ttribute %s not found"
,
colname
);
elog
(
ERROR
,
"
A
ttribute %s not found"
,
colname
);
refname
=
rte
->
refname
;
}
...
...
@@ -129,14 +128,9 @@ MakeTargetEntryIdent(ParseState *pstate,
}
else
{
#if TRUE
elog
(
ERROR
,
"Unable to convert %s to %s for column %s"
,
typeidTypeName
(
attrtype_id
),
typeidTypeName
(
attrtype_target
),
target_colname
);
#else
elog
(
ERROR
,
"Type or size of %s(%d) does not match target column %s(%d)"
,
colname
,
attrtypmod
,
target_colname
,
attrtypmod_target
);
#endif
}
}
}
...
...
@@ -152,11 +146,7 @@ MakeTargetEntryIdent(ParseState *pstate,
name
=
((
*
resname
!=
NULL
)
?
*
resname
:
colname
);
#if FALSE
expr
=
transformIdent
(
pstate
,
(
Node
*
)
ident
,
EXPR_COLUMN_FIRST
);
#else
expr
=
transformExpr
(
pstate
,
node
,
EXPR_COLUMN_FIRST
);
#endif
attrtype_target
=
exprType
(
expr
);
if
(
nodeTag
(
expr
)
==
T_Var
)
...
...
@@ -187,7 +177,7 @@ MakeTargetEntryIdent(ParseState *pstate,
* - thomas 1998-05-08
*
* Added resjunk flag and made extern so that it can be use by GROUP/
* ORDER BY a function or exp
er
sion not in the target_list
* ORDER BY a function or exp
res
sion not in the target_list
* - daveh@insightdist.com 1998-07-31
*/
TargetEntry
*
...
...
@@ -207,7 +197,7 @@ MakeTargetEntryExpr(ParseState *pstate,
Resdom
*
resnode
;
if
(
expr
==
NULL
)
elog
(
ERROR
,
"
MakeTargetEntryExpr: invalid use of NULL expression
"
);
elog
(
ERROR
,
"
Invalid use of NULL expression (internal error)
"
);
type_id
=
exprType
(
expr
);
if
(
nodeTag
(
expr
)
==
T_Var
)
...
...
@@ -251,9 +241,9 @@ MakeTargetEntryExpr(ParseState *pstate,
expr
=
CoerceTargetExpr
(
pstate
,
expr
,
type_id
,
typelem
);
if
(
!
HeapTupleIsValid
(
expr
))
elog
(
ERROR
,
"
parser: a
ttribute '%s' is of type '%s'"
elog
(
ERROR
,
"
A
ttribute '%s' is of type '%s'"
" but expression is of type '%s'"
"
\n\t
You will need to rewrite or cast the expression"
,
"
\n\t
You will need to rewrite or cast the expression"
,
colname
,
typeidTypeName
(
attrtype
),
typeidTypeName
(
type_id
));
...
...
@@ -323,6 +313,45 @@ MakeTargetEntryExpr(ParseState *pstate,
return
makeTargetEntry
(
resnode
,
expr
);
}
/* MakeTargetEntryExpr() */
/*
* MakeTargetEntryCase()
* Make a TargetEntry from a case node.
*/
static
TargetEntry
*
MakeTargetEntryCase
(
ParseState
*
pstate
,
ResTarget
*
res
)
{
TargetEntry
*
tent
;
CaseExpr
*
expr
;
Resdom
*
resnode
;
int
resdomno
;
Oid
type_id
;
int32
type_mod
;
expr
=
(
CaseExpr
*
)
transformExpr
(
pstate
,
(
Node
*
)
res
->
val
,
EXPR_COLUMN_FIRST
);
type_id
=
expr
->
casetype
;
type_mod
=
-
1
;
handleTargetColname
(
pstate
,
&
res
->
name
,
NULL
,
NULL
);
if
(
res
->
name
==
NULL
)
res
->
name
=
FigureColname
((
Node
*
)
expr
,
res
->
val
);
resdomno
=
pstate
->
p_last_resno
++
;
resnode
=
makeResdom
((
AttrNumber
)
resdomno
,
(
Oid
)
type_id
,
type_mod
,
res
->
name
,
(
Index
)
0
,
(
Oid
)
0
,
0
);
tent
=
makeNode
(
TargetEntry
);
tent
->
resdom
=
resnode
;
tent
->
expr
=
(
Node
*
)
expr
;
return
tent
;
}
/* MakeTargetEntryCase() */
/*
* MakeTargetEntryComplex()
* Make a TargetEntry from a complex node.
...
...
@@ -351,7 +380,7 @@ MakeTargetEntryComplex(ParseState *pstate,
Value
*
constval
;
if
(
exprType
(
expr
)
!=
UNKNOWNOID
||
!
IsA
(
expr
,
Const
))
elog
(
ERROR
,
"
yyparse: string constant expected
"
);
elog
(
ERROR
,
"
String constant expected (internal error)
"
);
val
=
(
char
*
)
textout
((
struct
varlena
*
)
((
Const
*
)
expr
)
->
constvalue
);
...
...
@@ -376,7 +405,7 @@ MakeTargetEntryComplex(ParseState *pstate,
else
lindx
[
i
]
=
1
;
if
(
lindx
[
i
]
>
uindx
[
i
])
elog
(
ERROR
,
"
yyparse: l
ower index cannot be greater than upper index"
);
elog
(
ERROR
,
"
L
ower index cannot be greater than upper index"
);
sprintf
(
str
,
"[%d:%d]"
,
lindx
[
i
],
uindx
[
i
]);
str
+=
strlen
(
str
);
...
...
@@ -388,7 +417,7 @@ MakeTargetEntryComplex(ParseState *pstate,
resdomno
=
attnameAttNum
(
rd
,
res
->
name
);
ndims
=
attnumAttNelems
(
rd
,
resdomno
);
if
(
i
!=
ndims
)
elog
(
ERROR
,
"
yyparse: a
rray dimensions do not match"
);
elog
(
ERROR
,
"
A
rray dimensions do not match"
);
constval
=
makeNode
(
Value
);
constval
->
type
=
T_String
;
...
...
@@ -400,9 +429,9 @@ MakeTargetEntryComplex(ParseState *pstate,
}
else
{
char
*
colname
=
res
->
name
;
/* this is not an array assignment */
char
*
colname
=
res
->
name
;
if
(
colname
==
NULL
)
{
...
...
@@ -540,6 +569,11 @@ transformTargetList(ParseState *pstate, List *targetlist)
tent
=
MakeTargetEntryComplex
(
pstate
,
res
);
break
;
}
case
T_CaseExpr
:
{
tent
=
MakeTargetEntryCase
(
pstate
,
res
);
break
;
}
case
T_Attr
:
{
bool
expand_star
=
false
;
...
...
@@ -604,7 +638,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
}
default:
/* internal error */
elog
(
ERROR
,
"
internal error: do not know how to transform targetlist
"
);
elog
(
ERROR
,
"
Unable to transform targetlist (internal error)
"
);
break
;
}
...
...
@@ -788,7 +822,7 @@ ExpandAllTables(ParseState *pstate)
/* this should not happen */
if
(
rtable
==
NULL
)
elog
(
ERROR
,
"
cannot expand: null p_rtable
"
);
elog
(
ERROR
,
"
Cannot expand tables; null p_rtable (internal error)
"
);
/*
* go through the range table and make a list of range table entries
...
...
@@ -838,7 +872,7 @@ FigureColname(Node *expr, Node *resval)
{
switch
(
nodeTag
(
expr
))
{
case
T_Aggreg
:
case
T_Aggreg
:
return
(
char
*
)
((
Aggreg
*
)
expr
)
->
aggname
;
case
T_Expr
:
if
(((
Expr
*
)
expr
)
->
opType
==
FUNC_EXPR
)
...
...
src/backend/rewrite/rewriteHandler.c
View file @
bedd04a5
...
...
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.2
5 1998/10/21 16:21:24 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.2
6 1998/12/04 15:34:36 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -39,7 +39,6 @@
#include "catalog/pg_type.h"
static
RewriteInfo
*
gatherRewriteMeta
(
Query
*
parsetree
,
Query
*
rule_action
,
Node
*
rule_qual
,
...
...
@@ -55,17 +54,6 @@ static SubLink *modifyAggregMakeSublink(Expr *origexp, Query *parsetree);
static
void
modifyAggregQual
(
Node
**
nodePtr
,
Query
*
parsetree
);
static
Query
*
fireRIRrules
(
Query
*
parsetree
);
...
...
@@ -293,6 +281,46 @@ rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
}
break
;
case
T_CaseExpr
:
{
CaseExpr
*
exp
=
(
CaseExpr
*
)
node
;
if
(
rangeTableEntry_used
(
(
Node
*
)(
exp
->
args
),
rt_index
,
sublevels_up
))
return
TRUE
;
if
(
rangeTableEntry_used
(
(
Node
*
)(
exp
->
defresult
),
rt_index
,
sublevels_up
))
return
TRUE
;
return
FALSE
;
}
break
;
case
T_CaseWhen
:
{
CaseWhen
*
when
=
(
CaseWhen
*
)
node
;
if
(
rangeTableEntry_used
(
(
Node
*
)(
when
->
expr
),
rt_index
,
sublevels_up
))
return
TRUE
;
if
(
rangeTableEntry_used
(
(
Node
*
)(
when
->
result
),
rt_index
,
sublevels_up
))
return
TRUE
;
return
FALSE
;
}
break
;
case
T_Query
:
{
Query
*
qry
=
(
Query
*
)
node
;
...
...
@@ -1055,10 +1083,12 @@ modifyAggregMakeSublink(Expr *origexp, Query *parsetree)
Expr
*
exp
=
copyObject
(
origexp
);
if
(
nodeTag
(
nth
(
0
,
exp
->
args
))
==
T_Aggreg
)
{
if
(
nodeTag
(
nth
(
1
,
exp
->
args
))
==
T_Aggreg
)
elog
(
ERROR
,
"rewrite: comparision of 2 aggregate columns not supported"
);
else
elog
(
ERROR
,
"rewrite: aggregate column of view must be at rigth side in qual"
);
}
aggreg
=
(
Aggreg
*
)
nth
(
1
,
exp
->
args
);
target
=
(
Var
*
)(
aggreg
->
target
);
...
...
@@ -1189,6 +1219,33 @@ modifyAggregQual(Node **nodePtr, Query *parsetree)
}
break
;
case
T_CaseExpr
:
{
/* We're calling recursively,
* and this routine knows how to handle lists
* so let it do the work to handle the WHEN clauses... */
modifyAggregQual
(
(
Node
**
)(
&
(((
CaseExpr
*
)
node
)
->
args
)),
parsetree
);
modifyAggregQual
(
(
Node
**
)(
&
(((
CaseExpr
*
)
node
)
->
defresult
)),
parsetree
);
}
break
;
case
T_CaseWhen
:
{
modifyAggregQual
(
(
Node
**
)(
&
(((
CaseWhen
*
)
node
)
->
expr
)),
parsetree
);
modifyAggregQual
(
(
Node
**
)(
&
(((
CaseWhen
*
)
node
)
->
result
)),
parsetree
);
}
break
;
case
T_Iter
:
{
Iter
*
iter
=
(
Iter
*
)
node
;
...
...
@@ -1827,6 +1884,10 @@ fireRIRonSubselect(Node *node)
}
break
;
case
T_CaseExpr
:
case
T_CaseWhen
:
break
;
case
T_Query
:
{
Query
*
qry
=
(
Query
*
)
node
;
...
...
src/include/nodes/nodes.h
View file @
bedd04a5
...
...
@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: nodes.h,v 1.3
1 1998/10/01 02:04:01 tgl
Exp $
* $Id: nodes.h,v 1.3
2 1998/12/04 15:34:44 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -213,11 +213,13 @@ typedef enum NodeTag
T_SortClause
,
T_GroupClause
,
T_SubSelect
,
T_JoinUsing
T_JoinUsing
,
T_CaseExpr
,
T_CaseWhen
}
NodeTag
;
/*
* The first field of a node of any type is g
au
ranteed to be the NodeTag.
* The first field of a node of any type is g
ua
ranteed to be the NodeTag.
* Hence the type of any node can be gotten by casting it to Node. Declaring
* a variable to be of Node * (instead of void *) can also facilitate
* debugging.
...
...
src/include/nodes/parsenodes.h
View file @
bedd04a5
...
...
@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: parsenodes.h,v 1.6
1 1998/10/22 13:52:24 momjian
Exp $
* $Id: parsenodes.h,v 1.6
2 1998/12/04 15:34:44 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -713,6 +713,28 @@ typedef struct A_Const
TypeName
*
typename
;
/* typecast */
}
A_Const
;
/*
* CaseExpr - a CASE expression
*/
typedef
struct
CaseExpr
{
NodeTag
type
;
Oid
casetype
;
Node
*
arg
;
/* implicit equality comparison argument */
List
*
args
;
/* the arguments (list of WHEN clauses) */
Node
*
defresult
;
/* the default result (ELSE clause) */
}
CaseExpr
;
/*
* CaseWhen - an argument to a CASE expression
*/
typedef
struct
CaseWhen
{
NodeTag
type
;
Node
*
expr
;
/* comparison expression */
Node
*
result
;
/* substitution result */
}
CaseWhen
;
/*
* ColumnDef - column definition (used in various creates)
*/
...
...
@@ -777,7 +799,7 @@ typedef struct ResTarget
}
ResTarget
;
/*
* ParamString - used in
with
clauses
* ParamString - used in
WITH
clauses
*/
typedef
struct
ParamString
{
...
...
@@ -797,7 +819,7 @@ typedef struct RelExpr
}
RelExpr
;
/*
* SortGroupBy - for
order by
clause
* SortGroupBy - for
ORDER BY
clause
*/
typedef
struct
SortGroupBy
{
...
...
@@ -807,7 +829,7 @@ typedef struct SortGroupBy
}
SortGroupBy
;
/*
* JoinUsing - for
join using
clause
* JoinUsing - for
JOIN USING
clause
*/
typedef
struct
JoinUsing
{
...
...
@@ -818,7 +840,7 @@ typedef struct JoinUsing
}
JoinUsing
;
/*
* RangeVar - range variable, used in
from
clauses
* RangeVar - range variable, used in
FROM
clauses
*/
typedef
struct
RangeVar
{
...
...
@@ -828,7 +850,7 @@ typedef struct RangeVar
}
RangeVar
;
/*
* IndexElem - index parameters (used in
create index
)
* IndexElem - index parameters (used in
CREATE INDEX
)
*/
typedef
struct
IndexElem
{
...
...
src/include/optimizer/clauses.h
View file @
bedd04a5
...
...
@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: clauses.h,v 1.1
3 1998/09/01 04:36:53 momjian
Exp $
* $Id: clauses.h,v 1.1
4 1998/12/04 15:34:49 thomas
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -34,6 +34,8 @@ extern Expr *get_notclausearg(Expr *notclause);
extern
bool
and_clause
(
Node
*
clause
);
extern
Expr
*
make_andclause
(
List
*
andclauses
);
extern
bool
case_clause
(
Node
*
clause
);
extern
List
*
pull_constant_clauses
(
List
*
quals
,
List
**
constantQual
);
extern
void
clause_get_relids_vars
(
Node
*
clause
,
List
**
relids
,
List
**
vars
);
extern
int
NumRelids
(
Node
*
clause
);
...
...
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