View Javadoc
1 package net.sourceforge.backpedal.impl.core; 2 3 import net.mikehogan.veggie.exceptions.VeggieSystemException; 4 import net.mikehogan.veggie.sql.Sql; 5 import net.sourceforge.backpedal.api.core.BackpedalFactory; 6 import net.sourceforge.backpedal.api.core.BindVariableResolver; 7 import net.sourceforge.backpedal.api.core.ParsedStatement; 8 import net.sourceforge.backpedal.api.db.BindVariable; 9 import net.sourceforge.backpedal.api.db.BindVariableSet; 10 import net.sourceforge.backpedal.api.db.ColumnMetadata; 11 import net.sourceforge.backpedal.api.db.TableMetadata; 12 import net.sourceforge.backpedal.impl.AbstractComponent; 13 import net.sourceforge.backpedal.impl.db.BooleanBindVariable; 14 import net.sourceforge.backpedal.impl.db.CharBindVariable; 15 import net.sourceforge.backpedal.impl.db.DateBindVariable; 16 import net.sourceforge.backpedal.impl.db.IntegerBindVariable; 17 import net.sourceforge.backpedal.impl.db.StringBindVariable; 18 import net.sourceforge.backpedal.impl.db.TimestampBindVariable; 19 20 import java.sql.Connection; 21 import java.sql.Date; 22 import java.sql.PreparedStatement; 23 import java.sql.ResultSet; 24 import java.sql.SQLException; 25 import java.sql.Timestamp; 26 import java.util.ArrayList; 27 import java.util.Collection; 28 import java.util.HashMap; 29 import java.util.Iterator; 30 import java.util.List; 31 import java.util.Map; 32 33 public class BindVariableResolverImpl extends AbstractComponent implements BindVariableResolver { 34 private static final Map bindVariablePrototypeInstances = new HashMap(); 35 private final BackpedalFactory backpedalFactory; 36 37 public BindVariableResolverImpl(BackpedalFactory backpedalFactory) { 38 this.backpedalFactory = backpedalFactory; 39 } 40 41 public Collection getBindVariableSetsForMutatedRows(ParsedStatement parsedStatement, BindVariableSet bindVariableSet, TableMetadata tableMetadata, Connection connection) { 42 final Collection result = new ArrayList(); 43 if ("INSERT".equalsIgnoreCase(parsedStatement.getSqlKeyword())) { 44 result.add(bindVariableSet); 45 } else { 46 handleUpdateOrDelete(parsedStatement, connection, bindVariableSet, result, tableMetadata); 47 } 48 return result; 49 } 50 51 private void handleUpdateOrDelete(ParsedStatement parsedStatement, Connection connection, BindVariableSet bindVariableSet, final Collection result, TableMetadata tableMetadata) { 52 PreparedStatement statement = null; 53 ResultSet resultSet = null; 54 try { 55 final String affectedRowsSql = getSelectForAffectedRows(parsedStatement); 56 statement = connection.prepareStatement(affectedRowsSql); 57 /*** 58 * The WHERE clause in affectedRowsSql should be the same as the WHERE clause 59 * in parsedStatement. But, bindVariableSet can contain bind variables that 60 * are used outside the WHERE clause (consider "UPDATE X SET Y=? WHERE Z=?"). 61 * So, we'll figure out how many bind variables to skip in bindVariableSet to 62 * get us to the bind variables for the WHERE clause. Its 63 * bindVariableSet.size() - parsedStatement.getWhereColumnNames.length 64 */ 65 final List bindVariables = new ArrayList(); 66 for (Iterator i = bindVariableSet.iterator(); i.hasNext();) { 67 bindVariables.add(i.next()); 68 } 69 final String[] whereColumnNames = parsedStatement.getWhereColumnNames(); 70 int indexForWhereBindVariables = bindVariableSet.size() - whereColumnNames.length; 71 for (int i = 0; i < whereColumnNames.length; i++) { 72 final BindVariable b = (BindVariable) bindVariables.get(i + indexForWhereBindVariables); 73 log().debug("Setting bindvariable " + b + " into statement " + statement); 74 b.setInto(statement); 75 76 } 77 resultSet = statement.executeQuery(); 78 79 while (resultSet.next()) { 80 result.add(createBindVariableSet(resultSet, tableMetadata, parsedStatement)); 81 } 82 } catch (SQLException e) { 83 throw new VeggieSystemException("Exception trying to find backpedal bind variables", e); 84 } finally { 85 Sql.close(resultSet); 86 Sql.close(statement); 87 } 88 } 89 90 /*** 91 * Return a bind variable set for all the columns in a table, assuming 92 * resultSet contains a row from that table. 93 */ 94 private BindVariableSet createBindVariableSet(final ResultSet resultSet, final TableMetadata tableMetadata, final ParsedStatement parsedStatement) { 95 final BindVariableSet bindVariableSet = backpedalFactory.createBindVariableSet(); 96 int index = 1; 97 if (parsedStatement.getChangedColumnNames().length != 0) { 98 //We've got an INSERT or UPDATE with a specific set of changed cols followed by an optional WHERE clause with cols. 99 //So, first do the changed cols 100 index = createBindVariablesForColumns(parsedStatement.getChangedColumnNames(), bindVariableSet, index, tableMetadata, resultSet); 101 //And now do the where columns 102 createBindVariablesForColumns(parsedStatement.getWhereColumnNames(), bindVariableSet, index, tableMetadata, resultSet); 103 } else { 104 //This is a DELETE, so we need to store all cols in table for the affected row. 105 for (Iterator i = tableMetadata.getColumns(); i.hasNext();) { 106 final ColumnMetadata columnMetadata = (ColumnMetadata) i.next(); 107 bindVariableSet.add(createBindVariable(columnMetadata, index, resultSet)); 108 index++; 109 } 110 } 111 return bindVariableSet; 112 } 113 114 private int createBindVariablesForColumns(String[] columnNames, final BindVariableSet bindVariableSet, int index, final TableMetadata tableMetadata, final ResultSet resultSet) { 115 for (int i = 0; i < columnNames.length; i++) { 116 final ColumnMetadata columnMetadata = tableMetadata.getColumn(columnNames[i]); 117 bindVariableSet.add(createBindVariable(columnMetadata, index, resultSet)); 118 index++; 119 } 120 return index; 121 } 122 123 private BindVariable createBindVariable(final ColumnMetadata columnMetadata, int index, final ResultSet resultSet) { 124 BindVariable bindVariable; 125 log().debug("index = " + index + ", column name = " + columnMetadata.getName()); 126 try { 127 final BindVariable prototype = (BindVariable) bindVariablePrototypeInstances.get(new Integer(columnMetadata.getSqlType())); 128 if (prototype != null) { 129 bindVariable = (BindVariable) prototype.clone(); 130 bindVariable.setIndex(index); 131 bindVariable.setValue(resultSet.getObject(index)); 132 bindVariable.setColumnName(columnMetadata.getName()); 133 } else { 134 throw new VeggieSystemException("No prototype instance registered for SQL type " + columnMetadata.getSqlType()); 135 } 136 } catch (VeggieSystemException e) { 137 throw e; 138 } catch (Exception e) { 139 throw new VeggieSystemException("Exception trying to create a bind variable", e); 140 } 141 return bindVariable; 142 } 143 144 private String getSelectForAffectedRows(ParsedStatement parsedStatement) { 145 final StringBuffer buffer = new StringBuffer("SELECT * FROM "); 146 buffer.append(parsedStatement.getTableName()); 147 buffer.append(" WHERE "); 148 final String[] columnNames = parsedStatement.getWhereColumnNames(); 149 appendWhereClause(columnNames, buffer); 150 return buffer.toString(); 151 } 152 153 /*** 154 * Append the body of a WHERE clause to buffer using columnNames. 155 */ 156 private void appendWhereClause(final String[] columnNames, final StringBuffer buffer) { 157 for (int i = 0; i < columnNames.length; i++) { 158 if (i > 0) { 159 buffer.append(" AND "); 160 } 161 buffer.append(columnNames[i]); 162 buffer.append(" = ?"); 163 } 164 } 165 166 167 static { 168 addPrototypeInstance(new StringBindVariable(1, "who cares","who cares")); 169 addPrototypeInstance(new IntegerBindVariable(1, 1,"who cares")); 170 addPrototypeInstance(new BooleanBindVariable(1, true,"who cares")); 171 addPrototypeInstance(new DateBindVariable(1, new Date(1),"who cares")); 172 addPrototypeInstance(new TimestampBindVariable(1, new Timestamp(1),"who cares")); 173 addPrototypeInstance(new CharBindVariable(1, "who cares","who cares")); 174 } 175 176 private static void addPrototypeInstance(BindVariable bindVariable) { 177 bindVariablePrototypeInstances.put(new Integer(bindVariable.getSqlType()), bindVariable); 178 } 179 180 }

This page was automatically generated by Maven