/* ** This is the top-level implementation of sqlite4_step(). Call ** sqlite4Step() to do most of the work. If a schema error occurs, ** call sqlite4Reprepare() and try again. */ int sqlite4_step(sqlite4_stmt *pStmt) { int rc = SQLITE4_OK; /* Result from sqlite4Step() */ int rc2 = SQLITE4_OK; /* Result from sqlite4Reprepare() */ Vdbe *v = (Vdbe*)pStmt; /* the prepared statement */ int cnt = 0; /* Counter to prevent infinite loop of reprepares */ sqlite4 *db; /* The database connection */ if( vdbeSafetyNotNull(v) ) { return SQLITE4_MISUSE_BKPT; } db = v->db; sqlite4_mutex_enter(db->mutex); while( (rc = sqlite4Step(v))==SQLITE4_SCHEMA && cnt++ < SQLITE4_MAX_SCHEMA_RETRY && (rc2 = rc = sqlite4Reprepare(v))==SQLITE4_OK ) { sqlite4_reset(pStmt); assert( v->expired==0 ); } if( rc2!=SQLITE4_OK && ALWAYS(db->pErr) ) { /* This case occurs after failing to recompile an sql statement. ** The error message from the SQL compiler has already been loaded ** into the database handle. This block copies the error message ** from the database handle into the statement and sets the statement ** program counter to 0 to ensure that when the statement is ** finalized or reset the parser error message is available via ** sqlite4_errmsg() and sqlite4_errcode(). */ const char *zErr = sqlite4_value_text(db->pErr, 0); sqlite4DbFree(db, v->zErrMsg); if( !db->mallocFailed ) { v->zErrMsg = sqlite4DbStrDup(db, zErr); v->rc = rc2; } else { v->zErrMsg = 0; v->rc = rc = SQLITE4_NOMEM; } } rc = sqlite4ApiExit(db, rc); sqlite4_mutex_leave(db->mutex); return rc; }
/* ** Execute the statement pStmt, either until a row of data is ready, the ** statement is completely executed or an error occurs. ** ** This routine implements the bulk of the logic behind the sqlite_step() ** API. The only thing omitted is the automatic recompile if a ** schema change has occurred. That detail is handled by the ** outer sqlite4_step() wrapper procedure. */ static int sqlite4Step(Vdbe *p) { sqlite4 *db; int rc; assert(p); if( p->magic!=VDBE_MAGIC_RUN ) { /* We used to require that sqlite4_reset() be called before retrying ** sqlite4_step() after any error or after SQLITE4_DONE. But beginning ** with version 3.7.0, we changed this so that sqlite4_reset() would ** be called automatically instead of throwing the SQLITE4_MISUSE error. ** This "automatic-reset" change is not technically an incompatibility, ** since any application that receives an SQLITE4_MISUSE is broken by ** definition. ** ** Nevertheless, some published applications that were originally written ** for version 3.6.23 or earlier do in fact depend on SQLITE4_MISUSE ** returns, and those were broken by the automatic-reset change. As a ** a work-around, the SQLITE4_OMIT_AUTORESET compile-time restores the ** legacy behavior of returning SQLITE4_MISUSE for cases where the ** previous sqlite4_step() returned something other than a SQLITE4_LOCKED ** or SQLITE4_BUSY error. */ #ifdef SQLITE4_OMIT_AUTORESET if( p->rc==SQLITE4_BUSY || p->rc==SQLITE4_LOCKED ) { sqlite4_reset((sqlite4_stmt*)p); } else { return SQLITE4_MISUSE_BKPT; } #else sqlite4_reset((sqlite4_stmt*)p); #endif } /* Check that malloc() has not failed. If it has, return early. */ db = p->db; if( db->mallocFailed ) { p->rc = SQLITE4_NOMEM; return SQLITE4_NOMEM; } if( p->pc<=0 && p->expired ) { p->rc = SQLITE4_SCHEMA; rc = SQLITE4_ERROR; goto end_of_step; } if( p->pc<0 ) { /* If there are no other statements currently running, then ** reset the interrupt flag. This prevents a call to sqlite4_interrupt ** from interrupting a statement that has not yet started. */ if( db->activeVdbeCnt==0 ) { db->u1.isInterrupted = 0; } assert( db->writeVdbeCnt>0 || db->pSavepoint || db->nDeferredCons==0 ); #ifndef SQLITE4_OMIT_TRACE if( db->xProfile && !db->init.busy ) { sqlite4OsCurrentTime(0, &p->startTime); } #endif db->activeVdbeCnt++; if( p->readOnly==0 ) db->writeVdbeCnt++; p->pc = 0; } #ifndef SQLITE4_OMIT_EXPLAIN if( p->explain ) { rc = sqlite4VdbeList(p); } else #endif /* SQLITE4_OMIT_EXPLAIN */ { db->vdbeExecCnt++; rc = sqlite4VdbeExec(p); db->vdbeExecCnt--; } #ifndef SQLITE4_OMIT_TRACE /* Invoke the profile callback if there is one */ if( rc!=SQLITE4_ROW && db->xProfile && !db->init.busy && p->zSql ) { sqlite4_uint64 iNow = 0; sqlite4OsCurrentTime(0, &iNow); db->xProfile(db->pProfileArg, p->zSql, (iNow - p->startTime)*1000000); } #endif db->errCode = rc; if( SQLITE4_NOMEM==sqlite4ApiExit(p->db, p->rc) ) { p->rc = SQLITE4_NOMEM; } end_of_step: /* At this point local variable rc holds the value that should be ** returned if this statement was compiled using the legacy ** sqlite4_prepare() interface. According to the docs, this can only ** be one of the values in the first assert() below. Variable p->rc ** contains the value that would be returned if sqlite4_finalize() ** were called on statement p. */ assert( rc==SQLITE4_ROW || rc==SQLITE4_DONE || rc==SQLITE4_ERROR || rc==SQLITE4_BUSY || rc==SQLITE4_MISUSE ); assert( p->rc!=SQLITE4_ROW && p->rc!=SQLITE4_DONE ); if( rc!=SQLITE4_ROW && rc!=SQLITE4_DONE ) { rc = sqlite4VdbeTransferError(p); } return rc; }
int tbl_to_db(struct freeq_ctx *ctx, struct freeq_table *tbl, sqlite4 *mDb) { sqlite4_stmt *stmt; GString *sql = g_string_sized_new(255); GSList *colp[tbl->numcols]; memset(colp, 0, tbl->numcols * sizeof(GSList *) ); for (int j = 0; j < tbl->numcols; j++) colp[j] = tbl->columns[j].data; int res; freeq_table_print(ctx, tbl, stdout); if (sqlite4_exec(mDb, "BEGIN TRANSACTION;", NULL, NULL) != SQLITE4_OK) { dbg(ctx, "unable to start transaction: %s\n", sqlite4_errmsg(mDb)); return 1; } g_string_printf(sql, "DROP TABLE %s;", tbl->name); if (sqlite4_exec(mDb, sql->str, NULL, NULL) != SQLITE4_OK) dbg(ctx, "failed to drop table, ignoring\n"); table_ddl(ctx, tbl, sql); if (sqlite4_exec(mDb, sql->str, NULL, NULL) != SQLITE4_OK) { dbg(ctx, "failed to create table, rolling back\n"); sqlite4_exec(mDb, "ROLLBACK;", NULL, NULL); g_string_free(sql, 1); return 1; } ddl_insert(ctx, tbl, sql); if ((res = sqlite4_prepare(mDb, sql->str, sql->len, &stmt, NULL)) != SQLITE4_OK) { dbg(ctx, "failed to create statement (%d), rolling back\n", res); sqlite4_exec(mDb, "ROLLBACK;", NULL, NULL); g_string_free(sql,1); return 1; } g_string_free(sql,1); for (uint32_t i = 0; i < tbl->numrows; i++) { for (uint32_t j = 0; j < tbl->numcols; j++) { switch (tbl->columns[j].coltype) { case FREEQ_COL_STRING: res = sqlite4_bind_text(stmt, j+1, colp[j]->data == NULL ? "" : colp[j]->data, colp[j]->data == NULL ? 0 : strlen(colp[j]->data), SQLITE4_TRANSIENT, NULL); if (res != SQLITE4_OK) { dbg(ctx, "stmt: %s\n", (char *)stmt); dbg(ctx, "row %d failed binding string column %d %s: %s (%d)\n", i, j, (char *)colp[j]->data, sqlite4_errmsg(mDb), res); } break; case FREEQ_COL_NUMBER: res = sqlite4_bind_int(stmt, j, GPOINTER_TO_INT(colp[j]->data)); if (res != SQLITE4_OK) { dbg(ctx, "row %d failed bind: %s\n", i, sqlite4_errmsg(mDb)); } break; default: break; } colp[j] = g_slist_next(colp[j]); } if (sqlite4_step(stmt) != SQLITE4_DONE) { dbg(ctx, "execute failed: %s\n", sqlite4_errmsg(mDb)); sqlite4_exec(mDb, "ROLLBACK;", NULL, NULL); sqlite4_finalize(stmt); return -1; } else { sqlite4_reset(stmt); } } dbg(ctx, "committing transaction\n"); res = sqlite4_exec(mDb, "COMMIT TRANSACTION;", NULL, NULL); dbg(ctx, "result of commit was %d\n", res); sqlite4_finalize(stmt); return 0; }