/* This file is part of the KDE project Copyright (C) 2004 Lucijan Busch Copyright (C) 2004-2018 Jarosław Staniek This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // To keep binary compatibility, do not reorder tokens! Add new only at the end. %token SQL_TYPE %token AS %token AS_EMPTY /* used for aliases with skipped AS keyword */ %token ASC %token AUTO_INCREMENT %token BIT %token BITWISE_SHIFT_LEFT %token BITWISE_SHIFT_RIGHT %token BY %token CHARACTER_STRING_LITERAL %token CONCATENATION /* || */ %token CREATE %token DESC %token DISTINCT %token DOUBLE_QUOTED_STRING %token FROM %token JOIN %token KEY %token LEFT %token LESS_OR_EQUAL %token GREATER_OR_EQUAL %token SQL_NULL %token SQL_IS %token SQL_IS_NULL /*helper */ %token SQL_IS_NOT_NULL /*helper */ %token ORDER %token PRIMARY %token SELECT %token INTEGER_CONST %token REAL_CONST %token RIGHT %token SQL_ON %token DATE_CONST %token DATETIME_CONST %token TIME_CONST %token TABLE %token IDENTIFIER %token IDENTIFIER_DOT_ASTERISK %token QUERY_PARAMETER %token VARCHAR %token WHERE %token SQL %token SQL_TRUE %token SQL_FALSE %token UNION %token SCAN_ERROR //%token SQL_ABS //%token ACOS //%token AMPERSAND //%token SQL_ABSOLUTE //%token ADA //%token ADD //%token ADD_DAYS //%token ADD_HOURS //%token ADD_MINUTES //%token ADD_MONTHS //%token ADD_SECONDS //%token ADD_YEARS //%token ALL //%token ALLOCATE //%token ALTER %token AND //%token ANY //%token ARE //%token ASIN //%token ASCII //%token ASSERTION //%token ATAN //%token ATAN2 //%token AUTHORIZATION //%token AVG //%token BEFORE %token BETWEEN %token NOT_BETWEEN //%token SQL_BEGIN //%token BIGINT //%token BINARY //%token BIT_LENGTH //%token BREAK //%token CASCADE //%token CASCADED //%token CASE //%token CAST //%token CATALOG //%token CEILING //%token CENTER //%token SQL_CHAR //%token CHAR_LENGTH //%token CHECK //%token CLOSE //%token COALESCE //%token COBOL //%token COLLATE //%token COLLATION //%token COLUMN //%token COMMIT //%token COMPUTE //%token CONCAT //%token CONNECT //%token CONNECTION //%token CONSTRAINT //%token CONSTRAINTS //%token CONTINUE //%token CONVERT //%token CORRESPONDING //%token COS //%token COT //%token COUNT //%token CURDATE //%token CURRENT //%token CURRENT_DATE //%token CURRENT_TIME //%token CURRENT_TIMESTAMP //%token CURTIME //%token CURSOR //%token DATABASE //%token SQL_DATE //%token DATE_FORMAT //%token DATE_REMAINDER //%token DATE_VALUE //%token DAY //%token DAYOFMONTH //%token DAYOFWEEK //%token DAYOFYEAR //%token DAYS_BETWEEN //%token DEALLOCATE //%token DEC //%token DECLARE //%token DEFAULT //%token DEFERRABLE //%token DEFERRED //%token SQL_DELETE //%token DESCRIBE //%token DESCRIPTOR //%token DIAGNOSTICS //%token DICTIONARY //%token DIRECTORY //%token DISCONNECT //%token DISPLACEMENT //%token DOMAIN_TOKEN //%token SQL_DOUBLE //%token DROP //%token ELSE //%token END //%token END_EXEC //%token ESCAPE %token EXCEPT //%token SQL_EXCEPTION //%token EXEC //%token EXECUTE //%token EXISTS //%token EXP //%token EXPONENT //%token EXTERNAL //%token EXTRACT //%token FETCH //%token FIRST //%token SQL_FLOAT //%token FLOOR //%token FN //%token FOR //%token FOREIGN //%token FORTRAN //%token FOUND //%token FOUR_DIGITS //%token FULL //%token GET //%token GLOBAL //%token GO //%token GOTO //%token GRANT //conflict %token GROUP //%token HAVING //%token HOUR //%token HOURS_BETWEEN //%token IDENTITY //%token IFNULL //%token SQL_IGNORE //%token IMMEDIATE //%token INCLUDE //%token INDEX //%token INDICATOR //%token INITIALLY //%token INNER //%token SQL_INPUT %token SQL_IN //%token INSENSITIVE //%token INSERT //%token INTEGER %token INTERSECT //%token INTERVAL //%token INTO //%token IS //%token ISOLATION //%token JUSTIFY //%token LANGUAGE //%token LAST //%token LCASE //%token LENGTH //%token LEVEL %token LIKE %token ILIKE %token NOT_LIKE //%token LINE_WIDTH //%token LOCAL //%token LOCATE //%token LOG //%token SQL_LONG //%token LOWER //%token LTRIM //%token LTRIP //%token MATCH //%token SQL_MAX //%token MICROSOFT //%token SQL_MIN //%token MINUTE //%token MINUTES_BETWEEN //%token MOD //%token MODIFY //%token MODULE //%token MONTH //%token MONTHS_BETWEEN //%token MUMPS //%token NAMES //%token NATIONAL //%token NCHAR //%token NEXT //%token NODUP //%token NONE %token NOT %token NOT_EQUAL %token NOT_EQUAL2 //%token NOW //%token NULLIF //%token NUMERIC //%token OCTET_LENGTH //%token ODBC //%token OF //%token SQL_OFF //%token ONLY //%token OPEN //%token OPTION //%token OUTER //%token OUTPUT //%token OVERLAPS //%token PAGE //%token PARTIAL //%token SQL_PASCAL //%token PERSISTENT //%token CQL_PI %token OR //%token PLI //%token POSITION //%token PRECISION //%token PREPARE //%token PRESERVE //%token PRIOR //%token PRIVILEGES //%token PROCEDURE //%token PRODUCT //%token PUBLIC //%token QUARTER //%token QUIT //%token RAND //%token READ_ONLY //%token REAL //%token REFERENCES //%token REPEAT //%token REPLACE //%token RESTRICT //%token REVOKE //%token ROLLBACK //%token ROWS //%token RPAD //%token RTRIM //%token SCHEMA //%token SCREEN_WIDTH //%token SCROLL //%token SECOND //%token SECONDS_BETWEEN //%token SEQUENCE //%token SETOPT //%token SET //%token SHOWOPT //%token SIGN %token SIMILAR_TO %token NOT_SIMILAR_TO //%token SIN //%token SQL_SIZE //%token SMALLINT //%token SOME //%token SPACE //%token SQLCA //%token SQLCODE //%token SQLERROR //%token SQLSTATE //%token SQLWARNING //%token SQRT //%token STDEV //%token SUBSTRING //%token SUM //%token SYSDATE //%token SYSDATE_FORMAT //%token SYSTEM //%token TAN //%token TEMPORARY //%token THEN //%token THREE_DIGITS //%token TIME //%token TIMESTAMP //%token TIMEZONE_HOUR //%token TIMEZONE_MINUTE //%token TINYINT //%token TO //%token TO_CHAR //%token TO_DATE //%token TRANSACTION //%token TRANSLATE //%token TRANSLATION //%token TRUNCATE //%token GENERAL_TITLE //%token TWO_DIGITS //%token UCASE //%token UNIQUE //%token SQL_UNKNOWN //%token UNSIGNED_INTEGER //%token UPDATE //%token UPPER //%token USAGE //%token USER //%token ERROR_DIGIT_BEFORE_IDENTIFIER //%token USING //%token VALUE //%token VALUES //%token VARBINARY //%token VARYING //%token VENDOR //%token VIEW //%token WEEK //%token WHEN //%token WHENEVER //%token WHERE_CURRENT_OF //%token WITH //%token WORD_WRAPPED //%token WORK //%token WRAPPED %token XOR //%token YEAR //%token YEARS_BETWEEN %token UMINUS %token TABS_OR_SPACES // e.g. inside of date or time constants %token DATE_TIME_INTEGER // inside of date or time constants %token TIME_AM %token TIME_PM %type IDENTIFIER %type IDENTIFIER_DOT_ASTERISK %type QUERY_PARAMETER %type CHARACTER_STRING_LITERAL %type DOUBLE_QUOTED_STRING /* %type ColExpression %type ColView */ %type ColExpression %type ColWildCard //%type ColView %type ColItem %type ColViews %type aExpr %type aExpr2 %type aExpr3 %type aExpr4 %type aExpr5 %type aExpr6 %type aExpr7 %type aExpr8 %type aExpr9 %type aExpr10 %type DateConst %type DateValue %type YearConst %type TimeConst %type TimeValue %type DateTimeConst %type TimeMs %type TimePeriod %type aExprList %type aExprList2 %type WhereClause %type OrderByClause %type OrderByOption %type OrderByColumnId %type SelectOptions %type FlatTable %type Tables %type FlatTableList %type SelectStatement %type Select /*todo : list*/ %type StatementList /*todo: not only select*/ %type Statement %type SQL_TYPE %type INTEGER_CONST %type REAL_CONST %type DATE_TIME_INTEGER /*%type SIGNED_INTEGER */ %{ #include #include #include #include #include //! @todo OK? #ifdef Q_OS_WIN //workaround for bug on msvc # undef LLONG_MIN #endif #ifndef LLONG_MAX # define LLONG_MAX 0x7fffffffffffffffLL #endif #ifndef LLONG_MIN # define LLONG_MIN 0x8000000000000000LL #endif #ifndef LLONG_MAX # define ULLONG_MAX 0xffffffffffffffffLL #endif #ifdef _WIN32 # include #endif #include #include #include #include "KDbConnection.h" #include "KDbDateTime.h" #include "KDbExpression.h" #include "KDbField.h" #include "KDbOrderByColumn.h" #include "KDbParser.h" #include "KDbParser_p.h" #include "KDbQuerySchema.h" #include "KDbQuerySchema_p.h" #include "KDbSqlTypes.h" #include "KDbTableSchema.h" #include "kdb_debug.h" struct OrderByColumnInternal; #ifdef Q_OS_SOLARIS #include #endif QDebug operator<<(QDebug dbg, const KDbExpressionPtr& expr) { dbg.nospace() << expr.e; return dbg.space(); } int yylex(); #define YY_NO_UNPUT #define YYSTACK_USE_ALLOCA 1 #define YYMAXDEPTH 255 extern "C" { int yywrap() { return 1; } } %} %union { QString* stringValue; QByteArray* binaryValue; qint64 integerValue; bool booleanValue; KDbDate* dateValue; KDbYear* yearValue; KDbTime* timeValue; KDbTime::Period timePeriodValue; KDbDateTime* dateTimeValue; KDbOrderByColumn::SortOrder sortOrderValue; KDbField::Type colType; KDbField *field; KDbExpression *expr; KDbNArgExpression *exprList; KDbConstExpression *constExpression; KDbQuerySchema *querySchema; SelectOptionsInternal *selectOptions; QList *orderByColumns; QVariant *variantValue; } /* precedence: lowest to highest */ //%nonassoc SIMILAR //%nonassoc ESCAPE //%nonassoc OVERLAPS //%nonassoc IN_P //%left POSTFIXOP // dummy for postfix Op rules //%left Op OPERATOR // multi-character ops and user-defined operators //%nonassoc NOTNULL //%nonassoc ISNULL //%nonassoc IS // sets precedence for IS NULL, etc //%nonassoc NULL_P //%nonassoc TRUE_P //%nonassoc FALSE_P // <-- To keep binary compatibility insert new tokens here. /* * These might seem to be low-precedence, but actually they are not part * of the arithmetic hierarchy at all in their use as JOIN operators. * We make them high-precedence to support their use as function names. * They wouldn't be given a precedence at all, were it not that we need * left-associativity among the JOIN rules themselves. */ /* %left JOIN %left UNIONJOIN %left CROSS %left LEFT %left FULL %left RIGHT %left INNER_P %left NATURAL */ %% TopLevelStatement : StatementList { //todo: multiple statements //todo: not only "select" statements KDbParserPrivate::get(globalParser)->setStatementType(KDbParser::Select); KDbParserPrivate::get(globalParser)->setQuerySchema($1); } ; StatementList: Statement ';' StatementList { //todo: multiple statements } | Statement | Statement ';' { $$ = $1; } ; /* Statement CreateTableStatement { YYACCEPT; } | Statement SelectStatement { } */ Statement : /*CreateTableStatement { YYACCEPT; } | */ SelectStatement { $$ = $1; } ; /*CreateTableStatement : CREATE TABLE IDENTIFIER { globalParser->setStatementType(KDbParser::CreateTable); globalParser->createTable($3->toLatin1()); delete $3; } '(' ColDefs ')' ; ColDefs: ColDefs ',' ColDef|ColDef { } ; ColDef: IDENTIFIER ColType { sqlParserDebug() << "adding field " << *$1; globalField->setName(*$1); globalParser->table()->addField(globalField); globalField = nullptr; delete $1; } | IDENTIFIER ColType ColKeys { sqlParserDebug() << "adding field " << *$1; globalField->setName(*$1); delete $1; globalParser->table()->addField(globalField); // if(globalField->isPrimaryKey()) // globalParser->table()->addPrimaryKey(globalField->name()); // delete globalField; // globalField = nullptr; } ; ColKeys: ColKeys ColKey|ColKey { } ; ColKey: PRIMARY KEY { globalField->setPrimaryKey(true); sqlParserDebug() << "primary"; } | NOT SQL_NULL { globalField->setNotNull(true); sqlParserDebug() << "not_null"; } | AUTO_INCREMENT { globalField->setAutoIncrement(true); sqlParserDebug() << "ainc"; } ; ColType: SQL_TYPE { globalField = new KDbField(); globalField->setType($1); } | SQL_TYPE '(' INTEGER_CONST ')' { sqlParserDebug() << "sql + length"; globalField = new KDbField(); globalField->setPrecision($3); globalField->setType($1); } | VARCHAR '(' INTEGER_CONST ')' { globalField = new KDbField(); globalField->setPrecision($3); globalField->setType(KDbField::Text); } | %empty { // SQLITE compatibillity globalField = new KDbField(); globalField->setType(KDbField::InvalidType); } ;*/ SelectStatement: Select { sqlParserDebug() << "Select"; if (!($$ = buildSelectQuery( $1, nullptr ))) YYABORT; } | Select ColViews { sqlParserDebug() << "Select ColViews=" << *$2; if (!($$ = buildSelectQuery( $1, $2 ))) YYABORT; } | Select ColViews Tables { if (!($$ = buildSelectQuery( $1, $2, $3 ))) YYABORT; } | Select Tables { sqlParserDebug() << "Select ColViews Tables"; if (!($$ = buildSelectQuery( $1, nullptr, $2 ))) YYABORT; } | Select ColViews SelectOptions { sqlParserDebug() << "Select ColViews Conditions"; if (!($$ = buildSelectQuery( $1, $2, nullptr, $3 ))) YYABORT; } | Select Tables SelectOptions { sqlParserDebug() << "Select Tables SelectOptions"; if (!($$ = buildSelectQuery( $1, nullptr, $2, $3 ))) YYABORT; } | Select ColViews Tables SelectOptions { sqlParserDebug() << "Select ColViews Tables SelectOptions"; if (!($$ = buildSelectQuery( $1, $2, $3, $4 ))) YYABORT; } ; Select: SELECT { sqlParserDebug() << "SELECT"; $$ = KDbParserPrivate::get(globalParser)->createQuery(); } ; SelectOptions: /* todo: more options (having, group by, limit...) */ WhereClause { sqlParserDebug() << "WhereClause"; $$ = new SelectOptionsInternal; $$->whereExpr = *$1; delete $1; } | ORDER BY OrderByClause { sqlParserDebug() << "OrderByClause"; $$ = new SelectOptionsInternal; $$->orderByColumns = $3; } | WhereClause ORDER BY OrderByClause { sqlParserDebug() << "WhereClause ORDER BY OrderByClause"; $$ = new SelectOptionsInternal; $$->whereExpr = *$1; delete $1; $$->orderByColumns = $4; } | ORDER BY OrderByClause WhereClause { sqlParserDebug() << "OrderByClause WhereClause"; $$ = new SelectOptionsInternal; $$->whereExpr = *$4; delete $4; $$->orderByColumns = $3; } ; WhereClause: WHERE aExpr { $$ = $2; } ; /* todo: support "ORDER BY NULL" as described here https://dev.mysql.com/doc/refman/5.1/en/select.html */ /* todo: accept expr and position as well */ OrderByClause: OrderByColumnId { sqlParserDebug() << "ORDER BY IDENTIFIER"; $$ = new QList; OrderByColumnInternal orderByColumn; orderByColumn.setColumnByNameOrNumber( *$1 ); $$->append( orderByColumn ); delete $1; } | OrderByColumnId OrderByOption { sqlParserDebug() << "ORDER BY IDENTIFIER OrderByOption"; $$ = new QList; OrderByColumnInternal orderByColumn; orderByColumn.setColumnByNameOrNumber( *$1 ); orderByColumn.order = $2; $$->append( orderByColumn ); delete $1; } | OrderByColumnId ',' OrderByClause { $$ = $3; OrderByColumnInternal orderByColumn; orderByColumn.setColumnByNameOrNumber( *$1 ); $$->append( orderByColumn ); delete $1; } | OrderByColumnId OrderByOption ',' OrderByClause { $$ = $4; OrderByColumnInternal orderByColumn; orderByColumn.setColumnByNameOrNumber( *$1 ); orderByColumn.order = $2; $$->append( orderByColumn ); delete $1; } ; OrderByColumnId: IDENTIFIER { $$ = new QVariant( *$1 ); sqlParserDebug() << "OrderByColumnId: " << *$$; delete $1; } | IDENTIFIER '.' IDENTIFIER { $$ = new QVariant( *$1 + QLatin1Char('.') + *$3 ); sqlParserDebug() << "OrderByColumnId: " << *$$; delete $1; delete $3; } | INTEGER_CONST { $$ = new QVariant($1); sqlParserDebug() << "OrderByColumnId: " << *$$; } OrderByOption: ASC { $$ = KDbOrderByColumn::SortOrder::Ascending; } | DESC { $$ = KDbOrderByColumn::SortOrder::Descending; } ; aExpr: aExpr2 ; /* --- binary logical --- */ aExpr2: aExpr3 AND aExpr2 { // sqlParserDebug() << "AND " << $3.debugString(); $$ = new KDbBinaryExpression(*$1, KDbToken::AND, *$3); delete $1; delete $3; } | aExpr3 OR aExpr2 { $$ = new KDbBinaryExpression(*$1, KDbToken::OR, *$3); delete $1; delete $3; } | aExpr3 XOR aExpr2 { $$ = new KDbBinaryExpression(*$1, KDbToken::XOR, *$3); delete $1; delete $3; } | aExpr3 ; /* relational op precedence */ aExpr3: aExpr4 '>' %prec GREATER_OR_EQUAL aExpr3 { $$ = new KDbBinaryExpression(*$1, '>', *$3); delete $1; delete $3; } | aExpr4 GREATER_OR_EQUAL aExpr3 { $$ = new KDbBinaryExpression(*$1, KDbToken::GREATER_OR_EQUAL, *$3); delete $1; delete $3; } | aExpr4 '<' %prec LESS_OR_EQUAL aExpr3 { $$ = new KDbBinaryExpression(*$1, '<', *$3); delete $1; delete $3; } | aExpr4 LESS_OR_EQUAL aExpr3 { $$ = new KDbBinaryExpression(*$1, KDbToken::LESS_OR_EQUAL, *$3); delete $1; delete $3; } | aExpr4 '=' aExpr3 { $$ = new KDbBinaryExpression(*$1, '=', *$3); delete $1; delete $3; } | aExpr4 ; /* relational (equality) op precedence */ aExpr4: aExpr5 NOT_EQUAL aExpr4 { $$ = new KDbBinaryExpression(*$1, KDbToken::NOT_EQUAL, *$3); delete $1; delete $3; } | aExpr5 NOT_EQUAL2 aExpr4 { $$ = new KDbBinaryExpression(*$1, KDbToken::NOT_EQUAL2, *$3); delete $1; delete $3; } | aExpr5 LIKE aExpr4 { $$ = new KDbBinaryExpression(*$1, KDbToken::LIKE, *$3); delete $1; delete $3; } | aExpr5 NOT_LIKE aExpr4 { $$ = new KDbBinaryExpression(*$1, KDbToken::NOT_LIKE, *$3); delete $1; delete $3; } | aExpr5 SQL_IN aExpr4 { $$ = new KDbBinaryExpression(*$1, KDbToken::SQL_IN, *$3); delete $1; delete $3; } | aExpr5 SIMILAR_TO aExpr4 { $$ = new KDbBinaryExpression(*$1, KDbToken::SIMILAR_TO, *$3); delete $1; delete $3; } | aExpr5 NOT_SIMILAR_TO aExpr4 { $$ = new KDbBinaryExpression(*$1, KDbToken::NOT_SIMILAR_TO, *$3); delete $1; delete $3; } | aExpr5 BETWEEN aExpr4 AND aExpr4 { $$ = new KDbNArgExpression(KDb::RelationalExpression, KDbToken::BETWEEN_AND); $$->toNArg().append( *$1 ); $$->toNArg().append( *$3 ); $$->toNArg().append( *$5 ); delete $1; delete $3; delete $5; } | aExpr5 NOT_BETWEEN aExpr4 AND aExpr4 { $$ = new KDbNArgExpression(KDb::RelationalExpression, KDbToken::NOT_BETWEEN_AND); $$->toNArg().append( *$1 ); $$->toNArg().append( *$3 ); $$->toNArg().append( *$5 ); delete $1; delete $3; delete $5; } | aExpr5 ; /* --- unary logical right --- */ aExpr5: aExpr5 SQL_IS_NULL { $$ = new KDbUnaryExpression( KDbToken::SQL_IS_NULL, *$1 ); delete $1; } | aExpr5 SQL_IS_NOT_NULL { $$ = new KDbUnaryExpression( KDbToken::SQL_IS_NOT_NULL, *$1 ); delete $1; } | aExpr6 ; /* arithm. lowest precedence */ aExpr6: aExpr7 BITWISE_SHIFT_LEFT aExpr6 { $$ = new KDbBinaryExpression(*$1, KDbToken::BITWISE_SHIFT_LEFT, *$3); delete $1; delete $3; } | aExpr7 BITWISE_SHIFT_RIGHT aExpr6 { $$ = new KDbBinaryExpression(*$1, KDbToken::BITWISE_SHIFT_RIGHT, *$3); delete $1; delete $3; } | aExpr7 ; /* arithm. lower precedence */ aExpr7: aExpr8 '+' aExpr7 { $$ = new KDbBinaryExpression(*$1, '+', *$3); delete $1; delete $3; } | aExpr8 CONCATENATION aExpr7 { $$ = new KDbBinaryExpression(*$1, KDbToken::CONCATENATION, *$3); delete $1; delete $3; } | aExpr8 '-' %prec UMINUS aExpr7 { $$ = new KDbBinaryExpression(*$1, '-', *$3); delete $1; delete $3; } | aExpr8 '&' aExpr7 { $$ = new KDbBinaryExpression(*$1, '&', *$3); delete $1; delete $3; } | aExpr8 '|' aExpr7 { $$ = new KDbBinaryExpression(*$1, '|', *$3); delete $1; delete $3; } | aExpr8 ; /* arithm. higher precedence */ aExpr8: aExpr9 '/' aExpr8 { $$ = new KDbBinaryExpression(*$1, '/', *$3); delete $1; delete $3; } | aExpr9 '*' aExpr8 { $$ = new KDbBinaryExpression(*$1, '*', *$3); delete $1; delete $3; } | aExpr9 '%' aExpr8 { $$ = new KDbBinaryExpression(*$1, '%', *$3); delete $1; delete $3; } | aExpr9 ; /* parenthesis, unary operators, and terminals precedence */ aExpr9: /* --- unary logical left --- */ '-' aExpr9 { $$ = new KDbUnaryExpression( '-', *$2 ); delete $2; } | '+' aExpr9 { $$ = new KDbUnaryExpression( '+', *$2 ); delete $2; } | '~' aExpr9 { $$ = new KDbUnaryExpression( '~', *$2 ); delete $2; } | NOT aExpr9 { $$ = new KDbUnaryExpression( KDbToken::NOT, *$2 ); delete $2; } | IDENTIFIER { $$ = new KDbVariableExpression( *$1 ); //! @todo simplify this later if that's 'only one field name' expression sqlParserDebug() << " + identifier: " << *$1; delete $1; } | QUERY_PARAMETER { $$ = new KDbQueryParameterExpression( *$1 ); sqlParserDebug() << " + query parameter:" << *$$; delete $1; } | IDENTIFIER aExprList { sqlParserDebug() << " + function:" << *$1 << "(" << *$2 << ")"; $$ = new KDbFunctionExpression(*$1, *$2); delete $1; delete $2; } /*! @todo shall we also support db name? */ | IDENTIFIER '.' IDENTIFIER { $$ = new KDbVariableExpression( *$1 + QLatin1Char('.') + *$3 ); sqlParserDebug() << " + identifier.identifier:" << *$1 << "." << *$3; delete $1; delete $3; } | SQL_NULL { $$ = new KDbConstExpression( KDbToken::SQL_NULL, QVariant() ); sqlParserDebug() << " + NULL"; // $$ = new KDbField(); //$$->setName(QString::null); } | SQL_TRUE { $$ = new KDbConstExpression( KDbToken::SQL_TRUE, true ); } | SQL_FALSE { $$ = new KDbConstExpression( KDbToken::SQL_FALSE, false ); } | CHARACTER_STRING_LITERAL { $$ = new KDbConstExpression( KDbToken::CHARACTER_STRING_LITERAL, *$1 ); sqlParserDebug() << " + constant " << $1; delete $1; } | INTEGER_CONST { QVariant val; if ($1 <= INT_MAX && $1 >= INT_MIN) val = (int)$1; else if ($1 <= UINT_MAX && $1 >= 0) val = (uint)$1; else if ($1 <= LLONG_MAX && $1 >= LLONG_MIN) val = (qint64)$1; // if ($1 < ULLONG_MAX) // val = (quint64)$1; //! @todo ok? $$ = new KDbConstExpression( KDbToken::INTEGER_CONST, val ); sqlParserDebug() << " + int constant: " << val.toString(); } | REAL_CONST { $$ = new KDbConstExpression( KDbToken::REAL_CONST, *$1 ); sqlParserDebug() << " + real constant: " << *$1; delete $1; } | DateConst { $$ = new KDbConstExpression(KDbToken::DATE_CONST, QVariant::fromValue(*$1)); sqlParserDebug() << " + date constant:" << *$1; delete $1; } | TimeConst { $$ = new KDbConstExpression(KDbToken::TIME_CONST, QVariant::fromValue(*$1)); sqlParserDebug() << " + time constant:" << *$1; delete $1; } | DateTimeConst { $$ = new KDbConstExpression(KDbToken::DATETIME_CONST, QVariant::fromValue(*$1)); sqlParserDebug() << " + datetime constant:" << *$1; delete $1; } | aExpr10 ; DateConst: '#' DateValue '#' { $$ = $2; sqlParserDebug() << "DateConst:" << *$$; } ; DateValue: YearConst '-' DATE_TIME_INTEGER '-' DATE_TIME_INTEGER { $$ = new KDbDate(*$1, *$3, *$5); sqlParserDebug() << "DateValue:" << *$$; delete $1; delete $3; delete $5; } | DATE_TIME_INTEGER '/' DATE_TIME_INTEGER '/' YearConst /* M/D/Y */ { $$ = new KDbDate(*$5, *$1, *$3); sqlParserDebug() << "DateValue:" << *$$; delete $1; delete $3; delete $5; } ; YearConst: DATE_TIME_INTEGER { $$ = new KDbYear(KDbYear::Sign::None, *$1); sqlParserDebug() << "YearConst:" << *$$; delete $1; } | '+' DATE_TIME_INTEGER { $$ = new KDbYear(KDbYear::Sign::Plus, *$2); sqlParserDebug() << "YearConst:" << *$$; delete $2; } | '-' DATE_TIME_INTEGER { $$ = new KDbYear(KDbYear::Sign::Minus, *$2); sqlParserDebug() << "YearConst:" << *$$; delete $2; } ; TimeConst: '#' TimeValue '#' { $$ = $2; sqlParserDebug() << "TimeConst:" << *$$; } ; TimeValue: DATE_TIME_INTEGER ':' DATE_TIME_INTEGER TimeMs TimePeriod { $$ = new KDbTime(*$1, *$3, {}, *$4, $5); sqlParserDebug() << "TimeValue:" << *$$; delete $1; delete $3; delete $4; } | DATE_TIME_INTEGER ':' DATE_TIME_INTEGER ':' DATE_TIME_INTEGER TimeMs TimePeriod { $$ = new KDbTime(*$1, *$3, *$5, *$6, $7); sqlParserDebug() << "TimeValue:" << *$$; delete $1; delete $3; delete $5; delete $6; } ; TimeMs: '.' DATE_TIME_INTEGER { $$ = $2; } | %empty { $$ = new QByteArray; } ; TimePeriod: TIME_AM { $$ = KDbTime::Period::Am; } | TIME_PM { $$ = KDbTime::Period::Pm; } | %empty { $$ = KDbTime::Period::None; } ; DateTimeConst: '#' DateValue TABS_OR_SPACES TimeValue '#' { $$ = new KDbDateTime(*$2, *$4); sqlParserDebug() << "DateTimeConst:" << *$$; delete $2; delete $4; } ; aExpr10: '(' aExpr ')' { sqlParserDebug() << "(expr)"; $$ = new KDbUnaryExpression('(', *$2); delete $2; } ; aExprList: '(' aExprList2 ')' { $$ = $2; } | '(' ')' { $$ = new KDbNArgExpression(KDb::ArgumentListExpression, ','); } ; aExprList2: aExpr ',' aExprList2 { $$ = $3; $$->prepend( *$1 ); delete $1; } | aExpr { $$ = new KDbNArgExpression(KDb::ArgumentListExpression, ','); $$->append( *$1 ); delete $1; } ; Tables: FROM FlatTableList { $$ = $2; } /* | Tables LEFT JOIN IDENTIFIER SQL_ON ColExpression { sqlParserDebug() << "LEFT JOIN: '" << *$4 << "' ON " << $6; addTable($4->toQString()); delete $4; } | Tables LEFT OUTER JOIN IDENTIFIER SQL_ON ColExpression { sqlParserDebug() << "LEFT OUTER JOIN: '" << $5 << "' ON " << $7; addTable($5); } | Tables INNER JOIN IDENTIFIER SQL_ON ColExpression { sqlParserDebug() << "INNER JOIN: '" << *$4 << "' ON " << $6; addTable($4->toQString()); delete $4; } | Tables RIGHT JOIN IDENTIFIER SQL_ON ColExpression { sqlParserDebug() << "RIGHT JOIN: '" << *$4 << "' ON " << $6; addTable(*$4); delete $4; } | Tables RIGHT OUTER JOIN IDENTIFIER SQL_ON ColExpression { sqlParserDebug() << "RIGHT OUTER JOIN: '" << *$5 << "' ON " << $7; addTable($5->toQString()); delete $5; }*/ ; /* FlatTableList: aFlatTableList { $$ } ;*/ FlatTableList: FlatTableList ',' FlatTable { $$ = $1; $$->append(*$3); delete $3; } |FlatTable { $$ = new KDbNArgExpression(KDb::TableListExpression, KDbToken::IDENTIFIER); //ok? $$->append(*$1); delete $1; } ; FlatTable: IDENTIFIER { sqlParserDebug() << "FROM: '" << *$1 << "'"; $$ = new KDbVariableExpression(*$1); //! @todo this isn't ok for more tables: /* KDbField::ListIterator it = globalParser->query()->fieldsIterator(); for(KDbField *item; (item = it.current()); ++it) { if(item->table() == dummy) { item->setTable(schema); } if(item->table() && !item->isQueryAsterisk()) { KDbField *f = item->table()->field(item->name()); if(!f) { KDbParserError err(KDbParser::tr("Field List Error"), KDbParser::tr("Unknown column '%1' in table '%2'",item->name(),schema->name()), ctoken, current); globalParser->setError(err); yyerror("fieldlisterror"); } } }*/ delete $1; } | IDENTIFIER IDENTIFIER { //table + alias $$ = new KDbBinaryExpression( KDbVariableExpression(*$1), KDbToken::AS_EMPTY, KDbVariableExpression(*$2) ); delete $1; delete $2; } | IDENTIFIER AS IDENTIFIER { //table + alias $$ = new KDbBinaryExpression( KDbVariableExpression(*$1), KDbToken::AS, KDbVariableExpression(*$3) ); delete $1; delete $3; } ; ColViews: ColViews ',' ColItem { $$ = $1; $$->append(*$3); delete $3; sqlParserDebug() << "ColViews: ColViews , ColItem"; } |ColItem { $$ = new KDbNArgExpression(KDb::FieldListExpression, KDbToken()); $$->append(*$1); delete $1; sqlParserDebug() << "ColViews: ColItem"; } ; ColItem: ColExpression { // $$ = new KDbField(); // dummy->addField($$); // $$->setExpression( $1 ); // globalParser->query()->addField($$); $$ = $1; sqlParserDebug() << " added column expr:" << *$1; } | ColWildCard { $$ = $1; sqlParserDebug() << " added column wildcard:" << *$1; } | ColExpression AS IDENTIFIER { $$ = new KDbBinaryExpression( *$1, KDbToken::AS, KDbVariableExpression(*$3) ); sqlParserDebug() << " added column expr:" << *$$; delete $1; delete $3; } | ColExpression IDENTIFIER { $$ = new KDbBinaryExpression( *$1, KDbToken::AS_EMPTY, KDbVariableExpression(*$2) ); sqlParserDebug() << " added column expr:" << *$$; delete $1; delete $2; } ; ColExpression: aExpr { $$ = $1; } /* HANDLED BY 'IDENTIFIER aExprList' | IDENTIFIER '(' ColViews ')' { $$ = new KDbFunctionExpression( $1, $3 ); }*/ //! @todo /* | SUM '(' ColExpression ')' { KDbFunctionExpression( // $$ = new AggregationExpression( SUM, ); // $$->setName("SUM(" + $3->name() + ")"); //wait $$->containsGroupingAggregate(true); //wait globalParser->query()->grouped(true); }*/ //! @todo /* | SQL_MIN '(' ColExpression ')' { $$ = $3; // $$->setName("MIN(" + $3->name() + ")"); //wait $$->containsGroupingAggregate(true); //wait globalParser->query()->grouped(true); }*/ //! @todo /* | SQL_MAX '(' ColExpression ')' { $$ = $3; // $$->setName("MAX(" + $3->name() + ")"); //wait $$->containsGroupingAggregate(true); //wait globalParser->query()->grouped(true); }*/ //! @todo /* | AVG '(' ColExpression ')' { $$ = $3; // $$->setName("AVG(" + $3->name() + ")"); //wait $$->containsGroupingAggregate(true); //wait globalParser->query()->grouped(true); }*/ | DISTINCT '(' ColExpression ')' { $$ = $3; //! @todo DISTINCT '(' ColExpression ')' // $$->setName("DISTINCT(" + $3->name() + ")"); } ; ColWildCard: '*' { $$ = new KDbVariableExpression(QLatin1String("*")); sqlParserDebug() << "all columns"; // KDbQueryAsterisk *ast = new KDbQueryAsterisk(globalParser->query(), dummy); // globalParser->query()->addAsterisk(ast); // requiresTable = true; } | IDENTIFIER '.' '*' { QString s( *$1 ); s += QLatin1String(".*"); $$ = new KDbVariableExpression(s); sqlParserDebug() << " + all columns from " << s; delete $1; } /*| ERROR_DIGIT_BEFORE_IDENTIFIER { $$ = new KDbVariableExpression($1); sqlParserDebug() << " Invalid identifier! " << $1; setError(KDbParser::tr("Invalid identifier \"%1\"",$1)); }*/ ; %%