Skip to content

Commit 37aaa4c

Browse files
committed
Avoid using std::regex for now
It turned out that on some platforms we still aim to support the stdlib had not yet implemented std::regex. For this reason we want to avoid using it for now. In the particular use cases here it was also not the best solution. It was faster to write using a regular expression instead of a hand coded loop but clearly a simple loop should be more efficient here. See issue #1873.
1 parent d87f253 commit 37aaa4c

File tree

3 files changed

+76
-16
lines changed

3 files changed

+76
-16
lines changed

src/sql/ObjectIdentifier.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
#include "ObjectIdentifier.h"
22

3-
#include <regex>
3+
static std::string duplicate_char(std::string str, char to_replace)
4+
{
5+
size_t pos = 0;
6+
while((pos = str.find(to_replace, pos)) != std::string::npos)
7+
{
8+
str.insert(pos, 1, to_replace);
9+
pos += 2; // Advance by two characters in order to avoid escaping a character multiple times
10+
}
11+
return str;
12+
}
413

514
namespace sqlb {
615

@@ -15,7 +24,7 @@ std::string escapeIdentifier(const std::string& id)
1524
{
1625
switch(customQuoting) {
1726
case GraveAccents:
18-
return '`' + std::regex_replace(id, std::regex("\\`"), std::string("``")) + '`';
27+
return '`' + duplicate_char(id, '`') + '`';
1928
case SquareBrackets:
2029
// There aren't any escaping possibilities for square brackets inside the identifier,
2130
// so we rely on the user to not enter these characters when this kind of quoting is
@@ -26,7 +35,7 @@ std::string escapeIdentifier(const std::string& id)
2635
// This may produce a 'control reaches end of non-void function' warning if the
2736
// default branch is removed, even though we have covered all possibilities in the
2837
// switch statement.
29-
return '"' + std::regex_replace(id, std::regex("\\\""), std::string("\"\"")) + '"';
38+
return '"' + duplicate_char(id, '"') + '"';
3039
}
3140
}
3241

src/sql/sqlitetypes.cpp

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,18 @@
66
#include <sstream>
77
#include <iostream>
88
#include <clocale> // This include seems to only be necessary for the Windows build
9-
#include <regex>
109
#include <numeric>
1110

11+
namespace {
12+
bool starts_with_ci(const std::string& str, const std::string& with)
13+
{
14+
if(str.size() < with.size())
15+
return false;
16+
else
17+
return compare_ci(str.substr(0, with.size()), with);
18+
}
19+
}
20+
1221
namespace sqlb {
1322

1423
StringVector escapeIdentifier(StringVector ids)
@@ -235,32 +244,55 @@ std::string Field::toString(const std::string& indent, const std::string& sep) c
235244

236245
bool Field::isText() const
237246
{
238-
std::regex is_text("(^(character|varchar|varying character|nchar|native character|nvarchar))|(^(text|clob)$)", std::regex::icase);
239-
return std::regex_match(m_type, is_text);
247+
if(starts_with_ci(m_type, "character")) return true;
248+
if(starts_with_ci(m_type, "varchar")) return true;
249+
if(starts_with_ci(m_type, "varying character")) return true;
250+
if(starts_with_ci(m_type, "nchar")) return true;
251+
if(starts_with_ci(m_type, "native character")) return true;
252+
if(starts_with_ci(m_type, "nvarchar")) return true;
253+
if(compare_ci(m_type, "text")) return true;
254+
if(compare_ci(m_type, "clob")) return true;
255+
return false;
240256
}
241257

242258
bool Field::isInteger() const
243259
{
244-
std::regex is_integer("^(int|integer|tinyint|smallint|mediumint|bigint|unsigned big int|int2|int8)$", std::regex::icase);
245-
return std::regex_match(m_type, is_integer);
260+
if(compare_ci(m_type, "int")) return true;
261+
if(compare_ci(m_type, "integer")) return true;
262+
if(compare_ci(m_type, "tinyint")) return true;
263+
if(compare_ci(m_type, "smallint")) return true;
264+
if(compare_ci(m_type, "mediumint")) return true;
265+
if(compare_ci(m_type, "bigint")) return true;
266+
if(compare_ci(m_type, "unsigned big int")) return true;
267+
if(compare_ci(m_type, "int2")) return true;
268+
if(compare_ci(m_type, "int8")) return true;
269+
return false;
246270
}
247271

248272
bool Field::isReal() const
249273
{
250-
std::regex is_real("^(real|double|double precision|float)$", std::regex::icase);
251-
return std::regex_match(m_type, is_real);
274+
if(compare_ci(m_type, "real")) return true;
275+
if(compare_ci(m_type, "double")) return true;
276+
if(compare_ci(m_type, "double precision")) return true;
277+
if(compare_ci(m_type, "float")) return true;
278+
return false;
252279
}
253280

254281
bool Field::isNumeric() const
255282
{
256-
std::regex is_numeric("(^(decimal))|(^(numeric|boolean|date|datetime)$)", std::regex::icase);
257-
return std::regex_match(m_type, is_numeric);
283+
if(starts_with_ci(m_type, "decimal")) return true;
284+
if(compare_ci(m_type, "numeric")) return true;
285+
if(compare_ci(m_type, "boolean")) return true;
286+
if(compare_ci(m_type, "date")) return true;
287+
if(compare_ci(m_type, "datetime")) return true;
288+
return false;
258289
}
259290

260291
bool Field::isBlob() const
261292
{
262-
std::regex is_blob("(^$)|(^blob$)", std::regex::icase);
263-
return std::regex_match(m_type, is_blob);
293+
if(m_type.empty()) return true;
294+
if(compare_ci(m_type, "blob")) return true;
295+
return false;
264296
}
265297

266298
std::string Field::affinity() const
@@ -591,6 +623,19 @@ void Table::renameKeyInAllConstraints(const std::string& key, const std::string&
591623

592624
namespace
593625
{
626+
std::string unescape_identifier(std::string str, char quote_char)
627+
{
628+
std::string quote(2, quote_char);
629+
630+
size_t pos = 0;
631+
while((pos = str.find(quote, pos)) != std::string::npos)
632+
{
633+
str.erase(pos, 1);
634+
pos += 1; // Don't remove the other quote char too
635+
}
636+
return str;
637+
}
638+
594639
std::string identifier(antlr::RefAST ident)
595640
{
596641
std::string sident = ident->getText();
@@ -599,7 +644,7 @@ std::string identifier(antlr::RefAST ident)
599644
ident->getType() == sqlite3TokenTypes::STRINGLITERAL)
600645
{
601646
// Remember the way the identifier is quoted
602-
std::string quoteChar(1, sident.at(0));
647+
char quoteChar = sident.at(0);
603648

604649
// Remove first and final character, i.e. the quotes
605650
sident = sident.substr(1, sident.size() - 2);
@@ -608,7 +653,7 @@ std::string identifier(antlr::RefAST ident)
608653
// by a single instance. This is done because two quotes can be used as a means of escaping
609654
// the quote character, thus only the visual representation has its two quotes, the actual
610655
// name contains only one.
611-
sident = std::regex_replace(sident, std::regex("\\" + quoteChar + "\\" + quoteChar), quoteChar);
656+
sident = unescape_identifier(sident, quoteChar);
612657
}
613658

614659
return sident;

src/sql/sqlitetypes.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ bool compare_ci(const T& a, const T& b)
2424
});
2525
}
2626

27+
template<typename T>
28+
bool compare_ci(const T& a, const char* b)
29+
{
30+
return compare_ci(a, std::string(b));
31+
}
32+
2733
namespace sqlb {
2834

2935
using StringVector = std::vector<std::string>;

0 commit comments

Comments
 (0)