Add implementation of the REGEXP operator

When not configured otherwise in the Preferences Dialog register a
SQLite function for performing the regular expression matching which
SQLite doesn't implement. This adds support for the REGEXP operator even
when no extension which implements this is loaded.

See issue #215.
This commit is contained in:
Martin Kleusberg
2015-03-06 12:52:47 +01:00
parent befb60376c
commit 6d1a874f80
3 changed files with 40 additions and 0 deletions

View File

@@ -72,6 +72,7 @@ void PreferencesDialog::loadSettings()
ui->spinLogFontSize->setValue(getSettingsValue("log", "fontsize").toInt());
ui->listExtensions->addItems(getSettingsValue("extensions", "list").toStringList());
ui->checkRegexDisabled->setChecked(getSettingsValue("extensions", "disableregex").toBool());
fillLanguageBox();
}
@@ -100,6 +101,7 @@ void PreferencesDialog::saveSettings()
foreach(QListWidgetItem* item, ui->listExtensions->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard))
extList.append(item->text());
setSettingsValue("extensions", "list", extList);
setSettingsValue("extensions", "disableregex", ui->checkRegexDisabled->isChecked());
// Warn about restarting to change language
QVariant newLanguage = ui->languageComboBox->itemData(ui->languageComboBox->currentIndex());
@@ -233,6 +235,10 @@ QVariant PreferencesDialog::getSettingsDefaultValue(const QString& group, const
if(group == "extensions" && name == "list")
return QStringList();
// extensions/disableregex?
if(group == "extension" && name == "disableregex")
return false;
// Unknown combination of group and name? Return an invalid QVariant!
return QVariant();
}

View File

@@ -498,6 +498,16 @@
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkRegexDisabled">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;While supporting the REGEXP operator SQLite doesn't implement any regular expression&lt;br/&gt;algorithm but calls back the running application. DB Browser for SQLite implements this&lt;br/&gt;algorithm for you to let you use REGEXP out of the box. However, as there are multiple possible&lt;br/&gt;implementations of this and you might want to use another one, you're free to disable the&lt;br/&gt;application's implementation and load your own by using an extension. Requires restart of the application.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Disable Regular Expression extension</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>

View File

@@ -35,6 +35,26 @@ void collation_needed(void* /*pData*/, sqlite3* db, int eTextRep, const char* sC
sqlite3_create_collation(db, sCollationName, eTextRep, NULL, collCompare);
}
static void regexp(sqlite3_context* ctx, int /*argc*/, sqlite3_value* argv[])
{
// Get arguments and check their values
QRegExp arg1((const char*)sqlite3_value_text(argv[0]));
QString arg2((const char*)sqlite3_value_text(argv[1]));
if(!arg1.isValid() || arg2.isNull())
return sqlite3_result_error(ctx, "invalid operand", -1);
// Set the pattern matching syntax to a Perl-like one. This is the default in Qt 4.x but Qt 5
// changes this to a greedy one (QRegExp::RegExp2). To make sure the behaviour of our application
// doesn't change depending on the build environment, we make sure to always set the same pattern
// matching syntax.
arg1.setPatternSyntax(QRegExp::RegExp);
// Perform the actual matching and return the result. Note that Qt's QRegExp returns -1 if the regex
// doesn't match and the position in the string otherwise; SQLite expects a 0 for not found and a 1 for found.
sqlite3_result_int(ctx, arg1.indexIn(arg2) >= 0);
}
bool DBBrowserDB::isOpen ( ) const
{
return _db!=0;
@@ -93,6 +113,10 @@ bool DBBrowserDB::open(const QString& db)
// Enable extension loading
sqlite3_enable_load_extension(_db, 1);
// Register REGEXP function
if(settings.value("/extensions/disableregex", false) == false)
sqlite3_create_function(_db, "REGEXP", 2, SQLITE_UTF8, NULL, regexp, NULL, NULL);
curDBFilename = db;
return true;
} else {