com.clickzetta.client.jdbc.core.CZStatement Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of clickzetta-java Show documentation
Show all versions of clickzetta-java Show documentation
The java SDK for clickzetta's Lakehouse
package com.clickzetta.client.jdbc.core;
import java.sql.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.clickzetta.client.ClickZettaClient;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import cz.proto.FileSystem;
import cz.proto.ObjectIdentifier;
import cz.proto.ObjectType;
import cz.proto.coordinator.CoordinatorServiceOuterClass;
import cz.proto.coordinator.CoordinatorServiceOuterClass.SubmitJobResponse;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.lang.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.clickzetta.client.jdbc.core.CZLakehouseResponseHelper.genVolumeResultSet;
public class CZStatement implements Statement {
public static final String JOB_ALREADY_EXIST = "CZLH-60007";
public static final String JOB_NOT_EXIST = "CZLH-60005";
public static final String JOB_STATUS_UNKNOWN = "CZLH-60022";
public static final String JOB_NOT_SUBMITTED = "CZLH-60023";
private final CZConnectContext connectContext;
private final LakehouseClient lakehouseClient;
private String warning;
private String errorMessage;
private boolean cancelled = false;
// private boolean created = false;
private CoordinatorServiceOuterClass.JobStatus jobStatus;
Logger logger = LoggerFactory.getLogger(CZStatement.class);
private final int MAX_TRIED = 10;
private final int INTERVAL = 6000;
private CZJobMetric jobMetric;
enum CommandType {
NO_COPY, COPY_FROM, COPY_TO, PUT_VOLUME, GET_VOLUME
}
public CommandType commandType = CommandType.NO_COPY;
public String copyTable;
public String copyLocation;
private Integer queryTimeoutMs = null;
private int executeCount = 0;
public CZStatement(CZConnectContext context) {
this.connectContext = context;
warning = "";
lakehouseClient = context.lakehouseClient();
jobMetric = new CZJobMetric();
initCommandMap();
logger.info("Statement {} init done", this);
}
public ResultSet executeQuery(String sql, String jobId) throws Exception {
this.jobIdPassIn = jobId;
ResultSet rs = executeQuery(sql);
logger.info("Job {} executeQuery done, got resultSet: {}", jobId, rs);
return rs;
}
@Override
public ResultSet executeQuery(String sql) throws SQLException {
executeInternal(sql);
if (resultSet == null) {
throw new CZNullResultException(String.format("Job %s: %s resultSet is null.", jobId, sql));
}
logger.info("Job {} executeQuery done, got resultSet: {}", jobId, resultSet);
return resultSet;
}
/**
* @return true if job finish, else false
*/
public boolean isJobFinish() throws Exception {
return isJobFinish(jobId);
}
public boolean isJobFinish(String jobId) throws Exception {
if (resultSet != null) {
return true;
} else if (!cancelled && !jobId.isEmpty()) {
CoordinatorServiceOuterClass.GetJobResultResponse getJobResultResponse =
getJobResult(jobId, connectContext.getWorkspace(), connectContext.getInstanceId(),
connectContext.useInternalOssEndpoint(), 1, INTERVAL);
jobStatus = getJobResultResponse.getStatus();
return isJobFinish(getJobResultResponse, 10);
}
throw new CZException(String.format("Get job %s status, %s.", jobId,
cancelled ? "job already cancelled" : "error"));
}
private boolean executeInternal(String s) throws SQLException {
logger.debug("executeInternal: {}", s);
long beginExecute = System.currentTimeMillis();
long startExecute = beginExecute;
cancelled = false;
if (resultSet != null) {
resultSet.close();
resultSet = null;
}
jobResultSet = null;
commandType = CommandType.NO_COPY;
copyTable = "";
copyLocation = "";
warning = "";
executeCount++;
List multiQueries = CZUtil.querySplit2(s, ';');
int queryIndex = 0;
for (; queryIndex < multiQueries.size(); queryIndex++) {
String trimed = multiQueries.get(queryIndex).trim();
if (!trimed.isEmpty()) {
if (!executeManageQuery(trimed)) {
break;
} else {
connectContext.addConfigStatementHistory(trimed);
}
}
}
String logStr = String.format("Parse manage query %s: %d(ms)\n", jobId, System.currentTimeMillis() - beginExecute);
beginExecute = System.currentTimeMillis();
logger.debug(logStr);
if (connectContext.showDebug()) {
warning += logStr;
}
if (queryIndex == multiQueries.size()) {
return resultSet != null;
}
String sql = multiQueries.get(queryIndex);
// replace select {fn ... }
// sql = CZUtil.fnReplace(sql);
String[] volumeInfo = new String[2];
connectContext.setConfig("cz.sql.sdk.info", ClickZettaClient.SDK_INFO);
if (commandType == CommandType.COPY_TO) {
if (copyTable.contains(" ")) {
sql = copyTable;
} else {
sql = "select * from " + copyTable;
}
// TODO: do we need to set csv related (orginally for upload only) context here?
connectContext.setConfig("cz.sql.adhoc.result.type", "file");
if (!connectContext.getConfigs().containsKey("cz.sql.adhoc.default.format") ||
(connectContext.getConfigs().containsKey("cz.sql.adhoc.default.format") &&
connectContext.getConfigs().get("cz.sql.adhoc.default.format").equalsIgnoreCase("ARROW"))) {
connectContext.setConfig("cz.sql.adhoc.default.format", "TEXT");
}
if (!connectContext.getConfigs().containsKey("cz.sql.job.result.file.presigned.url.enabled")) {
connectContext.setConfig("cz.sql.job.result.file.presigned.url.enabled", "true");
}
if (!connectContext.getConfigs().containsKey("cz.sql.job.result.file.presigned.url.ttl")) {
connectContext.setConfig("cz.sql.job.result.file.presigned.url.ttl", "3600");
}
logger.info("copy to command {}", sql);
} else if (commandType == CommandType.COPY_FROM) {
logger.info("copy from command {}", sql);
return true;
} else if (commandType == CommandType.PUT_VOLUME) {
volumeInfo = connectContext.getVolumePath().split("/", 2);
sql = "select get_presigned_url(volume " +
volumeInfo[0] +
", '" +
volumeInfo[1] +
"', " +
3600 +
", 'PUT'" +
")";
logger.info("put volume command {}", sql);
} else if (commandType == CommandType.GET_VOLUME) {
volumeInfo = connectContext.getVolumePath().split("/", 2);
sql = "select get_presigned_url(volume " +
volumeInfo[0] +
", '" +
volumeInfo[1] +
"', " +
3600 +
", 'GET'" +
")";
logger.info("get volume command {}", sql);
}
logStr = String.format("Before execute %s: %d(ms)\n", jobId, System.currentTimeMillis() - beginExecute);
beginExecute = System.currentTimeMillis();
logger.debug(logStr);
if (connectContext.showDebug()) {
warning += logStr;
}
jobStatus = CoordinatorServiceOuterClass.JobStatus.newBuilder().build();
try {
sql = sql + "\n;";
if (!jobIdPassIn.isEmpty()) {
jobId = jobIdPassIn;
} else {
jobId = CZRequestIdGenerator.getInstance().generate();
}
logStr = String.format("Gen job id %s: %s %d(ms)\n", jobId, sql, System.currentTimeMillis() - beginExecute);
beginExecute = System.currentTimeMillis();
logger.info(logStr);
if (connectContext.showDebug()) {
warning += logStr;
warning += String.format("\nConfigInfo maxRows: %d, %d\n\n", getMaxRows(), connectContext.getMaxRowSize());
}
String requestStr = CZLakehouseRequestHelper.constructSubmitJobRequest(
sql, jobId, connectContext.getConfigStatementHistory(), connectContext.toJson(),
connectContext.getWorkspace(),
connectContext.getSchema(),
connectContext.getVirtualCluster(),
CoordinatorServiceOuterClass.JobRequestMode.HYBRID,
connectContext.getHybridPollingTimeout(),
connectContext.getPriority(),
connectContext.getConfigs(),
connectContext.getQueryTag(),
connectContext.getHost(),
queryTimeoutMs == null ? connectContext.getJdbcQueryTimeoutMs() : queryTimeoutMs);
logStr = String.format("Send request: %s, %s, %s, %d(ms)\n", jobId, sql, requestStr,
System.currentTimeMillis() - beginExecute);
logger.debug(logStr);
if (connectContext.showDebug()) {
warning += logStr;
}
// submit job
SubmitJobResponse response = submitJob(requestStr);
// When the error code is CZLH-57015, jobid needs to be generated to resubmit the job, at most 1 times
if (response != null && isNeedReExecute(response.getStatus().getErrorCode())) {
return executeInternal(s);
}
if (commandType == CommandType.NO_COPY) {
if (CZConnectContext.getDbapiMode() && sql.toLowerCase().startsWith("show tables")) {
// hack for dbapi mode
resultSet = getTableNameResultSet(resultSet, jobResultSet);
}
} else if (commandType == CommandType.COPY_TO) {
beginExecute = System.currentTimeMillis();
connectContext.setConfig("cz.sql.adhoc.result.type", "embedded");
connectContext.setConfig("cz.sql.adhoc.default.format", "ARROW");
CZUtil.saveRemoteFileToLocal(jobResultSet.getLocation(), copyLocation);
logStr = String.format("Save oss file to local: %s, %d(ms)\n", jobId, System.currentTimeMillis() - beginExecute);
logger.info(logStr);
if (connectContext.showDebug()) {
warning += logStr;
}
return false;
} else if (commandType == CommandType.PUT_VOLUME) {
while (resultSet.next()) {
CZUtil.putObjectWithHttp((String) resultSet.getObject(1), connectContext.getLocalFilePath());
}
resultSet = genVolumeResultSet(connectContext.getLocalFilePath(), volumeInfo[1], commandType);
} else if (commandType == CommandType.GET_VOLUME && connectContext.getVolumeDownloadFlag()) {
while (resultSet.next()) {
CZUtil.getObjectWithHttp((String) resultSet.getObject(1), connectContext.getLocalFilePath());
}
resultSet = genVolumeResultSet(volumeInfo[1], connectContext.getLocalFilePath(), commandType);
}
return resultSet != null;
} catch (CZUnsupportedVersionException | SQLTimeoutException | CZJobAsyncRunningException e) {
throw e;
} catch (Exception e) {
logger.error("executeQuery fail", e);
errorMessage = e.getMessage();
warning += String.format("Job %s, status %s, \n%s", jobId, jobStatus.getState().isEmpty() ? "NoState" : jobStatus.getState(), e.getMessage());
} finally {
executeCount--;
}
throw new SQLException(warning);
}
private ResultSet getTableNameResultSet(ResultSet resultSet, CoordinatorServiceOuterClass.JobResultSet jobResult)
throws SQLException {
List rawDatas = new ArrayList<>();
while (resultSet.next()) {
rawDatas.add((String) resultSet.getObject(2));
}
List columnMetaDatas = new ArrayList<>();
columnMetaDatas.add(CZLakehouseResponseHelper.parseColumnMetaData(jobResult.getMetadata()).get(1));
CZResult czResult = new CZInMemoryTextResult(rawDatas, columnMetaDatas, connectContext.getMaxRowSize());
return new CZTextResultSet(columnMetaDatas, czResult);
}
// return true if submitted, else false
private boolean checkNotSubmitted() {
CoordinatorServiceOuterClass.GetJobResultResponse getJobResultResponse = null;
try {
getJobResultResponse = getJobResult(jobId, connectContext.getWorkspace(), connectContext.getInstanceId(),
connectContext.useInternalOssEndpoint(), 3, 3000);
} catch (Exception e) {
return true;
}
return getJobResultResponse == null;
}
private boolean waitContinueSubmit(int tried) {
if (tried >= MAX_TRIED) {
return false;
}
if (checkNotSubmitted()) {
try {
Thread.sleep(500L * tried);
return true;
} catch (InterruptedException e) {
logger.warn("Receive Interrupt but Job {} is still running...", jobId);
}
}
return false;
}
private SubmitJobResponse submitJob(String requestStr) throws Exception {
long beginExecute = System.currentTimeMillis();
long gatewayBegin = 0;
jobMetric.setClientRequestMs(beginExecute);
SubmitJobResponse response = null;
for (int tried = 1; !cancelled && tried <= MAX_TRIED; ++tried) {
try {
response = lakehouseClient.submitJob(requestStr, connectContext, jobId);
if (gatewayBegin == 0) {
gatewayBegin = connectContext.getHttpHelper().getGatewayStartMs();
}
if (response == null) {
if (waitContinueSubmit(tried)) {
continue;
}
} else if (stsTokenError(response.getResultSet(), connectContext.useInternalOssEndpoint())) {
throw new SQLException("Sts token is not generated");
} else if (response.getStatus().getErrorCode().equals(JOB_ALREADY_EXIST)) {
logger.warn("Job {} already exist, no need to submit again", jobId);
} else if (response.getStatus().getErrorCode().equals(JOB_STATUS_UNKNOWN)) {
logger.warn("Job {} status unknown, need to submit again", jobId);
if (waitContinueSubmit(tried)) {
continue;
}
} else if (response.getStatus().getErrorCode().equals(JOB_NOT_SUBMITTED)) {
logger.warn("Job {} not submitted, need to submit again", jobId);
if (waitContinueSubmit(tried)) {
continue;
}
}
} catch (NumberFormatException e) {
throw e;
} catch (Exception e) {
long cost = System.currentTimeMillis() - beginExecute;
String logStr = String.format("submitJob throw Exception, %s tried %d, left %d, got exception: %s, cost: %d(ms)\n",
jobId, tried, MAX_TRIED-tried, e, cost);
warning += logStr;
if (waitContinueSubmit(tried)) {
logger.warn(logStr);
continue;
} else if (tried < MAX_TRIED) {
// job submitted success
break;
}
logger.error(logStr);
throw e;
}
if (response == null || !CZUtil.isJobFinished(response.getRespStatus(), response.getStatus(), response.getResultSet(), 0)) {
try {
StringBuilder warnInLoop = retryGetResult(beginExecute);
warning += warnInLoop.toString();
break;
} catch (CZJobNotExistsException e) {
// do nothing, try submitJob again
logger.error("job {} not exist, try submit again", jobId, e);
}
} else {
if (isNeedReExecute(response.getStatus().getErrorCode())) {
break;
}
resultSet = CZLakehouseResponseHelper.parseSubmitJobResponse(response,
connectContext.getMaxRowSize(),
connectContext.useInternalOssEndpoint(),
connectContext.getConfigs(),
connectContext.useObjectStoreHttps());
jobStatus = response.getStatus();
jobResultSet = response.getResultSet();
String logStr = String.format("Parse result finish: %s, %d(ms), lakehouse running ms: %d\n", jobId,
System.currentTimeMillis() - beginExecute,
response.getStatus().getRunningTime());
logger.info(logStr);
warning = connectContext.showDebug() ? warning += logStr : warning;
break;
}
}
jobMetric.setGatewayStartMs(gatewayBegin);
jobMetric.setGatewayEndMs(connectContext.getHttpHelper().getGatewayEndMs());
jobMetric.setServerSubmitMs(jobStatus.getSubmitTime());
jobMetric.setServerStartMs(jobStatus.getStartTime());
jobMetric.setServerEndMs(jobStatus.getEndTime());
jobMetric.fillServerJobProfiling(jobStatus.getJobProfiling());
jobMetric.setClientResponseMs(connectContext.getHttpHelper().getHttpCallEndMs());
return response;
}
private boolean isNeedReExecute(String errorCode) {
return errorCode.equals("CZLH-57015") && executeCount < 2;
}
/**
* getResult loop
*/
private StringBuilder retryGetResult(long startExecute) throws Exception {
int retryTime = 1, sleepTimer = 50;
StringBuilder warnInLoop = new StringBuilder();
while (true) {
CoordinatorServiceOuterClass.GetJobResultResponse getJobResultResponse =
getJobResult(jobId, connectContext.getWorkspace(), connectContext.getInstanceId(),
connectContext.useInternalOssEndpoint(), 1, INTERVAL);
if (getJobResultResponse == null) {
warnInLoop.append("Get Job Result Failed. Retry for ").append(retryTime).append(" times\n");
retryTime++;
continue;
}
jobStatus = getJobResultResponse.getStatus();
if (isJobFinish(getJobResultResponse, retryTime)) {
if (connectContext.showDebug()) {
warnInLoop.append("JobResult: \n").append(responseToString(getJobResultResponse)).append("\n\n\n");
}
break;
}
long timeExecuted = System.currentTimeMillis() - startExecute;
String logStr = String.format("Job %s is running... status: %s, tried %d, %d(ms)\n", jobId, jobStatus.toString(),
retryTime, timeExecuted);
logger.info(logStr);
retryTime++;
if (connectContext.getQueryTimeout() > 0 && timeExecuted > connectContext.getQueryTimeout()) {
logger.error("Job {} execute timeout, used {} ms", jobId, timeExecuted);
cancel();
throw new SQLTimeoutException(String.format("executeQuery timeout, used %d ms", timeExecuted));
} else if (connectContext.getJDBCMode() > 0 && timeExecuted > 30*1000) {
logger.warn("Job {} used {} ms, throw async running exception.", jobId, timeExecuted);
throw new CZJobAsyncRunningException(jobId);
}
try {
Thread.sleep(sleepTimer);
} catch (InterruptedException e) {
System.out.println("Job " + jobId + " is still running...");
logger.warn("Receive Interrupt but Job {} is still running...", jobId);
}
if (sleepTimer < 3000) {
sleepTimer *= 2;
}
}
return warnInLoop;
}
private boolean isJobFinish(CoordinatorServiceOuterClass.GetJobResultResponse getJobResultResponse,
int retryTime) throws Exception {
if (CZUtil.isJobFinished(getJobResultResponse.getRespStatus(), getJobResultResponse.getStatus(),
getJobResultResponse.getResultSet(), retryTime)) {
resultSet = CZLakehouseResponseHelper.parseJobResult(
getJobResultResponse.getStatus(),
getJobResultResponse.getResultSet(),
connectContext.getMaxRowSize(),
connectContext.useInternalOssEndpoint(),
connectContext.getConfigs(),
connectContext.useObjectStoreHttps());
jobResultSet = getJobResultResponse.getResultSet();
return true;
}
return false;
}
private String responseToString(SubmitJobResponse response) throws InvalidProtocolBufferException {
SubmitJobResponse.Builder logResponse = SubmitJobResponse.newBuilder(response);
logResponse.getResultSetBuilder().clearLocation().clearData();
return JsonFormat.printer().print(logResponse);
}
private String responseToString(CoordinatorServiceOuterClass.GetJobResultResponse response) throws InvalidProtocolBufferException {
CoordinatorServiceOuterClass.GetJobResultResponse.Builder logResponse = CoordinatorServiceOuterClass.GetJobResultResponse.newBuilder(response);
logResponse.getResultSetBuilder().clearLocation().clearData();
return JsonFormat.printer().print(logResponse);
}
@Override
public int executeUpdate(String s) throws SQLException {
return 0;
}
@Override
public void close() throws SQLException {
logger.info("Statement: {} start closing resultSet: {}", this, resultSet);
if (resultSet != null) {
resultSet.close();
resultSet = null;
}
}
@Override
public int getMaxFieldSize() throws SQLException {
return 0;
}
@Override
public void setMaxFieldSize(int i) throws SQLException {
}
@Override
public int getMaxRows() throws SQLException {
return maxRows;
}
@Override
public void setMaxRows(int max) throws SQLException {
if (max > 1000000) {
throw new SQLException("setMaxRows larger than 1000000.");
}
this.maxRows = max;
connectContext.setMaxRowSize(max);
}
@Override
public void setEscapeProcessing(boolean b) throws SQLException {
}
@Override
public int getQueryTimeout() throws SQLException {
if (queryTimeoutMs == null) {
return connectContext.getJdbcQueryTimeoutMs() / 1000;
}
return queryTimeoutMs / 1000;
}
@Override
public void setQueryTimeout(int i) throws SQLException {
queryTimeoutMs = i * 1000;
}
@Override
public void cancel() throws SQLException {
cancel(jobId);
}
public void cancel(String jobId) throws SQLException {
logger.info("try to cancel query: {}", jobId);
try {
String requestStr = CZLakehouseRequestHelper.constructCancelJobRequest(jobId
, connectContext.getWorkspace(), -1);
CoordinatorServiceOuterClass.CancelJobResponse response =
lakehouseClient.cancelJob(requestStr, connectContext, jobId);
logger.info("cancel response {}", JsonFormat.printer().print(response));
if (jobId.equals(this.jobId)) {
cancelled = true;
}
} catch (Exception e) {
logger.info("cancel fail", e);
}
}
@Override
public SQLWarning getWarnings() throws SQLException {
if (!warning.isEmpty()) {
return new SQLWarning(jobId + ", " + warning);
} else {
return null;
}
}
@Override
public void clearWarnings() throws SQLException {
warning = "";
}
@Override
public void setCursorName(String s) throws SQLException {
}
public CoordinatorServiceOuterClass.JobStatus getJobStatus() {
return jobStatus;
}
boolean executeManageQuery(String originStr) throws SQLException {
String stripOriginStr = CZUtil.stripLeadingComment(originStr);
String str = stripOriginStr.toLowerCase();
if (!str.startsWith("use") && !str.startsWith("set") && !str.startsWith("clear")
&& !str.startsWith("show configs") && !str.startsWith("show context") && !str.startsWith(
"print") && !str.startsWith("copy") && !str.startsWith("put") && !str.startsWith("get volume")) {
return false;
}
for (Map.Entry> entry : commandMap.entrySet()) {
if (str.startsWith(entry.getKey())) {
return entry.getValue().apply(stripOriginStr);
}
}
return false;
}
public CoordinatorServiceOuterClass.JobResultSet getJobResultSet() {
return jobResultSet;
}
public String getErrorMessage() {
return errorMessage;
}
public boolean execute(String statement, String jobId) throws Exception {
this.jobIdPassIn = jobId;
return execute(statement);
}
@Override
public boolean execute(String s) throws SQLException {
return executeInternal(s);
}
@Override
public ResultSet getResultSet() throws SQLException {
logger.info("Statement {} getResultSet: {}", this, resultSet);
return resultSet;
}
@Override
public int getUpdateCount() throws SQLException {
return -1;
}
@Override
public boolean getMoreResults() throws SQLException {
return false;
}
@Override
public void setFetchDirection(int i) throws SQLException {
}
@Override
public int getFetchDirection() throws SQLException {
return 0;
}
@Override
public void setFetchSize(int i) throws SQLException {
}
@Override
public int getFetchSize() throws SQLException {
return 0;
}
@Override
public int getResultSetConcurrency() throws SQLException {
return 0;
}
@Override
public int getResultSetType() throws SQLException {
return 0;
}
@Override
public void addBatch(String s) throws SQLException {
}
@Override
public void clearBatch() throws SQLException {
}
@Override
public int[] executeBatch() throws SQLException {
return new int[0];
}
@Override
public Connection getConnection() throws SQLException {
return null;
}
@Override
public boolean getMoreResults(int i) throws SQLException {
return false;
}
@Override
public ResultSet getGeneratedKeys() throws SQLException {
return null;
}
@Override
public int executeUpdate(String s, int i) throws SQLException {
return 0;
}
@Override
public int executeUpdate(String s, int[] ints) throws SQLException {
return 0;
}
@Override
public int executeUpdate(String s, String[] strings) throws SQLException {
return 0;
}
@Override
public boolean execute(String s, int i) throws SQLException {
return false;
}
@Override
public boolean execute(String s, int[] ints) throws SQLException {
return false;
}
@Override
public boolean execute(String s, String[] strings) throws SQLException {
return false;
}
@Override
public int getResultSetHoldability() throws SQLException {
return 0;
}
@Override
public boolean isClosed() throws SQLException {
return false;
}
@Override
public void setPoolable(boolean poolable) throws SQLException {
this.poolable = poolable;
}
@Override
public boolean isPoolable() throws SQLException {
return poolable;
}
@Override
public void closeOnCompletion() throws SQLException {
}
@Override
public boolean isCloseOnCompletion() throws SQLException {
return false;
}
@Override
public T unwrap(Class aClass) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class> aClass) throws SQLException {
return false;
}
public CoordinatorServiceOuterClass.GetJobPlanResponse getJobPlan(CoordinatorServiceOuterClass.JobID jobId) throws Exception {
String request =
CZLakehouseRequestHelper.constructGetJobPlanRequest(jobId.getId()
, jobId.getWorkspace(), jobId.getInstanceId());
return lakehouseClient.getJobPlan(request, connectContext, jobId.getId());
}
@Deprecated
public CoordinatorServiceOuterClass.GetJobSummaryResponse getJobSummary(CoordinatorServiceOuterClass.JobID jobId) throws Exception {
String request = CZLakehouseRequestHelper.constructGetJobSummaryRequest(jobId.getId()
, jobId.getWorkspace(), jobId.getInstanceId());
return lakehouseClient.getJobSummary(request, connectContext, jobId.getId());
}
@Deprecated
public CoordinatorServiceOuterClass.GetJobProgressResponse getJobProgress(CoordinatorServiceOuterClass.JobID jobId) throws Exception {
String request = CZLakehouseRequestHelper.constructGetJobProgressRequest(jobId.getId()
, jobId.getWorkspace(), jobId.getInstanceId());
return lakehouseClient.getJobProgress(request, connectContext, jobId.getId());
}
private CoordinatorServiceOuterClass.GetJobResultResponse getJobResult(CoordinatorServiceOuterClass.JobID jobId,
boolean useInternalOss,
int max_retry, int interval) throws Exception {
return getJobResult(jobId.getId(), jobId.getWorkspace(), jobId.getInstanceId(), useInternalOss, max_retry, interval);
}
private CoordinatorServiceOuterClass.GetJobResultResponse getJobResult(String jobId, String workspace, long instanceId,
boolean useInternalOss,
int max_retry, int interval) throws Exception {
String request = CZLakehouseRequestHelper.constructGetJobResultRequest(jobId, workspace, instanceId, connectContext.getHost());
CoordinatorServiceOuterClass.GetJobResultResponse getResult = null;
for (int tried = 1; tried <= max_retry; ++tried) {
try {
getResult = lakehouseClient.getJobResult(request, connectContext, jobId);
// sts token error, try again
if (getResult == null) {
continue;
} else if (stsTokenError(getResult.getResultSet(), useInternalOss)) {
logger.warn(String.format("Oss sts token is not given, tried %d.", tried));
if (!cancelled && tried < max_retry) {
Thread.sleep(interval);
continue;
} else {
throw new SQLException("Sts token is not generated");
}
}
break;
} catch (Exception e) {
logger.error("getJobResult error: {}", e.toString());
if (!e.getMessage().contains("NoCoordinatorServing") && !e.getMessage().contains(JOB_STATUS_UNKNOWN) &&
!e.getMessage().contains(JOB_NOT_SUBMITTED)) {
throw e;
} else {
Thread.sleep(interval);
}
}
}
// job not exist
if (getResult != null && getResult.getStatus().getErrorCode().equals(JOB_NOT_EXIST)) {
throw new CZJobNotExistsException(jobId);
}
// http request error
if (getResult != null && getResult.getStatus().getState().isEmpty()) {
throw new SQLException(JsonFormat.printer().print(getResult));
}
return getResult;
}
private boolean stsTokenError(CoordinatorServiceOuterClass.JobResultSet resultSet, boolean useInternalOss) {
if (!resultSet.hasData() && resultSet.hasLocation() && resultSet.getLocation().getLocationCount() > 0) {
CoordinatorServiceOuterClass.JobResultLocation location = resultSet.getLocation();
if (location.getFileSystem().equals(FileSystem.FileSystemType.GCS)) {
return location.getStsToken().isEmpty();
} else {
return location.getStsAkId().isEmpty() || location.getStsAkSecret().isEmpty() ||
location.getStsToken().isEmpty();
}
}
return false;
}
public CZJobMetric getJobMetric() {
return jobMetric;
}
@Deprecated
public CoordinatorServiceOuterClass.GetJobProfileResponse getJobProfile(CoordinatorServiceOuterClass.JobID jobId) throws Exception {
String request = CZLakehouseRequestHelper.constructGetJobProfileRequest(jobId.getId()
, jobId.getWorkspace(), jobId.getInstanceId());
return lakehouseClient.getJobProfile(request, connectContext, jobId.getId());
}
@Deprecated
public CoordinatorServiceOuterClass.CreateWorkspaceResponse createWorkspace(CoordinatorServiceOuterClass.CreateWorkspaceRequest request) throws Exception {
return lakehouseClient.createWorkspace(JsonFormat.printer().print(request), connectContext);
}
@Deprecated
public CoordinatorServiceOuterClass.DeleteWorkspaceResponse deleteWorkspace(String workspaceName, long instanceId) throws Exception {
CoordinatorServiceOuterClass.DeleteWorkspaceRequest req =
CoordinatorServiceOuterClass.DeleteWorkspaceRequest.newBuilder().setIdentifier(
ObjectIdentifier.newBuilder().setName(workspaceName).setInstanceId(instanceId).setType(ObjectType.WORKSPACE).build()).build();
return lakehouseClient.deleteWorkspace(JsonFormat.printer().print(req), connectContext);
}
@Deprecated
public CoordinatorServiceOuterClass.UpdateWorkspaceResponse updateWorkspace(CoordinatorServiceOuterClass.UpdateWorkspaceRequest request) throws Exception {
return lakehouseClient.updateWorkspace(JsonFormat.printer().print(request), connectContext);
}
@Deprecated
public CoordinatorServiceOuterClass.GetWorkspaceResponse getWorkspace(String workspaceName, long instanceId) throws Exception {
CoordinatorServiceOuterClass.GetWorkspaceRequest req =
CoordinatorServiceOuterClass.GetWorkspaceRequest.newBuilder().setIdentifier(
ObjectIdentifier.newBuilder().setName(workspaceName).setInstanceId(instanceId).setType(ObjectType.WORKSPACE).build()).build();
return lakehouseClient.getWorkspace(JsonFormat.printer().print(req), connectContext);
}
@Deprecated
public CoordinatorServiceOuterClass.ListWorkspacesResponse listWorkspaces(long instanceId) throws Exception {
CoordinatorServiceOuterClass.ListWorkspacesRequest req =
CoordinatorServiceOuterClass.ListWorkspacesRequest.newBuilder().setInstanceId(instanceId).build();
return lakehouseClient.listWorkspaces(JsonFormat.printer().print(req), connectContext);
}
public CoordinatorServiceOuterClass.OpenTableResponse openTable(
String schemaName, String tableName, boolean icebergFormat) throws Exception {
String request = CZLakehouseRequestHelper.constructOpenTableRequest(
connectContext.getWorkspace()
, schemaName, tableName, connectContext.getInstanceId(), icebergFormat);
return lakehouseClient
.openTable(request, connectContext, schemaName, tableName);
}
private String parseStrInQuote(String str) throws SQLException {
if (str.length() < 2) {
throw new SQLException(str + " should start and end with ' or \"");
} else if (str.charAt(0) == '\'' && str.charAt(str.length() - 1) == '\'') {
return str.substring(1, str.length() - 1);
} else if (str.charAt(0) == '"' && str.charAt(str.length() - 1) == '"') {
return str.substring(1, str.length() - 1);
} else {
throw new SQLException(str + " should start and end with ' or \"");
}
}
@FunctionalInterface
interface ThrowingFunction {
R apply(T t) throws E;
}
private final Map>commandMap = new LinkedHashMap<>();
private int maxRows = 0;
private boolean poolable = false;
private final Set openResultSets = ConcurrentHashMap.newKeySet();
// result set currently in use
private ResultSet resultSet = null;
private CoordinatorServiceOuterClass.JobResultSet jobResultSet = null;
private String jobId = "";
private String jobIdPassIn = "";
private Boolean isClosed = false;
private final String useSchema_ = "use schema ";
private final String use_ = "use ";
private final String useVcluster_ = "use vcluster ";
private final String setMode = "set mode";
private final String setPriority = "set priority";
private final String setScheduleJobPriority = "set schedule_job_priority";
private final String setConfig_ = "set ";
private final String showConfig = "show configs";
private final String showContext = "show context";
private final String clearConfig = "clear configs";
private final String printDebug = "print debug";
private final String printNoDebug = "print nodebug";
private final String clearContext = "clear context";
private final String setWorkspace = "set workspace";
private final String setInstanceId = "set instanceid";
private final String setUserId = "set userid";
private final String setPollingTimeout = "set pollingtimeout";
private final String setQueryTimeout = "set querytimeout";
private final String setJdbcQueryTimeout = "set jdbc.query.timeout.ms";
private final String setMaxRowSize = "set maxrowsize";
private final String setCopyCsvDelimiter = "set copy.csv.delimiter";
private final String setCopyCsvFieldDelimiter = "set copy.csv.field.delimiter";
private final String setCopyCsvEscape = "set copy.csv.escape";
private final String setCopyCsvWithHeader = "set copy.csv.with.header";
private final String setCopyCsvSkipHeader = "set copy.csv.skip.header";
private final String setCopyCsvNullString = "set copy.csv.null.string";
private final String setCopyCsvIgnoreMalformedRecord = "set copy.csv.ignore.malformed.record";
private final String setCopyCsvTimeZonePlus = "set copy.csv.timezone.plus";
private final String copy_ = "copy ";
private final String setQueryTag = "set query_tag";
private final String putvolume = "put ";
private final String getVolume = "get volume";
private final String setVolumeDownload = "set volume.download";
private void initCommandMap() {
commandMap.put(clearContext, this::clearContext);
commandMap.put(useSchema_, this::useSchema);
commandMap.put(useVcluster_, this::useVCluster);
commandMap.put(use_, this::useSchemaAlias);
commandMap.put(setUserId, this::setUserId);
commandMap.put(setInstanceId, this::setInstanceId);
commandMap.put(setWorkspace, this::setWorkspace);
commandMap.put(setMode, this::setMode);
commandMap.put(setPollingTimeout, this::setPollingTimeout);
commandMap.put(setQueryTimeout, this::setQueryTimeout);
commandMap.put(setJdbcQueryTimeout, this::setJdbcQueryTimeout);
commandMap.put(setMaxRowSize, this::setMaxRowSize);
commandMap.put(setQueryTag, this::setQueryTag);
commandMap.put(setCopyCsvDelimiter, this::setCopyCsvDelimiter);
commandMap.put(setCopyCsvFieldDelimiter, this::setCopyCsvFieldDelimiter);
commandMap.put(setCopyCsvEscape, this::setCopyCsvEscape);
commandMap.put(setCopyCsvWithHeader, this::setCopyCsvWithHeader);
commandMap.put(setCopyCsvSkipHeader, this::setCopyCsvSkipHeader);
commandMap.put(setCopyCsvNullString, this::setCopyCsvNullString);
commandMap.put(setCopyCsvIgnoreMalformedRecord, this::setCopyCsvIgnoreMalformedRecord);
commandMap.put(setCopyCsvTimeZonePlus, this::setCopyCsvTimeZonePlus);
commandMap.put(setPriority, this::setPriority);
commandMap.put(setScheduleJobPriority, this::setScheduleJobPriority);
commandMap.put(setVolumeDownload, this::setVolumeDownload);
commandMap.put(setConfig_, this::setConfig);
commandMap.put(showConfig, this::showConfig);
commandMap.put(showContext, this::showContext);
commandMap.put(clearConfig, this::clearConfig);
commandMap.put(printDebug, this::printDebug);
commandMap.put(printNoDebug, this::printNoDebug);
commandMap.put(copy_, this::copyCommand);
commandMap.put(putvolume, this::putVolume);
commandMap.put(getVolume, this::getVolume);
}
private boolean clearContext(String stripOriginStr) throws SQLException {
logger.info("clearing context");
connectContext.clearContextForDirectMode();
return true;
}
private boolean useSchema(String stripOriginStr) throws SQLException {
String str = stripOriginStr.toLowerCase();
String schema = str.substring(useSchema_.length()).trim();
logger.info("using schema: {}", schema);
checkSchema(schema);
connectContext.setSchema(getRealSchema(schema));
return true;
}
private boolean useVCluster(String stripOriginStr) throws SQLException {
String vc = stripOriginStr.substring(useVcluster_.length()).trim();
logger.info("using virtual cluster: {}", vc);
if (vc.contains(" ")) {
throw new SQLException("invalid vcluster: " + vc);
}
connectContext.setVc(vc);
return true;
}
private boolean useSchemaAlias(String stripOriginStr) throws SQLException {
String str = stripOriginStr.toLowerCase();
String schema = str.substring(use_.length()).trim();
logger.info("using schema: {}", schema);
checkSchema(schema);
connectContext.setSchema(getRealSchema(schema));
return true;
}
private boolean setUserId(String stripOriginStr) throws SQLException {
String str = stripOriginStr.toLowerCase();
if (connectContext.getRunningMode() != CZConnectContext.RunningMode.COORDINATOR &&
connectContext.getRunningMode() != CZConnectContext.RunningMode.COORDINATOR_SERVICE) {
throw new SQLException("Set user id is not supported in running mode " + connectContext.getRunningMode());
}
String equalStr = str.substring(setUserId.length()).trim();
if (equalStr.startsWith("=")) {
long newUserId = Long.parseLong(equalStr.substring("=".length()).trim());
logger.info("setting user id: {}", newUserId);
connectContext.setUserId(newUserId);
return true;
} else {
throw new SQLException("Invalid statement: " + str);
}
}
private boolean setInstanceId(String stripOriginStr) throws SQLException {
String str = stripOriginStr.toLowerCase();
if (connectContext.getRunningMode() != CZConnectContext.RunningMode.COORDINATOR &&
connectContext.getRunningMode() != CZConnectContext.RunningMode.COORDINATOR_SERVICE) {
throw new SQLException("Set instance id is not supported in running mode " + connectContext.getRunningMode());
}
String equalStr = str.substring(setInstanceId.length()).trim();
if (equalStr.startsWith("=")) {
long newInstanceId = Long.parseLong(equalStr.substring("=".length()).trim());
logger.info("setting instance id: {}", newInstanceId);
connectContext.setInstanceId(newInstanceId);
return true;
} else {
throw new SQLException("Invalid statement " + str);
}
}
private boolean setWorkspace(String stripOriginStr) throws SQLException {
String str = stripOriginStr.toLowerCase();
if (connectContext.getRunningMode() != CZConnectContext.RunningMode.COORDINATOR &&
connectContext.getRunningMode() != CZConnectContext.RunningMode.COORDINATOR_SERVICE) {
throw new SQLException("Set workspace is not supported in running mode " + connectContext.getRunningMode());
}
String equalStr = str.substring(setWorkspace.length()).trim();
if (equalStr.startsWith("=")) {
String newWorkspace = equalStr.substring("=".length()).trim();
logger.info("setting workspace: {}", newWorkspace);
connectContext.setWorkspace(newWorkspace);
return true;
} else {
throw new SQLException("Invalid statement " + str);
}
}
private boolean setMode(String stripOriginStr) throws SQLException {
String str = stripOriginStr.toLowerCase();
String equalStr = str.substring(setMode.length()).trim();
if (equalStr.startsWith("=")) {
String mode = equalStr.substring("=".length()).trim();
logger.info("setting jdbc mode: {}", mode);
if (mode.equals("hybrid")) {
connectContext.setJDBCMode(1);
} else {
connectContext.setJDBCMode(0);
}
return true;
} else {
throw new SQLException("Invalid statement " + str);
}
}
private boolean setPollingTimeout(String stripOriginStr) throws SQLException {
String str = stripOriginStr.toLowerCase();
String equalStr = str.substring(setPollingTimeout.length()).trim();
if (equalStr.startsWith("=")) {
String timeoutStr = equalStr.substring("=".length()).trim();
logger.info("setting polling timeout: {}", timeoutStr);
connectContext.setHybridPollingTimeout(Integer.parseInt(timeoutStr));
return true;
} else {
throw new SQLException("Invalid statement " + str);
}
}
private boolean setQueryTimeout(String stripOriginStr) throws SQLException {
String str = stripOriginStr.toLowerCase();
String equalStr = str.substring(setQueryTimeout.length()).trim();
if (equalStr.startsWith("=")) {
String timeoutStr = equalStr.substring("=".length()).trim();
logger.info("setting query timeout: {}", timeoutStr);
connectContext.setQueryTimeout(Integer.parseInt(timeoutStr));
return true;
} else {
throw new SQLException("Invalid statement " + str);
}
}
private boolean setMaxRowSize(String stripOriginStr) throws SQLException {
String str = stripOriginStr.toLowerCase();
String equalStr = str.substring(setMaxRowSize.length()).trim();
if (equalStr.startsWith("=")) {
String rowSize = equalStr.substring("=".length()).trim();
logger.info("setting max row size: {}", rowSize);
connectContext.setMaxRowSize(Integer.parseInt(rowSize));
return true;
} else {
throw new SQLException("Invalid statement " + str);
}
}
private boolean setQueryTag(String stripOriginStr) throws SQLException {
String equalStr = stripOriginStr.substring(setQueryTag.length()).trim();
if (equalStr.startsWith("=")) {
String queryTag = parseStrInQuote(equalStr.substring("=".length()).trim());
logger.info("setting query tag: {}", queryTag);
connectContext.setQueryTag(queryTag);
return true;
} else {
throw new SQLException("Invalid statement " + stripOriginStr);
}
}
private boolean setCopyCsvDelimiter(String stripOriginStr) throws SQLException {
String equalStr = stripOriginStr.substring(setCopyCsvDelimiter.length()).trim();
if (equalStr.startsWith("=")) {
String delimiterStr = parseStrInQuote(equalStr.substring("=".length()).trim());
logger.info("setting csv field delimiter: '{}'", delimiterStr);
if (CZUtil.escapeMap.containsKey(delimiterStr)) {
connectContext.setCsvFieldDelimiter((Character) CZUtil.escapeMap.get(delimiterStr));
return true;
} else if (delimiterStr.length() == 1) {
connectContext.setCsvFieldDelimiter(delimiterStr.charAt(0));
return true;
}
}
throw new SQLException("Invalid statement." + stripOriginStr);
}
private boolean setCopyCsvFieldDelimiter(String stripOriginStr) throws SQLException {
String equalStr = stripOriginStr.substring(setCopyCsvFieldDelimiter.length()).trim();
if (equalStr.startsWith("=")) {
String delimiterStr = parseStrInQuote(equalStr.substring("=".length()).trim());
logger.info("setting csv field delimiter: '{}'", delimiterStr);
if (CZUtil.escapeMap.containsKey(delimiterStr)) {
connectContext.setCsvFieldDelimiter((Character) CZUtil.escapeMap.get(delimiterStr));
return true;
} else if (delimiterStr.length() == 1) {
connectContext.setCsvFieldDelimiter(delimiterStr.charAt(0));
return true;
}
}
throw new SQLException("Invalid statement." + stripOriginStr);
}
private boolean setCopyCsvEscape(String stripOriginStr) throws SQLException {
String equalStr = stripOriginStr.substring(setCopyCsvEscape.length()).trim();
if (equalStr.startsWith("=")) {
String escapeStr = parseStrInQuote(equalStr.substring("=".length()).trim());
if (escapeStr.length() == 1) {
connectContext.setCsvEscapeChar(escapeStr.charAt(0));
} else if (escapeStr.length() > 1) {
connectContext.setCsvEscapeChar(StringEscapeUtils.escapeJava(escapeStr).charAt(0));
}
logger.info("setting csv escape: '{}'", connectContext.getCsvEscapeChar());
return true;
}
throw new SQLException("Invalid statement " + stripOriginStr);
}
private boolean setCopyCsvWithHeader(String stripOriginStr) throws SQLException {
String str = stripOriginStr.toLowerCase();
String equalStr = str.substring(setCopyCsvWithHeader.length()).trim();
if (equalStr.startsWith("=")) {
String value = equalStr.substring("=".length()).trim();
logger.info("setting csv with header: {}", value);
if (value.equalsIgnoreCase("false")) {
connectContext.setCsvWithHeader(false);
return true;
} else if (value.equalsIgnoreCase("true")) {
connectContext.setCsvWithHeader(true);
return true;
}
}
throw new SQLException("Invalid statement." + str);
}
private boolean setCopyCsvSkipHeader(String stripOriginStr) throws SQLException {
String str = stripOriginStr.toLowerCase();
String equalStr = str.substring(setCopyCsvSkipHeader.length()).trim();
if (equalStr.startsWith("=")) {
String skipStr = equalStr.substring("=".length()).trim();
logger.info("setting csv skip header: {}", skipStr);
if (skipStr.equalsIgnoreCase("false")) {
connectContext.setCsvSkipHeaer(false);
return true;
} else if (skipStr.equalsIgnoreCase("true")) {
connectContext.setCsvSkipHeaer(true);
return true;
}
}
throw new SQLException("Invalid statement " + str);
}
private boolean setCopyCsvNullString(String stripOriginStr) throws SQLException {
String equalStr = stripOriginStr.substring(setCopyCsvNullString.length()).trim();
if (equalStr.startsWith("=")) {
String nullStr = parseStrInQuote(equalStr.substring("=".length()).trim());
logger.info("setting csv null string: '{}'", nullStr);
connectContext.setCsvNullString(nullStr);
return true;
}
throw new SQLException("Invalid statement " + stripOriginStr);
}
private boolean setCopyCsvIgnoreMalformedRecord(String stripOriginStr) throws SQLException {
String equalStr = stripOriginStr.substring(setCopyCsvIgnoreMalformedRecord.length()).trim();
if (equalStr.startsWith("=")) {
String value = parseStrInQuote(equalStr.substring("=".length()).trim());
logger.info("setting csv ignore malformed record: {}", value);
connectContext.setCsvIgnoreMalformedRecord(Long.parseLong(value));
return true;
}
throw new SQLException("Invalid set copy.csv.ignore.malformed.record statement." + stripOriginStr);
}
private boolean setCopyCsvTimeZonePlus(String stripOriginStr) throws SQLException {
String equalStr = stripOriginStr.substring(setCopyCsvTimeZonePlus.length()).trim();
if (equalStr.startsWith("=")) {
String value = parseStrInQuote(equalStr.substring("=".length()).trim());
logger.info("{} {}", setCopyCsvTimeZonePlus, value);
connectContext.setCsvTimeZonePlus(Long.parseLong(value));
return true;
}
throw new SQLException("Invalid set copy.csv.timezone.plus. " + stripOriginStr);
}
private boolean setPriority(String stripOriginStr) throws SQLException {
String equalStr = stripOriginStr.substring(setPriority.length()).trim();
if (equalStr.startsWith("=")) {
String priorityStr = equalStr.substring("=".length()).trim();
logger.info("setting priority: {}", priorityStr);
connectContext.setPriorityInString(priorityStr);
return true;
} else {
throw new SQLException("Invalid statement " + stripOriginStr);
}
}
private boolean setScheduleJobPriority(String stripOriginStr) throws SQLException {
String equalStr = stripOriginStr.substring(setScheduleJobPriority.length()).trim();
if (equalStr.startsWith("=")) {
String priorityStr = equalStr.substring("=".length()).trim();
logger.info("setting priority: {}", priorityStr);
connectContext.setPriorityInString(priorityStr);
return true;
} else {
throw new SQLException("Invalid statement " + stripOriginStr);
}
}
private boolean setConfig(String stripOriginStr) throws SQLException {
String str = stripOriginStr.toLowerCase();
logger.info("setting config: " + str);
String setStatement = stripOriginStr.substring(setConfig_.length());
List setKeyValue = CZUtil.querySplit2(setStatement, '=', 1);
if (setKeyValue.size() == 2 && !setKeyValue.get(0).trim().isEmpty() && !setKeyValue.get(1).trim().isEmpty()) {
logger.info(String.format("setting config: '%s' = '%s'", setKeyValue.get(0).trim(), setKeyValue.get(1).trim()));
connectContext.setConfig(setKeyValue.get(0).trim(), setKeyValue.get(1).trim());
return true;
} else {
throw new SQLException("Invalid statement " + stripOriginStr);
}
}
private boolean showContext(String stripOriginStr) throws SQLException {
logger.info("showing context:");
Map configs = connectContext.getConfigs();
List columnMetaDatas = new ArrayList<>();
columnMetaDatas.add(new CZColumnMetaData("Instance", "VARCHAR",
Types.VARCHAR));
columnMetaDatas.add(new CZColumnMetaData("Workspace", "VARCHAR",
java.sql.Types.VARCHAR));
columnMetaDatas.add(new CZColumnMetaData("Schema", "VARCHAR",
java.sql.Types.VARCHAR));
List> rows = new ArrayList<>();
List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy