/** * Add an undo log entry to this session. * * @param table the table * @param operation the operation type (see {@link UndoLogRecord}) * @param row the row */ public void log(Table table, short operation, Row row) { if (undoLogEnabled) { UndoLogRecord log = new UndoLogRecord(table, operation, row); // called _after_ the row was inserted successfully into the table, // otherwise rollback will try to rollback a not-inserted row if (SysProperties.CHECK) { int lockMode = database.getLockMode(); if (lockMode != Constants.LOCK_MODE_OFF && !database.isMultiVersion()) { String tableType = log.getTable().getTableType(); if (locks.indexOf(log.getTable()) < 0 && !Table.TABLE_LINK.equals(tableType) && !Table.EXTERNAL_TABLE_ENGINE.equals(tableType)) { DbException.throwInternalError(); } } } undoLog.add(log); } else { if (database.isMultiVersion()) { // see also UndoLogRecord.commit ArrayList<Index> indexes = table.getIndexes(); for (int i = 0, size = indexes.size(); i < size; i++) { Index index = indexes.get(i); index.commit(operation, row); } row.commit(); } } }
/** * Add a lock for the given table. The object is unlocked on commit or rollback. * * @param table the table that is locked */ public void addLock(Table table) { if (SysProperties.CHECK) { if (locks.indexOf(table) >= 0) { DbException.throwInternalError(); } } locks.add(table); }
Value getMergedValue(Database database, boolean distinct) { if (distinct) { count = 0; groupDistinct(database); } Value v = null; switch (aggregateType) { case Aggregate.COUNT: case Aggregate.COUNT_ALL: v = ValueLong.get(count); break; case Aggregate.SUM: case Aggregate.MIN: case Aggregate.MAX: case Aggregate.BOOL_OR: case Aggregate.BOOL_AND: v = value; break; case Aggregate.AVG: case Aggregate.STDDEV_POP: case Aggregate.STDDEV_SAMP: case Aggregate.VAR_POP: case Aggregate.VAR_SAMP: return value == null ? ValueNull.INSTANCE : value; case Aggregate.SELECTIVITY: if (value != null) { v = divide(value, count); } break; case Aggregate.GROUP_CONCAT: return null; case Aggregate.HISTOGRAM: ValueArray[] values = new ValueArray[distinctValues.size()]; int i = 0; for (Value dv : distinctValues.keys()) { AggregateData d = distinctValues.get(dv); values[i] = ValueArray.get(new Value[] {dv, ValueLong.get(d.count)}); i++; } final CompareMode compareMode = database.getCompareMode(); Arrays.sort( values, new Comparator<ValueArray>() { public int compare(ValueArray v1, ValueArray v2) { Value a1 = v1.getList()[0]; Value a2 = v2.getList()[0]; return a1.compareTo(a2, compareMode); } }); v = ValueArray.get(values); break; default: DbException.throwInternalError("type=" + aggregateType); } return v == null ? ValueNull.INSTANCE : v.convertTo(dataType); }
/** * Remember that the given LOB value must be un-linked (disconnected from the table) at commit. * * @param v the value */ public void unlinkAtCommit(Value v) { if (SysProperties.CHECK && !v.isLinked()) { DbException.throwInternalError(); } if (unlinkLobMap == null) { unlinkLobMap = New.hashMap(); } unlinkLobMap.put(v.toString(), v); }
public synchronized void checkTransfers() { if (transferList != null) { for (int i = 0; i < transferList.size(); i++) { Transfer transfer = transferList.get(i); try { if (transfer.available() > 0) throw DbException.throwInternalError( "the transfer available bytes was " + transfer.available()); } catch (IOException e) { throw DbException.convert(e); } } } }
private void unlockAll() { if (SysProperties.CHECK) { if (undoLog.size() > 0) { DbException.throwInternalError(); } } if (locks.size() > 0) { synchronized (database) { // don't use the enhanced for loop to save memory for (int i = 0, size = locks.size(); i < size; i++) { Table t = locks.get(i); t.unlock(this); } locks.clear(); } } savepoints = null; sessionStateChanged = true; }
/** * Called to flush the output after data has been sent to the server and just before receiving * data. This method also reads the status code from the server and throws any exception the * server sent. * * @param transfer the transfer object * @throws DbException if the server sent an exception * @throws IOException if there is a communication problem between client and server */ public void done(Transfer transfer) throws IOException { // 正常来讲不会出现这种情况,如果出现了,说明存在bug,找出为什么transfer的输入流没正常读完的原因 if (transfer.available() > 0) { throw DbException.throwInternalError( "before transfer flush, the available bytes was " + transfer.available()); } transfer.flush(); int status = transfer.readInt(); if (status == STATUS_ERROR) { parseError(transfer); } else if (status == STATUS_CLOSED) { transferList = null; } else if (status == STATUS_OK_STATE_CHANGED) { sessionStateChanged = true; } else if (status == STATUS_OK) { // ok } else { throw DbException.get(ErrorCode.CONNECTION_BROKEN_1, "unexpected status " + status); } }
private void initDb() throws SQLException { Statement stat = null; ResultSet rs = null; try { synchronized (server) { // better would be: set the database to exclusive mode rs = conn.getMetaData().getTables(null, "PG_CATALOG", "PG_VERSION", null); boolean tableFound = rs.next(); stat = conn.createStatement(); if (!tableFound) { installPgCatalog(stat); } rs = stat.executeQuery("SELECT * FROM PG_CATALOG.PG_VERSION"); if (!rs.next() || rs.getInt(1) < 2) { // installation incomplete, or old version installPgCatalog(stat); } else { // version 2 or newer: check the read version int versionRead = rs.getInt(2); if (versionRead > 2) { throw DbException.throwInternalError("Incompatible PG_VERSION"); } } } stat.execute("set search_path = PUBLIC, pg_catalog"); HashSet<Integer> typeSet = server.getTypeSet(); if (typeSet.size() == 0) { rs = stat.executeQuery("SELECT OID FROM PG_CATALOG.PG_TYPE"); while (rs.next()) { typeSet.add(rs.getInt(1)); } } } finally { JdbcUtils.closeSilently(stat); JdbcUtils.closeSilently(rs); } }
/** * Add a value to this aggregate. * * @param database the database * @param distinct if the calculation should be distinct * @param v the value */ void add(Database database, boolean distinct, Value v) { if (aggregateType == Aggregate.SELECTIVITY) { count++; if (distinctHashes == null) { distinctHashes = new IntIntHashMap(); } int size = distinctHashes.size(); if (size > Constants.SELECTIVITY_DISTINCT_COUNT) { distinctHashes = new IntIntHashMap(); m2 += size; } int hash = v.hashCode(); // the value -1 is not supported distinctHashes.put(hash, 1); return; } else if (aggregateType == Aggregate.COUNT_ALL) { count++; return; } else if (aggregateType == Aggregate.HISTOGRAM) { if (distinctValues == null) { distinctValues = ValueHashMap.newInstance(); } AggregateData a = distinctValues.get(v); if (a == null) { if (distinctValues.size() < Constants.SELECTIVITY_DISTINCT_COUNT) { a = new AggregateData(Aggregate.HISTOGRAM, dataType); distinctValues.put(v, a); } } if (a != null) { a.count++; } return; } if (v == ValueNull.INSTANCE) { return; } count++; if (distinct) { if (distinctValues == null) { distinctValues = ValueHashMap.newInstance(); } distinctValues.put(v, this); return; } switch (aggregateType) { case Aggregate.COUNT: case Aggregate.HISTOGRAM: return; case Aggregate.SUM: if (value == null) { value = v.convertTo(dataType); } else { v = v.convertTo(value.getType()); value = value.add(v); } break; case Aggregate.AVG: if (value == null) { value = v.convertTo(DataType.getAddProofType(dataType)); } else { v = v.convertTo(value.getType()); value = value.add(v); } break; case Aggregate.MIN: if (value == null || database.compare(v, value) < 0) { value = v; } break; case Aggregate.MAX: if (value == null || database.compare(v, value) > 0) { value = v; } break; case Aggregate.GROUP_CONCAT: { if (list == null) { list = New.arrayList(); } list.add(v); break; } case Aggregate.STDDEV_POP: case Aggregate.STDDEV_SAMP: case Aggregate.VAR_POP: case Aggregate.VAR_SAMP: { // Using Welford's method, see also // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance // http://www.johndcook.com/standard_deviation.html double x = v.getDouble(); if (count == 1) { mean = x; m2 = 0; } else { double delta = x - mean; mean += delta / count; m2 += delta * (x - mean); } break; } case Aggregate.BOOL_AND: v = v.convertTo(Value.BOOLEAN); if (value == null) { value = v; } else { value = ValueBoolean.get(value.getBoolean().booleanValue() && v.getBoolean().booleanValue()); } break; case Aggregate.BOOL_OR: v = v.convertTo(Value.BOOLEAN); if (value == null) { value = v; } else { value = ValueBoolean.get(value.getBoolean().booleanValue() || v.getBoolean().booleanValue()); } break; default: DbException.throwInternalError("type=" + aggregateType); } }
/** * Get the aggregate result. * * @param database the database * @param distinct if distinct is used * @return the value */ Value getValue(Database database, boolean distinct) { if (distinct) { count = 0; groupDistinct(database); } Value v = null; switch (aggregateType) { case Aggregate.SELECTIVITY: { int s = 0; if (count == 0) { s = 0; } else { m2 += distinctHashes.size(); m2 = 100 * m2 / count; s = (int) m2; s = s <= 0 ? 1 : s > 100 ? 100 : s; } v = ValueInt.get(s); break; } case Aggregate.COUNT: case Aggregate.COUNT_ALL: v = ValueLong.get(count); break; case Aggregate.SUM: case Aggregate.MIN: case Aggregate.MAX: case Aggregate.BOOL_OR: case Aggregate.BOOL_AND: v = value; break; case Aggregate.AVG: if (value != null) { v = divide(value, count); } break; case Aggregate.GROUP_CONCAT: return null; case Aggregate.STDDEV_POP: { if (count < 1) { return ValueNull.INSTANCE; } v = ValueDouble.get(Math.sqrt(m2 / count)); break; } case Aggregate.STDDEV_SAMP: { if (count < 2) { return ValueNull.INSTANCE; } v = ValueDouble.get(Math.sqrt(m2 / (count - 1))); break; } case Aggregate.VAR_POP: { if (count < 1) { return ValueNull.INSTANCE; } v = ValueDouble.get(m2 / count); break; } case Aggregate.VAR_SAMP: { if (count < 2) { return ValueNull.INSTANCE; } v = ValueDouble.get(m2 / (count - 1)); break; } case Aggregate.HISTOGRAM: ValueArray[] values = new ValueArray[distinctValues.size()]; int i = 0; for (Value dv : distinctValues.keys()) { AggregateData d = distinctValues.get(dv); values[i] = ValueArray.get(new Value[] {dv, ValueLong.get(d.count)}); i++; } final CompareMode compareMode = database.getCompareMode(); Arrays.sort( values, new Comparator<ValueArray>() { public int compare(ValueArray v1, ValueArray v2) { Value a1 = v1.getList()[0]; Value a2 = v2.getList()[0]; return a1.compareTo(a2, compareMode); } }); v = ValueArray.get(values); break; default: DbException.throwInternalError("type=" + aggregateType); } return v == null ? ValueNull.INSTANCE : v.convertTo(dataType); }
void merge(Database database, boolean distinct, Value v) { if (aggregateType == Aggregate.COUNT || aggregateType == Aggregate.COUNT_ALL) { count += v.getLong(); return; } else if (aggregateType == Aggregate.HISTOGRAM) { if (distinctValues == null) { distinctValues = ValueHashMap.newInstance(); } AggregateData a = distinctValues.get(v); if (a == null) { if (distinctValues.size() < Constants.SELECTIVITY_DISTINCT_COUNT) { a = new AggregateData(Aggregate.HISTOGRAM, dataType); distinctValues.put(v, a); } } if (a != null) { a.count++; } return; } if (v == ValueNull.INSTANCE) { return; } count++; if (distinct) { if (distinctValues == null) { distinctValues = ValueHashMap.newInstance(); } distinctValues.put(v, this); return; } switch (aggregateType) { case Aggregate.COUNT: case Aggregate.HISTOGRAM: return; case Aggregate.SUM: case Aggregate.SELECTIVITY: if (value == null) { value = v.convertTo(dataType); } else { v = v.convertTo(value.getType()); value = value.add(v); } break; case Aggregate.AVG: if (value == null) { value = v.convertTo(DataType.getAddProofType(dataType)); } else { // AVG聚合函数merge的次数不会超过1 DbException.throwInternalError("type=" + aggregateType); } break; case Aggregate.MIN: if (value == null || database.compare(v, value) < 0) { value = v; } break; case Aggregate.MAX: if (value == null || database.compare(v, value) > 0) { value = v; } break; case Aggregate.GROUP_CONCAT: { if (list == null) { list = New.arrayList(); } list.add(v); break; } case Aggregate.STDDEV_POP: case Aggregate.STDDEV_SAMP: case Aggregate.VAR_POP: case Aggregate.VAR_SAMP: { v = v.convertTo(Value.DOUBLE); if (value == null) { value = v; } else { // 这4种聚合函数merge的次数不会超过1 DbException.throwInternalError("type=" + aggregateType); } break; } case Aggregate.BOOL_AND: v = v.convertTo(Value.BOOLEAN); if (value == null) { value = v; } else { value = ValueBoolean.get(value.getBoolean().booleanValue() && v.getBoolean().booleanValue()); } break; case Aggregate.BOOL_OR: v = v.convertTo(Value.BOOLEAN); if (value == null) { value = v; } else { value = ValueBoolean.get(value.getBoolean().booleanValue() || v.getBoolean().booleanValue()); } break; default: DbException.throwInternalError("type=" + aggregateType); } }