From d74ee34d9128295faa116c919bd1dcca77744975 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 14 May 2026 01:49:34 +0900 Subject: [PATCH] refac --- backend/open_webui/models/knowledge.py | 41 ++++++++++++++++++++------ backend/open_webui/models/notes.py | 4 +-- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/backend/open_webui/models/knowledge.py b/backend/open_webui/models/knowledge.py index 75825a10bc..bc06012e4e 100644 --- a/backend/open_webui/models/knowledge.py +++ b/backend/open_webui/models/knowledge.py @@ -24,7 +24,6 @@ from sqlalchemy import ( String, Text, UniqueConstraint, - cast, delete, func, or_, @@ -361,21 +360,41 @@ class KnowledgeTable: ) # Apply filename / content search + # Use ->> (as_string) instead of CAST(-> AS TEXT) to avoid + # PostgreSQL "invalid memory alloc request size" on large + # extracted-content rows (#24670). + content_text = File.data['content'].as_string() + search_filter = None if filter: q = filter.get('query') if q: - stmt = stmt.filter( - or_( - File.filename.ilike(f'%{q}%'), - cast(File.data['content'], Text).ilike(f'%{q}%'), - ) + search_filter = or_( + File.filename.ilike(f'%{q}%'), + content_text.ilike(f'%{q}%'), ) + stmt = stmt.filter(search_filter) # Order by file changes stmt = stmt.order_by(File.updated_at.desc(), File.id.asc()) - # Count before pagination - count_result = await db.execute(select(func.count()).select_from(stmt.subquery())) + # Lightweight count: avoid selecting File.data and ORDER BY + count_stmt = ( + select(func.count(File.id)) + .select_from(File) + .join(KnowledgeFile, File.id == KnowledgeFile.file_id) + .join(Knowledge, KnowledgeFile.knowledge_id == Knowledge.id) + ) + count_stmt = AccessGrants.has_permission_filter( + db=db, + query=count_stmt, + DocumentModel=Knowledge, + filter=filter, + resource_type='knowledge', + permission='read', + ) + if search_filter is not None: + count_stmt = count_stmt.filter(search_filter) + count_result = await db.execute(count_stmt) total = count_result.scalar() if skip: @@ -527,10 +546,14 @@ class KnowledgeTable: if filter: query_key = filter.get('query') if query_key: + # Use ->> (as_string) instead of CAST(-> AS TEXT) to + # avoid PostgreSQL memory allocation failures on large + # content (#24670). + content_text = File.data['content'].as_string() stmt = stmt.filter( or_( File.filename.ilike(f'%{query_key}%'), - cast(File.data['content'], Text).ilike(f'%{query_key}%'), + content_text.ilike(f'%{query_key}%'), ) ) diff --git a/backend/open_webui/models/notes.py b/backend/open_webui/models/notes.py index 9a858bd2f6..1cddd2f8fa 100644 --- a/backend/open_webui/models/notes.py +++ b/backend/open_webui/models/notes.py @@ -9,7 +9,7 @@ from open_webui.models.access_grants import AccessGrantModel, AccessGrants from open_webui.models.groups import Groups from open_webui.models.users import User, UserModel, UserResponse, Users from pydantic import BaseModel, ConfigDict, Field -from sqlalchemy import JSON, BigInteger, Boolean, Column, ForeignKey, Text, cast, delete, func, or_, select, update +from sqlalchemy import JSON, BigInteger, Boolean, Column, ForeignKey, Text, delete, func, or_, select, update from sqlalchemy.ext.asyncio import AsyncSession #################### @@ -180,7 +180,7 @@ class NoteTable: or_( func.replace(func.replace(Note.title, '-', ''), ' ', '').ilike(f'%{word}%'), func.replace( - func.replace(cast(Note.data['content']['md'], Text), '-', ''), + func.replace(Note.data['content']['md'].as_string(), '-', ''), ' ', '', ).ilike(f'%{word}%'),