Index: src/parse.y ================================================================== --- src/parse.y +++ src/parse.y @@ -99,10 +99,19 @@ */ struct ValueList { ExprList *pList; Select *pSelect; }; + +/* +** An instance of this structure stores the optional Oracle Hierarchical +** Query clauses - the START WITH and CONNECT BY clauses. +*/ +struct HierarchicalQuery { + Expr *pStartWith; /* The START WITH condition */ + Expr *pConnectBy; /* The CONNECT BY condition */ +}; } // end %include // Input is a single SQL command input ::= cmdlist. @@ -436,11 +445,11 @@ %type multiselect_op {int} multiselect_op(A) ::= UNION(OP). {A = @OP;} multiselect_op(A) ::= UNION ALL. {A = TK_ALL;} multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP;} %endif SQLITE_OMIT_COMPOUND_SELECT -oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) +oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) hq_opt groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). { A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset); } // The "distinct" nonterminal is true (1) if the DISTINCT keyword is @@ -636,10 +645,23 @@ limit_opt(A) ::= LIMIT expr(X). {A.pLimit = X.pExpr; A.pOffset = 0;} limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y). {A.pLimit = X.pExpr; A.pOffset = Y.pExpr;} limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y). {A.pOffset = X.pExpr; A.pLimit = Y.pExpr;} + +///////// Oracle-style CONNECT BY clauses for hierarchical queries //////////// + +%type hq_opt {struct HierarchicalQuery} +%destructor hq_opt { + sqlite3ExprDelete(pParse->db, $$.pStartWith); + sqlite3ExprDelete(pParse->db, $$.pConnectBy); +} + +hq_opt(A) ::= START WITH expr(X) CONNECT BY expr(Y). + { A.pStartWith=X.pExpr; A.pConnectBy=Y.pExpr; } +hq_opt(A) ::= CONNECT BY expr(Y). { A.pStartWith=0; A.pConnectBy=Y.pExpr; } +hq_opt(A) ::= . { A.pStartWith=0; A.pConnectBy=0; } /////////////////////////// The DELETE statement ///////////////////////////// // %ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT cmd ::= DELETE FROM fullname(X) indexed_opt(I) where_opt(W) @@ -983,10 +1005,12 @@ expr(A) ::= BITNOT(B) expr(X). {spanUnaryPrefix(&A,pParse,@B,&X,&B);} expr(A) ::= MINUS(B) expr(X). [BITNOT] {spanUnaryPrefix(&A,pParse,TK_UMINUS,&X,&B);} expr(A) ::= PLUS(B) expr(X). [BITNOT] {spanUnaryPrefix(&A,pParse,TK_UPLUS,&X,&B);} +expr(A) ::= PRIOR(B) expr(X). [BITNOT] + {spanUnaryPrefix(&A,pParse,TK_PRIOR,&X,&B);} %type between_op {int} between_op(A) ::= BETWEEN. {A = 0;} between_op(A) ::= NOT BETWEEN. {A = 1;} expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] { Index: tool/mkkeywordhash.c ================================================================== --- tool/mkkeywordhash.c +++ tool/mkkeywordhash.c @@ -136,10 +136,15 @@ #ifdef SQLITE_OMIT_AUTOVACUUM # define AUTOVACUUM 0 #else # define AUTOVACUUM 0x00020000 #endif +#ifdef SQLITE_OMIT_CONNECTBY +# define CONNECTBY 0 +#else +# define CONNECTBY 0x00040000 +#endif /* ** These are the keywords */ static Keyword aKeywordTable[] = { @@ -165,10 +170,11 @@ { "CHECK", "TK_CHECK", ALWAYS }, { "COLLATE", "TK_COLLATE", ALWAYS }, { "COLUMN", "TK_COLUMNKW", ALTER }, { "COMMIT", "TK_COMMIT", ALWAYS }, { "CONFLICT", "TK_CONFLICT", CONFLICT }, + { "CONNECT", "TK_CONNECT", CONNECTBY }, { "CONSTRAINT", "TK_CONSTRAINT", ALWAYS }, { "CREATE", "TK_CREATE", ALWAYS }, { "CROSS", "TK_JOIN_KW", ALWAYS }, { "CURRENT_DATE", "TK_CTIME_KW", ALWAYS }, { "CURRENT_TIME", "TK_CTIME_KW", ALWAYS }, @@ -230,10 +236,11 @@ { "ORDER", "TK_ORDER", ALWAYS }, { "OUTER", "TK_JOIN_KW", ALWAYS }, { "PLAN", "TK_PLAN", EXPLAIN }, { "PRAGMA", "TK_PRAGMA", PRAGMA }, { "PRIMARY", "TK_PRIMARY", ALWAYS }, + { "PRIOR", "TK_PRIOR", CONNECTBY }, { "QUERY", "TK_QUERY", EXPLAIN }, { "RAISE", "TK_RAISE", TRIGGER }, { "REFERENCES", "TK_REFERENCES", FKEY }, { "REGEXP", "TK_LIKE_KW", ALWAYS }, { "REINDEX", "TK_REINDEX", REINDEX }, @@ -245,10 +252,11 @@ { "ROLLBACK", "TK_ROLLBACK", ALWAYS }, { "ROW", "TK_ROW", TRIGGER }, { "SAVEPOINT", "TK_SAVEPOINT", ALWAYS }, { "SELECT", "TK_SELECT", ALWAYS }, { "SET", "TK_SET", ALWAYS }, + { "START", "TK_START", CONNECTBY }, { "TABLE", "TK_TABLE", ALWAYS }, { "TEMP", "TK_TEMP", ALWAYS }, { "TEMPORARY", "TK_TEMP", ALWAYS }, { "THEN", "TK_THEN", ALWAYS }, { "TO", "TK_TO", ALWAYS }, @@ -260,10 +268,11 @@ { "USING", "TK_USING", ALWAYS }, { "VACUUM", "TK_VACUUM", VACUUM }, { "VALUES", "TK_VALUES", ALWAYS }, { "VIEW", "TK_VIEW", VIEW }, { "VIRTUAL", "TK_VIRTUAL", VTAB }, + { "WITH", "TK_WITH", CONNECTBY }, { "WITHOUT", "TK_WITHOUT", ALWAYS }, { "WHEN", "TK_WHEN", ALWAYS }, { "WHERE", "TK_WHERE", ALWAYS }, };