【发布时间】:2013-08-03 15:49:41
【问题描述】:
是否可以提取 Boost.Proto 表达式树的部分,单独(外部)评估它们,然后改变表达式树,用结果替换提取的部分?
在我的具体情况下,我正在尝试评估是否可以重复重写一些遗留代码:
- 生成sql
- 查询数据库
- 使用结果生成新的 sql 查询
- 再次查询数据库 ... (等等)
我希望做的是: 1. 生成单个大型表达式树 2. 从表达式树中获取 SQL。这包括: 湾。访问树并检查在生成单个 sql 之前必须评估的子查询 C。如果有子查询,则创建 sql 并以字符串形式返回,在外部评估 sql,然后改变树,用结果替换子查询
(另外,我想识别相同的子查询,如果可能的话,只评估一次)
这可能吗?是否需要难以理解/学习的代码?
我浏览了 Boost.Proto 文档,但我不确定它是否适用于我需要从外部评估子树并用结果替换它的场景,直到整个树减少为单个查询.
编辑:
假设我有以下表格:
对象 编号 |名字
属性链接 对象ID |属性id
属性 编号 |父母身份 |姓名 |价值
我的查询以自定义“查询”对象的形式出现——具有多个 AND、OR 子句的(二叉树)树。
示例: query1 = object.id=10 OR (attribute.name = "name" OR attribute.name = "name2")
这转换为:获取对象 10 的属性,其中属性的名称是“名称”。注意 parentid 字段,这意味着我们要查找的属性名称可以嵌套,而不是直接链接到我们的对象。
我需要做的是: 1. 将其翻译成具有足够信息的表达式树 2.将这棵树发送到db层 3. 如上所述处理树(有时分多个阶段)
也许表达式树看起来像:
find_attributes(object_id = 10 AND attribute_name = ("name" OR "name2"))
有多个数据库的 SQL 语法不同,这就是我想这样做的原因。因此,我需要能够覆盖一些基于数据库的处理步骤。
例如PostgreSQL:
处理将首先识别 find_attributes 节点,并知道我们正在搜索属性
进一步看,属性需要链接到object.id = 10,我们立即生成并运行查询以获取所有object.id = 10的属性,并将object_id = 10节点替换为具有实际属性 id (object_id = 10) => (attribute_id = (20 OR 21)) 的表达式树。
然后,我们找到attribute_name节点,由于属性是嵌套的,我们需要找到所有name = "name" or "name2"的属性行
作为一个(可选的)优化步骤,由于有数百万个属性,我们需要将attribute_id 和attribute_name 节点合并到一个查询中
生成的查询可能类似于:
(find attributeids) SELECT id FROM attributes WHERE objectid = 10)
-
(最终查询)---
有
get_roots AS (SELECT * FROM attributes WHERE (id=20 OR id=21)),
get_childs AS (SELECT * FROM get_roots, attributes WHERE attributes.parentid = get_roots.id),
get_grandchilds AS (SELECT * FROM get_childs, attributes WHERE attributes.parentid = get_childs.id)SELECT * FROM get_roots 联盟
选择 * 从 get_childs 联盟
SELECT * FROM get_grandchilds
(假设这里的属性只有三层深,可能会被重写为递归CTE)
我想这可能是可能的,但工作量会太大吗?有一组有限的查询,这里介绍的查询是最复杂的。
【问题讨论】:
-
从 Proto 的描述“它提供了用于构造、类型检查、转换和执行表达式模板的工具”听起来很匹配。
-
是的,确实如此。但是,我在文档中没有找到可以评估和转换子树的示例。不过,可能我看的不够仔细……
-
我不确定能否提供帮助,但我喜欢玩 Boost.Proto。您能否添加几个示例查询(包括子查询)并说明您使用的是什么 sql 库?
-
谢谢。我认为,我添加了一个突出大多数问题的示例。如果解释令人困惑,我会尽量让它更清楚。
标签: c++ expression-trees boost-proto