diff options
author | drh <drh@noemail.net> | 2017-07-11 01:38:45 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2017-07-11 01:38:45 +0000 |
commit | dc4dde6bd9ee6409ce5987e38f0e3d667f906679 (patch) | |
tree | 5a7fd12972ab7995352172505c1bb03a7792491d /ext/misc/completion.c | |
parent | 3265b5649ec87ca82026c7cd177434993a00c482 (diff) | |
download | sqlite-dc4dde6bd9ee6409ce5987e38f0e3d667f906679.tar.gz sqlite-dc4dde6bd9ee6409ce5987e38f0e3d667f906679.zip |
The COMPLETION virtual table now looks at the names of databases, tables,
and columns in addition to SQL keywords.
FossilOrigin-Name: 1cc97711fa86a3938f0930200476d1b0991e4b893a8be3a19015423a3de56bef
Diffstat (limited to 'ext/misc/completion.c')
-rw-r--r-- | ext/misc/completion.c | 115 |
1 files changed, 96 insertions, 19 deletions
diff --git a/ext/misc/completion.c b/ext/misc/completion.c index f4cd1b91b..ae11ef422 100644 --- a/ext/misc/completion.c +++ b/ext/misc/completion.c @@ -54,7 +54,7 @@ struct completion_cursor { /* Values for ePhase: */ -#define COMPLETION_FIRST_PHASE 0 +#define COMPLETION_FIRST_PHASE 1 #define COMPLETION_KEYWORDS 1 #define COMPLETION_PRAGMAS 2 #define COMPLETION_FUNCTIONS 3 @@ -63,8 +63,9 @@ struct completion_cursor { #define COMPLETION_TRIGGERS 6 #define COMPLETION_DATABASES 7 #define COMPLETION_TABLES 8 -#define COMPLETION_MODULES 9 -#define COMPLETION_LAST_PHASE 10 +#define COMPLETION_COLUMNS 9 +#define COMPLETION_MODULES 10 +#define COMPLETION_EOF 11 /* ** The completionConnect() method is invoked to create a new @@ -138,6 +139,7 @@ static void completionCursorReset(completion_cursor *pCur){ sqlite3_free(pCur->zPrefix); pCur->zPrefix = 0; pCur->nPrefix = 0; sqlite3_free(pCur->zLine); pCur->zLine = 0; pCur->nLine = 0; sqlite3_finalize(pCur->pStmt); pCur->pStmt = 0; + pCur->j = 0; } /* @@ -178,28 +180,103 @@ static const char *completionKwrds[] = { */ static int completionNext(sqlite3_vtab_cursor *cur){ completion_cursor *pCur = (completion_cursor*)cur; + int eNextPhase = 0;/* Next phase to try if current phase reaches end */ + int iCol = -1; /* If >=0 then step pCur->pStmt and use the i-th column */ pCur->iRowid++; - if( pCur->ePhase==COMPLETION_FIRST_PHASE ){ - pCur->ePhase = COMPLETION_KEYWORDS; - pCur->j = -1; - } - if( pCur->ePhase==COMPLETION_KEYWORDS ){ - while(1){ - const char *z; - pCur->j++; - if( pCur->j >= sizeof(completionKwrds)/sizeof(completionKwrds[0]) ){ - pCur->ePhase = COMPLETION_LAST_PHASE; + while( pCur->ePhase!=COMPLETION_EOF ){ + switch( pCur->ePhase ){ + case COMPLETION_KEYWORDS: { + if( pCur->j >= sizeof(completionKwrds)/sizeof(completionKwrds[0]) ){ + pCur->zCurrentRow = 0; + pCur->ePhase = COMPLETION_DATABASES; + }else{ + pCur->zCurrentRow = completionKwrds[pCur->j++]; + } + iCol = -1; + break; + } + case COMPLETION_DATABASES: { + if( pCur->pStmt==0 ){ + sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, + &pCur->pStmt, 0); + } + iCol = 1; + eNextPhase = COMPLETION_TABLES; + break; + } + case COMPLETION_TABLES: { + if( pCur->pStmt==0 ){ + sqlite3_stmt *pS2; + char *zSql = 0; + const char *zSep = ""; + sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0); + while( sqlite3_step(pS2)==SQLITE_ROW ){ + const char *zDb = (const char*)sqlite3_column_text(pS2, 1); + zSql = sqlite3_mprintf( + "%z%s" + "SELECT name FROM \"%w\".sqlite_master" + " WHERE type='table'", + zSql, zSep, zDb + ); + if( zSql==0 ) return SQLITE_NOMEM; + zSep = " UNION "; + } + sqlite3_finalize(pS2); + sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0); + sqlite3_free(zSql); + } + iCol = 0; + eNextPhase = COMPLETION_COLUMNS; break; } - z = completionKwrds[pCur->j]; - if( pCur->nPrefix==0 - || sqlite3_strnicmp(pCur->zPrefix, z, pCur->nPrefix)==0 - ){ - pCur->zCurrentRow = z; + case COMPLETION_COLUMNS: { + if( pCur->pStmt==0 ){ + sqlite3_stmt *pS2; + char *zSql = 0; + const char *zSep = ""; + sqlite3_prepare_v2(pCur->db, "PRAGMA database_list", -1, &pS2, 0); + while( sqlite3_step(pS2)==SQLITE_ROW ){ + const char *zDb = (const char*)sqlite3_column_text(pS2, 1); + zSql = sqlite3_mprintf( + "%z%s" + "SELECT pti.name FROM \"%w\".sqlite_master AS sm" + " JOIN pragma_table_info(sm.name,%Q) AS pti" + " WHERE sm.type='table'", + zSql, zSep, zDb, zDb + ); + if( zSql==0 ) return SQLITE_NOMEM; + zSep = " UNION "; + } + sqlite3_finalize(pS2); + sqlite3_prepare_v2(pCur->db, zSql, -1, &pCur->pStmt, 0); + sqlite3_free(zSql); + } + iCol = 0; + eNextPhase = COMPLETION_EOF; break; } } + if( iCol<0 ){ + /* This case is when the phase presets zCurrentRow */ + if( pCur->zCurrentRow==0 ) continue; + }else{ + if( sqlite3_step(pCur->pStmt)==SQLITE_ROW ){ + /* Extract the next row of content */ + pCur->zCurrentRow = (const char*)sqlite3_column_text(pCur->pStmt, iCol); + }else{ + /* When all rows are finished, advance to the next phase */ + sqlite3_finalize(pCur->pStmt); + pCur->pStmt = 0; + pCur->ePhase = eNextPhase; + continue; + } + } + if( pCur->nPrefix==0 ) break; + if( sqlite3_strnicmp(pCur->zPrefix, pCur->zCurrentRow, pCur->nPrefix)==0 ){ + break; + } } + return SQLITE_OK; } @@ -246,7 +323,7 @@ static int completionRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ */ static int completionEof(sqlite3_vtab_cursor *cur){ completion_cursor *pCur = (completion_cursor*)cur; - return pCur->ePhase >= COMPLETION_LAST_PHASE; + return pCur->ePhase >= COMPLETION_EOF; } /* |