/** * Method declaration * * * @param e * * @return * * @throws Exception */ private bool test(Expression e) { if (e == null) { return true; } return e.test(); }
/** * Method declaration * * * @param e * * @throws Exception */ public void setCondition(Expression e) { int type = e.getType(); Expression e1 = e.getArg(); Expression e2 = e.getArg2(); if (type == Expression.AND) { setCondition(e1); setCondition(e2); return; } int candidate; switch (type) { case Expression.NOT_EQUAL: case Expression.LIKE: // todo: maybe use index case Expression.IN: candidate = 0; break; case Expression.EQUAL: candidate = 1; break; case Expression.BIGGER: case Expression.BIGGER_EQUAL: candidate = 2; break; case Expression.SMALLER: case Expression.SMALLER_EQUAL: candidate = 3; break; default: // not a condition so forget it return; } if (e1.getFilter() == this) { // ok include this } else if (e2.getFilter() == this && candidate != 0) { // swap and try again to allow index usage e.swapCondition(); setCondition(e); return; } else { // unrelated: don't include return; } Trace.assert(e1.getFilter() == this, "setCondition"); if (!e2.isResolved()) { return; } if (candidate == 0) { addAndCondition(e); return; } int i = e1.getColumnNr(); Index index = tTable.getIndexForColumn(i); if (index == null || (iIndex != index && iIndex != null)) { // no index or already another index is used addAndCondition(e); return; } iIndex = index; if (candidate == 1) { // candidate for both start & end if (eStart != null || eEnd != null) { addAndCondition(e); return; } eStart = new Expression(e); eEnd = eStart; } else if (candidate == 2) { // candidate for start if (eStart != null) { addAndCondition(e); return; } eStart = new Expression(e); } else if (candidate == 3) { // candidate for end if (eEnd != null) { addAndCondition(e); return; } eEnd = new Expression(e); } e.setTrue(); }
/** * Method declaration * * * @param e */ private void addAndCondition(Expression e) { Expression e2 = new Expression(e); if (eAnd == null) { eAnd = e2; } else { Expression and = new Expression(Expression.AND, eAnd, e2); eAnd = and; } e.setTrue(); }
/** * Constructor declaration * * * @param type * @param e * @param e2 */ public Expression(int type, Expression e, Expression e2) { iType = type; eArg = e; eArg2 = e2; }
/** * Method declaration * * * @throws Exception */ public void swapCondition() { int i = EQUAL; switch (iType) { case BIGGER_EQUAL: i = SMALLER_EQUAL; break; case SMALLER_EQUAL: i = BIGGER_EQUAL; break; case SMALLER: i = BIGGER; break; case BIGGER: i = SMALLER; break; case EQUAL: break; default: Trace.assert(false, "Expression.swapCondition"); } iType = i; Expression e = eArg; eArg = eArg2; eArg2 = e; }
/** * Method declaration * * * @return * * @throws Exception */ public Result processUpdate() { string token = tTokenizer.getstring(); cChannel.checkReadWrite(); cChannel.check(token, Access.UPDATE); Table table = dDatabase.getTable(token, cChannel); TableFilter filter = new TableFilter(table, null, false); tTokenizer.getThis("SET"); ArrayList vColumn = new ArrayList(); ArrayList eColumn = new ArrayList(); int len = 0; token = null; do { len++; int i = table.getColumnNr(tTokenizer.getstring()); vColumn.Add(i); tTokenizer.getThis("="); Expression e = parseExpression(); e.resolve(filter); eColumn.Add(e); token = tTokenizer.getstring(); } while (token.Equals(",")); Expression eCondition = null; if (token.Equals("WHERE")) { eCondition = parseExpression(); eCondition.resolve(filter); filter.setCondition(eCondition); } else { tTokenizer.back(); } // do the update Expression[] exp = new Expression[len]; eColumn.CopyTo(exp); int[] col = new int[len]; int[] type = new int[len]; for (int i = 0; i < len; i++) { col[i] = ((int) vColumn[i]); type[i] = table.getType(col[i]); } int count = 0; if (filter.findFirst()) { Result del = new Result(); // don't need column count and so on Result ins = new Result(); int size = table.getColumnCount(); do { if (eCondition == null || eCondition.test()) { object[] nd = filter.oCurrentData; del.add(nd); object[] ni = table.getNewRow(); for (int i = 0; i < size; i++) { ni[i] = nd[i]; } for (int i = 0; i < len; i++) { ni[col[i]] = exp[i].getValue(type[i]); } ins.add(ni); } } while (filter.next()); cChannel.beginNestedTransaction(); try { Record nd = del.rRoot; while (nd != null) { table.deleteNoCheck(nd.data, cChannel); nd = nd.next; } Record ni = ins.rRoot; while (ni != null) { table.insertNoCheck(ni.data, cChannel); ni = ni.next; count++; } table.checkUpdate(col, del, ins); ni = ins.rRoot; while (ni != null) { ni = ni.next; } cChannel.endNestedTransaction(false); } catch (Exception e) { // update failed (violation of primary key / referential integrity) cChannel.endNestedTransaction(true); throw e; } } Result r = new Result(); r.iUpdateCount = count; return r; }
private TableFilter tFilter; // null if not yet resolved #endregion Fields #region Constructors /** * Constructor declaration * * * @param f */ /* Expression(Function f) { iType = FUNCTION; fFunction = f; } */ /** * Constructor declaration * * * @param e */ public Expression(Expression e) { iType = e.iType; iDataType = e.iDataType; eArg = e.eArg; eArg2 = e.eArg2; cLikeEscape = e.cLikeEscape; sSelect = e.sSelect; // fFunction = e.fFunction; }
/** * Method declaration * * * @return * * @throws Exception */ private Expression readSum() { Expression r = readFactor(); while (true) { int type; if (iToken == Expression.PLUS) { type = Expression.ADD; } else if (iToken == Expression.NEGATE) { type = Expression.SUBTRACT; } else { break; } Expression a = r; read(); r = new Expression(type, a, readFactor()); } return r; }
/** * Method declaration * * * @return * * @throws Exception */ private Expression readTerm() { Expression r = null; if (iToken == Expression.COLUMN) { string name = sToken; r = new Expression(sTable, sToken); read(); /* if (iToken == Expression.OPEN) { Function f = new Function(dDatabase.getAlias(name), cChannel); int len = f.getArgCount(); int i = 0; read(); if (iToken != Expression.CLOSE) { while (true) { f.setArgument(i++, readOr()); if (iToken != Expression.COMMA) { break; } read(); } } readThis(Expression.CLOSE); r = new Expression(f); } */ } else if (iToken == Expression.NEGATE) { int type = iToken; read(); r = new Expression(type, readTerm(), null); } else if (iToken == Expression.PLUS) { read(); r = readTerm(); } else if (iToken == Expression.OPEN) { read(); r = readOr(); if (iToken != Expression.CLOSE) { throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken); } read(); } else if (iToken == Expression.VALUE) { r = new Expression(iType, oData); read(); } else if (iToken == Expression.SELECT) { r = new Expression(parseSelect()); read(); } else if (iToken == Expression.MULTIPLY) { r = new Expression(sTable, null); read(); } else if (iToken == Expression.IFNULL || iToken == Expression.CONCAT) { int type = iToken; read(); readThis(Expression.OPEN); r = readOr(); readThis(Expression.COMMA); r = new Expression(type, r, readOr()); readThis(Expression.CLOSE); } else if (iToken == Expression.CASEWHEN) { int type = iToken; read(); readThis(Expression.OPEN); r = readOr(); readThis(Expression.COMMA); Expression thenelse = readOr(); readThis(Expression.COMMA); // thenelse part is never evaluated; only init thenelse = new Expression(type, thenelse, readOr()); r = new Expression(type, r, thenelse); readThis(Expression.CLOSE); } else if (iToken == Expression.CONVERT) { int type = iToken; read(); readThis(Expression.OPEN); r = readOr(); readThis(Expression.COMMA); int t = Column.getTypeNr(sToken); r = new Expression(type, r, null); r.setDataType(t); read(); readThis(Expression.CLOSE); } else if (iToken == Expression.CAST) { read(); readThis(Expression.OPEN); r = readOr(); Trace.check(sToken.Equals("AS"), Trace.UNEXPECTED_TOKEN, sToken); read(); int t = Column.getTypeNr(sToken); r = new Expression(Expression.CONVERT, r, null); r.setDataType(t); read(); readThis(Expression.CLOSE); } else { throw Trace.error(Trace.UNEXPECTED_TOKEN, sToken); } return r; }
/** * Method declaration * * * @return * * @throws Exception */ private Expression readFactor() { Expression r = readTerm(); while (iToken == Expression.MULTIPLY || iToken == Expression.DIVIDE) { int type = iToken; Expression a = r; read(); r = new Expression(type, a, readTerm()); } return r; }
/** * Method declaration * * * @return * * @throws Exception */ private Expression readOr() { Expression r = readAnd(); while (iToken == Expression.OR) { int type = iToken; Expression a = r; read(); r = new Expression(type, a, readAnd()); } return r; }
/** * Method declaration * * * @return * * @throws Exception */ private Expression readCondition() { if (iToken == Expression.NOT) { int type = iToken; read(); return new Expression(type, readCondition(), null); } else if (iToken == Expression.EXISTS) { int type = iToken; read(); readThis(Expression.OPEN); Trace.check(iToken == Expression.SELECT, Trace.UNEXPECTED_TOKEN); Expression s = new Expression(parseSelect()); read(); readThis(Expression.CLOSE); return new Expression(type, s, null); } else { Expression a = readConcat(); bool not = false; if (iToken == Expression.NOT) { not = true; read(); } if (iToken == Expression.LIKE) { read(); Expression b = readConcat(); char escape = "0".ToChar(); if (sToken.Equals("ESCAPE")) { read(); Expression c = readTerm(); Trace.check(c.getType() == Expression.VALUE, Trace.INVALID_ESCAPE); string s = (string) c.getValue(Column.VARCHAR); if (s == null || s.Length < 1) { throw Trace.error(Trace.INVALID_ESCAPE, s); } escape = s.Substring(0,1).ToChar(); } a = new Expression(Expression.LIKE, a, b); a.setLikeEscape(escape); } else if (iToken == Expression.BETWEEN) { read(); Expression l = new Expression(Expression.BIGGER_EQUAL, a, readConcat()); readThis(Expression.AND); Expression h = new Expression(Expression.SMALLER_EQUAL, a, readConcat()); a = new Expression(Expression.AND, l, h); } else if (iToken == Expression.IN) { int type = iToken; read(); readThis(Expression.OPEN); Expression b = null; if (iToken == Expression.SELECT) { b = new Expression(parseSelect()); read(); } else { tTokenizer.back(); ArrayList v = new ArrayList(); while (true) { v.Add(getValue(Column.VARCHAR)); read(); if (iToken != Expression.COMMA) { break; } } b = new Expression(v); } readThis(Expression.CLOSE); a = new Expression(type, a, b); } else { Trace.check(!not, Trace.UNEXPECTED_TOKEN); if (Expression.isCompare(iToken)) { int type = iToken; read(); return new Expression(type, a, readConcat()); } return a; } if (not) { a = new Expression(Expression.NOT, a, null); } return a; } }
/** * Method declaration * * * @return * * @throws Exception */ private Expression readConcat() { Expression r = readSum(); while (iToken == Expression.STRINGCONCAT) { int type = Expression.CONCAT; Expression a = r; read(); r = new Expression(type, a, readSum()); } return r; }
/** * Method declaration * * * @return * * @throws Exception */ private Select parseSelect() { Select select = new Select(); // [email protected] begin changes from 1.50 select.limitStart = 0; select.limitCount = cChannel.getMaxRows(); // [email protected] end changes from 1.50 string token = tTokenizer.getstring(); if (token.Equals("DISTINCT")) { select.bDistinct = true; // [email protected] begin changes from 1.50 } else if( token.Equals("LIMIT")) { string limStart = tTokenizer.getstring(); string limEnd = tTokenizer.getstring(); //System.out.println( "LIMIT used from "+limStart+","+limEnd); select.limitStart = limStart.ToInt32(); select.limitCount = limEnd.ToInt32(); // [email protected] end changes from 1.50 } else { tTokenizer.back(); } // parse column list ArrayList vcolumn = new ArrayList(); do { Expression e = parseExpression(); token = tTokenizer.getstring(); if (token.Equals("AS")) { e.setAlias(tTokenizer.getName()); token = tTokenizer.getstring(); } else if (tTokenizer.wasName()) { e.setAlias(token); token = tTokenizer.getstring(); } vcolumn.Add(e); } while (token.Equals(",")); if (token.Equals("INTO")) { select.sIntoTable = tTokenizer.getstring(); token = tTokenizer.getstring(); } if (!token.Equals("FROM")) { throw Trace.error(Trace.UNEXPECTED_TOKEN, token); } Expression condition = null; // parse table list ArrayList vfilter = new ArrayList(); vfilter.Add(parseTableFilter(false)); while (true) { token = tTokenizer.getstring(); if (token.Equals("LEFT")) { token = tTokenizer.getstring(); if (token.Equals("OUTER")) { token = tTokenizer.getstring(); } Trace.check(token.Equals("JOIN"), Trace.UNEXPECTED_TOKEN, token); vfilter.Add(parseTableFilter(true)); tTokenizer.getThis("ON"); condition = addCondition(condition, parseExpression()); } else if (token.Equals("INNER")) { tTokenizer.getThis("JOIN"); vfilter.Add(parseTableFilter(false)); tTokenizer.getThis("ON"); condition = addCondition(condition, parseExpression()); } else if (token.Equals(",")) { vfilter.Add(parseTableFilter(false)); } else { break; } } tTokenizer.back(); int len = vfilter.Count; TableFilter[] filter = new TableFilter[len]; vfilter.CopyTo(filter); select.tFilter = filter; // expand [table.]* columns len = vcolumn.Count; for (int i = 0; i < len; i++) { Expression e = (Expression) (vcolumn[i]); if (e.getType() == Expression.ASTERIX) { int current = i; Table table = null; string n = e.getTableName(); for (int t = 0; t < filter.Length; t++) { TableFilter f = filter[t]; e.resolve(f); if (n != null &&!n.Equals(f.getName())) { continue; } table = f.getTable(); int col = table.getColumnCount(); for (int c = 0; c < col; c++) { Expression ins = new Expression(f.getName(), table.getColumnName(c)); vcolumn.Insert(current++,ins); // now there is one element more to parse len++; } } Trace.check(table != null, Trace.TABLE_NOT_FOUND, n); // minus the asterix element len--; vcolumn.RemoveAt(current); } else if (e.getType()==Expression.COLUMN) { if (e.getTableName() == null) { for (int filterIndex=0; filterIndex < filter.Length; filterIndex++) { e.resolve(filter[filterIndex]); } } } } select.iResultLen = len; // where token = tTokenizer.getstring(); if (token.Equals("WHERE")) { condition = addCondition(condition, parseExpression()); token = tTokenizer.getstring(); } select.eCondition = condition; if (token.Equals("GROUP")) { tTokenizer.getThis("BY"); len = 0; do { vcolumn.Add(parseExpression()); token = tTokenizer.getstring(); len++; } while (token.Equals(",")); select.iGroupLen = len; } if (token.Equals("ORDER")) { tTokenizer.getThis("BY"); len = 0; do { Expression e = parseExpression(); if (e.getType() == Expression.VALUE) { // order by 1,2,3 if (e.getDataType() == Column.INTEGER) { int i = ((int) e.getValue()).ToInt32(); e = (Expression) vcolumn[i - 1]; } } else if (e.getType() == Expression.COLUMN && e.getTableName() == null) { // this could be an alias column string s = e.getColumnName(); for (int i = 0; i < vcolumn.Count; i++) { Expression ec = (Expression) vcolumn[i]; if (s.Equals(ec.getAlias())) { e = ec; break; } } } token = tTokenizer.getstring(); if (token.Equals("DESC")) { e.setDescending(); token = tTokenizer.getstring(); } else if (token.Equals("ASC")) { token = tTokenizer.getstring(); } vcolumn.Add(e); len++; } while (token.Equals(",")); select.iOrderLen = len; } len = vcolumn.Count; select.eColumn = new Expression[len]; vcolumn.CopyTo(select.eColumn); if (token.Equals("UNION")) { token = tTokenizer.getstring(); if (token.Equals("ALL")) { select.iUnionType = Select.UNIONALL; } else { select.iUnionType = Select.UNION; tTokenizer.back(); } tTokenizer.getThis("SELECT"); select.sUnion = parseSelect(); } else if (token.Equals("INTERSECT")) { tTokenizer.getThis("SELECT"); select.iUnionType = Select.INTERSECT; select.sUnion = parseSelect(); } else if (token.Equals("EXCEPT") || token.Equals("MINUS")) { tTokenizer.getThis("SELECT"); select.iUnionType = Select.EXCEPT; select.sUnion = parseSelect(); } else { tTokenizer.back(); } return select; }
/** * Method declaration * * * @return * * @throws Exception */ private Expression parseExpression() { read(); // todo: really this should be in readTerm // but then grouping is much more complex if (iToken == Expression.MIN || iToken == Expression.MAX || iToken == Expression.COUNT || iToken == Expression.SUM || iToken == Expression.AVG) { int type = iToken; read(); Expression r = new Expression(type, readOr(), null); tTokenizer.back(); return r; } Expression rx = readOr(); tTokenizer.back(); return rx; }
/** * Method declaration * * * @param e1 * @param e2 * * @return */ private Expression addCondition(Expression e1, Expression e2) { if (e1 == null) { return e2; } else if (e2 == null) { return e1; } else { return new Expression(Expression.AND, e1, e2); } }