/** * Prepare a transaction. * * @param session the session * @param transaction the name of the transaction */ void prepareCommit(Session session, String transaction) { if (trace.isDebugEnabled()) { trace.debug("log prepare commit s: " + session.getId() + ", " + transaction); } if (store.getDatabase().getPageStore() == null) { // database already closed return; } // store it on a separate log page int pageSize = store.getPageSize(); pageOut.flush(); pageOut.fillPage(); Data buffer = getBuffer(); buffer.writeByte((byte) PREPARE_COMMIT); buffer.writeVarInt(session.getId()); buffer.writeString(transaction); if (buffer.length() >= PageStreamData.getCapacity(pageSize)) { throw DbException.getInvalidValueException("transaction name (too long)", transaction); } write(buffer); // store it on a separate log page flushOut(); pageOut.fillPage(); if (store.getDatabase().getFlushOnEachCommit()) { flush(); } }
private void closeSession() { if (session != null) { RuntimeException closeError = null; try { Command rollback = session.prepareLocal("ROLLBACK"); rollback.executeUpdate(); } catch (RuntimeException e) { closeError = e; server.traceError(e); } catch (Exception e) { server.traceError(e); } try { session.close(); server.removeConnection(threadId); } catch (RuntimeException e) { if (closeError == null) { closeError = e; server.traceError(e); } } catch (Exception e) { server.traceError(e); } finally { session = null; } if (closeError != null) { throw closeError; } } }
ResultTempTable(Session session, Expression[] expressions, boolean distinct, SortOrder sort) { this.session = session; this.distinct = distinct; this.sort = sort; this.columnCount = expressions.length; Schema schema = session.getDatabase().getSchema(Constants.SCHEMA_MAIN); CreateTableData data = new CreateTableData(); for (int i = 0; i < expressions.length; i++) { int type = expressions[i].getType(); Column col = new Column(COLUMN_NAME + i, type); if (type == Value.CLOB || type == Value.BLOB) { containsLob = true; } data.columns.add(col); } data.id = session.getDatabase().allocateObjectId(); data.tableName = "TEMP_RESULT_SET_" + data.id; data.temporary = true; data.persistIndexes = false; data.persistData = true; data.create = true; data.session = session; table = schema.createTable(data); if (sort != null || distinct) { createIndex(); } parent = null; }
/** * Construct a new row list for this session. * * @param session the session */ public RowList(Session session) { this.session = session; if (session.getDatabase().isPersistent()) { maxMemory = session.getDatabase().getMaxOperationMemory(); } else { maxMemory = 0; } }
/** * A table is truncated. * * @param session the session * @param tableId the table id */ void logTruncate(Session session, int tableId) { if (trace.isDebugEnabled()) { trace.debug("log truncate s: " + session.getId() + " table: " + tableId); } session.addLogPos(logSectionId, logPos); logPos++; Data buffer = getBuffer(); buffer.writeByte((byte) TRUNCATE); buffer.writeVarInt(session.getId()); buffer.writeVarInt(tableId); write(buffer); }
public double getCost(Session session, int[] masks) { if (recursive) { return 1000; } IntArray masksArray = new IntArray(masks == null ? Utils.EMPTY_INT_ARRAY : masks); CostElement cachedCost = costCache.get(masksArray); if (cachedCost != null) { long time = System.currentTimeMillis(); if (time < cachedCost.evaluatedAt + Constants.VIEW_COST_CACHE_MAX_AGE) { return cachedCost.cost; } } Query q = (Query) session.prepare(querySQL, true); if (masks != null) { IntArray paramIndex = new IntArray(); for (int i = 0; i < masks.length; i++) { int mask = masks[i]; if (mask == 0) { continue; } paramIndex.add(i); } int len = paramIndex.size(); for (int i = 0; i < len; i++) { int idx = paramIndex.get(i); int mask = masks[idx]; int nextParamIndex = q.getParameters().size() + view.getParameterOffset(); if ((mask & IndexCondition.EQUALITY) != 0) { Parameter param = new Parameter(nextParamIndex); q.addGlobalCondition(param, idx, Comparison.EQUAL_NULL_SAFE); } else { if ((mask & IndexCondition.START) != 0) { Parameter param = new Parameter(nextParamIndex); q.addGlobalCondition(param, idx, Comparison.BIGGER_EQUAL); } if ((mask & IndexCondition.END) != 0) { Parameter param = new Parameter(nextParamIndex); q.addGlobalCondition(param, idx, Comparison.SMALLER_EQUAL); } } } String sql = q.getPlanSQL(); q = (Query) session.prepare(sql, true); } double cost = q.getCost(); cachedCost = new CostElement(); cachedCost.evaluatedAt = System.currentTimeMillis(); cachedCost.cost = cost; costCache.put(masksArray, cachedCost); return cost; }
@Override public SessionInterface reconnect(boolean write) { readSessionState(); close(); Session newSession = Engine.getInstance().createSession(connectionInfo); newSession.sessionState = sessionState; newSession.recreateSessionState(); if (write) { while (!newSession.database.beforeWriting()) { // wait until we are allowed to write } } return newSession; }
private void createIndex() { IndexColumn[] indexCols = null; if (sort != null) { int[] colIndex = sort.getQueryColumnIndexes(); indexCols = new IndexColumn[colIndex.length]; for (int i = 0; i < colIndex.length; i++) { IndexColumn indexColumn = new IndexColumn(); indexColumn.column = table.getColumn(colIndex[i]); indexColumn.sortType = sort.getSortTypes()[i]; indexColumn.columnName = COLUMN_NAME + i; indexCols[i] = indexColumn; } } else { indexCols = new IndexColumn[columnCount]; for (int i = 0; i < columnCount; i++) { IndexColumn indexColumn = new IndexColumn(); indexColumn.column = table.getColumn(i); indexColumn.columnName = COLUMN_NAME + i; indexCols[i] = indexColumn; } } String indexName = table.getSchema().getUniqueIndexName(session, table, Constants.PREFIX_INDEX); int indexId = session.getDatabase().allocateObjectId(); IndexType indexType = IndexType.createNonUnique(true); index = table.addIndex(session, indexName, indexId, indexCols, indexType, true, null); }
private boolean sameResultAsLast(Session s, Value[] params, Value[] lastParams, long lastEval) { if (!cacheableChecked) { long max = getMaxDataModificationId(); noCache = max == Long.MAX_VALUE; cacheableChecked = true; } if (noCache) { return false; } Database db = s.getDatabase(); for (int i = 0; i < params.length; i++) { Value a = lastParams[i], b = params[i]; if (a.getType() != b.getType() || !db.areEqual(a, b)) { return false; } } if (!isEverything(ExpressionVisitor.DETERMINISTIC_VISITOR) || !isEverything(ExpressionVisitor.INDEPENDENT_VISITOR)) { return false; } if (db.getModificationDataId() > lastEval && getMaxDataModificationId() > lastEval) { return false; } return true; }
private void writeAllRows() { if (file == null) { Database db = session.getDatabase(); String fileName = db.createTempFile(); file = db.openFile(fileName, "rw", false); file.setCheckedWriting(false); file.seek(FileStore.HEADER_LENGTH); rowBuff = Data.create(db, Constants.DEFAULT_PAGE_SIZE); file.seek(FileStore.HEADER_LENGTH); } Data buff = rowBuff; initBuffer(buff); for (int i = 0, size = list.size(); i < size; i++) { if (i > 0 && buff.length() > Constants.IO_BUFFER_SIZE) { flushBuffer(buff); initBuffer(buff); } Row r = list.get(i); writeRow(buff, r); } flushBuffer(buff); file.autoDelete(); list.clear(); memory = 0; }
/** * Flush the current value, including the margin, to disk. * * @param session the session */ public synchronized void flush(Session session) { if (session == null || !database.isSysTableLocked()) { // This session may not lock the sys table (except if it already has locked it) // because it must be committed immediately, // otherwise other threads can not access the sys table. Session sysSession = database.getSystemSession(); synchronized (sysSession) { flushInternal(sysSession); sysSession.commit(false); } } else { synchronized (session) { flushInternal(session); } } }
@Override public Value[] next() { if (resultCursor == null) { Index idx; if (distinct || sort != null) { idx = index; } else { idx = table.getScanIndex(session); } if (session.getDatabase().getMvStore() != null) { // sometimes the transaction is already committed, // in which case we can't use the session if (idx.getRowCount(session) == 0 && rowCount > 0) { // this means querying is not transactional resultCursor = idx.find((Session) null, null, null); } else { // the transaction is still open resultCursor = idx.find(session, null, null); } } else { resultCursor = idx.find(session, null, null); } } if (!resultCursor.next()) { return null; } Row row = resultCursor.get(); return row.getValueList(); }
private Query getQuery(Session session, int[] masks) { Query q = (Query) session.prepare(querySQL, true); if (masks == null) { return q; } int firstIndexParam = originalParameters == null ? 0 : originalParameters.size(); firstIndexParam += view.getParameterOffset(); IntArray paramIndex = new IntArray(); for (int i = 0; i < masks.length; i++) { int mask = masks[i]; if (mask == 0) { continue; } paramIndex.add(i); if ((mask & IndexCondition.RANGE) == IndexCondition.RANGE) { // two parameters for range queries: >= x AND <= y paramIndex.add(i); } } int len = paramIndex.size(); columns = new Column[len]; for (int i = 0; i < len; ) { int idx = paramIndex.get(i); Column col = table.getColumn(idx); columns[i] = col; int mask = masks[idx]; if ((mask & IndexCondition.EQUALITY) == IndexCondition.EQUALITY) { Parameter param = new Parameter(firstIndexParam + i); q.addGlobalCondition(param, idx, Comparison.EQUAL_NULL_SAFE); i++; } else { if ((mask & IndexCondition.START) == IndexCondition.START) { Parameter param = new Parameter(firstIndexParam + i); q.addGlobalCondition(param, idx, Comparison.BIGGER_EQUAL); i++; } if ((mask & IndexCondition.END) == IndexCondition.END) { Parameter param = new Parameter(firstIndexParam + i); q.addGlobalCondition(param, idx, Comparison.SMALLER_EQUAL); i++; } } } String sql = q.getPlanSQL(); q = (Query) session.prepare(sql, true); return q; }
private void dropTable() { if (table == null) { return; } if (containsLob) { // contains BLOB or CLOB: can not truncate now, // otherwise the BLOB and CLOB entries are removed return; } try { Database database = session.getDatabase(); // Need to lock because not all of the code-paths // that reach here have already taken this lock, // notably via the close() paths. synchronized (session) { synchronized (database) { table.truncate(session); } } // This session may not lock the sys table (except if it already has // locked it) because it must be committed immediately, otherwise // other threads can not access the sys table. If the table is not // removed now, it will be when the database is opened the next // time. (the table is truncated, so this is just one record) if (!database.isSysTableLocked()) { Session sysSession = database.getSystemSession(); table.removeChildrenAndResources(sysSession); if (index != null) { // need to explicitly do this, // as it's not registered in the system session session.removeLocalTempTableIndex(index); } // the transaction must be committed immediately // TODO this synchronization cascade is very ugly synchronized (session) { synchronized (sysSession) { synchronized (database) { sysSession.commit(false); } } } } } finally { table = null; } }
/** * A record is added to a table, or removed from a table. * * @param session the session * @param tableId the table id * @param row the row to add * @param add true if the row is added, false if it is removed */ void logAddOrRemoveRow(Session session, int tableId, Row row, boolean add) { if (trace.isDebugEnabled()) { trace.debug( "log " + (add ? "+" : "-") + " s: " + session.getId() + " table: " + tableId + " row: " + row); } session.addLogPos(logSectionId, logPos); logPos++; Data data = dataBuffer; data.reset(); int columns = row.getColumnCount(); data.writeVarInt(columns); data.checkCapacity(row.getByteCount(data)); if (session.isRedoLogBinaryEnabled()) { for (int i = 0; i < columns; i++) { data.writeValue(row.getValue(i)); } } else { for (int i = 0; i < columns; i++) { Value v = row.getValue(i); if (v.getType() == Value.BYTES) { data.writeValue(ValueNull.INSTANCE); } else { data.writeValue(v); } } } Data buffer = getBuffer(); buffer.writeByte((byte) (add ? ADD : REMOVE)); buffer.writeVarInt(session.getId()); buffer.writeVarInt(tableId); buffer.writeVarLong(row.getKey()); if (add) { buffer.writeVarInt(data.length()); buffer.checkCapacity(data.length()); buffer.write(data.getBytes(), 0, data.length()); } write(buffer); }
@Override public Row getRow(Session session, long key) { TransactionMap<Value, Value> map = getMap(session); Value v = map.get(ValueLong.get(key)); ValueArray array = (ValueArray) v; Row row = session.createRow(array.getList(), 0); row.setKey(key); return row; }
/** * Re-compile the query, updating the SQL statement. * * @param session the session * @return the query */ public Query recompileQuery(Session session) { Prepared p = session.prepare(querySQL); if (!(p instanceof Query)) { throw DbException.getSyntaxError(querySQL, 0); } Query query = (Query) p; querySQL = query.getPlanSQL(); return query; }
@Override public Row get() { if (row == null) { if (current != null) { ValueArray array = (ValueArray) current.getValue(); row = session.createRow(array.getList(), 0); row.setKey(current.getKey().getLong()); } } return row; }
@Override public Expression[] getExpressionColumns(Session session) { ExpressionColumn[] expr = new ExpressionColumn[list.length]; for (int i = 0; i < list.length; i++) { Expression e = list[i]; Column col = new Column( "C" + (i + 1), e.getType(), e.getPrecision(), e.getScale(), e.getDisplaySize()); expr[i] = new ExpressionColumn(session.getDatabase(), col); } return expr; }
/** * @param conn Connection. * @param qry Query. * @param explain Explain. * @return Table. * @throws IgniteCheckedException */ private GridMergeTable createMergeTable( JdbcConnection conn, GridCacheSqlQuery qry, boolean explain) throws IgniteCheckedException { try { Session ses = (Session) conn.getSession(); CreateTableData data = new CreateTableData(); data.tableName = "T___"; data.schema = ses.getDatabase().getSchema(ses.getCurrentSchemaName()); data.create = true; if (!explain) { LinkedHashMap<String, ?> colsMap = qry.columns(); assert colsMap != null; ArrayList<Column> cols = new ArrayList<>(colsMap.size()); for (Map.Entry<String, ?> e : colsMap.entrySet()) { String alias = e.getKey(); GridSqlType t = (GridSqlType) e.getValue(); assert !F.isEmpty(alias); Column c = new Column(alias, t.type(), t.precision(), t.scale(), t.displaySize()); cols.add(c); } data.columns = cols; } else data.columns = planColumns(); return new GridMergeTable(data, ctx); } catch (Exception e) { U.closeQuiet(conn); throw new IgniteCheckedException(e); } }
public void createIndexConditions(Session session, TableFilter filter) { if (!(this.left instanceof ExpressionColumn)) { return; } ExpressionColumn l = (ExpressionColumn) this.left; if (filter != l.getTableFilter()) { return; } if (session.getDatabase().getSettings().optimizeInList) { filter.addIndexCondition(IndexCondition.getInList(l, this.valueList)); return; } }
/** * Create a temporary view out of the given query. * * @param session the session * @param owner the owner of the query * @param name the view name * @param query the query * @param topQuery the top level query * @return the view table */ public static TableView createTempView( Session session, User owner, String name, Query query, Query topQuery) { Schema mainSchema = session.getDatabase().getSchema(Constants.SCHEMA_MAIN); String querySQL = query.getPlanSQL(); TableView v = new TableView(mainSchema, 0, name, querySQL, query.getParameters(), null, session, false); v.setTopQuery(topQuery); if (v.createException != null) { throw v.createException; } v.setOwner(owner); v.setTemporary(true); return v; }
@Override public void add(Session session, Row row) { if (mainIndexColumn == -1) { if (row.getKey() == 0) { row.setKey(++lastKey); } } else { long c = row.getValue(mainIndexColumn).getLong(); row.setKey(c); } if (mvTable.getContainsLargeObject()) { for (int i = 0, len = row.getColumnCount(); i < len; i++) { Value v = row.getValue(i); Value v2 = v.link(database, getId()); if (v2.isLinked()) { session.unlinkAtCommitStop(v2); } if (v != v2) { row.setValue(i, v2); } } } TransactionMap<Value, Value> map = getMap(session); Value key = ValueLong.get(row.getKey()); Value old = map.getLatest(key); if (old != null) { String sql = "PRIMARY KEY ON " + table.getSQL(); if (mainIndexColumn >= 0 && mainIndexColumn < indexColumns.length) { sql += "(" + indexColumns[mainIndexColumn].getSQL() + ")"; } DbException e = DbException.get(ErrorCode.DUPLICATE_KEY_1, sql); e.setSource(this); throw e; } try { map.put(key, ValueArray.get(row.getValueList())); } catch (IllegalStateException e) { throw DbException.get(ErrorCode.CONCURRENT_UPDATE_1, table.getName()); } lastKey = Math.max(lastKey, row.getKey()); }
@Override public Expression optimize(Session session) { userConnection = session.createConnection(false); int len = args.length; argTypes = new int[len]; for (int i = 0; i < len; i++) { Expression expr = args[i]; args[i] = expr.optimize(session); int type = expr.getType(); argTypes[i] = type; } try { Aggregate aggregate = getInstance(); dataType = aggregate.getInternalType(argTypes); } catch (SQLException e) { throw DbException.convert(e); } return this; }
ResultDiskBuffer(Session session, SortOrder sort, int columnCount) { this.parent = null; this.sort = sort; this.columnCount = columnCount; Database db = session.getDatabase(); rowBuff = Data.create(db, Constants.DEFAULT_PAGE_SIZE); String fileName = db.createTempFile(); file = db.openFile(fileName, "rw", false); file.setCheckedWriting(false); file.seek(FileStore.HEADER_LENGTH); if (sort != null) { tapes = New.arrayList(); mainTape = null; } else { tapes = null; mainTape = new ResultDiskTape(); mainTape.pos = FileStore.HEADER_LENGTH; } this.maxBufferSize = db.getSettings().largeResultBufferSize; }
@Override public void createIndexConditions(Session session, TableFilter filter) { if (!(left instanceof ExpressionColumn)) { return; } ExpressionColumn l = (ExpressionColumn) left; if (filter != l.getTableFilter()) { return; } if (session.getDatabase().getSettings().optimizeInList) { ExpressionVisitor visitor = ExpressionVisitor.getNotFromResolverVisitor(filter); for (Expression e : valueList) { if (!e.isEverything(visitor)) { return; } } filter.addIndexCondition(IndexCondition.getInList(l, valueList)); return; } }
@Override public void remove(Session session, Row row) { if (mvTable.getContainsLargeObject()) { for (int i = 0, len = row.getColumnCount(); i < len; i++) { Value v = row.getValue(i); if (v.isLinked()) { session.unlinkAtCommit(v); } } } TransactionMap<Value, Value> map = getMap(session); try { Value old = map.remove(ValueLong.get(row.getKey())); if (old == null) { throw DbException.get( ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1, getSQL() + ": " + row.getKey()); } } catch (IllegalStateException e) { throw DbException.get(ErrorCode.CONCURRENT_UPDATE_1, table.getName()); } }
private Row readRow(Data buff) { if (buff.readByte() == 0) { return null; } int mem = buff.readInt(); int columnCount = buff.readInt(); long key = buff.readLong(); int version = buff.readInt(); if (readUncached) { key = 0; } boolean deleted = buff.readInt() == 1; int sessionId = buff.readInt(); Value[] values = new Value[columnCount]; for (int i = 0; i < columnCount; i++) { Value v; if (buff.readByte() == 0) { v = null; } else { v = buff.readValue(); if (v.isLinked()) { // the table id is 0 if it was linked when writing // a temporary entry if (v.getTableId() == 0) { session.unlinkAtCommit(v); } } } values[i] = v; } Row row = new Row(values, mem); row.setKey(key); row.setVersion(version); row.setDeleted(deleted); row.setSessionId(sessionId); return row; }
private Cursor find(Row row) { if (index == null) { // for the case "in(select ...)", the query might // use an optimization and not create the index // up front createIndex(); } Cursor cursor = index.find(session, row, row); while (cursor.next()) { SearchRow found = cursor.getSearchRow(); boolean ok = true; Database db = session.getDatabase(); for (int i = 0; i < row.getColumnCount(); i++) { if (!db.areEqual(row.getValue(i), found.getValue(i))) { ok = false; break; } } if (ok) { return cursor; } } return null; }
private int getState(int oldModificationId) { if (session.getModificationId() == oldModificationId) { return SessionRemote.STATUS_OK; } return SessionRemote.STATUS_OK_STATE_CHANGED; }