Skip to content

[sqlite3_native_assets] How to enable loading extensions #295

@rodydavis

Description

@rodydavis

I cannot figure out how to add custom extension loading when using the sqlite3_native_assets package and customizing the flags.

Unhandled exception:
SqliteException(21): Could not load extension

For example I added flags to support the SQLite Session extension:

import 'dart:convert';
import 'dart:io';

import 'package:archive/archive.dart';
import 'package:http/http.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart';
import 'package:native_assets_cli/native_assets_cli.dart';
import 'package:native_toolchain_c/native_toolchain_c.dart';

void main(List<String> args) async {
  await build(args, (input, output) async {
    final source = input.outputDirectory.resolve('sqlite3.c');
    final response = await get(
      Uri.parse('https://sqlite.org/2025/sqlite-amalgamation-3490100.zip'),
    );
    if (response.statusCode != 200) {
      throw 'Could not download sqlite3: ${response.statusCode} ${response.reasonPhrase} ${response.body}';
    }
    final archive = ZipDecoder().decodeBytes(response.bodyBytes);
    for (final file in archive) {
      if (posix.basename(file.name) == 'sqlite3.c') {
        await File(source.toFilePath()).writeAsBytes(file.content);
      }
    }

    final builder = CBuilder.library(
      name: 'sqlite3',
      assetName: 'sqlite3_native_assets.dart',
      sources: [source.toFilePath()],
      defines: collectDefines(),
      // flags: ['-lpthread', '-ldl', '-lm'],
    );

    await builder.run(
      input: input,
      // This adds a dependency on sqlite3.c, which confuses dependency tracking
      // because that file was also changed by this build script.
      output: _IgnoreSourceDependency(output),
      logger:
          Logger('')
            ..level = Level.ALL
            ..onRecord.listen((record) => print(record.message)),
    );
  });
}

final class _IgnoreSourceDependency extends BuildOutputBuilder {
  final BuildOutputBuilder _inner;

  _IgnoreSourceDependency(this._inner);

  @override
  EncodedAssetBuildOutputBuilder get assets => _inner.assets;

  @override
  void addDependencies(Iterable<Uri> uris) {
    super.addDependencies(uris.where((e) => url.extension(e.path) != '.c'));
  }
}

// Note: Keep in sync with https://github.com/simolus3/sqlite-native-libraries/blob/master/sqlite3-native-library/cpp/CMakeLists.txt
const _defines = '''
  SQLITE_ENABLE_DBSTAT_VTAB
  SQLITE_ENABLE_FTS5
  SQLITE_ENABLE_RTREE
  SQLITE_DQS=0
  SQLITE_DEFAULT_MEMSTATUS=0
  SQLITE_TEMP_STORE=2
  SQLITE_MAX_EXPR_DEPTH=0
  SQLITE_STRICT_SUBTYPE=1
  SQLITE_OMIT_AUTHORIZATION
  SQLITE_OMIT_DECLTYPE
  SQLITE_OMIT_DEPRECATED
  SQLITE_OMIT_PROGRESS_CALLBACK
  SQLITE_OMIT_SHARED_CACHE
  SQLITE_OMIT_TCL_VARIABLE
  SQLITE_OMIT_TRACE
  SQLITE_USE_ALLOCA
  SQLITE_UNTESTABLE
  SQLITE_HAVE_ISNAN
  SQLITE_HAVE_LOCALTIME_R
  SQLITE_HAVE_LOCALTIME_S
  SQLITE_HAVE_MALLOC_USABLE_SIZE
  SQLITE_HAVE_STRCHRNUL
+  SQLITE_ENABLE_SESSION
+  SQLITE_ENABLE_PREUPDATE_HOOK
''';

Map<String, String?> collectDefines() {
  final entries = <String, String?>{};
  for (final line in const LineSplitter().convert(_defines)) {
    if (line.contains('=')) {
      final [key, value] = line.trim().split('=');
      entries[key] = value;
    } else {
      entries[line.trim()] = null;
    }
  }
  return entries;
}

No matter what flags I add, it still passes the SQLITE_OMIT_LOAD_EXTENSION flag is being included but cannot find it in the source code.

Curious where I should look next to try to debug?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions