📄 convert.java
字号:
/******************************************************************************
* The contents of this file are subject to the Compiere License Version 1.1
* ("License"); You may not use this file except in compliance with the License
* You may obtain a copy of the License at http://www.compiere.org/license.html
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
* The Original Code is Compiere ERP & CRM Smart Business Solution. The Initial
* Developer of the Original Code is Jorg Janke. Portions created by Jorg Janke
* are Copyright (C) 1999-2005 Jorg Janke.
* All parts are Copyright (C) 1999-2005 ComPiere, Inc. All Rights Reserved.
* Contributor(s): ______________________________________.
*****************************************************************************/
package org.compiere.dbPort;
import java.sql.*;
import java.util.*;
import java.util.logging.*;
import java.util.regex.*;
import org.compiere.db.*;
import org.compiere.util.*;
/**
* Convert SQL to Target DB
*
* @author Jorg Janke, Victor Perez
* @version $Id: Convert.java,v 1.24 2005/09/16 03:54:02 jjanke Exp $
*/
public class Convert
{
/**
* Cosntructor
* @param type Database.DB_
*/
public Convert (String type)
{
if (Database.DB_ORACLE.equals(type))
m_isOracle = true;
else if (Database.DB_SYBASE.equals(type))
m_map = ConvertMap.getSybaseMap();
else if (Database.DB_POSTGRESQL.equals(type))
m_map = ConvertMap.getPostgeSQLMap();
else
throw new UnsupportedOperationException ("Unsupported database: " + type);
} // Convert
/** RegEx: insensitive and dot to include line end characters */
public static final int REGEX_FLAGS = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
/** Is Oracle */
private boolean m_isOracle = false;
/** Used Resorce Bundle */
private TreeMap m_map;
/** Statement used */
private Statement m_stmt = null;
/** Last Conversion Error */
private String m_conversionError = null;
/** Last Execution Error */
private Exception m_exception = null;
/** Verbose Messages */
private boolean m_verbose = true;
/** Logger */
private static CLogger log = CLogger.getCLogger (Convert.class);
/**
* Set Verbose
* @param verbose
*/
public void setVerbose (boolean verbose)
{
m_verbose = verbose;
} // setVerbose
/**
* Is Oracle DB
* @return true if connection is Oracle DB
*/
public boolean isOracle()
{
return m_isOracle;
} // isOracle
/**************************************************************************
* Execute SQL Statement (stops at first error).
* If an error occured hadError() returns true.
* You can get details via getConversionError() or getException()
* @param sqlStatements
* @return true if success
* @throws IllegalStateException if no connection
*/
public boolean execute (String sqlStatements, Connection conn)
{
if (conn == null)
throw new IllegalStateException ("Require connection");
//
String[] sql = convert (sqlStatements);
m_exception = null;
if (m_conversionError != null || sql == null)
return false;
boolean ok = true;
int i = 0;
String statement = null;
try
{
if (m_stmt == null)
m_stmt = conn.createStatement();
//
for (i = 0; ok && i < sql.length; i++)
{
statement = sql[i];
if (statement.length() == 0)
{
if (m_verbose)
log.finer("Skipping empty (" + i + ")");
}
else
{
if (m_verbose)
log.info("Executing (" + i + ") <<" + statement + ">>");
else
log.info("Executing " + i);
try
{
m_stmt.clearWarnings();
int no = m_stmt.executeUpdate(statement);
SQLWarning warn = m_stmt.getWarnings();
if (warn != null)
{
if (m_verbose)
log.info("- " + warn);
else
{
log.info("Executing (" + i + ") <<" + statement + ">>");
log.info("- " + warn);
}
}
if (m_verbose)
log.fine("- ok " + no);
}
catch (SQLException ex)
{
// Ignore Drop Errors
if (!statement.startsWith("DROP "))
{
ok = false;
m_exception = ex;
}
if (!m_verbose)
log.info("Executing (" + i + ") <<" + statement + ">>");
log.info("Error executing " + i + "/" + sql.length + " = " + ex);
}
}
} // for all statements
}
catch (SQLException e)
{
m_exception = e;
if (!m_verbose)
log.info("Executing (" + i + ") <<" + statement + ">>");
log.info("Error executing " + i + "/" + sql.length + " = " + e);
return false;
}
return ok;
} // execute
/**
* Return last execution exception
* @return execution exception
*/
public Exception getException()
{
return m_exception;
} // getException
/**
* Returns true if a conversion or execution error had occured.
* Get more details via getConversionError() or getException()
* @return true if error had occured
*/
public boolean hasError()
{
return (m_exception != null) | (m_conversionError != null);
} // hasError
/**
* Convert SQL Statement (stops at first error).
* Statements are delimited by /
* If an error occured hadError() returns true.
* You can get details via getConversionError()
* @param sqlStatements
* @return converted statement as a string
*/
public String convertAll (String sqlStatements)
{
String[] sql = convert (sqlStatements);
StringBuffer sb = new StringBuffer (sqlStatements.length() + 10);
for (int i = 0; i < sql.length; i++)
{
// line.separator
sb.append(sql[i]).append("\n/\n");
if (m_verbose)
log.info("Statement " + i + ": " + sql[i]);
}
return sb.toString();
} // convertAll
/**
* Convert SQL Statement (stops at first error).
* If an error occured hadError() returns true.
* You can get details via getConversionError()
* @param sqlStatements
* @return Array of converted Statements
*/
public String[] convert (String sqlStatements)
{
m_conversionError = null;
if (sqlStatements == null || sqlStatements.length() == 0)
{
m_conversionError = "SQL_Statement is null or has zero length";
log.info(m_conversionError);
return null;
}
//
return convertIt (sqlStatements);
} // convert
/**
* Return last conversion error or null.
* @return lst conversion error
*/
public String getConversionError()
{
return m_conversionError;
} // getConversionError
/**************************************************************************
* Conversion routine (stops at first error).
* <pre>
* - mask / in Strings
* - break into single statement
* - unmask statements
* - for each statement: convertStatement
* - remove comments
* - process FUNCTION/TRIGGER/PROCEDURE
* - process Statement: convertSimpleStatement
* - based on ConvertMap
* - convertComplexStatement
* - decode, sequence, exception
* </pre>
* @param sqlStatements
* @return array of converted statements
*/
private String[] convertIt (String sqlStatements)
{
// Need to mask / in SQL Strings !
final char MASK = '\u001F'; // Unit Separator
StringBuffer masked = new StringBuffer(sqlStatements.length());
Matcher m = Pattern.compile("'[^']+'", Pattern.DOTALL).matcher(sqlStatements);
while (m.find())
{
String group = m.group(); // SQL string
if (group.indexOf("/") != -1) // / in string
group = group.replace('/', MASK);
if (group.indexOf('$') != -1) // Group character needs to be escaped
group = Util.replace(group, "$", "\\$");
m.appendReplacement(masked, group);
}
m.appendTail(masked);
String tempResult = masked.toString();
/** @todo Need to mask / in comments */
// Statements ending with /
String[] sql = tempResult.split("\\s/\\s"); // ("(;\\s)|(\\s/\\s)");
ArrayList<String> result = new ArrayList<String> (sql.length);
// process statements
for (int i = 0; i < sql.length; i++)
{
String statement = sql[i];
if (statement.indexOf(MASK) != -1)
statement = statement.replace(MASK, '/');
result.addAll(convertStatement(statement)); // may return more than one target statement
}
// convert to array
sql = new String[result.size()];
result.toArray(sql);
return sql;
} // convertIt
/**
* Convert single Statements.
* - remove comments
* - process FUNCTION/TRIGGER/PROCEDURE
* - process Statement
* @param sqlStatement
* @return converted statement
*/
private ArrayList<String> convertStatement (String sqlStatement)
{
ArrayList<String> result = new ArrayList<String>();
if (m_isOracle)
{
result.add(sqlStatement);
return result;
}
// remove comments
String statement = removeComments (sqlStatement);
// log.info("------------------------------------------------------------");
// log.info(statement);
// log.info("------------------->");
String cmpString = statement.toUpperCase();
boolean isCreate = cmpString.startsWith("CREATE ");
// Process
if (isCreate && cmpString.indexOf(" FUNCTION ") != -1)
result.addAll(convertFunction(statement));
else if (isCreate && cmpString.indexOf(" TRIGGER ") != -1)
result.addAll(convertTrigger(statement));
else if (isCreate && cmpString.indexOf(" PROCEDURE ") != -1)
result.addAll(convertProcedure(statement));
else if (isCreate && cmpString.indexOf(" VIEW ") != -1)
result.addAll(convertView(statement));
// Simple Statement
else
result.add(converSimpleStatement(statement));
//
// log.info("<-------------------");
// for (int i = 0; i < result.size(); i++)
// log.info(result.get(i));
// log.info("------------------------------------------------------------");
return result;
} // convertStatement
/**
* Convert simple SQL Statement.
* Based on ConvertMap
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -