/*
* NOTE: This copyright does *not* cover user programs that use HQ
* program services by normal system calls through the application
* program interfaces provided as part of the Hyperic Plug-in Development
* Kit or the Hyperic Client Development Kit - this is merely considered
* normal use of the program, and does *not* fall under the heading of
* "derived work".
*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of HQ.
*
* HQ is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program is distributed
* in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.tools.db;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.apache.oro.text.perl.Perl5Util;
abstract class DataSet
{
private DBSetup m_parent;
private String m_strTableName;
private static Perl5Util regexp = new Perl5Util();
protected DataSet(String tableName, DBSetup dbsetup)
{
this.m_strTableName = tableName;
this.m_parent = dbsetup;
}
protected int create() throws SQLException
{
PreparedStatement stmt = null;
int rowcnt = 0;
try {
for(;this.next();rowcnt ++)
{
// We only prepare the statement on the first row. We do this
// inside the loop because determining the number of rows may
// not be possible before iterating.
if(rowcnt == 0)
{
String strCmd = this.getCreateCommand();
stmt = (PreparedStatement)m_parent.doSQL(strCmd, true);
}
// For all rows we set the data in the prepared statement and execute it.
if(this.setSqlData(stmt))
{
stmt.executeUpdate();
this.m_parent.getConn().commit();
}
}
} catch (SQLException e) {
try { this.m_parent.getConn().rollback(); }
catch (Exception e2) {
// Log this?
}
throw e;
} finally {
if (stmt != null) stmt.close();
}
return rowcnt; // The number of rows created.
}
protected String getCreateCommand() throws SQLException
{
int iCols = this.getNumberColumns();
StringBuffer strCmd = new StringBuffer("INSERT INTO ");
strCmd.append(this.getTableName());
strCmd.append(" (");
for(int i = 0;i < iCols;i++)
{
Data data = this.getData(i);
if(i > 0)
strCmd.append(',');
strCmd.append(data.getColumnName());
}
strCmd.append(") VALUES (");
for(int i = 0;i < iCols;i ++)
{
if(i > 0)
strCmd.append(',');
strCmd.append('?');
}
strCmd.append(')');
return strCmd.toString();
}
protected String getUpdateCommand(String strCol) throws SQLException
{
int iCols = this.getNumberColumns();
StringBuffer strCmd = new StringBuffer("UPDATE ");
strCmd.append(this.getTableName());
strCmd.append(" SET ");
for(int i = 0;i < iCols;i++)
{
Data data = this.getData(i);
String colName = data.getColumnName();
if (!colName.equals("CTIME") && !colName.equals("ENTRY_TIME")) {
if(i > 0)
strCmd.append(',');
strCmd.append(colName);
strCmd.append(" = ?");
}
}
strCmd.append(" WHERE ").append(strCol).append(" = ?");
return strCmd.toString();
}
protected boolean setSqlData(PreparedStatement stmt) throws SQLException
{
Statement stmtQuery = null;
boolean bResult = true;
ResultSet results = null;
String strSelect;
String cid = "0";
int iCols = this.getNumberColumns();
// This may seem kludgy, but beats the alternative
for(int i = 0; i < iCols; i++) {
Data data = this.getData(i);
//////////////////////////////////////////////////////////
// Update the row if it already exists
if(data.getColumnName().equalsIgnoreCase("CID") ||
data.getColumnName().equalsIgnoreCase("ID"))
{
String strCol = data.getColumnName();
String strValue = data.getValue();
strSelect = "SELECT " + strCol + " FROM " + this.getTableName() +
" WHERE " + strCol +" = " + strValue;
try {
stmtQuery = m_parent.getConn().createStatement();
results = stmtQuery.executeQuery(strSelect);
if(results.next()) { // If the row exists already, we update
bResult = false; // Return false in the end
cid = strValue;
String strCmd = this.getUpdateCommand(strCol);
// before we overwrite stmt, close a previous statement
// if there was one
if (stmt != null) stmt.close();
stmt = (PreparedStatement)m_parent.doSQL(strCmd, true);
}
} finally {
if (results != null) {
try { results.close(); } catch (SQLException e2) {}
}
if (stmtQuery != null) {
try { stmtQuery.close(); } catch (SQLException e2) {}
}
}
break;
}
}
for(int i = 0;i < iCols;i++)
{
Data data = this.getData(i);
String colName = data.getColumnName();
// We don't want to update CTIME or ENTRY_TIME as they represent creation times...
if (!bResult && (colName.equals("CTIME") || colName.equals("ENTRY_TIME"))) {
continue;
}
String strValue = data.getValue();
//////////////////////////////////////////////////////////
// Look for data references and translate them
if((strValue.length() > 1) &&
strValue.charAt(0) == '%' && strValue.charAt(1) != '%' &&
regexp.match("m/^%[A-Z]+\\w+\\.[A-Z]+\\w+:\\d+$/i", strValue))
{
int iColDelim = strValue.indexOf('.');
int iDataDelim = strValue.indexOf(':');
String strTab = strValue.substring(1, iColDelim);
String strCol = strValue.substring(iColDelim + 1,
iDataDelim);
String strSID = strValue.substring(iDataDelim + 1);
strSelect = "SELECT " + strCol + " FROM " + strTab +
" WHERE " + strCol + " = " + strSID;
try {
stmtQuery = m_parent.getConn().createStatement();
results = stmtQuery.executeQuery(strSelect);
if(results.next()) {
strValue = results.getString(1);
} else {
strValue = null; // No foreign key
if(m_parent.isQuiet() == false)
System.out.println("Error: Cannot find Foreign Key: \'" + strSelect + '\'');
}
} finally {
if (results != null) {
try { results.close(); } catch (SQLException e2) {}
}
if (stmtQuery != null) {
try { stmtQuery.close(); } catch (SQLException e2) {}
}
}
}
if (strValue != null) {
if (strValue.equals("TRUE")) {
stmt.setBoolean(i + 1, true);
continue;
}
else if (strValue.equals("FALSE")) {
stmt.setBoolean(i + 1, false);
continue;
}
else if (strValue.equals("NOW()")) {
stmt.setLong(i + 1, System.currentTimeMillis());
continue;
}
stmt.setString(i + 1, strValue);
}
else {
// If the strVal is null, means that the foreign key is null
stmt.setNull(i + 1, java.sql.Types.INTEGER);
}
}
// If we don't want to return to caller, then we finish it right here
if (!bResult) {
stmt.setString(iCols + 1, cid);
try {
stmt.executeUpdate();
this.m_parent.getConn().commit();
} catch (SQLException e) {
try { this.m_parent.getConn().rollback(); }
catch (Exception e2) {
// Log this?
}
throw e;
}
}
return bResult;
}
protected int getNumberColumns()
{
return 0;
}
protected String getTableName()
{
return this.m_strTableName;
}
protected abstract Data getData(int columnIndex);
protected abstract boolean next();
}