@@ -595,44 +595,49 @@ jobs:
595595 print('patched CreateTrigger to preserve original SQL text')
596596 PY_TRIGGER_SQL
597597
598- # Treat 0-byte page reads as empty pages instead of erroring.
599- # SQLite's pager treats reads past EOF as zero-filled; Turso
600- # bails with `short read on page N: expected 4096 bytes, got 0`,
601- # which surfaces as a state-dependent failure mid-suite for
602- # testCreateTemporaryTable and testTemporaryTableHasPriorityOverStandardTable.
603- # Drop the !allow_empty_read special case for the bytes_read==0
604- # branch so the existing empty-buffer path runs instead — match
605- # SQLite's "zeros past EOF" behaviour.
606- python3 - <<'PY_PAGER_EMPTY_READ'
607- p = 'core/storage/sqlite3_ondisk.rs'
598+ # Force temp tables to use MemoryIO under all conditions, to
599+ # bypass the disk-temp pager's state-dependent
600+ # `short read on page N` bug that breaks
601+ # testCreateTemporaryTable + testTemporaryTableHasPriorityOverStandardTable.
602+ #
603+ # Setting this via runtime PRAGMA temp_store = MEMORY crashes
604+ # testReconstructTable in the pager (memory:
605+ # project_turso_testreconstructtable_fragile). Instead, patch
606+ # `effective_temp_store` so it returns `TempStore::Memory`
607+ # unconditionally — a compile-time change that doesn't go
608+ # through `set_temp_store` / `bump_prepare_context_generation`,
609+ # so testReconstructTable's prepared-statement cache is
610+ # untouched.
611+ python3 - <<'PY_TEMP_MEMORY'
612+ p = 'core/connection.rs'
608613 s = open(p).read()
609614 old = (
610- " // Handle truncated database files: if we read fewer bytes than expected\n"
611- " // (and it's not an intentional empty read), return a ShortRead error.\n"
612- " if bytes_read == 0 {\n"
613- " if !allow_empty_read {\n"
614- " tracing::error!(\"short read on page {page_idx}: expected {buf_len} bytes, got 0\");\n"
615- " page.clear_locked();\n"
616- " return Some(CompletionError::ShortRead {\n"
617- " page_idx,\n"
618- " expected: buf_len,\n"
619- " actual: 0,\n"
620- " });\n"
621- " }\n"
622- " } else if bytes_read != buf_len as i32 {\n"
615+ " fn effective_temp_store(&self) -> crate::TempStore {\n"
616+ " let temp_store = self.get_temp_store();\n"
617+ " #[cfg(feature = \"fs\")]\n"
618+ " {\n"
619+ " temp_store\n"
620+ " }\n"
621+ " #[cfg(not(feature = \"fs\"))]\n"
622+ " {\n"
623+ " let _ = temp_store;\n"
624+ " crate::TempStore::Memory\n"
625+ " }\n"
626+ " }\n"
623627 )
624628 new = (
625- " // Match SQLite: a read of 0 bytes (page beyond EOF / not yet\n"
626- " // written) is treated as a zero-filled page instead of an error.\n"
627- " // Truncated reads (1..buf_len-1 bytes) are still rejected.\n"
628- " if bytes_read == 0 {\n"
629- " // fall through to the empty-buffer path below\n"
630- " } else if bytes_read != buf_len as i32 {\n"
629+ " fn effective_temp_store(&self) -> crate::TempStore {\n"
630+ " // Always use MemoryIO for temp tables: avoids a state-dependent\n"
631+ " // `short read on page N` bug in the disk-temp pager that breaks\n"
632+ " // testCreateTemporaryTable mid-suite under PHPUnit.\n"
633+ " let _ = self.get_temp_store();\n"
634+ " crate::TempStore::Memory\n"
635+ " }\n"
631636 )
632- assert old in s, 'sqlite3_ondisk short-read block not found'
637+ assert old in s, 'effective_temp_store block not found'
633638 open(p, 'w').write(s.replace(old, new, 1))
634- print('patched sqlite3_ondisk to treat 0-byte page read as empty (SQLite-compatible) ')
635- PY_PAGER_EMPTY_READ
639+ print('patched effective_temp_store to always return TempStore::Memory ')
640+ PY_TEMP_MEMORY
636641
637642 echo '--- Patched stub! macro ---'
638643 sed -n '/macro_rules! stub/,/^}$/p' sqlite3/src/lib.rs
0 commit comments