File: SqlUiLexer.cpp

package info (click to toggle)
sqlitebrowser 3.10.1-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 10,616 kB
  • sloc: cpp: 89,765; xml: 45; python: 27; sh: 7; makefile: 5
file content (181 lines) | stat: -rw-r--r-- 12,578 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include "SqlUiLexer.h"
#include "Qsci/qsciapis.h"

SqlUiLexer::SqlUiLexer(QObject* parent) :
    QsciLexerSQL(parent)
{
    // Setup auto completion
    autocompleteApi = new QsciAPIs(this);
    setupAutoCompletion();
    autocompleteApi->prepare();

    // Setup folding
    setFoldComments(true);
    setFoldCompact(false);
}

void SqlUiLexer::setupAutoCompletion()
{
    // Set keywords
    QStringList keywordPatterns;
    keywordPatterns
            // Keywords
            << "ABORT" << "ACTION" << "ADD" << "AFTER" << "ALL"
            << "ALTER" << "ANALYZE" << "AND" << "AS" << "ASC"
            << "ATTACH" << "AUTOINCREMENT" << "BEFORE" << "BEGIN" << "BETWEEN"
            << "BY" << "CASCADE" << "CASE" << "CAST" << "CHECK"
            << "COLLATE" << "COLUMN" << "COMMIT" << "CONFLICT" << "CONSTRAINT"
            << "CREATE" << "CROSS" << "CURRENT_DATE" << "CURRENT_TIME" << "CURRENT_TIMESTAMP"
            << "DATABASE" << "DEFAULT" << "DEFERRABLE" << "DEFERRED" << "DELETE"
            << "DESC" << "DETACH" << "DISTINCT" << "DROP" << "EACH"
            << "ELSE" << "END" << "ESCAPE" << "EXCEPT" << "EXCLUSIVE"
            << "EXISTS" << "EXPLAIN" << "FAIL" << "FOR" << "FOREIGN"
            << "FROM" << "FULL" << "GLOB" << "GROUP" << "HAVING"
            << "IF" << "IGNORE" << "IMMEDIATE" << "IN" << "INDEX"
            << "INDEXED" << "INITIALLY" << "INNER" << "INSERT" << "INSTEAD"
            << "INTERSECT" << "INTO" << "IS" << "ISNULL" << "JOIN"
            << "KEY" << "LEFT" << "LIKE" << "LIMIT" << "MATCH"
            << "NATURAL" << "NO" << "NOT" << "NOTNULL" << "NULL"
            << "OF" << "OFFSET" << "ON" << "OR" << "ORDER"
            << "OUTER" << "PLAN" << "PRAGMA" << "PRIMARY" << "QUERY"
            << "RAISE" << "RECURSIVE" << "REFERENCES" << "REGEXP" << "REINDEX" << "RELEASE"
            << "RENAME" << "REPLACE" << "RESTRICT" << "RIGHT" << "ROLLBACK"
            << "ROW" << "SAVEPOINT" << "SELECT" << "SET" << "TABLE"
            << "TEMP" << "TEMPORARY" << "THEN" << "TO" << "TRANSACTION"
            << "TRIGGER" << "UNION" << "UNIQUE" << "UPDATE" << "USING"
            << "VACUUM" << "VALUES" << "VIEW" << "VIRTUAL" << "WHEN"
            << "WHERE" << "WITH" << "WITHOUT"
            // Data types
            << "INT" << "INTEGER" << "REAL" << "TEXT" << "BLOB" << "NUMERIC" << "CHAR";
    foreach(const QString& keyword, keywordPatterns)
    {
        autocompleteApi->add(keyword + "?" + QString::number(ApiCompleterIconIdKeyword));
        autocompleteApi->add(keyword.toLower() + "?" + QString::number(ApiCompleterIconIdKeyword));
    }

    // Functions
    QStringList functionPatterns;
    functionPatterns
            // Core functions
            << "abs" + tr("(X) The abs(X) function returns the absolute value of the numeric argument X.")
            << "changes" + tr("() The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement.")
            << "char" + tr("(X1,X2,...) The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code point values of integers X1 through XN, respectively. ")
            << "coalesce" + tr("(X,Y,...) The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL")
            << "glob" + tr("(X,Y) The glob(X,Y) function is equivalent to the expression \"Y GLOB X\".")
            << "ifnull" + tr("(X,Y) The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL.")
            << "instr" + tr("(X,Y) The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X.")
            << "hex" + tr("(X) The hex() function interprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob.")
            << "last_insert_rowid" + tr("() The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function.")
            << "length" + tr("(X) For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character.")
            << "like" + tr("(X,Y) The like() function is used to implement the \"Y LIKE X\" expression.")
            << "like" + tr("(X,Y,Z) The like() function is used to implement the \"Y LIKE X ESCAPE Z\" expression.")
            << "load_extension" + tr("(X) The load_extension(X) function loads SQLite extensions out of the shared library file named X.")
            << "load_extension" + tr("(X,Y) The load_extension(X) function loads SQLite extensions out of the shared library file named X using the entry point Y.")
            << "lower" + tr("(X) The lower(X) function returns a copy of string X with all ASCII characters converted to lower case.")
            << "ltrim" + tr("(X) ltrim(X) removes spaces from the left side of X.")
            << "ltrim" + tr("(X,Y) The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X.")
            << "max" + tr("(X,Y,...) The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL.")
            << "min" + tr("(X,Y,...) The multi-argument min() function returns the argument with the minimum value.")
            << "nullif" + tr("(X,Y) The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same.")
            << "printf" + tr("(FORMAT,...) The printf(FORMAT,...) SQL function works like the sqlite3_mprintf() C-language function and the printf() function from the standard C library.")
            << "quote" + tr("(X) The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement.")
            << "random" + tr("() The random() function returns a pseudo-random integer between -9223372036854775808 and +9223372036854775807.")
            << "randomblob" + tr("(N) The randomblob(N) function return an N-byte blob containing pseudo-random bytes.")
            << "replace" + tr("(X,Y,Z) The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X.")
            << "round" + tr("(X) The round(X) function returns a floating-point value X rounded to zero digits to the right of the decimal point.")
            << "round" + tr("(X,Y) The round(X,Y) function returns a floating-point value X rounded to Y digits to the right of the decimal point.")
            << "rtrim" + tr("(X) rtrim(X) removes spaces from the right side of X.")
            << "rtrim" + tr("(X,Y) The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X.")
            << "soundex" + tr("(X) The soundex(X) function returns a string that is the soundex encoding of the string X.")
            << "substr" + tr("(X,Y) substr(X,Y) returns all characters through the end of the string X beginning with the Y-th.")
            << "substr" + tr("(X,Y,Z) The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long.")
            << "total_changes" + tr("() The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened.")
            << "trim" + tr("(X) trim(X) removes spaces from both ends of X.")
            << "trim" + tr("(X,Y) The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X.")
            << "typeof" + tr("(X) The typeof(X) function returns a string that indicates the datatype of the expression X.")
            << "unicode" + tr("(X) The unicode(X) function returns the numeric unicode code point corresponding to the first character of the string X.")
            << "upper" + tr("(X) The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent.")
            << "zeroblob" + tr("(N) The zeroblob(N) function returns a BLOB consisting of N bytes of 0x00.")
            // Date and time functions
            << "date" + tr("(timestring,modifier,modifier,...)")
            << "time" + tr("(timestring,modifier,modifier,...)")
            << "datetime" + tr("(timestring,modifier,modifier,...)")
            << "julianday" + tr("(timestring,modifier,modifier,...)")
            << "strftime" + tr("(format,timestring,modifier,modifier,...)")
            // Aggregate functions
            << "avg" + tr("(X) The avg() function returns the average value of all non-NULL X within a group.")
            << "count" + tr("(X) The count(X) function returns a count of the number of times that X is not NULL in a group.")
            << "group_concat" + tr("(X) The group_concat() function returns a string which is the concatenation of all non-NULL values of X.")
            << "group_concat" + tr("(X,Y) The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X.")
            << "max" + tr("(X) The max() aggregate function returns the maximum value of all values in the group.")
            << "min" + tr("(X) The min() aggregate function returns the minimum non-NULL value of all values in the group.")
            << "sum" + tr("(X) The sum() and total() aggregate functions return sum of all non-NULL values in the group.")
            << "total" + tr("(X) The sum() and total() aggregate functions return sum of all non-NULL values in the group.");

    listFunctions.clear();
    foreach(const QString& keyword, functionPatterns)
    {
        QString fn = keyword.left(keyword.indexOf('('));
        QString descr = keyword.mid(keyword.indexOf('('));

        autocompleteApi->add(fn + "?" + QString::number(ApiCompleterIconIdFunction) + descr);
        autocompleteApi->add(fn.toUpper() + "?" + QString::number(ApiCompleterIconIdFunction) + descr);

        // Store all function names in order to highlight them in a different colour
        listFunctions.append(fn);
    }
}

