00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "parser_p.h"
00021 #include "sqlparser.h"
00022
00023 #include <kdebug.h>
00024 #include <klocale.h>
00025
00026 #include <qregexp.h>
00027
00028 #include <assert.h>
00029
00030 using namespace KexiDB;
00031
00032 Parser *parser;
00033 Field *field;
00034
00035 QPtrList<Field> fieldList;
00036 int current = 0;
00037 QString ctoken = "";
00038
00039
00040
00041 ParserPrivate::ParserPrivate()
00042 : reservedKeywords(997, 997, false)
00043 , initialized(false)
00044 {
00045 clear();
00046 table = 0;
00047 select = 0;
00048 db = 0;
00049 }
00050
00051 ParserPrivate::~ParserPrivate()
00052 {
00053 delete select;
00054 delete table;
00055 }
00056
00057 void ParserPrivate::clear()
00058 {
00059 operation = Parser::OP_None;
00060 error = ParserError();
00061 }
00062
00063
00064
00065 ParseInfo::ParseInfo(KexiDB::QuerySchema *query)
00066 : repeatedTablesAndAliases(997, false)
00067 , querySchema(query)
00068 {
00069 repeatedTablesAndAliases.setAutoDelete(true);
00070 }
00071
00072 ParseInfo::~ParseInfo()
00073 {
00074 }
00075
00076
00077
00078 extern int yyparse();
00079 extern void tokenize(const char *data);
00080
00081 void yyerror(const char *str)
00082 {
00083 KexiDBDbg << "error: " << str << endl;
00084 KexiDBDbg << "at character " << current << " near tooken " << ctoken << endl;
00085 parser->setOperation(Parser::OP_Error);
00086
00087 const bool otherError = (qstrnicmp(str, "other error", 11)==0);
00088
00089 if (parser->error().type().isEmpty()
00090 && (str==0 || strlen(str)==0
00091 || qstrnicmp(str, "syntax error", 12)==0 || qstrnicmp(str, "parse error", 11)==0)
00092 || otherError)
00093 {
00094 KexiDBDbg << parser->statement() << endl;
00095 QString ptrline = "";
00096 for(int i=0; i < current; i++)
00097 ptrline += " ";
00098
00099 ptrline += "^";
00100
00101 KexiDBDbg << ptrline << endl;
00102
00103
00104 QString lexerErr = parser->error().error();
00105
00106 QString errtypestr(str);
00107 if (lexerErr.isEmpty()) {
00108 #if 0
00109 if (errtypestr.startsWith("parse error, unexpected ")) {
00110
00111 QString e = errtypestr.mid(24);
00112 KexiDBDbg << e <<endl;
00113 QString token = "IDENTIFIER";
00114 if (e.startsWith(token)) {
00115 QRegExp re("'.'");
00116 int pos=0;
00117 pos = re.search(e, pos);
00118 QStringList captured=re.capturedTexts();
00119 if (captured.count()>=2) {
00120
00121
00122 }
00123 }
00124
00125
00126
00127
00128 e = errtypestr.mid(47);
00129 KexiDBDbg << e <<endl;
00130
00131
00132
00133 } else
00134 #endif
00135 if (errtypestr.startsWith("parse error, expecting `IDENTIFIER'"))
00136 lexerErr = i18n("identifier was expected");
00137 }
00138
00139 if (!otherError) {
00140 if (!lexerErr.isEmpty())
00141 lexerErr.prepend(": ");
00142
00143 if (parser->isReservedKeyword(ctoken.latin1()))
00144 parser->setError( ParserError(i18n("Syntax Error"),
00145 i18n("\"%1\" is a reserved keyword").arg(ctoken)+lexerErr, ctoken, current) );
00146 else
00147 parser->setError( ParserError(i18n("Syntax Error"),
00148 i18n("Syntax Error near \"%1\"").arg(ctoken)+lexerErr, ctoken, current) );
00149 }
00150 }
00151 }
00152
00153 void setError(const QString& errName, const QString& errDesc)
00154 {
00155 parser->setError( ParserError(errName, errDesc, ctoken, current) );
00156 yyerror(errName.latin1());
00157 }
00158
00159 void setError(const QString& errDesc)
00160 {
00161 setError("other error", errDesc);
00162 }
00163
00164
00165 #define IMPL_ERROR(errmsg) setError("Implementation error", errmsg)
00166
00167 bool parseData(Parser *p, const char *data)
00168 {
00169
00170 parser = p;
00171 parser->clear();
00172 field = 0;
00173 fieldList.clear();
00174
00175
00176 if (!data) {
00177 ParserError err(i18n("Error"), i18n("No query specified"), ctoken, current);
00178 parser->setError(err);
00179 yyerror("");
00180 parser = 0;
00181 return false;
00182 }
00183
00184 tokenize(data);
00185 if (!parser->error().type().isEmpty()) {
00186 parser = 0;
00187 return false;
00188 }
00189 yyparse();
00190
00191 bool ok = true;
00192 if(parser->operation() == Parser::OP_Select)
00193 {
00194 KexiDBDbg << "parseData(): ok" << endl;
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216 }
00217 else {
00218 ok = false;
00219 }
00220
00221
00222 parser = 0;
00223 return ok;
00224 }
00225
00226
00227
00228
00229
00230 bool addColumn( ParseInfo& parseInfo, BaseExpr* columnExpr )
00231 {
00232 if (!columnExpr->validate(parseInfo)) {
00233 setError(parseInfo.errMsg, parseInfo.errDescr);
00234 return false;
00235 }
00236
00237 VariableExpr *v_e = columnExpr->toVariable();
00238 if (columnExpr->exprClass() == KexiDBExpr_Variable && v_e) {
00239
00240 if (v_e->name=="*") {
00241 if (parseInfo.querySchema->tables()->isEmpty()) {
00242 setError(i18n("\"*\" could not be used if no tables are specified"));
00243 return false;
00244 }
00245 parseInfo.querySchema->addAsterisk( new QueryAsterisk(parseInfo.querySchema) );
00246 }
00247 else if (v_e->tableForQueryAsterisk) {
00248 parseInfo.querySchema->addAsterisk(
00249 new QueryAsterisk(parseInfo.querySchema, v_e->tableForQueryAsterisk) );
00250 }
00251 else if (v_e->field) {
00252 parseInfo.querySchema->addField(v_e->field, v_e->tablePositionForField);
00253 }
00254 else {
00255 IMPL_ERROR("addColumn(): unknown case!");
00256 return false;
00257 }
00258 return true;
00259 }
00260
00261
00262 parseInfo.querySchema->addExpression(columnExpr);
00263
00264 #if 0
00265 KexiDBDbg << "found variable name: " << varName << endl;
00266 int dotPos = varName.find('.');
00267 QString tableName, fieldName;
00268
00269 if (dotPos>0) {
00270 tableName = varName.left(dotPos);
00271 fieldName = varName.mid(dotPos+1);
00272 }
00273 if (tableName.isEmpty()) {
00274 fieldName = varName;
00275 if (fieldName=="*") {
00276 parseInfo.querySchema->addAsterisk( new QueryAsterisk(parseInfo.querySchema) );
00277 }
00278 else {
00279
00280 Field *firstField = 0;
00281 for (TableSchema::ListIterator it(*parseInfo.querySchema->tables()); it.current(); ++it) {
00282 Field *f = it.current()->field(fieldName);
00283 if (f) {
00284 if (!firstField) {
00285 firstField = f;
00286 } else if (f->table()!=firstField->table()) {
00287
00288 setError(i18n("Ambiguous field name"),
00289 i18n("Both table \"%1\" and \"%2\" have defined \"%3\" field. "
00290 "Use \"<tableName>.%4\" notation to specify table name.")
00291 .arg(firstField->table()->name()).arg(f->table()->name())
00292 .arg(fieldName).arg(fieldName));
00293 return false;
00294 }
00295 }
00296 }
00297 if (!firstField) {
00298 setError(i18n("Field not found"),
00299 i18n("Table containing \"%1\" field not found").arg(fieldName));
00300 return false;
00301 }
00302
00303 parseInfo.querySchema->addField(firstField);
00304 }
00305 }
00306 else {
00307 tableName = tableName.lower();
00308 TableSchema *ts = parseInfo.querySchema->table( tableName );
00309 if (ts) {
00310
00311 const QValueList<int> tPositions = parseInfo.querySchema->tablePositions(tableName);
00312 QValueList<int>::ConstIterator it = tPositions.constBegin();
00313 QCString tableAlias;
00314 bool covered = true;
00315 for (; it!=tPositions.constEnd() && covered; ++it) {
00316 tableAlias = parseInfo.querySchema->tableAlias(*it);
00317 if (tableAlias.isEmpty() || tableAlias.lower()==tableName.latin1())
00318 covered = false;
00319 KexiDBDbg << " --" << "covered by " << tableAlias << " alias" << endl;
00320 }
00321 if (covered) {
00322 setError(i18n("Could not access the table directly using its name"),
00323 i18n("Table \"%1\" is covered by aliases. Instead of \"%2\", "
00324 "you can write \"%3\"").arg(tableName)
00325 .arg(tableName+"."+fieldName).arg(tableAlias+"."+fieldName.latin1()));
00326 return false;
00327 }
00328 }
00329
00330 int tablePosition = -1;
00331 if (!ts) {
00332 tablePosition = parseInfo.querySchema->tablePositionForAlias( tableName.latin1() );
00333 if (tablePosition>=0) {
00334 ts = parseInfo.querySchema->tables()->at(tablePosition);
00335 if (ts) {
00336
00337 }
00338 }
00339 }
00340
00341
00342 if (ts) {
00343 QValueList<int> *positionsList = repeatedTablesAndAliases[ tableName ];
00344 if (!positionsList) {
00345 IMPL_ERROR(tableName + "." + fieldName + ", !positionsList ");
00346 return false;
00347 }
00348
00349 if (fieldName=="*") {
00350 if (positionsList->count()>1) {
00351 setError(i18n("Ambiguous \"%1.*\" expression").arg(tableName),
00352 i18n("More than one \"%1\" table or alias defined").arg(tableName));
00353 return false;
00354 }
00355 parseInfo.querySchema->addAsterisk( new QueryAsterisk(parseInfo.querySchema, ts) );
00356 }
00357 else {
00358
00359 Field *realField = ts->field(fieldName);
00360 if (realField) {
00361
00362
00363 int numberOfTheSameFields = 0;
00364 for (QValueList<int>::iterator it = positionsList->begin();
00365 it!=positionsList->end();++it)
00366 {
00367 TableSchema *otherTS = parseInfo.querySchema->tables()->at(*it);
00368 if (otherTS->field(fieldName))
00369 numberOfTheSameFields++;
00370 if (numberOfTheSameFields>1) {
00371 setError(i18n("Ambiguous \"%1.%2\" expression").arg(tableName).arg(fieldName),
00372 i18n("More than one \"%1\" table or alias defined containing \"%2\" field")
00373 .arg(tableName).arg(fieldName));
00374 return false;
00375 }
00376 }
00377
00378 parseInfo.querySchema->addField(realField, tablePosition);
00379 }
00380 else {
00381 setError(i18n("Field not found"), i18n("Table \"%1\" has no \"%2\" field")
00382 .arg(tableName).arg(fieldName));
00383 return false;
00384 }
00385 }
00386 }
00387 else {
00388 tableNotFoundError(tableName);
00389 return false;
00390 }
00391 }
00392 #endif
00393 return true;
00394 }
00395
00397 #define CLEANUP \
00398 delete colViews; \
00399 delete tablesList; \
00400 delete options
00401
00402 QuerySchema* buildSelectQuery(
00403 QuerySchema* querySchema, NArgExpr* colViews, NArgExpr* tablesList,
00404 SelectOptionsInternal* options )
00405 {
00406 ParseInfo parseInfo(querySchema);
00407
00408
00409
00410
00411 uint columnNum = 0;
00412
00413
00414
00415
00416
00417 if (tablesList) {
00418 for (int i=0; i<tablesList->args(); i++, columnNum++) {
00419 BaseExpr *e = tablesList->arg(i);
00420 VariableExpr* t_e = 0;
00421 QCString aliasString;
00422 if (e->exprClass() == KexiDBExpr_SpecialBinary) {
00423 BinaryExpr* t_with_alias = e->toBinary();
00424 assert(t_with_alias);
00425 assert(t_with_alias->left()->exprClass() == KexiDBExpr_Variable);
00426 assert(t_with_alias->right()->exprClass() == KexiDBExpr_Variable
00427 && (t_with_alias->token()==AS || t_with_alias->token()==0));
00428 t_e = t_with_alias->left()->toVariable();
00429 aliasString = t_with_alias->right()->toVariable()->name.latin1();
00430 }
00431 else {
00432 t_e = e->toVariable();
00433 }
00434 assert(t_e);
00435 QCString tname = t_e->name.latin1();
00436 TableSchema *s = parser->db()->tableSchema(tname);
00437 if(!s) {
00438 setError(
00439 i18n("Table \"%1\" does not exist").arg(tname));
00440
00441 CLEANUP;
00442 return 0;
00443 }
00444 QCString tableOrAliasName;
00445 if (!aliasString.isEmpty()) {
00446 tableOrAliasName = aliasString;
00447
00448 } else {
00449 tableOrAliasName = tname;
00450 }
00451
00452
00453 QValueList<int> *list = parseInfo.repeatedTablesAndAliases[tableOrAliasName];
00454 if (list) {
00455
00456 list->append( i );
00457
00458 }
00459 else {
00460 list = new QValueList<int>();
00461 list->append( i );
00462 parseInfo.repeatedTablesAndAliases.insert( tableOrAliasName, list );
00463
00464 }
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484 querySchema->addTable( s, aliasString );
00485 }
00486 }
00487
00488
00489
00490 if (querySchema->tables()->count()==1)
00491 querySchema->setMasterTable(querySchema->tables()->first());
00492
00493
00494 if (colViews) {
00495 BaseExpr *e;
00496 columnNum = 0;
00497 const uint colCount = colViews->list.count();
00498
00499 colViews->list.first();
00500 for (; columnNum<colCount; columnNum++) {
00501 e = colViews->list.current();
00502 bool moveNext = true;
00503 BaseExpr *columnExpr = e;
00504 VariableExpr* aliasVariable = 0;
00505 if (e->exprClass() == KexiDBExpr_SpecialBinary && e->toBinary()
00506 && (e->token()==AS || e->token()==0))
00507 {
00508
00509 columnExpr = e->toBinary()->left();
00510
00511 aliasVariable = e->toBinary()->right()->toVariable();
00512 if (!aliasVariable) {
00513 setError(i18n("Invalid alias definition for column \"%1\"")
00514 .arg(columnExpr->toString()));
00515 CLEANUP;
00516 return 0;
00517 }
00518 }
00519
00520 const int c = columnExpr->exprClass();
00521 const bool isExpressionField =
00522 c == KexiDBExpr_Const
00523 || c == KexiDBExpr_Unary
00524 || c == KexiDBExpr_Arithm
00525 || c == KexiDBExpr_Logical
00526 || c == KexiDBExpr_Relational
00527 || c == KexiDBExpr_Const
00528 || c == KexiDBExpr_Function
00529 || c == KexiDBExpr_Aggregation;
00530
00531 if (c == KexiDBExpr_Variable) {
00532
00533 }
00534 else if (isExpressionField) {
00535
00536
00537 colViews->list.take();
00538 moveNext = false;
00539 }
00540 else if (aliasVariable) {
00541
00542 e->toBinary()->m_larg = 0;
00543 }
00544 else {
00545 setError(i18n("Invalid \"%1\" column definition").arg(e->toString()));
00546 CLEANUP;
00547 return 0;
00548 }
00549
00550 if (!addColumn( parseInfo, columnExpr )) {
00551 CLEANUP;
00552 return 0;
00553 }
00554
00555 if (aliasVariable) {
00556
00557
00558 querySchema->setColumnAlias(columnNum, aliasVariable->name.latin1());
00559 }
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575 if (moveNext) {
00576 colViews->list.next();
00577
00578 }
00579 }
00580 }
00581
00582 if (options) {
00583
00584 if (options->whereExpr) {
00585 if (!options->whereExpr->validate(parseInfo)) {
00586 setError(parseInfo.errMsg, parseInfo.errDescr);
00587 CLEANUP;
00588 return false;
00589 }
00590 querySchema->setWhereExpression(options->whereExpr);
00591 }
00592
00593 if (options->orderByColumns) {
00594 OrderByColumnList &orderByColumnList = querySchema->orderByColumnList();
00595 OrderByColumnInternal::ListConstIterator it = options->orderByColumns->constEnd();
00596 uint count = options->orderByColumns->count();
00597 --it;
00598 for (;count>0; --it, --count)
00599
00600 {
00601
00602 QueryColumnInfo *columnInfo = querySchema->columnInfo( (*it).aliasOrName, false );
00603 if (columnInfo) {
00604 orderByColumnList.appendColumn( *columnInfo, (*it).ascending );
00605 }
00606 else {
00607
00608 if ((*it).columnNumber != -1) {
00609 if (!orderByColumnList.appendColumn( *querySchema,
00610 (*it).ascending, (*it).columnNumber-1 ))
00611 {
00612 setError(i18n("Could not define sorting - no column at position %1")
00613 .arg((*it).columnNumber));
00614 CLEANUP;
00615 return 0;
00616 }
00617 }
00618 else {
00619 Field * f = querySchema->findTableField((*it).aliasOrName);
00620 if (!f) {
00621 setError(i18n("Could not define sorting - "
00622 "column name or alias \"%1\" does not exist").arg((*it).aliasOrName));
00623 CLEANUP;
00624 return 0;
00625 }
00626 orderByColumnList.appendField( *f, (*it).ascending );
00627 }
00628 }
00629 }
00630 }
00631 }
00632
00633
00634
00635
00636 CLEANUP;
00637 return querySchema;
00638 }
00639
00640 #undef CLEANUP
00641