001: /*
002: * Jython Database Specification API 2.0
003: *
004: * $Id: BCP.java 3248 2007-05-30 05:19:19Z cgroves $
005: *
006: * Copyright (c) 2001 brian zimmer <bzimmer@ziclix.com>
007: *
008: */
009: package com.ziclix.python.sql.util;
010:
011: import org.python.core.ClassDictInit;
012: import org.python.core.Py;
013: import org.python.core.PyBuiltinMethodSet;
014: import org.python.core.PyClass;
015: import org.python.core.PyList;
016: import org.python.core.PyObject;
017: import org.python.core.PyString;
018: import com.ziclix.python.sql.PyConnection;
019: import com.ziclix.python.sql.zxJDBC;
020: import com.ziclix.python.sql.pipe.Pipe;
021: import com.ziclix.python.sql.pipe.db.DBSink;
022: import com.ziclix.python.sql.pipe.db.DBSource;
023:
024: /**
025: * A class to perform efficient Bulk CoPy of database tables.
026: */
027: public class BCP extends PyObject implements ClassDictInit {
028:
029: /**
030: * Field sourceDH, destDH
031: */
032: protected Class sourceDH, destDH;
033:
034: /**
035: * Field batchsize, queuesize
036: */
037: protected int batchsize, queuesize;
038:
039: /**
040: * Field source, destination
041: */
042: protected PyConnection source, destination;
043:
044: /**
045: * The source connection will produce the rows while the destination
046: * connection will consume the rows and coerce as necessary for the
047: * destination database.
048: */
049: public BCP(PyConnection source, PyConnection destination) {
050: this (source, destination, -1);
051: }
052:
053: /**
054: * The source connection will produce the rows while the destination
055: * connection will consume the rows and coerce as necessary for the
056: * destination database.
057: *
058: * @param batchsize used to batch the inserts on the destination
059: */
060: public BCP(PyConnection source, PyConnection destination,
061: int batchsize) {
062:
063: this .source = source;
064: this .destination = destination;
065: this .destDH = null;
066: this .sourceDH = null;
067: this .batchsize = batchsize;
068: this .queuesize = 0;
069: }
070:
071: // __class__ boilerplate -- see PyObject for details
072:
073: /**
074: * Field __class__
075: */
076: public static PyClass __class__;
077:
078: /**
079: * Method getPyClass
080: *
081: * @return PyClass
082: */
083: protected PyClass getPyClass() {
084: return __class__;
085: }
086:
087: /**
088: * Field __methods__
089: */
090: protected static PyList __methods__;
091:
092: /**
093: * Field __members__
094: */
095: protected static PyList __members__;
096:
097: static {
098: PyObject[] m = new PyObject[1];
099:
100: m[0] = new PyString("bcp");
101: __methods__ = new PyList(m);
102: m = new PyObject[6];
103: m[0] = new PyString("source");
104: m[1] = new PyString("destination");
105: m[2] = new PyString("batchsize");
106: m[3] = new PyString("queuesize");
107: m[4] = new PyString("sourceDataHandler");
108: m[5] = new PyString("destinationDataHandler");
109: __members__ = new PyList(m);
110: }
111:
112: /**
113: * String representation of the object.
114: *
115: * @return a string representation of the object.
116: */
117: public String toString() {
118: return "<BCP object instance at " + hashCode() + ">";
119: }
120:
121: /**
122: * Sets the attribute name to value.
123: *
124: * @param name
125: * @param value
126: */
127: public void __setattr__(String name, PyObject value) {
128:
129: if ("destinationDataHandler".equals(name)) {
130: this .destDH = (Class) value.__tojava__(Class.class);
131: } else if ("sourceDataHandler".equals(name)) {
132: this .sourceDH = (Class) value.__tojava__(Class.class);
133: } else if ("batchsize".equals(name)) {
134: this .batchsize = ((Number) value.__tojava__(Number.class))
135: .intValue();
136: } else if ("queuesize".equals(name)) {
137: this .queuesize = ((Number) value.__tojava__(Number.class))
138: .intValue();
139: } else {
140: super .__setattr__(name, value);
141: }
142: }
143:
144: /**
145: * Gets the value of the attribute name.
146: *
147: * @param name
148: * @return the attribute for the given name
149: */
150: public PyObject __findattr__(String name) {
151:
152: if ("destinationDataHandler".equals(name)) {
153: return Py.java2py(this .destDH);
154: } else if ("sourceDataHandler".equals(name)) {
155: return Py.java2py(this .sourceDH);
156: } else if ("batchsize".equals(name)) {
157: return Py.newInteger(this .batchsize);
158: } else if ("queuesize".equals(name)) {
159: return Py.newInteger(this .queuesize);
160: }
161:
162: return super .__findattr__(name);
163: }
164:
165: /**
166: * Initializes the object's namespace.
167: *
168: * @param dict
169: */
170: static public void classDictInit(PyObject dict) {
171:
172: dict.__setitem__("__version__", Py.newString(
173: "$Revision: 3248 $").__getslice__(Py.newInteger(11),
174: Py.newInteger(-2), null));
175: dict.__setitem__("bcp", new BCPFunc("bcp", 0, 1, 2, zxJDBC
176: .getString("bcp")));
177: dict.__setitem__("batchsize", Py.newString(zxJDBC
178: .getString("batchsize")));
179: dict.__setitem__("queuesize", Py.newString(zxJDBC
180: .getString("queuesize")));
181:
182: // hide from python
183: dict.__setitem__("classDictInit", null);
184: dict.__setitem__("toString", null);
185: dict.__setitem__("PyClass", null);
186: dict.__setitem__("getPyClass", null);
187: dict.__setitem__("sourceDH", null);
188: dict.__setitem__("destDH", null);
189: }
190:
191: /**
192: * Bulkcopy data from one database to another.
193: *
194: * @param fromTable the table in question on the source database
195: * @param where an optional where clause, defaults to '(1=1)' if null
196: * @param params optional params to substituted in the where clause
197: * @param include the columns to be queried from the source, '*' if None
198: * @param exclude the columns to be excluded from insertion on the destination, all if None
199: * @param toTable if non-null, the table in the destination db, otherwise the same table name as the source
200: * @param bindings the optional bindings for the destination, this allows morphing of types during the copy
201: * @return the count of the total number of rows bulk copied, -1 if the query returned no rows
202: */
203: protected PyObject bcp(String fromTable, String where,
204: PyObject params, PyObject include, PyObject exclude,
205: String toTable, PyObject bindings) {
206:
207: Pipe pipe = new Pipe();
208: String _toTable = (toTable == null) ? fromTable : toTable;
209: DBSource source = new DBSource(this .source, sourceDH,
210: fromTable, where, include, params);
211: DBSink sink = new DBSink(this .destination, destDH, _toTable,
212: exclude, bindings, this .batchsize);
213:
214: return pipe.pipe(source, sink).__sub__(Py.newInteger(1));
215: }
216: }
217:
218: /**
219: * @author last modified by $Author: cgroves $
220: * @version $Revision: 3248 $
221: * @date last modified on $Date: 2007-05-29 22:19:19 -0700 (Tue, 29 May 2007) $
222: * @copyright 2001 brian zimmer
223: */
224: class BCPFunc extends PyBuiltinMethodSet {
225:
226: BCPFunc(String name, int index, int argcount, String doc) {
227: this (name, index, argcount, argcount, doc);
228: }
229:
230: BCPFunc(String name, int index, int minargs, int maxargs, String doc) {
231: super (name, index, minargs, maxargs, doc, BCP.class);
232: }
233:
234: /**
235: * Method __call__
236: *
237: * @param arg
238: * @return PyObject
239: */
240: public PyObject __call__(PyObject arg) {
241:
242: BCP bcp = (BCP) __self__;
243:
244: switch (index) {
245:
246: case 0:
247: String table = (String) arg.__tojava__(String.class);
248:
249: if (table == null) {
250: throw Py.ValueError(zxJDBC
251: .getString("invalidTableName"));
252: }
253:
254: PyObject count = bcp.bcp(table, null, Py.None, Py.None,
255: Py.None, null, Py.None);
256:
257: return count;
258:
259: default:
260: throw info.unexpectedCall(1, false);
261: }
262: }
263:
264: public PyObject __call__(PyObject arga, PyObject argb) {
265:
266: BCP bcp = (BCP) __self__;
267:
268: switch (index) {
269:
270: case 0:
271: String table = (String) arga.__tojava__(String.class);
272:
273: if (table == null) {
274: throw Py.ValueError(zxJDBC
275: .getString("invalidTableName"));
276: }
277:
278: String where = (String) argb.__tojava__(String.class);
279: PyObject count = bcp.bcp(table, where, Py.None, Py.None,
280: Py.None, null, Py.None);
281:
282: return count;
283:
284: default:
285: throw info.unexpectedCall(2, false);
286: }
287: }
288:
289: public PyObject __call__(PyObject arga, PyObject argb, PyObject argc) {
290:
291: BCP bcp = (BCP) __self__;
292:
293: switch (index) {
294:
295: case 0:
296: String table = (String) arga.__tojava__(String.class);
297:
298: if (table == null) {
299: throw Py.ValueError(zxJDBC
300: .getString("invalidTableName"));
301: }
302:
303: String where = (String) argb.__tojava__(String.class);
304: PyObject count = bcp.bcp(table, where, argc, Py.None,
305: Py.None, null, Py.None);
306:
307: return count;
308:
309: default:
310: throw info.unexpectedCall(3, false);
311: }
312: }
313:
314: public PyObject __call__(PyObject[] args, String[] keywords) {
315:
316: BCP bcp = (BCP) __self__;
317:
318: switch (index) {
319:
320: case 0:
321:
322: /*
323: * B.bcp(table, [where=None, params=None, include=None, exclude=None, toTable=None, bindings=None])
324: */
325: String where = null;
326: PyObject params = Py.None;
327: PyArgParser parser = new PyArgParser(args, keywords);
328: String table = (String) parser.arg(0, Py.None).__tojava__(
329: String.class);
330:
331: if (table == null) {
332: throw Py.ValueError(zxJDBC
333: .getString("invalidTableName"));
334: }
335:
336: // 'where' can be the second argument or a keyword
337: if (parser.numArg() >= 2) {
338: where = (String) parser.arg(1, Py.None).__tojava__(
339: String.class);
340: }
341:
342: if (where == null) {
343: where = (String) parser.kw("where", Py.None)
344: .__tojava__(String.class);
345: }
346:
347: // 'params' can be the third argument or a keyword
348: if (parser.numArg() >= 3) {
349: params = parser.arg(2, Py.None);
350: }
351:
352: if (params == Py.None) {
353: params = parser.kw("params", Py.None);
354: }
355:
356: String toTable = (String) parser.kw("toTable", Py.None)
357: .__tojava__(String.class);
358: PyObject include = parser.kw("include", Py.None);
359: PyObject exclude = parser.kw("exclude", Py.None);
360: PyObject bindings = parser.kw("bindings", Py.None);
361: PyObject count = bcp.bcp(table, where, params, include,
362: exclude, toTable, bindings);
363:
364: return count;
365:
366: default:
367: throw info.unexpectedCall(3, false);
368: }
369: }
370: }
|