Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Adding LIMIT clause to query results in assertion failure

未关闭
#243 2 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
3/5
预计耗时
1-2 天
新手友好度
42/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
停滞
技术栈
scala, sql
领域
backend, database

调研方向

从 SqlMapping.scala:1717 开始,复现应用了子 Limit 的所提供 Scala 查询。检查 addFilterOrderByOffsetLimit,以及 join 中现有的 ORDER BY 如何与 limit 交互。完成标准是查询不再触发 assertion,并生成保留所请求 limit 的有效 SQL。

由索引模型根据 Issue 内容生成。

描述

bug

The following query

Select(
  "programs", 
  Nil, 
  Filter(
    And(
      Or(
        Contains(ListPath(List("users", "userId")), Const("u-107")), 
        Eql(UniquePath(List("piUserId")), Const("u-107"))
      ), 
      Eql(UniquePath(List("existence")), Const(Present))
    ), 
    Group(
      List(
        Select("id", List(), Empty),  
        Select("name", List(), Empty)
      )
    )
  )
)

produces the following SQL.

SELECT
  t_program.c_name,
  t_program.c_program_id
FROM
  t_program
  INNER JOIN (
    SELECT
      DISTINCT ON ((t_program.c_program_id COLLATE "C"))(t_program.c_program_id COLLATE "C")
    FROM
      t_program
      LEFT JOIN t_program_user ON (
        t_program_user.c_program_id = t_program.c_program_id
      )
    WHERE
      (
        (
          (
            (t_program_user.c_user_id = $1)
            OR (t_program.c_pi_user_id = $2)
          )
          AND (t_program.c_existence = $3)
        )
      )
      AND (t_program.c_program_id IS NOT NULL)
    ORDER BY
      (t_program.c_program_id COLLATE "C") NULLS LAST
  ) AS t_program_pred ON (
    t_program_pred.c_program_id = t_program.c_program_id
  )

Adding a Limit to the child query, thus

Select(
  "programs",
  Nil,
  Filter(
    And(
      Or(
        Contains(ListPath(List("users", "userId")), Const("u-107")),
        Eql(UniquePath(List("piUserId")), Const("u-107"))
      ),
      Eql(UniquePath(List("existence")), Const(Present))
    ),
    Limit(
      1000,
      Group(
        List(
          Select("id", Nil, Empty), 
          Select("name", Nil, Empty)
        )
      )
    )
  )
)

results in

java.lang.AssertionError: assertion failed
	at scala.Predef$.assert(Predef.scala:264)
	at edu.gemini.grackle.sql.SqlMapping$SqlQuery$SqlSelect.addFilterOrderByOffsetLimit(SqlMapping.scala:1717)
        ...

due to (I assume) the already-present ORDER BY caused by the joins ... ?

assert(orders.isEmpty && offset.isEmpty && limit.isEmpty && !isDistinct)

Relevant [abbreviated] definitions:

create table t_user (
  c_user_id     d_user_id     primary key not null,
  ...
);

create table t_program (
  c_program_id  d_program_id  not null primary key,
  c_existence   e_existence   not null,
  c_pi_user_id  d_user_id,
  c_name        text,
  ...
);

create table t_program_user (
  c_program_id  d_program_id  not null,
  c_user_id     d_user_id     not null,
  ...
);
object Program extends TableDef("t_program") {
  val Id        = col("c_program_id", program_id)
  val PiUserId  = col("c_pi_user_id", user_id)
  val Existence = col("c_existence", existence)
  val Name      = col("c_name", text_nonempty.opt)
}
object ProgramUser extends TableDef("t_program_user") {
  val ProgramId = col("c_program_id", program_id)
  val UserId    = col("c_user_id", user_id)
  val Role      = col("c_role", program_user_role)
}
object User extends TableDef("t_user") {
  val Id = col("c_user_id", user_id)
}
ObjectMapping(
  tpe = QueryType,
  fieldMappings = List(
    SqlRoot("programs"),
    SqlRoot("program"),
  )
),
ObjectMapping(
  tpe = ProgramType,
  fieldMappings = List(
    SqlField("id", Program.Id, key = true),
    SqlField("existence", Program.Existence, hidden = true),
    SqlField("name", Program.Name),
    SqlField("piUserId", Program.PiUserId, hidden = true),
    SqlObject("pi", Join(Program.PiUserId, User.Id)),
    SqlObject("users", Join(Program.Id, ProgramUser.ProgramId)),
  ),
),
ObjectMapping(
  tpe = ProgramUserType,
  fieldMappings = List(
    SqlField("programId", ProgramUser.ProgramId, hidden = true, key = true),
    SqlField("userId", ProgramUser.UserId, key = true),
    SqlField("role", ProgramUser.Role),
    SqlObject("user", Join(ProgramUser.UserId, User.Id))
  ),
),
LeafMapping[lucuma.core.model.User.Id](UserIdType),
LeafMapping[lucuma.core.model.Program.Id](ProgramIdType),
LeafMapping[ProgramUserRole](ProgramUserRoleType),
主要语言
Scala
星标
189
派生
32
平均合并
14 小时 48 分钟
30 天内合并 PR
25

环境准备

  • 提供 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

typelevel/grackle 的其他 Issue

查看 typelevel/grackle 的全部 Issue

相似的 Issue

更多 Scala Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。