001: /*
002: * Jython Database Specification API 2.0
003: *
004: * $Id: PyStatement.java 2542 2005-06-20 17:12:15Z fwierzbicki $
005: *
006: * Copyright (c) 2001 brian zimmer <bzimmer@ziclix.com>
007: *
008: */
009: package com.ziclix.python.sql;
010:
011: import org.python.core.Py;
012: import org.python.core.PyClass;
013: import org.python.core.PyException;
014: import org.python.core.PyInteger;
015: import org.python.core.PyList;
016: import org.python.core.PyObject;
017: import org.python.core.PyString;
018:
019: import java.sql.CallableStatement;
020: import java.sql.PreparedStatement;
021: import java.sql.SQLException;
022: import java.sql.Statement;
023:
024: /**
025: * Class PyStatement
026: *
027: * @author brian zimmer
028: * @version $Revision: 2542 $
029: */
030: public class PyStatement extends PyObject {
031:
032: /**
033: * Field STATEMENT_STATIC
034: */
035: public static final int STATEMENT_STATIC = 2;
036:
037: /**
038: * Field STATEMENT_PREPARED
039: */
040: public static final int STATEMENT_PREPARED = 4;
041:
042: /**
043: * Field STATEMENT_CALLABLE
044: */
045: public static final int STATEMENT_CALLABLE = 8;
046:
047: /**
048: * Field style
049: */
050: private int style;
051:
052: /**
053: * Field sql
054: */
055: private Object sql;
056:
057: /**
058: * Field closed
059: */
060: private boolean closed;
061:
062: /**
063: * Field statement
064: */
065: Statement statement;
066:
067: /**
068: * Constructor PyStatement
069: *
070: * @param statement
071: * @param sql
072: * @param style
073: */
074: public PyStatement(Statement statement, Object sql, int style) {
075:
076: this .sql = sql;
077: this .style = style;
078: this .closed = false;
079: this .statement = statement;
080: }
081:
082: /**
083: * Constructor PyStatement
084: *
085: * @param statement
086: * @param procedure
087: */
088: public PyStatement(Statement statement, Procedure procedure) {
089: this (statement, procedure, STATEMENT_CALLABLE);
090: }
091:
092: /**
093: * Field __class__
094: */
095: public static PyClass __class__;
096:
097: /**
098: * Method getPyClass
099: *
100: * @return PyClass
101: */
102: protected PyClass getPyClass() {
103: return __class__;
104: }
105:
106: /**
107: * Field __methods__
108: */
109: protected static PyList __methods__;
110:
111: /**
112: * Field __members__
113: */
114: protected static PyList __members__;
115:
116: static {
117: PyObject[] m = new PyObject[1];
118:
119: m[0] = new PyString("close");
120: __methods__ = new PyList(m);
121: m = new PyObject[3];
122: m[0] = new PyString("style");
123: m[1] = new PyString("closed");
124: m[2] = new PyString("__statement__");
125: __members__ = new PyList(m);
126: }
127:
128: /**
129: * Method __str__
130: *
131: * @return PyString
132: */
133: public PyString __str__() {
134:
135: if (sql instanceof String) {
136: return Py.newString((String) sql);
137: } else if (sql instanceof Procedure) {
138: try {
139: return Py.newString(((Procedure) sql).toSql());
140: } catch (SQLException e) {
141: throw zxJDBC.makeException(e);
142: }
143: }
144:
145: return super .__str__();
146: }
147:
148: /**
149: * Method __repr__
150: *
151: * @return PyString
152: */
153: public PyString __repr__() {
154:
155: // care is taken not to display a rounded second value
156: StringBuffer buf = new StringBuffer("<PyStatement object for [");
157:
158: buf.append(__str__().toString());
159: buf.append("] at ").append(Py.id(this )).append(">");
160:
161: return Py.newString(buf.toString());
162: }
163:
164: /**
165: * Method toString
166: *
167: * @return String
168: */
169: public String toString() {
170: return __repr__().toString();
171: }
172:
173: /**
174: * Gets the value of the attribute name.
175: *
176: * @param name
177: * @return the attribute for the given name
178: */
179: public PyObject __findattr__(String name) {
180:
181: if ("style".equals(name)) {
182: return Py.newInteger(style);
183: } else if ("closed".equals(name)) {
184: return Py.newBoolean(closed);
185: } else if ("__statement__".equals(name)) {
186: return Py.java2py(statement);
187: } else if ("__methods__".equals(name)) {
188: return __methods__;
189: } else if ("__members__".equals(name)) {
190: return __members__;
191: }
192:
193: return super .__findattr__(name);
194: }
195:
196: /**
197: * Initializes the object's namespace.
198: *
199: * @param dict
200: */
201: static public void classDictInit(PyObject dict) {
202:
203: dict.__setitem__("__version__", Py.newString(
204: "$Revision: 2542 $").__getslice__(Py.newInteger(11),
205: Py.newInteger(-2), null));
206:
207: // hide from python
208: dict.__setitem__("classDictInit", null);
209: dict.__setitem__("statement", null);
210: dict.__setitem__("execute", null);
211: dict.__setitem__("prepare", null);
212: dict.__setitem__("STATEMENT_STATIC", null);
213: dict.__setitem__("STATEMENT_PREPARED", null);
214: dict.__setitem__("STATEMENT_CALLABLE", null);
215: }
216:
217: /**
218: * Delete the statement.
219: */
220: public void __del__() {
221: close();
222: }
223:
224: /**
225: * Method execute
226: *
227: * @param cursor
228: * @param params
229: * @param bindings
230: * @throws SQLException
231: */
232: public void execute(PyCursor cursor, PyObject params,
233: PyObject bindings) throws SQLException {
234:
235: if (this .closed) {
236: throw zxJDBC.makeException(zxJDBC.ProgrammingError,
237: "statement is closed");
238: }
239:
240: this .prepare(cursor, params, bindings);
241:
242: Fetch fetch = cursor.fetch;
243:
244: switch (this .style) {
245:
246: case STATEMENT_STATIC:
247: if (this .statement.execute((String) this .sql)) {
248: fetch.add(this .statement.getResultSet());
249: }
250: break;
251:
252: case STATEMENT_PREPARED:
253: final PreparedStatement preparedStatement = (PreparedStatement) this .statement;
254:
255: if (preparedStatement.execute()) {
256: fetch.add(preparedStatement.getResultSet());
257: }
258: break;
259:
260: case STATEMENT_CALLABLE:
261: final CallableStatement callableStatement = (CallableStatement) this .statement;
262:
263: if (callableStatement.execute()) {
264: fetch.add(callableStatement.getResultSet());
265: }
266:
267: fetch.add(callableStatement, (Procedure) sql, params);
268: break;
269:
270: default:
271: throw zxJDBC.makeException(zxJDBC.ProgrammingError, zxJDBC
272: .getString("invalidStyle"));
273: }
274: }
275:
276: /**
277: * Method prepare
278: *
279: * @param cursor
280: * @param params
281: * @param bindings
282: * @throws SQLException
283: */
284: private void prepare(PyCursor cursor, PyObject params,
285: PyObject bindings) throws SQLException {
286:
287: if ((params == Py.None) || (this .style == STATEMENT_STATIC)) {
288: return;
289: }
290:
291: // [3, 4] or (3, 4)
292: final DataHandler datahandler = cursor.datahandler;
293: int columns = 0, column = 0, index = params.__len__();
294: final PreparedStatement preparedStatement = (PreparedStatement) statement;
295: final Procedure procedure = (this .style == STATEMENT_CALLABLE) ? (Procedure) this .sql
296: : null;
297:
298: if (this .style != STATEMENT_CALLABLE) {
299: columns = params.__len__();
300:
301: // clear the statement so all new bindings take affect only if not a callproc
302: // this is because Procedure already registered the OUT parameters and we
303: // don't want to lose those
304: preparedStatement.clearParameters();
305: } else {
306: columns = (procedure.columns == Py.None) ? 0
307: : procedure.columns.__len__();
308: }
309:
310: // count backwards through all the columns
311: while (columns-- > 0) {
312: column = columns + 1;
313:
314: if ((procedure != null) && (!procedure.isInput(column))) {
315: continue;
316: }
317:
318: // working from right to left
319: PyObject param = params.__getitem__(--index);
320:
321: if (bindings != Py.None) {
322: PyObject binding = bindings.__finditem__(Py
323: .newInteger(index));
324:
325: if (binding != null) {
326: try {
327: int bindingValue = ((PyInteger) binding
328: .__int__()).getValue();
329:
330: datahandler.setJDBCObject(preparedStatement,
331: column, param, bindingValue);
332: } catch (PyException e) {
333: throw zxJDBC.makeException(
334: zxJDBC.ProgrammingError, zxJDBC
335: .getString("bindingValue"));
336: }
337:
338: continue;
339: }
340: }
341:
342: datahandler.setJDBCObject(preparedStatement, column, param);
343: }
344:
345: return;
346: }
347:
348: /**
349: * Method close
350: */
351: public void close() {
352:
353: try {
354: this .statement.close();
355: } catch (SQLException e) {
356: throw zxJDBC.makeException(e);
357: } finally {
358: this .closed = true;
359: }
360: }
361: }
|