blob: 741aee55b8f44e1de9350654540fba619246afee [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 org.apache.skywalking.oap.server.storage.plugin.jdbc.h2.dao;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.oap.server.core.storage.StorageData;
import org.apache.skywalking.oap.server.core.storage.model.Model;
import org.apache.skywalking.oap.server.core.storage.model.ModelColumn;
import org.apache.skywalking.oap.server.core.storage.model.SQLDatabaseModelExtension;
import org.apache.skywalking.oap.server.core.storage.type.Convert2Storage;
import org.apache.skywalking.oap.server.core.storage.type.HashMapConverter;
import org.apache.skywalking.oap.server.core.storage.type.StorageBuilder;
import org.apache.skywalking.oap.server.core.storage.type.StorageDataComplexObject;
import org.apache.skywalking.oap.server.library.client.jdbc.JDBCClientException;
import org.apache.skywalking.oap.server.library.client.jdbc.hikaricp.JDBCHikariCPClient;
import org.apache.skywalking.oap.server.library.util.CollectionUtils;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLBuilder;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.SQLExecutor;
import org.apache.skywalking.oap.server.storage.plugin.jdbc.TableMetaInfo;
@Slf4j
public class H2SQLExecutor {
protected <T extends StorageData> List<StorageData> getByIDs(JDBCHikariCPClient h2Client,
String modelName,
String[] ids,
StorageBuilder<T> storageBuilder) throws IOException {
try (Connection connection = h2Client.getConnection()) {
SQLBuilder sql = new SQLBuilder("SELECT * FROM " + modelName + " WHERE id in (");
List<Object> parameters = new ArrayList<>(ids.length);
for (int i = 0; i < ids.length; i++) {
if (i == 0) {
sql.append("?");
} else {
sql.append(",?");
}
parameters.add(ids[i]);
}
sql.append(")");
try (ResultSet rs = h2Client.executeQuery(connection, sql.toString(), parameters.toArray(new Object[0]))) {
StorageData storageData;
List<StorageData> storageDataList = new ArrayList<>();
do {
storageData = toStorageData(rs, modelName, storageBuilder);
if (storageData != null) {
storageDataList.add(storageData);
}
}
while (storageData != null);
return storageDataList;
}
} catch (SQLException | JDBCClientException e) {
throw new IOException(e.getMessage(), e);
}
}
protected <T extends StorageData> StorageData getByID(JDBCHikariCPClient h2Client, String modelName, String id,
StorageBuilder<T> storageBuilder) throws IOException {
try (Connection connection = h2Client.getConnection();
ResultSet rs = h2Client.executeQuery(connection, "SELECT * FROM " + modelName + " WHERE id = ?", id)) {
return toStorageData(rs, modelName, storageBuilder);
} catch (SQLException | JDBCClientException e) {
throw new IOException(e.getMessage(), e);
}
}
protected StorageData getByColumn(JDBCHikariCPClient h2Client, String modelName, String columnName, Object value,
StorageBuilder<? extends StorageData> storageBuilder) throws IOException {
try (Connection connection = h2Client.getConnection();
ResultSet rs = h2Client.executeQuery(
connection, "SELECT * FROM " + modelName + " WHERE " + columnName + " = ?", value)) {
return toStorageData(rs, modelName, storageBuilder);
} catch (SQLException | JDBCClientException e) {
throw new IOException(e.getMessage(), e);
}
}
protected StorageData toStorageData(ResultSet rs, String modelName,
StorageBuilder<? extends StorageData> storageBuilder) throws SQLException {
if (rs.next()) {
Map<String, Object> data = new HashMap<>();
List<ModelColumn> columns = TableMetaInfo.get(modelName).getColumns();
for (ModelColumn column : columns) {
data.put(column.getColumnName().getName(), rs.getObject(column.getColumnName().getStorageName()));
}
return storageBuilder.storage2Entity(new HashMapConverter.ToEntity(data));
}
return null;
}
protected <T extends StorageData> SQLExecutor getInsertExecutor(String modelName, T metrics,
StorageBuilder<T> storageBuilder,
Convert2Storage<Map<String, Object>> converter) throws IOException {
Model model = TableMetaInfo.get(modelName);
storageBuilder.entity2Storage(metrics, converter);
Map<String, Object> objectMap = converter.obtain();
//build main table sql
Map<String, Object> mainEntity = new HashMap<>();
model.getColumns().forEach(column -> {
mainEntity.put(column.getColumnName().getName(), objectMap.get(column.getColumnName().getName()));
});
SQLExecutor sqlExecutor = buildInsertExecutor(
modelName, model.getColumns(), metrics, mainEntity);
//build additional table sql
for (SQLDatabaseModelExtension.AdditionalTable additionalTable : model.getSqlDBModelExtension()
.getAdditionalTables()
.values()) {
Map<String, Object> additionalEntity = new HashMap<>();
additionalTable.getColumns().forEach(column -> {
additionalEntity.put(column.getColumnName().getName(), objectMap.get(column.getColumnName().getName()));
});
List<SQLExecutor> additionalSQLExecutors = buildAdditionalInsertExecutor(
additionalTable.getName(), additionalTable.getColumns(), metrics, additionalEntity
);
sqlExecutor.appendAdditionalSQLs(additionalSQLExecutors);
}
return sqlExecutor;
}
private <T extends StorageData> SQLExecutor buildInsertExecutor(String tableName,
List<ModelColumn> columns,
T metrics,
Map<String, Object> objectMap) throws IOException {
SQLBuilder sqlBuilder = new SQLBuilder("INSERT INTO " + tableName + " VALUES");
List<Object> param = new ArrayList<>();
sqlBuilder.append("(?,");
param.add(metrics.id());
for (int i = 0; i < columns.size(); i++) {
ModelColumn column = columns.get(i);
sqlBuilder.append("?");
Object value = objectMap.get(column.getColumnName().getName());
if (value instanceof StorageDataComplexObject) {
param.add(((StorageDataComplexObject) value).toStorageData());
} else {
param.add(value);
}
if (i != columns.size() - 1) {
sqlBuilder.append(",");
}
}
sqlBuilder.append(")");
return new SQLExecutor(sqlBuilder.toString(), param);
}
private <T extends StorageData> List<SQLExecutor> buildAdditionalInsertExecutor(String tableName,
List<ModelColumn> columns,
T metrics,
Map<String, Object> objectMap) throws IOException {
List<SQLExecutor> sqlExecutors = new ArrayList<>();
SQLBuilder sqlBuilder = new SQLBuilder("INSERT INTO " + tableName + " VALUES");
List<Object> param = new ArrayList<>();
sqlBuilder.append("(?,");
param.add(metrics.id());
int position = 0;
List valueList = new ArrayList();
for (int i = 0; i < columns.size(); i++) {
ModelColumn column = columns.get(i);
if (List.class.isAssignableFrom(column.getType())) {
valueList = (List) objectMap.get(column.getColumnName().getName());
sqlBuilder.append("?");
param.add(null);
position = i + 1;
} else {
sqlBuilder.append("?");
Object value = objectMap.get(column.getColumnName().getName());
if (value instanceof StorageDataComplexObject) {
param.add(((StorageDataComplexObject) value).toStorageData());
} else {
param.add(value);
}
}
if (i != columns.size() - 1) {
sqlBuilder.append(",");
}
}
sqlBuilder.append(")");
String sql = sqlBuilder.toString();
if (!CollectionUtils.isEmpty(valueList)) {
for (Object object : valueList) {
List<Object> paramCopy = new ArrayList<>(param);
paramCopy.set(position, object);
sqlExecutors.add(new SQLExecutor(sql, paramCopy));
}
} else {
sqlExecutors.add(new SQLExecutor(sql, param));
}
return sqlExecutors;
}
protected <T extends StorageData> SQLExecutor getUpdateExecutor(String modelName, T metrics,
StorageBuilder<T> storageBuilder) throws IOException {
final HashMapConverter.ToStorage toStorage = new HashMapConverter.ToStorage();
storageBuilder.entity2Storage(metrics, toStorage);
Map<String, Object> objectMap = toStorage.obtain();
SQLBuilder sqlBuilder = new SQLBuilder("UPDATE " + modelName + " SET ");
List<ModelColumn> columns = TableMetaInfo.get(modelName).getColumns();
List<Object> param = new ArrayList<>();
for (int i = 0; i < columns.size(); i++) {
ModelColumn column = columns.get(i);
sqlBuilder.append(column.getColumnName().getStorageName() + "= ?");
if (i != columns.size() - 1) {
sqlBuilder.append(",");
}
Object value = objectMap.get(column.getColumnName().getName());
if (value instanceof StorageDataComplexObject) {
param.add(((StorageDataComplexObject) value).toStorageData());
} else {
param.add(value);
}
}
sqlBuilder.append(" WHERE id = ?");
param.add(metrics.id());
return new SQLExecutor(sqlBuilder.toString(), param);
}
}