void SqlUiLexer::setTableNames(const TablesAndColumnsMap& tables)
{
    // Update list for auto completion
    autocompleteApi->clear();
    listTables.clear();
    setupAutoCompletion();
    for(auto it=tables.constBegin();it!=tables.constEnd();++it)
    {
        foreach(const QString& field, it.value())
            autocompleteApi->add(it.key() + "?" + QString::number(SqlUiLexer::ApiCompleterIconIdTable) + "." +
                                 field + "?" + QString::number(SqlUiLexer::ApiCompleterIconIdColumn));

        // Store the table name list in order to highlight them in a different colour
        listTables.append(it.key());
    }
    autocompleteApi->prepare();
}

const char* SqlUiLexer::keywords(int set) const
{
    // Function and table names are generated automatically but need to be returned to the calling functions.
    // In order to not have them deleted after this function ends they are stored as static variables. Because
    // the functions list doesn't change after the first call it's initialised here whereas the tables list, which
    // can change, is updated for each call
    static std::string functions = listFunctions.join(" ").toUtf8().constData();
    static std::string tables;

    if(set == 6)            // This corresponds to the QsciLexerSQL::KeywordSet6 style in SqlTextEdit
    {
        tables = listTables.join(" ").toLower().toUtf8().constData();
        return tables.c_str();
    } else if(set == 7) {   // This corresponds to the QsciLexerSQL::KeywordSet7 style in SqlTextEdit
        return functions.c_str();
    } else {
        // For all other keyword sets simply call the parent implementation
        return QsciLexerSQL::keywords(set);
    }
}

QStringList SqlUiLexer::autoCompletionWordSeparators() const
{
    // The only word separator for auto completion in SQL is "." as in "tablename.columnname".
    // Because this isn't implemented in the default QScintilla SQL lexer for some reason we add it here.

    QStringList wl;
    wl << ".";
    return wl;
}

bool SqlUiLexer::caseSensitive() const
{
    return false;
}