QString DbFunc::makeCreationSqlFromPragmaInfo( const QString& tablename, const QList<SqlitePragmaInfoField>& infolist) { QStringList fieldspecs; const int size = infolist.size(); for (int i = 0; i < size; ++i) { const SqlitePragmaInfoField& info = infolist.at(i); QStringList elements; elements.append(delimit(info.name)); elements.append(info.type); if (info.notnull) { elements.append("NOT NULL"); } if (!info.dflt_value.isNull()) { elements.append("DEFAULT " + info.dflt_value.toString()); // default value already delimited by SQLite } if (info.pk) { elements.append("PRIMARY KEY"); } fieldspecs.append(elements.join(" ")); } return QString("CREATE TABLE IF NOT EXISTS %1 (%2)").arg( delimit(tablename), fieldspecs.join(", ")); }
static int __init tipc_init(void) { int res; tipc_log_resize(CONFIG_TIPC_LOG); info("Activated (version " TIPC_MOD_VER " compiled " __DATE__ " " __TIME__ ")\n"); tipc_own_addr = 0; tipc_remote_management = 1; tipc_max_publications = 10000; tipc_max_subscriptions = 2000; tipc_max_ports = delimit(CONFIG_TIPC_PORTS, 127, 65536); tipc_max_zones = delimit(CONFIG_TIPC_ZONES, 1, 255); tipc_max_clusters = delimit(CONFIG_TIPC_CLUSTERS, 1, 1); tipc_max_nodes = delimit(CONFIG_TIPC_NODES, 8, 2047); tipc_max_slaves = delimit(CONFIG_TIPC_SLAVE_NODES, 0, 2047); tipc_net_id = 4711; if ((res = tipc_core_start())) err("Unable to start in single node mode\n"); else info("Started in single node mode\n"); return res; }
void DbFunc::changeColumnTypes(const QSqlDatabase& db, const QString& tablename, const QList<QPair<QString, QString>>& changes, const QString& tempsuffix) { // changes: pairs <fieldname, newtype> if (!tableExists(db, tablename)) { qWarning() << "WARNING: ignoring changeColumnTypes for non-existent " "table:" << tablename; return; } QString dummytable = tablename + tempsuffix; if (tableExists(db, dummytable)) { UiFunc::stopApp("DbFunc::changeColumnTypes: temporary table exists: " + dummytable); } QList<SqlitePragmaInfoField> infolist = getPragmaInfo(db, tablename); qDebug() << "changeColumnTypes"; qDebug() << "- pragma info:" << infolist; qDebug() << "- changes:" << changes; int n_changes = 0; for (int i = 0; i < changes.size(); ++i) { QString changefield = changes.at(i).first; for (int j = 0; i < infolist.size(); ++j) { SqlitePragmaInfoField& info = infolist[j]; if (changefield.compare(info.name, Qt::CaseInsensitive) == 0) { QString newtype = changes.at(i).second; info.type = newtype; ++n_changes; } } } if (n_changes == 0) { qDebug() << "... nothing to do"; return; } QString creation_sql = makeCreationSqlFromPragmaInfo(tablename, infolist); QString fieldnames = fieldNamesFromPragmaInfo(infolist, true).join(","); QString delimited_tablename = delimit(tablename); QString delimited_dummytable = delimit(dummytable); exec(db, "BEGIN TRANSACTION"); exec(db, QString("ALTER TABLE %1 RENAME TO %2").arg(delimited_tablename, delimited_dummytable)); exec(db, creation_sql); // make a new clean table exec(db, QString("INSERT INTO %1 (%2) SELECT %3 FROM %4").arg( delimited_tablename, fieldnames, fieldnames, delimited_dummytable)); exec(db, QString("DROP TABLE %1").arg(delimited_dummytable)); commit(db); }
static __u32 str2addr(char *str) { uint z, c, n; char dummy; if (sscanf(str, "%u.%u.%u%c", &z, &c, &n, &dummy) != 3) fatal("invalid network address, use syntax: Z.C.N\n"); if ((z != delimit(z, 0, 255)) || (c != delimit(c, 0, 4095)) || (n != delimit(n, 0, 4095))) fatal("network address field value(s) too large\n"); return tipc_addr(z, c, n); }
QString DbFunc::sqlCreateTable(const QString& tablename, const QList<Field>& fieldlist) { QStringList coldefs; for (int i = 0; i < fieldlist.size(); ++i) { const Field& field = fieldlist.at(i); QString coltype = field.sqlColumnDef(); coldefs << QString("%1 %2").arg(delimit(field.name()), coltype); } QString sql = QString("CREATE TABLE IF NOT EXISTS %1 (%2)").arg( delimit(tablename), coldefs.join(", ")); return sql; }
bool DbFunc::createIndex(const QSqlDatabase& db, const QString& indexname, const QString& tablename, QStringList fieldnames) { if (!tableExists(db, tablename)) { qWarning() << "WARNING: ignoring createIndex for non-existent table:" << tablename; return false; } for (int i = 0; i < fieldnames.size(); ++i) { fieldnames[i] = delimit(fieldnames[i]); } QString sql = QString("CREATE INDEX IF NOT EXISTS %1 ON %2 (%3)").arg( delimit(indexname), delimit(tablename), fieldnames.join("")); return exec(db, sql); }
int DbFunc::count(const QSqlDatabase& db, const QString& tablename, const WhereConditions& where) { SqlArgs sqlargs("SELECT COUNT(*) FROM " + delimit(tablename)); addWhereClause(where, sqlargs); return dbFetchInt(db, sqlargs, 0); }
static struct sk_buff *cfg_set_max_clusters(void) { u32 value; if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value != delimit(value, 1, 1)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (max clusters fixed at 1)"); return tipc_cfg_reply_none(); }
static struct sk_buff *cfg_set_max_subscriptions(void) { u32 value; if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value != delimit(value, 1, 65535)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (max subscriptions must be 1-65535"); tipc_max_subscriptions = value; return tipc_cfg_reply_none(); }
struct sk_buff *tipc_log_resize(const void *req_tlv_area, int req_tlv_space) { u32 value; if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value != delimit(value, 0, 32768)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (log size must be 0-32768)"); tipc_log_reinit(value); return tipc_cfg_reply_none(); }
QStringList DbFunc::fieldNamesFromPragmaInfo( const QList<SqlitePragmaInfoField>& infolist, bool delimited) { QStringList fieldnames; const int size = infolist.size(); for (int i = 0; i < size; ++i) { QString name = infolist.at(i).name; if (delimited) { name = delimit(name); } fieldnames.append(name); } return fieldnames; }
void DbFunc::addWhereClause(const WhereConditions& where, SqlArgs& sqlargs_altered) { if (where.isEmpty()) { return; } QStringList whereclauses; QMapIterator<QString, QVariant> it(where); while (it.hasNext()) { it.next(); QString wherefield = it.key(); QVariant wherevalue = it.value(); whereclauses.append(delimit(wherefield) + "=?"); sqlargs_altered.args.append(wherevalue); } sqlargs_altered.sql += " WHERE " + whereclauses.join(" AND "); }
static struct sk_buff *cfg_set_netid(void) { u32 value; if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value == tipc_net_id) return tipc_cfg_reply_none(); if (value != delimit(value, 1, 9999)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (network id must be 1-9999)"); if (tipc_mode == TIPC_NET_MODE) return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED " (cannot change network id once TIPC has joined a network)"); tipc_net_id = value; return tipc_cfg_reply_none(); }
static struct sk_buff *cfg_set_max_ports(void) { u32 value; if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); if (value == tipc_max_ports) return tipc_cfg_reply_none(); if (value != delimit(value, 127, 65535)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (max ports must be 127-65535)"); if (tipc_mode != TIPC_NOT_RUNNING) return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED " (cannot change max ports while TIPC is active)"); tipc_max_ports = value; return tipc_cfg_reply_none(); }
static struct sk_buff *cfg_set_max_nodes(void) { u32 value; if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); value = *(u32 *)TLV_DATA(req_tlv_area); value = ntohl(value); if (value == tipc_max_nodes) return tipc_cfg_reply_none(); if (value != delimit(value, 8, 2047)) return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE " (max nodes must be 8-2047)"); if (tipc_mode == TIPC_NET_MODE) return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED " (cannot change max nodes once TIPC has joined a network)"); tipc_max_nodes = value; return tipc_cfg_reply_none(); }
QList<SqlitePragmaInfoField> DbFunc::getPragmaInfo(const QSqlDatabase& db, const QString& tablename) { QString sql = QString("PRAGMA table_info(%1)").arg(delimit(tablename)); QSqlQuery query(db); if (!execQuery(query, sql)) { UiFunc::stopApp("DbFunc::getPragmaInfo: PRAGMA table_info failed for " "table " + tablename); } QList<SqlitePragmaInfoField> infolist; while (query.next()) { SqlitePragmaInfoField fieldinfo; fieldinfo.cid = query.value(0).toInt(); // column ID fieldinfo.name = query.value(1).toString(); fieldinfo.type = query.value(2).toString(); fieldinfo.notnull = query.value(3).toBool(); fieldinfo.dflt_value = query.value(4); fieldinfo.pk = query.value(5).toBool(); infolist.append(fieldinfo); } return infolist; }
bool xs::pipe_t::check_read () { if (unlikely (!in_active || (state != active && state != pending))) return false; // Check if there's an item in the pipe. if (!inpipe->check_read ()) { in_active = false; return false; } // If the next item in the pipe is message delimiter, // initiate termination process. if (inpipe->probe (is_delimiter)) { msg_t msg; bool ok = inpipe->read (&msg); xs_assert (ok); delimit (); return false; } return true; }
bool xs::pipe_t::read (msg_t *msg_) { if (unlikely (!in_active || (state != active && state != pending))) return false; if (!inpipe->read (msg_)) { in_active = false; return false; } // If delimiter was read, start termination process of the pipe. if (msg_->is_delimiter ()) { delimit (); return false; } if (!(msg_->flags () & msg_t::more)) msgs_read++; if (lwm > 0 && msgs_read % lwm == 0) send_activate_write (peer, msgs_read); return true; }
void contdisp_parser_t::parse_guts () { abuf_stat_t r = ABUF_OK; bool inc; bool flag = true; while (r == ABUF_OK && flag) { OKDBG4(SVC_MPFD, CHATTER, "contdisp_parser_t::parse_guts loop " "r=%d, state=%d", int (r), int (state)); inc = true; switch (state) { case CONTDISP_START: r = delimit (&typ_scr, ';', true, true); break; case CONTDISP_SEP1: r = abuf->skip_hws (1); if (mystrcmp (typ_scr.cstr(), "form-data")) { typ = CONTDISP_FORMDAT; } else if (mystrcmp (typ_scr.cstr(), "attachment")) { state = CONTDISP_FILENAME_KEY; inc = true; typ = CONTDISP_ATTACH; } break; case CONTDISP_NAME_KEY: r = force_match ("name=\""); break; case CONTDISP_NAME_VAL: r = delimit (&name, '"', false, true); break; case CONTDISP_SEP2A: r = eol (); if (r == ABUF_OK) flag = false; else if (r == ABUF_NOMATCH) r = ABUF_OK; break; case CONTDISP_SEP2B: r = abuf->requirechar (';'); break; case CONTDISP_SEP2C: r = abuf->skip_hws (); break; case CONTDISP_FILENAME_KEY: r = force_match ("filename=\""); break; case CONTDISP_FILENAME_VAL: r = delimit (&filename_scr, '\r', false, false); if (r == ABUF_PARSE_ERR) r = ABUF_OK; // found '\n' before '\r' -- that's OK if (r == ABUF_OK) { filename = str (filename_scr.cstr (), filename_scr.len () - 1); flag = false; } break; default: break; } if (r == ABUF_OK && inc) state = static_cast<contdisp_state_t> (state + 1); } OKDBG4(SVC_MPFD, CHATTER, "contdisp_parser_t::parse_guts exit loop " "r=%d, state=%d", int (r), int (state)); switch (r) { case ABUF_OK: finish_parse (HTTP_OK); break; case ABUF_EOF: case ABUF_PARSE_ERR: finish_parse (HTTP_BAD_REQUEST); break; default: break; } }
int main(int argc, const char * const *argv) { int help = 0, version = 0, hang = 0, prefix = -1, repeat = 0, suffix = -1, Tab = 1, width = 72, body = 0, cap = 0, div = 0, Err = 0, expel = 0, fit = 0, guess = 0, invis = 0, just = 0, last = 0, quote = 0, Report = 0, touch = -1; int prefixbak, suffixbak, c, sawnonblank, oweblank, n, i, afp, fs; charset *bodychars = NULL, *protectchars = NULL, *quotechars = NULL; char *parinit = NULL, *arg, **inlines = NULL, **endline, **firstline, *end, **nextline, **outlines = NULL, **line; const char *env, * const whitechars = " \f\n\r\t\v"; errmsg_t errmsg = { '\0' }; lineprop *props = NULL, *firstprop, *nextprop; FILE *errout; /* Process environment variables: */ env = getenv("PARBODY"); if (!env) env = ""; bodychars = parsecharset(env,errmsg); if (*errmsg) { help = 1; goto parcleanup; } env = getenv("PARPROTECT"); if (!env) env = ""; protectchars = parsecharset(env,errmsg); if (*errmsg) { help = 1; goto parcleanup; } env = getenv("PARQUOTE"); if (!env) env = "> "; quotechars = parsecharset(env,errmsg); if (*errmsg) { help = 1; goto parcleanup; } env = getenv("PARINIT"); if (env) { parinit = malloc((strlen(env) + 1) * sizeof (char)); if (!parinit) { strcpy(errmsg,outofmem); goto parcleanup; } strcpy(parinit,env); arg = strtok(parinit,whitechars); while (arg) { parsearg(arg, &help, &version, bodychars, protectchars, quotechars, &hang, &prefix, &repeat, &suffix, &Tab, &width, &body, &cap, &div, &Err, &expel, &fit, &guess, &invis, &just, &last, "e, &Report, &touch, errmsg ); if (*errmsg || help || version) goto parcleanup; arg = strtok(NULL,whitechars); } free(parinit); parinit = NULL; } /* Process command line arguments: */ while (*++argv) { parsearg(*argv, &help, &version, bodychars, protectchars, quotechars, &hang, &prefix, &repeat, &suffix, &Tab, &width, &body, &cap, &div, &Err, &expel, &fit, &guess, &invis, &just, &last, "e, &Report, &touch, errmsg ); if (*errmsg || help || version) goto parcleanup; } if (Tab == 0) { strcpy(errmsg, "<Tab> must not be 0.\n"); goto parcleanup; } if (touch < 0) touch = fit || last; prefixbak = prefix; suffixbak = suffix; /* Main loop: */ for (sawnonblank = oweblank = 0; ; ) { for (;;) { c = getchar(); if (expel && c == '\n') { oweblank = sawnonblank; continue; } if (csmember((char) c, protectchars)) { sawnonblank = 1; if (oweblank) { putchar('\n'); oweblank = 0; } while (c != '\n' && c != EOF) { putchar(c); c = getchar(); } } if (c != '\n') break; putchar(c); } if (c == EOF) break; ungetc(c,stdin); inlines = readlines(&props, protectchars, quotechars, Tab, invis, quote, errmsg); if (*errmsg) goto parcleanup; for (endline = inlines; *endline; ++endline); if (endline == inlines) { free(inlines); inlines = NULL; continue; } sawnonblank = 1; if (oweblank) { putchar('\n'); oweblank = 0; } delimit((const char * const *) inlines, (const char * const *) endline, bodychars, repeat, body, div, 0, 0, props); if (expel) marksuperf((const char * const *) inlines, (const char * const *) endline, props); firstline = inlines, firstprop = props; do { if (isbodiless(firstprop)) { if (!isinvis(firstprop) && !(expel && issuperf(firstprop))) { for (end = *firstline; *end; ++end); if (!repeat || firstprop->rc == ' ' && !firstprop->s) { while (end > *firstline && end[-1] == ' ') --end; *end = '\0'; puts(*firstline); } else { n = width - firstprop->p - firstprop->s; if (n < 0) { sprintf(errmsg,impossibility,5); goto parcleanup; } printf("%.*s", firstprop->p, *firstline); for (i = n; i; --i) putchar(firstprop->rc); puts(end - firstprop->s); } } ++firstline, ++firstprop; continue; } for (nextline = firstline + 1, nextprop = firstprop + 1; nextline < endline && !isbodiless(nextprop) && !isfirst(nextprop); ++nextline, ++nextprop); prefix = prefixbak, suffix = suffixbak; setaffixes((const char * const *) firstline, (const char * const *) nextline, firstprop, bodychars, quotechars, hang, body, quote, &afp, &fs, &prefix, &suffix); if (width <= prefix + suffix) { sprintf(errmsg, "<width> (%d) <= <prefix> (%d) + <suffix> (%d)\n", width, prefix, suffix); goto parcleanup; } outlines = reformat((const char * const *) firstline, (const char * const *) nextline, afp, fs, hang, prefix, suffix, width, cap, fit, guess, just, last, Report, touch, errmsg); if (*errmsg) goto parcleanup; for (line = outlines; *line; ++line) puts(*line); freelines(outlines); outlines = NULL; firstline = nextline, firstprop = nextprop; } while (firstline < endline); freelines(inlines); inlines = NULL; free(props); props = NULL; } parcleanup: if (bodychars) freecharset(bodychars); if (protectchars) freecharset(protectchars); if (quotechars) freecharset(quotechars); if (parinit) free(parinit); if (inlines) freelines(inlines); if (props) free(props); if (outlines) freelines(outlines); errout = Err ? stderr : stdout; if (*errmsg) fprintf(errout, "par error:\n%.*s", errmsg_size, errmsg); if (version) fputs("par 1.50\n",errout); if (help) fputs(usagemsg,errout); return *errmsg ? EXIT_FAILURE : EXIT_SUCCESS; }
void DbFunc::renameColumns(const QSqlDatabase& db, QString tablename, const QList<QPair<QString, QString>>& from_to, const QString& tempsuffix) { if (!tableExists(db, tablename)) { qWarning() << "WARNING: ignoring renameColumns for non-existent table:" << tablename; return; } QString creation_sql = dbTableDefinitionSql(db, tablename); QStringList old_fieldnames = dbFieldNames(db, tablename); QStringList new_fieldnames = old_fieldnames; QString dummytable = tablename + tempsuffix; if (tableExists(db, dummytable)) { UiFunc::stopApp("DbFunc::renameColumns: temporary table exists: " + dummytable); } int n_changes = 0; for (int i = 0; i < from_to.size(); ++i) { // For each rename... QString from = from_to.at(i).first; QString to = from_to.at(i).second; if (from == to) { continue; } // Check the source is valid if (!old_fieldnames.contains(from)) { UiFunc::stopApp("DbFunc::renameColumns: 'from' field doesn't " "exist: " + tablename + "." + from); } // Check the destination doesn't exist already if (new_fieldnames.contains(to)) { UiFunc::stopApp( "DbFunc::renameColumns: destination field already exists (or " "attempt to rename two columns to the same name): " + tablename + "." + to); } // Rename the fieldname in the new_fieldnames list, and in the SQL new_fieldnames[new_fieldnames.indexOf(from)] = to; creation_sql.replace(delimit(from), delimit(to)); ++n_changes; } if (n_changes == 0) { qDebug() << "renameColumns: nothing to do:" << tablename; return; } qDebug() << Q_FUNC_INFO; qDebug() << "- table:" << tablename; qDebug() << "- from_to:" << from_to; qDebug() << "- old_fieldnames:" << old_fieldnames; qDebug() << "- new_fieldnames:" << new_fieldnames; // Delimit everything QString delimited_tablename = delimit(tablename); QString delimited_dummytable = delimit(dummytable); for (int i = 0; i < old_fieldnames.size(); ++i) { old_fieldnames[i] = delimit(old_fieldnames[i]); new_fieldnames[i] = delimit(new_fieldnames[i]); } exec(db, "BEGIN TRANSACTION"); exec(db, QString("ALTER TABLE %1 RENAME TO %2").arg(delimited_tablename, delimited_dummytable)); // Make a new, clean table: exec(db, creation_sql); // Copy the data across: exec(db, QString("INSERT INTO %1 (%2) SELECT %3 FROM %4").arg( delimited_tablename, new_fieldnames.join(","), old_fieldnames.join(","), delimited_dummytable)); // Drop the temporary table: exec(db, QString("DROP TABLE %1").arg(delimited_dummytable)); commit(db); }
static void delimit( const char * const *lines, const char * const *endline, const charset *bodychars, int repeat, int body, int div, int pre, int suf, lineprop *props ) /* lines is an array of strings, up to but not including */ /* endline. Sets fields in each lineprop in the parallel */ /* array props as appropriate, except for the L_SUPERF flag, */ /* which is never set. It is assumed that the comprelen */ /* and comsuflen of the lines in lines have already been */ /* determined to be at least pre and suf, respectively. */ { const char * const *line, *end, *p, * const *nextline; char rc; lineprop *prop, *nextprop; int anybodiless = 0, status; if (endline == lines) return; if (endline == lines + 1) { props->flags |= L_FIRST; props->p = pre, props->s = suf; return; } compresuflen(lines, endline, bodychars, body, pre, suf, &pre, &suf); line = lines, prop = props; do { prop->flags |= L_BODILESS; prop->p = pre, prop->s = suf; for (end = *line; *end; ++end); end -= suf; p = *line + pre; rc = p < end ? *p : ' '; if (rc != ' ' && (!repeat || end - p < repeat)) prop->flags &= ~L_BODILESS; else while (p < end) { if (*p != rc) { prop->flags &= ~L_BODILESS; break; } ++p; } if (isbodiless(prop)) { anybodiless = 1; prop->rc = rc; } ++line, ++prop; } while (line < endline); if (anybodiless) { line = lines, prop = props; do { if (isbodiless(prop)) { ++line, ++prop; continue; } for (nextline = line + 1, nextprop = prop + 1; nextline < endline && !isbodiless(nextprop); ++nextline, ++nextprop); delimit(line,nextline,bodychars,repeat,body,div,pre,suf,prop); line = nextline, prop = nextprop; } while (line < endline); return; } if (!div) { props->flags |= L_FIRST; return; } line = lines, prop = props; status = ((*lines)[pre] == ' '); do { if (((*line)[pre] == ' ') == status) prop->flags |= L_FIRST; ++line, ++prop; } while (line < endline); }
void DbFunc::createTable(const QSqlDatabase& db, const QString& tablename, const QList<Field>& fieldlist, const QString& tempsuffix) { QString creation_sql = sqlCreateTable(tablename, fieldlist); if (!tableExists(db, tablename)) { // Create table from scratch. exec(db, creation_sql); return; } // Otherwise, it's a bit more complex... // 1. Create a list of plans. Start with the fields we want, which we // will add (unless later it turns out they exist already). QList<FieldCreationPlan> planlist; QStringList goodfieldlist; for (int i = 0; i < fieldlist.size(); ++i) { const Field& field = fieldlist.at(i); FieldCreationPlan p; p.name = field.name(); p.intended_field = &field; p.add = true; planlist.append(p); goodfieldlist.append(delimit(p.name)); } // 2. Fetch a list of existing fields. // - If any are in our "desired" list, and we didn't know they were in // the database, don't add them (but maybe change them if we want them // to have a different type). // - If they're not in our "desired" list, then they're superfluous, so // aim to drop them. QList<SqlitePragmaInfoField> infolist = getPragmaInfo(db, tablename); for (int i = 0; i < infolist.size(); ++i) { const SqlitePragmaInfoField& info = infolist.at(i); bool existing_is_superfluous = true; for (int j = 0; j < planlist.size(); ++j) { FieldCreationPlan& plan = planlist[j]; const Field* intended_field = plan.intended_field; if (!intended_field) { // This shouldn't happen! continue; } if (!plan.exists_in_db && intended_field->name() == info.name) { plan.exists_in_db = true; plan.add = false; plan.change = ( info.type != intended_field->sqlColumnType() || info.notnull != intended_field->allowsNull() || info.pk != intended_field->isPk() ); plan.existing_type = info.type; plan.existing_not_null = info.notnull; existing_is_superfluous = false; } } if (existing_is_superfluous) { FieldCreationPlan plan; plan.name = info.name; plan.exists_in_db = true; plan.existing_type = info.type; plan.drop = true; planlist.append(plan); } } // 3. For any fields that require adding: add them. // For any that require dropping or altering, make a note for the // complex step. bool drop_or_change_mods_required = false; for (int i = 0; i < planlist.size(); ++i) { const FieldCreationPlan& plan = planlist.at(i); if (plan.add && plan.intended_field) { if (plan.intended_field->isPk()) { UiFunc::stopApp(QString( "DbFunc::createTable: Cannot add a PRIMARY KEY column " "(%s.%s)").arg(tablename, plan.name)); } exec(db, QString("ALTER TABLE %1 ADD COLUMN %2 %3").arg( tablename, delimit(plan.name), plan.intended_field->sqlColumnDef())); } if (plan.drop || plan.change) { drop_or_change_mods_required = true; } } /* qDebug() << Q_FUNC_INFO << "tablename:" << tablename << "goodfieldlist:" << goodfieldlist << "infolist:" << infolist << "modifications_required:" << drop_or_change_mods_required << "plan:" << planlist; */ if (!drop_or_change_mods_required) { qDebug() << "Table" << tablename << "OK; no drop/change alteration required"; return; } // 4. Implement drop/change modifications (via a temporary table). qDebug().nospace() << "Amendment plan for " << tablename << ": " << planlist; // Deleting columns: http://www.sqlite.org/faq.html#q11 // ... also http://stackoverflow.com/questions/8442147/ // Basically, requires (a) copy data to temporary table; (b) drop original; // (c) create new; (d) copy back. // Or, another method: (a) rename table; (b) create new; (c) copy data // across; (d) drop temporary. // We deal with fields of incorrect type similarly (in this case, any // conversion occurs as we SELECT back the values into the new, proper // fields). Not sure it really is important, though: // http://sqlite.org/datatype3.html QString dummytable = tablename + tempsuffix; if (tableExists(db, dummytable)) { UiFunc::stopApp("DbFunc::createTable: temporary table exists: " + dummytable); } QString delimited_tablename = delimit(tablename); QString delimited_dummytable = delimit(dummytable); QString goodfieldstring = goodfieldlist.join(","); exec(db, "BEGIN TRANSACTION"); exec(db, QString("ALTER TABLE %1 RENAME TO %2").arg(delimited_tablename, delimited_dummytable)); exec(db, creation_sql); // make a new clean table exec(db, QString("INSERT INTO %1 (%2) SELECT %3 FROM %4").arg( delimited_tablename, goodfieldstring, goodfieldstring, delimited_dummytable)); exec(db, QString("DROP TABLE %1").arg(delimited_dummytable)); commit(db); }