#include "sqlparse.h"
#include "sqlscanner.h"
enum IndexParseState{
IPPrepair,
IPCreate,
IPUnique,
IPIndex,
IPIf,
IPIfNotExists,
IPDBName,
IPDNDot,
IPName,
IPOn,
IPTableName,
IPCollist,
IPColName,
IPColCollate,
IPCollateName,
IPColSort,
IPEnd
};
enum TableDefState
{
TbDefCreate,
TbDefTemp,
TbDefTable,
TbDefIf,
TbDefIfNotExists,
TbDefName
};
enum ColumnDefState
{
ColDefName,
ColDefType,
ColDefLength,
ColDefLenFirst,
ColDefLenComma,
ColDefLenSecond,
ColDefTypeEnd,
ColDefNotNull,
ColDefPKey,
ColDefUnique,
ColDefCheck
};
SqliteColumn::SqliteColumn()
{
auto_inc = false;
check=QString();
conlate=QString();
defaultValue=QString();
isPK=false;
isUnique=false;
length=0;
length2=0;
name=QString();
notnull=false;
notnullconflict=QString();
pkconflict=QString();
pksort_order=QString();
type=QString();
unique_conflict = QString();
state = 0;
}
SqliteColumn& SqliteColumn::operator =(const SqliteColumn &other)
{
auto_inc = other.auto_inc;
check = other.check;
conlate = other.conlate;
defaultValue = other.defaultValue;
isPK = other.isPK;
isUnique = other.isUnique;
length = other.length;
length2 = other.length2;
name = other.name;
notnull = other.notnull;
notnullconflict = other.notnullconflict;
pkconflict = other.pkconflict;
pksort_order = other.pksort_order;
type = other.type;
unique_conflict = other.unique_conflict;
state = other.state;
return *this;
}
//Q_DECLARE_METATYPE(SqliteIndex);
void SqlParse::reset()
{
state = Prepair;
//ÖØÖÃtableÀïµÄÄÚÈÝ
QVector::iterator iter = table.column_list.begin();
for(;iter!=table.column_list.end();++iter)
{
delete (*iter);
}
table.column_list.clear();
}
bool SqlParse::parse(const QString &sql)
{
SqlScanner scanner;
if(!scanner.scan(sql))
return false;
reset();
SqliteToken *token=0;
SqliteToken *next=0;
SqliteColumn *column =0;
bool error = false;
while(true)
{
token = scanner.next();
if(state == Prepair){
if(token->id == TokenCreate){
parse_table(&scanner);
}else{
//error
break;
}
}
else if(state == ParseColumnList){
if(token->id == TokenID){
column = new SqliteColumn();
table.column_list.append(column);
column->name = token->value;
parse_column(&scanner,column);
}
else if (token->id == TokenPrimary)
{
next = scanner.next();
if(next->id == TokenLeft){
state = ParsePKey;
}else{
//´íÎóµÄPKeyÔ¼Êø¸ñʽ
error = true;
break;
}
}
else if(token->id == TokenUnique)
{
next = scanner.next();
if(next->id == TokenLeft){
state = ParseUnique;
}else{
//´íÎóµÄUniqueÔ¼Êø¸ñʽ
error = true;
break;
}
}
else if(token->id == TokenCheck)
{
next = scanner.next();
if(next->id == TokenLeft){
state = ParseCheck;
}else{
//´íÎóµÄCheckÔ¼Êø¸ñʽ
error = true;
break;
}
}
else
{
error = true;
break;
}
}
else if(state == ParsePKey){
if(token->id == TokenID){
//SqliteColumn *col = findBy(token->value);
//if(!col)
// col->isPK = true;
table.pkey.column_list.push_back(token->value);
state = ParsePKeyCol;
}else{
error = true;
break;
//PKey¸ñʽ´íÎó
}
}
else if(state == ParsePKeyCol){
if(token->id == TokenComma){
state = ParsePKey;
}
else if(token->id == TokenRight){
state = ParsePKeyColEnd;
}else{
error = true;
break;
//´íÎóµÄPKey¸ñʽ
}
}
else if(state == ParsePKeyColEnd){
if(token->id == TokenOn){
if(!parse_conflict(&scanner,table.pkey.conflict))
{
break;
}
}else if(token->id == TokenComma){
state = ParseColumnList;
}else if(token->id == TokenRight){
state = ParseEnd;
}else{
error = true;
break;
//´íÎó¸ñʽ
}
}
else if(state == ParseUnique){
if(token->id == TokenID){
//SqliteColumn *col = findBy(token->value);
//if(!col)
// col->isPK = true;
table.uq.column_list.push_back(token->value);
state = ParseUniqueCol;
}else{
error = true;
break;
//PKey¸ñʽ´íÎó
}
}
else if(state == ParseUniqueCol){
if(token->id == TokenComma){
state = ParseUnique;
}
else if(token->id == TokenRight){
state = ParseUniqueColEnd;
}else{
error = true;
break;
//´íÎóµÄUnique¸ñʽ
}
}
else if(state == ParseUniqueColEnd){
if(token->id == TokenOn){
if(!parse_conflict(&scanner,table.uq.conflict))
{
break;
}
}else if(token->id == TokenComma){
state = ParseColumnList;
}else if(token->id == TokenRight){
state = ParseEnd;
}else{
error = true;
break;
//´íÎó¸ñʽ
}
}
else if(state == ParseCheck){
if(token->id == TokenRight){
state = ParseCheckEnd;
}else{
table.check_expr.push_back(token->value);
}
}
else if(state == ParseCheckEnd){
if(token->id == TokenComma){
state = ParseColumnList;
}else if(token->id == TokenRight){
state = ParseEnd;
}else{
error = true;
break;
}
}
else if(state == ParseEnd)
{
break;
}
}
return !error;
}
bool SqlParse::parse_table(SqlScanner *scanner)
{
TableDefState def_state = TbDefCreate;
bool error = false;
SqliteToken *token = 0;
while(true){
token = scanner->next();
if(token==0)break;
if(def_state == TbDefCreate)
{
if(token->id == TokenTemp)
{
def_state = TbDefTemp;
continue;
}
else if(token->id == TokenTable)
{
def_state = TbDefTable;
continue;
}
else
{
error = true;
break;
}
}
else if(def_state == TbDefTemp)
{
if(token->id == TokenTable){
def_state = TbDefTable;
continue;
}
else{
error = true;
break;
}
}
else if(def_state == TbDefTable)
{
if(token->id == TokenIf){
def_state = TbDefIf;
continue;
}
else if(token->id == TokenID){
def_state = TbDefName;
table.name = token->value;
continue;
}
}
else if(def_state == TbDefIf)
{
SqliteToken *next = scanner->next();
if(token->id == TokenNot && next->id == TokenExists)
{
def_state = TbDefIfNotExists;
}
else {
error = true;
break;
}
}
else if(def_state == TbDefIfNotExists)
{
if(token->id == TokenID)
{
def_state = TbDefName;
table.name = token->value;
}
}
else if(def_state == TbDefName)
{
if(token->id == TokenLeft)
{
state = ParseColumnList;
break;
}
else
{
error = true;
break;
}
}
}
return error;
}
bool SqlParse::parse_column(SqlScanner *scanner,SqliteColumn *col)
{
ColumnDefState def_state = ColDefName;
SqliteToken *token = scanner->next();
SqliteToken *next = 0;
QList exp_stack;
bool error = false;
while(true)
{
if(token==0)break;
if(def_state == ColDefName)
{
if(token->id == TokenChar
||token->id == TokenVarchar
|| token->id == TokenText
|| token->id == TokenBlob
|| token->id == TokenInt
|| token->id == TokenFloat
|| token->id == TokenDecimal
|| token->id == TokenDateTime)
{
def_state = ColDefType;
col->type = token->value;
}
else if(token->id == TokenID){
def_state = ColDefType;
col->type = token->value;
}
else if(token->id == TokenComma)
{
state = ParseColumnList;
//µ±Ç°Áж¨Òå½áÊø
break;
}
else if(token->id == TokenRight){
state = ParseEnd;
break;
}
else if(token->id == TokenNot)
{
//not null Ô¼Êø¶¨Òå
}
}
else if(def_state == ColDefType)
{
if(token->id == TokenLeft)
{
def_state = ColDefLength;
}
else if (token->id == TokenComma)
{
state = ParseColumnList;
//µ±Ç°Áж¨Òå½áÊø
break;
}else if(token->id == TokenRight){
state = ParseEnd;
break;
}else if(token->id == TokenNot)
{
next = scanner->next();
if(next->id==TokenNull){
col->notnull = true;
def_state = ColDefNotNull;
}
else
{
//´íÎóµÄnot nullÁÐÔ¼Êø¶¨Òå
error = true;
break;
}
}
else if(token->id == TokenPrimary)
{
next = scanner->next();
if(next->id == TokenKey){
def_state = ColDefPKey;
col->isPK = true;
}else{
//´íÎóµÄÖ÷¼üÉùÃ÷
error = true;
break;
}
}
else if(token->id == TokenUnique)
{
col->isUnique = true;
def_state = ColDefUnique;
}
else if(token->id == TokenCheck)
{
next = scanner->next();
if(next->id == TokenLeft){
def_state = ColDefCheck;
}
else
{
//䶨ÒåµÄCheckÔ¼Êø
error = true;
break;
}
}
else if(token->id == TokenDefault)
{
col->defaultValue = scanner->next()->value;
}
else if(token->id == TokenCollate)
{
col->conlate = scanner->next()->value;
}
else{
error = true;
break;
}
}
else if(def_state == ColDefLength)
{
if(token->id == TokenIntConst){
col->length = token->value.toInt();
def_state = ColDefLenFirst;
}
else
{
error = true;
break;
}
}
else if(def_state == ColDefLenFirst)
{
if(token->id == TokenComma)
{
def_state = ColDefLenComma;
}
else if(token->id == TokenRight)
{
def_state = ColDefTypeEnd;
}
else
{
error = true;
break;
}
}
else if(def_state == ColDefLenComma)
{
if(token->id == TokenIntConst){
col->length2 = token->value.toInt();
def_state = ColDefLenSecond;
}
else
{
error = true;
break;
}
}
else if(def_state == ColDefLenSecond)
{
if(token->id == TokenRight){
def_state = ColDefTypeEnd;
}else{
error = true;
break;
}
}
//TYPEEND:
else if(def_state == ColDefTypeEnd)
{
if(token->id == TokenComma)
{
state = ParseColumnList;
//µ±Ç°Áж¨Òå½áÊø
break;
}
else if(token->id == TokenRight){
state = ParseEnd;
break;
}
else if(token->id == TokenNot)
{
next = scanner->next();
if(next->id==TokenNull){
col->notnull = true;
def_state = ColDefNotNull;
}
else
{
//´íÎóµÄnot nullÁÐÔ¼Êø¶¨Òå
error = true;
break;
}
}
else if(token->id == TokenPrimary)
{
next = scanner->next();
if(next->id == TokenKey){
def_state = ColDefPKey;
col->isPK = true;
}else{
//´íÎóµÄÖ÷¼üÉùÃ÷
error = true;
break;
}
}
else if(token->id == TokenUnique)
{
col->isUnique = true;
def_state = ColDefUnique;
}
else if(token->id == TokenCheck)
{
next = scanner->next();
if(next->id == TokenLeft){
def_state = ColDefCheck;
exp_stack.clear();
}
else
{
//䶨ÒåµÄCheckÔ¼Êø
error = true;
break;
}
}
else if(token->id == TokenDefault)
{
col->defaultValue = scanner->next()->value;
}
else if(token->id == TokenCollate)
{
col->conlate = scanner->next()->value;
}
else
{
error = true;
break;
}
}
else if(def_state == ColDefNotNull)
{
if(token->id == TokenOn)
{
if(!parse_conflict(scanner,col->notnullconflict)){
break;
}
}
else
{
def_state = ColDefTypeEnd;
continue;
//goto TYPEEND;
}
}
else if(def_state == ColDefPKey)
{
if(token->id == TokenOn)
{
if(!parse_conflict(scanner,col->pkconflict)){
break;
}
}
else if(token->id == TokenAutoIncrement){
col->auto_inc = true;
}
else {
def_state = ColDefTypeEnd;
continue;
//goto TYPEEND;
}
}
else if(def_state == ColDefUnique)
{
if(token->id == TokenOn)
{
if(!parse_conflict(scanner,col->unique_conflict)){
break;
}
}
else
{
def_state = ColDefTypeEnd;
continue;
//goto TYPEEND;
}
}
else if(def_state == ColDefCheck)
{
if(token->id == TokenLeft){
col->check.push_back(token->value);
exp_stack.push_back(token);
}
else if(token->id==TokenRight){
if(exp_stack.isEmpty()){
def_state = ColDefTypeEnd;
}else{
exp_stack.pop_back();
col->check.push_back(token->value);
}
}
else
{
col->check.append(token->value);
}
}
token = scanner->next();
}
return error;
}
bool SqlParse::parse_conflict(SqlScanner *scanner,QString &conflict)
{
SqliteToken *next = scanner->next();
if(next->id == TokenConflict){
conflict = scanner->next()->value;
return true;
}
else{
//´íÎóµÄconflictÉùÃ÷
return false;
}
}
bool SqlParse::parse_index(const QString &src,
const QString &dbname,
SqliteIndex &index)
{
if(src.isEmpty())
return false;
SqlScanner scanner;
if(!scanner.scan(src))
return false;
index.name.clear();
index.unique = false;
index.collist.clear();
IndexParseState ip_state = IPPrepair;
SqliteIndexColumn *ic=0;
bool error = false;
SqliteToken *token = scanner.next();
while(true){
if(token==0)break;
if(ip_state == IPPrepair)
{
if(token->id == TokenCreate)
{
ip_state = IPCreate;
}
else
{
error = true;
break;
}
}
else if(ip_state == IPCreate)
{
if(token->id ==TokenUnique){
ip_state = IPUnique;
index.unique = true;
}
else if(token->id == TokenIndex){
ip_state = IPIndex;
index.unique = false;
}else{
error = true;
break;
}
}
else if(ip_state == IPUnique){
if(token->id == TokenIndex){
ip_state = IPIndex;
}else{
error = true;
break;
}
}
else if(ip_state == IPIndex)
{
if(token->id == TokenIf){
ip_state = IPIf;
}
else if(token->id == TokenID){
if(token->value==dbname){
ip_state = IPDBName;
}else{
ip_state = IPName;
index.name = token->value;
}
}else
{
error = true;
break;
}
}
else if(ip_state == IPIf)
{
SqliteToken *next = scanner.next();
if(token->id == TokenNot && next->id == TokenExists)
{
ip_state = IPIfNotExists;
}
else {
error = true;
break;
}
}
else if(ip_state == IPDBName)
{
SqliteToken *next = scanner.next();
if(token->id == TokenMember && next->id == TokenID){
ip_state = IPName;
index.name = next->value;
}else{
error = true;
break;
}
}
else if(ip_state == IPIfNotExists)
{
if(token->id == TokenID)
{
if(token->value == dbname){
ip_state = IPDBName;
}else{
ip_state = IPName;
index.name = token->value;
}
}else{
error = true;
break;
}
}
else if(ip_state == IPName)
{
if(token->id == TokenOn)
{
ip_state = IPOn;
}
else
{
error = true;
break;
}
}
else if(ip_state == IPOn){
if(token->id == TokenID){
index.tbname = token->value;
ip_state = IPTableName;
}else{
error = true;
break;
}
}
else if(ip_state == IPTableName){
if(token->id == TokenLeft){
ip_state = IPCollist;
}else{
error = true;
break;
}
}
else if(ip_state == IPCollist){
if(token->id == TokenID){
ip_state = IPColName;
ic = new SqliteIndexColumn;
ic->name = token->value;
}else{
error = true;
break;
}
}
else if(ip_state == IPColName){
if(token->id == TokenCollate){
ip_state = IPColCollate;
}
else if(token->id == TokenAsc || token->id == TokenDesc){
ip_state = IPColSort;
ic->sort = token->value;
}
else if(token->id == TokenComma){
ip_state = IPCollist;
index.collist.push_back(ic);
}
else if(token->id == TokenRight){
ip_state = IPEnd;
index.collist.push_back(ic);
break;
}
else{
error = true;
break;
}
}
else if(ip_state == IPColCollate){
if(token->id == TokenID){
ip_state = IPCollateName;
ic->collate = token->value;
}else{
error = true;
break;
}
}
else if(ip_state == IPCollateName){
if(token->id == TokenAsc || token->id == TokenDesc){
ip_state = IPColSort;
ic->sort = token->value;
}
else if(token->id == TokenComma){
ip_state = IPCollist;
index.collist.push_back(ic);
}
else if(token->id == TokenRight){
ip_state = IPEnd;
index.collist.push_back(ic);
break;
}else{
error = true;
break;
}
}
else if(ip_state == IPColSort){
if(token->id == TokenComma)
{
ip_state = IPCollist;
index.collist.push_back(ic);
}
else if(token->id == TokenRight){
ip_state = IPEnd;
index.collist.push_back(ic);
break;
}else{
error = true;
break;
}
}
token = scanner.next();
}
return !error;
}
//SqliteColumn* SqlParse::findBy(const QString &col_name)
//{
// foreach(SqliteColumn *col,table.column_list){
// if(col->name==col_name)
// return col;
// }
// return 0;
//}