fix: avoid D1 LIKE pattern length limit on admin search (#956) (#957)

D1 caps LIKE/GLOB pattern length at 50 bytes. /admin/address and
/admin/users wrapped the query as `%${query}%` and fed it to LIKE,
so searching by a full email address crashed with "LIKE or GLOB
pattern too complex". Fall back to instr() above the 50-byte
threshold.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dream Hunter
2026-04-07 19:23:26 +08:00
committed by GitHub
parent 42281cdc49
commit e6ef110ec9
5 changed files with 69 additions and 6 deletions

View File

@@ -39,15 +39,21 @@ export default {
getUsers: async (c: Context<HonoCustomType>) => {
const { limit, offset, query } = c.req.query();
if (query) {
// D1 caps LIKE pattern length at 50 bytes; fall back to instr()
// for longer queries to avoid "LIKE or GLOB pattern too complex" (#956).
const useInstr = new TextEncoder().encode(query).length + 2 > 50;
const param = useInstr ? query : `%${query}%`;
const userEmailWhere = useInstr ? `instr(u.user_email, ?) > 0` : `u.user_email like ?`;
const userEmailWhereCount = useInstr ? `instr(user_email, ?) > 0` : `user_email like ?`;
return await handleListQuery(c,
`SELECT u.id as id, u.user_email, u.created_at, u.updated_at,`
+ ` ur.role_text as role_text,`
+ ` (SELECT COUNT(*) FROM users_address WHERE user_id = u.id) AS address_count`
+ ` FROM users u`
+ ` LEFT JOIN user_roles ur ON u.id = ur.user_id`
+ ` where u.user_email like ?`,
`SELECT count(*) as count FROM users where user_email like ?`,
[`%${query}%`], limit, offset
+ ` where ${userEmailWhere}`,
`SELECT count(*) as count FROM users where ${userEmailWhereCount}`,
[param], limit, offset
);
}
return await handleListQuery(c,

View File

@@ -76,14 +76,19 @@ api.get('/admin/address', async (c) => {
const sortDirection = sort_order === 'ascend' ? 'asc' : 'desc';
const orderBy = `${sortColumn} ${sortDirection}`;
if (query) {
// D1 caps LIKE pattern length at 50 bytes; fall back to instr() for
// longer queries to avoid "LIKE or GLOB pattern too complex" (#956).
const useInstr = new TextEncoder().encode(query).length + 2 > 50;
const whereClause = useInstr ? `instr(name, ?) > 0` : `name like ?`;
const param = useInstr ? query : `%${query}%`;
return await handleListQuery(c,
`SELECT a.*,`
+ ` (SELECT COUNT(*) FROM raw_mails WHERE address = a.name) AS mail_count,`
+ ` (SELECT COUNT(*) FROM sendbox WHERE address = a.name) AS send_count`
+ ` FROM address a`
+ ` where name like ?`,
`SELECT count(*) as count FROM address where name like ?`,
[`%${query}%`], limit, offset, orderBy
+ ` where ${whereClause}`,
`SELECT count(*) as count FROM address where ${whereClause}`,
[param], limit, offset, orderBy
);
}
return await handleListQuery(c,