/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* Licensed 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.jkiss.dbeaver.ext.mysql.model;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.ext.mysql.MySQLConstants;
import org.jkiss.dbeaver.model.DBPDataKind;
import org.jkiss.dbeaver.model.DBPEvaluationContext;
import org.jkiss.dbeaver.model.DBPRefreshableObject;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCPreparedStatement;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCResultSet;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCSession;
import org.jkiss.dbeaver.model.impl.jdbc.JDBCUtils;
import org.jkiss.dbeaver.model.impl.struct.AbstractProcedure;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.struct.DBSObject;
import org.jkiss.dbeaver.model.struct.rdb.DBSProcedureType;
import org.jkiss.dbeaver.utils.GeneralUtils;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Locale;
/**
* GenericProcedure
*/
public class MySQLProcedure extends AbstractProcedure<MySQLDataSource, MySQLCatalog> implements MySQLSourceObject, DBPRefreshableObject
{
private DBSProcedureType procedureType;
private String resultType;
private String bodyType;
private boolean deterministic;
private transient String clientBody;
private String charset;
public MySQLProcedure(MySQLCatalog catalog)
{
super(catalog, false);
this.procedureType = DBSProcedureType.PROCEDURE;
this.bodyType = "SQL";
this.resultType = "";
this.deterministic = false;
}
public MySQLProcedure(
MySQLCatalog catalog,
ResultSet dbResult)
{
super(catalog, true);
loadInfo(dbResult);
}
private void loadInfo(ResultSet dbResult)
{
setName(JDBCUtils.safeGetString(dbResult, MySQLConstants.COL_ROUTINE_NAME));
setDescription(JDBCUtils.safeGetString(dbResult, MySQLConstants.COL_ROUTINE_COMMENT));
String procType = JDBCUtils.safeGetString(dbResult, MySQLConstants.COL_ROUTINE_TYPE);
this.procedureType = procType == null ? DBSProcedureType.PROCEDURE : DBSProcedureType.valueOf(procType.toUpperCase(Locale.ENGLISH));
this.resultType = JDBCUtils.safeGetString(dbResult, MySQLConstants.COL_DTD_IDENTIFIER);
this.bodyType = JDBCUtils.safeGetString(dbResult, MySQLConstants.COL_ROUTINE_BODY);
this.charset = JDBCUtils.safeGetString(dbResult, MySQLConstants.COL_CHARACTER_SET_CLIENT);
this.deterministic = JDBCUtils.safeGetBoolean(dbResult, MySQLConstants.COL_IS_DETERMINISTIC, "YES");
this.description = JDBCUtils.safeGetString(dbResult, MySQLConstants.COL_ROUTINE_COMMENT);
}
@Override
@Property(order = 2)
public DBSProcedureType getProcedureType()
{
return procedureType ;
}
public void setProcedureType(DBSProcedureType procedureType)
{
this.procedureType = procedureType;
}
@Property(order = 2)
public String getResultType()
{
return resultType;
}
@Property(order = 3)
public String getBodyType()
{
return bodyType;
}
@Property(hidden = true, editable = true, updatable = true, order = -1)
public String getDeclaration(DBRProgressMonitor monitor)
throws DBException
{
if (clientBody == null) {
if (!persisted) {
this.clientBody =
"CREATE " + getProcedureType().name() + " " + getFullyQualifiedName(DBPEvaluationContext.DDL) + "()" + GeneralUtils.getDefaultLineSeparator() +
(procedureType == DBSProcedureType.FUNCTION ? "RETURNS INT" + GeneralUtils.getDefaultLineSeparator() : "") +
"BEGIN" + GeneralUtils.getDefaultLineSeparator() +
"END";
} else {
try (JDBCSession session = DBUtils.openMetaSession(monitor, getDataSource(), "Read procedure declaration")) {
try (JDBCPreparedStatement dbStat = session.prepareStatement("SHOW CREATE " + getProcedureType().name() + " " + getFullyQualifiedName(DBPEvaluationContext.DDL))) {
try (JDBCResultSet dbResult = dbStat.executeQuery()) {
if (dbResult.next()) {
clientBody = JDBCUtils.safeGetString(dbResult, (getProcedureType() == DBSProcedureType.PROCEDURE ? "Create Procedure" : "Create Function"));
if (clientBody == null) {
clientBody = "";
} else {
clientBody = normalizeCreateStatement(clientBody);
}
} else {
clientBody = "";
}
}
}
} catch (SQLException e) {
clientBody = e.getMessage();
throw new DBException(e, getDataSource());
}
}
/*
StringBuilder cb = new StringBuilder(getBody().length() + 100);
cb.append("CREATE ").append(procedureType).append(' ').append(getFullyQualifiedName()).append(" (");
int colIndex = 0;
for (MySQLProcedureParameter column : CommonUtils.safeCollection(getParameters(monitor))) {
if (column.getParameterKind() == DBSProcedureParameterKind.RETURN) {
continue;
}
if (colIndex > 0) {
cb.append(", ");
}
if (getProcedureType() == DBSProcedureType.PROCEDURE) {
cb.append(column.getParameterKind()).append(' ');
}
cb.append(column.getName()).append(' ');
appendParameterType(cb, column);
colIndex++;
}
cb.append(")").append(GeneralUtils.getDefaultLineSeparator());
for (MySQLProcedureParameter column : CommonUtils.safeCollection(getParameters(monitor))) {
if (column.getParameterKind() == DBSProcedureParameterKind.RETURN) {
cb.append("RETURNS ");
appendParameterType(cb, column);
cb.append(GeneralUtils.getDefaultLineSeparator());
}
}
if (deterministic) {
cb.append("DETERMINISTIC").append(GeneralUtils.getDefaultLineSeparator());
}
cb.append(getBody());
clientBody = cb.toString();
*/
}
return clientBody;
}
private String normalizeCreateStatement(String createDDL) {
String procType = getProcedureType().name();
int divPos = createDDL.indexOf(procType + " `");
if (divPos != -1) {
return createDDL.substring(0, divPos) + procType +
" `" + getContainer().getName() + "`." +
createDDL.substring(divPos + procType.length() + 1);
}
return createDDL;
}
@Property(editable = true, updatable = true, order = 3)
public boolean isDeterministic()
{
return deterministic;
}
public void setDeterministic(boolean deterministic)
{
this.deterministic = deterministic;
}
private static void appendParameterType(StringBuilder cb, MySQLProcedureParameter column)
{
cb.append(column.getTypeName());
if (column.getDataKind() == DBPDataKind.STRING && column.getMaxLength() > 0) {
cb.append('(').append(column.getMaxLength()).append(')');
}
}
public String getDeclaration()
{
return clientBody;
}
public void setDeclaration(String clientBody)
{
this.clientBody = clientBody;
}
//@Property(name = "Client Charset", order = 4)
public String getCharset()
{
return charset;
}
@Override
public Collection<MySQLProcedureParameter> getParameters(DBRProgressMonitor monitor)
throws DBException
{
return getContainer().proceduresCache.getChildren(monitor, getContainer(), this);
}
@NotNull
@Override
public String getFullyQualifiedName(DBPEvaluationContext context)
{
return DBUtils.getFullQualifiedName(getDataSource(),
getContainer(),
this);
}
@Override
@Property(hidden = true, editable = true, updatable = true, order = -1)
public String getObjectDefinitionText(DBRProgressMonitor monitor) throws DBException
{
return getDeclaration(monitor);
}
@Override
public void setObjectDefinitionText(String sourceText) throws DBException
{
setDeclaration(sourceText);
}
@Override
public DBSObject refreshObject(@NotNull DBRProgressMonitor monitor) throws DBException {
return getContainer().proceduresCache.refreshObject(monitor, getContainer(), this);
}
}