Skip to content

Bug: jieba_dict_dir parameter value is lowercased, breaking case-sensitive filesystem paths #37

Description

@qtchen-vault

Bug: jieba_dict_dir parameter value is lowercased, breaking case-sensitive filesystem paths

LadybugDB version

v0.19.0 (also present in the extensions repo HEAD)

What happened?

When using the FTS extension with tokenizer:='jieba', the jieba_dict_dir parameter is silently lowercased before being used to open the dictionary files. On case-sensitive filesystems (Linux), this makes the parameter unusable for any path containing ASCII uppercase letters, and crashes the process with a hard FATAL abort (not a recoverable exception).

Repro (Node.js binding, but the root cause is in the shared extension code):

INSTALL fts;
LOAD fts;
CREATE NODE TABLE Chunk (id INT64 PRIMARY KEY, content STRING);
CALL CREATE_FTS_INDEX('Chunk', 'c1', ['content'],
  tokenizer:='jieba',
  jieba_dict_dir:='/some/path/With-Uppercase');  -- valid, exists, contains jieba dicts

Process aborts with:

.../third_party/cppjieba/include/cppjieba/DictTrie.hpp:206 FATAL exp: [ifs.is_open()] false.
open /some/path/with-uppercase/jieba.dict.utf8 failed.

Note the path With-Uppercase was opened as with-uppercase.

I also verified that paths containing Chinese characters, digits, -, and _ work fine — only ASCII uppercase letters are affected (they get mapped to lowercase).

Root cause

In fts/src/function/fts_config.cpp (CreateFTSConfig constructor):

} else if (lowerCaseName == "jieba_dict_dir") {
    value.validateType(common::LogicalTypeID::STRING);
    tokenizerInfo.jiebaDictDir =
        common::StringUtils::getLower(value.getValue<std::string>());
}

The value of jieba_dict_dir is passed through common::StringUtils::getLower(). That helper is a Unicode-aware lowercase conversion (changeCaseBaseLowerUpperFunction with utf8proc), so it maps every ASCII A-Z to a-z.

Other parameters in this same block legitimately lowercase their values because they are case-insensitive enums/patterns (stemmer, ignore_pattern, tokenizer). But jieba_dict_dir is a filesystem path, and on case-sensitive filesystems (Linux, and anywhere a mount is case-sensitive) lowercasing a path changes which directory/file is opened. The default value in fts_config.h happens to be lowercase so the shipped default works, but any user-supplied path with uppercase letters breaks.

Expected behavior

jieba_dict_dir should be used verbatim (no case transformation), like any other path parameter.

Suggested fix

Remove the getLower call for the jieba_dict_dir case:

} else if (lowerCaseName == "jieba_dict_dir") {
    value.validateType(common::LogicalTypeID::STRING);
    tokenizerInfo.jiebaDictDir = value.getValue<std::string>();
}

Additional observations

  • The failure is a FATAL process abort in cppjieba (DictTrie.hpp:206, exp: [ifs.is_open()] false), not a catchable exception. Even with the lowercasing fixed, a genuinely missing dictionary directory will still hard-crash the host process. Consider validating the directory up front and raising a proper BinderException/RuntimeException instead.
  • Same family of issues as #588 (create-time vs runtime tokenization contract), but distinct: this one is a pure path mangling bug.
  • Verification performed against the prebuilt @ladybugdb/core-linux-x64 v0.19.0 Node.js binding and the extensions repo source (fts_config.cpp).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions