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 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
|
#include "querygenerator.h"
#include "common/global.h"
#include "common/utils_sql.h"
#include "db/db.h"
#include "common/unused.h"
QueryGenerator::QueryGenerator()
{
}
QString QueryGenerator::generateSelectFromTable(Db* db, const QString& table, const StrHash<QVariantList> values)
{
return generateSelectFromTable(db, QString(), table, values);
}
QString QueryGenerator::generateSelectFromTable(Db* db, const QString& database, const QString& table, const StrHash<QVariantList> values)
{
SchemaResolver resolver(db);
QStringList columns = resolver.getTableColumns(database, table);
return generateSelectFromTableOrView(db, database, table, columns, values);
}
QString QueryGenerator::generateInsertToTable(Db* db, const QString& table, const StrHash<QVariantList> values)
{
return generateInsertToTable(db, QString(), table, values);
}
QString QueryGenerator::generateInsertToTable(Db* db, const QString& database, const QString& table, StrHash<QVariantList> values)
{
static_qstring(tpl, "INSERT INTO %1 (%2) VALUES %3");
static_qstring(rowTpl, "(%1)");
QString target = toFullObjectName(database, table);
// Get all table's columns
SchemaResolver resolver(db);
QStringList tableCols = resolver.getTableColumns(database, table);
// If no values were given, then column names will serve as values for insertion
if (values.isEmpty())
{
QStringList valueList = wrapStrings(tableCols);
QStringList wrappedCols = wrapObjNamesIfNeeded(tableCols);
return tpl.arg(target, wrappedCols.join(", "), rowTpl.arg(valueList.join(", ")));
}
// Values were given. Sort given columns in order they are defined in table
QStringList valueCols = values.keys();
sortWithReferenceList(valueCols, tableCols);
// Group values into rows
QStringList valueSets = toValueSets(valueCols, values);
QString valueStr = rowTpl.arg(valueSets.join("), ("));
// Wrap given column names
QStringList wrappedCols = wrapObjNamesIfNeeded(valueCols);
return tpl.arg(target, wrappedCols.join(", "), valueStr);
}
QString QueryGenerator::generateUpdateOfTable(Db* db, const QString& table, const StrHash<QVariantList> values)
{
return generateUpdateOfTable(db, QString(), table, values);
}
QString QueryGenerator::generateUpdateOfTable(Db* db, const QString& database, const QString& table, StrHash<QVariantList> values)
{
static_qstring(tpl, "UPDATE %1 SET %2%3");
static_qstring(tplWithWhere, "UPDATE %1 SET %2 WHERE %3");
static_qstring(updateColTpl, "%1 = %2");
QString target = toFullObjectName(database, table);
// Get all columns of the table
SchemaResolver resolver(db);
QStringList tableCols = resolver.getTableColumns(database, table);
// Create list of "column = 'column'"
QStringList commonUpdateCols;
for (const QString& col : tableCols)
commonUpdateCols << updateColTpl.arg(wrapObjIfNeeded(col), wrapString(col));
// Put it to comma spearated string
QString commonColumnStr = commonUpdateCols.join(", ");
// If no values were given, we simply use column names as values everywhere
if (values.isEmpty())
{
QString conditionStr = commonUpdateCols.join(" AND ");
return tplWithWhere.arg(target, commonColumnStr, conditionStr);
}
// If values were given, then they will be used in WHERE clause
QStringList valueCols = values.keys();
sortWithReferenceList(valueCols, tableCols);
// Conditions for WHERE clause
QString conditionStr = valuesToConditionStr(values);
return tpl.arg(target, commonColumnStr, conditionStr);
}
QString QueryGenerator::generateDeleteFromTable(Db* db, const QString& table, const StrHash<QVariantList> values)
{
return generateDeleteFromTable(db, QString(), table, values);
}
QString QueryGenerator::generateDeleteFromTable(Db* db, const QString& database, const QString& table, StrHash<QVariantList> values)
{
static_qstring(tpl, "DELETE FROM %1%2");
static_qstring(tplWithWhere, "DELETE FROM %1 WHERE %2");
static_qstring(conditionColTpl, "%1 = %2");
QString target = toFullObjectName(database, table);
// Get all columns of the table
SchemaResolver resolver(db);
QStringList tableCols = resolver.getTableColumns(database, table);
// If no values were given, we simply use column names as values everywhere
if (values.isEmpty())
{
// Create list of "column = 'column'"
QStringList conditionCols;
for (const QString& col : tableCols)
conditionCols << conditionColTpl.arg(wrapObjIfNeeded(col), wrapString(col));
// Put it to comma spearated string
QString conditionStr = conditionCols.join(" AND ");
return tplWithWhere.arg(target, conditionStr);
}
// If values were given, then they will be used in WHERE clause
QStringList valueCols = values.keys();
sortWithReferenceList(valueCols, tableCols);
// Conditions for WHERE clause
QString conditionStr = valuesToConditionStr(values);
return tpl.arg(target, conditionStr);
}
QString QueryGenerator::generateSelectFromView(Db* db, const QString& view, const StrHash<QVariantList> values)
{
return generateSelectFromView(db, QString(), view, values);
}
QString QueryGenerator::generateSelectFromView(Db* db, const QString& database, const QString& view, const StrHash<QVariantList> values)
{
SchemaResolver resolver(db);
QStringList columns = resolver.getViewColumns(database, view);
return generateSelectFromTableOrView(db, database, view, columns, values);
}
QString QueryGenerator::generateSelectFromSelect(Db* db, const QString& initialSelect, const StrHash<QVariantList> values, const BiStrHash& dbNameToAttach)
{
static_qstring(tpl, "SELECT %1 FROM (%2)%3");
// Resolve all columns of the select
QList<SelectResolver::Column> columns = SelectResolver::sqliteResolveColumns(db, initialSelect, dbNameToAttach);
// Generate result columns
QStringList resCols;
for (const SelectResolver::Column& col : columns)
resCols << toResultColumnString(col);
// Generate conditions for WHERE clause
QString conditionStr = valuesToConditionStr(values);
return tpl.arg(resCols.join(", "), initialSelect, conditionStr);
}
QString QueryGenerator::generateSelectFromTableOrView(Db* db, const QString& database, const QString& tableOrView, const QStringList& columns, const StrHash<QVariantList> values)
{
UNUSED(db);
static_qstring(tpl, "SELECT %1 FROM %2%3");
QStringList wrappedCols = wrapObjNamesIfNeeded(columns);
QString target = toFullObjectName(database, tableOrView);
QString conditionStr = valuesToConditionStr(values);
return tpl.arg(wrappedCols.join(", "), target, conditionStr);
}
QString QueryGenerator::getAlias(const QString& name, QSet<QString>& usedAliases)
{
static_qstring(tpl, "%2%1");
QString letter;
if (name.length() == 0)
letter = "t";
else
letter = name[0];
QString alias = letter + "1";
int i = 2;
while (usedAliases.contains(alias))
alias = tpl.arg(i++).arg(letter);
usedAliases << alias;
return alias;
}
QStringList QueryGenerator::valuesToConditionList(const StrHash<QVariantList>& values)
{
static_qstring(conditionTpl0, "%1 IS NULL");
static_qstring(conditionTpl1, "%1 = %2");
static_qstring(conditionTpl2, "%1 IN (%2)");
QStringList conditions;
QStringList conditionValues;
for (const QString& col : values.keys())
{
conditionValues = valueListToSqlList(values[col]);
conditionValues.removeDuplicates();
if (conditionValues.size() == 1)
{
if (conditionValues.first() == "NULL")
conditions << conditionTpl0.arg(wrapObjIfNeeded(col));
else
conditions << conditionTpl1.arg(wrapObjIfNeeded(col), conditionValues.first());
}
else
conditions << conditionTpl2.arg(wrapObjIfNeeded(col), conditionValues.join(", "));
}
return conditions;
}
QString QueryGenerator::valuesToConditionStr(const StrHash<QVariantList>& values)
{
static_qstring(condTpl, " WHERE %1");
QStringList conditions = valuesToConditionList(values);
QString conditionStr = "";
if (conditions.size() > 0)
conditionStr = condTpl.arg(conditions.join(" AND "));
return conditionStr;
}
QString QueryGenerator::toResultColumnString(const SelectResolver::Column& column)
{
return wrapObjIfNeeded(column.displayName);
}
QString QueryGenerator::toFullObjectName(const QString& database, const QString& object)
{
static_qstring(tpl, "%1%2");
QString dbName = "";
if (!database.isEmpty() && dbName.toLower() != "main")
dbName = wrapObjIfNeeded(database);
if (!dbName.isEmpty())
dbName.append(".");
return tpl.arg(dbName, wrapObjIfNeeded(object));
}
QStringList QueryGenerator::toValueSets(const QStringList& columns, const StrHash<QVariantList> values)
{
QStringList rows;
QVariantList rowValues;
QStringList valueList;
for (int total = values.values().first().size(), i = 0; i < total; i++)
{
rowValues.clear();
for (const QString& col : columns)
rowValues << values[col][i];
valueList = valueListToSqlList(rowValues);
rows << valueList.join(", ");
}
return rows;
}
|