001: /*
002: * Jython Database Specification API 2.0
003: *
004: * $Id: PyExtendedCursor.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;
010:
011: import java.sql.DatabaseMetaData;
012: import java.sql.SQLException;
013: import java.util.HashSet;
014: import java.util.Set;
015: import org.python.core.Py;
016: import org.python.core.PyBuiltinMethodSet;
017: import org.python.core.PyClass;
018: import org.python.core.PyList;
019: import org.python.core.PyObject;
020: import org.python.core.PyString;
021:
022: /**
023: * A cursor with extensions to the DB API 2.0.
024: *
025: * @author brian zimmer
026: * @author last revised by $Author: cgroves $
027: * @version $Revision: 3248 $
028: */
029: public class PyExtendedCursor extends PyCursor {
030:
031: /**
032: * Field __class__
033: */
034: public static PyClass __class__;
035:
036: /**
037: * Method getPyClass
038: *
039: * @return PyClass
040: */
041: protected PyClass getPyClass() {
042: return __class__;
043: }
044:
045: /**
046: * Field __members__
047: */
048: protected static PyList __members__;
049:
050: /**
051: * Field __methods__
052: */
053: protected static PyList __methods__;
054:
055: static {
056: PyObject[] m = new PyObject[9];
057:
058: m[0] = new PyString("tables");
059: m[1] = new PyString("columns");
060: m[2] = new PyString("primarykeys");
061: m[3] = new PyString("foreignkeys");
062: m[4] = new PyString("procedures");
063: m[5] = new PyString("procedurecolumns");
064: m[6] = new PyString("statistics");
065: m[7] = new PyString("bestrow");
066: m[8] = new PyString("versioncolumns");
067: __methods__ = new PyList(m);
068:
069: __methods__.extend(PyCursor.__methods__);
070:
071: m = new PyObject[0];
072: __members__ = new PyList(m);
073:
074: __members__.extend(PyCursor.__members__);
075: }
076:
077: /**
078: * Constructor PyExtendedCursor
079: *
080: * @param connection
081: */
082: PyExtendedCursor(PyConnection connection) {
083: super (connection);
084: }
085:
086: /**
087: * Constructor PyExtendedCursor
088: *
089: * @param connection
090: * @param dynamicFetch
091: */
092: PyExtendedCursor(PyConnection connection, boolean dynamicFetch) {
093: super (connection, dynamicFetch);
094: }
095:
096: /**
097: * Constructor PyExtendedCursor
098: *
099: * @param connection
100: * @param dynamicFetch
101: * @param rsType
102: * @param rsConcur
103: */
104: PyExtendedCursor(PyConnection connection, boolean dynamicFetch,
105: PyObject rsType, PyObject rsConcur) {
106: super (connection, dynamicFetch, rsType, rsConcur);
107: }
108:
109: /**
110: * String representation of the object.
111: *
112: * @return a string representation of the object.
113: */
114: public String toString() {
115: return "<PyExtendedCursor object instance at " + Py.id(this )
116: + ">";
117: }
118:
119: /**
120: * Initializes the module.
121: *
122: * @param dict
123: */
124: static public void classDictInit(PyObject dict) {
125:
126: PyCursor.classDictInit(dict);
127: dict.__setitem__("__version__", Py.newString(
128: "$Revision: 3248 $").__getslice__(Py.newInteger(11),
129: Py.newInteger(-2), null));
130: dict.__setitem__("tables", new ExtendedCursorFunc("tables",
131: 100, 4, 4, "query for table information"));
132: dict.__setitem__("columns", new ExtendedCursorFunc("columns",
133: 101, 4, 4, "query for column information"));
134: dict.__setitem__("primarykeys", new ExtendedCursorFunc(
135: "primarykeys", 102, 3, 3, "query for primary keys"));
136: dict.__setitem__("foreignkeys", new ExtendedCursorFunc(
137: "foreignkeys", 103, 6, 6, "query for foreign keys"));
138: dict.__setitem__("procedures", new ExtendedCursorFunc(
139: "procedures", 104, 3, 3, "query for procedures"));
140: dict.__setitem__("procedurecolumns", new ExtendedCursorFunc(
141: "procedurecolumns", 105, 4, 4,
142: "query for procedures columns"));
143: dict.__setitem__("statistics", new ExtendedCursorFunc(
144: "statistics", 106, 5, 5,
145: "description of a table's indices and statistics"));
146: dict.__setitem__("gettypeinfo", new ExtendedCursorFunc(
147: "gettypeinfo", 107, 0, 1, "query for sql type info"));
148: dict
149: .__setitem__("gettabletypeinfo",
150: new ExtendedCursorFunc("gettabletypeinfo", 108,
151: 0, 1, "query for table types"));
152: dict
153: .__setitem__(
154: "bestrow",
155: new ExtendedCursorFunc("bestrow", 109, 3, 3,
156: "optimal set of columns that uniquely identifies a row"));
157: dict
158: .__setitem__(
159: "versioncolumns",
160: new ExtendedCursorFunc("versioncolumns", 110,
161: 3, 3,
162: "columns that are automatically updated when any value in a row is updated"));
163:
164: // hide from python
165: dict.__setitem__("classDictInit", null);
166: dict.__setitem__("toString", null);
167: }
168:
169: /**
170: * Finds the attribute.
171: *
172: * @param name the name of the attribute of interest
173: * @return the value for the attribute of the specified name
174: */
175: public PyObject __findattr__(String name) {
176:
177: if ("__methods__".equals(name)) {
178: return __methods__;
179: } else if ("__members__".equals(name)) {
180: return __members__;
181: }
182:
183: return super .__findattr__(name);
184: }
185:
186: /**
187: * Only table descriptions matching the catalog, schema, table name and type
188: * criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and
189: * TABLE_NAME.
190: *
191: * @param qualifier
192: * @param owner
193: * @param table
194: * @param type
195: */
196: protected void tables(PyObject qualifier, PyObject owner,
197: PyObject table, PyObject type) {
198:
199: clear();
200:
201: String q = getMetaDataName(qualifier);
202: String o = getMetaDataName(owner);
203: String t = getMetaDataName(table);
204: String[] y = null;
205:
206: // postgresql interprets the types to be uppercase exclusively
207: // so we'll force this on everyone else as well
208: if (type != Py.None) {
209: String typeName = null;
210:
211: if (isSeq(type)) {
212: int len = type.__len__();
213:
214: y = new String[len];
215:
216: for (int i = 0; i < len; i++) {
217: typeName = getMetaDataName(type.__getitem__(i));
218: y[i] = (typeName == null) ? null : typeName
219: .toUpperCase();
220: }
221: } else {
222: typeName = getMetaDataName(type.__getitem__(type));
223: y = new String[] { (typeName == null) ? null : typeName
224: .toUpperCase() };
225: }
226: }
227:
228: try {
229: this .fetch.add(getMetaData().getTables(q, o, t, y));
230: } catch (SQLException e) {
231: throw zxJDBC.makeException(e);
232: }
233: }
234:
235: /**
236: * Returns the columns for a table.
237: *
238: * @param qualifier
239: * @param owner
240: * @param table
241: * @param column
242: */
243: protected void columns(PyObject qualifier, PyObject owner,
244: PyObject table, PyObject column) {
245:
246: clear();
247:
248: String q = getMetaDataName(qualifier);
249: String o = getMetaDataName(owner);
250: String t = getMetaDataName(table);
251: String c = getMetaDataName(column);
252:
253: try {
254: this .fetch.add(getMetaData().getColumns(q, o, t, c));
255: } catch (SQLException e) {
256: throw zxJDBC.makeException(e);
257: }
258: }
259:
260: /**
261: * Gets a description of the stored procedures available for the qualifier and owner.
262: *
263: * @param qualifier
264: * @param owner
265: * @param procedure
266: */
267: protected void procedures(PyObject qualifier, PyObject owner,
268: PyObject procedure) {
269:
270: clear();
271:
272: String q = getMetaDataName(qualifier);
273: String o = getMetaDataName(owner);
274: String p = getMetaDataName(procedure);
275:
276: try {
277: this .fetch.add(getMetaData().getProcedures(q, o, p));
278: } catch (SQLException e) {
279: throw zxJDBC.makeException(e);
280: }
281: }
282:
283: /**
284: * Gets the columns for the procedure.
285: *
286: * @param qualifier
287: * @param owner
288: * @param procedure
289: * @param column
290: */
291: protected void procedurecolumns(PyObject qualifier, PyObject owner,
292: PyObject procedure, PyObject column) {
293:
294: clear();
295:
296: String q = getMetaDataName(qualifier);
297: String o = getMetaDataName(owner);
298: String p = getMetaDataName(procedure);
299: String c = getMetaDataName(column);
300:
301: try {
302: this .fetch.add(getMetaData()
303: .getProcedureColumns(q, o, p, c));
304: } catch (SQLException e) {
305: throw zxJDBC.makeException(e);
306: }
307: }
308:
309: /**
310: * Gets a description of a table's primary key columns. They are ordered by
311: * COLUMN_NAME.
312: *
313: * @param qualifier a schema name
314: * @param owner an owner name
315: * @param table a table name
316: */
317: protected void primarykeys(PyObject qualifier, PyObject owner,
318: PyObject table) {
319:
320: clear();
321:
322: String q = getMetaDataName(qualifier);
323: String o = getMetaDataName(owner);
324: String t = getMetaDataName(table);
325:
326: try {
327: this .fetch.add(getMetaData().getPrimaryKeys(q, o, t));
328: } catch (SQLException e) {
329: throw zxJDBC.makeException(e);
330: }
331: }
332:
333: /**
334: * Gets a description of the foreign key columns in the foreign key table
335: * that reference the primary key columns of the primary key table (describe
336: * how one table imports another's key.) This should normally return a single
337: * foreign key/primary key pair (most tables only import a foreign key from a
338: * table once.) They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME,
339: * and KEY_SEQ.
340: *
341: * @param primaryQualifier
342: * @param primaryOwner
343: * @param primaryTable
344: * @param foreignQualifier
345: * @param foreignOwner
346: * @param foreignTable
347: */
348: protected void foreignkeys(PyObject primaryQualifier,
349: PyObject primaryOwner, PyObject primaryTable,
350: PyObject foreignQualifier, PyObject foreignOwner,
351: PyObject foreignTable) {
352:
353: clear();
354:
355: String pq = getMetaDataName(primaryQualifier);
356: String po = getMetaDataName(primaryOwner);
357: String pt = getMetaDataName(primaryTable);
358: String fq = getMetaDataName(foreignQualifier);
359: String fo = getMetaDataName(foreignOwner);
360: String ft = getMetaDataName(foreignTable);
361:
362: try {
363: this .fetch.add(getMetaData().getCrossReference(pq, po, pt,
364: fq, fo, ft));
365: } catch (SQLException e) {
366: throw zxJDBC.makeException(e);
367: }
368: }
369:
370: /**
371: * Gets a description of a table's indices and statistics. They are ordered by
372: * NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.
373: *
374: * @param qualifier
375: * @param owner
376: * @param table
377: * @param unique
378: * @param accuracy
379: */
380: protected void statistics(PyObject qualifier, PyObject owner,
381: PyObject table, PyObject unique, PyObject accuracy) {
382:
383: clear();
384:
385: Set skipCols = new HashSet();
386:
387: skipCols.add(new Integer(12));
388:
389: String q = getMetaDataName(qualifier);
390: String o = getMetaDataName(owner);
391: String t = getMetaDataName(table);
392: boolean u = unique.__nonzero__();
393: boolean a = accuracy.__nonzero__();
394:
395: try {
396: this .fetch.add(getMetaData().getIndexInfo(q, o, t, u, a),
397: skipCols);
398: } catch (SQLException e) {
399: throw zxJDBC.makeException(e);
400: }
401: }
402:
403: /**
404: * Gets a description of the type information for a given type.
405: *
406: * @param type data type for which to provide information
407: */
408: protected void typeinfo(PyObject type) {
409:
410: clear();
411:
412: Set skipCols = new HashSet();
413:
414: skipCols.add(new Integer(16));
415: skipCols.add(new Integer(17));
416:
417: try {
418: this .fetch.add(getMetaData().getTypeInfo(), skipCols);
419: } catch (SQLException e) {
420: throw zxJDBC.makeException(e);
421: }
422:
423: // if the type is non-null, then trim the result list down to that type only
424: // if(type != null &&!Py.None.equals(type)) {
425: // for(int i = 0; i < ((PyObject) this.results.get(0)).__len__(); i++) {
426: // PyObject row = ((PyObject) this.results.get(0)).__getitem__(new PyInteger(i));
427: // PyObject sqlType = row.__getitem__(new PyInteger(1));
428: // if(type.equals(sqlType)) {
429: // this.results.remove(0);
430: // this.results.add(0, new PyList(new PyObject[] {
431: // row
432: // }));
433: // }
434: // }
435: // }
436: }
437:
438: /**
439: * Gets a description of possible table types.
440: */
441: protected void tabletypeinfo() {
442:
443: clear();
444:
445: try {
446: this .fetch.add(getMetaData().getTableTypes());
447: } catch (SQLException e) {
448: throw zxJDBC.makeException(e);
449: }
450: }
451:
452: /**
453: * Gets a description of a table's optimal set of columns that uniquely
454: * identifies a row. They are ordered by SCOPE.
455: *
456: * @param qualifier
457: * @param owner
458: * @param table
459: */
460: protected void bestrow(PyObject qualifier, PyObject owner,
461: PyObject table) {
462:
463: clear();
464:
465: String c = getMetaDataName(qualifier);
466: String s = getMetaDataName(owner);
467: String t = getMetaDataName(table);
468: int p = DatabaseMetaData.bestRowSession; // scope
469: boolean n = true; // nullable
470:
471: try {
472: this .fetch.add(getMetaData().getBestRowIdentifier(c, s, t,
473: p, n));
474: } catch (SQLException e) {
475: throw zxJDBC.makeException(e);
476: }
477: }
478:
479: /**
480: * Gets a description of a table's columns that are automatically
481: * updated when any value in a row is updated. They are unordered.
482: *
483: * @param qualifier a schema name
484: * @param owner an owner name
485: * @param table a table name
486: */
487: protected void versioncolumns(PyObject qualifier, PyObject owner,
488: PyObject table) {
489:
490: clear();
491:
492: String q = getMetaDataName(qualifier);
493: String o = getMetaDataName(owner);
494: String t = getMetaDataName(table);
495:
496: try {
497: this .fetch.add(getMetaData().getVersionColumns(q, o, t));
498: } catch (SQLException e) {
499: throw zxJDBC.makeException(e);
500: }
501: }
502:
503: /**
504: * Method getMetaDataName
505: *
506: * @param name
507: * @return String
508: */
509: protected String getMetaDataName(PyObject name) {
510:
511: if (name == Py.None) {
512: return null;
513: }
514:
515: String string = name.__str__().toString();
516:
517: // see if the driver can help us
518: try {
519: if (getMetaData().storesLowerCaseIdentifiers()) {
520: return string.toLowerCase();
521: } else if (getMetaData().storesUpperCaseIdentifiers()) {
522: return string.toUpperCase();
523: }
524: } catch (SQLException e) {
525: }
526:
527: // well we don't know yet so give it to the datahandler
528: return datahandler.getMetaDataName(name);
529: }
530: }
531:
532: class ExtendedCursorFunc extends PyBuiltinMethodSet {
533:
534: ExtendedCursorFunc(String name, int index, int argcount, String doc) {
535: this (name, index, argcount, argcount, doc);
536: }
537:
538: ExtendedCursorFunc(String name, int index, int minargs,
539: int maxargs, String doc) {
540: super (name, index, minargs, maxargs, doc,
541: PyExtendedCursor.class);
542: }
543:
544: public PyObject __call__() {
545:
546: PyExtendedCursor cursor = (PyExtendedCursor) __self__;
547:
548: switch (index) {
549:
550: case 107:
551: cursor.typeinfo(Py.None);
552:
553: return Py.None;
554:
555: case 108:
556: cursor.tabletypeinfo();
557:
558: return Py.None;
559:
560: default:
561: throw info.unexpectedCall(0, false);
562: }
563: }
564:
565: public PyObject __call__(PyObject arga) {
566:
567: PyExtendedCursor cursor = (PyExtendedCursor) __self__;
568:
569: switch (index) {
570:
571: case 107:
572: cursor.typeinfo(arga);
573:
574: return Py.None;
575:
576: default:
577: throw info.unexpectedCall(1, false);
578: }
579: }
580:
581: public PyObject __call__(PyObject arga, PyObject argb, PyObject argc) {
582:
583: PyExtendedCursor cursor = (PyExtendedCursor) __self__;
584:
585: switch (index) {
586:
587: case 102:
588: cursor.primarykeys(arga, argb, argc);
589:
590: return Py.None;
591:
592: case 104:
593: cursor.procedures(arga, argb, argc);
594:
595: return Py.None;
596:
597: case 109:
598: cursor.bestrow(arga, argb, argc);
599:
600: return Py.None;
601:
602: case 110:
603: cursor.versioncolumns(arga, argb, argc);
604:
605: return Py.None;
606:
607: default:
608: throw info.unexpectedCall(3, false);
609: }
610: }
611:
612: public PyObject fancyCall(PyObject[] args) {
613:
614: PyExtendedCursor cursor = (PyExtendedCursor) __self__;
615:
616: switch (index) {
617:
618: case 103:
619: cursor.foreignkeys(args[0], args[1], args[2], args[3],
620: args[4], args[5]);
621:
622: return Py.None;
623:
624: case 106:
625: cursor.statistics(args[0], args[1], args[2], args[3],
626: args[4]);
627:
628: return Py.None;
629:
630: default:
631: throw info.unexpectedCall(args.length, true);
632: }
633: }
634:
635: public PyObject __call__(PyObject arg1, PyObject arg2,
636: PyObject arg3, PyObject arg4) {
637:
638: PyExtendedCursor cursor = (PyExtendedCursor) __self__;
639:
640: switch (index) {
641:
642: case 100:
643: cursor.tables(arg1, arg2, arg3, arg4);
644:
645: return Py.None;
646:
647: case 101:
648: cursor.columns(arg1, arg2, arg3, arg4);
649:
650: return Py.None;
651:
652: case 105:
653: cursor.procedurecolumns(arg1, arg2, arg3, arg4);
654:
655: return Py.None;
656:
657: default:
658: throw info.unexpectedCall(4, false);
659: }
660: }
661: }
|