com.axibase.tsd.driver.jdbc.ext.AtsdMeta Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of atsd-jdbc Show documentation
Show all versions of atsd-jdbc Show documentation
JDBC driver for SQL API using
/*
* Copyright 2016 Axibase Corporation or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* https://www.axibase.com/atsd/axibase-apache-2.0.pdf
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.axibase.tsd.driver.jdbc.ext;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import com.axibase.tsd.driver.jdbc.DriverConstants;
import com.axibase.tsd.driver.jdbc.content.ContentDescription;
import com.axibase.tsd.driver.jdbc.content.ContentMetadata;
import com.axibase.tsd.driver.jdbc.content.DataProvider;
import com.axibase.tsd.driver.jdbc.content.StatementContext;
import com.axibase.tsd.driver.jdbc.enums.AtsdType;
import com.axibase.tsd.driver.jdbc.enums.DefaultColumn;
import com.axibase.tsd.driver.jdbc.enums.timedatesyntax.EndTime;
import com.axibase.tsd.driver.jdbc.intf.IDataProvider;
import com.axibase.tsd.driver.jdbc.intf.IStoreStrategy;
import com.axibase.tsd.driver.jdbc.logging.LoggingFacade;
import com.axibase.tsd.driver.jdbc.util.TimeDateExpression;
import org.apache.calcite.avatica.*;
import org.apache.calcite.avatica.remote.TypedValue;
public class AtsdMeta extends MetaImpl {
private static final LoggingFacade log = LoggingFacade.getLogger(AtsdMeta.class);
private final AtomicInteger idGenerator = new AtomicInteger(1);
private final Map metaCache = new ConcurrentHashMap<>();
private final Map providerCache = new ConcurrentHashMap<>();
private final Map contextMap = new ConcurrentHashMap<>();
private final ReentrantLock lock = new ReentrantLock();
private static final ThreadLocal DATE_FORMATTER = new ThreadLocal() {
@Override
protected SimpleDateFormat initialValue() {
SimpleDateFormat sdt = new SimpleDateFormat("yyyy-MM-dd", Locale.UK);
sdt.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdt;
}
};
public static final ThreadLocal TIME_FORMATTER = new ThreadLocal() {
@Override
protected SimpleDateFormat initialValue() {
SimpleDateFormat sdt = new SimpleDateFormat("HH:mm:ss", Locale.UK);
sdt.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdt;
}
};
public static final ThreadLocal TIMESTAMP_FORMATTER = new ThreadLocal() {
@Override
protected SimpleDateFormat initialValue() {
SimpleDateFormat sdt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.UK);
sdt.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdt;
}
};
public static final ThreadLocal TIMESTAMP_SHORT_FORMATTER = new ThreadLocal() {
@Override
protected SimpleDateFormat initialValue() {
SimpleDateFormat sdt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.UK);
sdt.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdt;
}
};
private final String schema;
public AtsdMeta(final AvaticaConnection conn) {
super(conn);
this.connProps.setAutoCommit(true);
this.connProps.setReadOnly(true);
this.connProps.setTransactionIsolation(Connection.TRANSACTION_NONE);
this.connProps.setDirty(false);
this.schema = null;
}
public StatementContext getContextFromMap(StatementHandle statementHandle) {
return contextMap.get(statementHandle.id);
}
@Override
public StatementHandle prepare(ConnectionHandle connectionHandle, String query, long maxRowCount) {
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
if (log.isDebugEnabled()) {
log.debug("[prepare] " + e.getMessage());
}
Thread.currentThread().interrupt();
}
final int id = idGenerator.getAndIncrement();
if (log.isTraceEnabled()) {
log.trace("[prepare] locked: {} handle: {} query: {}", lock.getHoldCount(), id, query);
}
Signature signature = new Signature(null, query, Collections.emptyList(), null,
CursorFactory.LIST, StatementType.SELECT);
return new StatementHandle(connectionHandle.id, id, signature);
}
@Override
public ExecuteResult execute(StatementHandle statementHandle, List parameterValues, long maxRowsCount)
throws NoSuchStatementException {
return execute(statementHandle, parameterValues, AvaticaUtils.toSaturatedInt(maxRowsCount));
}
@Override
public ExecuteResult execute(StatementHandle statementHandle, List parameterValues, int maxRowsInFirstFrame) throws NoSuchStatementException {
if (log.isTraceEnabled()) {
log.trace("[execute] maxRowsInFirstFrame: {} parameters: {} handle: {}", maxRowsInFirstFrame, parameterValues.size(),
statementHandle.toString());
}
final String query = substitutePlaceholders(statementHandle.signature.sql, parameterValues);
IDataProvider provider = null;
try {
provider = initProvider(statementHandle, query);
} catch (IOException e) {
if (log.isDebugEnabled()) {
log.debug("[execute]" + e.getMessage());
}
}
assert provider != null;
try {
final Statement statement = connection.statementMap.get(statementHandle.id);
final int maxRows = getMaxRows(statement);
final int timeout = getQueryTimeout(statement);
provider.fetchData(maxRows, timeout);
final ContentMetadata contentMetadata = findMetadata(query, statementHandle.connectionId, statementHandle.id);
return new ExecuteResult(contentMetadata.getList());
} catch (final RuntimeException e) {
if (log.isErrorEnabled()) {
log.error("[execute] error", e);
}
throw e;
} catch (final Exception e) {
if (log.isErrorEnabled()) {
log.error("[execute] error", e);
}
throw new AtsdRuntimeException(e.getMessage(), e);
}
}
private static String substitutePlaceholders(String query, List parameterValues) {
if (query.contains("?")) {
final StringBuilder buffer = new StringBuilder(query.length());
final String[] parts = query.split("\\?", -1);
if (parts.length != parameterValues.size() + 1) {
throw new IndexOutOfBoundsException(
String.format("Number of specified values [%d] does not match to number of occurences [%d]",
parameterValues.size(), parts.length - 1));
}
buffer.append(parts[0]);
int position = 0;
for (TypedValue parameterValue : parameterValues) {
++position;
Object value = parameterValue.value;
if (value instanceof Number || value instanceof TimeDateExpression || value instanceof EndTime) {
buffer.append(value);
} else if (value instanceof String) {
buffer.append('\'').append((String) value).append('\'');
} else if (value instanceof java.sql.Date) {
buffer.append('\'').append(DATE_FORMATTER.get().format((java.sql.Date) value)).append('\'');
} else if (value instanceof Time) {
buffer.append('\'').append(TIME_FORMATTER.get().format((Time) value)).append('\'');
} else if (value instanceof Timestamp) {
buffer.append('\'').append(TIMESTAMP_FORMATTER.get().format((Timestamp) value)).append('\'');
}
buffer.append(parts[position]);
}
final String result = buffer.toString();
if (log.isDebugEnabled()) {
log.debug("[substitutePlaceholders] " + result);
}
return result;
}
return query;
}
private int getMaxRows(Statement statement) {
int maxRows = 0;
if (statement != null) {
try {
maxRows = statement.getMaxRows();
} catch (SQLException e) {
maxRows = 0;
}
}
return maxRows;
}
private int getQueryTimeout(Statement statement) {
int timeout = 0;
if (statement != null) {
try {
timeout = statement.getQueryTimeout();
} catch (SQLException e) {
timeout = 0;
}
}
return timeout;
}
@Override
public ExecuteResult prepareAndExecute(StatementHandle statementHandle, String query, long maxRowCount,
PrepareCallback callback) throws NoSuchStatementException {
return prepareAndExecute(statementHandle, query, maxRowCount, 0, callback);
}
@Override
public ExecuteResult prepareAndExecute(StatementHandle statementHandle, String query, long maxRowCount,
int maxRowsInFrame, PrepareCallback callback) throws NoSuchStatementException {
long limit = maxRowCount < 0 ? 0 : maxRowCount;
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
if (log.isDebugEnabled()) {
log.debug("[prepareAndExecute] " + e.getMessage());
}
Thread.currentThread().interrupt();
}
if (log.isTraceEnabled()) {
log.trace("[prepareAndExecute] locked: {} maxRowCount: {} handle: {} query: {}", lock.getHoldCount(),
limit, statementHandle.toString(), query);
}
try {
final IDataProvider provider = initProvider(statementHandle, query);
final Statement statement = (Statement) callback.getMonitor();
provider.fetchData(limit, statement.getQueryTimeout());
final ContentMetadata contentMetadata = findMetadata(query, statementHandle.connectionId, statementHandle.id);
synchronized (callback.getMonitor()) {
// callback.clear();
callback.assign(contentMetadata.getSign(), null, -1);
}
final ExecuteResult result = new ExecuteResult(contentMetadata.getList());
callback.execute();
return result;
} catch (final RuntimeException e) {
if (log.isErrorEnabled()) {
log.error("[prepareAndExecute] error", e);
}
throw e;
} catch (final Exception e) {
if (log.isErrorEnabled()) {
log.error("[prepareAndExecute] error", e);
}
throw new AtsdRuntimeException(e.getMessage(), e);
}
}
@Override
public ExecuteBatchResult prepareAndExecuteBatch(StatementHandle statementHandle, List list) throws NoSuchStatementException {
throw new UnsupportedOperationException("Batch not yet implemented");
}
@Override
public ExecuteBatchResult executeBatch(StatementHandle statementHandle, List> list) throws NoSuchStatementException {
throw new UnsupportedOperationException("Batch not yet implemented");
}
@Override
public Frame fetch(final StatementHandle statementHandle, long loffset, int fetchMaxRowCount)
throws NoSuchStatementException, MissingResultsException {
final int offset = (int) loffset;
if (log.isTraceEnabled()) {
log.trace("[fetch] fetchMaxRowCount: {} offset: {}", fetchMaxRowCount, offset);
}
IDataProvider provider = providerCache.get(statementHandle.id);
assert provider != null;
final ContentDescription contentDescription = provider.getContentDescription();
final IStoreStrategy strategy = provider.getStrategy();
final ContentMetadata contentMetadata = metaCache.get(statementHandle.id);
if (contentMetadata == null) {
throw new MissingResultsException(statementHandle);
}
try {
if (offset == 0) {
final String[] headers = strategy.openToRead(contentMetadata.getMetadataList());
if (headers == null || headers.length == 0) {
throw new MissingResultsException(statementHandle);
}
contentDescription.setHeaders(headers);
}
@SuppressWarnings("unchecked")
final List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy