DatabaseMetaData.java 92.6 KB
Newer Older
Peter Mount's avatar
Peter Mount committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
package org.postgresql.jdbc2;

// IMPORTANT NOTE: This file implements the JDBC 2 version of the driver.
// If you make any modifications to this file, you must make sure that the
// changes are also made (if relevent) to the related JDBC 1 class in the
// org.postgresql.jdbc1 package.

import java.sql.*;
import java.util.*;
import org.postgresql.Field;

/**
 * This class provides information about the database as a whole.
 *
 * <p>Many of the methods here return lists of information in ResultSets.  You
16
 * can use the normal ResultSet methods such as getString and getInt to
Peter Mount's avatar
Peter Mount committed
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
 * retrieve the data from these ResultSets.  If a given form of metadata is
 * not available, these methods should throw a SQLException.
 *
 * <p>Some of these methods take arguments that are String patterns.  These
 * arguments all have names such as fooPattern.  Within a pattern String,
 * "%" means match any substring of 0 or more characters, and "_" means
 * match any one character.  Only metadata entries matching the search
 * pattern are returned.  if a search pattern argument is set to a null
 * ref, it means that argument's criteria should be dropped from the
 * search.
 *
 * <p>A SQLException will be throws if a driver does not support a meta
 * data method.  In the case of methods that return a ResultSet, either
 * a ResultSet (which may be empty) is returned or a SQLException is
 * thrown.
 *
 * @see java.sql.DatabaseMetaData
 */
