Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Greenplum
Gpdb
提交
bedd04a5
G
Gpdb
项目概览
Greenplum
/
Gpdb
通知
7
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
Gpdb
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
bedd04a5
编写于
12月 04, 1998
作者:
T
Thomas G. Lockhart
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Implement CASE expression.
上级
19740e2f
变更
17
隐藏空白更改
内联
并排
Showing
17 changed file
with
777 addition
and
108 deletion
+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
未找到文件。
src/backend/executor/execQual.c
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
浏览文件 @
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
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录