@@ -69,6 +69,10 @@ impl HostBindingKind {
6969/// Documented call-index blocks shared by builtins and host imports.
7070///
7171/// Must match the block table in `src/builtins/catalog.rs`.
72+ /// The ordinary block's top four IDs are frozen for SQLite. Keep allocation
73+ /// explicit here: incrementing a `u16` cursor from `0xFFFF` would overflow.
74+ pub ( crate ) const SQLITE_RESERVED_TOP_START : u16 = 0xFFFC ;
75+ pub ( crate ) const SQLITE_RESERVED_TOP_END : u16 = u16:: MAX ;
7276pub ( crate ) const ORDINARY_BLOCK_START : u16 = 0xFFA2 ;
7377pub ( crate ) const SPECIAL_CALL_BLOCK_START : u16 = 0xFF90 ;
7478pub ( crate ) const SPECIAL_CALL_BLOCK_END : u16 = 0xFFA1 ;
@@ -143,11 +147,24 @@ fn main() {
143147 . join ( "runtime" )
144148 . join ( "namespaces.rs" ) ;
145149 println ! ( "cargo:rerun-if-changed={}" , namespace_manifest. display( ) ) ;
146- let namespaces = parse_namespace_manifest ( & namespace_manifest) ;
150+ let mut namespaces = parse_namespace_manifest ( & namespace_manifest) ;
147151
148152 let catalog_path = manifest_dir. join ( "src" ) . join ( "builtins" ) . join ( "catalog.rs" ) ;
149153 println ! ( "cargo:rerun-if-changed={}" , catalog_path. display( ) ) ;
150- let catalog = parse_catalog ( & catalog_path) ;
154+ let mut catalog = parse_catalog ( & catalog_path) ;
155+
156+ // The SQLite namespace is optional: its builtin module links rusqlite,
157+ // which is not available on every target or without the `sqlite` feature.
158+ // When the feature is off (or the target is wasm32, where rusqlite's
159+ // bundled build is unsupported), drop the namespace and its static
160+ // catalog IDs so the generated catalog, dispatch, and compiler namespace
161+ // surface stay consistent and feature-clean.
162+ let sqlite_enabled = env:: var_os ( "CARGO_FEATURE_SQLITE" ) . is_some ( )
163+ && env:: var ( "CARGO_CFG_TARGET_ARCH" ) . as_deref ( ) != Ok ( "wasm32" ) ;
164+ if !sqlite_enabled {
165+ namespaces. retain ( |namespace| namespace. namespace != "sqlite" ) ;
166+ catalog. retain ( |entry| !entry. source_name . starts_with ( "sqlite::" ) ) ;
167+ }
151168
152169 let host_sources = [ SourceSpec {
153170 path : "src/builtins/runtime/host.rs" . to_string ( ) ,
@@ -522,6 +539,7 @@ fn strip_quoted(value: &str) -> Option<String> {
522539/// - a catalog variant does not match the derived variant for its source name;
523540/// - a class disagrees with the dispatch classification (ordinary vs
524541/// special-call) or with the `__` internal-name prefix;
542+ /// - a non-SQLite entry uses one of the frozen top-u16 SQLite IDs;
525543/// - an ID falls outside its documented block.
526544pub ( crate ) fn validate_catalog_contract (
527545 entries : & [ CatalogEntry ] ,
@@ -547,6 +565,16 @@ pub(crate) fn validate_catalog_contract(
547565 ) ;
548566 }
549567 for entry in entries {
568+ if ( SQLITE_RESERVED_TOP_START ..=SQLITE_RESERVED_TOP_END ) . contains ( & entry. id )
569+ && !entry. source_name . starts_with ( "sqlite::" )
570+ {
571+ panic ! (
572+ "builtin '{}' id 0x{:04X} falls in the SQLite-reserved top-u16 range \
573+ 0x{SQLITE_RESERVED_TOP_START:04X}..=0x{SQLITE_RESERVED_TOP_END:04X}; \
574+ do not allocate IDs by arithmetic",
575+ entry. source_name, entry. id
576+ ) ;
577+ }
550578 let expected_variant = builtin_variant_name ( & entry. source_name ) ;
551579 if expected_variant != entry. variant {
552580 panic ! (
@@ -766,6 +794,11 @@ fn render_builtin_catalog(
766794 . collect :: < Vec < _ > > ( ) ,
767795 ) ) ;
768796
797+ writeln ! (
798+ & mut out,
799+ "// The top-u16 range 0xFFFC..=0xFFFF is reserved for SQLite's frozen IDs; do not allocate it arithmetically."
800+ )
801+ . unwrap ( ) ;
769802 writeln ! (
770803 & mut out,
771804 "#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]"
0 commit comments