35
public class DatabaseMetaData implements java.sql.DatabaseMetaData
Peter Mount's avatar
Peter Mount committed
36 37
{
  Connection connection;		// The connection association
38

Peter Mount's avatar
Peter Mount committed
39 40 41 42 43 44
  // These define various OID's. Hopefully they will stay constant.
  static final int iVarcharOid = 1043;	// OID for varchar
  static final int iBoolOid = 16;	// OID for bool
  static final int iInt2Oid = 21;	// OID for int2
  static final int iInt4Oid = 23;	// OID for int4
  static final int VARHDRSZ =  4;	// length for int4
45

Peter Mount's avatar
Peter Mount committed
46 47
  // This is a default value for remarks
  private static final byte defaultRemarks[]="no remarks".getBytes();
48

Peter Mount's avatar
Peter Mount committed
49 50 51 52
  public DatabaseMetaData(Connection conn)
  {
    this.connection = conn;
  }
53

Peter Mount's avatar
Peter Mount committed
54 55 56 57 58 59 60 61 62 63 64
  /**
   * Can all the procedures returned by getProcedures be called
   * by the current user?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean allProceduresAreCallable() throws SQLException
  {
    return true;		// For now...
  }
65

Peter Mount's avatar
Peter Mount committed
66 67 68 69 70 71 72 73 74 75 76
  /**
   * Can all the tables returned by getTable be SELECTed by
   * the current user?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean allTablesAreSelectable() throws SQLException
  {
    return true;		// For now...
  }
77

Peter Mount's avatar
Peter Mount committed
78 79 80 81 82 83 84 85 86 87
  /**
   * What is the URL for this database?
   *
   * @return the url or null if it cannott be generated
   * @exception SQLException if a database access error occurs
   */
  public String getURL() throws SQLException
  {
    return connection.getURL();
  }
88

Peter Mount's avatar
Peter Mount committed
89 90 91 92 93 94 95 96 97 98
  /**
   * What is our user name as known to the database?
   *
   * @return our database user name
   * @exception SQLException if a database access error occurs
   */
  public String getUserName() throws SQLException
  {
    return connection.getUserName();
  }
99

Peter Mount's avatar
Peter Mount committed
100 101 102 103 104 105 106 107 108 109
  /**
   * Is the database in read-only mode?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean isReadOnly() throws SQLException
  {
    return connection.isReadOnly();
  }
110

Peter Mount's avatar
Peter Mount committed
111 112 113 114 115 116 117 118 119 120
  /**
   * Are NULL values sorted high?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean nullsAreSortedHigh() throws SQLException
  {
    return false;
  }
121

Peter Mount's avatar
Peter Mount committed
122 123 124 125 126 127 128 129 130 131
  /**
   * Are NULL values sorted low?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean nullsAreSortedLow() throws SQLException
  {
    return false;
  }
132

Peter Mount's avatar
Peter Mount committed
133 134 135 136 137 138 139 140 141 142
  /**
   * Are NULL values sorted at the start regardless of sort order?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean nullsAreSortedAtStart() throws SQLException
  {
    return false;
  }
143

Peter Mount's avatar
Peter Mount committed
144 145 146 147 148 149 150 151 152 153
  /**
   * Are NULL values sorted at the end regardless of sort order?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean nullsAreSortedAtEnd() throws SQLException
  {
    return true;
  }
154

Peter Mount's avatar
Peter Mount committed
155 156 157 158 159 160 161 162 163
  /**
   * What is the name of this database product - we hope that it is
   * PostgreSQL, so we return that explicitly.
   *
   * @return the database product name
   * @exception SQLException if a database access error occurs
   */
  public String getDatabaseProductName() throws SQLException
  {
164
    return "PostgreSQL";
Peter Mount's avatar
Peter Mount committed
165
  }
166

Peter Mount's avatar
Peter Mount committed
167 168 169 170 171 172 173 174
  /**
   * What is the version of this database product.
   *
   * @return the database version
   * @exception SQLException if a database access error occurs
   */
  public String getDatabaseProductVersion() throws SQLException
  {
175 176 177 178 179 180 181 182
	java.sql.ResultSet resultSet = connection.ExecSQL("select version()");
	resultSet.next();

	StringTokenizer versionParts = new StringTokenizer(resultSet.getString(1));
	versionParts.nextToken(); /* "PostgreSQL" */
	String versionNumber = versionParts.nextToken(); /* "X.Y.Z" */

	return versionNumber;
Peter Mount's avatar
Peter Mount committed
183
  }
184

Peter Mount's avatar
Peter Mount committed
185 186 187 188 189 190 191 192 193
  /**
   * What is the name of this JDBC driver?  If we don't know this
   * we are doing something wrong!
   *
   * @return the JDBC driver name
   * @exception SQLException why?
   */
  public String getDriverName() throws SQLException
  {
194
    return "PostgreSQL Native Driver";
Peter Mount's avatar
Peter Mount committed
195
  }
196

Peter Mount's avatar
Peter Mount committed
197 198 199 200 201 202 203 204 205
  /**
   * What is the version string of this JDBC driver?  Again, this is
   * static.
   *
   * @return the JDBC driver name.
   * @exception SQLException why?
   */
  public String getDriverVersion() throws SQLException
  {
206
      return connection.this_driver.getVersion();
Peter Mount's avatar
Peter Mount committed
207
  }
208

Peter Mount's avatar
Peter Mount committed
209 210 211 212 213 214 215 216 217
  /**
   * What is this JDBC driver's major version number?
   *
   * @return the JDBC driver major version
   */
  public int getDriverMajorVersion()
  {
    return connection.this_driver.getMajorVersion();
  }
218

Peter Mount's avatar
Peter Mount committed
219 220 221 222 223 224 225 226 227
  /**
   * What is this JDBC driver's minor version number?
   *
   * @return the JDBC driver minor version
   */
  public int getDriverMinorVersion()
  {
    return connection.this_driver.getMinorVersion();
  }
228

Peter Mount's avatar
Peter Mount committed
229 230 231
  /**
   * Does the database store tables in a local file?  No - it
   * stores them in a file on the server.
232
   *
Peter Mount's avatar
Peter Mount committed
233 234 235 236 237 238 239
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean usesLocalFiles() throws SQLException
  {
    return false;
  }
240

Peter Mount's avatar
Peter Mount committed
241 242
  /**
   * Does the database use a file for each table?  Well, not really,
243
   * since it doesnt use local files.
Peter Mount's avatar
Peter Mount committed
244 245 246 247 248 249 250 251
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean usesLocalFilePerTable() throws SQLException
  {
    return false;
  }
252

Peter Mount's avatar
Peter Mount committed
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
  /**
   * Does the database treat mixed case unquoted SQL identifiers
   * as case sensitive and as a result store them in mixed case?
   * A JDBC-Compliant driver will always return false.
   *
   * <p>Predicament - what do they mean by "SQL identifiers" - if it
   * means the names of the tables and columns, then the answers
   * given below are correct - otherwise I don't know.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsMixedCaseIdentifiers() throws SQLException
  {
    return false;
  }
269

Peter Mount's avatar
Peter Mount committed
270 271 272 273 274 275 276 277 278 279
  /**
   * Does the database treat mixed case unquoted SQL identifiers as
   * case insensitive and store them in upper case?
   *
   * @return true if so
   */
  public boolean storesUpperCaseIdentifiers() throws SQLException
  {
    return false;
  }
280

Peter Mount's avatar
Peter Mount committed
281 282 283 284 285 286 287 288 289 290
  /**
   * Does the database treat mixed case unquoted SQL identifiers as
   * case insensitive and store them in lower case?
   *
   * @return true if so
   */
  public boolean storesLowerCaseIdentifiers() throws SQLException
  {
    return true;
  }
291

Peter Mount's avatar
Peter Mount committed
292 293 294 295 296 297 298 299 300 301
  /**
   * Does the database treat mixed case unquoted SQL identifiers as
   * case insensitive and store them in mixed case?
   *
   * @return true if so
   */
  public boolean storesMixedCaseIdentifiers() throws SQLException
  {
    return false;
  }
302

Peter Mount's avatar
Peter Mount committed
303 304 305
  /**
   * Does the database treat mixed case quoted SQL identifiers as
   * case sensitive and as a result store them in mixed case?  A
306
   * JDBC compliant driver will always return true.
Peter Mount's avatar
Peter Mount committed
307 308 309 310 311 312 313 314 315 316 317 318
   *
   * <p>Predicament - what do they mean by "SQL identifiers" - if it
   * means the names of the tables and columns, then the answers
   * given below are correct - otherwise I don't know.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException
  {
    return true;
  }
319

Peter Mount's avatar
Peter Mount committed
320 321 322 323 324 325 326 327 328 329
  /**
   * Does the database treat mixed case quoted SQL identifiers as
   * case insensitive and store them in upper case?
   *
   * @return true if so
   */
  public boolean storesUpperCaseQuotedIdentifiers() throws SQLException
  {
    return false;
  }
330

Peter Mount's avatar
Peter Mount committed
331 332 333 334 335 336 337 338 339 340
  /**
   * Does the database treat mixed case quoted SQL identifiers as case
   * insensitive and store them in lower case?
   *
   * @return true if so
   */
  public boolean storesLowerCaseQuotedIdentifiers() throws SQLException
  {
    return false;
  }
341

Peter Mount's avatar
Peter Mount committed
342 343 344 345 346 347 348 349 350 351
  /**
   * Does the database treat mixed case quoted SQL identifiers as case
   * insensitive and store them in mixed case?
   *
   * @return true if so
   */
  public boolean storesMixedCaseQuotedIdentifiers() throws SQLException
  {
    return false;
  }
352

Peter Mount's avatar
Peter Mount committed
353 354 355 356 357 358 359 360 361 362 363 364 365
  /**
   * What is the string used to quote SQL identifiers?  This returns
   * a space if identifier quoting isn't supported.  A JDBC Compliant
   * driver will always use a double quote character.
   *
   * <p>If an SQL identifier is a table name, column name, etc. then
   * we do not support it.
   *
   * @return the quoting string
   * @exception SQLException if a database access error occurs
   */
  public String getIdentifierQuoteString() throws SQLException
  {
366
    return "\"";
Peter Mount's avatar
Peter Mount committed
367
  }
368

Peter Mount's avatar
Peter Mount committed
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
  /**
   * Get a comma separated list of all a database's SQL keywords that
   * are NOT also SQL92 keywords.
   *
   * <p>Within PostgreSQL, the keywords are found in
   * 	src/backend/parser/keywords.c
   *
   * <p>For SQL Keywords, I took the list provided at
   * 	<a href="http://web.dementia.org/~shadow/sql/sql3bnf.sep93.txt">
   * http://web.dementia.org/~shadow/sql/sql3bnf.sep93.txt</a>
   * which is for SQL3, not SQL-92, but it is close enough for
   * this purpose.
   *
   * @return a comma separated list of keywords we use
   * @exception SQLException if a database access error occurs
   */
  public String getSQLKeywords() throws SQLException
  {
387
    return "abort,acl,add,aggregate,append,archive,arch_store,backward,binary,change,cluster,copy,database,delimiters,do,extend,explain,forward,heavy,index,inherits,isnull,light,listen,load,merge,nothing,notify,notnull,oids,purge,rename,replace,retrieve,returns,rule,recipe,setof,stdin,stdout,store,vacuum,verbose,version";
Peter Mount's avatar
Peter Mount committed
388
  }
389

Peter Mount's avatar
Peter Mount committed
390 391 392 393 394
  public String getNumericFunctions() throws SQLException
  {
    // XXX-Not Implemented
    return "";
  }
395

Peter Mount's avatar
Peter Mount committed
396 397 398 399 400
  public String getStringFunctions() throws SQLException
  {
    // XXX-Not Implemented
    return "";
  }
401

Peter Mount's avatar
Peter Mount committed
402 403 404 405 406
  public String getSystemFunctions() throws SQLException
  {
    // XXX-Not Implemented
    return "";
  }
407

Peter Mount's avatar
Peter Mount committed
408 409 410 411 412
  public String getTimeDateFunctions() throws SQLException
  {
    // XXX-Not Implemented
    return "";
  }
413

Peter Mount's avatar
Peter Mount committed
414 415 416 417 418 419 420 421 422
  /**
   * This is the string that can be used to escape '_' and '%' in
   * a search string pattern style catalog search parameters
   *
   * @return the string used to escape wildcard characters
   * @exception SQLException if a database access error occurs
   */
  public String getSearchStringEscape() throws SQLException
  {
423
    return "\\";
Peter Mount's avatar
Peter Mount committed
424
  }
425

Peter Mount's avatar
Peter Mount committed
426
  /**
427
   * Get all the "extra" characters that can be used in unquoted
Peter Mount's avatar
Peter Mount committed
428 429 430 431 432 433 434 435 436 437 438
   * identifier names (those beyond a-zA-Z0-9 and _)
   *
   * <p>From the file src/backend/parser/scan.l, an identifier is
   * {letter}{letter_or_digit} which makes it just those listed
   * above.
   *
   * @return a string containing the extra characters
   * @exception SQLException if a database access error occurs
   */
  public String getExtraNameCharacters() throws SQLException
  {
439
    return "";
Peter Mount's avatar
Peter Mount committed
440
  }
441

Peter Mount's avatar
Peter Mount committed
442 443 444 445 446 447 448 449 450 451 452
  /**
   * Is "ALTER TABLE" with an add column supported?
   * Yes for PostgreSQL 6.1
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsAlterTableWithAddColumn() throws SQLException
  {
    return true;
  }
453

Peter Mount's avatar
Peter Mount committed
454 455
  /**
   * Is "ALTER TABLE" with a drop column supported?
456
   * Peter 10/10/2000 This was set to true, but 7.1devel doesn't support it!
Peter Mount's avatar
Peter Mount committed
457 458 459 460 461 462
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsAlterTableWithDropColumn() throws SQLException
  {
463
      return false;
Peter Mount's avatar
Peter Mount committed
464
  }
465

Peter Mount's avatar
Peter Mount committed
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
  /**
   * Is column aliasing supported?
   *
   * <p>If so, the SQL AS clause can be used to provide names for
   * computed columns or to provide alias names for columns as
   * required.  A JDBC Compliant driver always returns true.
   *
   * <p>e.g.
   *
   * <br><pre>
   * select count(C) as C_COUNT from T group by C;
   *
   * </pre><br>
   * should return a column named as C_COUNT instead of count(C)
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsColumnAliasing() throws SQLException
  {
    return true;
  }
488

Peter Mount's avatar
Peter Mount committed
489 490 491 492 493 494 495 496 497 498 499
  /**
   * Are concatenations between NULL and non-NULL values NULL?  A
   * JDBC Compliant driver always returns true
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean nullPlusNonNullIsNull() throws SQLException
  {
    return true;
  }
500

Peter Mount's avatar
Peter Mount committed
501 502 503 504 505
  public boolean supportsConvert() throws SQLException
  {
    // XXX-Not Implemented
    return false;
  }
506

Peter Mount's avatar
Peter Mount committed
507 508 509 510 511
  public boolean supportsConvert(int fromType, int toType) throws SQLException
  {
    // XXX-Not Implemented
    return false;
  }
512

Peter Mount's avatar
Peter Mount committed
513 514 515 516 517
  public boolean supportsTableCorrelationNames() throws SQLException
  {
    // XXX-Not Implemented
    return false;
  }
518

Peter Mount's avatar
Peter Mount committed
519 520 521 522 523
  public boolean supportsDifferentTableCorrelationNames() throws SQLException
  {
    // XXX-Not Implemented
    return false;
  }
524

Peter Mount's avatar
Peter Mount committed
525
  /**
526
   * Are expressions in "ORDER BY" lists supported?
527
   *
Peter Mount's avatar
Peter Mount committed
528 529 530 531 532 533 534 535 536
   * <br>e.g. select * from t order by a + b;
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsExpressionsInOrderBy() throws SQLException
  {
    return true;
  }
537

Peter Mount's avatar
Peter Mount committed
538 539 540 541 542 543 544 545 546 547 548
  /**
   * Can an "ORDER BY" clause use columns not in the SELECT?
   * I checked it, and you can't.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsOrderByUnrelated() throws SQLException
  {
    return false;
  }
549

Peter Mount's avatar
Peter Mount committed
550 551 552 553 554 555 556 557 558 559 560
  /**
   * Is some form of "GROUP BY" clause supported?
   * I checked it, and yes it is.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsGroupBy() throws SQLException
  {
    return true;
  }
561

Peter Mount's avatar
Peter Mount committed
562 563 564 565 566 567 568 569 570 571 572
  /**
   * Can a "GROUP BY" clause use columns not in the SELECT?
   * I checked it - it seems to allow it
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsGroupByUnrelated() throws SQLException
  {
    return true;
  }
573

Peter Mount's avatar
Peter Mount committed
574 575 576 577 578 579 580 581 582 583 584 585
  /**
   * Can a "GROUP BY" clause add columns not in the SELECT provided
   * it specifies all the columns in the SELECT?  Does anyone actually
   * understand what they mean here?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsGroupByBeyondSelect() throws SQLException
  {
    return true;		// For now...
  }
586

Peter Mount's avatar
Peter Mount committed
587 588 589 590 591 592 593 594 595 596 597
  /**
   * Is the escape character in "LIKE" clauses supported?  A
   * JDBC compliant driver always returns true.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsLikeEscapeClause() throws SQLException
  {
    return true;
  }
598

Peter Mount's avatar
Peter Mount committed
599 600 601 602
  /**
   * Are multiple ResultSets from a single execute supported?
   * Well, I implemented it, but I dont think this is possible from
   * the back ends point of view.
603
   *
Peter Mount's avatar
Peter Mount committed
604 605 606 607 608 609 610
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsMultipleResultSets() throws SQLException
  {
    return false;
  }
611

Peter Mount's avatar
Peter Mount committed
612 613 614 615 616 617 618 619 620 621 622 623
  /**
   * Can we have multiple transactions open at once (on different
   * connections?)
   * I guess we can have, since Im relying on it.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsMultipleTransactions() throws SQLException
  {
    return true;
  }
624

Peter Mount's avatar
Peter Mount committed
625 626 627 628 629 630 631 632 633 634 635 636 637 638
  /**
   * Can columns be defined as non-nullable.  A JDBC Compliant driver
   * always returns true.
   *
   * <p>This changed from false to true in v6.2 of the driver, as this
   * support was added to the backend.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsNonNullableColumns() throws SQLException
  {
    return true;
  }
639

Peter Mount's avatar
Peter Mount committed
640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
  /**
   * Does this driver support the minimum ODBC SQL grammar.  This
   * grammar is defined at:
   *
   * <p><a href="http://www.microsoft.com/msdn/sdk/platforms/doc/odbc/src/intropr.htm">http://www.microsoft.com/msdn/sdk/platforms/doc/odbc/src/intropr.htm</a>
   *
   * <p>In Appendix C.  From this description, we seem to support the
   * ODBC minimal (Level 0) grammar.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsMinimumSQLGrammar() throws SQLException
  {
    return true;
  }
656

Peter Mount's avatar
Peter Mount committed
657 658 659 660 661 662 663 664 665 666 667
  /**
   * Does this driver support the Core ODBC SQL grammar.  We need
   * SQL-92 conformance for this.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsCoreSQLGrammar() throws SQLException
  {
    return false;
  }
668

Peter Mount's avatar
Peter Mount committed
669 670 671 672 673 674 675 676 677 678 679 680
  /**
   * Does this driver support the Extended (Level 2) ODBC SQL
   * grammar.  We don't conform to the Core (Level 1), so we can't
   * conform to the Extended SQL Grammar.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsExtendedSQLGrammar() throws SQLException
  {
    return false;
  }
681

Peter Mount's avatar
Peter Mount committed
682 683 684 685 686 687 688 689 690 691 692 693
  /**
   * Does this driver support the ANSI-92 entry level SQL grammar?
   * All JDBC Compliant drivers must return true.  I think we have
   * to support outer joins for this to be true.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsANSI92EntryLevelSQL() throws SQLException
  {
    return false;
  }
694

Peter Mount's avatar
Peter Mount committed
695 696 697 698 699 700 701 702 703 704 705 706
  /**
   * Does this driver support the ANSI-92 intermediate level SQL
   * grammar?  Anyone who does not support Entry level cannot support
   * Intermediate level.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsANSI92IntermediateSQL() throws SQLException
  {
    return false;
  }
707

Peter Mount's avatar
Peter Mount committed
708 709 710 711 712 713 714 715 716 717
  /**
   * Does this driver support the ANSI-92 full SQL grammar?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsANSI92FullSQL() throws SQLException
  {
    return false;
  }
718

Peter Mount's avatar
Peter Mount committed
719 720 721
  /**
   * Is the SQL Integrity Enhancement Facility supported?
   * I haven't seen this mentioned anywhere, so I guess not
722
   *
Peter Mount's avatar
Peter Mount committed
723 724 725 726 727 728 729
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsIntegrityEnhancementFacility() throws SQLException
  {
    return false;
  }
730

Peter Mount's avatar
Peter Mount committed
731 732 733 734 735 736 737 738
  /**
   * Is some form of outer join supported?  From my knowledge, nope.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsOuterJoins() throws SQLException
  {
739
    return true; // yes 7.1 does
Peter Mount's avatar
Peter Mount committed
740
  }
741

Peter Mount's avatar
Peter Mount committed
742 743 744 745 746 747 748 749 750
  /**
   * Are full nexted outer joins supported?  Well, we dont support any
   * form of outer join, so this is no as well
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsFullOuterJoins() throws SQLException
  {
751
    return true; // yes in 7.1
Peter Mount's avatar
Peter Mount committed
752
  }
753

Peter Mount's avatar
Peter Mount committed
754 755 756 757 758 759 760 761 762
  /**
   * Is there limited support for outer joins?  (This will be true if
   * supportFullOuterJoins is true)
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsLimitedOuterJoins() throws SQLException
  {
763
    return true; // yes in 7.1
Peter Mount's avatar
Peter Mount committed
764
  }
765

Peter Mount's avatar
Peter Mount committed
766 767 768 769 770 771 772 773 774 775
  /**
   * What is the database vendor's preferred term for "schema" - well,
   * we do not provide support for schemas, so lets just use that
   * term.
   *
   * @return the vendor term
   * @exception SQLException if a database access error occurs
   */
  public String getSchemaTerm() throws SQLException
  {
776
    return "Schema";
Peter Mount's avatar
Peter Mount committed
777
  }
778

Peter Mount's avatar
Peter Mount committed
779
  /**
780
   * What is the database vendor's preferred term for "procedure" -
Peter Mount's avatar
Peter Mount committed
781 782 783 784 785 786 787
   * I kind of like "Procedure" myself.
   *
   * @return the vendor term
   * @exception SQLException if a database access error occurs
   */
  public String getProcedureTerm() throws SQLException
  {
788
    return "Procedure";
Peter Mount's avatar
Peter Mount committed
789
  }
790

Peter Mount's avatar
Peter Mount committed
791 792 793 794 795 796 797 798 799
  /**
   * What is the database vendor's preferred term for "catalog"? -
   * we dont have a preferred term, so just use Catalog
   *
   * @return the vendor term
   * @exception SQLException if a database access error occurs
   */
  public String getCatalogTerm() throws SQLException
  {
800
    return "Catalog";
Peter Mount's avatar
Peter Mount committed
801
  }
802

Peter Mount's avatar
Peter Mount committed
803 804 805 806 807 808 809 810 811 812 813
  /**
   * Does a catalog appear at the start of a qualified table name?
   * (Otherwise it appears at the end).
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean isCatalogAtStart() throws SQLException
  {
    return false;
  }
814

Peter Mount's avatar
Peter Mount committed
815 816 817 818 819 820 821 822 823 824 825
  /**
   * What is the Catalog separator.  Hmmm....well, I kind of like
   * a period (so we get catalog.table definitions). - I don't think
   * PostgreSQL supports catalogs anyhow, so it makes no difference.
   *
   * @return the catalog separator string
   * @exception SQLException if a database access error occurs
   */
  public String getCatalogSeparator() throws SQLException
  {
    // PM Sep 29 97 - changed from "." as we don't support catalogs.
826
    return "";
Peter Mount's avatar
Peter Mount committed
827
  }
828

Peter Mount's avatar
Peter Mount committed
829 830 831 832 833 834 835 836 837 838
  /**
   * Can a schema name be used in a data manipulation statement?  Nope.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsSchemasInDataManipulation() throws SQLException
  {
    return false;
  }
839

Peter Mount's avatar
Peter Mount committed
840 841 842 843 844 845 846 847 848 849
  /**
   * Can a schema name be used in a procedure call statement?  Nope.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsSchemasInProcedureCalls() throws SQLException
  {
    return false;
  }
850

Peter Mount's avatar
Peter Mount committed
851 852 853 854 855 856 857 858 859 860
  /**
   * Can a schema be used in a table definition statement?  Nope.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsSchemasInTableDefinitions() throws SQLException
  {
    return false;
  }
861

Peter Mount's avatar
Peter Mount committed
862 863 864 865 866 867 868 869 870 871
  /**
   * Can a schema name be used in an index definition statement?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsSchemasInIndexDefinitions() throws SQLException
  {
    return false;
  }
872

Peter Mount's avatar
Peter Mount committed
873 874 875 876 877 878 879 880 881 882
  /**
   * Can a schema name be used in a privilege definition statement?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException
  {
    return false;
  }
883

Peter Mount's avatar
Peter Mount committed
884 885 886 887 888 889 890 891 892 893
  /**
   * Can a catalog name be used in a data manipulation statement?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsCatalogsInDataManipulation() throws SQLException
  {
    return false;
  }
894

Peter Mount's avatar
Peter Mount committed
895 896 897 898 899 900 901 902 903 904
  /**
   * Can a catalog name be used in a procedure call statement?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsCatalogsInProcedureCalls() throws SQLException
  {
    return false;
  }
905

Peter Mount's avatar
Peter Mount committed
906 907 908 909 910 911 912 913 914 915
  /**
   * Can a catalog name be used in a table definition statement?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsCatalogsInTableDefinitions() throws SQLException
  {
    return false;
  }
916

Peter Mount's avatar
Peter Mount committed
917 918 919 920 921 922 923 924 925 926
  /**
   * Can a catalog name be used in an index definition?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsCatalogsInIndexDefinitions() throws SQLException
  {
    return false;
  }
927

Peter Mount's avatar
Peter Mount committed
928 929 930 931 932 933 934 935 936 937
  /**
   * Can a catalog name be used in a privilege definition statement?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException
  {
    return false;
  }
938

Peter Mount's avatar
Peter Mount committed
939 940 941 942 943 944 945 946 947 948 949
  /**
   * We support cursors for gets only it seems.  I dont see a method
   * to get a positioned delete.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsPositionedDelete() throws SQLException
  {
    return false;			// For now...
  }
950

Peter Mount's avatar
Peter Mount committed
951 952
  /**
   * Is positioned UPDATE supported?
953
   *
Peter Mount's avatar
Peter Mount committed
954 955 956 957 958 959 960
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsPositionedUpdate() throws SQLException
  {
    return false;			// For now...
  }
961

Peter Mount's avatar
Peter Mount committed
962 963 964 965 966
  public boolean supportsSelectForUpdate() throws SQLException
  {
    // XXX-Not Implemented
    return false;
  }
967

Peter Mount's avatar
Peter Mount committed
968 969 970 971 972
  public boolean supportsStoredProcedures() throws SQLException
  {
    // XXX-Not Implemented
    return false;
  }
973

Peter Mount's avatar
Peter Mount committed
974 975 976 977 978
  public boolean supportsSubqueriesInComparisons() throws SQLException
  {
    // XXX-Not Implemented
    return false;
  }
979

Peter Mount's avatar
Peter Mount committed
980 981 982 983 984
  public boolean supportsSubqueriesInExists() throws SQLException
  {
    // XXX-Not Implemented
    return false;
  }
985

Peter Mount's avatar
Peter Mount committed
986 987 988 989 990
  public boolean supportsSubqueriesInIns() throws SQLException
  {
    // XXX-Not Implemented
    return false;
  }
991

Peter Mount's avatar
Peter Mount committed
992 993 994 995 996
  public boolean supportsSubqueriesInQuantifieds() throws SQLException
  {
    // XXX-Not Implemented
    return false;
  }
997

Peter Mount's avatar
Peter Mount committed
998 999 1000 1001 1002
  public boolean supportsCorrelatedSubqueries() throws SQLException
  {
    // XXX-Not Implemented
    return false;
  }
1003

Peter Mount's avatar
Peter Mount committed
1004 1005 1006 1007 1008 1009 1010 1011
  /**
   * Is SQL UNION supported?  Nope.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsUnion() throws SQLException
  {
1012
    return true; // 7.0?
Peter Mount's avatar
Peter Mount committed
1013
  }
1014

Peter Mount's avatar
Peter Mount committed
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
  /**
   * Is SQL UNION ALL supported?  Nope.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsUnionAll() throws SQLException
  {
    return false;
  }
1025

Peter Mount's avatar
Peter Mount committed
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
  /**
   * In PostgreSQL, Cursors are only open within transactions.
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsOpenCursorsAcrossCommit() throws SQLException
  {
    return false;
  }
1036

Peter Mount's avatar
Peter Mount committed
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
  /**
   * Do we support open cursors across multiple transactions?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsOpenCursorsAcrossRollback() throws SQLException
  {
    return false;
  }
1047

Peter Mount's avatar
Peter Mount committed
1048 1049 1050
  /**
   * Can statements remain open across commits?  They may, but
   * this driver cannot guarentee that.  In further reflection.
1051
   * we are talking a Statement object here, so the answer is
Peter Mount's avatar
Peter Mount committed
1052 1053 1054 1055 1056 1057 1058 1059 1060
   * yes, since the Statement is only a vehicle to ExecSQL()
   *
   * @return true if they always remain open; false otherwise
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsOpenStatementsAcrossCommit() throws SQLException
  {
    return true;
  }
1061

Peter Mount's avatar
Peter Mount committed
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
  /**
   * Can statements remain open across rollbacks?  They may, but
   * this driver cannot guarentee that.  In further contemplation,
   * we are talking a Statement object here, so the answer is yes,
   * since the Statement is only a vehicle to ExecSQL() in Connection
   *
   * @return true if they always remain open; false otherwise
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsOpenStatementsAcrossRollback() throws SQLException
  {
    return true;
  }
1075

Peter Mount's avatar
Peter Mount committed
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
  /**
   * How many hex characters can you have in an inline binary literal
   *
   * @return the max literal length
   * @exception SQLException if a database access error occurs
   */
  public int getMaxBinaryLiteralLength() throws SQLException
  {
    return 0;				// For now...
  }
1086

Peter Mount's avatar
Peter Mount committed
1087 1088 1089 1090 1091 1092 1093 1094 1095
  /**
   * What is the maximum length for a character literal
   * I suppose it is 8190 (8192 - 2 for the quotes)
   *
   * @return the max literal length
   * @exception SQLException if a database access error occurs
   */
  public int getMaxCharLiteralLength() throws SQLException
  {
1096
    return 65535;
Peter Mount's avatar
Peter Mount committed
1097
  }
1098

Peter Mount's avatar
Peter Mount committed
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
  /**
   * Whats the limit on column name length.  The description of
   * pg_class would say '32' (length of pg_class.relname) - we
   * should probably do a query for this....but....
   *
   * @return the maximum column name length
   * @exception SQLException if a database access error occurs
   */
  public int getMaxColumnNameLength() throws SQLException
  {
    return 32;
  }
1111

Peter Mount's avatar
Peter Mount committed
1112 1113 1114 1115
  /**
   * What is the maximum number of columns in a "GROUP BY" clause?
   *
   * @return the max number of columns
1116
   * @exception SQLException if a database access error occurs
Peter Mount's avatar
Peter Mount committed
1117 1118 1119 1120 1121
   */
  public int getMaxColumnsInGroupBy() throws SQLException
  {
    return getMaxColumnsInTable();
  }
1122

Peter Mount's avatar
Peter Mount committed
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134
  /**
   * What's the maximum number of columns allowed in an index?
   * 6.0 only allowed one column, but 6.1 introduced multi-column
   * indices, so, theoretically, its all of them.
   *
   * @return max number of columns
   * @exception SQLException if a database access error occurs
   */
  public int getMaxColumnsInIndex() throws SQLException
  {
    return getMaxColumnsInTable();
  }
1135

Peter Mount's avatar
Peter Mount committed
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146
  /**
   * What's the maximum number of columns in an "ORDER BY clause?
   * Theoretically, all of them!
   *
   * @return the max columns
   * @exception SQLException if a database access error occurs
   */
  public int getMaxColumnsInOrderBy() throws SQLException
  {
    return getMaxColumnsInTable();
  }
1147

Peter Mount's avatar
Peter Mount committed
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
  /**
   * What is the maximum number of columns in a "SELECT" list?
   * Theoretically, all of them!
   *
   * @return the max columns
   * @exception SQLException if a database access error occurs
   */
  public int getMaxColumnsInSelect() throws SQLException
  {
    return getMaxColumnsInTable();
  }
1159

Peter Mount's avatar
Peter Mount committed
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
  /**
   * What is the maximum number of columns in a table? From the
   * create_table(l) manual page...
   *
   * <p>"The new class is created as a heap with no initial data.  A
   * class can have no more than 1600 attributes (realistically,
   * this is limited by the fact that tuple sizes must be less than
   * 8192 bytes)..."
   *
   * @return the max columns
   * @exception SQLException if a database access error occurs
   */
  public int getMaxColumnsInTable() throws SQLException
  {
    return 1600;
  }
1176

Peter Mount's avatar
Peter Mount committed
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
  /**
   * How many active connection can we have at a time to this
   * database?  Well, since it depends on postmaster, which just
   * does a listen() followed by an accept() and fork(), its
   * basically very high.  Unless the system runs out of processes,
   * it can be 65535 (the number of aux. ports on a TCP/IP system).
   * I will return 8192 since that is what even the largest system
   * can realistically handle,
   *
   * @return the maximum number of connections
   * @exception SQLException if a database access error occurs
   */
  public int getMaxConnections() throws SQLException
  {
    return 8192;
  }
1193

Peter Mount's avatar
Peter Mount committed
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
  /**
   * What is the maximum cursor name length (the same as all
   * the other F***** identifiers!)
   *
   * @return max cursor name length in bytes
   * @exception SQLException if a database access error occurs
   */
  public int getMaxCursorNameLength() throws SQLException
  {
    return 32;
  }
1205

Peter Mount's avatar
Peter Mount committed
1206 1207
  /**
   * What is the maximum length of an index (in bytes)?  Now, does
1208
   * the spec. mean name of an index (in which case its 32, the
Peter Mount's avatar
Peter Mount committed
1209 1210
   * same as a table) or does it mean length of an index element
   * (in which case its 8192, the size of a row) or does it mean
1211
   * the number of rows it can access (in which case it 2^32 -
Peter Mount's avatar
Peter Mount committed
1212 1213 1214 1215 1216 1217 1218 1219
   * a 4 byte OID number)?  I think its the length of an index
   * element, personally, so Im setting it to 8192.
   *
   * @return max index length in bytes
   * @exception SQLException if a database access error occurs
   */
  public int getMaxIndexLength() throws SQLException
  {
1220
    return 65535;
Peter Mount's avatar
Peter Mount committed
1221
  }
1222

Peter Mount's avatar
Peter Mount committed
1223 1224 1225 1226 1227
  public int getMaxSchemaNameLength() throws SQLException
  {
    // XXX-Not Implemented
    return 0;
  }
1228

Peter Mount's avatar
Peter Mount committed
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240
  /**
   * What is the maximum length of a procedure name?
   * (length of pg_proc.proname used) - again, I really
   * should do a query here to get it.
   *
   * @return the max name length in bytes
   * @exception SQLException if a database access error occurs
   */
  public int getMaxProcedureNameLength() throws SQLException
  {
    return 32;
  }
1241

Peter Mount's avatar
Peter Mount committed
1242 1243 1244 1245 1246
  public int getMaxCatalogNameLength() throws SQLException
  {
    // XXX-Not Implemented
    return 0;
  }
1247

Peter Mount's avatar
Peter Mount committed
1248 1249
  /**
   * What is the maximum length of a single row?  (not including
1250
   * blobs).  65535 is defined in PostgreSQL.
Peter Mount's avatar
Peter Mount committed
1251 1252 1253 1254 1255 1256
   *
   * @return max row size in bytes
   * @exception SQLException if a database access error occurs
   */
  public int getMaxRowSize() throws SQLException
  {
1257
    return 65535;
Peter Mount's avatar
Peter Mount committed
1258
  }
1259

Peter Mount's avatar
Peter Mount committed
1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
  /**
   * Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY
   * blobs?  We don't handle blobs yet
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean doesMaxRowSizeIncludeBlobs() throws SQLException
  {
    return false;
  }
1271

Peter Mount's avatar
Peter Mount committed
1272 1273 1274 1275 1276 1277 1278 1279
  /**
   * What is the maximum length of a SQL statement?
   *
   * @return max length in bytes
   * @exception SQLException if a database access error occurs
   */
  public int getMaxStatementLength() throws SQLException
  {
1280
    return 65535;
Peter Mount's avatar
Peter Mount committed
1281
  }
1282

Peter Mount's avatar
Peter Mount committed
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297
  /**
   * How many active statements can we have open at one time to
   * this database?  Basically, since each Statement downloads
   * the results as the query is executed, we can have many.  However,
   * we can only really have one statement per connection going
   * at once (since they are executed serially) - so we return
   * one.
   *
   * @return the maximum
   * @exception SQLException if a database access error occurs
   */
  public int getMaxStatements() throws SQLException
  {
    return 1;
  }
1298

Peter Mount's avatar
Peter Mount committed
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
  /**
   * What is the maximum length of a table name?  This was found
   * from pg_class.relname length
   *
   * @return max name length in bytes
   * @exception SQLException if a database access error occurs
   */
  public int getMaxTableNameLength() throws SQLException
  {
    return 32;
  }
1310

Peter Mount's avatar
Peter Mount committed
1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
  /**
   * What is the maximum number of tables that can be specified
   * in a SELECT?  Theoretically, this is the same number as the
   * number of tables allowable.  In practice tho, it is much smaller
   * since the number of tables is limited by the statement, we
   * return 1024 here - this is just a number I came up with (being
   * the number of tables roughly of three characters each that you
   * can fit inside a 8192 character buffer with comma separators).
   *
   * @return the maximum
   * @exception SQLException if a database access error occurs
   */
  public int getMaxTablesInSelect() throws SQLException
  {
    return 1024;
  }
1327

Peter Mount's avatar
Peter Mount committed
1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
  /**
   * What is the maximum length of a user name?  Well, we generally
   * use UNIX like user names in PostgreSQL, so I think this would
   * be 8.  However, showing the schema for pg_user shows a length
   * for username of 32.
   *
   * @return the max name length in bytes
   * @exception SQLException if a database access error occurs
   */
  public int getMaxUserNameLength() throws SQLException
  {
    return 32;
  }
1341 1342


Peter Mount's avatar
Peter Mount committed
1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354
  /**
   * What is the database's default transaction isolation level?  We
   * do not support this, so all transactions are SERIALIZABLE.
   *
   * @return the default isolation level
   * @exception SQLException if a database access error occurs
   * @see Connection
   */
  public int getDefaultTransactionIsolation() throws SQLException
  {
      return Connection.TRANSACTION_READ_COMMITTED;
  }
1355

Peter Mount's avatar
Peter Mount committed
1356 1357 1358
  /**
   * Are transactions supported?  If not, commit and rollback are noops
   * and the isolation level is TRANSACTION_NONE.  We do support
1359
   * transactions.
Peter Mount's avatar
Peter Mount committed
1360 1361 1362 1363 1364 1365 1366 1367
   *
   * @return true if transactions are supported
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsTransactions() throws SQLException
  {
    return true;
  }
1368

Peter Mount's avatar
Peter Mount committed
1369 1370 1371
  /**
   * Does the database support the given transaction isolation level?
   * We only support TRANSACTION_SERIALIZABLE and TRANSACTION_READ_COMMITTED
1372
   *
Peter Mount's avatar
Peter Mount committed
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385
   * @param level the values are defined in java.sql.Connection
   * @return true if so
   * @exception SQLException if a database access error occurs
   * @see Connection
   */
  public boolean supportsTransactionIsolationLevel(int level) throws SQLException
  {
    if (level == Connection.TRANSACTION_SERIALIZABLE ||
        level == Connection.TRANSACTION_READ_COMMITTED)
      return true;
    else
      return false;
  }
1386

Peter Mount's avatar
Peter Mount committed
1387
  /**
1388
   * Are both data definition and data manipulation transactions
Peter Mount's avatar
Peter Mount committed
1389 1390 1391 1392 1393 1394 1395 1396 1397 1398
   * supported?  I checked it, and could not do a CREATE TABLE
   * within a transaction, so I am assuming that we don't
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException
  {
    return false;
  }
1399

Peter Mount's avatar
Peter Mount committed
1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410
  /**
   * Are only data manipulation statements withing a transaction
   * supported?
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean supportsDataManipulationTransactionsOnly() throws SQLException
  {
    return true;
  }
1411

Peter Mount's avatar
Peter Mount committed
1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
  /**
   * Does a data definition statement within a transaction force
   * the transaction to commit?  I think this means something like:
   *
   * <p><pre>
   * CREATE TABLE T (A INT);
   * INSERT INTO T (A) VALUES (2);
   * BEGIN;
   * UPDATE T SET A = A + 1;
   * CREATE TABLE X (A INT);
   * SELECT A FROM T INTO X;
   * COMMIT;
   * </pre><p>
   *
1426
   * does the CREATE TABLE call cause a commit?  The answer is no.
Peter Mount's avatar
Peter Mount committed
1427 1428 1429 1430 1431 1432 1433 1434
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean dataDefinitionCausesTransactionCommit() throws SQLException
  {
    return false;
  }
1435

Peter Mount's avatar
Peter Mount committed
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446
  /**
   * Is a data definition statement within a transaction ignored?
   * It seems to be (from experiment in previous method)
   *
   * @return true if so
   * @exception SQLException if a database access error occurs
   */
  public boolean dataDefinitionIgnoredInTransactions() throws SQLException
  {
    return true;
  }
1447

Peter Mount's avatar
Peter Mount committed
1448 1449
  /**
   * Get a description of stored procedures available in a catalog
1450
   *
Peter Mount's avatar
Peter Mount committed
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485
   * <p>Only procedure descriptions matching the schema and procedure
   * name criteria are returned.  They are ordered by PROCEDURE_SCHEM
   * and PROCEDURE_NAME
   *
   * <p>Each procedure description has the following columns:
   * <ol>
   * <li><b>PROCEDURE_CAT</b> String => procedure catalog (may be null)
   * <li><b>PROCEDURE_SCHEM</b> String => procedure schema (may be null)
   * <li><b>PROCEDURE_NAME</b> String => procedure name
   * <li><b>Field 4</b> reserved (make it null)
   * <li><b>Field 5</b> reserved (make it null)
   * <li><b>Field 6</b> reserved (make it null)
   * <li><b>REMARKS</b> String => explanatory comment on the procedure
   * <li><b>PROCEDURE_TYPE</b> short => kind of procedure
   *	<ul>
   *    <li> procedureResultUnknown - May return a result
   * 	<li> procedureNoResult - Does not return a result
   *	<li> procedureReturnsResult - Returns a result
   *    </ul>
   * </ol>
   *
   * @param catalog - a catalog name; "" retrieves those without a
   *	catalog; null means drop catalog name from criteria
   * @param schemaParrern - a schema name pattern; "" retrieves those
   *	without a schema - we ignore this parameter
   * @param procedureNamePattern - a procedure name pattern
   * @return ResultSet - each row is a procedure description
   * @exception SQLException if a database access error occurs
   */
  public java.sql.ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException
  {
    // the field descriptors for the new ResultSet
    Field f[] = new Field[8];
    java.sql.ResultSet r;	// ResultSet for the SQL query that we need to do
    Vector v = new Vector();		// The new ResultSet tuple stuff
1486

Peter Mount's avatar
Peter Mount committed
1487
    byte remarks[] = defaultRemarks;
1488

Peter Mount's avatar
Peter Mount committed
1489 1490 1491 1492 1493 1494
    f[0] = new Field(connection, "PROCEDURE_CAT",   iVarcharOid, 32);
    f[1] = new Field(connection, "PROCEDURE_SCHEM", iVarcharOid, 32);
    f[2] = new Field(connection, "PROCEDURE_NAME",  iVarcharOid, 32);
    f[3] = f[4] = f[5] = null;	// reserved, must be null for now
    f[6] = new Field(connection, "REMARKS",	   iVarcharOid, 8192);
    f[7] = new Field(connection, "PROCEDURE_TYPE", iInt2Oid,	2);
1495

Peter Mount's avatar
Peter Mount committed
1496 1497 1498
    // If the pattern is null, then set it to the default
    if(procedureNamePattern==null)
      procedureNamePattern="%";
1499

1500
    r = connection.ExecSQL("select proname, proretset from pg_proc where proname like '"+procedureNamePattern.toLowerCase()+"' order by proname");
1501

Peter Mount's avatar
Peter Mount committed
1502 1503 1504
    while (r.next())
      {
	byte[][] tuple = new byte[8][0];
1505

Peter Mount's avatar
Peter Mount committed
1506 1507 1508 1509 1510
	tuple[0] = null;			// Catalog name
	tuple[1] = null;			// Schema name
	tuple[2] = r.getBytes(1);		// Procedure name
	tuple[3] = tuple[4] = tuple[5] = null;	// Reserved
	tuple[6] = remarks;			// Remarks
1511

Peter Mount's avatar
Peter Mount committed
1512 1513 1514 1515
	if (r.getBoolean(2))
	  tuple[7] = Integer.toString(java.sql.DatabaseMetaData.procedureReturnsResult).getBytes();
	else
	  tuple[7] = Integer.toString(java.sql.DatabaseMetaData.procedureNoResult).getBytes();
1516

Peter Mount's avatar
Peter Mount committed
1517 1518 1519 1520
	v.addElement(tuple);
      }
    return new ResultSet(connection, f, v, "OK", 1);
  }
1521

Peter Mount's avatar
Peter Mount committed
1522 1523 1524 1525 1526 1527 1528 1529 1530 1531
  /**
   * Get a description of a catalog's stored procedure parameters
   * and result columns.
   *
   * <p>Only descriptions matching the schema, procedure and parameter
   * name criteria are returned. They are ordered by PROCEDURE_SCHEM
   * and PROCEDURE_NAME. Within this, the return value, if any, is
   * first. Next are the parameter descriptions in call order. The
   * column descriptions follow in column number order.
   *
1532
   * <p>Each row in the ResultSet is a parameter description or column
Peter Mount's avatar
Peter Mount committed
1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571
   * description with the following fields:
   * <ol>
   * <li><b>PROCEDURE_CAT</b> String => procedure catalog (may be null)
   * <li><b>PROCEDURE_SCHE</b>M String => procedure schema (may be null)
   * <li><b>PROCEDURE_NAME</b> String => procedure name
   * <li><b>COLUMN_NAME</b> String => column/parameter name
   * <li><b>COLUMN_TYPE</b> Short => kind of column/parameter:
   * <ul><li>procedureColumnUnknown - nobody knows
   * <li>procedureColumnIn - IN parameter
   * <li>procedureColumnInOut - INOUT parameter
   * <li>procedureColumnOut - OUT parameter
   * <li>procedureColumnReturn - procedure return value
   * <li>procedureColumnResult - result column in ResultSet
   * </ul>
   * <li><b>DATA_TYPE</b> short => SQL type from java.sql.Types
   * <li><b>TYPE_NAME</b> String => SQL type name
   * <li><b>PRECISION</b> int => precision
   * <li><b>LENGTH</b> int => length in bytes of data
   * <li><b>SCALE</b> short => scale
   * <li><b>RADIX</b> short => radix
   * <li><b>NULLABLE</b> short => can it contain NULL?
   * <ul><li>procedureNoNulls - does not allow NULL values
   * <li>procedureNullable - allows NULL values
   * <li>procedureNullableUnknown - nullability unknown
   * <li><b>REMARKS</b> String => comment describing parameter/column
   * </ol>
   * @param catalog This is ignored in org.postgresql, advise this is set to null
   * @param schemaPattern This is ignored in org.postgresql, advise this is set to null
   * @param procedureNamePattern a procedure name pattern
   * @param columnNamePattern a column name pattern
   * @return each row is a stored procedure parameter or column description
   * @exception SQLException if a database-access error occurs
   * @see #getSearchStringEscape
   */
  // Implementation note: This is required for Borland's JBuilder to work
  public java.sql.ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException
  {
    if(procedureNamePattern==null)
      procedureNamePattern="%";
1572

Peter Mount's avatar
Peter Mount committed
1573 1574
    if(columnNamePattern==null)
      columnNamePattern="%";
1575

Peter Mount's avatar
Peter Mount committed
1576 1577 1578 1579
    // for now, this returns an empty result set.
    Field f[] = new Field[13];
    ResultSet r;	// ResultSet for the SQL query that we need to do
    Vector v = new Vector();		// The new ResultSet tuple stuff
1580

1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593
    f[0] = new Field(connection, "PROCEDURE_CAT", iVarcharOid, 32);
    f[1] = new Field(connection, "PROCEDURE_SCHEM", iVarcharOid, 32);
    f[2] = new Field(connection, "PROCEDURE_NAME", iVarcharOid, 32);
    f[3] = new Field(connection, "COLUMN_NAME", iVarcharOid, 32);
    f[4] = new Field(connection, "COLUMN_TYPE", iInt2Oid, 2);
    f[5] = new Field(connection, "DATA_TYPE", iInt2Oid, 2);
    f[6] = new Field(connection, "TYPE_NAME", iVarcharOid, 32);
    f[7] = new Field(connection, "PRECISION", iInt4Oid, 4);
    f[8] = new Field(connection, "LENGTH", iInt4Oid, 4);
    f[9] = new Field(connection, "SCALE", iInt2Oid, 2);
    f[10] = new Field(connection, "RADIX", iInt2Oid, 2);
    f[11] = new Field(connection, "NULLABLE", iInt2Oid, 2);
    f[12] = new Field(connection, "REMARKS", iVarcharOid, 32);
1594

Peter Mount's avatar
Peter Mount committed
1595
    // add query loop here
1596

Peter Mount's avatar
Peter Mount committed
1597 1598
    return new ResultSet(connection, f, v, "OK", 1);
  }
1599

Peter Mount's avatar
Peter Mount committed
1600
  /**
1601
   * Get a description of tables available in a catalog.
Peter Mount's avatar
Peter Mount committed
1602 1603 1604
   *
   * <p>Only table descriptions matching the catalog, schema, table
   * name and type criteria are returned. They are ordered by
1605 1606 1607
   * TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.
   *
   * <p>Each table description has the following columns:
Peter Mount's avatar
Peter Mount committed
1608 1609
   *
   * <ol>
1610 1611
   * <li><b>TABLE_CAT</b> String => table catalog (may be null)
   * <li><b>TABLE_SCHEM</b> String => table schema (may be null)
Peter Mount's avatar
Peter Mount committed
1612 1613 1614
   * <li><b>TABLE_NAME</b> String => table name
   * <li><b>TABLE_TYPE</b> String => table type. Typical types are "TABLE",
   * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL
1615
   * TEMPORARY", "ALIAS", "SYNONYM".
Peter Mount's avatar
Peter Mount committed
1616 1617 1618 1619
   * <li><b>REMARKS</b> String => explanatory comment on the table
   * </ol>
   *
   * <p>The valid values for the types parameter are:
1620
   * "TABLE", "INDEX", "SEQUENCE", "SYSTEM TABLE" and "SYSTEM INDEX"
Peter Mount's avatar
Peter Mount committed
1621 1622 1623 1624 1625 1626 1627 1628
   *
   * @param catalog a catalog name; For org.postgresql, this is ignored, and
   * should be set to null
   * @param schemaPattern a schema name pattern; For org.postgresql, this is ignored, and
   * should be set to null
   * @param tableNamePattern a table name pattern. For all tables this should be "%"
   * @param types a list of table types to include; null returns
   * all types
1629
   * @return each row is a table description
Peter Mount's avatar
Peter Mount committed
1630 1631 1632 1633 1634 1635 1636
   * @exception SQLException if a database-access error occurs.
   */
  public java.sql.ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String types[]) throws SQLException
  {
    // Handle default value for types
    if(types==null)
      types = defaultTableTypes;
1637

Peter Mount's avatar
Peter Mount committed
1638 1639
    if(tableNamePattern==null)
      tableNamePattern="%";
1640

Peter Mount's avatar
Peter Mount committed
1641 1642 1643 1644
    // the field descriptors for the new ResultSet
    Field f[] = new Field[5];
    java.sql.ResultSet r;	// ResultSet for the SQL query that we need to do
    Vector v = new Vector();		// The new ResultSet tuple stuff
1645

1646 1647 1648 1649 1650
    f[0] = new Field(connection, "TABLE_CAT", iVarcharOid, 32);
    f[1] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32);
    f[2] = new Field(connection, "TABLE_NAME", iVarcharOid, 32);
    f[3] = new Field(connection, "TABLE_TYPE", iVarcharOid, 32);
    f[4] = new Field(connection, "REMARKS", iVarcharOid, 32);
1651

Peter Mount's avatar
Peter Mount committed
1652
    // Now form the query
Bruce Momjian's avatar
Bruce Momjian committed
1653
    StringBuffer sql = new StringBuffer("select relname,oid,relkind from pg_class where (");
Peter Mount's avatar
Peter Mount committed
1654 1655 1656 1657
    boolean notFirst=false;
    for(int i=0;i<types.length;i++) {
      for(int j=0;j<getTableTypes.length;j++)
	if(getTableTypes[j][0].equals(types[i])) {
1658 1659
	  if(notFirst)
	    sql.append(" or ");
Peter Mount's avatar
Peter Mount committed
1660 1661 1662 1663
	  sql.append(getTableTypes[j][1]);
	  notFirst=true;
	}
    }
1664

Peter Mount's avatar
Peter Mount committed
1665 1666 1667 1668
    // Added by Stefan Andreasen <stefan@linux.kapow.dk>
    // Now take the pattern into account
    sql.append(") and relname like '");
    sql.append(tableNamePattern.toLowerCase());
1669
    sql.append("' order by relkind, relname");
1670

Peter Mount's avatar
Peter Mount committed
1671
    // Now run the query
1672
    r = connection.ExecSQL(sql.toString());
1673

Peter Mount's avatar
Peter Mount committed
1674
    byte remarks[];
1675

Peter Mount's avatar
Peter Mount committed
1676 1677 1678
    while (r.next())
      {
	byte[][] tuple = new byte[5][0];
1679

Peter Mount's avatar
Peter Mount committed
1680
	// Fetch the description for the table (if any)
1681
	java.sql.ResultSet dr = connection.ExecSQL("select description from pg_description where objoid="+r.getInt(2));
Peter Mount's avatar
Peter Mount committed
1682 1683 1684 1685 1686 1687
	if(((org.postgresql.ResultSet)dr).getTupleCount()==1) {
	  dr.next();
	  remarks = dr.getBytes(1);
	} else
	  remarks = defaultRemarks;
	dr.close();
1688

Bruce Momjian's avatar
Bruce Momjian committed
1689 1690
	String relKind;
	switch (r.getBytes(3)[0]) {
1691
	case (byte) 'r':
Bruce Momjian's avatar
Bruce Momjian committed
1692 1693
	    relKind = "TABLE";
	    break;
1694
	case (byte) 'i':
Bruce Momjian's avatar
Bruce Momjian committed
1695 1696
	    relKind = "INDEX";
	    break;
1697
	case (byte) 'S':
Bruce Momjian's avatar
Bruce Momjian committed
1698 1699
	    relKind = "SEQUENCE";
	    break;
1700
	case (byte) 'v':
1701 1702
	    relKind = "VIEW";
	    break;
Bruce Momjian's avatar
Bruce Momjian committed
1703 1704 1705 1706
	default:
	    relKind = null;
	}

Peter Mount's avatar
Peter Mount committed
1707 1708
	tuple[0] = null;		// Catalog name
	tuple[1] = null;		// Schema name
1709
	tuple[2] = r.getBytes(1);	// Table name
1710
	tuple[3] = (relKind==null) ? null : relKind.getBytes();	// Table type
Peter Mount's avatar
Peter Mount committed
1711 1712 1713 1714 1715 1716
	tuple[4] = remarks;		// Remarks
	v.addElement(tuple);
      }
    r.close();
    return new ResultSet(connection, f, v, "OK", 1);
  }
1717

Peter Mount's avatar
Peter Mount committed
1718 1719 1720 1721 1722 1723 1724 1725
  // This array contains the valid values for the types argument
  // in getTables().
  //
  // Each supported type consists of it's name, and the sql where
  // clause to retrieve that value.
  //
  // IMPORTANT: the query must be enclosed in ( )
  private static final String getTableTypes[][] = {
1726
    {"TABLE",		"(relkind='r' and relhasrules='f' and relname !~ '^pg_' and relname !~ '^xinv')"},
1727 1728
    {"VIEW",        "(relkind='v' and relname !~ '^pg_')"},
    {"INDEX",		"(relkind='i' and relname !~ '^pg_')"},
Peter Mount's avatar
Peter Mount committed
1729 1730 1731 1732
    {"SEQUENCE",	"(relkind='S' and relname !~ '^pg_')"},
    {"SYSTEM TABLE",	"(relkind='r' and relname ~ '^pg_')"},
    {"SYSTEM INDEX",	"(relkind='i' and relname ~ '^pg_')"}
  };
1733

Peter Mount's avatar
Peter Mount committed
1734 1735 1736
  // These are the default tables, used when NULL is passed to getTables
  // The choice of these provide the same behaviour as psql's \d
  private static final String defaultTableTypes[] = {
1737
    "TABLE","VIEW","INDEX","SEQUENCE"
Peter Mount's avatar
Peter Mount committed
1738
  };
1739

Peter Mount's avatar
Peter Mount committed
1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758
  /**
   * Get the schema names available in this database.  The results
   * are ordered by schema name.
   *
   * <P>The schema column is:
   *  <OL>
   *	<LI><B>TABLE_SCHEM</B> String => schema name
   *  </OL>
   *
   * @return ResultSet each row has a single String column that is a
   * schema name
   */
  public java.sql.ResultSet getSchemas() throws SQLException
  {
    // We don't use schemas, so we simply return a single schema name "".
    //
    Field f[] = new Field[1];
    Vector v = new Vector();
    byte[][] tuple = new byte[1][0];
1759
    f[0] = new Field(connection,"TABLE_SCHEM",iVarcharOid,32);
Peter Mount's avatar
Peter Mount committed
1760 1761 1762 1763
    tuple[0] = "".getBytes();
    v.addElement(tuple);
    return new ResultSet(connection,f,v,"OK",1);
  }
1764

Peter Mount's avatar
Peter Mount committed
1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782
  /**
   * Get the catalog names available in this database.  The results
   * are ordered by catalog name.
   *
   * <P>The catalog column is:
   *  <OL>
   *	<LI><B>TABLE_CAT</B> String => catalog name
   *  </OL>
   *
   * @return ResultSet each row has a single String column that is a
   * catalog name
   */
  public java.sql.ResultSet getCatalogs() throws SQLException
  {
    // We don't use catalogs, so we simply return a single catalog name "".
    Field f[] = new Field[1];
    Vector v = new Vector();
    byte[][] tuple = new byte[1][0];
1783
    f[0] = new Field(connection,"TABLE_CAT",iVarcharOid,32);
Peter Mount's avatar
Peter Mount committed
1784 1785 1786 1787
    tuple[0] = "".getBytes();
    v.addElement(tuple);
    return new ResultSet(connection,f,v,"OK",1);
  }
1788

Peter Mount's avatar
Peter Mount committed
1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808
  /**
   * Get the table types available in this database.  The results
   * are ordered by table type.
   *
   * <P>The table type is:
   *  <OL>
   *	<LI><B>TABLE_TYPE</B> String => table type.  Typical types are "TABLE",
   *			"VIEW",	"SYSTEM TABLE", "GLOBAL TEMPORARY",
   *			"LOCAL TEMPORARY", "ALIAS", "SYNONYM".
   *  </OL>
   *
   * @return ResultSet each row has a single String column that is a
   * table type
   */
  public java.sql.ResultSet getTableTypes() throws SQLException
  {
    Field f[] = new Field[1];
    Vector v = new Vector();
    f[0] = new Field(connection,new String("TABLE_TYPE"),iVarcharOid,32);
    for(int i=0;i<getTableTypes.length;i++) {
1809
      byte[][] tuple = new byte[2][0];
Peter Mount's avatar
Peter Mount committed
1810 1811 1812 1813 1814
      tuple[0] = getTableTypes[i][0].getBytes();
      v.addElement(tuple);
    }
    return new ResultSet(connection,f,v,"OK",1);
  }
1815

Peter Mount's avatar
Peter Mount committed
1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869
  /**
   * Get a description of table columns available in a catalog.
   *
   * <P>Only column descriptions matching the catalog, schema, table
   * and column name criteria are returned.  They are ordered by
   * TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.
   *
   * <P>Each column description has the following columns:
   *  <OL>
   *	<LI><B>TABLE_CAT</B> String => table catalog (may be null)
   *	<LI><B>TABLE_SCHEM</B> String => table schema (may be null)
   *	<LI><B>TABLE_NAME</B> String => table name
   *	<LI><B>COLUMN_NAME</B> String => column name
   *	<LI><B>DATA_TYPE</B> short => SQL type from java.sql.Types
   *	<LI><B>TYPE_NAME</B> String => Data source dependent type name
   *	<LI><B>COLUMN_SIZE</B> int => column size.  For char or date
   *	    types this is the maximum number of characters, for numeric or
   *	    decimal types this is precision.
   *	<LI><B>BUFFER_LENGTH</B> is not used.
   *	<LI><B>DECIMAL_DIGITS</B> int => the number of fractional digits
   *	<LI><B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
   *	<LI><B>NULLABLE</B> int => is NULL allowed?
   *      <UL>
   *      <LI> columnNoNulls - might not allow NULL values
   *      <LI> columnNullable - definitely allows NULL values
   *      <LI> columnNullableUnknown - nullability unknown
   *      </UL>
   *	<LI><B>REMARKS</B> String => comment describing column (may be null)
   * 	<LI><B>COLUMN_DEF</B> String => default value (may be null)
   *	<LI><B>SQL_DATA_TYPE</B> int => unused
   *	<LI><B>SQL_DATETIME_SUB</B> int => unused
   *	<LI><B>CHAR_OCTET_LENGTH</B> int => for char types the
   *       maximum number of bytes in the column
   *	<LI><B>ORDINAL_POSITION</B> int	=> index of column in table
   *      (starting at 1)
   *	<LI><B>IS_NULLABLE</B> String => "NO" means column definitely
   *      does not allow NULL values; "YES" means the column might
   *      allow NULL values.  An empty string means nobody knows.
   *  </OL>
   *
   * @param catalog a catalog name; "" retrieves those without a catalog
   * @param schemaPattern a schema name pattern; "" retrieves those
   * without a schema
   * @param tableNamePattern a table name pattern
   * @param columnNamePattern a column name pattern
   * @return ResultSet each row is a column description
   * @see #getSearchStringEscape
   */
  public java.sql.ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException
  {
    // the field descriptors for the new ResultSet
    Field f[] = new Field[18];
    java.sql.ResultSet r;	// ResultSet for the SQL query that we need to do
    Vector v = new Vector();		// The new ResultSet tuple stuff
1870

1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888
    f[0] = new Field(connection, "TABLE_CAT", iVarcharOid, 32);
    f[1] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32);
    f[2] = new Field(connection, "TABLE_NAME", iVarcharOid, 32);
    f[3] = new Field(connection, "COLUMN_NAME", iVarcharOid, 32);
    f[4] = new Field(connection, "DATA_TYPE", iInt2Oid, 2);
    f[5] = new Field(connection, "TYPE_NAME", iVarcharOid, 32);
    f[6] = new Field(connection, "COLUMN_SIZE", iInt4Oid, 4);
    f[7] = new Field(connection, "BUFFER_LENGTH", iVarcharOid, 32);
    f[8] = new Field(connection, "DECIMAL_DIGITS", iInt4Oid, 4);
    f[9] = new Field(connection, "NUM_PREC_RADIX", iInt4Oid, 4);
    f[10] = new Field(connection, "NULLABLE", iInt4Oid, 4);
    f[11] = new Field(connection, "REMARKS", iVarcharOid, 32);
    f[12] = new Field(connection, "COLUMN_DEF", iVarcharOid, 32);
    f[13] = new Field(connection, "SQL_DATA_TYPE", iInt4Oid, 4);
    f[14] = new Field(connection, "SQL_DATETIME_SUB", iInt4Oid, 4);
    f[15] = new Field(connection, "CHAR_OCTET_LENGTH", iVarcharOid, 32);
    f[16] = new Field(connection, "ORDINAL_POSITION", iInt4Oid,4);
    f[17] = new Field(connection, "IS_NULLABLE", iVarcharOid, 32);
1889

Peter Mount's avatar
Peter Mount committed
1890 1891 1892 1893
    // Added by Stefan Andreasen <stefan@linux.kapow.dk>
    // If the pattern are  null then set them to %
    if (tableNamePattern == null) tableNamePattern="%";
    if (columnNamePattern == null) columnNamePattern="%";
1894

Peter Mount's avatar
Peter Mount committed
1895 1896
    // Now form the query
    // Modified by Stefan Andreasen <stefan@linux.kapow.dk>
1897
    r = connection.ExecSQL("select a.oid,c.relname,a.attname,a.atttypid,a.attnum,a.attnotnull,a.attlen,a.atttypmod from pg_class c, pg_attribute a where a.attrelid=c.oid and c.relname like '"+tableNamePattern.toLowerCase()+"' and a.attname like '"+columnNamePattern.toLowerCase()+"' and a.attnum>0 order by c.relname,a.attnum");
1898

Peter Mount's avatar
Peter Mount committed
1899
    byte remarks[];
1900

Peter Mount's avatar
Peter Mount committed
1901 1902
    while(r.next()) {
	byte[][] tuple = new byte[18][0];
1903

Peter Mount's avatar
Peter Mount committed
1904
	// Fetch the description for the table (if any)
1905
	java.sql.ResultSet dr = connection.ExecSQL("select description from pg_description where objoid="+r.getInt(1));
Peter Mount's avatar
Peter Mount committed
1906 1907 1908 1909 1910
	if(((org.postgresql.ResultSet)dr).getTupleCount()==1) {
	  dr.next();
	  tuple[11] = dr.getBytes(1);
	} else
	  tuple[11] = defaultRemarks;
1911

Peter Mount's avatar
Peter Mount committed
1912
	dr.close();
1913

Peter Mount's avatar
Peter Mount committed
1914 1915 1916 1917
	tuple[0] = "".getBytes();	// Catalog name
	tuple[1] = "".getBytes();	// Schema name
	tuple[2] = r.getBytes(2);	// Table name
	tuple[3] = r.getBytes(3);	// Column name
1918

1919
	dr = connection.ExecSQL("select typname from pg_type where oid = "+r.getString(4));
Peter Mount's avatar
Peter Mount committed
1920 1921 1922 1923 1924
	dr.next();
	String typname=dr.getString(1);
	dr.close();
	tuple[4] = Integer.toString(Field.getSQLType(typname)).getBytes();	// Data type
	tuple[5] = typname.getBytes();	// Type name
1925

Peter Mount's avatar
Peter Mount committed
1926 1927 1928 1929 1930 1931 1932 1933 1934
	// Column size
	// Looking at the psql source,
	// I think the length of a varchar as specified when the table was created
	// should be extracted from atttypmod which contains this length + sizeof(int32)
	if (typname.equals("bpchar") || typname.equals("varchar")) {
	  int atttypmod = r.getInt(8);
	  tuple[6] = Integer.toString(atttypmod != -1 ? atttypmod - VARHDRSZ : 0).getBytes();
	} else
	  tuple[6] = r.getBytes(7);
1935

Peter Mount's avatar
Peter Mount committed
1936
	tuple[7] = null;	// Buffer length
1937

Peter Mount's avatar
Peter Mount committed
1938 1939
	tuple[8] = "0".getBytes();	// Decimal Digits - how to get this?
	tuple[9] = "10".getBytes();	// Num Prec Radix - assume decimal
1940

Peter Mount's avatar
Peter Mount committed
1941 1942
	// tuple[10] is below
	// tuple[11] is above
1943

Peter Mount's avatar
Peter Mount committed
1944
	tuple[12] = null;	// column default
1945

Peter Mount's avatar
Peter Mount committed
1946 1947
	tuple[13] = null;	// sql data type (unused)
	tuple[14] = null;	// sql datetime sub (unused)
1948

Peter Mount's avatar
Peter Mount committed
1949
	tuple[15] = tuple[6];	// char octet length
1950

Peter Mount's avatar
Peter Mount committed
1951
	tuple[16] = r.getBytes(5);	// ordinal position
1952

Peter Mount's avatar
Peter Mount committed
1953 1954 1955
	String nullFlag = r.getString(6);
	tuple[10] = Integer.toString(nullFlag.equals("f")?java.sql.DatabaseMetaData.columnNullable:java.sql.DatabaseMetaData.columnNoNulls).getBytes();	// Nullable
	tuple[17] = (nullFlag.equals("f")?"YES":"NO").getBytes();	// is nullable
1956

Peter Mount's avatar
Peter Mount committed
1957 1958 1959 1960 1961
	v.addElement(tuple);
      }
    r.close();
    return new ResultSet(connection, f, v, "OK", 1);
  }
1962

Peter Mount's avatar
Peter Mount committed
1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993
  /**
   * Get a description of the access rights for a table's columns.
   *
   * <P>Only privileges matching the column name criteria are
   * returned.  They are ordered by COLUMN_NAME and PRIVILEGE.
   *
   * <P>Each privilige description has the following columns:
   *  <OL>
   *	<LI><B>TABLE_CAT</B> String => table catalog (may be null)
   *	<LI><B>TABLE_SCHEM</B> String => table schema (may be null)
   *	<LI><B>TABLE_NAME</B> String => table name
   *	<LI><B>COLUMN_NAME</B> String => column name
   *	<LI><B>GRANTOR</B> => grantor of access (may be null)
   *	<LI><B>GRANTEE</B> String => grantee of access
   *	<LI><B>PRIVILEGE</B> String => name of access (SELECT,
   *      INSERT, UPDATE, REFRENCES, ...)
   *	<LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
   *      to grant to others; "NO" if not; null if unknown
   *  </OL>
   *
   * @param catalog a catalog name; "" retrieves those without a catalog
   * @param schema a schema name; "" retrieves those without a schema
   * @param table a table name
   * @param columnNamePattern a column name pattern
   * @return ResultSet each row is a column privilege description
   * @see #getSearchStringEscape
   */
  public java.sql.ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException
  {
    Field f[] = new Field[8];
    Vector v = new Vector();
1994

Peter Mount's avatar
Peter Mount committed
1995 1996
    if(table==null)
      table="%";
1997

Peter Mount's avatar
Peter Mount committed
1998 1999 2000 2001
    if(columnNamePattern==null)
      columnNamePattern="%";
    else
      columnNamePattern=columnNamePattern.toLowerCase();
2002

2003 2004 2005 2006 2007 2008 2009 2010
    f[0] = new Field(connection,"TABLE_CAT",iVarcharOid,32);
    f[1] = new Field(connection,"TABLE_SCHEM",iVarcharOid,32);
    f[2] = new Field(connection,"TABLE_NAME",iVarcharOid,32);
    f[3] = new Field(connection,"COLUMN_NAME",iVarcharOid,32);
    f[4] = new Field(connection,"GRANTOR",iVarcharOid,32);
    f[5] = new Field(connection,"GRANTEE",iVarcharOid,32);
    f[6] = new Field(connection,"PRIVILEGE",iVarcharOid,32);
    f[7] = new Field(connection,"IS_GRANTABLE",iVarcharOid,32);
2011

Peter Mount's avatar
Peter Mount committed
2012
    // This is taken direct from the psql source
2013
    java.sql.ResultSet r = connection.ExecSQL("SELECT relname, relacl FROM pg_class, pg_user WHERE ( relkind = 'r' OR relkind = 'i') and relname !~ '^pg_' and relname !~ '^xin[vx][0-9]+' and usesysid = relowner and relname like '"+table.toLowerCase()+"' ORDER BY relname");
Peter Mount's avatar
Peter Mount committed
2014 2015 2016 2017
    while(r.next()) {
      byte[][] tuple = new byte[8][0];
      tuple[0] = tuple[1]= "".getBytes();
      DriverManager.println("relname=\""+r.getString(1)+"\" relacl=\""+r.getString(2)+"\"");
2018

Peter Mount's avatar
Peter Mount committed
2019 2020 2021
      // For now, don't add to the result as relacl needs to be processed.
      //v.addElement(tuple);
    }
2022

Peter Mount's avatar
Peter Mount committed
2023 2024
    return new ResultSet(connection,f,v,"OK",1);
  }
2025

Peter Mount's avatar
Peter Mount committed
2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059
  /**
   * Get a description of the access rights for each table available
   * in a catalog.
   *
   * <P>Only privileges matching the schema and table name
   * criteria are returned.  They are ordered by TABLE_SCHEM,
   * TABLE_NAME, and PRIVILEGE.
   *
   * <P>Each privilige description has the following columns:
   *  <OL>
   *	<LI><B>TABLE_CAT</B> String => table catalog (may be null)
   *	<LI><B>TABLE_SCHEM</B> String => table schema (may be null)
   *	<LI><B>TABLE_NAME</B> String => table name
   *	<LI><B>COLUMN_NAME</B> String => column name
   *	<LI><B>GRANTOR</B> => grantor of access (may be null)
   *	<LI><B>GRANTEE</B> String => grantee of access
   *	<LI><B>PRIVILEGE</B> String => name of access (SELECT,
   *      INSERT, UPDATE, REFRENCES, ...)
   *	<LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
   *      to grant to others; "NO" if not; null if unknown
   *  </OL>
   *
   * @param catalog a catalog name; "" retrieves those without a catalog
   * @param schemaPattern a schema name pattern; "" retrieves those
   * without a schema
   * @param tableNamePattern a table name pattern
   * @return ResultSet each row is a table privilege description
   * @see #getSearchStringEscape
   */
  public java.sql.ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException
  {
    // XXX-Not Implemented
    return null;
  }
2060

Peter Mount's avatar
Peter Mount committed
2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101
  /**
   * Get a description of a table's optimal set of columns that
   * uniquely identifies a row. They are ordered by SCOPE.
   *
   * <P>Each column description has the following columns:
   *  <OL>
   *	<LI><B>SCOPE</B> short => actual scope of result
   *      <UL>
   *      <LI> bestRowTemporary - very temporary, while using row
   *      <LI> bestRowTransaction - valid for remainder of current transaction
   *      <LI> bestRowSession - valid for remainder of current session
   *      </UL>
   *	<LI><B>COLUMN_NAME</B> String => column name
   *	<LI><B>DATA_TYPE</B> short => SQL data type from java.sql.Types
   *	<LI><B>TYPE_NAME</B> String => Data source dependent type name
   *	<LI><B>COLUMN_SIZE</B> int => precision
   *	<LI><B>BUFFER_LENGTH</B> int => not used
   *	<LI><B>DECIMAL_DIGITS</B> short	 => scale
   *	<LI><B>PSEUDO_COLUMN</B> short => is this a pseudo column
   *      like an Oracle ROWID
   *      <UL>
   *      <LI> bestRowUnknown - may or may not be pseudo column
   *      <LI> bestRowNotPseudo - is NOT a pseudo column
   *      <LI> bestRowPseudo - is a pseudo column
   *      </UL>
   *  </OL>
   *
   * @param catalog a catalog name; "" retrieves those without a catalog
   * @param schema a schema name; "" retrieves those without a schema
   * @param table a table name
   * @param scope the scope of interest; use same values as SCOPE
   * @param nullable include columns that are nullable?
   * @return ResultSet each row is a column description
   */
  // Implementation note: This is required for Borland's JBuilder to work
  public java.sql.ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException
  {
    // for now, this returns an empty result set.
    Field f[] = new Field[8];
    ResultSet r;	// ResultSet for the SQL query that we need to do
    Vector v = new Vector();		// The new ResultSet tuple stuff
2102

2103 2104 2105 2106 2107 2108 2109 2110
    f[0] = new Field(connection, "SCOPE", iInt2Oid, 2);
    f[1] = new Field(connection, "COLUMN_NAME", iVarcharOid, 32);
    f[2] = new Field(connection, "DATA_TYPE", iInt2Oid, 2);
    f[3] = new Field(connection, "TYPE_NAME", iVarcharOid, 32);
    f[4] = new Field(connection, "COLUMN_SIZE", iInt4Oid, 4);
    f[5] = new Field(connection, "BUFFER_LENGTH", iInt4Oid, 4);
    f[6] = new Field(connection, "DECIMAL_DIGITS", iInt2Oid, 2);
    f[7] = new Field(connection, "PSEUDO_COLUMN", iInt2Oid, 2);
2111

Peter Mount's avatar
Peter Mount committed
2112 2113
    return new ResultSet(connection, f, v, "OK", 1);
  }
2114

Peter Mount's avatar
Peter Mount committed
2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147
  /**
   * Get a description of a table's columns that are automatically
   * updated when any value in a row is updated.  They are
   * unordered.
   *
   * <P>Each column description has the following columns:
   *  <OL>
   *	<LI><B>SCOPE</B> short => is not used
   *	<LI><B>COLUMN_NAME</B> String => column name
   *	<LI><B>DATA_TYPE</B> short => SQL data type from java.sql.Types
   *	<LI><B>TYPE_NAME</B> String => Data source dependent type name
   *	<LI><B>COLUMN_SIZE</B> int => precision
   *	<LI><B>BUFFER_LENGTH</B> int => length of column value in bytes
   *	<LI><B>DECIMAL_DIGITS</B> short	 => scale
   *	<LI><B>PSEUDO_COLUMN</B> short => is this a pseudo column
   *      like an Oracle ROWID
   *      <UL>
   *      <LI> versionColumnUnknown - may or may not be pseudo column
   *      <LI> versionColumnNotPseudo - is NOT a pseudo column
   *      <LI> versionColumnPseudo - is a pseudo column
   *      </UL>
   *  </OL>
   *
   * @param catalog a catalog name; "" retrieves those without a catalog
   * @param schema a schema name; "" retrieves those without a schema
   * @param table a table name
   * @return ResultSet each row is a column description
   */
 public java.sql.ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException
  {
    // XXX-Not Implemented
    return null;
  }
2148

Peter Mount's avatar
Peter Mount committed
2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187
  /**
   * Get a description of a table's primary key columns.  They
   * are ordered by COLUMN_NAME.
   *
   * <P>Each column description has the following columns:
   *  <OL>
   *	<LI><B>TABLE_CAT</B> String => table catalog (may be null)
   *	<LI><B>TABLE_SCHEM</B> String => table schema (may be null)
   *	<LI><B>TABLE_NAME</B> String => table name
   *	<LI><B>COLUMN_NAME</B> String => column name
   *	<LI><B>KEY_SEQ</B> short => sequence number within primary key
   *	<LI><B>PK_NAME</B> String => primary key name (may be null)
   *  </OL>
   *
   * @param catalog a catalog name; "" retrieves those without a catalog
   * @param schema a schema name pattern; "" retrieves those
   * without a schema
   * @param table a table name
   * @return ResultSet each row is a primary key column description
   */
  public java.sql.ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException
  {
    return connection.createStatement().executeQuery("SELECT " +
                                                     "'' as TABLE_CAT," +
                                                     "'' AS TABLE_SCHEM," +
                                                     "bc.relname AS TABLE_NAME," +
                                                     "a.attname AS COLUMN_NAME," +
                                                     "a.attnum as KEY_SEQ,"+
                                                     "ic.relname as PK_NAME " +
                                                     " FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a" +
                                                     " WHERE bc.relkind = 'r' " + //    -- not indices
                                                     "  and upper(bc.relname) = upper('"+table+"')" +
                                                     "  and i.indrelid = bc.oid" +
                                                     "  and i.indexrelid = ic.oid" +
                                                     "  and ic.oid = a.attrelid" +
                                                     "  and i.indisprimary='t' " +
                                                     " ORDER BY table_name, pk_name, key_seq"
                                                     );
  }
2188

2189 2190 2191 2192 2193 2194 2195 2196
  private Vector importLoop(java.sql.ResultSet keyRelation) throws SQLException {
    String s,s2;
    String origTable=null, primTable=new String(""), schema;
    int i;
    Vector v;

    s=keyRelation.getString(1);
    s2=s;
2197
    // System.out.println(s);
2198 2199 2200 2201
    v=new Vector();
    for (i=0;;i++) {
      s=s.substring(s.indexOf("\\000")+4);
      if (s.compareTo("")==0) {
2202
	//System.out.println();
2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251
	break;
      }
      s2=s.substring(0,s.indexOf("\\000"));
      switch (i) {
      case 0:
	origTable=s2;
	break;
      case 1:
	primTable=s2;
	break;
      case 2:
	schema=s2;
	break;
      default:
	v.add(s2);
      }
  }

  java.sql.ResultSet rstmp=connection.ExecSQL("select * from "+origTable+" where 1=0");
  java.sql.ResultSetMetaData origCols=rstmp.getMetaData();

  String stmp;
  Vector tuples=new Vector();
  byte tuple[][];

  // the foreign keys are only on even positions in the Vector.
  for (i=0;i<v.size();i+=2) {
    stmp=(String)v.elementAt(i);

    for (int j=1;j<=origCols.getColumnCount();j++) {
      if (stmp.compareTo(origCols.getColumnName(j))==0) {
	tuple=new byte[14][0];

	for (int k=0;k<14;k++)
	  tuple[k]=null;

	//PKTABLE_NAME
	tuple[2]=primTable.getBytes();
	//PKTABLE_COLUMN
	stmp=(String)v.elementAt(i+1);
	tuple[3]=stmp.getBytes();
	//FKTABLE_NAME
	tuple[6]=origTable.getBytes();
	//FKCOLUMN_NAME
	tuple[7]=origCols.getColumnName(j).getBytes();
	//KEY_SEQ
	tuple[8]=Integer.toString(j).getBytes();

	tuples.add(tuple);
2252
/*
2253 2254 2255
	System.out.println(origCols.getColumnName(j)+
	": "+j+" -> "+primTable+": "+
	(String)v.elementAt(i+1));
2256
*/
2257 2258 2259 2260 2261 2262 2263 2264
	break;
      }
    }
  }

  return tuples;
  }

Peter Mount's avatar
Peter Mount committed
2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317
  /**
   * Get a description of the primary key columns that are
   * referenced by a table's foreign key columns (the primary keys
   * imported by a table).  They are ordered by PKTABLE_CAT,
   * PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.
   *
   * <P>Each primary key column description has the following columns:
   *  <OL>
   *	<LI><B>PKTABLE_CAT</B> String => primary key table catalog
   *      being imported (may be null)
   *	<LI><B>PKTABLE_SCHEM</B> String => primary key table schema
   *      being imported (may be null)
   *	<LI><B>PKTABLE_NAME</B> String => primary key table name
   *      being imported
   *	<LI><B>PKCOLUMN_NAME</B> String => primary key column name
   *      being imported
   *	<LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
   *	<LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
   *	<LI><B>FKTABLE_NAME</B> String => foreign key table name
   *	<LI><B>FKCOLUMN_NAME</B> String => foreign key column name
   *	<LI><B>KEY_SEQ</B> short => sequence number within foreign key
   *	<LI><B>UPDATE_RULE</B> short => What happens to
   *       foreign key when primary is updated:
   *      <UL>
   *      <LI> importedKeyCascade - change imported key to agree
   *               with primary key update
   *      <LI> importedKeyRestrict - do not allow update of primary
   *               key if it has been imported
   *      <LI> importedKeySetNull - change imported key to NULL if
   *               its primary key has been updated
   *      </UL>
   *	<LI><B>DELETE_RULE</B> short => What happens to
   *      the foreign key when primary is deleted.
   *      <UL>
   *      <LI> importedKeyCascade - delete rows that import a deleted key
   *      <LI> importedKeyRestrict - do not allow delete of primary
   *               key if it has been imported
   *      <LI> importedKeySetNull - change imported key to NULL if
   *               its primary key has been deleted
   *      </UL>
   *	<LI><B>FK_NAME</B> String => foreign key name (may be null)
   *	<LI><B>PK_NAME</B> String => primary key name (may be null)
   *  </OL>
   *
   * @param catalog a catalog name; "" retrieves those without a catalog
   * @param schema a schema name pattern; "" retrieves those
   * without a schema
   * @param table a table name
   * @return ResultSet each row is a primary key column description
   * @see #getExportedKeys
   */
  public java.sql.ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException
  {
2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350
    // Added by Ola Sundell <ola@miranda.org>
    // FIXME: error checking galore!
    java.sql.ResultSet rsret;
    Field f[]=new Field[14];
    byte tuple[][];

    f[0]=new Field(connection, "PKTABLE_CAT", iVarcharOid, 32);
    f[1]=new Field(connection, "PKTABLE_SCHEM", iVarcharOid, 32);
    f[2]=new Field(connection, "PKTABLE_NAME", iVarcharOid, 32);
    f[3]=new Field(connection, "PKCOLUMN_NAME", iVarcharOid, 32);
    f[4]=new Field(connection, "FKTABLE_CAT", iVarcharOid, 32);
    f[5]=new Field(connection, "FKTABLE_SCHEM", iVarcharOid, 32);
    f[6]=new Field(connection, "FKTABLE_NAME", iVarcharOid, 32);
    f[7]=new Field(connection, "FKCOLUMN_NAME", iVarcharOid, 32);
    f[8]=new Field(connection, "KEY_SEQ", iInt2Oid, 2);
    f[9]=new Field(connection, "UPDATE_RULE", iInt2Oid, 2);
    f[10]=new Field(connection, "DELETE_RULE", iInt2Oid, 2);
    f[11]=new Field(connection, "FK_NAME", iVarcharOid, 32);
    f[12]=new Field(connection, "PK_NAME", iVarcharOid, 32);
    f[13]=new Field(connection, "DEFERRABILITY", iInt2Oid, 2);

    java.sql.ResultSet rs=connection.ExecSQL("select t.tgargs "+
	    "from pg_class as c, pg_trigger as t "+
	    "where c.relname like '"+table+"' and c.relfilenode=t.tgrelid");
    Vector tuples=new Vector();
    
    while (rs.next()) {
	    tuples.addAll(importLoop(rs));	
    }

    rsret=new ResultSet(connection, f, tuples, "OK", 1);

    return rsret;
Peter Mount's avatar
Peter Mount committed
2351
  }
2352

Peter Mount's avatar
Peter Mount committed
2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408
  /**
   * Get a description of a foreign key columns that reference a
   * table's primary key columns (the foreign keys exported by a
   * table).  They are ordered by FKTABLE_CAT, FKTABLE_SCHEM,
   * FKTABLE_NAME, and KEY_SEQ.
   *
   * <P>Each foreign key column description has the following columns:
   *  <OL>
   *	<LI><B>PKTABLE_CAT</B> String => primary key table catalog (may be null)
   *	<LI><B>PKTABLE_SCHEM</B> String => primary key table schema (may be null)
   *	<LI><B>PKTABLE_NAME</B> String => primary key table name
   *	<LI><B>PKCOLUMN_NAME</B> String => primary key column name
   *	<LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
   *      being exported (may be null)
   *	<LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
   *      being exported (may be null)
   *	<LI><B>FKTABLE_NAME</B> String => foreign key table name
   *      being exported
   *	<LI><B>FKCOLUMN_NAME</B> String => foreign key column name
   *      being exported
   *	<LI><B>KEY_SEQ</B> short => sequence number within foreign key
   *	<LI><B>UPDATE_RULE</B> short => What happens to
   *       foreign key when primary is updated:
   *      <UL>
   *      <LI> importedKeyCascade - change imported key to agree
   *               with primary key update
   *      <LI> importedKeyRestrict - do not allow update of primary
   *               key if it has been imported
   *      <LI> importedKeySetNull - change imported key to NULL if
   *               its primary key has been updated
   *      </UL>
   *	<LI><B>DELETE_RULE</B> short => What happens to
   *      the foreign key when primary is deleted.
   *      <UL>
   *      <LI> importedKeyCascade - delete rows that import a deleted key
   *      <LI> importedKeyRestrict - do not allow delete of primary
   *               key if it has been imported
   *      <LI> importedKeySetNull - change imported key to NULL if
   *               its primary key has been deleted
   *      </UL>
   *	<LI><B>FK_NAME</B> String => foreign key identifier (may be null)
   *	<LI><B>PK_NAME</B> String => primary key identifier (may be null)
   *  </OL>
   *
   * @param catalog a catalog name; "" retrieves those without a catalog
   * @param schema a schema name pattern; "" retrieves those
   * without a schema
   * @param table a table name
   * @return ResultSet each row is a foreign key column description
   * @see #getImportedKeys
   */
  public java.sql.ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException
  {
    // XXX-Not Implemented
    return null;
  }
2409

