001: package net.sf.saxon.sql;
002:
003: import net.sf.saxon.expr.Expression;
004: import net.sf.saxon.expr.SimpleExpression;
005: import net.sf.saxon.expr.XPathContext;
006: import net.sf.saxon.instruct.Executable;
007: import net.sf.saxon.om.Axis;
008: import net.sf.saxon.om.AxisIterator;
009: import net.sf.saxon.om.Item;
010: import net.sf.saxon.om.NodeInfo;
011: import net.sf.saxon.style.ExtensionInstruction;
012: import net.sf.saxon.trans.XPathException;
013: import net.sf.saxon.value.AtomicValue;
014: import net.sf.saxon.value.ObjectValue;
015:
016: import java.sql.Connection;
017: import java.sql.PreparedStatement;
018: import java.sql.SQLException;
019: import java.util.ArrayList;
020: import java.util.List;
021:
022: /**
023: * An sql:insert element in the stylesheet.
024: */
025:
026: public class SQLInsert extends ExtensionInstruction {
027:
028: Expression connection;
029: String table;
030:
031: public void prepareAttributes() throws XPathException {
032:
033: table = getAttributeList().getValue("", "table");
034: if (table == null) {
035: reportAbsence("table");
036: }
037: String connectAtt = getAttributeList().getValue("",
038: "connection");
039: if (connectAtt == null) {
040: reportAbsence("connection");
041: } else {
042: connection = makeExpression(connectAtt);
043: }
044: }
045:
046: public void validate() throws XPathException {
047: super .validate();
048: connection = typeCheck("connection", connection);
049: }
050:
051: public Expression compile(Executable exec) throws XPathException {
052:
053: // Collect names of columns to be added
054:
055: StringBuffer statement = new StringBuffer(120);
056: statement.append("INSERT INTO " + table + " (");
057:
058: AxisIterator kids = iterateAxis(Axis.CHILD);
059: NodeInfo child;
060: int cols = 0;
061: while (true) {
062: child = (NodeInfo) kids.next();
063: if (child == null) {
064: break;
065: }
066: if (child instanceof SQLColumn) {
067: if (cols++ > 0)
068: statement.append(',');
069: String colname = ((SQLColumn) child).getColumnName();
070: statement.append(colname);
071: }
072: }
073: statement.append(") VALUES (");
074:
075: // Add "?" marks for the variable parameters
076:
077: for (int i = 0; i < cols; i++) {
078: if (i != 0) {
079: statement.append(',');
080: }
081: statement.append('?');
082: }
083: ;
084:
085: statement.append(')');
086:
087: return new InsertInstruction(connection, statement.toString(),
088: getColumnInstructions(exec));
089: }
090:
091: public List getColumnInstructions(Executable exec)
092: throws XPathException {
093: List list = new ArrayList(10);
094:
095: AxisIterator kids = iterateAxis(Axis.CHILD);
096: NodeInfo child;
097: while (true) {
098: child = (NodeInfo) kids.next();
099: if (child == null) {
100: break;
101: }
102: if (child instanceof SQLColumn) {
103: list.add(((SQLColumn) child).compile(exec));
104: }
105: }
106:
107: return list;
108: }
109:
110: private static class InsertInstruction extends SimpleExpression {
111:
112: public static final int CONNECTION = 0;
113: public static final int FIRST_COLUMN = 1;
114: String statement;
115:
116: public InsertInstruction(Expression connection,
117: String statement, List columnInstructions) {
118: Expression[] sub = new Expression[columnInstructions.size() + 1];
119: sub[CONNECTION] = connection;
120: for (int i = 0; i < columnInstructions.size(); i++) {
121: sub[i + FIRST_COLUMN] = (Expression) columnInstructions
122: .get(i);
123: }
124: this .statement = statement;
125: setArguments(sub);
126: }
127:
128: /**
129: * A subclass must provide one of the methods evaluateItem(), iterate(), or process().
130: * This method indicates which of the three is provided.
131: */
132:
133: public int getImplementationMethod() {
134: return Expression.EVALUATE_METHOD;
135: }
136:
137: public String getExpressionType() {
138: return "sql:insert";
139: }
140:
141: public Item evaluateItem(XPathContext context)
142: throws XPathException {
143:
144: // Prepare the SQL statement (only do this once)
145:
146: Item conn = arguments[CONNECTION].evaluateItem(context);
147: if (!(conn instanceof ObjectValue && ((ObjectValue) conn)
148: .getObject() instanceof Connection)) {
149: dynamicError(
150: "Value of connection expression is not a JDBC Connection",
151: context);
152: }
153: Connection connection = (Connection) ((ObjectValue) conn)
154: .getObject();
155: PreparedStatement ps = null;
156:
157: try {
158: ps = connection.prepareStatement(statement);
159:
160: // Add the actual column values to be inserted
161:
162: int i = 1;
163: for (int c = FIRST_COLUMN; c < arguments.length; c++) {
164: AtomicValue v = (AtomicValue) ((SQLColumn.ColumnInstruction) arguments[c])
165: .getSelectValue(context);
166:
167: // TODO: the values are all strings. There is no way of adding to a numeric column
168: String val = v.getStringValue();
169:
170: // another hack: setString() doesn't seem to like single-character string values
171: if (val.length() == 1)
172: val += " ";
173: //System.err.println("Set statement parameter " + i + " to " + val);
174: ps.setObject(i++, val);
175:
176: }
177:
178: ps.executeUpdate();
179: if (!connection.getAutoCommit()) {
180: connection.commit();
181: }
182:
183: } catch (SQLException ex) {
184: dynamicError("(SQL INSERT) " + ex.getMessage(), context);
185: } finally {
186: if (ps != null) {
187: try {
188: ps.close();
189: } catch (SQLException ignore) {
190: }
191: }
192: }
193:
194: return null;
195: }
196:
197: }
198:
199: }
200:
201: //
202: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
203: // you may not use this file except in compliance with the License. You may obtain a copy of the
204: // License at http://www.mozilla.org/MPL/
205: //
206: // Software distributed under the License is distributed on an "AS IS" basis,
207: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
208: // See the License for the specific language governing rights and limitations under the License.
209: //
210: // The Original Code is: all this file.
211: //
212: // The Initial Developer of the Original Code is Michael H. Kay.
213: //
214: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
215: //
216: // Contributor(s): none.
217: //
|