Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
2dot5
ClickHouse
提交
20fe3751
C
ClickHouse
项目概览
2dot5
/
ClickHouse
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
ClickHouse
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
20fe3751
编写于
6月 02, 2015
作者:
A
Alexey Arno
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Merge
上级
018a31f4
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
209 addition
and
147 deletion
+209
-147
dbms/include/DB/Parsers/ASTSelectQuery.h
dbms/include/DB/Parsers/ASTSelectQuery.h
+24
-147
dbms/src/Parsers/ASTSelectQuery.cpp
dbms/src/Parsers/ASTSelectQuery.cpp
+179
-0
dbms/tests/queries/0_stateless/00098_j_union_all.reference
dbms/tests/queries/0_stateless/00098_j_union_all.reference
+4
-0
dbms/tests/queries/0_stateless/00098_j_union_all.sql
dbms/tests/queries/0_stateless/00098_j_union_all.sql
+2
-0
未找到文件。
dbms/include/DB/Parsers/ASTSelectQuery.h
浏览文件 @
20fe3751
...
...
@@ -9,11 +9,34 @@
namespace
DB
{
/** SELECT запрос
*/
class
ASTSelectQuery
:
public
ASTQueryWithOutput
{
public:
ASTSelectQuery
()
=
default
;
ASTSelectQuery
(
const
StringRange
range_
);
/** Получить текст, который идентифицирует этот элемент. */
String
getID
()
const
override
{
return
"SelectQuery"
;
};
/// Проверить наличие функции arrayJoin. (Не большого ARRAY JOIN.)
static
bool
hasArrayJoin
(
const
ASTPtr
&
ast
);
/// Содержит ли запрос астериск?
bool
hasAsterisk
()
const
;
/// Переименовать столбцы запроса в такие же имена, как в исходном запросе.
void
renameColumns
(
const
ASTSelectQuery
&
source
);
/// Переписывает select_expression_list, чтобы вернуть только необходимые столбцы в правильном порядке.
void
rewriteSelectExpressionList
(
const
Names
&
column_names
);
/// Переписывает select_expression_list, чтобы вернуть только необходимые столбцы в правильном порядке.
void
rewriteSelectExpressionList3
(
const
Names
&
column_names
);
ASTPtr
clone
()
const
override
;
public:
bool
distinct
=
false
;
ASTPtr
select_expression_list
;
...
...
@@ -32,152 +55,6 @@ public:
ASTPtr
limit_offset
;
ASTPtr
limit_length
;
ASTPtr
next_union_all
;
/// Следующий запрос SELECT в цепочке UNION ALL, если такой есть
ASTSelectQuery
()
=
default
;
ASTSelectQuery
(
const
StringRange
range_
)
:
ASTQueryWithOutput
(
range_
)
{}
/** Получить текст, который идентифицирует этот элемент. */
String
getID
()
const
override
{
return
"SelectQuery"
;
};
/// Проверить наличие функции arrayJoin. (Не большого ARRAY JOIN.)
static
bool
hasArrayJoin
(
const
ASTPtr
&
ast
)
{
if
(
const
ASTFunction
*
function
=
typeid_cast
<
const
ASTFunction
*>
(
&*
ast
))
if
(
function
->
kind
==
ASTFunction
::
ARRAY_JOIN
)
return
true
;
for
(
const
auto
&
child
:
ast
->
children
)
if
(
hasArrayJoin
(
child
))
return
true
;
return
false
;
}
/// Содержит ли запрос астериск?
bool
hasAsterisk
()
const
{
for
(
const
auto
&
ast
:
select_expression_list
->
children
)
if
(
typeid_cast
<
const
ASTAsterisk
*>
(
&*
ast
)
!=
nullptr
)
return
true
;
return
false
;
}
/// Переименовать столбцы запроса в такие же имена, как в исходном запросе.
void
renameColumns
(
const
ASTSelectQuery
&
source
)
{
const
ASTs
&
from
=
source
.
select_expression_list
->
children
;
ASTs
&
to
=
select_expression_list
->
children
;
if
(
from
.
size
()
!=
to
.
size
())
throw
Exception
(
"Size mismatch in UNION ALL chain"
,
DB
::
ErrorCodes
::
UNION_ALL_RESULT_STRUCTURES_MISMATCH
);
for
(
size_t
i
=
0
;
i
<
from
.
size
();
++
i
)
{
/// Если столбец имеет алиас, то он должен совпадать с названием исходного столбца.
/// В противном случае мы ему присваиваем алиас, если требуется.
if
(
!
to
[
i
]
->
tryGetAlias
().
empty
())
{
if
(
to
[
i
]
->
tryGetAlias
()
!=
from
[
i
]
->
getAliasOrColumnName
())
throw
Exception
(
"Column alias mismatch in UNION ALL chain"
,
DB
::
ErrorCodes
::
UNION_ALL_COLUMN_ALIAS_MISMATCH
);
}
else
if
(
to
[
i
]
->
getColumnName
()
!=
from
[
i
]
->
getAliasOrColumnName
())
to
[
i
]
->
setAlias
(
from
[
i
]
->
getAliasOrColumnName
());
}
}
/// Переписывает select_expression_list, чтобы вернуть только необходимые столбцы в правильном порядке.
void
rewriteSelectExpressionList
(
const
Names
&
column_names
)
{
ASTPtr
result
=
new
ASTExpressionList
;
ASTs
asts
=
select_expression_list
->
children
;
/// Не будем выбрасывать выражения, содержащие функцию arrayJoin.
std
::
set
<
ASTPtr
>
unremovable_asts
;
for
(
size_t
j
=
0
;
j
<
asts
.
size
();
++
j
)
{
if
(
hasArrayJoin
(
asts
[
j
]))
{
result
->
children
.
push_back
(
asts
[
j
]
->
clone
());
unremovable_asts
.
insert
(
asts
[
j
]);
}
}
for
(
const
auto
&
column_name
:
column_names
)
{
bool
done
=
false
;
for
(
size_t
j
=
0
;
j
<
asts
.
size
();
++
j
)
{
if
(
asts
[
j
]
->
getAliasOrColumnName
()
==
column_name
)
{
if
(
!
unremovable_asts
.
count
(
asts
[
j
]))
result
->
children
.
push_back
(
asts
[
j
]
->
clone
());
done
=
true
;
}
}
if
(
!
done
)
throw
Exception
(
"Error while rewriting expression list for select query."
" Could not find alias: "
+
column_name
,
DB
::
ErrorCodes
::
UNKNOWN_IDENTIFIER
);
}
for
(
auto
&
child
:
children
)
{
if
(
child
==
select_expression_list
)
{
child
=
result
;
break
;
}
}
select_expression_list
=
result
;
/** NOTE: Может показаться, что мы могли испортить запрос, выбросив выражение с алиасом, который используется где-то еще.
* Такого произойти не может, потому что этот метод вызывается всегда для запроса, на котором хоть раз создавали
* ExpressionAnalyzer, что гарантирует, что в нем все алиасы уже подставлены. Не совсем очевидная логика :)
*/
}
ASTPtr
clone
()
const
override
{
ASTSelectQuery
*
res
=
new
ASTSelectQuery
(
*
this
);
ASTPtr
ptr
{
res
};
res
->
children
.
clear
();
#define CLONE(member) if (member) { res->member = member->clone(); res->children.push_back(res->member); }
/** NOTE Члены должны клонироваться точно в таком же порядке,
* в каком они были вставлены в children в ParserSelectQuery.
* Это важно, потому что из имён children-ов составляется идентификатор (getTreeID),
* который может быть использован для идентификаторов столбцов в случае подзапросов в операторе IN.
* При распределённой обработке запроса, в случае, если один из серверов localhost, а другой - нет,
* запрос на localhost выполняется в рамках процесса и при этом клонируется,
* а на удалённый сервер запрос отправляется в текстовом виде по TCP.
* И если порядок при клонировании не совпадает с порядком при парсинге,
* то на разных серверах получатся разные идентификаторы.
*/
CLONE
(
select_expression_list
)
CLONE
(
database
)
CLONE
(
table
)
CLONE
(
array_join_expression_list
)
CLONE
(
join
)
CLONE
(
sample_size
)
CLONE
(
prewhere_expression
)
CLONE
(
where_expression
)
CLONE
(
group_expression_list
)
CLONE
(
having_expression
)
CLONE
(
order_expression_list
)
CLONE
(
limit_offset
)
CLONE
(
limit_length
)
CLONE
(
format
)
CLONE
(
next_union_all
)
#undef CLONE
return
ptr
;
}
};
}
dbms/src/Parsers/ASTSelectQuery.cpp
0 → 100644
浏览文件 @
20fe3751
#include <DB/Parsers/ASTSelectQuery.h>
namespace
DB
{
ASTSelectQuery
::
ASTSelectQuery
(
const
StringRange
range_
)
:
ASTQueryWithOutput
(
range_
)
{
}
bool
ASTSelectQuery
::
hasArrayJoin
(
const
ASTPtr
&
ast
)
{
if
(
const
ASTFunction
*
function
=
typeid_cast
<
const
ASTFunction
*>
(
&*
ast
))
if
(
function
->
kind
==
ASTFunction
::
ARRAY_JOIN
)
return
true
;
for
(
const
auto
&
child
:
ast
->
children
)
if
(
hasArrayJoin
(
child
))
return
true
;
return
false
;
}
bool
ASTSelectQuery
::
hasAsterisk
()
const
{
for
(
const
auto
&
ast
:
select_expression_list
->
children
)
if
(
typeid_cast
<
const
ASTAsterisk
*>
(
&*
ast
)
!=
nullptr
)
return
true
;
return
false
;
}
void
ASTSelectQuery
::
renameColumns
(
const
ASTSelectQuery
&
source
)
{
const
ASTs
&
from
=
source
.
select_expression_list
->
children
;
ASTs
&
to
=
select_expression_list
->
children
;
if
(
from
.
size
()
!=
to
.
size
())
throw
Exception
(
"Size mismatch in UNION ALL chain"
,
DB
::
ErrorCodes
::
UNION_ALL_RESULT_STRUCTURES_MISMATCH
);
for
(
size_t
i
=
0
;
i
<
from
.
size
();
++
i
)
{
/// Если столбец имеет алиас, то он должен совпадать с названием исходного столбца.
/// В противном случае мы ему присваиваем алиас, если требуется.
if
(
!
to
[
i
]
->
tryGetAlias
().
empty
())
{
if
(
to
[
i
]
->
tryGetAlias
()
!=
from
[
i
]
->
getAliasOrColumnName
())
throw
Exception
(
"Column alias mismatch in UNION ALL chain"
,
DB
::
ErrorCodes
::
UNION_ALL_COLUMN_ALIAS_MISMATCH
);
}
else
if
(
to
[
i
]
->
getColumnName
()
!=
from
[
i
]
->
getAliasOrColumnName
())
to
[
i
]
->
setAlias
(
from
[
i
]
->
getAliasOrColumnName
());
}
}
void
ASTSelectQuery
::
rewriteSelectExpressionList
(
const
Names
&
column_names
)
{
ASTPtr
result
=
new
ASTExpressionList
;
ASTs
asts
=
select_expression_list
->
children
;
/// Создать отображение.
/// Элемент отображения.
struct
Arrow
{
Arrow
()
=
default
;
Arrow
(
size_t
to_position_
)
:
to_position
(
to_position_
),
is_selected
(
true
)
{
}
size_t
to_position
=
0
;
bool
is_selected
=
false
;
};
/// Отображение одного SELECT выражения в другое.
using
Mapping
=
std
::
vector
<
Arrow
>
;
Mapping
mapping
(
asts
.
size
());
std
::
vector
<
size_t
>
from
(
column_names
.
size
());
/// Не будем выбрасывать выражения, содержащие функцию arrayJoin.
for
(
size_t
i
=
0
;
i
<
asts
.
size
();
++
i
)
{
if
(
hasArrayJoin
(
asts
[
i
]))
mapping
[
i
]
=
Arrow
(
i
);
}
for
(
size_t
i
=
0
;
i
<
column_names
.
size
();
++
i
)
{
bool
done
=
false
;
for
(
size_t
j
=
0
;
j
<
asts
.
size
();
++
j
)
{
if
(
asts
[
j
]
->
getAliasOrColumnName
()
==
column_names
[
i
])
{
from
[
i
]
=
j
;
done
=
true
;
break
;
}
}
if
(
!
done
)
throw
Exception
(
"Error while rewriting expression list for select query."
" Could not find alias: "
+
column_names
[
i
],
DB
::
ErrorCodes
::
UNKNOWN_IDENTIFIER
);
}
auto
to
=
from
;
std
::
sort
(
from
.
begin
(),
from
.
end
());
for
(
size_t
i
=
0
;
i
<
column_names
.
size
();
++
i
)
{
auto
&
arrow
=
mapping
[
from
[
i
]];
if
(
!
arrow
.
is_selected
)
arrow
=
Arrow
(
to
[
i
]);
}
/// Составить новое выражение.
for
(
const
auto
&
arrow
:
mapping
)
{
if
(
arrow
.
is_selected
)
result
->
children
.
push_back
(
asts
[
arrow
.
to_position
]
->
clone
());
}
for
(
auto
&
child
:
children
)
{
if
(
child
==
select_expression_list
)
{
child
=
result
;
break
;
}
}
select_expression_list
=
result
;
/** NOTE: Может показаться, что мы могли испортить запрос, выбросив выражение с алиасом, который используется где-то еще.
* Такого произойти не может, потому что этот метод вызывается всегда для запроса, на котором хоть раз создавали
* ExpressionAnalyzer, что гарантирует, что в нем все алиасы уже подставлены. Не совсем очевидная логика :)
*/
}
ASTPtr
ASTSelectQuery
::
clone
()
const
{
ASTSelectQuery
*
res
=
new
ASTSelectQuery
(
*
this
);
ASTPtr
ptr
{
res
};
res
->
children
.
clear
();
#define CLONE(member) if (member) { res->member = member->clone(); res->children.push_back(res->member); }
/** NOTE Члены должны клонироваться точно в таком же порядке,
* в каком они были вставлены в children в ParserSelectQuery.
* Это важно, потому что из имён children-ов составляется идентификатор (getTreeID),
* который может быть использован для идентификаторов столбцов в случае подзапросов в операторе IN.
* При распределённой обработке запроса, в случае, если один из серверов localhost, а другой - нет,
* запрос на localhost выполняется в рамках процесса и при этом клонируется,
* а на удалённый сервер запрос отправляется в текстовом виде по TCP.
* И если порядок при клонировании не совпадает с порядком при парсинге,
* то на разных серверах получатся разные идентификаторы.
*/
CLONE
(
select_expression_list
)
CLONE
(
database
)
CLONE
(
table
)
CLONE
(
array_join_expression_list
)
CLONE
(
join
)
CLONE
(
sample_size
)
CLONE
(
prewhere_expression
)
CLONE
(
where_expression
)
CLONE
(
group_expression_list
)
CLONE
(
having_expression
)
CLONE
(
order_expression_list
)
CLONE
(
limit_offset
)
CLONE
(
limit_length
)
CLONE
(
format
)
CLONE
(
next_union_all
)
#undef CLONE
return
ptr
;
}
};
dbms/tests/queries/0_stateless/00098_j_union_all.reference
0 → 100644
浏览文件 @
20fe3751
0 -1
0 -1
-1 0
-1 0
dbms/tests/queries/0_stateless/00098_j_union_all.sql
0 → 100644
浏览文件 @
20fe3751
SELECT
*
FROM
(
SELECT
dummy
,
-
1
as
x
UNION
ALL
SELECT
dummy
,
arrayJoin
([
-
1
])
as
x
);
SELECT
*
FROM
(
SELECT
-
1
as
x
,
dummy
UNION
ALL
SELECT
arrayJoin
([
-
1
])
as
x
,
dummy
);
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录