All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.h2.mvstore.db.MVTempResult Maven / Gradle / Ivy

There is a newer version: 1.0.0-beta2
Show newest version
/*
 * Copyright 2004-2019 H2 Group. Multiple-Licensed under the MPL 2.0,
 * and the EPL 1.0 (https://h2database.com/html/license.html).
 * Initial Developer: H2 Group
 */
package org.h2.mvstore.db;

import java.io.IOException;
import java.lang.ref.Reference;
import java.util.Collection;

import org.h2.engine.Constants;
import org.h2.engine.Database;
import org.h2.expression.Expression;
import org.h2.message.DbException;
import org.h2.mvstore.MVStore;
import org.h2.mvstore.MVStore.Builder;
import org.h2.result.ResultExternal;
import org.h2.result.SortOrder;
import org.h2.store.fs.FileUtils;
import org.h2.util.TempFileDeleter;
import org.h2.value.TypeInfo;
import org.h2.value.Value;

/**
 * Temporary result.
 *
 * 

* A separate MVStore in a temporary file is used for each result. The file is * removed when this result and all its copies are closed. * {@link TempFileDeleter} is also used to delete this file if results are not * closed properly. *

*/ public abstract class MVTempResult implements ResultExternal { private static final class CloseImpl implements AutoCloseable { /** * MVStore. */ private final MVStore store; /** * File name. */ private final String fileName; CloseImpl(MVStore store, String fileName) { this.store = store; this.fileName = fileName; } @Override public void close() throws Exception { store.closeImmediately(); FileUtils.tryDelete(fileName); } } /** * Creates MVStore-based temporary result. * * @param database * database * @param expressions * expressions * @param distinct * is output distinct * @param distinctIndexes * indexes of distinct columns for DISTINCT ON results * @param visibleColumnCount * count of visible columns * @param resultColumnCount * the number of columns including visible columns and additional * virtual columns for ORDER BY and DISTINCT ON clauses * @param sort * sort order, or {@code null} * @return temporary result */ public static ResultExternal of(Database database, Expression[] expressions, boolean distinct, int[] distinctIndexes, int visibleColumnCount, int resultColumnCount, SortOrder sort) { return distinct || distinctIndexes != null || sort != null ? new MVSortedTempResult(database, expressions, distinct, distinctIndexes, visibleColumnCount, resultColumnCount, sort) : new MVPlainTempResult(database, expressions, visibleColumnCount, resultColumnCount); } /** * MVStore. */ final MVStore store; /** * Column expressions. */ final Expression[] expressions; /** * Count of visible columns. */ final int visibleColumnCount; /** * Total count of columns. */ final int resultColumnCount; final boolean hasEnum; /** * Count of rows. Used only in a root results, copies always have 0 value. */ int rowCount; /** * Parent store for copies. If {@code null} this result is a root result. */ final MVTempResult parent; /** * Count of child results. */ int childCount; /** * Whether this result is closed. */ boolean closed; /** * Temporary file deleter. */ private final TempFileDeleter tempFileDeleter; /** * Closeable to close the storage. */ private final CloseImpl closeable; /** * Reference to the record in the temporary file deleter. */ private final Reference fileRef; /** * Creates a shallow copy of the result. * * @param parent * parent result */ MVTempResult(MVTempResult parent) { this.parent = parent; this.store = parent.store; this.expressions = parent.expressions; this.visibleColumnCount = parent.visibleColumnCount; this.resultColumnCount = parent.resultColumnCount; this.hasEnum = parent.hasEnum; this.tempFileDeleter = null; this.closeable = null; this.fileRef = null; } /** * Creates a new temporary result. * * @param database * database * @param expressions * column expressions * @param visibleColumnCount * count of visible columns * @param resultColumnCount * total count of columns */ MVTempResult(Database database, Expression[] expressions, int visibleColumnCount, int resultColumnCount) { try { String fileName = FileUtils.createTempFile("h2tmp", Constants.SUFFIX_TEMP_FILE, true); Builder builder = new MVStore.Builder().fileName(fileName).cacheSize(0).autoCommitDisabled(); byte[] key = database.getFileEncryptionKey(); if (key != null) { builder.encryptionKey(MVTableEngine.decodePassword(key)); } store = builder.open(); this.expressions = expressions; this.visibleColumnCount = visibleColumnCount; this.resultColumnCount = resultColumnCount; boolean hasEnum = false; for (int i = 0; i < resultColumnCount; i++) { Expression e = expressions[i]; if (e.getType().getValueType() == Value.ENUM) { hasEnum = true; break; } } this.hasEnum = hasEnum; tempFileDeleter = database.getTempFileDeleter(); closeable = new CloseImpl(store, fileName); fileRef = tempFileDeleter.addFile(closeable, this); } catch (IOException e) { throw DbException.convert(e); } parent = null; } @Override public int addRows(Collection rows) { for (Value[] row : rows) { addRow(row); } return rowCount; } @Override public synchronized void close() { if (closed) { return; } closed = true; if (parent != null) { parent.closeChild(); } else { if (childCount == 0) { delete(); } } } private synchronized void closeChild() { if (--childCount == 0 && closed) { delete(); } } private void delete() { tempFileDeleter.deleteFile(fileRef, closeable); } /** * If any value in the rows is a ValueEnum, apply custom type conversion. * * @param row the array of values (modified in-place if needed) */ final void fixEnum(Value[] row) { for (int i = 0, l = resultColumnCount; i < l; i++) { TypeInfo type = expressions[i].getType(); if (type.getValueType() == Value.ENUM) { row[i] = type.getExtTypeInfo().cast(row[i]); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy