info.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:86k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /* Module:          info.c
  2.  *
  3.  * Description:     This module contains routines related to
  4.  *                  ODBC informational functions.
  5.  *
  6.  * Classes:         n/a
  7.  *
  8.  * API functions:   SQLGetInfo, SQLGetTypeInfo, SQLGetFunctions, 
  9.  *                  SQLTables, SQLColumns, SQLStatistics, SQLSpecialColumns,
  10.  *                  SQLPrimaryKeys, SQLForeignKeys, 
  11.  *                  SQLProcedureColumns(NI), SQLProcedures(NI), 
  12.  *                  SQLTablePrivileges(NI), SQLColumnPrivileges(NI)
  13.  *
  14.  * Comments:        See "notice.txt" for copyright and license information.
  15.  *
  16.  */
  17. #ifdef HAVE_CONFIG_H
  18. #include "config.h"
  19. #endif
  20. #include <string.h>
  21. #include <stdio.h>
  22. #include "psqlodbc.h"
  23. #ifndef WIN32
  24. #include "iodbc.h"
  25. #include "isql.h"
  26. #include "isqlext.h"
  27. #include <ctype.h> /* for tolower function */
  28. #else
  29. #include <windows.h>
  30. #include <sql.h> 
  31. #include <sqlext.h>
  32. #endif
  33. #include "tuple.h"
  34. #include "pgtypes.h"
  35. #include "environ.h"
  36. #include "connection.h"
  37. #include "statement.h"
  38. #include "qresult.h"
  39. #include "bind.h"
  40. #include "misc.h"
  41. #include "pgtypes.h"
  42. /* Trigger related stuff for SQLForeign Keys */
  43. #define TRIGGER_SHIFT 3
  44. #define TRIGGER_MASK   0x03
  45. #define TRIGGER_DELETE 0x01
  46. #define TRIGGER_UPDATE 0x02
  47. extern GLOBAL_VALUES globals;
  48. //      -       -       -       -       -       -       -       -       -
  49. RETCODE SQL_API SQLGetInfo(
  50.         HDBC      hdbc,
  51.         UWORD     fInfoType,
  52.         PTR       rgbInfoValue,
  53.         SWORD     cbInfoValueMax,
  54.         SWORD FAR *pcbInfoValue)
  55. {
  56. static char *func = "SQLGetInfo";
  57. ConnectionClass *conn = (ConnectionClass *) hdbc;
  58. ConnInfo *ci;
  59. char *p = NULL;
  60. int len = 0, value = 0;
  61. RETCODE result;
  62. mylog( "%s: entering...fInfoType=%dn", func, fInfoType);
  63. if ( ! conn) {
  64. CC_log_error(func, "", NULL);
  65. return SQL_INVALID_HANDLE;
  66. }
  67. ci = &conn->connInfo;
  68.     switch (fInfoType) {
  69.     case SQL_ACCESSIBLE_PROCEDURES: /* ODBC 1.0 */
  70. p = "N";
  71.         break;
  72.     case SQL_ACCESSIBLE_TABLES: /* ODBC 1.0 */
  73. p = "N";
  74.         break;
  75.     case SQL_ACTIVE_CONNECTIONS: /* ODBC 1.0 */
  76.         len = 2;
  77.         value = MAX_CONNECTIONS;
  78.         break;
  79.     case SQL_ACTIVE_STATEMENTS: /* ODBC 1.0 */
  80.         len = 2;
  81.         value = 0;
  82.         break;
  83.     case SQL_ALTER_TABLE: /* ODBC 2.0 */
  84.         len = 4;
  85.         value = SQL_AT_ADD_COLUMN;
  86.         break;
  87.     case SQL_BOOKMARK_PERSISTENCE: /* ODBC 2.0 */
  88. /* very simple bookmark support */        
  89. len = 4;
  90.         value = globals.use_declarefetch ? 0 : (SQL_BP_SCROLL);
  91.         break;
  92.     case SQL_COLUMN_ALIAS: /* ODBC 2.0 */
  93. p = "N";
  94.         break;
  95.     case SQL_CONCAT_NULL_BEHAVIOR: /* ODBC 1.0 */
  96.         len = 2;
  97.         value = SQL_CB_NON_NULL;
  98.         break;
  99.     case SQL_CONVERT_BIGINT:
  100.     case SQL_CONVERT_BINARY:
  101.     case SQL_CONVERT_BIT:
  102.     case SQL_CONVERT_CHAR:
  103.     case SQL_CONVERT_DATE:
  104.     case SQL_CONVERT_DECIMAL:
  105.     case SQL_CONVERT_DOUBLE:
  106.     case SQL_CONVERT_FLOAT:
  107.     case SQL_CONVERT_INTEGER:
  108.     case SQL_CONVERT_LONGVARBINARY:
  109.     case SQL_CONVERT_LONGVARCHAR:
  110.     case SQL_CONVERT_NUMERIC:
  111.     case SQL_CONVERT_REAL:
  112.     case SQL_CONVERT_SMALLINT:
  113.     case SQL_CONVERT_TIME:
  114.     case SQL_CONVERT_TIMESTAMP:
  115.     case SQL_CONVERT_TINYINT:
  116.     case SQL_CONVERT_VARBINARY:
  117.     case SQL_CONVERT_VARCHAR: /* ODBC 1.0 */
  118. len = 4;
  119.         value = fInfoType;
  120.         break;
  121.     case SQL_CONVERT_FUNCTIONS: /* ODBC 1.0 */
  122. len = 4;
  123.         value = 0;
  124.         break;
  125.     case SQL_CORRELATION_NAME: /* ODBC 1.0 */
  126. /* Saying no correlation name makes Query not work right.
  127. value = SQL_CN_NONE;
  128. */
  129. len = 2;
  130.         value = SQL_CN_ANY;
  131.         break;
  132.     case SQL_CURSOR_COMMIT_BEHAVIOR: /* ODBC 1.0 */
  133.         len = 2;
  134.         value = SQL_CB_CLOSE;
  135.         break;
  136.     case SQL_CURSOR_ROLLBACK_BEHAVIOR: /* ODBC 1.0 */
  137.         len = 2;
  138.         value = SQL_CB_CLOSE;
  139.         break;
  140.     case SQL_DATA_SOURCE_NAME: /* ODBC 1.0 */
  141. p = CC_get_DSN(conn);
  142.         break;
  143.     case SQL_DATA_SOURCE_READ_ONLY: /* ODBC 1.0 */
  144. p = CC_is_readonly(conn) ? "Y" : "N";
  145.         break;
  146.     case SQL_DATABASE_NAME: /* Support for old ODBC 1.0 Apps */
  147. /* Returning the database name causes problems in MS Query.
  148. It generates query like: "SELECT DISTINCT a FROM byronncrap3 crap3"
  149. p = CC_get_database(conn);
  150. */
  151. p = "";    
  152. break;
  153.     case SQL_DBMS_NAME: /* ODBC 1.0 */
  154. p = DBMS_NAME;
  155.         break;
  156.     case SQL_DBMS_VER: /* ODBC 1.0 */
  157. p = DBMS_VERSION;
  158.         break;
  159.     case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */
  160. len = 4;
  161.         value = SQL_TXN_READ_COMMITTED; //SQL_TXN_SERIALIZABLE;
  162.         break;
  163.     case SQL_DRIVER_NAME: /* ODBC 1.0 */
  164.         p = DRIVER_FILE_NAME;
  165.         break;
  166.     case SQL_DRIVER_ODBC_VER:
  167. p = DRIVER_ODBC_VER;
  168.         break;
  169.     case SQL_DRIVER_VER: /* ODBC 1.0 */
  170.         p = POSTGRESDRIVERVERSION;
  171.         break;
  172.     case SQL_EXPRESSIONS_IN_ORDERBY: /* ODBC 1.0 */
  173. p = "N";
  174.         break;
  175.     case SQL_FETCH_DIRECTION: /* ODBC 1.0 */
  176. len = 4;
  177.         value = globals.use_declarefetch ? (SQL_FD_FETCH_NEXT) : (SQL_FD_FETCH_NEXT |
  178.                                    SQL_FD_FETCH_FIRST |
  179.                                    SQL_FD_FETCH_LAST |
  180.                                    SQL_FD_FETCH_PRIOR |
  181.                                    SQL_FD_FETCH_ABSOLUTE |
  182.    SQL_FD_FETCH_RELATIVE | 
  183.    SQL_FD_FETCH_BOOKMARK);
  184.         break;
  185.     case SQL_FILE_USAGE: /* ODBC 2.0 */
  186. len = 2;
  187.         value = SQL_FILE_NOT_SUPPORTED;
  188.         break;
  189.     case SQL_GETDATA_EXTENSIONS: /* ODBC 2.0 */
  190. len = 4;
  191.         value = (SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND | SQL_GD_BLOCK);
  192.         break;
  193.     case SQL_GROUP_BY: /* ODBC 2.0 */
  194. len = 2;
  195.         value = SQL_GB_GROUP_BY_EQUALS_SELECT;
  196.         break;
  197.     case SQL_IDENTIFIER_CASE: /* ODBC 1.0 */
  198.         /* are identifiers case-sensitive (yes, but only when quoted.  If not quoted, they
  199. default to lowercase)
  200. */
  201. len = 2;
  202.         value = SQL_IC_LOWER;
  203.         break;
  204.     case SQL_IDENTIFIER_QUOTE_CHAR: /* ODBC 1.0 */
  205.         /* the character used to quote "identifiers" */
  206. p = PROTOCOL_62(ci) ? " " : """;
  207.         break;
  208.     case SQL_KEYWORDS: /* ODBC 2.0 */
  209. p = "";
  210.         break;
  211.     case SQL_LIKE_ESCAPE_CLAUSE: /* ODBC 2.0 */
  212. /* is there a character that escapes '%' and '_' in a LIKE clause?
  213. not as far as I can tell
  214. */
  215.         p = "N";
  216.         break;
  217.     case SQL_LOCK_TYPES: /* ODBC 2.0 */
  218. len = 4;
  219.         value = globals.lie ? (SQL_LCK_NO_CHANGE | SQL_LCK_EXCLUSIVE | SQL_LCK_UNLOCK) : SQL_LCK_NO_CHANGE;
  220.         break;
  221.     case SQL_MAX_BINARY_LITERAL_LEN: /* ODBC 2.0 */
  222. len = 4;
  223.         value = 0;
  224.         break;
  225.     case SQL_MAX_CHAR_LITERAL_LEN: /* ODBC 2.0 */
  226. len = 4;
  227.         value = 0;
  228.         break;
  229.     case SQL_MAX_COLUMN_NAME_LEN: /* ODBC 1.0 */
  230. len = 2;
  231.         value = MAX_COLUMN_LEN;
  232.         break;
  233.     case SQL_MAX_COLUMNS_IN_GROUP_BY: /* ODBC 2.0 */
  234. len = 2;
  235.         value = 0;
  236.         break;
  237.     case SQL_MAX_COLUMNS_IN_INDEX: /* ODBC 2.0 */
  238. len = 2;
  239.         value = 0;
  240.         break;
  241.     case SQL_MAX_COLUMNS_IN_ORDER_BY: /* ODBC 2.0 */
  242. len = 2;
  243.         value = 0;
  244.         break;
  245.     case SQL_MAX_COLUMNS_IN_SELECT: /* ODBC 2.0 */
  246. len = 2;
  247.         value = 0;
  248.         break;
  249.     case SQL_MAX_COLUMNS_IN_TABLE: /* ODBC 2.0 */
  250. len = 2;
  251.         value = 0;
  252.         break;
  253.     case SQL_MAX_CURSOR_NAME_LEN: /* ODBC 1.0 */
  254. len = 2;
  255.         value = MAX_CURSOR_LEN;
  256.         break;
  257.     case SQL_MAX_INDEX_SIZE: /* ODBC 2.0 */
  258. len = 4;
  259.         value = 0;
  260.         break;
  261.     case SQL_MAX_OWNER_NAME_LEN: /* ODBC 1.0 */
  262. len = 2;
  263.         value = 0;
  264.         break;
  265.     case SQL_MAX_PROCEDURE_NAME_LEN: /* ODBC 1.0 */
  266. len = 2;
  267.         value = 0;
  268.         break;
  269.     case SQL_MAX_QUALIFIER_NAME_LEN: /* ODBC 1.0 */
  270. len = 2;
  271.         value = 0;
  272.         break;
  273.     case SQL_MAX_ROW_SIZE: /* ODBC 2.0 */
  274. len = 4;
  275.         value = BLCKSZ;
  276.         break;
  277.     case SQL_MAX_ROW_SIZE_INCLUDES_LONG: /* ODBC 2.0 */
  278.         /* does the preceding value include LONGVARCHAR and LONGVARBINARY
  279. fields?   Well, it does include longvarchar, but not longvarbinary.
  280. */
  281. p = "Y";
  282.         break;
  283.     case SQL_MAX_STATEMENT_LEN: /* ODBC 2.0 */
  284.         /* maybe this should be 0? */
  285. len = 4;
  286.         value = MAX_QUERY_SIZE;
  287.         break;
  288.     case SQL_MAX_TABLE_NAME_LEN: /* ODBC 1.0 */
  289. len = 2;
  290.         value = MAX_TABLE_LEN;
  291.         break;
  292.     case SQL_MAX_TABLES_IN_SELECT: /* ODBC 2.0 */
  293. len = 2;
  294.         value = 0;
  295.         break;
  296.     case SQL_MAX_USER_NAME_LEN:
  297. len = 2;
  298.         value = 0;
  299.         break;
  300.     case SQL_MULT_RESULT_SETS: /* ODBC 1.0 */
  301.         /* Don't support multiple result sets but say yes anyway? */
  302. p = "Y";
  303.         break;
  304.     case SQL_MULTIPLE_ACTIVE_TXN: /* ODBC 1.0 */
  305. p = "Y";
  306.         break;
  307.     case SQL_NEED_LONG_DATA_LEN: /* ODBC 2.0 */
  308. /* Dont need the length, SQLPutData can handle any size and multiple calls */
  309. p = "N";
  310.         break;
  311.     case SQL_NON_NULLABLE_COLUMNS: /* ODBC 1.0 */
  312. len = 2;
  313.         value = SQL_NNC_NON_NULL;
  314.         break;
  315.     case SQL_NULL_COLLATION: /* ODBC 2.0 */
  316.         /* where are nulls sorted? */
  317. len = 2;
  318.         value = SQL_NC_END;
  319.         break;
  320.     case SQL_NUMERIC_FUNCTIONS: /* ODBC 1.0 */
  321. len = 4;
  322.         value = 0;
  323.         break;
  324.     case SQL_ODBC_API_CONFORMANCE: /* ODBC 1.0 */
  325. len = 2;
  326.         value = SQL_OAC_LEVEL1;
  327.         break;
  328.     case SQL_ODBC_SAG_CLI_CONFORMANCE: /* ODBC 1.0 */
  329. len = 2;
  330.         value = SQL_OSCC_NOT_COMPLIANT;
  331.         break;
  332.     case SQL_ODBC_SQL_CONFORMANCE: /* ODBC 1.0 */
  333. len = 2;
  334.         value = SQL_OSC_CORE;
  335.         break;
  336.     case SQL_ODBC_SQL_OPT_IEF: /* ODBC 1.0 */
  337. p = "N";
  338.         break;
  339.     case SQL_ORDER_BY_COLUMNS_IN_SELECT: /* ODBC 2.0 */
  340. p = "Y";
  341.         break;
  342.     case SQL_OUTER_JOINS: /* ODBC 1.0 */
  343. p = "N";
  344.         break;
  345.     case SQL_OWNER_TERM: /* ODBC 1.0 */
  346. p = "owner";
  347.         break;
  348.     case SQL_OWNER_USAGE: /* ODBC 2.0 */
  349. len = 4;
  350.         value = 0;
  351.         break;
  352.     case SQL_POS_OPERATIONS: /* ODBC 2.0 */
  353. len = 4;
  354.         value = globals.lie ? (SQL_POS_POSITION | SQL_POS_REFRESH | SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD) : (SQL_POS_POSITION | SQL_POS_REFRESH);
  355.         break;
  356.     case SQL_POSITIONED_STATEMENTS: /* ODBC 2.0 */
  357. len = 4;
  358.         value = globals.lie ? (SQL_PS_POSITIONED_DELETE | 
  359. SQL_PS_POSITIONED_UPDATE | 
  360. SQL_PS_SELECT_FOR_UPDATE) : 0;
  361.         break;
  362.     case SQL_PROCEDURE_TERM: /* ODBC 1.0 */
  363.         p = "procedure";
  364.         break;
  365.     case SQL_PROCEDURES: /* ODBC 1.0 */
  366. p = "Y";
  367.         break;
  368.     case SQL_QUALIFIER_LOCATION: /* ODBC 2.0 */
  369. len = 2;
  370.         value = SQL_QL_START;
  371.         break;
  372.     case SQL_QUALIFIER_NAME_SEPARATOR: /* ODBC 1.0 */
  373. p = "";
  374.         break;
  375.     case SQL_QUALIFIER_TERM: /* ODBC 1.0 */
  376. p = "";
  377.         break;
  378.     case SQL_QUALIFIER_USAGE: /* ODBC 2.0 */
  379. len = 4;
  380.         value = 0;
  381.         break;
  382.     case SQL_QUOTED_IDENTIFIER_CASE: /* ODBC 2.0 */
  383.         /* are "quoted" identifiers case-sensitive?  YES! */
  384. len = 2;
  385.         value = SQL_IC_SENSITIVE;
  386.         break;
  387.     case SQL_ROW_UPDATES: /* ODBC 1.0 */
  388.         /*  Driver doesn't support keyset-driven or mixed cursors, so
  389. not much point in saying row updates are supported
  390. */
  391.         p = globals.lie ? "Y" : "N";
  392.         break;
  393.     case SQL_SCROLL_CONCURRENCY: /* ODBC 1.0 */
  394. len = 4;
  395.         value = globals.lie ? (SQL_SCCO_READ_ONLY | 
  396. SQL_SCCO_LOCK | 
  397. SQL_SCCO_OPT_ROWVER | 
  398. SQL_SCCO_OPT_VALUES) : (SQL_SCCO_READ_ONLY);
  399.         break;
  400.     case SQL_SCROLL_OPTIONS: /* ODBC 1.0 */
  401. len = 4;
  402.         value = globals.lie ? (SQL_SO_FORWARD_ONLY | 
  403. SQL_SO_STATIC | 
  404. SQL_SO_KEYSET_DRIVEN | 
  405. SQL_SO_DYNAMIC | 
  406. SQL_SO_MIXED) : (globals.use_declarefetch ? SQL_SO_FORWARD_ONLY : (SQL_SO_FORWARD_ONLY | SQL_SO_STATIC));
  407.         break;
  408.     case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */
  409. p = "";
  410.         break;
  411.     case SQL_SERVER_NAME: /* ODBC 1.0 */
  412. p = CC_get_server(conn);
  413.         break;
  414.     case SQL_SPECIAL_CHARACTERS: /* ODBC 2.0 */
  415.         p = "_";
  416.         break;
  417.     case SQL_STATIC_SENSITIVITY: /* ODBC 2.0 */
  418. len = 4;
  419.         value = globals.lie ? (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES) : 0;
  420.         break;
  421.     case SQL_STRING_FUNCTIONS: /* ODBC 1.0 */
  422. len = 4;
  423.         value = (SQL_FN_STR_CONCAT |
  424. SQL_FN_STR_LCASE | 
  425. SQL_FN_STR_LENGTH | 
  426. SQL_FN_STR_LOCATE | 
  427. SQL_FN_STR_LTRIM | 
  428. SQL_FN_STR_RTRIM |
  429. SQL_FN_STR_SUBSTRING |
  430. SQL_FN_STR_UCASE);
  431.         break;
  432.     case SQL_SUBQUERIES: /* ODBC 2.0 */
  433. /* postgres 6.3 supports subqueries */
  434. len = 4;
  435.         value = (SQL_SQ_QUANTIFIED |
  436. SQL_SQ_IN |
  437. SQL_SQ_EXISTS |
  438. SQL_SQ_COMPARISON);
  439.         break;
  440.     case SQL_SYSTEM_FUNCTIONS: /* ODBC 1.0 */
  441. len = 4;
  442. value = 0;
  443.         break;
  444.     case SQL_TABLE_TERM: /* ODBC 1.0 */
  445. p = "table";
  446.         break;
  447.     case SQL_TIMEDATE_ADD_INTERVALS: /* ODBC 2.0 */
  448. len = 4;
  449.         value = 0;
  450.         break;
  451.     case SQL_TIMEDATE_DIFF_INTERVALS: /* ODBC 2.0 */
  452. len = 4;
  453.         value = 0;
  454.         break;
  455.     case SQL_TIMEDATE_FUNCTIONS: /* ODBC 1.0 */
  456. len = 4;
  457.         value = (SQL_FN_TD_NOW);
  458.         break;
  459.     case SQL_TXN_CAPABLE: /* ODBC 1.0 */
  460.         /* Postgres can deal with create or drop table statements in a transaction */
  461. len = 2;
  462.         value = SQL_TC_ALL;
  463.         break;
  464.     case SQL_TXN_ISOLATION_OPTION: /* ODBC 1.0 */
  465. len = 4;
  466.         value = SQL_TXN_READ_COMMITTED; // SQL_TXN_SERIALIZABLE;
  467.         break;
  468.     case SQL_UNION: /* ODBC 2.0 */
  469. /*  unions with all supported in postgres 6.3 */
  470. len = 4;
  471.         value = (SQL_U_UNION | SQL_U_UNION_ALL);
  472.         break;
  473.     case SQL_USER_NAME: /* ODBC 1.0 */
  474. p = CC_get_username(conn);
  475.         break;
  476.     default:
  477.         /* unrecognized key */
  478.         conn->errormsg = "Unrecognized key passed to SQLGetInfo.";
  479.         conn->errornumber = CONN_NOT_IMPLEMENTED_ERROR;
  480. CC_log_error(func, "", conn);
  481.         return SQL_ERROR;
  482.     }
  483. result = SQL_SUCCESS;
  484. mylog("SQLGetInfo: p='%s', len=%d, value=%d, cbMax=%dn", p?p:"<NULL>", len, value, cbInfoValueMax);
  485. /* NOTE, that if rgbInfoValue is NULL, then no warnings or errors should
  486. result and just pcbInfoValue is returned, which indicates what length 
  487. would be required if a real buffer had been passed in.
  488. */
  489. if (p) {  /* char/binary data */
  490. len = strlen(p);
  491. if (rgbInfoValue) {
  492. strncpy_null((char *)rgbInfoValue, p, (size_t)cbInfoValueMax);
  493. if (len >= cbInfoValueMax)  {
  494. result = SQL_SUCCESS_WITH_INFO;
  495. conn->errornumber = STMT_TRUNCATED;
  496. conn->errormsg = "The buffer was too small for the result.";
  497. }
  498. }
  499. }
  500. else { /* numeric data */
  501. if (rgbInfoValue) {
  502. if (len == 2 ) 
  503. *((WORD *)rgbInfoValue) = (WORD) value;
  504. else if (len == 4)
  505. *((DWORD *)rgbInfoValue) = (DWORD) value;
  506. }
  507. }
  508. if (pcbInfoValue) 
  509. *pcbInfoValue = len;
  510. return result;
  511. }
  512. //      -       -       -       -       -       -       -       -       -
  513. RETCODE SQL_API SQLGetTypeInfo(
  514.         HSTMT   hstmt,
  515.         SWORD   fSqlType)
  516. {
  517. static char *func = "SQLGetTypeInfo";
  518. StatementClass *stmt = (StatementClass *) hstmt;
  519. TupleNode *row;
  520. int i;
  521. // Int4 type;
  522. Int4 pgType; 
  523. Int2 sqlType;
  524. mylog("%s: entering...fSqlType = %dn", func, fSqlType);
  525. if( ! stmt) {
  526. SC_log_error(func, "", NULL);
  527. return SQL_INVALID_HANDLE;
  528. }
  529. stmt->manual_result = TRUE;
  530. stmt->result = QR_Constructor();
  531. if( ! stmt->result) {
  532. SC_log_error(func, "Error creating result.", stmt);
  533. return SQL_ERROR;
  534. }
  535. extend_bindings(stmt, 15);
  536. QR_set_num_fields(stmt->result, 15);
  537. QR_set_field_info(stmt->result, 0, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  538. QR_set_field_info(stmt->result, 1, "DATA_TYPE", PG_TYPE_INT2, 2);
  539. QR_set_field_info(stmt->result, 2, "PRECISION", PG_TYPE_INT4, 4);
  540. QR_set_field_info(stmt->result, 3, "LITERAL_PREFIX", PG_TYPE_TEXT, MAX_INFO_STRING);
  541. QR_set_field_info(stmt->result, 4, "LITERAL_SUFFIX", PG_TYPE_TEXT, MAX_INFO_STRING);
  542. QR_set_field_info(stmt->result, 5, "CREATE_PARAMS", PG_TYPE_TEXT, MAX_INFO_STRING);
  543. QR_set_field_info(stmt->result, 6, "NULLABLE", PG_TYPE_INT2, 2);
  544. QR_set_field_info(stmt->result, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2);
  545. QR_set_field_info(stmt->result, 8, "SEARCHABLE", PG_TYPE_INT2, 2);
  546. QR_set_field_info(stmt->result, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2);
  547. QR_set_field_info(stmt->result, 10, "MONEY", PG_TYPE_INT2, 2);
  548. QR_set_field_info(stmt->result, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2);
  549. QR_set_field_info(stmt->result, 12, "LOCAL_TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  550. QR_set_field_info(stmt->result, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
  551. QR_set_field_info(stmt->result, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
  552. for(i=0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i]) {
  553. pgType = sqltype_to_pgtype(sqlType);
  554. if (fSqlType == SQL_ALL_TYPES || fSqlType == sqlType) {
  555. row = (TupleNode *)malloc(sizeof(TupleNode) + (15 - 1)*sizeof(TupleField));
  556. /* These values can't be NULL */
  557. set_tuplefield_string(&row->tuple[0], pgtype_to_name(stmt, pgType));
  558. set_tuplefield_int2(&row->tuple[1], (Int2) sqlType);
  559. set_tuplefield_int2(&row->tuple[6], pgtype_nullable(stmt, pgType));
  560. set_tuplefield_int2(&row->tuple[7], pgtype_case_sensitive(stmt, pgType));
  561. set_tuplefield_int2(&row->tuple[8], pgtype_searchable(stmt, pgType));
  562. set_tuplefield_int2(&row->tuple[10], pgtype_money(stmt, pgType));
  563. /* Localized data-source dependent data type name (always NULL) */
  564. set_tuplefield_null(&row->tuple[12]);
  565. /* These values can be NULL */
  566. set_nullfield_int4(&row->tuple[2], pgtype_precision(stmt, pgType, PG_STATIC, PG_STATIC));
  567. set_nullfield_string(&row->tuple[3], pgtype_literal_prefix(stmt, pgType));
  568. set_nullfield_string(&row->tuple[4], pgtype_literal_suffix(stmt, pgType));
  569. set_nullfield_string(&row->tuple[5], pgtype_create_params(stmt, pgType));
  570. set_nullfield_int2(&row->tuple[9], pgtype_unsigned(stmt, pgType));
  571. set_nullfield_int2(&row->tuple[11], pgtype_auto_increment(stmt, pgType));
  572. set_nullfield_int2(&row->tuple[13], pgtype_scale(stmt, pgType));
  573. set_nullfield_int2(&row->tuple[14], pgtype_scale(stmt, pgType));
  574. QR_add_tuple(stmt->result, row);
  575. }
  576. }
  577.     stmt->status = STMT_FINISHED;
  578.     stmt->currTuple = -1;
  579. stmt->rowset_start = -1;
  580. stmt->current_col = -1;
  581.     return SQL_SUCCESS;
  582. }
  583. //      -       -       -       -       -       -       -       -       -
  584. RETCODE SQL_API SQLGetFunctions(
  585.         HDBC      hdbc,
  586.         UWORD     fFunction,
  587.         UWORD FAR *pfExists)
  588. {
  589. static char *func="SQLGetFunctions";
  590. mylog( "%s: entering...n", func);
  591.     if (fFunction == SQL_API_ALL_FUNCTIONS) {
  592. if (globals.lie) {
  593. int i;
  594. memset(pfExists, 0, sizeof(UWORD)*100);
  595. pfExists[SQL_API_SQLALLOCENV] = TRUE;
  596. pfExists[SQL_API_SQLFREEENV] = TRUE;
  597. for (i = SQL_API_SQLALLOCCONNECT; i <= SQL_NUM_FUNCTIONS; i++)
  598. pfExists[i] = TRUE;
  599. for (i = SQL_EXT_API_START; i <= SQL_EXT_API_LAST; i++)
  600. pfExists[i] = TRUE;
  601. }
  602. else {
  603. memset(pfExists, 0, sizeof(UWORD)*100);
  604. // ODBC core functions
  605. pfExists[SQL_API_SQLALLOCCONNECT]     = TRUE;
  606. pfExists[SQL_API_SQLALLOCENV]         = TRUE;
  607. pfExists[SQL_API_SQLALLOCSTMT]        = TRUE;
  608. pfExists[SQL_API_SQLBINDCOL]          = TRUE;  
  609. pfExists[SQL_API_SQLCANCEL]           = TRUE;
  610. pfExists[SQL_API_SQLCOLATTRIBUTES]    = TRUE;
  611. pfExists[SQL_API_SQLCONNECT]          = TRUE;
  612. pfExists[SQL_API_SQLDESCRIBECOL]      = TRUE;  // partial
  613. pfExists[SQL_API_SQLDISCONNECT]       = TRUE;
  614. pfExists[SQL_API_SQLERROR]            = TRUE;
  615. pfExists[SQL_API_SQLEXECDIRECT]       = TRUE;
  616. pfExists[SQL_API_SQLEXECUTE]          = TRUE;
  617. pfExists[SQL_API_SQLFETCH]            = TRUE;
  618. pfExists[SQL_API_SQLFREECONNECT]      = TRUE;
  619. pfExists[SQL_API_SQLFREEENV]          = TRUE;
  620. pfExists[SQL_API_SQLFREESTMT]         = TRUE;
  621. pfExists[SQL_API_SQLGETCURSORNAME]    = TRUE;
  622. pfExists[SQL_API_SQLNUMRESULTCOLS]    = TRUE;
  623. pfExists[SQL_API_SQLPREPARE]          = TRUE;  // complete?
  624. pfExists[SQL_API_SQLROWCOUNT]         = TRUE;
  625. pfExists[SQL_API_SQLSETCURSORNAME]    = TRUE;
  626. pfExists[SQL_API_SQLSETPARAM]         = FALSE; // odbc 1.0
  627. pfExists[SQL_API_SQLTRANSACT]         = TRUE;
  628. // ODBC level 1 functions
  629. pfExists[SQL_API_SQLBINDPARAMETER]    = TRUE;
  630. pfExists[SQL_API_SQLCOLUMNS]          = TRUE;
  631. pfExists[SQL_API_SQLDRIVERCONNECT]    = TRUE;
  632. pfExists[SQL_API_SQLGETCONNECTOPTION] = TRUE;  // partial
  633. pfExists[SQL_API_SQLGETDATA]          = TRUE;
  634. pfExists[SQL_API_SQLGETFUNCTIONS]     = TRUE;                                                       
  635. pfExists[SQL_API_SQLGETINFO]          = TRUE;
  636. pfExists[SQL_API_SQLGETSTMTOPTION]    = TRUE;  // partial
  637. pfExists[SQL_API_SQLGETTYPEINFO]      = TRUE;
  638. pfExists[SQL_API_SQLPARAMDATA]        = TRUE;
  639. pfExists[SQL_API_SQLPUTDATA]          = TRUE;
  640. pfExists[SQL_API_SQLSETCONNECTOPTION] = TRUE;  // partial
  641. pfExists[SQL_API_SQLSETSTMTOPTION]    = TRUE;
  642. pfExists[SQL_API_SQLSPECIALCOLUMNS]   = TRUE;
  643. pfExists[SQL_API_SQLSTATISTICS]       = TRUE;
  644. pfExists[SQL_API_SQLTABLES]           = TRUE;
  645. // ODBC level 2 functions
  646. pfExists[SQL_API_SQLBROWSECONNECT]    = FALSE;
  647. pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
  648. pfExists[SQL_API_SQLDATASOURCES]      = FALSE;  // only implemented by DM
  649. pfExists[SQL_API_SQLDESCRIBEPARAM]    = FALSE; // not properly implemented
  650. pfExists[SQL_API_SQLDRIVERS]          = FALSE;  // only implemented by DM
  651. pfExists[SQL_API_SQLEXTENDEDFETCH]    = TRUE;
  652. pfExists[SQL_API_SQLFOREIGNKEYS]      = TRUE;
  653. pfExists[SQL_API_SQLMORERESULTS]      = TRUE;
  654. pfExists[SQL_API_SQLNATIVESQL]        = TRUE;
  655. pfExists[SQL_API_SQLNUMPARAMS]        = TRUE;
  656. pfExists[SQL_API_SQLPARAMOPTIONS]     = FALSE;
  657. pfExists[SQL_API_SQLPRIMARYKEYS]      = TRUE;
  658. pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE;
  659. pfExists[SQL_API_SQLPROCEDURES]       = FALSE;
  660. pfExists[SQL_API_SQLSETPOS]           = TRUE;
  661. pfExists[SQL_API_SQLSETSCROLLOPTIONS] = TRUE; // odbc 1.0
  662. pfExists[SQL_API_SQLTABLEPRIVILEGES]  = FALSE;
  663. }
  664.     } else {
  665. if (globals.lie)
  666. *pfExists = TRUE;
  667. else {
  668. switch(fFunction) {
  669. case SQL_API_SQLALLOCCONNECT:     *pfExists = TRUE; break;
  670. case SQL_API_SQLALLOCENV:         *pfExists = TRUE; break;
  671. case SQL_API_SQLALLOCSTMT:        *pfExists = TRUE; break;
  672. case SQL_API_SQLBINDCOL:          *pfExists = TRUE; break;
  673. case SQL_API_SQLCANCEL:           *pfExists = TRUE; break;
  674. case SQL_API_SQLCOLATTRIBUTES:    *pfExists = TRUE; break;
  675. case SQL_API_SQLCONNECT:          *pfExists = TRUE; break;
  676. case SQL_API_SQLDESCRIBECOL:      *pfExists = TRUE; break;  // partial
  677. case SQL_API_SQLDISCONNECT:       *pfExists = TRUE; break;
  678. case SQL_API_SQLERROR:            *pfExists = TRUE; break;
  679. case SQL_API_SQLEXECDIRECT:       *pfExists = TRUE; break;
  680. case SQL_API_SQLEXECUTE:          *pfExists = TRUE; break;
  681. case SQL_API_SQLFETCH:            *pfExists = TRUE; break;
  682. case SQL_API_SQLFREECONNECT:      *pfExists = TRUE; break;
  683. case SQL_API_SQLFREEENV:          *pfExists = TRUE; break;
  684. case SQL_API_SQLFREESTMT:         *pfExists = TRUE; break;
  685. case SQL_API_SQLGETCURSORNAME:    *pfExists = TRUE; break;
  686. case SQL_API_SQLNUMRESULTCOLS:    *pfExists = TRUE; break;
  687. case SQL_API_SQLPREPARE:          *pfExists = TRUE; break;
  688. case SQL_API_SQLROWCOUNT:         *pfExists = TRUE; break;
  689. case SQL_API_SQLSETCURSORNAME:    *pfExists = TRUE; break;
  690. case SQL_API_SQLSETPARAM:         *pfExists = FALSE; break; // odbc 1.0
  691. case SQL_API_SQLTRANSACT:         *pfExists = TRUE; break;
  692. // ODBC level 1 functions
  693. case SQL_API_SQLBINDPARAMETER:    *pfExists = TRUE; break;
  694. case SQL_API_SQLCOLUMNS:          *pfExists = TRUE; break;
  695. case SQL_API_SQLDRIVERCONNECT:    *pfExists = TRUE; break;
  696. case SQL_API_SQLGETCONNECTOPTION: *pfExists = TRUE; break;  // partial
  697. case SQL_API_SQLGETDATA:          *pfExists = TRUE; break;
  698. case SQL_API_SQLGETFUNCTIONS:     *pfExists = TRUE; break;
  699. case SQL_API_SQLGETINFO:          *pfExists = TRUE; break;
  700. case SQL_API_SQLGETSTMTOPTION:    *pfExists = TRUE; break;  // partial
  701. case SQL_API_SQLGETTYPEINFO:      *pfExists = TRUE; break;
  702. case SQL_API_SQLPARAMDATA:        *pfExists = TRUE; break;
  703. case SQL_API_SQLPUTDATA:          *pfExists = TRUE; break;
  704. case SQL_API_SQLSETCONNECTOPTION: *pfExists = TRUE; break;  // partial
  705. case SQL_API_SQLSETSTMTOPTION:    *pfExists = TRUE; break;
  706. case SQL_API_SQLSPECIALCOLUMNS:   *pfExists = TRUE; break;
  707. case SQL_API_SQLSTATISTICS:       *pfExists = TRUE; break;
  708. case SQL_API_SQLTABLES:           *pfExists = TRUE; break;
  709. // ODBC level 2 functions
  710. case SQL_API_SQLBROWSECONNECT:    *pfExists = FALSE; break;
  711. case SQL_API_SQLCOLUMNPRIVILEGES: *pfExists = FALSE; break;
  712. case SQL_API_SQLDATASOURCES:      *pfExists = FALSE; break;  // only implemented by DM
  713. case SQL_API_SQLDESCRIBEPARAM:    *pfExists = FALSE; break;  // not properly implemented
  714. case SQL_API_SQLDRIVERS:          *pfExists = FALSE; break;  // only implemented by DM
  715. case SQL_API_SQLEXTENDEDFETCH:    *pfExists = TRUE; break;
  716. case SQL_API_SQLFOREIGNKEYS:      *pfExists = TRUE; break;
  717. case SQL_API_SQLMORERESULTS:      *pfExists = TRUE; break;
  718. case SQL_API_SQLNATIVESQL:        *pfExists = TRUE; break;
  719. case SQL_API_SQLNUMPARAMS:        *pfExists = TRUE; break;
  720. case SQL_API_SQLPARAMOPTIONS:     *pfExists = FALSE; break;
  721. case SQL_API_SQLPRIMARYKEYS:      *pfExists = TRUE; break;
  722. case SQL_API_SQLPROCEDURECOLUMNS: *pfExists = FALSE; break;
  723. case SQL_API_SQLPROCEDURES:       *pfExists = FALSE; break;
  724. case SQL_API_SQLSETPOS:           *pfExists = TRUE; break;
  725. case SQL_API_SQLSETSCROLLOPTIONS: *pfExists = TRUE; break; // odbc 1.0
  726. case SQL_API_SQLTABLEPRIVILEGES:  *pfExists = FALSE; break;
  727. }
  728. }
  729.     }
  730.     return SQL_SUCCESS;
  731. }
  732. RETCODE SQL_API SQLTables(
  733.                           HSTMT       hstmt,
  734.                           UCHAR FAR * szTableQualifier,
  735.                           SWORD       cbTableQualifier,
  736.                           UCHAR FAR * szTableOwner,
  737.                           SWORD       cbTableOwner,
  738.                           UCHAR FAR * szTableName,
  739.                           SWORD       cbTableName,
  740.                           UCHAR FAR * szTableType,
  741.                           SWORD       cbTableType)
  742. {
  743. static char *func = "SQLTables";
  744. StatementClass *stmt = (StatementClass *) hstmt;
  745. StatementClass *tbl_stmt;
  746. TupleNode *row;
  747. HSTMT htbl_stmt;
  748. RETCODE result;
  749. char *tableType;
  750. char tables_query[MAX_STATEMENT_LEN];
  751. char table_name[MAX_INFO_STRING], table_owner[MAX_INFO_STRING], relhasrules[MAX_INFO_STRING];
  752. ConnInfo *ci;
  753. char *prefix[32], prefixes[MEDIUM_REGISTRY_LEN];
  754. char *table_type[32], table_types[MAX_INFO_STRING];
  755. char show_system_tables, show_regular_tables, show_views;
  756. char regular_table, view, systable;
  757. int i;
  758. mylog("%s: entering...stmt=%un", func, stmt);
  759. if( ! stmt) {
  760. SC_log_error(func, "", NULL);
  761. return SQL_INVALID_HANDLE;
  762. }
  763. stmt->manual_result = TRUE;
  764. stmt->errormsg_created = TRUE;
  765. ci = &stmt->hdbc->connInfo;
  766. result = SQLAllocStmt( stmt->hdbc, &htbl_stmt);
  767. if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  768. stmt->errornumber = STMT_NO_MEMORY_ERROR;
  769. stmt->errormsg = "Couldn't allocate statement for SQLTables result.";
  770. SC_log_error(func, "", stmt);
  771. return SQL_ERROR;
  772. }
  773. tbl_stmt = (StatementClass *) htbl_stmt;
  774. // **********************************************************************
  775. // Create the query to find out the tables
  776. // **********************************************************************
  777. strcpy(tables_query, "select relname, usename, relhasrules from pg_class, pg_user");
  778. strcat(tables_query, " where relkind = 'r'");
  779. my_strcat(tables_query, " and usename like '%.*s'", szTableOwner, cbTableOwner);
  780. my_strcat(tables_query, " and relname like '%.*s'", szTableName, cbTableName);
  781. // Parse the extra systable prefix 
  782. strcpy(prefixes, globals.extra_systable_prefixes);
  783. i = 0;
  784. prefix[i] = strtok(prefixes, ";");
  785. while (prefix[i] && i<32) {
  786. prefix[++i] = strtok(NULL, ";");
  787. }
  788. /* Parse the desired table types to return */
  789. show_system_tables = FALSE;
  790. show_regular_tables = FALSE;
  791. show_views = FALSE;
  792. /* make_string mallocs memory */
  793. tableType = make_string(szTableType, cbTableType, NULL);
  794. if (tableType) {
  795. strcpy(table_types, tableType);
  796. free(tableType);
  797. i = 0;
  798. table_type[i] = strtok(table_types, ",");
  799. while (table_type[i] && i<32) {
  800. table_type[++i] = strtok(NULL, ",");
  801. }
  802. /* Check for desired table types to return */
  803. i = 0;
  804. while (table_type[i]) {
  805. if ( strstr(table_type[i], "SYSTEM TABLE"))
  806. show_system_tables = TRUE;
  807. else if ( strstr(table_type[i], "TABLE"))
  808. show_regular_tables = TRUE;
  809. else if ( strstr(table_type[i], "VIEW"))
  810. show_views = TRUE;
  811. i++;
  812. }
  813. }
  814. else {
  815. show_regular_tables = TRUE;
  816. show_views = TRUE;
  817. }
  818. /*  If not interested in SYSTEM TABLES then filter them out
  819. to save some time on the query.  If treating system tables
  820. as regular tables, then dont filter either.
  821. */
  822. if ( ! atoi(ci->show_system_tables) && ! show_system_tables) {
  823. strcat(tables_query, " and relname !~ '^" POSTGRES_SYS_PREFIX);
  824. /* Also filter out user-defined system table types */
  825. i = 0;
  826. while(prefix[i]) {
  827. strcat(tables_query, "|^");
  828. strcat(tables_query, prefix[i]);
  829. i++;
  830. }
  831. strcat(tables_query, "'");
  832. }
  833. /* filter out large objects unconditionally (they are not system tables) and match users */
  834. strcat(tables_query, " and relname !~ '^xinv[0-9]+'");
  835. strcat(tables_query, " and int4out(usesysid) = int4out(relowner)");
  836. strcat(tables_query, "order by relname");
  837. // **********************************************************************
  838. result = SQLExecDirect(htbl_stmt, tables_query, strlen(tables_query));
  839. if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  840. stmt->errormsg = SC_create_errormsg(htbl_stmt);
  841. stmt->errornumber = tbl_stmt->errornumber;
  842. SC_log_error(func, "", stmt);
  843. SQLFreeStmt(htbl_stmt, SQL_DROP);
  844. return SQL_ERROR;
  845. }
  846.     result = SQLBindCol(htbl_stmt, 1, SQL_C_CHAR,
  847.                         table_name, MAX_INFO_STRING, NULL);
  848.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  849. stmt->errormsg = tbl_stmt->errormsg;
  850. stmt->errornumber = tbl_stmt->errornumber;
  851. SC_log_error(func, "", stmt);
  852. SQLFreeStmt(htbl_stmt, SQL_DROP);
  853.         return SQL_ERROR;
  854.     }
  855.     result = SQLBindCol(htbl_stmt, 2, SQL_C_CHAR,
  856.                         table_owner, MAX_INFO_STRING, NULL);
  857.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  858. stmt->errormsg = tbl_stmt->errormsg;
  859. stmt->errornumber = tbl_stmt->errornumber;
  860. SC_log_error(func, "", stmt);
  861. SQLFreeStmt(htbl_stmt, SQL_DROP);
  862.         return SQL_ERROR;
  863.     }
  864.     result = SQLBindCol(htbl_stmt, 3, SQL_C_CHAR,
  865.                         relhasrules, MAX_INFO_STRING, NULL);
  866.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  867. stmt->errormsg = tbl_stmt->errormsg;
  868. stmt->errornumber = tbl_stmt->errornumber;
  869. SC_log_error(func, "", stmt);
  870. SQLFreeStmt(htbl_stmt, SQL_DROP);
  871.         return SQL_ERROR;
  872.     }
  873. stmt->result = QR_Constructor();
  874. if(!stmt->result) {
  875. stmt->errormsg = "Couldn't allocate memory for SQLTables result.";
  876. stmt->errornumber = STMT_NO_MEMORY_ERROR;
  877. SC_log_error(func, "", stmt);
  878. SQLFreeStmt(htbl_stmt, SQL_DROP);
  879. return SQL_ERROR;
  880. }
  881.     // the binding structure for a statement is not set up until
  882.     // a statement is actually executed, so we'll have to do this ourselves.
  883. extend_bindings(stmt, 5);
  884.     // set the field names
  885. QR_set_num_fields(stmt->result, 5);
  886. QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
  887. QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
  888. QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  889. QR_set_field_info(stmt->result, 3, "TABLE_TYPE", PG_TYPE_TEXT, MAX_INFO_STRING);
  890. QR_set_field_info(stmt->result, 4, "REMARKS", PG_TYPE_TEXT, 254);
  891.     // add the tuples
  892. result = SQLFetch(htbl_stmt);
  893. while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
  894. /* Determine if this table name is a system table.
  895. If treating system tables as regular tables, then 
  896. no need to do this test.
  897. */
  898. systable = FALSE;
  899. if( ! atoi(ci->show_system_tables)) {
  900. if ( strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0)
  901. systable = TRUE;
  902. else { /* Check extra system table prefixes */
  903. i = 0;
  904. while (prefix[i]) {
  905. mylog("table_name='%s', prefix[%d]='%s'n", table_name, i, prefix[i]);
  906. if (strncmp(table_name, prefix[i], strlen(prefix[i])) == 0) {
  907. systable = TRUE;
  908. break;
  909. }
  910. i++;
  911. }
  912. }
  913. }
  914. /* Determine if the table name is a view */
  915. view = (relhasrules[0] == '1');
  916. /* It must be a regular table */
  917. regular_table = ( ! systable && ! view);
  918. /* Include the row in the result set if meets all criteria */
  919. /* NOTE: Unsupported table types (i.e., LOCAL TEMPORARY, ALIAS, etc)
  920. will return nothing */
  921. if ( (systable && show_system_tables) ||
  922.  (view && show_views) || 
  923.  (regular_table && show_regular_tables)) {
  924. row = (TupleNode *)malloc(sizeof(TupleNode) + (5 - 1) * sizeof(TupleField));
  925. set_tuplefield_string(&row->tuple[0], "");
  926. // I have to hide the table owner from Access, otherwise it
  927. // insists on referring to the table as 'owner.table'.
  928. // (this is valid according to the ODBC SQL grammar, but
  929. // Postgres won't support it.)
  930. // set_tuplefield_string(&row->tuple[1], table_owner);
  931. mylog("SQLTables: table_name = '%s'n", table_name);
  932. set_tuplefield_string(&row->tuple[1], "");
  933. set_tuplefield_string(&row->tuple[2], table_name);
  934. set_tuplefield_string(&row->tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE"));
  935. set_tuplefield_string(&row->tuple[4], "");
  936. QR_add_tuple(stmt->result, row);
  937. }
  938. result = SQLFetch(htbl_stmt);
  939.     }
  940. if(result != SQL_NO_DATA_FOUND) {
  941. stmt->errormsg = SC_create_errormsg(htbl_stmt);
  942. stmt->errornumber = tbl_stmt->errornumber;
  943. SC_log_error(func, "", stmt);
  944. SQLFreeStmt(htbl_stmt, SQL_DROP);
  945. return SQL_ERROR;
  946. }
  947.     // also, things need to think that this statement is finished so
  948.     // the results can be retrieved.
  949. stmt->status = STMT_FINISHED;
  950.     // set up the current tuple pointer for SQLFetch
  951. stmt->currTuple = -1;
  952. stmt->rowset_start = -1;
  953. stmt->current_col = -1;
  954. SQLFreeStmt(htbl_stmt, SQL_DROP);
  955. mylog("SQLTables(): EXIT,  stmt=%un", stmt);
  956. return SQL_SUCCESS;
  957. }
  958. RETCODE SQL_API SQLColumns(
  959.                            HSTMT        hstmt,
  960.                            UCHAR FAR *  szTableQualifier,
  961.                            SWORD        cbTableQualifier,
  962.                            UCHAR FAR *  szTableOwner,
  963.                            SWORD        cbTableOwner,
  964.                            UCHAR FAR *  szTableName,
  965.                            SWORD        cbTableName,
  966.                            UCHAR FAR *  szColumnName,
  967.                            SWORD        cbColumnName)
  968. {
  969. static char *func = "SQLColumns";
  970. StatementClass *stmt = (StatementClass *) hstmt;
  971. TupleNode *row;
  972. HSTMT hcol_stmt;
  973. StatementClass *col_stmt;
  974. char columns_query[MAX_STATEMENT_LEN];
  975. RETCODE result;
  976. char table_owner[MAX_INFO_STRING], table_name[MAX_INFO_STRING], field_name[MAX_INFO_STRING], field_type_name[MAX_INFO_STRING];
  977. Int2 field_number, result_cols;
  978. Int4 field_type, the_type, field_length, mod_length;
  979. char not_null[MAX_INFO_STRING];
  980. ConnInfo *ci;
  981. mylog("%s: entering...stmt=%un", func, stmt);
  982. if( ! stmt) {
  983. SC_log_error(func, "", NULL);
  984. return SQL_INVALID_HANDLE;
  985. }
  986. stmt->manual_result = TRUE;
  987. stmt->errormsg_created = TRUE;
  988. ci = &stmt->hdbc->connInfo;
  989. // **********************************************************************
  990. // Create the query to find out the columns (Note: pre 6.3 did not have the atttypmod field)
  991. // **********************************************************************
  992. sprintf(columns_query, "select u.usename, c.relname, a.attname, a.atttypid,t.typname, a.attnum, a.attlen, %s, a.attnotnull from pg_user u, pg_class c, pg_attribute a, pg_type t where "
  993. "int4out(u.usesysid) = int4out(c.relowner) and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)",
  994. PROTOCOL_62(ci) ? "a.attlen" : "a.atttypmod");
  995. my_strcat(columns_query, " and c.relname like '%.*s'", szTableName, cbTableName);
  996. my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner);
  997. my_strcat(columns_query, " and a.attname like '%.*s'", szColumnName, cbColumnName);
  998.     // give the output in the order the columns were defined
  999.     // when the table was created
  1000.     strcat(columns_query, " order by attnum");
  1001. // **********************************************************************
  1002.     result = SQLAllocStmt( stmt->hdbc, &hcol_stmt);
  1003.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1004. stmt->errornumber = STMT_NO_MEMORY_ERROR;
  1005. stmt->errormsg = "Couldn't allocate statement for SQLColumns result.";
  1006. SC_log_error(func, "", stmt);
  1007.         return SQL_ERROR;
  1008.     }
  1009. col_stmt = (StatementClass *) hcol_stmt;
  1010. mylog("SQLColumns: hcol_stmt = %u, col_stmt = %un", hcol_stmt, col_stmt);
  1011.     result = SQLExecDirect(hcol_stmt, columns_query,
  1012.                            strlen(columns_query));
  1013.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1014. stmt->errormsg = SC_create_errormsg(hcol_stmt);
  1015. stmt->errornumber = col_stmt->errornumber;
  1016. SC_log_error(func, "", stmt);
  1017. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1018.         return SQL_ERROR;
  1019.     }
  1020.     result = SQLBindCol(hcol_stmt, 1, SQL_C_CHAR,
  1021.                         table_owner, MAX_INFO_STRING, NULL);
  1022.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1023. stmt->errormsg = col_stmt->errormsg;
  1024. stmt->errornumber = col_stmt->errornumber;
  1025. SC_log_error(func, "", stmt);
  1026. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1027.         return SQL_ERROR;
  1028.     }
  1029.     result = SQLBindCol(hcol_stmt, 2, SQL_C_CHAR,
  1030.                         table_name, MAX_INFO_STRING, NULL);
  1031.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1032. stmt->errormsg = col_stmt->errormsg;
  1033. stmt->errornumber = col_stmt->errornumber;
  1034. SC_log_error(func, "", stmt);
  1035. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1036.         return SQL_ERROR;
  1037.     }
  1038.     result = SQLBindCol(hcol_stmt, 3, SQL_C_CHAR,
  1039.                         field_name, MAX_INFO_STRING, NULL);
  1040.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1041. stmt->errormsg = col_stmt->errormsg;
  1042. stmt->errornumber = col_stmt->errornumber;
  1043. SC_log_error(func, "", stmt);
  1044. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1045.         return SQL_ERROR;
  1046.     }
  1047.     result = SQLBindCol(hcol_stmt, 4, SQL_C_LONG,
  1048.                         &field_type, 4, NULL);
  1049.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1050. stmt->errormsg = col_stmt->errormsg;
  1051. stmt->errornumber = col_stmt->errornumber;
  1052. SC_log_error(func, "", stmt);
  1053. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1054.         return SQL_ERROR;
  1055.     }
  1056.     result = SQLBindCol(hcol_stmt, 5, SQL_C_CHAR,
  1057.                         field_type_name, MAX_INFO_STRING, NULL);
  1058.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1059. stmt->errormsg = col_stmt->errormsg;
  1060. stmt->errornumber = col_stmt->errornumber;
  1061. SC_log_error(func, "", stmt);
  1062. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1063.         return SQL_ERROR;
  1064.     }
  1065.     result = SQLBindCol(hcol_stmt, 6, SQL_C_SHORT,
  1066.                         &field_number, MAX_INFO_STRING, NULL);
  1067.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1068. stmt->errormsg = col_stmt->errormsg;
  1069. stmt->errornumber = col_stmt->errornumber;
  1070. SC_log_error(func, "", stmt);
  1071. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1072.         return SQL_ERROR;
  1073.     }
  1074.     result = SQLBindCol(hcol_stmt, 7, SQL_C_LONG,
  1075.                         &field_length, MAX_INFO_STRING, NULL);
  1076.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1077. stmt->errormsg = col_stmt->errormsg;
  1078. stmt->errornumber = col_stmt->errornumber;
  1079. SC_log_error(func, "", stmt);
  1080. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1081.         return SQL_ERROR;
  1082.     }
  1083.     result = SQLBindCol(hcol_stmt, 8, SQL_C_LONG,
  1084.                         &mod_length, MAX_INFO_STRING, NULL);
  1085.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1086. stmt->errormsg = col_stmt->errormsg;
  1087. stmt->errornumber = col_stmt->errornumber;
  1088. SC_log_error(func, "", stmt);
  1089. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1090.         return SQL_ERROR;
  1091.     }
  1092.     result = SQLBindCol(hcol_stmt, 9, SQL_C_CHAR,
  1093.                         not_null, MAX_INFO_STRING, NULL);
  1094.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1095. stmt->errormsg = col_stmt->errormsg;
  1096. stmt->errornumber = col_stmt->errornumber;
  1097. SC_log_error(func, "", stmt);
  1098. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1099.         return SQL_ERROR;
  1100.     }
  1101.     stmt->result = QR_Constructor();
  1102.     if(!stmt->result) {
  1103. stmt->errormsg = "Couldn't allocate memory for SQLColumns result.";
  1104.         stmt->errornumber = STMT_NO_MEMORY_ERROR;
  1105. SC_log_error(func, "", stmt);
  1106. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1107.         return SQL_ERROR;
  1108.     }
  1109.     // the binding structure for a statement is not set up until
  1110.     // a statement is actually executed, so we'll have to do this ourselves.
  1111. result_cols = 14;
  1112.     extend_bindings(stmt, result_cols);
  1113.     // set the field names
  1114.     QR_set_num_fields(stmt->result, result_cols);
  1115.     QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
  1116.     QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
  1117.     QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1118.     QR_set_field_info(stmt->result, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1119.     QR_set_field_info(stmt->result, 4, "DATA_TYPE", PG_TYPE_INT2, 2);
  1120.     QR_set_field_info(stmt->result, 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1121.     QR_set_field_info(stmt->result, 6, "PRECISION", PG_TYPE_INT4, 4);
  1122.     QR_set_field_info(stmt->result, 7, "LENGTH", PG_TYPE_INT4, 4);
  1123.     QR_set_field_info(stmt->result, 8, "SCALE", PG_TYPE_INT2, 2);
  1124.     QR_set_field_info(stmt->result, 9, "RADIX", PG_TYPE_INT2, 2);
  1125.     QR_set_field_info(stmt->result, 10, "NULLABLE", PG_TYPE_INT2, 2);
  1126.     QR_set_field_info(stmt->result, 11, "REMARKS", PG_TYPE_TEXT, 254);
  1127. // User defined fields
  1128.     QR_set_field_info(stmt->result, 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
  1129. QR_set_field_info(stmt->result, 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
  1130. result = SQLFetch(hcol_stmt);
  1131. /* Only show oid if option AND there are other columns AND 
  1132. its not being called by SQLStatistics .
  1133. Always show OID if its a system table
  1134. */
  1135. if (result != SQL_ERROR && ! stmt->internal) {
  1136. if (atoi(ci->show_oid_column) || strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0) {
  1137. /* For OID fields */
  1138. the_type = PG_TYPE_OID;
  1139. row = (TupleNode *)malloc(sizeof(TupleNode) +
  1140.   (result_cols - 1) * sizeof(TupleField));
  1141. set_tuplefield_string(&row->tuple[0], "");
  1142. // see note in SQLTables()
  1143. //      set_tuplefield_string(&row->tuple[1], table_owner);
  1144. set_tuplefield_string(&row->tuple[1], "");
  1145. set_tuplefield_string(&row->tuple[2], table_name);
  1146. set_tuplefield_string(&row->tuple[3], "oid");
  1147. set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, the_type));
  1148. set_tuplefield_string(&row->tuple[5], "OID");
  1149. set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
  1150. set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, the_type, PG_STATIC, PG_STATIC));
  1151. set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, the_type));
  1152. set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, the_type));
  1153. set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS);
  1154. set_tuplefield_string(&row->tuple[11], "");
  1155. set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
  1156. set_tuplefield_int4(&row->tuple[13], the_type);
  1157. QR_add_tuple(stmt->result, row);
  1158. }
  1159. }
  1160.     while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
  1161.         row = (TupleNode *)malloc(sizeof(TupleNode) +
  1162.                                   (result_cols - 1) * sizeof(TupleField));
  1163.         set_tuplefield_string(&row->tuple[0], "");
  1164.         // see note in SQLTables()
  1165.         //      set_tuplefield_string(&row->tuple[1], table_owner);
  1166.         set_tuplefield_string(&row->tuple[1], "");
  1167.         set_tuplefield_string(&row->tuple[2], table_name);
  1168.         set_tuplefield_string(&row->tuple[3], field_name);
  1169.         set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, field_type));
  1170.         set_tuplefield_string(&row->tuple[5], field_type_name);
  1171. /* Some Notes about Postgres Data Types:
  1172. VARCHAR - the length is stored in the pg_attribute.atttypmod field
  1173. BPCHAR  - the length is also stored as varchar is
  1174. */
  1175.         if((field_type == PG_TYPE_VARCHAR) ||
  1176.    (field_type == PG_TYPE_BPCHAR)) {
  1177. if (mod_length >= 4)
  1178. mod_length -= 4; // the length is in atttypmod - 4
  1179. if (mod_length > globals.max_varchar_size || mod_length <= 0)
  1180. mod_length = globals.max_varchar_size;
  1181. mylog("SQLColumns: field type is VARCHAR,BPCHAR: field_type = %d, mod_length = %dn", field_type, mod_length);
  1182.             set_tuplefield_int4(&row->tuple[7], mod_length);
  1183. set_tuplefield_int4(&row->tuple[6], mod_length);
  1184. set_tuplefield_int4(&row->tuple[12], mod_length);
  1185.         } else {
  1186. mylog("SQLColumns: field type is OTHER: field_type = %d, pgtype_length = %dn", field_type, pgtype_length(stmt, field_type, PG_STATIC, PG_STATIC));
  1187.             set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, field_type, PG_STATIC, PG_STATIC));
  1188. set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, field_type, PG_STATIC, PG_STATIC));
  1189. set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, field_type, PG_STATIC, PG_STATIC));
  1190.         }
  1191. set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, field_type));
  1192. set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, field_type));
  1193. set_tuplefield_int2(&row->tuple[10], (Int2) (not_null[0] == '1' ? SQL_NO_NULLS : pgtype_nullable(stmt, field_type)));
  1194. set_tuplefield_string(&row->tuple[11], "");
  1195. set_tuplefield_int4(&row->tuple[13], field_type);
  1196.         QR_add_tuple(stmt->result, row);
  1197.         result = SQLFetch(hcol_stmt);
  1198.     }
  1199.     if(result != SQL_NO_DATA_FOUND) {
  1200. stmt->errormsg = SC_create_errormsg(hcol_stmt);
  1201. stmt->errornumber = col_stmt->errornumber;
  1202. SC_log_error(func, "", stmt);
  1203. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1204.         return SQL_ERROR;
  1205.     }
  1206. // Put the row version column at the end so it might not be
  1207. // mistaken for a key field.
  1208. if ( ! stmt->internal && atoi(ci->row_versioning)) {
  1209. /* For Row Versioning fields */
  1210. the_type = PG_TYPE_INT4;
  1211. row = (TupleNode *)malloc(sizeof(TupleNode) +
  1212.   (result_cols - 1) * sizeof(TupleField));
  1213. set_tuplefield_string(&row->tuple[0], "");
  1214. set_tuplefield_string(&row->tuple[1], "");
  1215. set_tuplefield_string(&row->tuple[2], table_name);
  1216. set_tuplefield_string(&row->tuple[3], "xmin");
  1217. set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, the_type));
  1218. set_tuplefield_string(&row->tuple[5], pgtype_to_name(stmt, the_type));
  1219. set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, the_type, PG_STATIC, PG_STATIC));
  1220. set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
  1221. set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, the_type));
  1222. set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, the_type));
  1223. set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS);
  1224. set_tuplefield_string(&row->tuple[11], "");
  1225. set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
  1226. set_tuplefield_int4(&row->tuple[13], the_type);
  1227. QR_add_tuple(stmt->result, row);
  1228. }
  1229.     // also, things need to think that this statement is finished so
  1230.     // the results can be retrieved.
  1231.     stmt->status = STMT_FINISHED;
  1232.     // set up the current tuple pointer for SQLFetch
  1233.     stmt->currTuple = -1;
  1234. stmt->rowset_start = -1;
  1235. stmt->current_col = -1;
  1236. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1237. mylog("SQLColumns(): EXIT,  stmt=%un", stmt);
  1238.     return SQL_SUCCESS;
  1239. }
  1240. RETCODE SQL_API SQLSpecialColumns(
  1241.                                   HSTMT        hstmt,
  1242.                                   UWORD        fColType,
  1243.                                   UCHAR FAR *  szTableQualifier,
  1244.                                   SWORD        cbTableQualifier,
  1245.                                   UCHAR FAR *  szTableOwner,
  1246.                                   SWORD        cbTableOwner,
  1247.                                   UCHAR FAR *  szTableName,
  1248.                                   SWORD        cbTableName,
  1249.                                   UWORD        fScope,
  1250.                                   UWORD        fNullable)
  1251. {
  1252. static char *func = "SQLSpecialColumns";
  1253. TupleNode *row;
  1254. StatementClass *stmt = (StatementClass *) hstmt;
  1255. ConnInfo *ci;
  1256. mylog("%s: entering...stmt=%un", func, stmt);
  1257.     if( ! stmt) {
  1258. SC_log_error(func, "", NULL);
  1259.         return SQL_INVALID_HANDLE;
  1260.     }
  1261. ci = &stmt->hdbc->connInfo;
  1262. stmt->manual_result = TRUE;
  1263.     stmt->result = QR_Constructor();
  1264.     extend_bindings(stmt, 8);
  1265.     QR_set_num_fields(stmt->result, 8);
  1266.     QR_set_field_info(stmt->result, 0, "SCOPE", PG_TYPE_INT2, 2);
  1267.     QR_set_field_info(stmt->result, 1, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1268.     QR_set_field_info(stmt->result, 2, "DATA_TYPE", PG_TYPE_INT2, 2);
  1269.     QR_set_field_info(stmt->result, 3, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1270.     QR_set_field_info(stmt->result, 4, "PRECISION", PG_TYPE_INT4, 4);
  1271.     QR_set_field_info(stmt->result, 5, "LENGTH", PG_TYPE_INT4, 4);
  1272.     QR_set_field_info(stmt->result, 6, "SCALE", PG_TYPE_INT2, 2);
  1273.     QR_set_field_info(stmt->result, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2);
  1274.     /* use the oid value for the rowid */
  1275.     if(fColType == SQL_BEST_ROWID) {
  1276.         row = (TupleNode *)malloc(sizeof(TupleNode) + (8 - 1) * sizeof(TupleField));
  1277.         set_tuplefield_int2(&row->tuple[0], SQL_SCOPE_SESSION);
  1278.         set_tuplefield_string(&row->tuple[1], "oid");
  1279.         set_tuplefield_int2(&row->tuple[2], pgtype_to_sqltype(stmt, PG_TYPE_OID));
  1280.         set_tuplefield_string(&row->tuple[3], "OID");
  1281.         set_tuplefield_int4(&row->tuple[4], pgtype_precision(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
  1282.         set_tuplefield_int4(&row->tuple[5], pgtype_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
  1283.         set_tuplefield_int2(&row->tuple[6], pgtype_scale(stmt, PG_TYPE_OID));
  1284.         set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
  1285.         QR_add_tuple(stmt->result, row);
  1286.     } else if(fColType == SQL_ROWVER) {
  1287. Int2 the_type = PG_TYPE_INT4;
  1288. if (atoi(ci->row_versioning)) {
  1289. row = (TupleNode *)malloc(sizeof(TupleNode) + (8 - 1) * sizeof(TupleField));
  1290. set_tuplefield_null(&row->tuple[0]);
  1291. set_tuplefield_string(&row->tuple[1], "xmin");
  1292. set_tuplefield_int2(&row->tuple[2], pgtype_to_sqltype(stmt, the_type));
  1293. set_tuplefield_string(&row->tuple[3], pgtype_to_name(stmt, the_type));
  1294. set_tuplefield_int4(&row->tuple[4], pgtype_precision(stmt, the_type, PG_STATIC, PG_STATIC));
  1295. set_tuplefield_int4(&row->tuple[5], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
  1296. set_tuplefield_int2(&row->tuple[6], pgtype_scale(stmt, the_type));
  1297. set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
  1298. QR_add_tuple(stmt->result, row);
  1299. }
  1300. }
  1301.     stmt->status = STMT_FINISHED;
  1302.     stmt->currTuple = -1;
  1303. stmt->rowset_start = -1;
  1304. stmt->current_col = -1;
  1305. mylog("SQLSpecialColumns(): EXIT,  stmt=%un", stmt);
  1306.     return SQL_SUCCESS;
  1307. }
  1308. RETCODE SQL_API SQLStatistics(
  1309.                               HSTMT         hstmt,
  1310.                               UCHAR FAR *   szTableQualifier,
  1311.                               SWORD         cbTableQualifier,
  1312.                               UCHAR FAR *   szTableOwner,
  1313.                               SWORD         cbTableOwner,
  1314.                               UCHAR FAR *   szTableName,
  1315.                               SWORD         cbTableName,
  1316.                               UWORD         fUnique,
  1317.                               UWORD         fAccuracy)
  1318. {
  1319. static char *func="SQLStatistics";
  1320. StatementClass *stmt = (StatementClass *) hstmt;
  1321. char index_query[MAX_STATEMENT_LEN];
  1322. HSTMT hindx_stmt;
  1323. RETCODE result;
  1324. char *table_name;
  1325. char index_name[MAX_INFO_STRING];
  1326. short fields_vector[8];
  1327. char isunique[10], isclustered[10];
  1328. SDWORD index_name_len, fields_vector_len;
  1329. TupleNode *row;
  1330. int i;
  1331. HSTMT hcol_stmt;
  1332. StatementClass *col_stmt, *indx_stmt;
  1333. char column_name[MAX_INFO_STRING];
  1334. char **column_names = 0;
  1335. Int4 column_name_len;
  1336. int total_columns = 0;
  1337. char error = TRUE;
  1338. ConnInfo *ci;
  1339. char buf[256];
  1340. mylog("%s: entering...stmt=%un", func, stmt);
  1341.     if( ! stmt) {
  1342. SC_log_error(func, "", NULL);
  1343.         return SQL_INVALID_HANDLE;
  1344.     }
  1345. stmt->manual_result = TRUE;
  1346. stmt->errormsg_created = TRUE;
  1347. ci = &stmt->hdbc->connInfo;
  1348.     stmt->result = QR_Constructor();
  1349.     if(!stmt->result) {
  1350.         stmt->errormsg = "Couldn't allocate memory for SQLStatistics result.";
  1351.         stmt->errornumber = STMT_NO_MEMORY_ERROR;
  1352. SC_log_error(func, "", stmt);
  1353.         return SQL_ERROR;
  1354.     }
  1355.     // the binding structure for a statement is not set up until
  1356.     // a statement is actually executed, so we'll have to do this ourselves.
  1357.     extend_bindings(stmt, 13);
  1358.     // set the field names
  1359.     QR_set_num_fields(stmt->result, 13);
  1360.     QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
  1361.     QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
  1362.     QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1363.     QR_set_field_info(stmt->result, 3, "NON_UNIQUE", PG_TYPE_INT2, 2);
  1364.     QR_set_field_info(stmt->result, 4, "INDEX_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
  1365.     QR_set_field_info(stmt->result, 5, "INDEX_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1366.     QR_set_field_info(stmt->result, 6, "TYPE", PG_TYPE_INT2, 2);
  1367.     QR_set_field_info(stmt->result, 7, "SEQ_IN_INDEX", PG_TYPE_INT2, 2);
  1368.     QR_set_field_info(stmt->result, 8, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1369.     QR_set_field_info(stmt->result, 9, "COLLATION", PG_TYPE_CHAR, 1);
  1370.     QR_set_field_info(stmt->result, 10, "CARDINALITY", PG_TYPE_INT4, 4);
  1371.     QR_set_field_info(stmt->result, 11, "PAGES", PG_TYPE_INT4, 4);
  1372.     QR_set_field_info(stmt->result, 12, "FILTER_CONDITION", PG_TYPE_TEXT, MAX_INFO_STRING);
  1373.     // only use the table name... the owner should be redundant, and
  1374.     // we never use qualifiers.
  1375. table_name = make_string(szTableName, cbTableName, NULL);
  1376. if ( ! table_name) {
  1377.         stmt->errormsg = "No table name passed to SQLStatistics.";
  1378.         stmt->errornumber = STMT_INTERNAL_ERROR;
  1379. SC_log_error(func, "", stmt);
  1380.         return SQL_ERROR;
  1381.     }
  1382. // we need to get a list of the field names first,
  1383. // so we can return them later.
  1384. result = SQLAllocStmt( stmt->hdbc, &hcol_stmt);
  1385. if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1386. stmt->errormsg = "SQLAllocStmt failed in SQLStatistics for columns.";
  1387. stmt->errornumber = STMT_NO_MEMORY_ERROR;
  1388. goto SEEYA;
  1389. }
  1390. col_stmt = (StatementClass *) hcol_stmt;
  1391. /* "internal" prevents SQLColumns from returning the oid if it is being shown.
  1392. This would throw everything off.
  1393. */
  1394. col_stmt->internal = TRUE;
  1395. result = SQLColumns(hcol_stmt, "", 0, "", 0, 
  1396. table_name, (SWORD) strlen(table_name), "", 0);
  1397. col_stmt->internal = FALSE;
  1398. if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1399. stmt->errormsg = col_stmt->errormsg;        // "SQLColumns failed in SQLStatistics.";
  1400. stmt->errornumber = col_stmt->errornumber;  // STMT_EXEC_ERROR;
  1401. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1402. goto SEEYA;
  1403. }
  1404. result = SQLBindCol(hcol_stmt, 4, SQL_C_CHAR,
  1405. column_name, MAX_INFO_STRING, &column_name_len);
  1406. if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1407. stmt->errormsg = col_stmt->errormsg;
  1408. stmt->errornumber = col_stmt->errornumber;
  1409. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1410. goto SEEYA;
  1411. }
  1412. result = SQLFetch(hcol_stmt);
  1413. while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
  1414. total_columns++;
  1415. column_names = 
  1416. (char **)realloc(column_names, 
  1417.  total_columns * sizeof(char *));
  1418. column_names[total_columns-1] = 
  1419. (char *)malloc(strlen(column_name)+1);
  1420. strcpy(column_names[total_columns-1], column_name);
  1421. mylog("SQLStatistics: column_name = '%s'n", column_name);
  1422. result = SQLFetch(hcol_stmt);
  1423. }
  1424. if(result != SQL_NO_DATA_FOUND || total_columns == 0) {
  1425. stmt->errormsg = SC_create_errormsg(hcol_stmt); // "Couldn't get column names in SQLStatistics.";
  1426. stmt->errornumber = col_stmt->errornumber;
  1427. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1428.     goto SEEYA;
  1429. }
  1430. SQLFreeStmt(hcol_stmt, SQL_DROP);
  1431.     // get a list of indexes on this table
  1432.     result = SQLAllocStmt( stmt->hdbc, &hindx_stmt);
  1433.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1434. stmt->errormsg = "SQLAllocStmt failed in SQLStatistics for indices.";
  1435. stmt->errornumber = STMT_NO_MEMORY_ERROR;
  1436. goto SEEYA;
  1437.     }
  1438. indx_stmt = (StatementClass *) hindx_stmt;
  1439. sprintf(index_query, "select c.relname, i.indkey, i.indisunique, i.indisclustered from pg_index i, pg_class c, pg_class d where c.oid = i.indexrelid and d.relname = '%s' and d.oid = i.indrelid", 
  1440. table_name);
  1441.     result = SQLExecDirect(hindx_stmt, index_query, strlen(index_query));
  1442.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1443. stmt->errormsg = SC_create_errormsg(hindx_stmt); // "Couldn't execute index query (w/SQLExecDirect) in SQLStatistics.";
  1444. stmt->errornumber = indx_stmt->errornumber;
  1445. SQLFreeStmt(hindx_stmt, SQL_DROP);
  1446.    goto SEEYA;
  1447.     }
  1448.     // bind the index name column
  1449.     result = SQLBindCol(hindx_stmt, 1, SQL_C_CHAR,
  1450.                         index_name, MAX_INFO_STRING, &index_name_len);
  1451.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1452. stmt->errormsg = indx_stmt->errormsg; // "Couldn't bind column in SQLStatistics.";
  1453. stmt->errornumber = indx_stmt->errornumber;
  1454. SQLFreeStmt(hindx_stmt, SQL_DROP);
  1455.     goto SEEYA;
  1456.     }
  1457.     // bind the vector column
  1458.     result = SQLBindCol(hindx_stmt, 2, SQL_C_DEFAULT,
  1459.                         fields_vector, 16, &fields_vector_len);
  1460.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1461. stmt->errormsg = indx_stmt->errormsg;  // "Couldn't bind column in SQLStatistics.";
  1462. stmt->errornumber = indx_stmt->errornumber;
  1463. SQLFreeStmt(hindx_stmt, SQL_DROP);
  1464. goto SEEYA;
  1465.     }
  1466.     // bind the "is unique" column
  1467.     result = SQLBindCol(hindx_stmt, 3, SQL_C_CHAR,
  1468.                         isunique, sizeof(isunique), NULL);
  1469.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1470. stmt->errormsg = indx_stmt->errormsg;  // "Couldn't bind column in SQLStatistics.";
  1471. stmt->errornumber = indx_stmt->errornumber;
  1472. SQLFreeStmt(hindx_stmt, SQL_DROP);
  1473. goto SEEYA;
  1474.     }
  1475.     // bind the "is clustered" column
  1476.     result = SQLBindCol(hindx_stmt, 4, SQL_C_CHAR,
  1477.                         isclustered, sizeof(isclustered), NULL);
  1478.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1479. stmt->errormsg = indx_stmt->errormsg;  // "Couldn't bind column in SQLStatistics.";
  1480. stmt->errornumber = indx_stmt->errornumber;
  1481. SQLFreeStmt(hindx_stmt, SQL_DROP);
  1482. goto SEEYA;
  1483.     }
  1484. /* fake index of OID */
  1485. if (atoi(ci->show_oid_column) && atoi(ci->fake_oid_index)) {
  1486. row = (TupleNode *)malloc(sizeof(TupleNode) + 
  1487.   (13 - 1) * sizeof(TupleField));
  1488. // no table qualifier
  1489. set_tuplefield_string(&row->tuple[0], "");
  1490. // don't set the table owner, else Access tries to use it
  1491. set_tuplefield_string(&row->tuple[1], "");
  1492. set_tuplefield_string(&row->tuple[2], table_name);
  1493. // non-unique index?
  1494. set_tuplefield_int2(&row->tuple[3], (Int2) (globals.unique_index ? FALSE : TRUE));
  1495. // no index qualifier
  1496. set_tuplefield_string(&row->tuple[4], "");
  1497. sprintf(buf, "%s_idx_fake_oid", table_name);
  1498. set_tuplefield_string(&row->tuple[5], buf);
  1499. // Clustered index?  I think non-clustered should be type OTHER not HASHED
  1500. set_tuplefield_int2(&row->tuple[6], (Int2) SQL_INDEX_OTHER);
  1501. set_tuplefield_int2(&row->tuple[7], (Int2) 1);
  1502. set_tuplefield_string(&row->tuple[8], "oid");
  1503. set_tuplefield_string(&row->tuple[9], "A");
  1504. set_tuplefield_null(&row->tuple[10]);
  1505. set_tuplefield_null(&row->tuple[11]);
  1506. set_tuplefield_null(&row->tuple[12]);
  1507. QR_add_tuple(stmt->result, row);
  1508. }
  1509.     result = SQLFetch(hindx_stmt);
  1510.     while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
  1511. // If only requesting unique indexs, then just return those.
  1512. if (fUnique == SQL_INDEX_ALL || 
  1513. (fUnique == SQL_INDEX_UNIQUE && atoi(isunique))) {
  1514. i = 0;
  1515. // add a row in this table for each field in the index
  1516. while(i < 8 && fields_vector[i] != 0) {
  1517. row = (TupleNode *)malloc(sizeof(TupleNode) + 
  1518.   (13 - 1) * sizeof(TupleField));
  1519. // no table qualifier
  1520. set_tuplefield_string(&row->tuple[0], "");
  1521. // don't set the table owner, else Access tries to use it
  1522. set_tuplefield_string(&row->tuple[1], "");
  1523. set_tuplefield_string(&row->tuple[2], table_name);
  1524. // non-unique index?
  1525. if (globals.unique_index)
  1526. set_tuplefield_int2(&row->tuple[3], (Int2) (atoi(isunique) ? FALSE : TRUE));
  1527. else
  1528. set_tuplefield_int2(&row->tuple[3], TRUE);
  1529. // no index qualifier
  1530. set_tuplefield_string(&row->tuple[4], "");
  1531. set_tuplefield_string(&row->tuple[5], index_name);
  1532. // Clustered index?  I think non-clustered should be type OTHER not HASHED
  1533. set_tuplefield_int2(&row->tuple[6], (Int2) (atoi(isclustered) ? SQL_INDEX_CLUSTERED : SQL_INDEX_OTHER));
  1534. set_tuplefield_int2(&row->tuple[7], (Int2) (i+1));
  1535. if(fields_vector[i] == OID_ATTNUM) {
  1536. set_tuplefield_string(&row->tuple[8], "oid");
  1537. mylog("SQLStatistics: column name = oidn");
  1538. }
  1539. else if(fields_vector[i] < 0 || fields_vector[i] > total_columns) {
  1540. set_tuplefield_string(&row->tuple[8], "UNKNOWN");
  1541. mylog("SQLStatistics: column name = UNKNOWNn");
  1542. }
  1543. else {
  1544. set_tuplefield_string(&row->tuple[8], column_names[fields_vector[i]-1]);
  1545. mylog("SQLStatistics: column name = '%s'n", column_names[fields_vector[i]-1]);
  1546. }
  1547. set_tuplefield_string(&row->tuple[9], "A");
  1548. set_tuplefield_null(&row->tuple[10]);
  1549. set_tuplefield_null(&row->tuple[11]);
  1550. set_tuplefield_null(&row->tuple[12]);
  1551. QR_add_tuple(stmt->result, row);
  1552. i++;
  1553. }
  1554. }
  1555.         result = SQLFetch(hindx_stmt);
  1556.     }
  1557.     if(result != SQL_NO_DATA_FOUND) {
  1558. stmt->errormsg = SC_create_errormsg(hindx_stmt); // "SQLFetch failed in SQLStatistics.";
  1559. stmt->errornumber = indx_stmt->errornumber;
  1560. SQLFreeStmt(hindx_stmt, SQL_DROP);
  1561. goto SEEYA;
  1562.     }
  1563. SQLFreeStmt(hindx_stmt, SQL_DROP);
  1564.     // also, things need to think that this statement is finished so
  1565.     // the results can be retrieved.
  1566.     stmt->status = STMT_FINISHED;
  1567.     // set up the current tuple pointer for SQLFetch
  1568.     stmt->currTuple = -1;
  1569. stmt->rowset_start = -1;
  1570. stmt->current_col = -1;
  1571. error = FALSE;
  1572. SEEYA:
  1573. /* These things should be freed on any error ALSO! */
  1574. free(table_name);
  1575.     for(i = 0; i < total_columns; i++) {
  1576. free(column_names[i]);
  1577.     }
  1578.     free(column_names);
  1579. mylog("SQLStatistics(): EXIT, %s, stmt=%un", error ? "error" : "success", stmt);
  1580. if (error) {
  1581. SC_log_error(func, "", stmt);
  1582. return SQL_ERROR;
  1583. }
  1584. else
  1585. return SQL_SUCCESS;
  1586. }
  1587. RETCODE SQL_API SQLColumnPrivileges(
  1588.                                     HSTMT        hstmt,
  1589.                                     UCHAR FAR *  szTableQualifier,
  1590.                                     SWORD        cbTableQualifier,
  1591.                                     UCHAR FAR *  szTableOwner,
  1592.                                     SWORD        cbTableOwner,
  1593.                                     UCHAR FAR *  szTableName,
  1594.                                     SWORD        cbTableName,
  1595.                                     UCHAR FAR *  szColumnName,
  1596.                                     SWORD        cbColumnName)
  1597. {
  1598. static char *func="SQLColumnPrivileges";
  1599. mylog("%s: entering...n", func);
  1600. /* Neither Access or Borland care about this. */
  1601. SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
  1602.     return SQL_ERROR;
  1603. }
  1604. RETCODE SQL_API SQLPrimaryKeys(
  1605.                                HSTMT         hstmt,
  1606.                                UCHAR FAR *   szTableQualifier,
  1607.                                SWORD         cbTableQualifier,
  1608.                                UCHAR FAR *   szTableOwner,
  1609.                                SWORD         cbTableOwner,
  1610.                                UCHAR FAR *   szTableName,
  1611.                                SWORD         cbTableName)
  1612. {
  1613. static char *func = "SQLPrimaryKeys";
  1614. StatementClass *stmt = (StatementClass *) hstmt;
  1615. TupleNode *row;
  1616. RETCODE result;
  1617. int seq = 0;
  1618. HSTMT htbl_stmt;
  1619. StatementClass *tbl_stmt;
  1620. char tables_query[MAX_STATEMENT_LEN];
  1621. char attname[MAX_INFO_STRING];
  1622. SDWORD attname_len;
  1623. char pktab[MAX_TABLE_LEN + 1];
  1624. Int2 result_cols;
  1625. mylog("%s: entering...stmt=%un", func, stmt);
  1626.     if( ! stmt) {
  1627. SC_log_error(func, "", NULL);
  1628.         return SQL_INVALID_HANDLE;
  1629.     }
  1630. stmt->manual_result = TRUE;
  1631. stmt->errormsg_created = TRUE;
  1632.     stmt->result = QR_Constructor();
  1633.     if(!stmt->result) {
  1634.         stmt->errormsg = "Couldn't allocate memory for SQLPrimaryKeys result.";
  1635.         stmt->errornumber = STMT_NO_MEMORY_ERROR;
  1636. SC_log_error(func, "", stmt);
  1637.         return SQL_ERROR;
  1638.     }
  1639.     // the binding structure for a statement is not set up until
  1640.     // a statement is actually executed, so we'll have to do this ourselves.
  1641. result_cols = 6;
  1642.     extend_bindings(stmt, result_cols);
  1643.     // set the field names
  1644.     QR_set_num_fields(stmt->result, result_cols);
  1645.     QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
  1646.     QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
  1647.     QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1648.     QR_set_field_info(stmt->result, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1649.     QR_set_field_info(stmt->result, 4, "KEY_SEQ", PG_TYPE_INT2, 2);
  1650.     QR_set_field_info(stmt->result, 5, "PK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1651.     result = SQLAllocStmt( stmt->hdbc, &htbl_stmt);
  1652.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1653. stmt->errornumber = STMT_NO_MEMORY_ERROR;
  1654. stmt->errormsg = "Couldn't allocate statement for Primary Key result.";
  1655. SC_log_error(func, "", stmt);
  1656.         return SQL_ERROR;
  1657.     }
  1658. tbl_stmt = (StatementClass *) htbl_stmt;
  1659. pktab[0] = '';
  1660. make_string(szTableName, cbTableName, pktab);
  1661. if ( pktab[0] == '') {
  1662. stmt->errormsg = "No Table specified to SQLPrimaryKeys.";
  1663.     stmt->errornumber = STMT_INTERNAL_ERROR;
  1664. SC_log_error(func, "", stmt);
  1665. SQLFreeStmt(htbl_stmt, SQL_DROP);
  1666. return SQL_ERROR;
  1667. }
  1668. sprintf(tables_query, "select distinct on attnum a2.attname, a2.attnum from pg_attribute a1, pg_attribute a2, pg_class c, pg_index i where c.relname = '%s_pkey' AND c.oid = i.indexrelid AND a1.attrelid = c.oid AND a2.attrelid = c.oid AND (i.indkey[0] = a1.attnum OR i.indkey[1] = a1.attnum OR i.indkey[2] = a1.attnum OR i.indkey[3] = a1.attnum OR i.indkey[4] = a1.attnum OR i.indkey[5] = a1.attnum OR i.indkey[6] = a1.attnum OR i.indkey[7] = a1.attnum) order by a2.attnum", pktab);
  1669. mylog("SQLPrimaryKeys: tables_query='%s'n", tables_query);
  1670.     result = SQLExecDirect(htbl_stmt, tables_query, strlen(tables_query));
  1671.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1672. stmt->errormsg = SC_create_errormsg(htbl_stmt);
  1673. stmt->errornumber = tbl_stmt->errornumber;
  1674. SC_log_error(func, "", stmt);
  1675. SQLFreeStmt(htbl_stmt, SQL_DROP);
  1676.         return SQL_ERROR;
  1677.     }
  1678.     result = SQLBindCol(htbl_stmt, 1, SQL_C_CHAR,
  1679.                         attname, MAX_INFO_STRING, &attname_len);
  1680.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1681. stmt->errormsg = tbl_stmt->errormsg;
  1682. stmt->errornumber = tbl_stmt->errornumber;
  1683. SC_log_error(func, "", stmt);
  1684. SQLFreeStmt(htbl_stmt, SQL_DROP);
  1685.         return SQL_ERROR;
  1686.     }
  1687.     result = SQLFetch(htbl_stmt);
  1688.     while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
  1689.         row = (TupleNode *)malloc(sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField));
  1690.         set_tuplefield_null(&row->tuple[0]);
  1691.         // I have to hide the table owner from Access, otherwise it
  1692.         // insists on referring to the table as 'owner.table'.
  1693.         // (this is valid according to the ODBC SQL grammar, but
  1694.         // Postgres won't support it.)
  1695.         set_tuplefield_string(&row->tuple[1], "");
  1696.         set_tuplefield_string(&row->tuple[2], pktab);
  1697.         set_tuplefield_string(&row->tuple[3], attname);
  1698. set_tuplefield_int2(&row->tuple[4], (Int2) (++seq));
  1699. set_tuplefield_null(&row->tuple[5]);
  1700.         QR_add_tuple(stmt->result, row);
  1701. mylog(">> primaryKeys: pktab = '%s', attname = '%s', seq = %dn", pktab, attname, seq);
  1702.         result = SQLFetch(htbl_stmt);
  1703.     }
  1704.     if(result != SQL_NO_DATA_FOUND) {
  1705. stmt->errormsg = SC_create_errormsg(htbl_stmt);
  1706. stmt->errornumber = tbl_stmt->errornumber;
  1707. SC_log_error(func, "", stmt);
  1708. SQLFreeStmt(htbl_stmt, SQL_DROP);
  1709.         return SQL_ERROR;
  1710.     }
  1711. SQLFreeStmt(htbl_stmt, SQL_DROP);
  1712.     // also, things need to think that this statement is finished so
  1713.     // the results can be retrieved.
  1714.     stmt->status = STMT_FINISHED;
  1715.     // set up the current tuple pointer for SQLFetch
  1716.     stmt->currTuple = -1;
  1717. stmt->rowset_start = -1;
  1718. stmt->current_col = -1;
  1719. mylog("SQLPrimaryKeys(): EXIT, stmt=%un", stmt);
  1720.     return SQL_SUCCESS;
  1721. }
  1722. RETCODE SQL_API SQLForeignKeys(
  1723.                                HSTMT         hstmt,
  1724.                                UCHAR FAR *   szPkTableQualifier,
  1725.                                SWORD         cbPkTableQualifier,
  1726.                                UCHAR FAR *   szPkTableOwner,
  1727.                                SWORD         cbPkTableOwner,
  1728.                                UCHAR FAR *   szPkTableName,
  1729.                                SWORD         cbPkTableName,
  1730.                                UCHAR FAR *   szFkTableQualifier,
  1731.                                SWORD         cbFkTableQualifier,
  1732.                                UCHAR FAR *   szFkTableOwner,
  1733.                                SWORD         cbFkTableOwner,
  1734.                                UCHAR FAR *   szFkTableName,
  1735.                                SWORD         cbFkTableName)
  1736. {
  1737. static char *func = "SQLForeignKeys";
  1738. StatementClass *stmt = (StatementClass *) hstmt;
  1739. TupleNode *row;
  1740. HSTMT htbl_stmt, hpkey_stmt;
  1741. StatementClass *tbl_stmt;
  1742. RETCODE result, keyresult;
  1743. char tables_query[MAX_STATEMENT_LEN];
  1744. char args[1024], tgname[MAX_INFO_STRING];
  1745. char pktab[MAX_TABLE_LEN + 1], fktab[MAX_TABLE_LEN + 1];
  1746. char *ptr, *pkey_ptr, *pkptr, *fkptr, *frel, *prel;
  1747. int i, k, pkeys, seq, ntabs;
  1748. SWORD nargs, rule_type, action;
  1749. char pkey[MAX_INFO_STRING];
  1750. Int2 result_cols;
  1751. mylog("%s: entering...stmt=%un", func, stmt);
  1752.     if( ! stmt) {
  1753. SC_log_error(func, "", NULL);
  1754.         return SQL_INVALID_HANDLE;
  1755.     }
  1756. stmt->manual_result = TRUE;
  1757. stmt->errormsg_created = TRUE;
  1758.     stmt->result = QR_Constructor();
  1759.     if(!stmt->result) {
  1760. stmt->errormsg = "Couldn't allocate memory for SQLForeignKeys result.";
  1761.         stmt->errornumber = STMT_NO_MEMORY_ERROR;
  1762. SC_log_error(func, "", stmt);
  1763. SQLFreeStmt(htbl_stmt, SQL_DROP);
  1764.         return SQL_ERROR;
  1765.     }
  1766.     // the binding structure for a statement is not set up until
  1767.     // a statement is actually executed, so we'll have to do this ourselves.
  1768. result_cols = 14;
  1769.     extend_bindings(stmt, result_cols);
  1770.     // set the field names
  1771.     QR_set_num_fields(stmt->result, result_cols);
  1772.     QR_set_field_info(stmt->result, 0, "PKTABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
  1773.     QR_set_field_info(stmt->result, 1, "PKTABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
  1774.     QR_set_field_info(stmt->result, 2, "PKTABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1775.     QR_set_field_info(stmt->result, 3, "PKCOLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1776.     QR_set_field_info(stmt->result, 4, "FKTABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
  1777.     QR_set_field_info(stmt->result, 5, "FKTABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
  1778.     QR_set_field_info(stmt->result, 6, "FKTABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1779.     QR_set_field_info(stmt->result, 7, "FKCOLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1780.     QR_set_field_info(stmt->result, 8, "KEY_SEQ", PG_TYPE_INT2, 2);
  1781.     QR_set_field_info(stmt->result, 9, "UPDATE_RULE", PG_TYPE_INT2, 2);
  1782.     QR_set_field_info(stmt->result, 10, "DELETE_RULE", PG_TYPE_INT2, 2);
  1783.     QR_set_field_info(stmt->result, 11, "FK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1784.     QR_set_field_info(stmt->result, 12, "PK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1785.     QR_set_field_info(stmt->result, 13, "TRIGGER_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  1786.     // also, things need to think that this statement is finished so
  1787.     // the results can be retrieved.
  1788.     stmt->status = STMT_FINISHED;
  1789.     // set up the current tuple pointer for SQLFetch
  1790.     stmt->currTuple = -1;
  1791. stmt->rowset_start = -1;
  1792. stmt->current_col = -1;
  1793.     result = SQLAllocStmt( stmt->hdbc, &htbl_stmt);
  1794.     if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1795. stmt->errornumber = STMT_NO_MEMORY_ERROR;
  1796. stmt->errormsg = "Couldn't allocate statement for SQLForeignKeys result.";
  1797. SC_log_error(func, "", stmt);
  1798.         return SQL_ERROR;
  1799.     }
  1800. tbl_stmt = (StatementClass *) htbl_stmt;
  1801. pktab[0] = '';
  1802. fktab[0] = '';
  1803. make_string(szPkTableName, cbPkTableName, pktab);
  1804. make_string(szFkTableName, cbFkTableName, fktab);
  1805. /* Case #2 -- Get the foreign keys in the specified table (fktab) that 
  1806. refer to the primary keys of other table(s).
  1807. */
  1808. if (fktab[0] != '') {
  1809. sprintf(tables_query, "select pg_trigger.tgargs, pg_trigger.tgnargs, pg_trigger.tgname from pg_proc, pg_trigger, pg_class where pg_proc.oid = pg_trigger.tgfoid and pg_trigger.tgrelid = pg_class.oid AND pg_proc.proname = 'check_primary_key' AND pg_class.relname = '%s'",
  1810. fktab);
  1811. result = SQLExecDirect(htbl_stmt, tables_query, strlen(tables_query));
  1812. if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1813. stmt->errormsg = SC_create_errormsg(htbl_stmt);
  1814. stmt->errornumber = tbl_stmt->errornumber;
  1815. SC_log_error(func, "", stmt);
  1816.      SQLFreeStmt(htbl_stmt, SQL_DROP);
  1817. return SQL_ERROR;
  1818. }
  1819. result = SQLBindCol(htbl_stmt, 1, SQL_C_BINARY,
  1820. args, MAX_INFO_STRING, NULL);
  1821. if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1822. stmt->errormsg = tbl_stmt->errormsg;
  1823. stmt->errornumber = tbl_stmt->errornumber;
  1824. SC_log_error(func, "", stmt);
  1825. SQLFreeStmt(htbl_stmt, SQL_DROP);
  1826. return SQL_ERROR;
  1827. }
  1828. result = SQLBindCol(htbl_stmt, 2, SQL_C_SHORT,
  1829. &nargs, 0, NULL);
  1830. if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1831. stmt->errormsg = tbl_stmt->errormsg;
  1832. stmt->errornumber = tbl_stmt->errornumber;
  1833. SC_log_error(func, "", stmt);
  1834. SQLFreeStmt(htbl_stmt, SQL_DROP);
  1835. return SQL_ERROR;
  1836. }
  1837. result = SQLBindCol(htbl_stmt, 3, SQL_C_CHAR,
  1838. tgname, sizeof(tgname), NULL);
  1839. if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1840. stmt->errormsg = tbl_stmt->errormsg;
  1841. stmt->errornumber = tbl_stmt->errornumber;
  1842. SC_log_error(func, "", stmt);
  1843. SQLFreeStmt(htbl_stmt, SQL_DROP);
  1844. return SQL_ERROR;
  1845. }
  1846. result = SQLFetch(htbl_stmt);
  1847. if (result == SQL_NO_DATA_FOUND)
  1848. return SQL_SUCCESS;
  1849. if(result != SQL_SUCCESS) {
  1850. stmt->errormsg = SC_create_errormsg(htbl_stmt);
  1851. stmt->errornumber = tbl_stmt->errornumber;
  1852. SC_log_error(func, "", stmt);
  1853. SQLFreeStmt(htbl_stmt, SQL_DROP);
  1854. return SQL_ERROR;
  1855. }
  1856. keyresult = SQLAllocStmt( stmt->hdbc, &hpkey_stmt);
  1857. if((keyresult != SQL_SUCCESS) && (keyresult != SQL_SUCCESS_WITH_INFO)) {
  1858. stmt->errornumber = STMT_NO_MEMORY_ERROR;
  1859. stmt->errormsg = "Couldn't allocate statement for SQLForeignKeys (pkeys) result.";
  1860. SC_log_error(func, "", stmt);
  1861. return SQL_ERROR;
  1862. }
  1863. keyresult = SQLBindCol(hpkey_stmt, 4, SQL_C_CHAR,
  1864. pkey, sizeof(pkey), NULL);
  1865. if (keyresult != SQL_SUCCESS) {
  1866. stmt->errornumber = STMT_NO_MEMORY_ERROR;
  1867. stmt->errormsg = "Couldn't bindcol for primary keys for SQLForeignKeys result.";
  1868. SC_log_error(func, "", stmt);
  1869. SQLFreeStmt(hpkey_stmt, SQL_DROP);
  1870. return SQL_ERROR;
  1871. }
  1872. while (result == SQL_SUCCESS) {
  1873. /* Compute the number of keyparts. */
  1874. pkeys = nargs / 2;
  1875. mylog("Foreign Key Case#2: nargs = %d, pkeys = %dn", nargs, pkeys);
  1876. ptr = args;
  1877. /* Get to the PK Table Name */
  1878. for (k = 0; k < pkeys; k++)
  1879. ptr += strlen(ptr) + 1;
  1880. prel = ptr;
  1881. mylog("prel = '%s'n", prel);
  1882. /* If there is a pk table specified, then check it. */
  1883. if (pktab[0] != '') {
  1884. /* If it doesn't match, then continue */
  1885. if ( strcmp(prel, pktab)) {
  1886. result = SQLFetch(htbl_stmt);
  1887. continue;
  1888. }
  1889. }
  1890. keyresult = SQLPrimaryKeys(hpkey_stmt, NULL, 0, NULL, 0, prel, SQL_NTS);
  1891. if (keyresult != SQL_SUCCESS) {
  1892. stmt->errornumber = STMT_NO_MEMORY_ERROR;
  1893. stmt->errormsg = "Couldn't get primary keys for SQLForeignKeys result.";
  1894. SC_log_error(func, "", stmt);
  1895. SQLFreeStmt(hpkey_stmt, SQL_DROP);
  1896. return SQL_ERROR;
  1897. }
  1898. /* Check that the key listed is the primary key */
  1899. keyresult = SQLFetch(hpkey_stmt);
  1900. for (k = 0; k < pkeys; k++) {
  1901. ptr += strlen(ptr) + 1;
  1902. if ( keyresult != SQL_SUCCESS || strcmp(ptr, pkey)) {
  1903. pkeys = 0;
  1904. break;
  1905. }
  1906. keyresult = SQLFetch(hpkey_stmt);
  1907. }
  1908. ptr = prel;
  1909. /* Set to first fk column */
  1910. fkptr = args;
  1911. seq = 0;
  1912. for (k = 0; k < pkeys; k++) {
  1913. row = (TupleNode *)malloc(sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField));
  1914. set_tuplefield_null(&row->tuple[0]);
  1915. set_tuplefield_string(&row->tuple[1], "");
  1916. set_tuplefield_string(&row->tuple[2], prel);
  1917. // Get to the primary key
  1918. ptr += strlen(ptr) + 1;
  1919. mylog("prel = '%s', ptr = '%s'n", prel, ptr);
  1920. set_tuplefield_string(&row->tuple[3], ptr);
  1921. set_tuplefield_null(&row->tuple[4]);
  1922. set_tuplefield_string(&row->tuple[5], "");
  1923. set_tuplefield_string(&row->tuple[6], fktab);
  1924. set_tuplefield_string(&row->tuple[7], fkptr);
  1925. mylog("fktab = '%s', fkptr = '%s'n", fktab, fkptr);
  1926. set_tuplefield_int2(&row->tuple[8], (Int2) (++seq));
  1927. set_tuplefield_null(&row->tuple[9]);
  1928. set_tuplefield_null(&row->tuple[10]);
  1929. set_tuplefield_null(&row->tuple[11]);
  1930. set_tuplefield_null(&row->tuple[12]);
  1931. set_tuplefield_string(&row->tuple[13], tgname);
  1932. QR_add_tuple(stmt->result, row);
  1933. // next foreign key
  1934. fkptr += strlen(fkptr) + 1;
  1935. }
  1936. result = SQLFetch(htbl_stmt);
  1937. }
  1938. }
  1939. /* Case #1 -- Get the foreign keys in other tables that refer to the primary key
  1940. in the specified table (pktab).  i.e., Who points to me?
  1941. */
  1942.     else if (pktab[0] != '') {
  1943. sprintf(tables_query, "select pg_trigger.tgargs, pg_trigger.tgnargs, pg_trigger.tgtype, pg_trigger.tgname from pg_proc, pg_trigger, pg_class where pg_proc.oid = pg_trigger.tgfoid and pg_trigger.tgrelid = pg_class.oid AND pg_proc.proname = 'check_foreign_key' AND pg_class.relname = '%s'",
  1944. pktab);
  1945. result = SQLExecDirect(htbl_stmt, tables_query, strlen(tables_query));
  1946. if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1947. stmt->errormsg = SC_create_errormsg(htbl_stmt);
  1948. stmt->errornumber = tbl_stmt->errornumber;
  1949. SC_log_error(func, "", stmt);
  1950.      SQLFreeStmt(htbl_stmt, SQL_DROP);
  1951. return SQL_ERROR;
  1952. }
  1953. result = SQLBindCol(htbl_stmt, 1, SQL_C_BINARY,
  1954. args, sizeof(args), NULL);
  1955. if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1956. stmt->errormsg = tbl_stmt->errormsg;
  1957. stmt->errornumber = tbl_stmt->errornumber;
  1958. SC_log_error(func, "", stmt);
  1959. SQLFreeStmt(htbl_stmt, SQL_DROP);
  1960. return SQL_ERROR;
  1961. }
  1962. result = SQLBindCol(htbl_stmt, 2, SQL_C_SHORT,
  1963. &nargs, 0, NULL);
  1964. if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1965. stmt->errormsg = tbl_stmt->errormsg;
  1966. stmt->errornumber = tbl_stmt->errornumber;
  1967. SC_log_error(func, "", stmt);
  1968. SQLFreeStmt(htbl_stmt, SQL_DROP);
  1969. return SQL_ERROR;
  1970. }
  1971. result = SQLBindCol(htbl_stmt, 3, SQL_C_SHORT,
  1972. &rule_type, 0, NULL);
  1973. if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1974. stmt->errormsg = tbl_stmt->errormsg;
  1975. stmt->errornumber = tbl_stmt->errornumber;
  1976. SC_log_error(func, "", stmt);
  1977. SQLFreeStmt(htbl_stmt, SQL_DROP);
  1978. return SQL_ERROR;
  1979. }
  1980. result = SQLBindCol(htbl_stmt, 4, SQL_C_CHAR,
  1981. tgname, sizeof(tgname), NULL);
  1982. if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  1983. stmt->errormsg = tbl_stmt->errormsg;
  1984. stmt->errornumber = tbl_stmt->errornumber;
  1985. SC_log_error(func, "", stmt);
  1986. SQLFreeStmt(htbl_stmt, SQL_DROP);
  1987. return SQL_ERROR;
  1988. }
  1989. result = SQLFetch(htbl_stmt);
  1990. if (result == SQL_NO_DATA_FOUND)
  1991. return SQL_SUCCESS;
  1992. if(result != SQL_SUCCESS) {
  1993. stmt->errormsg = SC_create_errormsg(htbl_stmt);
  1994. stmt->errornumber = tbl_stmt->errornumber;
  1995. SC_log_error(func, "", stmt);
  1996. SQLFreeStmt(htbl_stmt, SQL_DROP);
  1997. return SQL_ERROR;
  1998. }
  1999. keyresult = SQLAllocStmt( stmt->hdbc, &hpkey_stmt);
  2000. if((keyresult != SQL_SUCCESS) && (keyresult != SQL_SUCCESS_WITH_INFO)) {
  2001. stmt->errornumber = STMT_NO_MEMORY_ERROR;
  2002. stmt->errormsg = "Couldn't allocate statement for SQLForeignKeys (pkeys) result.";
  2003. SC_log_error(func, "", stmt);
  2004. return SQL_ERROR;
  2005. }
  2006. keyresult = SQLPrimaryKeys(hpkey_stmt, NULL, 0, NULL, 0, pktab, SQL_NTS);
  2007. if (keyresult != SQL_SUCCESS) {
  2008. stmt->errornumber = STMT_NO_MEMORY_ERROR;
  2009. stmt->errormsg = "Couldn't get primary keys for SQLForeignKeys result.";
  2010. SC_log_error(func, "", stmt);
  2011. SQLFreeStmt(hpkey_stmt, SQL_DROP);
  2012. return SQL_ERROR;
  2013. }
  2014. keyresult = SQLBindCol(hpkey_stmt, 4, SQL_C_CHAR,
  2015. pkey, sizeof(pkey), NULL);
  2016. if (keyresult != SQL_SUCCESS) {
  2017. stmt->errornumber = STMT_NO_MEMORY_ERROR;
  2018. stmt->errormsg = "Couldn't bindcol for primary keys for SQLForeignKeys result.";
  2019. SC_log_error(func, "", stmt);
  2020. SQLFreeStmt(hpkey_stmt, SQL_DROP);
  2021. return SQL_ERROR;
  2022. }
  2023. while (result == SQL_SUCCESS) {
  2024. // Get the number of tables
  2025. ptr = args;
  2026. ntabs = atoi(args);
  2027. ptr += strlen(ptr) + 1;
  2028. // Handle action (i.e., 'cascade', 'restrict', 'setnull')
  2029. switch(tolower(ptr[0])) {
  2030. case 'c':
  2031. action = SQL_CASCADE;
  2032. break;
  2033. case 'r':
  2034. action = SQL_RESTRICT;
  2035. break;
  2036. case 's':
  2037. action = SQL_SET_NULL;
  2038. break;
  2039. default:
  2040. action = -1;
  2041. break;
  2042. }
  2043. rule_type >>= TRIGGER_SHIFT;
  2044. ptr += strlen(ptr) + 1;
  2045. // Calculate the number of key parts
  2046. pkeys = (nargs - ( 2 + ntabs)) / (ntabs + 1);
  2047. pkey_ptr = ptr;
  2048. keyresult = SQLExtendedFetch(hpkey_stmt, SQL_FETCH_FIRST, -1, NULL, NULL);
  2049. if ( keyresult != SQL_SUCCESS || strcmp(pkey, ptr)) {
  2050. ntabs = 0;
  2051. }
  2052. // Get to the last primary keypart
  2053. for (i = 1; i < pkeys; i++) {
  2054. // If keypart doesnt match, skip this entry
  2055. if ( keyresult != SQL_SUCCESS || strcmp(pkey, ptr)) {
  2056. ntabs = 0;
  2057. break;
  2058. }
  2059. ptr += strlen(ptr) + 1;
  2060. keyresult = SQLExtendedFetch(hpkey_stmt, SQL_FETCH_NEXT, -1, NULL, NULL);
  2061. }
  2062. mylog("Foreign Key Case#1: nargs = %d, ntabs = %d, pkeys = %dn", nargs, ntabs, pkeys);
  2063. // Get Foreign Key Tables
  2064. for (i = 0; i < ntabs; i++) {
  2065. seq = 0;
  2066. pkptr = pkey_ptr;
  2067. ptr += strlen(ptr) + 1;
  2068. frel = ptr;
  2069. for (k = 0; k < pkeys; k++) {
  2070. row = (TupleNode *)malloc(sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField));
  2071. set_tuplefield_null(&row->tuple[0]);
  2072. set_tuplefield_string(&row->tuple[1], "");
  2073. set_tuplefield_string(&row->tuple[2], pktab);
  2074. set_tuplefield_string(&row->tuple[3], pkptr);
  2075. mylog("pktab = '%s', pkptr = '%s'n", pktab, pkptr);
  2076. set_tuplefield_null(&row->tuple[4]);
  2077. set_tuplefield_string(&row->tuple[5], "");
  2078. set_tuplefield_string(&row->tuple[6], frel);
  2079. // Get to the foreign key
  2080. ptr += strlen(ptr) + 1;
  2081. set_tuplefield_string(&row->tuple[7], ptr);
  2082. mylog("frel = '%s', ptr = '%s'n", frel, ptr);
  2083. mylog("rule_type = %d, action = %dn", rule_type, action);
  2084. set_tuplefield_int2(&row->tuple[8], (Int2) (++seq));
  2085. set_nullfield_int2(&row->tuple[9], (Int2) ((rule_type & TRIGGER_UPDATE) ? action : -1));
  2086. set_nullfield_int2(&row->tuple[10], (Int2) ((rule_type & TRIGGER_DELETE) ? action : -1));
  2087. set_tuplefield_null(&row->tuple[11]);
  2088. set_tuplefield_null(&row->tuple[12]);
  2089. set_tuplefield_string(&row->tuple[13], tgname);
  2090. QR_add_tuple(stmt->result, row);
  2091. // next primary key
  2092. pkptr += strlen(pkptr) + 1;
  2093. }
  2094. }
  2095. result = SQLFetch(htbl_stmt);
  2096. }
  2097.     }
  2098. else {
  2099. stmt->errormsg = "No tables specified to SQLForeignKeys.";
  2100. stmt->errornumber = STMT_INTERNAL_ERROR;
  2101. SC_log_error(func, "", stmt);
  2102. SQLFreeStmt(htbl_stmt, SQL_DROP);
  2103. return SQL_ERROR;
  2104. }
  2105. SQLFreeStmt(htbl_stmt, SQL_DROP);
  2106. SQLFreeStmt(hpkey_stmt, SQL_DROP);
  2107. mylog("SQLForeignKeys(): EXIT, stmt=%un", stmt);
  2108.     return SQL_SUCCESS;
  2109. }
  2110. RETCODE SQL_API SQLProcedureColumns(
  2111.                                     HSTMT         hstmt,
  2112.                                     UCHAR FAR *   szProcQualifier,
  2113.                                     SWORD         cbProcQualifier,
  2114.                                     UCHAR FAR *   szProcOwner,
  2115.                                     SWORD         cbProcOwner,
  2116.                                     UCHAR FAR *   szProcName,
  2117.                                     SWORD         cbProcName,
  2118.                                     UCHAR FAR *   szColumnName,
  2119.                                     SWORD         cbColumnName)
  2120. {
  2121. static char *func="SQLProcedureColumns";
  2122. mylog("%s: entering...n", func);
  2123. SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
  2124.     return SQL_ERROR;
  2125. }
  2126. RETCODE SQL_API SQLProcedures(
  2127.                               HSTMT          hstmt,
  2128.                               UCHAR FAR *    szProcQualifier,
  2129.                               SWORD          cbProcQualifier,
  2130.                               UCHAR FAR *    szProcOwner,
  2131.                               SWORD          cbProcOwner,
  2132.                               UCHAR FAR *    szProcName,
  2133.                               SWORD          cbProcName)
  2134. {
  2135. static char *func="SQLProcedures";
  2136. mylog("%s: entering...n", func);
  2137. SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
  2138.     return SQL_ERROR;
  2139. }
  2140. RETCODE SQL_API SQLTablePrivileges(
  2141.                                    HSTMT           hstmt,
  2142.                                    UCHAR FAR *     szTableQualifier,
  2143.                                    SWORD           cbTableQualifier,
  2144.                                    UCHAR FAR *     szTableOwner,
  2145.                                    SWORD           cbTableOwner,
  2146.                                    UCHAR FAR *     szTableName,
  2147.                                    SWORD           cbTableName)
  2148. {
  2149. static char *func="SQLTablePrivileges";
  2150. mylog("%s: entering...n", func);
  2151. SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
  2152.     return SQL_ERROR;
  2153. }