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 Field *field = new Field(parseInfo.querySchema, columnExpr);
00263 parseInfo.querySchema->addField(field);
00264
00265 #if 0
00266 KexiDBDbg << "found variable name: " << varName << endl;
00267 int dotPos = varName.find('.');
00268 QString tableName, fieldName;
00269
00270 if (dotPos>0) {
00271 tableName = varName.left(dotPos);
00272 fieldName = varName.mid(dotPos+1);
00273 }
00274 if (tableName.isEmpty()) {
00275 fieldName = varName;
00276 if (fieldName=="*") {
00277 parseInfo.querySchema->addAsterisk( new QueryAsterisk(parseInfo.querySchema) );
00278 }
00279 else {
00280
00281 Field *firstField = 0;
00282 for (TableSchema::ListIterator it(*parseInfo.querySchema->tables()); it.current(); ++it) {
00283 Field *f = it.current()->field(fieldName);
00284 if (f) {
00285 if (!firstField) {
00286 firstField = f;
00287 } else if (f->table()!=firstField->table()) {
00288
00289 setError(i18n("Ambiguous field name"),
00290 i18n("Both table \"%1\" and \"%2\" have defined \"%3\" field. "
00291 "Use \"<tableName>.%4\" notation to specify table name.")
00292 .arg(firstField->table()->name()).arg(f->table()->name())
00293 .arg(fieldName).arg(fieldName));
00294 return false;
00295 }
00296 }
00297 }
00298 if (!firstField) {
00299 setError(i18n("Field not found"),
00300 i18n("Table containing \"%1\" field not found").arg(fieldName));
00301 return false;
00302 }
00303
00304 parseInfo.querySchema->addField(firstField);
00305 }
00306 }
00307 else {
00308 tableName = tableName.lower();
00309 TableSchema *ts = parseInfo.querySchema->table( tableName );
00310 if (ts) {
00311
00312 const QValueList<int> tPositions = parseInfo.querySchema->tablePositions(tableName);
00313 QValueList<int>::ConstIterator it = tPositions.constBegin();
00314 QCString tableAlias;
00315 bool covered = true;
00316 for (; it!=tPositions.constEnd() && covered; ++it) {
00317 tableAlias = parseInfo.querySchema->tableAlias(*it);
00318 if (tableAlias.isEmpty() || tableAlias.lower()==tableName.latin1())
00319 covered = false;
00320 KexiDBDbg << " --" << "covered by " << tableAlias << " alias" << endl;
00321 }
00322 if (covered) {
00323 setError(i18n("Could not access the table directly using its name"),
00324 i18n("Table \"%1\" is covered by aliases. Instead of \"%2\", "
00325 "you can write \"%3\"").arg(tableName)
00326 .arg(tableName+"."+fieldName).arg(tableAlias+"."+fieldName.latin1()));
00327 return false;
00328 }
00329 }
00330
00331 int tablePosition = -1;
00332 if (!ts) {
00333 tablePosition = parseInfo.querySchema->tablePositionForAlias( tableName.latin1() );
00334 if (tablePosition>=0) {
00335 ts = parseInfo.querySchema->tables()->at(tablePosition);
00336 if (ts) {
00337
00338 }
00339 }
00340 }
00341
00342
00343 if (ts) {
00344 QValueList<int> *positionsList = repeatedTablesAndAliases[ tableName ];
00345 if (!positionsList) {
00346 IMPL_ERROR(tableName + "." + fieldName + ", !positionsList ");
00347 return false;
00348 }
00349
00350 if (fieldName=="*") {
00351 if (positionsList->count()>1) {
00352 setError(i18n("Ambiguous \"%1.*\" expression").arg(tableName),
00353 i18n("More than one \"%1\" table or alias defined").arg(tableName));
00354 return false;
00355 }
00356 parseInfo.querySchema->addAsterisk( new QueryAsterisk(parseInfo.querySchema, ts) );
00357 }
00358 else {
00359
00360 Field *realField = ts->field(fieldName);
00361 if (realField) {
00362
00363
00364 int numberOfTheSameFields = 0;
00365 for (QValueList<int>::iterator it = positionsList->begin();
00366 it!=positionsList->end();++it)
00367 {
00368 TableSchema *otherTS = parseInfo.querySchema->tables()->at(*it);
00369 if (otherTS->field(fieldName))
00370 numberOfTheSameFields++;
00371 if (numberOfTheSameFields>1) {
00372 setError(i18n("Ambiguous \"%1.%2\" expression").arg(tableName).arg(fieldName),
00373 i18n("More than one \"%1\" table or alias defined containing \"%2\" field")
00374 .arg(tableName).arg(fieldName));
00375 return false;
00376 }
00377 }
00378
00379 parseInfo.querySchema->addField(realField, tablePosition);
00380 }
00381 else {
00382 setError(i18n("Field not found"), i18n("Table \"%1\" has no \"%2\" field")
00383 .arg(tableName).arg(fieldName));
00384 return false;
00385 }
00386 }
00387 }
00388 else {
00389 tableNotFoundError(tableName);
00390 return false;
00391 }
00392 }
00393 #endif
00394 return true;
00395 }
00396
00397
00398 #define CLEANUP \
00399 delete colViews; \
00400 delete tablesList
00401
00402 QuerySchema* parseSelect(
00403 QuerySchema* querySchema, NArgExpr* colViews, NArgExpr* tablesList, BaseExpr* whereExpr )
00404 {
00405 ParseInfo parseInfo(querySchema);
00406
00407
00408
00409
00410 uint columnNum = 0;
00411
00412
00413
00414
00415
00416 if (tablesList) {
00417 for (int i=0; i<tablesList->args(); i++, columnNum++) {
00418 BaseExpr *e = tablesList->arg(i);
00419 VariableExpr* t_e = 0;
00420 QCString aliasString;
00421 if (e->exprClass() == KexiDBExpr_SpecialBinary) {
00422 BinaryExpr* t_with_alias = e->toBinary();
00423 assert(t_with_alias);
00424 assert(t_with_alias->left()->exprClass() == KexiDBExpr_Variable);
00425 assert(t_with_alias->right()->exprClass() == KexiDBExpr_Variable
00426 && (t_with_alias->token()==AS || t_with_alias->token()==0));
00427 t_e = t_with_alias->left()->toVariable();
00428 aliasString = t_with_alias->right()->toVariable()->name.latin1();
00429 }
00430 else {
00431 t_e = e->toVariable();
00432 }
00433 assert(t_e);
00434 QCString tname = t_e->name.latin1();
00435 TableSchema *s = parser->db()->tableSchema(tname);
00436 if(!s) {
00437 setError(
00438 i18n("Table \"%1\" does not exist").arg(tname));
00439
00440 CLEANUP;
00441 return 0;
00442 }
00443 QCString tableOrAliasName;
00444 if (!aliasString.isEmpty()) {
00445 tableOrAliasName = aliasString;
00446
00447 } else {
00448 tableOrAliasName = tname;
00449 }
00450
00451
00452 QValueList<int> *list = parseInfo.repeatedTablesAndAliases[tableOrAliasName];
00453 if (list) {
00454
00455 list->append( i );
00456
00457 }
00458 else {
00459 list = new QValueList<int>();
00460 list->append( i );
00461 parseInfo.repeatedTablesAndAliases.insert( tableOrAliasName, list );
00462
00463 }
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483 querySchema->addTable( s, aliasString );
00484 }
00485 }
00486
00487
00488
00489 if (querySchema->tables()->count()==1)
00490 querySchema->setMasterTable(querySchema->tables()->first());
00491
00492
00493 if (colViews) {
00494 BaseExpr *e;
00495 columnNum = 0;
00496 const uint colCount = colViews->list.count();
00497
00498 colViews->list.first();
00499 for (; columnNum<colCount; columnNum++) {
00500 e = colViews->list.current();
00501 bool moveNext = true;
00502 BaseExpr *columnExpr = e;
00503 VariableExpr* aliasVariable = 0;
00504 if (e->exprClass() == KexiDBExpr_SpecialBinary && e->toBinary()
00505 && (e->token()==AS || e->token()==0))
00506 {
00507
00508 columnExpr = e->toBinary()->left();
00509
00510 aliasVariable = e->toBinary()->right()->toVariable();
00511 if (!aliasVariable) {
00512 setError(i18n("Invalid alias definition for column \"%1\"")
00513 .arg(columnExpr->toString()));
00514 CLEANUP;
00515 return 0;
00516 }
00517 }
00518
00519 const int c = columnExpr->exprClass();
00520 const bool isExpressionField =
00521 c == KexiDBExpr_Const
00522 || c == KexiDBExpr_Unary
00523 || c == KexiDBExpr_Arithm
00524 || c == KexiDBExpr_Logical
00525 || c == KexiDBExpr_Relational
00526 || c == KexiDBExpr_Const
00527 || c == KexiDBExpr_Function
00528 || c == KexiDBExpr_Aggregation;
00529
00530 if (c == KexiDBExpr_Variable) {
00531
00532 }
00533 else if (isExpressionField) {
00534
00535
00536 colViews->list.take();
00537 moveNext = false;
00538 }
00539 else if (aliasVariable) {
00540
00541 e->toBinary()->m_larg = 0;
00542 }
00543 else {
00544 setError(i18n("Invalid \"%1\" column definition").arg(e->toString()));
00545 CLEANUP;
00546 return 0;
00547 }
00548
00549 if (!addColumn( parseInfo, columnExpr )) {
00550 CLEANUP;
00551 return 0;
00552 }
00553
00554 if (aliasVariable) {
00555
00556
00557 querySchema->setColumnAlias(columnNum, aliasVariable->name.latin1());
00558 }
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574 if (moveNext) {
00575 colViews->list.next();
00576
00577 }
00578 }
00579 }
00580
00581 if (whereExpr) {
00582 if (!whereExpr->validate(parseInfo)) {
00583 setError(parseInfo.errMsg, parseInfo.errDescr);
00584 CLEANUP;
00585 return false;
00586 }
00587 querySchema->setWhereExpression(whereExpr);
00588 }
00589
00590
00591
00592
00593 CLEANUP;
00594 return querySchema;
00595 }
00596
00597 #undef CLEANUP
00598