@@ -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 ( ) ,
@@ -532,6 +549,7 @@ fn strip_quoted(value: &str) -> Option<String> {
532549/// - a catalog variant does not match the derived variant for its source name;
533550/// - a class disagrees with the dispatch classification (ordinary vs
534551/// special-call) or with the `__` internal-name prefix;
552+ /// - a non-SQLite entry uses one of the frozen top-u16 SQLite IDs;
535553/// - an ID falls outside its documented block.
536554pub ( crate ) fn validate_catalog_contract (
537555 entries : & [ CatalogEntry ] ,
@@ -564,6 +582,16 @@ pub(crate) fn validate_catalog_contract(
564582 entry. source_name, entry. variant
565583 ) ;
566584 }
585+ if ( SQLITE_RESERVED_TOP_START ..=SQLITE_RESERVED_TOP_END ) . contains ( & entry. id )
586+ && !entry. source_name . starts_with ( "sqlite::" )
587+ {
588+ panic ! (
589+ "builtin '{}' id 0x{:04X} falls in the SQLite-reserved top-u16 range \
590+ 0x{SQLITE_RESERVED_TOP_START:04X}..=0x{SQLITE_RESERVED_TOP_END:04X}; \
591+ do not allocate IDs by arithmetic",
592+ entry. source_name, entry. id
593+ ) ;
594+ }
567595 let is_special_call = special_variants. contains ( & entry. variant ) ;
568596 match entry. class {
569597 CatalogClass :: Ordinary => {
@@ -776,6 +804,11 @@ fn render_builtin_catalog(
776804 . collect :: < Vec < _ > > ( ) ,
777805 ) ) ;
778806
807+ writeln ! (
808+ & mut out,
809+ "// The top-u16 range 0xFFFC..=0xFFFF is reserved for SQLite's frozen IDs; do not allocate it arithmetically."
810+ )
811+ . unwrap ( ) ;
779812 writeln ! (
780813 & mut out,
781814 "#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]"
0 commit comments