Peter Mount's avatar
Peter Mount committed
2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468
  /**
   * Get a description of the foreign key columns in the foreign key
   * table that reference the primary key columns of the primary key
   * table (describe how one table imports another's key.) This
   * should normally return a single foreign key/primary key pair
   * (most tables only import a foreign key from a table once.)  They
   * are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and
   * KEY_SEQ.
   *
   * <P>Each foreign key column description has the following columns:
   *  <OL>
   *	<LI><B>PKTABLE_CAT</B> String => primary key table catalog (may be null)
   *	<LI><B>PKTABLE_SCHEM</B> String => primary key table schema (may be null)
   *	<LI><B>PKTABLE_NAME</B> String => primary key table name
   *	<LI><B>PKCOLUMN_NAME</B> String => primary key column name
   *	<LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
   *      being exported (may be null)
   *	<LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
   *      being exported (may be null)
   *	<LI><B>FKTABLE_NAME</B> String => foreign key table name
   *      being exported
   *	<LI><B>FKCOLUMN_NAME</B> String => foreign key column name
   *      being exported
   *	<LI><B>KEY_SEQ</B> short => sequence number within foreign key
   *	<LI><B>UPDATE_RULE</B> short => What happens to
   *       foreign key when primary is updated:
   *      <UL>
   *      <LI> importedKeyCascade - change imported key to agree
   *               with primary key update
   *      <LI> importedKeyRestrict - do not allow update of primary
   *               key if it has been imported
   *      <LI> importedKeySetNull - change imported key to NULL if
   *               its primary key has been updated
   *      </UL>
   *	<LI><B>DELETE_RULE</B> short => What happens to
   *      the foreign key when primary is deleted.
   *      <UL>
   *      <LI> importedKeyCascade - delete rows that import a deleted key
   *      <LI> importedKeyRestrict - do not allow delete of primary
   *               key if it has been imported
   *      <LI> importedKeySetNull - change imported key to NULL if
   *               its primary key has been deleted
   *      </UL>
   *	<LI><B>FK_NAME</B> String => foreign key identifier (may be null)
   *	<LI><B>PK_NAME</B> String => primary key identifier (may be null)
   *  </OL>
   *
   * @param catalog a catalog name; "" retrieves those without a catalog
   * @param schema a schema name pattern; "" retrieves those
   * without a schema
   * @param table a table name
   * @return ResultSet each row is a foreign key column description
   * @see #getImportedKeys
   */
  public java.sql.ResultSet getCrossReference(String primaryCatalog, String primarySchema, String primaryTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException
  {
    // XXX-Not Implemented
    return null;
  }
2469

Peter Mount's avatar
Peter Mount committed
2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516
  /**
   * Get a description of all the standard SQL types supported by
   * this database. They are ordered by DATA_TYPE and then by how
   * closely the data type maps to the corresponding JDBC SQL type.
   *
   * <P>Each type description has the following columns:
   *  <OL>
   *	<LI><B>TYPE_NAME</B> String => Type name
   *	<LI><B>DATA_TYPE</B> short => SQL data type from java.sql.Types
   *	<LI><B>PRECISION</B> int => maximum precision
   *	<LI><B>LITERAL_PREFIX</B> String => prefix used to quote a literal
   *      (may be null)
   *	<LI><B>LITERAL_SUFFIX</B> String => suffix used to quote a literal
   (may be null)
   *	<LI><B>CREATE_PARAMS</B> String => parameters used in creating
   *      the type (may be null)
   *	<LI><B>NULLABLE</B> short => can you use NULL for this type?
   *      <UL>
   *      <LI> typeNoNulls - does not allow NULL values
   *      <LI> typeNullable - allows NULL values
   *      <LI> typeNullableUnknown - nullability unknown
   *      </UL>
   *	<LI><B>CASE_SENSITIVE</B> boolean=> is it case sensitive?
   *	<LI><B>SEARCHABLE</B> short => can you use "WHERE" based on this type:
   *      <UL>
   *      <LI> typePredNone - No support
   *      <LI> typePredChar - Only supported with WHERE .. LIKE
   *      <LI> typePredBasic - Supported except for WHERE .. LIKE
   *      <LI> typeSearchable - Supported for all WHERE ..
   *      </UL>
   *	<LI><B>UNSIGNED_ATTRIBUTE</B> boolean => is it unsigned?
   *	<LI><B>FIXED_PREC_SCALE</B> boolean => can it be a money value?
   *	<LI><B>AUTO_INCREMENT</B> boolean => can it be used for an
   *      auto-increment value?
   *	<LI><B>LOCAL_TYPE_NAME</B> String => localized version of type name
   *      (may be null)
   *	<LI><B>MINIMUM_SCALE</B> short => minimum scale supported
   *	<LI><B>MAXIMUM_SCALE</B> short => maximum scale supported
   *	<LI><B>SQL_DATA_TYPE</B> int => unused
   *	<LI><B>SQL_DATETIME_SUB</B> int => unused
   *	<LI><B>NUM_PREC_RADIX</B> int => usually 2 or 10
   *  </OL>
   *
   * @return ResultSet each row is a SQL type description
   */
  public java.sql.ResultSet getTypeInfo() throws SQLException
  {
2517
    java.sql.ResultSet rs = connection.ExecSQL("select typname from pg_type");
Peter Mount's avatar
Peter Mount committed
2518 2519 2520 2521
    if(rs!=null) {
      Field f[] = new Field[18];
      ResultSet r;	// ResultSet for the SQL query that we need to do
      Vector v = new Vector();		// The new ResultSet tuple stuff
2522

2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540
      f[0] = new Field(connection, "TYPE_NAME", iVarcharOid, 32);
      f[1] = new Field(connection, "DATA_TYPE", iInt2Oid, 2);
      f[2] = new Field(connection, "PRECISION", iInt4Oid, 4);
      f[3] = new Field(connection, "LITERAL_PREFIX", iVarcharOid, 32);
      f[4] = new Field(connection, "LITERAL_SUFFIX", iVarcharOid, 32);
      f[5] = new Field(connection, "CREATE_PARAMS", iVarcharOid, 32);
      f[6] = new Field(connection, "NULLABLE", iInt2Oid, 2);
      f[7] = new Field(connection, "CASE_SENSITIVE", iBoolOid, 1);
      f[8] = new Field(connection, "SEARCHABLE", iInt2Oid, 2);
      f[9] = new Field(connection, "UNSIGNED_ATTRIBUTE", iBoolOid, 1);
      f[10] = new Field(connection, "FIXED_PREC_SCALE", iBoolOid, 1);
      f[11] = new Field(connection, "AUTO_INCREMENT", iBoolOid, 1);
      f[12] = new Field(connection, "LOCAL_TYPE_NAME", iVarcharOid, 32);
      f[13] = new Field(connection, "MINIMUM_SCALE", iInt2Oid, 2);
      f[14] = new Field(connection, "MAXIMUM_SCALE", iInt2Oid, 2);
      f[15] = new Field(connection, "SQL_DATA_TYPE", iInt4Oid, 4);
      f[16] = new Field(connection, "SQL_DATETIME_SUB", iInt4Oid, 4);
      f[17] = new Field(connection, "NUM_PREC_RADIX", iInt4Oid, 4);
2541

Peter Mount's avatar
Peter Mount committed
2542 2543 2544 2545 2546 2547 2548
      // cache some results, this will keep memory useage down, and speed
      // things up a little.
      byte b9[]  = "9".getBytes();
      byte b10[] = "10".getBytes();
      byte bf[]  = "f".getBytes();
      byte bnn[] = Integer.toString(typeNoNulls).getBytes();
      byte bts[] = Integer.toString(typeSearchable).getBytes();
2549

Peter Mount's avatar
Peter Mount committed
2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570
      while(rs.next()) {
	byte[][] tuple = new byte[18][];
	String typname=rs.getString(1);
	tuple[0] = typname.getBytes();
	tuple[1] = Integer.toString(Field.getSQLType(typname)).getBytes();
	tuple[2] = b9;	// for now
	tuple[6] = bnn; // for now
	tuple[7] = bf; // false for now - not case sensitive
	tuple[8] = bts;
	tuple[9] = bf; // false for now - it's signed
	tuple[10] = bf; // false for now - must handle money
	tuple[11] = bf; // false for now - handle autoincrement
	// 12 - LOCAL_TYPE_NAME is null
	// 13 & 14 ?
	// 15 & 16 are unused so we return null
	tuple[17] = b10; // everything is base 10
	v.addElement(tuple);
      }
      rs.close();
      return new ResultSet(connection, f, v, "OK", 1);
    }
2571

Peter Mount's avatar
Peter Mount committed
2572 2573
    return null;
  }
2574

Peter Mount's avatar
Peter Mount committed
2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625
  /**
   * Get a description of a table's indices and statistics. They are
   * ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.
   *
   * <P>Each index column description has the following columns:
   *  <OL>
   *	<LI><B>TABLE_CAT</B> String => table catalog (may be null)
   *	<LI><B>TABLE_SCHEM</B> String => table schema (may be null)
   *	<LI><B>TABLE_NAME</B> String => table name
   *	<LI><B>NON_UNIQUE</B> boolean => Can index values be non-unique?
   *      false when TYPE is tableIndexStatistic
   *	<LI><B>INDEX_QUALIFIER</B> String => index catalog (may be null);
   *      null when TYPE is tableIndexStatistic
   *	<LI><B>INDEX_NAME</B> String => index name; null when TYPE is
   *      tableIndexStatistic
   *	<LI><B>TYPE</B> short => index type:
   *      <UL>
   *      <LI> tableIndexStatistic - this identifies table statistics that are
   *           returned in conjuction with a table's index descriptions
   *      <LI> tableIndexClustered - this is a clustered index
   *      <LI> tableIndexHashed - this is a hashed index
   *      <LI> tableIndexOther - this is some other style of index
   *      </UL>
   *	<LI><B>ORDINAL_POSITION</B> short => column sequence number
   *      within index; zero when TYPE is tableIndexStatistic
   *	<LI><B>COLUMN_NAME</B> String => column name; null when TYPE is
   *      tableIndexStatistic
   *	<LI><B>ASC_OR_DESC</B> String => column sort sequence, "A" => ascending
   *      "D" => descending, may be null if sort sequence is not supported;
   *      null when TYPE is tableIndexStatistic
   *	<LI><B>CARDINALITY</B> int => When TYPE is tableIndexStatisic then
   *      this is the number of rows in the table; otherwise it is the
   *      number of unique values in the index.
   *	<LI><B>PAGES</B> int => When TYPE is  tableIndexStatisic then
   *      this is the number of pages used for the table, otherwise it
   *      is the number of pages used for the current index.
   *	<LI><B>FILTER_CONDITION</B> String => Filter condition, if any.
   *      (may be null)
   *  </OL>
   *
   * @param catalog a catalog name; "" retrieves those without a catalog
   * @param schema a schema name pattern; "" retrieves those without a schema
   * @param table a table name
   * @param unique when true, return only indices for unique values;
   *     when false, return indices regardless of whether unique or not
   * @param approximate when true, result is allowed to reflect approximate
   *     or out of data values; when false, results are requested to be
   *     accurate
   * @return ResultSet each row is an index column description
   */
  // Implementation note: This is required for Borland's JBuilder to work
2626
  public java.sql.ResultSet getIndexInfo(String catalog, String schema, String tableName, boolean unique, boolean approximate) throws SQLException
Peter Mount's avatar
Peter Mount committed
2627 2628
  {
    Field f[] = new Field[13];
2629
    java.sql.ResultSet r;	// ResultSet for the SQL query that we need to do
Peter Mount's avatar
Peter Mount committed
2630
    Vector v = new Vector();		// The new ResultSet tuple stuff
2631

2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644
    f[0] = new Field(connection, "TABLE_CAT", iVarcharOid, 32);
    f[1] = new Field(connection, "TABLE_SCHEM", iVarcharOid, 32);
    f[2] = new Field(connection, "TABLE_NAME", iVarcharOid, 32);
    f[3] = new Field(connection, "NON_UNIQUE", iBoolOid, 1);
    f[4] = new Field(connection, "INDEX_QUALIFIER", iVarcharOid, 32);
    f[5] = new Field(connection, "INDEX_NAME", iVarcharOid, 32);
    f[6] = new Field(connection, "TYPE", iInt2Oid, 2);
    f[7] = new Field(connection, "ORDINAL_POSITION", iInt2Oid, 2);
    f[8] = new Field(connection, "COLUMN_NAME", iVarcharOid, 32);
    f[9] = new Field(connection, "ASC_OR_DESC", iVarcharOid, 32);
    f[10] = new Field(connection, "CARDINALITY", iInt4Oid, 4);
    f[11] = new Field(connection, "PAGES", iInt4Oid, 4);
    f[12] = new Field(connection, "FILTER_CONDITION", iVarcharOid, 32);
2645

2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658
    r = connection.ExecSQL("select " +
				"c.relname, " +
				"x.indisunique, " +
				"i.relname, " +
				"x.indisclustered, " +
				"a.amname, " +
				"x.indkey, " +
				"c.reltuples, " +
				"c.relpages " +
				"FROM pg_index x, pg_class c, pg_class i, pg_am a " +
				"WHERE ((c.relname = '" + tableName.toLowerCase() + "') " +
				" AND (c.oid = x.indrelid) " +
				" AND (i.oid = x.indexrelid) " +
2659
				" AND (i.relam = a.oid)) " +
2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698
				"ORDER BY x.indisunique DESC, " +
				" x.indisclustered, a.amname, i.relname");  
    while (r.next()) {
        // indkey is an array of column ordinals (integers).  In the JDBC
        // interface, this has to be separated out into a separate
        // tuple for each indexed column.  Also, getArray() is not yet
        // implemented for Postgres JDBC, so we parse by hand.
        String columnOrdinalString = r.getString(6);
        StringTokenizer stok = new StringTokenizer(columnOrdinalString);
        int [] columnOrdinals = new int[stok.countTokens()];
        int o = 0;
        while (stok.hasMoreTokens()) {
            columnOrdinals[o++] = Integer.parseInt(stok.nextToken());
        }
        for (int i = 0; i < columnOrdinals.length; i++) {
            byte [] [] tuple = new byte [13] [];
            tuple[0] = "".getBytes(); 
            tuple[1] = "".getBytes();
            tuple[2] = r.getBytes(1);
            tuple[3] = r.getBoolean(2) ? "f".getBytes() : "t".getBytes();
            tuple[4] = null;
            tuple[5] = r.getBytes(3);
            tuple[6] = r.getBoolean(4) ?
                Integer.toString(tableIndexClustered).getBytes() :
                r.getString(5).equals("hash") ?
				Integer.toString(tableIndexHashed).getBytes() :
                Integer.toString(tableIndexOther).getBytes();
            tuple[7] = Integer.toString(i + 1).getBytes();
            java.sql.ResultSet columnNameRS = connection.ExecSQL("select a.attname FROM pg_attribute a, pg_class c WHERE (a.attnum = " + columnOrdinals[i] + ") AND (a.attrelid = " + r.getInt(8) + ")");
            columnNameRS.next();
            tuple[8] = columnNameRS.getBytes(1);
            tuple[9] = null;  // sort sequence ???
            tuple[10] = r.getBytes(7);  // inexact
            tuple[11] = r.getBytes(8);
            tuple[12] = null;
            v.addElement(tuple);
        }
    }

Peter Mount's avatar
Peter Mount committed
2699 2700
    return new ResultSet(connection, f, v, "OK", 1);
  }
2701

Peter Mount's avatar
Peter Mount committed
2702
    // ** JDBC 2 Extensions **
2703

Peter Mount's avatar
Peter Mount committed
2704 2705 2706
    /**
     * New in 7.1 - we don't support deletes so this must be false!
     */
Peter Mount's avatar
Peter Mount committed
2707 2708
    public boolean deletesAreDetected(int i) throws SQLException
    {
Peter Mount's avatar
Peter Mount committed
2709
	return false;
Peter Mount's avatar
Peter Mount committed
2710
    }
2711

Peter Mount's avatar
Peter Mount committed
2712 2713 2714
    /**
     * New in 7.1 - we don't support deletes so this must be false!
     */
Peter Mount's avatar
Peter Mount committed
2715 2716
    public boolean othersDeletesAreVisible(int i) throws SQLException
    {
Peter Mount's avatar
Peter Mount committed
2717
	return false;
Peter Mount's avatar
Peter Mount committed
2718
    }
2719

Peter Mount's avatar
Peter Mount committed
2720 2721 2722 2723
    public java.sql.Connection getConnection() throws SQLException
    {
	return (java.sql.Connection)connection;
    }
2724

Peter Mount's avatar
Peter Mount committed
2725 2726 2727
    /**
     * Return user defined types in a schema
     */
Peter Mount's avatar
Peter Mount committed
2728 2729 2730 2731 2732 2733 2734 2735
    public java.sql.ResultSet getUDTs(String catalog,
				      String schemaPattern,
				      String typeNamePattern,
				      int[] types
				      ) throws SQLException
    {
	throw org.postgresql.Driver.notImplemented();
    }
2736

Peter Mount's avatar
Peter Mount committed
2737 2738 2739
    /**
     * New in 7.1 - we don't support visible inserts so this must be false!
     */
Peter Mount's avatar
Peter Mount committed
2740 2741
    public boolean othersInsertsAreVisible(int type) throws SQLException
    {
Peter Mount's avatar
Peter Mount committed
2742
	return false;
Peter Mount's avatar
Peter Mount committed
2743
    }
2744

Peter Mount's avatar
Peter Mount committed
2745 2746 2747
    /**
     * New in 7.1 - we don't support visible updates so this must be false!
     */
Peter Mount's avatar
Peter Mount committed
2748 2749
    public boolean updatesAreDetected(int type) throws SQLException
    {
Peter Mount's avatar
Peter Mount committed
2750
	return false;
Peter Mount's avatar
Peter Mount committed
2751
    }
2752

Peter Mount's avatar
Peter Mount committed
2753 2754 2755
    /**
     * New in 7.1 - we don't support visible updates so this must be false!
     */
Peter Mount's avatar
Peter Mount committed
2756 2757
    public boolean othersUpdatesAreVisible(int type) throws SQLException
    {
Peter Mount's avatar
Peter Mount committed
2758
	return false;
Peter Mount's avatar
Peter Mount committed
2759
    }
2760

Peter Mount's avatar
Peter Mount committed
2761 2762
    public boolean ownUpdatesAreVisible(int type) throws SQLException
    {
Peter Mount's avatar
Peter Mount committed
2763
	return false;
Peter Mount's avatar
Peter Mount committed
2764
    }
2765

Peter Mount's avatar
Peter Mount committed
2766 2767
    public boolean ownInsertsAreVisible(int type) throws SQLException
    {
Peter Mount's avatar
Peter Mount committed
2768
	return false;
Peter Mount's avatar
Peter Mount committed
2769
    }
2770

Peter Mount's avatar
Peter Mount committed
2771 2772
    public boolean insertsAreDetected(int type) throws SQLException
    {
Peter Mount's avatar
Peter Mount committed
2773
	return false;
Peter Mount's avatar
Peter Mount committed
2774
    }
2775

Peter Mount's avatar
Peter Mount committed
2776 2777
    public boolean ownDeletesAreVisible(int type) throws SQLException
    {
Peter Mount's avatar
Peter Mount committed
2778
	return false;
Peter Mount's avatar
Peter Mount committed
2779
    }
2780

Peter Mount's avatar
Peter Mount committed
2781 2782
    public boolean rowChangesAreDetected(int type) throws SQLException
    {
Peter Mount's avatar
Peter Mount committed
2783
	return false;
Peter Mount's avatar
Peter Mount committed
2784
    }
2785

Peter Mount's avatar
Peter Mount committed
2786 2787
    public boolean rowChangesAreVisible(int type) throws SQLException
    {
Peter Mount's avatar
Peter Mount committed
2788
	return false;
Peter Mount's avatar
Peter Mount committed
2789
    }
2790

Peter Mount's avatar
Peter Mount committed
2791 2792 2793
    /**
     * New in 7.1 - If this is for PreparedStatement yes, ResultSet no
     */
Peter Mount's avatar
Peter Mount committed
2794 2795
    public boolean supportsBatchUpdates() throws SQLException
    {
Peter Mount's avatar
Peter Mount committed
2796
	return true;
Peter Mount's avatar
Peter Mount committed
2797
    }
2798

Peter Mount's avatar
Peter Mount committed
2799 2800 2801
    /**
     * New in 7.1
     */
Peter Mount's avatar
Peter Mount committed
2802 2803
    public boolean supportsResultSetConcurrency(int type,int concurrency) throws SQLException
    {
Peter Mount's avatar
Peter Mount committed
2804 2805 2806 2807 2808 2809 2810 2811 2812 2813
      // These combinations are not supported!
      if(type==java.sql.ResultSet.TYPE_SCROLL_SENSITIVE)
        return false;

      // We don't yet support Updateable ResultSets
      if(concurrency==java.sql.ResultSet.CONCUR_UPDATABLE)
        return false;

      // Everything else we do
      return true;
Peter Mount's avatar
Peter Mount committed
2814
    }
2815

Peter Mount's avatar
Peter Mount committed
2816 2817
    public boolean supportsResultSetType(int type) throws SQLException
    {
Peter Mount's avatar
Peter Mount committed
2818 2819
      // The only type we don't support
      return type!=java.sql.ResultSet.TYPE_SCROLL_SENSITIVE;
Peter Mount's avatar
Peter Mount committed
2820
    }
2821

Peter Mount's avatar
Peter Mount committed
2822
}