2 * Description: This module contains routines related to
3 * ODBC informational functions.
14 #include "dlg_specific.h"
17 #include "connection.h"
18 #include "statement.h"
23 #include "pgapifunc.h"
24 #include "multibyte.h"
26 #include "vxhelpers.h"
29 /* Trigger related stuff for SQLForeign Keys */
30 #define TRIGGER_SHIFT 3
31 #define TRIGGER_MASK 0x03
32 #define TRIGGER_DELETE 0x01
33 #define TRIGGER_UPDATE 0x02
35 #define NULL_IF_NULL(a) ((a) ? ((const char *) a) : "(NULL)")
37 /* extern GLOBAL_VALUES globals; */
39 CSTR pubstr
= "public";
44 PGAPI_GetInfo(HDBC hdbc
,
45 SQLUSMALLINT fInfoType
,
47 SQLSMALLINT cbInfoValueMax
,
48 SQLSMALLINT FAR
* pcbInfoValue
)
50 CSTR func
= "PGAPI_GetInfo";
51 ConnectionClass
*conn
= (ConnectionClass
*) hdbc
;
54 char tmp
[MAX_INFO_STRING
];
55 SQLULEN len
= 0, value
= 0;
60 mylog("%s: entering...fInfoType=%d\n", func
, fInfoType
);
64 CC_log_error(func
, NULL_STRING
, NULL
);
65 return SQL_INVALID_HANDLE
;
68 ci
= &(conn
->connInfo
);
72 case SQL_ACCESSIBLE_PROCEDURES
: /* ODBC 1.0 */
76 case SQL_ACCESSIBLE_TABLES
: /* ODBC 1.0 */
80 case SQL_ACTIVE_CONNECTIONS
: /* ODBC 1.0 */
82 value
= MAX_CONNECTIONS
;
85 case SQL_ACTIVE_STATEMENTS
: /* ODBC 1.0 */
90 case SQL_ALTER_TABLE
: /* ODBC 2.0 */
92 value
= SQL_AT_ADD_COLUMN
;
93 if (PG_VERSION_GE(conn
, 7.3))
94 value
|= SQL_AT_DROP_COLUMN
;
95 value
|= SQL_AT_ADD_COLUMN_SINGLE
;
96 if (PG_VERSION_GE(conn
, 7.1))
97 value
|= SQL_AT_ADD_CONSTRAINT
98 | SQL_AT_ADD_TABLE_CONSTRAINT
99 | SQL_AT_CONSTRAINT_INITIALLY_DEFERRED
100 | SQL_AT_CONSTRAINT_INITIALLY_IMMEDIATE
101 | SQL_AT_CONSTRAINT_DEFERRABLE
;
102 if (PG_VERSION_GE(conn
, 7.3))
103 value
|= SQL_AT_DROP_TABLE_CONSTRAINT_RESTRICT
104 | SQL_AT_DROP_TABLE_CONSTRAINT_CASCADE
105 | SQL_AT_DROP_COLUMN_RESTRICT
106 | SQL_AT_DROP_COLUMN_CASCADE
;
109 case SQL_BOOKMARK_PERSISTENCE
: /* ODBC 2.0 */
110 /* very simple bookmark support */
115 case SQL_COLUMN_ALIAS
: /* ODBC 2.0 */
119 case SQL_CONCAT_NULL_BEHAVIOR
: /* ODBC 1.0 */
121 value
= SQL_CB_NON_NULL
;
124 case SQL_CONVERT_INTEGER
:
125 case SQL_CONVERT_SMALLINT
:
126 case SQL_CONVERT_TINYINT
:
127 case SQL_CONVERT_BIT
:
128 case SQL_CONVERT_VARCHAR
: /* ODBC 1.0 */
129 len
= sizeof(SQLUINTEGER
);
130 value
= SQL_CVT_BIT
| SQL_CVT_INTEGER
;
131 mylog("SQL_CONVERT_ mask=" FORMAT_ULEN
"\n", value
);
133 case SQL_CONVERT_BIGINT
:
134 case SQL_CONVERT_DECIMAL
:
135 case SQL_CONVERT_DOUBLE
:
136 case SQL_CONVERT_FLOAT
:
137 case SQL_CONVERT_NUMERIC
:
138 case SQL_CONVERT_REAL
:
139 case SQL_CONVERT_DATE
:
140 case SQL_CONVERT_TIME
:
141 case SQL_CONVERT_TIMESTAMP
:
142 case SQL_CONVERT_BINARY
:
143 case SQL_CONVERT_LONGVARBINARY
:
144 case SQL_CONVERT_VARBINARY
: /* ODBC 1.0 */
145 case SQL_CONVERT_CHAR
:
146 case SQL_CONVERT_LONGVARCHAR
:
147 case SQL_CONVERT_WCHAR
:
148 case SQL_CONVERT_WLONGVARCHAR
:
149 case SQL_CONVERT_WVARCHAR
:
150 len
= sizeof(SQLUINTEGER
);
151 value
= 0; /* CONVERT is unavailable */
154 case SQL_CONVERT_FUNCTIONS
: /* ODBC 1.0 */
155 len
= sizeof(SQLUINTEGER
);
156 value
= SQL_FN_CVT_CONVERT
;
157 mylog("CONVERT_FUNCTIONS=" FORMAT_ULEN
"\n", value
);
160 case SQL_CORRELATION_NAME
: /* ODBC 1.0 */
163 * Saying no correlation name makes Query not work right.
164 * value = SQL_CN_NONE;
170 case SQL_CURSOR_COMMIT_BEHAVIOR
: /* ODBC 1.0 */
172 value
= SQL_CB_PRESERVE
;
175 case SQL_CURSOR_ROLLBACK_BEHAVIOR
: /* ODBC 1.0 */
177 value
= SQL_CB_PRESERVE
;
180 case SQL_DATA_SOURCE_NAME
: /* ODBC 1.0 */
181 p
= CC_get_DSN(conn
);
184 case SQL_DATA_SOURCE_READ_ONLY
: /* ODBC 1.0 */
185 p
= CC_is_onlyread(conn
) ? "Y" : "N";
188 case SQL_DATABASE_NAME
: /* Support for old ODBC 1.0 Apps */
191 * Returning the database name causes problems in MS Query. It
192 * generates query like: "SELECT DISTINCT a FROM byronnbad3
195 * p = CC_get_database(conn);
197 p
= CurrCatString(conn
);
200 case SQL_DBMS_NAME
: /* ODBC 1.0 */
201 if (CC_fake_mss(conn
))
202 p
= "Microsoft SQL Server";
207 case SQL_DBMS_VER
: /* ODBC 1.0 */
210 * The ODBC spec wants ##.##.#### ...whatever... so prepend
213 /* version number to the dbms version string */
215 snprintf(tmp, sizeof(tmp) - 1, "%s %s", POSTGRESDRIVERVERSION, conn->pg_version);
216 tmp[sizeof(tmp) - 1] = '\0'; */
217 if (CC_fake_mss(conn
))
221 strncpy_null(tmp
, conn
->pg_version
, sizeof(tmp
));
226 case SQL_DEFAULT_TXN_ISOLATION
: /* ODBC 1.0 */
228 if (PG_VERSION_LT(conn
, 6.5))
229 value
= SQL_TXN_SERIALIZABLE
;
231 value
= SQL_TXN_READ_COMMITTED
;
234 case SQL_DRIVER_NAME
: /* ODBC 1.0 */
235 p
= DRIVER_FILE_NAME
;
238 case SQL_DRIVER_ODBC_VER
:
239 i_odbcver
= conn
->driver_version
;
240 snprintf(odbcver
, sizeof(odbcver
), "%02x.%02x", i_odbcver
/ 256,
242 /* p = DRIVER_ODBC_VER; */
246 case SQL_DRIVER_VER
: /* ODBC 1.0 */
247 p
= VXODBCDRIVERVERSION
;
250 case SQL_EXPRESSIONS_IN_ORDERBY
: /* ODBC 1.0 */
254 case SQL_FETCH_DIRECTION
: /* ODBC 1.0 */
256 value
= (SQL_FD_FETCH_NEXT
|
261 SQL_FD_FETCH_ABSOLUTE
|
262 SQL_FD_FETCH_RELATIVE
| SQL_FD_FETCH_BOOKMARK
);
265 case SQL_FILE_USAGE
: /* ODBC 2.0 */
267 value
= SQL_FILE_NOT_SUPPORTED
;
270 case SQL_GETDATA_EXTENSIONS
: /* ODBC 2.0 */
273 (SQL_GD_ANY_COLUMN
| SQL_GD_ANY_ORDER
| SQL_GD_BOUND
|
277 case SQL_GROUP_BY
: /* ODBC 2.0 */
279 value
= SQL_GB_GROUP_BY_EQUALS_SELECT
;
282 case SQL_IDENTIFIER_CASE
: /* ODBC 1.0 */
285 * are identifiers case-sensitive (yes, but only when quoted.
286 * If not quoted, they default to lowercase)
289 value
= SQL_IC_LOWER
;
292 case SQL_IDENTIFIER_QUOTE_CHAR
: /* ODBC 1.0 */
293 /* the character used to quote "identifiers" */
294 p
= PG_VERSION_LE(conn
, 6.2) ? " " : "\"";
297 case SQL_KEYWORDS
: /* ODBC 2.0 */
301 case SQL_LIKE_ESCAPE_CLAUSE
: /* ODBC 2.0 */
304 * is there a character that escapes '%' and '_' in a LIKE
305 * clause? not as far as I can tell
310 case SQL_LOCK_TYPES
: /* ODBC 2.0 */
312 value
= SQL_LCK_NO_CHANGE
;
315 case SQL_MAX_BINARY_LITERAL_LEN
: /* ODBC 2.0 */
320 case SQL_MAX_CHAR_LITERAL_LEN
: /* ODBC 2.0 */
325 case SQL_MAX_COLUMN_NAME_LEN
: /* ODBC 1.0 */
326 // TODO: Look into MAX_COLUMN_LEN - is it sensible?
327 CC_set_error(conn
, CONN_NOT_IMPLEMENTED_ERROR
,
328 "SQL_MAX_COLUMN_NAME_LEN not yet implemented.", NULL
);
332 case SQL_MAX_COLUMNS_IN_GROUP_BY
: /* ODBC 2.0 */
337 case SQL_MAX_COLUMNS_IN_INDEX
: /* ODBC 2.0 */
342 case SQL_MAX_COLUMNS_IN_ORDER_BY
: /* ODBC 2.0 */
347 case SQL_MAX_COLUMNS_IN_SELECT
: /* ODBC 2.0 */
352 case SQL_MAX_COLUMNS_IN_TABLE
: /* ODBC 2.0 */
357 case SQL_MAX_CURSOR_NAME_LEN
: /* ODBC 1.0 */
359 value
= MAX_CURSOR_LEN
;
362 case SQL_MAX_INDEX_SIZE
: /* ODBC 2.0 */
367 case SQL_MAX_OWNER_NAME_LEN
: /* ODBC 1.0 */
368 // TODO: Look into MAX_SCHEMA_LEN - is it sensible?
369 CC_set_error(conn
, CONN_NOT_IMPLEMENTED_ERROR
,
370 "SQL_MAX_OWNER_NAME_LEN not yet implemented.", NULL
);
373 case SQL_MAX_PROCEDURE_NAME_LEN
: /* ODBC 1.0 */
378 case SQL_MAX_QUALIFIER_NAME_LEN
: /* ODBC 1.0 */
383 case SQL_MAX_ROW_SIZE
: /* ODBC 2.0 */
385 if (PG_VERSION_GE(conn
, 7.1))
387 /* Large Rowa in 7.1+ */
388 value
= MAX_ROW_SIZE
;
392 /* Without the Toaster we're limited to the blocksize */
397 case SQL_MAX_ROW_SIZE_INCLUDES_LONG
: /* ODBC 2.0 */
400 * does the preceding value include LONGVARCHAR and
401 * LONGVARBINARY fields? Well, it does include longvarchar,
402 * but not longvarbinary.
407 case SQL_MAX_STATEMENT_LEN
: /* ODBC 2.0 */
408 /* maybe this should be 0? */
410 value
= CC_get_max_query_len(conn
);
413 case SQL_MAX_TABLE_NAME_LEN
: /* ODBC 1.0 */
414 // TODO: Look into MAX_TABLE_LEN - is it sensible?
415 CC_set_error(conn
, CONN_NOT_IMPLEMENTED_ERROR
,
416 "SQL_MAX_TABLE_NAME_LEN not yet implemented.", NULL
);
419 case SQL_MAX_TABLES_IN_SELECT
: /* ODBC 2.0 */
424 case SQL_MAX_USER_NAME_LEN
:
429 case SQL_MULT_RESULT_SETS
: /* ODBC 1.0 */
430 /* Don't support multiple result sets but say yes anyway? */
434 case SQL_MULTIPLE_ACTIVE_TXN
: /* ODBC 1.0 */
438 case SQL_NEED_LONG_DATA_LEN
: /* ODBC 2.0 */
441 * Don't need the length, SQLPutData can handle any size and
447 case SQL_NON_NULLABLE_COLUMNS
: /* ODBC 1.0 */
449 value
= SQL_NNC_NON_NULL
;
452 case SQL_NULL_COLLATION
: /* ODBC 2.0 */
453 /* where are nulls sorted? */
455 if (PG_VERSION_GE(conn
, 7.2))
461 case SQL_NUMERIC_FUNCTIONS
: /* ODBC 1.0 */
466 case SQL_ODBC_API_CONFORMANCE
: /* ODBC 1.0 */
468 value
= SQL_OAC_LEVEL1
;
471 case SQL_ODBC_SAG_CLI_CONFORMANCE
: /* ODBC 1.0 */
473 value
= SQL_OSCC_NOT_COMPLIANT
;
476 case SQL_ODBC_SQL_CONFORMANCE
: /* ODBC 1.0 */
478 value
= SQL_OSC_CORE
;
481 case SQL_ODBC_SQL_OPT_IEF
: /* ODBC 1.0 */
485 case SQL_OJ_CAPABILITIES
: /* ODBC 2.01 */
487 if (PG_VERSION_GE(conn
, 7.1))
490 value
= (SQL_OJ_LEFT
|
495 SQL_OJ_INNER
| SQL_OJ_ALL_COMPARISON_OPS
);
498 /* OJs not in <7.1 */
502 case SQL_ORDER_BY_COLUMNS_IN_SELECT
: /* ODBC 2.0 */
503 p
= (PG_VERSION_LE(conn
, 6.3)) ? "Y" : "N";
506 case SQL_OUTER_JOINS
: /* ODBC 1.0 */
507 if (PG_VERSION_GE(conn
, 7.1))
511 /* OJs not in <7.1 */
515 case SQL_OWNER_TERM
: /* ODBC 1.0 */
516 if (conn
->schema_support
)
522 case SQL_OWNER_USAGE
: /* ODBC 2.0 */
525 if (conn
->schema_support
)
526 value
= SQL_OU_DML_STATEMENTS
527 | SQL_OU_TABLE_DEFINITION
528 | SQL_OU_INDEX_DEFINITION
| SQL_OU_PRIVILEGE_DEFINITION
;
531 case SQL_POS_OPERATIONS
: /* ODBC 2.0 */
533 value
= (SQL_POS_POSITION
| SQL_POS_REFRESH
);
534 if (0 != ci
->updatable_cursors
)
535 value
|= (SQL_POS_UPDATE
| SQL_POS_DELETE
| SQL_POS_ADD
);
538 case SQL_POSITIONED_STATEMENTS
: /* ODBC 2.0 */
543 case SQL_PROCEDURE_TERM
: /* ODBC 1.0 */
547 case SQL_PROCEDURES
: /* ODBC 1.0 */
551 case SQL_QUALIFIER_LOCATION
: /* ODBC 2.0 */
554 value
= SQL_QL_START
;
559 case SQL_QUALIFIER_NAME_SEPARATOR
: /* ODBC 1.0 */
566 case SQL_QUALIFIER_TERM
: /* ODBC 1.0 */
573 case SQL_QUALIFIER_USAGE
: /* ODBC 2.0 */
576 value
= SQL_CU_DML_STATEMENTS
;
581 case SQL_QUOTED_IDENTIFIER_CASE
: /* ODBC 2.0 */
582 /* are "quoted" identifiers case-sensitive? YES! */
584 value
= SQL_IC_SENSITIVE
;
587 case SQL_ROW_UPDATES
: /* ODBC 1.0 */
590 * Driver doesn't support keyset-driven or mixed cursors, so
591 * not much point in saying row updates are supported
593 p
= (0 != ci
->updatable_cursors
) ? "Y" : "N";
596 case SQL_SCROLL_CONCURRENCY
: /* ODBC 1.0 */
598 value
= SQL_SCCO_READ_ONLY
;
599 if (0 != ci
->updatable_cursors
)
600 value
|= SQL_SCCO_OPT_ROWVER
;
603 case SQL_SCROLL_OPTIONS
: /* ODBC 1.0 */
605 value
= SQL_SO_FORWARD_ONLY
| SQL_SO_STATIC
;
606 if (0 != (ci
->updatable_cursors
& ALLOW_KEYSET_DRIVEN_CURSORS
))
607 value
|= SQL_SO_KEYSET_DRIVEN
;
610 case SQL_SEARCH_PATTERN_ESCAPE
: /* ODBC 1.0 */
611 if (PG_VERSION_GE(conn
, 6.5))
617 case SQL_SERVER_NAME
: /* ODBC 1.0 */
618 p
= CC_get_server(conn
);
621 case SQL_SPECIAL_CHARACTERS
: /* ODBC 2.0 */
625 case SQL_STATIC_SENSITIVITY
: /* ODBC 2.0 */
628 if (0 != ci
->updatable_cursors
)
630 (SQL_SS_ADDITIONS
| SQL_SS_DELETIONS
| SQL_SS_UPDATES
);
633 case SQL_STRING_FUNCTIONS
: /* ODBC 1.0 */
635 value
= (SQL_FN_STR_CONCAT
|
641 SQL_FN_STR_SUBSTRING
| SQL_FN_STR_UCASE
);
644 case SQL_SUBQUERIES
: /* ODBC 2.0 */
645 /* postgres 6.3 supports subqueries */
647 value
= (SQL_SQ_QUANTIFIED
|
648 SQL_SQ_IN
| SQL_SQ_EXISTS
| SQL_SQ_COMPARISON
);
651 case SQL_SYSTEM_FUNCTIONS
: /* ODBC 1.0 */
656 case SQL_TABLE_TERM
: /* ODBC 1.0 */
660 case SQL_TIMEDATE_ADD_INTERVALS
: /* ODBC 2.0 */
665 case SQL_TIMEDATE_DIFF_INTERVALS
: /* ODBC 2.0 */
670 case SQL_TIMEDATE_FUNCTIONS
: /* ODBC 1.0 */
672 value
= (SQL_FN_TD_NOW
);
675 case SQL_TXN_CAPABLE
: /* ODBC 1.0 */
678 * Postgres can deal with create or drop table statements in a
685 case SQL_TXN_ISOLATION_OPTION
: /* ODBC 1.0 */
687 if (PG_VERSION_LT(conn
, 6.5))
688 value
= SQL_TXN_SERIALIZABLE
;
689 else if (PG_VERSION_GE(conn
, 7.1))
690 value
= SQL_TXN_READ_COMMITTED
| SQL_TXN_SERIALIZABLE
;
692 value
= SQL_TXN_READ_COMMITTED
;
695 case SQL_UNION
: /* ODBC 2.0 */
696 /* unions with all supported in postgres 6.3 */
698 value
= (SQL_U_UNION
| SQL_U_UNION_ALL
);
701 case SQL_USER_NAME
: /* ODBC 1.0 */
702 p
= CC_get_username(conn
);
706 /* unrecognized key */
707 CC_set_error(conn
, CONN_NOT_IMPLEMENTED_ERROR
,
708 "Unrecognized key passed to PGAPI_GetInfo.", NULL
);
712 result
= SQL_SUCCESS
;
714 mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func
,
715 p
? p
: "<NULL>", len
, value
, cbInfoValueMax
);
718 * NOTE, that if rgbInfoValue is NULL, then no warnings or errors
719 * should result and just pcbInfoValue is returned, which indicates
720 * what length would be required if a real buffer had been passed in.
724 /* char/binary data */
729 if (CC_is_in_unicode_driver(conn
))
732 utf8_to_ucs2(p
, len
, (SQLWCHAR
*) rgbInfoValue
,
733 cbInfoValueMax
/ WCLEN
);
737 strncpy_null((char *) rgbInfoValue
, p
,
738 (size_t) cbInfoValueMax
);
740 if (len
>= cbInfoValueMax
)
742 result
= SQL_SUCCESS_WITH_INFO
;
743 CC_set_error(conn
, CONN_TRUNCATED
,
744 "The buffer was too small for the InfoValue.",
748 #ifdef UNICODE_SUPPORT
749 else if (CC_is_in_unicode_driver(conn
))
751 #endif /* UNICODE_SUPPORT */
758 if (len
== sizeof(SQLSMALLINT
))
759 *((SQLUSMALLINT
*) rgbInfoValue
) = (SQLUSMALLINT
) value
;
760 else if (len
== sizeof(SQLINTEGER
))
761 *((SQLUINTEGER
*) rgbInfoValue
) = (SQLUINTEGER
) value
;
766 *pcbInfoValue
= (SQLSMALLINT
) len
;
771 RETCODE SQL_API
PGAPI_GetTypeInfo(HSTMT hstmt
, SQLSMALLINT fSqlType
)
773 CSTR func
= "PGAPI_GetTypeInfo";
774 StatementClass
*stmt
= (StatementClass
*) hstmt
;
775 ConnectionClass
*conn
;
783 RETCODE result
= SQL_SUCCESS
;
785 mylog("%s: entering...fSqlType = %d\n", func
, fSqlType
);
787 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
790 conn
= SC_get_conn(stmt
);
791 if (res
= QR_Constructor(), !res
)
793 SC_set_error(stmt
, STMT_INTERNAL_ERROR
,
794 "Error creating result.", func
);
797 SC_set_Result(stmt
, res
);
799 #define return DONT_CALL_RETURN_FROM_HERE???
801 extend_column_bindings(SC_get_ARDF(stmt
), result_cols
);
803 stmt
->catalog_result
= TRUE
;
804 QR_set_num_fields(res
, result_cols
);
805 QR_set_field_info_v(res
, 0, "TYPE_NAME", PG_TYPE_VARCHAR
,
807 QR_set_field_info_v(res
, 1, "DATA_TYPE", PG_TYPE_INT2
, 2);
808 QR_set_field_info_v(res
, 2, "PRECISION", PG_TYPE_INT4
, 4);
809 QR_set_field_info_v(res
, 3, "LITERAL_PREFIX", PG_TYPE_VARCHAR
,
811 QR_set_field_info_v(res
, 4, "LITERAL_SUFFIX", PG_TYPE_VARCHAR
,
813 QR_set_field_info_v(res
, 5, "CREATE_PARAMS", PG_TYPE_VARCHAR
,
815 QR_set_field_info_v(res
, 6, "NULLABLE", PG_TYPE_INT2
, 2);
816 QR_set_field_info_v(res
, 7, "CASE_SENSITIVE", PG_TYPE_INT2
, 2);
817 QR_set_field_info_v(res
, 8, "SEARCHABLE", PG_TYPE_INT2
, 2);
818 QR_set_field_info_v(res
, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2
, 2);
819 QR_set_field_info_v(res
, 10, "MONEY", PG_TYPE_INT2
, 2);
820 QR_set_field_info_v(res
, 11, "AUTO_INCREMENT", PG_TYPE_INT2
, 2);
821 QR_set_field_info_v(res
, 12, "LOCAL_TYPE_NAME", PG_TYPE_VARCHAR
,
823 QR_set_field_info_v(res
, 13, "MINIMUM_SCALE", PG_TYPE_INT2
, 2);
824 QR_set_field_info_v(res
, 14, "MAXIMUM_SCALE", PG_TYPE_INT2
, 2);
825 QR_set_field_info_v(res
, 15, "SQL_DATA_TYPE", PG_TYPE_INT2
, 2);
826 QR_set_field_info_v(res
, 16, "SQL_DATETIME_SUB", PG_TYPE_INT2
, 2);
827 QR_set_field_info_v(res
, 17, "NUM_PREC_RADIX", PG_TYPE_INT4
, 4);
828 QR_set_field_info_v(res
, 18, "INTERVAL_PRECISION", PG_TYPE_INT2
, 2);
830 for (i
= 0, sqlType
= sqlTypes
[0]; sqlType
; sqlType
= sqlTypes
[++i
])
832 pgType
= sqltype_to_pgtype(stmt
, sqlType
);
834 if (sqlType
== SQL_LONGVARBINARY
)
836 ConnInfo
*ci
= &(conn
->connInfo
);
837 inolog("%d sqltype=%d -> pgtype=%d\n",
838 ci
->bytea_as_longvarbinary
, sqlType
, pgType
);
841 if (fSqlType
== SQL_ALL_TYPES
|| fSqlType
== sqlType
)
843 int pgtcount
= 1, aunq_match
= -1, cnt
;
845 /*if (SQL_INTEGER == sqlType || SQL_TINYINT == sqlType) */
846 if (SQL_INTEGER
== sqlType
)
848 mylog("sqlType=%d ms_jet=%d\n", sqlType
, conn
->ms_jet
);
849 if (conn
->ms_jet
&& PG_VERSION_GE(conn
, 6.4))
854 mylog("aunq_match=%d pgtcount=%d\n", aunq_match
,
857 for (cnt
= 0; cnt
< pgtcount
; cnt
++)
859 tuple
= QR_AddNew(res
);
861 /* These values can't be NULL */
862 if (aunq_match
== cnt
)
864 set_tuplefield_string(&tuple
[0],
865 pgtype_to_name(stmt
, pgType
,
867 set_tuplefield_int2(&tuple
[6], SQL_NO_NULLS
);
868 inolog("serial in\n");
872 set_tuplefield_string(&tuple
[0],
873 pgtype_to_name(stmt
, pgType
,
875 set_tuplefield_int2(&tuple
[6],
876 pgtype_nullable(stmt
, pgType
));
878 set_tuplefield_int2(&tuple
[1], (Int2
) sqlType
);
879 set_tuplefield_int2(&tuple
[7],
880 pgtype_case_sensitive(stmt
,
882 set_tuplefield_int2(&tuple
[8],
883 pgtype_searchable(stmt
, pgType
));
884 set_tuplefield_int2(&tuple
[10],
885 pgtype_money(stmt
, pgType
));
888 * Localized data-source dependent data type name (always
891 set_tuplefield_null(&tuple
[12]);
893 /* These values can be NULL */
894 set_nullfield_int4(&tuple
[2],
895 pgtype_column_size(stmt
, pgType
,
898 set_nullfield_string(&tuple
[3],
899 pgtype_literal_prefix(stmt
,
901 set_nullfield_string(&tuple
[4],
902 pgtype_literal_suffix(stmt
,
904 set_nullfield_string(&tuple
[5],
905 pgtype_create_params(stmt
,
908 set_tuplefield_int2(&tuple
[9], SQL_TRUE
);
910 set_nullfield_int2(&tuple
[9],
911 pgtype_unsigned(stmt
, pgType
));
912 if (aunq_match
== cnt
)
913 set_tuplefield_int2(&tuple
[11], SQL_TRUE
);
915 set_nullfield_int2(&tuple
[11],
916 pgtype_auto_increment(stmt
,
918 set_nullfield_int2(&tuple
[13],
919 pgtype_min_decimal_digits(stmt
,
921 set_nullfield_int2(&tuple
[14],
922 pgtype_max_decimal_digits(stmt
,
924 set_nullfield_int2(&tuple
[15],
925 pgtype_to_sqldesctype(stmt
, pgType
,
927 set_nullfield_int2(&tuple
[16],
928 pgtype_to_datetime_sub(stmt
,
930 set_nullfield_int4(&tuple
[17],
931 pgtype_radix(stmt
, pgType
));
932 set_nullfield_int4(&tuple
[18], 0);
939 * also, things need to think that this statement is finished so the
940 * results can be retrieved.
942 stmt
->status
= STMT_FINISHED
;
943 stmt
->currTuple
= -1;
944 SC_set_rowset_start(stmt
, -1, FALSE
);
945 SC_set_current_col(stmt
, -1);
948 result
= DiscardStatementSvp(stmt
, result
, FALSE
);
953 PGAPI_GetFunctions(HDBC hdbc
,
954 SQLUSMALLINT fFunction
, SQLUSMALLINT FAR
* pfExists
)
956 CSTR func
= "PGAPI_GetFunctions";
957 ConnectionClass
*conn
= (ConnectionClass
*) hdbc
;
958 ConnInfo
*ci
= &(conn
->connInfo
);
960 mylog("%s: entering...%u\n", func
, fFunction
);
962 if (fFunction
== SQL_API_ALL_FUNCTIONS
)
965 memset(pfExists
, 0, sizeof(pfExists
[0]) * 100);
967 /* ODBC core functions */
968 pfExists
[SQL_API_SQLALLOCCONNECT
] = TRUE
;
969 pfExists
[SQL_API_SQLALLOCENV
] = TRUE
;
970 pfExists
[SQL_API_SQLALLOCSTMT
] = TRUE
;
971 pfExists
[SQL_API_SQLBINDCOL
] = TRUE
;
972 pfExists
[SQL_API_SQLCANCEL
] = TRUE
;
973 pfExists
[SQL_API_SQLCOLATTRIBUTES
] = TRUE
;
974 pfExists
[SQL_API_SQLCONNECT
] = TRUE
;
975 pfExists
[SQL_API_SQLDESCRIBECOL
] = TRUE
; /* partial */
976 pfExists
[SQL_API_SQLDISCONNECT
] = TRUE
;
977 pfExists
[SQL_API_SQLERROR
] = TRUE
;
978 pfExists
[SQL_API_SQLEXECDIRECT
] = TRUE
;
979 pfExists
[SQL_API_SQLEXECUTE
] = TRUE
;
980 pfExists
[SQL_API_SQLFETCH
] = TRUE
;
981 pfExists
[SQL_API_SQLFREECONNECT
] = TRUE
;
982 pfExists
[SQL_API_SQLFREEENV
] = TRUE
;
983 pfExists
[SQL_API_SQLFREESTMT
] = TRUE
;
984 pfExists
[SQL_API_SQLGETCURSORNAME
] = TRUE
;
985 pfExists
[SQL_API_SQLNUMRESULTCOLS
] = TRUE
;
986 pfExists
[SQL_API_SQLPREPARE
] = TRUE
; /* complete? */
987 pfExists
[SQL_API_SQLROWCOUNT
] = TRUE
;
988 pfExists
[SQL_API_SQLSETCURSORNAME
] = TRUE
;
989 pfExists
[SQL_API_SQLSETPARAM
] = FALSE
; /* odbc 1.0 */
990 pfExists
[SQL_API_SQLTRANSACT
] = TRUE
;
992 /* ODBC level 1 functions */
993 pfExists
[SQL_API_SQLBINDPARAMETER
] = TRUE
;
994 pfExists
[SQL_API_SQLCOLUMNS
] = TRUE
;
995 pfExists
[SQL_API_SQLDRIVERCONNECT
] = TRUE
;
996 pfExists
[SQL_API_SQLGETCONNECTOPTION
] = TRUE
; /* partial */
997 pfExists
[SQL_API_SQLGETDATA
] = TRUE
;
998 pfExists
[SQL_API_SQLGETFUNCTIONS
] = TRUE
;
999 pfExists
[SQL_API_SQLGETINFO
] = TRUE
;
1000 pfExists
[SQL_API_SQLGETSTMTOPTION
] = TRUE
; /* partial */
1001 pfExists
[SQL_API_SQLGETTYPEINFO
] = TRUE
;
1002 pfExists
[SQL_API_SQLPARAMDATA
] = TRUE
;
1003 pfExists
[SQL_API_SQLPUTDATA
] = TRUE
;
1004 pfExists
[SQL_API_SQLSETCONNECTOPTION
] = TRUE
; /* partial */
1005 pfExists
[SQL_API_SQLSETSTMTOPTION
] = TRUE
;
1006 pfExists
[SQL_API_SQLSPECIALCOLUMNS
] = TRUE
;
1007 pfExists
[SQL_API_SQLSTATISTICS
] = TRUE
;
1008 pfExists
[SQL_API_SQLTABLES
] = TRUE
;
1010 /* ODBC level 2 functions */
1011 pfExists
[SQL_API_SQLBROWSECONNECT
] = FALSE
;
1012 if (PG_VERSION_GE(conn
, 7.4))
1013 pfExists
[SQL_API_SQLCOLUMNPRIVILEGES
] = FALSE
;
1015 pfExists
[SQL_API_SQLCOLUMNPRIVILEGES
] = FALSE
;
1016 pfExists
[SQL_API_SQLDATASOURCES
] = FALSE
; /* only implemented by
1018 if (SUPPORT_DESCRIBE_PARAM(ci
))
1019 pfExists
[SQL_API_SQLDESCRIBEPARAM
] = TRUE
;
1021 pfExists
[SQL_API_SQLDESCRIBEPARAM
] = FALSE
; /* not properly
1023 pfExists
[SQL_API_SQLDRIVERS
] = FALSE
; /* only implemented by
1025 pfExists
[SQL_API_SQLEXTENDEDFETCH
] = TRUE
;
1026 pfExists
[SQL_API_SQLFOREIGNKEYS
] = TRUE
;
1027 pfExists
[SQL_API_SQLMORERESULTS
] = TRUE
;
1028 pfExists
[SQL_API_SQLNATIVESQL
] = TRUE
;
1029 pfExists
[SQL_API_SQLNUMPARAMS
] = TRUE
;
1030 pfExists
[SQL_API_SQLPARAMOPTIONS
] = TRUE
;
1031 pfExists
[SQL_API_SQLPRIMARYKEYS
] = TRUE
;
1032 if (PG_VERSION_LT(conn
, 6.5))
1033 pfExists
[SQL_API_SQLPROCEDURECOLUMNS
] = FALSE
;
1035 pfExists
[SQL_API_SQLPROCEDURECOLUMNS
] = TRUE
;
1036 if (PG_VERSION_LT(conn
, 6.5))
1037 pfExists
[SQL_API_SQLPROCEDURES
] = FALSE
;
1039 pfExists
[SQL_API_SQLPROCEDURES
] = TRUE
;
1040 pfExists
[SQL_API_SQLSETPOS
] = TRUE
;
1041 pfExists
[SQL_API_SQLSETSCROLLOPTIONS
] = TRUE
; /* odbc 1.0 */
1042 pfExists
[SQL_API_SQLTABLEPRIVILEGES
] = TRUE
;
1043 if (0 == ci
->updatable_cursors
)
1044 pfExists
[SQL_API_SQLBULKOPERATIONS
] = FALSE
;
1046 pfExists
[SQL_API_SQLBULKOPERATIONS
] = TRUE
;
1053 case SQL_API_SQLBINDCOL
:
1056 case SQL_API_SQLCANCEL
:
1059 case SQL_API_SQLCOLATTRIBUTE
:
1062 case SQL_API_SQLCONNECT
:
1065 case SQL_API_SQLDESCRIBECOL
:
1067 break; /* partial */
1068 case SQL_API_SQLDISCONNECT
:
1071 case SQL_API_SQLEXECDIRECT
:
1074 case SQL_API_SQLEXECUTE
:
1077 case SQL_API_SQLFETCH
:
1080 case SQL_API_SQLFREESTMT
:
1083 case SQL_API_SQLGETCURSORNAME
:
1086 case SQL_API_SQLNUMRESULTCOLS
:
1089 case SQL_API_SQLPREPARE
:
1092 case SQL_API_SQLROWCOUNT
:
1095 case SQL_API_SQLSETCURSORNAME
:
1099 /* ODBC level 1 functions */
1100 case SQL_API_SQLBINDPARAMETER
:
1103 case SQL_API_SQLCOLUMNS
:
1106 case SQL_API_SQLDRIVERCONNECT
:
1109 case SQL_API_SQLGETDATA
:
1112 case SQL_API_SQLGETFUNCTIONS
:
1115 case SQL_API_SQLGETINFO
:
1118 case SQL_API_SQLGETTYPEINFO
:
1121 case SQL_API_SQLPARAMDATA
:
1124 case SQL_API_SQLPUTDATA
:
1127 case SQL_API_SQLSPECIALCOLUMNS
:
1130 case SQL_API_SQLSTATISTICS
:
1133 case SQL_API_SQLTABLES
:
1137 /* ODBC level 2 functions */
1138 case SQL_API_SQLBROWSECONNECT
:
1141 case SQL_API_SQLCOLUMNPRIVILEGES
:
1144 case SQL_API_SQLDATASOURCES
:
1146 break; /* only implemented by DM */
1147 case SQL_API_SQLDESCRIBEPARAM
:
1148 if (SUPPORT_DESCRIBE_PARAM(ci
))
1152 break; /* not properly implemented */
1153 case SQL_API_SQLDRIVERS
:
1155 break; /* only implemented by DM */
1156 case SQL_API_SQLEXTENDEDFETCH
:
1159 case SQL_API_SQLFOREIGNKEYS
:
1162 case SQL_API_SQLMORERESULTS
:
1165 case SQL_API_SQLNATIVESQL
:
1168 case SQL_API_SQLNUMPARAMS
:
1171 case SQL_API_SQLPRIMARYKEYS
:
1174 case SQL_API_SQLPROCEDURECOLUMNS
:
1175 if (PG_VERSION_LT(conn
, 6.5))
1180 case SQL_API_SQLPROCEDURES
:
1181 if (PG_VERSION_LT(conn
, 6.5))
1186 case SQL_API_SQLSETPOS
:
1189 case SQL_API_SQLTABLEPRIVILEGES
:
1192 case SQL_API_SQLBULKOPERATIONS
: /* 24 */
1193 case SQL_API_SQLALLOCHANDLE
: /* 1001 */
1194 case SQL_API_SQLBINDPARAM
: /* 1002 */
1195 case SQL_API_SQLCLOSECURSOR
: /* 1003 */
1196 case SQL_API_SQLENDTRAN
: /* 1005 */
1197 case SQL_API_SQLFETCHSCROLL
: /* 1021 */
1198 case SQL_API_SQLFREEHANDLE
: /* 1006 */
1199 case SQL_API_SQLGETCONNECTATTR
: /* 1007 */
1200 case SQL_API_SQLGETDESCFIELD
: /* 1008 */
1201 case SQL_API_SQLGETDIAGFIELD
: /* 1010 */
1202 case SQL_API_SQLGETDIAGREC
: /* 1011 */
1203 case SQL_API_SQLGETENVATTR
: /* 1012 */
1204 case SQL_API_SQLGETSTMTATTR
: /* 1014 */
1205 case SQL_API_SQLSETCONNECTATTR
: /* 1016 */
1206 case SQL_API_SQLSETDESCFIELD
: /* 1017 */
1207 case SQL_API_SQLSETENVATTR
: /* 1019 */
1208 case SQL_API_SQLSETSTMTATTR
: /* 1020 */
1211 case SQL_API_SQLGETDESCREC
: /* 1009 */
1212 case SQL_API_SQLSETDESCREC
: /* 1018 */
1213 case SQL_API_SQLCOPYDESC
: /* 1004 */
1224 static char *simpleCatalogEscape(const void *_src
, int srclen
,
1226 const ConnectionClass
* conn
)
1229 const char *src
= (const char *)_src
, *in
;
1230 char *dest
= NULL
, escape_ch
= CC_get_escape(conn
);
1235 if (!src
|| srclen
== SQL_NULL_DATA
)
1237 else if (srclen
== SQL_NTS
)
1238 srclen
= (int) strlen(src
);
1241 mylog("simple in=%s(%d)\n", src
, srclen
);
1242 encoded_str_constr(&encstr
, conn
->ccsc
, src
);
1243 dest
= (char *)malloc(2 * srclen
+ 1);
1244 for (i
= 0, in
= src
, outlen
= 0; i
< srclen
; i
++, in
++)
1246 encoded_nextchar(&encstr
);
1247 if (ENCODE_STATUS(encstr
) != 0)
1249 dest
[outlen
++] = *in
;
1252 if (LITERAL_QUOTE
== *in
|| escape_ch
== *in
)
1253 dest
[outlen
++] = *in
;
1254 dest
[outlen
++] = *in
;
1256 dest
[outlen
] = '\0';
1258 *result_len
= outlen
;
1259 mylog("simple output=%s(%d)\n", dest
, outlen
);
1264 * PostgreSQL needs 2 '\\' to escape '_' and '%'.
1266 static char *adjustLikePattern(const void *_src
, int srclen
,
1267 char escape_ch
, int *result_len
,
1268 const ConnectionClass
* conn
)
1271 const char *src
= (const char *)_src
, *in
;
1272 char *dest
= NULL
, escape_in_literal
= CC_get_escape(conn
);
1273 BOOL escape_in
= FALSE
;
1278 if (!src
|| srclen
== SQL_NULL_DATA
)
1280 else if (srclen
== SQL_NTS
)
1281 srclen
= (int) strlen(src
);
1282 /* if (srclen <= 0) */
1285 mylog("adjust in=%s(%d)\n", src
, srclen
);
1286 encoded_str_constr(&encstr
, conn
->ccsc
, src
);
1287 dest
= (char *)malloc(2 * srclen
+ 1);
1288 for (i
= 0, in
= src
, outlen
= 0; i
< srclen
; i
++, in
++)
1290 encoded_nextchar(&encstr
);
1291 if (ENCODE_STATUS(encstr
) != 0)
1293 dest
[outlen
++] = *in
;
1302 if (escape_ch
== escape_in_literal
)
1303 dest
[outlen
++] = escape_in_literal
; /* and insert 1 more LEXER escape */
1304 dest
[outlen
++] = escape_ch
;
1307 if (escape_ch
== escape_in_literal
)
1308 dest
[outlen
++] = escape_in_literal
;
1309 dest
[outlen
++] = escape_ch
;
1310 if (escape_ch
== escape_in_literal
)
1311 dest
[outlen
++] = escape_in_literal
;
1312 dest
[outlen
++] = escape_ch
;
1316 if (*in
== escape_ch
)
1321 if (LITERAL_QUOTE
== *in
)
1322 dest
[outlen
++] = *in
;
1323 dest
[outlen
++] = *in
;
1326 dest
[outlen
] = '\0';
1328 *result_len
= outlen
;
1329 mylog("adjust output=%s(%d)\n", dest
, outlen
);
1335 * FIXME: we always return all tables, not parsing for wildcards, catalogs,
1336 * etc. This seems to be good enough for now but could easily explode in
1339 RETCODE SQL_API PGAPI_Tables
1341 const SQLCHAR FAR
* szTableQualifier
, /* PV X */
1342 SQLSMALLINT cbTableQualifier
,
1343 const SQLCHAR FAR
*szTableOwner
, /* PV E */
1344 SQLSMALLINT cbTableOwner
,
1345 const SQLCHAR FAR
*szTableName
, /* PV E */
1346 SQLSMALLINT cbTableName
,
1347 const SQLCHAR FAR
*szTableType
,
1348 SQLSMALLINT cbTableType
, UWORD flag
)
1350 StatementClass
*stmt
= (StatementClass
*)hstmt
;
1352 VxStatement
st(stmt
);
1355 rs
.runquery(st
.dbus(), "ExecChunkRecordset", "LIST TABLES");
1357 stmt
->catalog_result
= TRUE
;
1360 return st
.retcode();
1364 RETCODE SQL_API
PGAPI_Columns(HSTMT hstmt
, const SQLCHAR FAR
* szTableQualifier
, /* OA X */
1365 SQLSMALLINT cbTableQualifier
, const SQLCHAR FAR
* szTableOwner
, /* PV E */
1366 SQLSMALLINT cbTableOwner
, const SQLCHAR FAR
* szTableName
, /* PV E */
1367 SQLSMALLINT cbTableName
, const SQLCHAR FAR
* szColumnName
, /* PV E */
1368 SQLSMALLINT cbColumnName
,
1369 UWORD flag
, OID reloid
, Int2 attnum
)
1371 StatementClass
*stmt
= (StatementClass
*)hstmt
;
1373 VxStatement
st(stmt
);
1376 rs
.runquery(st
.dbus(), "ExecChunkRecordset",
1377 WvString("LIST COLUMNS %s", (const char *)szTableName
));
1379 stmt
->catalog_result
= TRUE
;
1382 return st
.retcode();
1386 RETCODE SQL_API
PGAPI_SpecialColumns(HSTMT hstmt
, SQLUSMALLINT fColType
, const SQLCHAR FAR
* szTableQualifier
, SQLSMALLINT cbTableQualifier
, const SQLCHAR FAR
* szTableOwner
, /* OA E */
1387 SQLSMALLINT cbTableOwner
, const SQLCHAR FAR
* szTableName
, /* OA(R) E */
1388 SQLSMALLINT cbTableName
,
1389 SQLUSMALLINT fScope
,
1390 SQLUSMALLINT fNullable
)
1392 CSTR func
= "PGAPI_SpecialColumns";
1394 StatementClass
*stmt
= (StatementClass
*) hstmt
;
1395 ConnectionClass
*conn
;
1398 HSTMT hcol_stmt
= NULL
;
1399 StatementClass
*col_stmt
;
1400 char columns_query
[INFO_INQUIRY_LEN
];
1401 char *escSchemaName
= NULL
, *escTableName
= NULL
;
1402 RETCODE result
= SQL_SUCCESS
;
1403 char relhasrules
[MAX_INFO_STRING
], relkind
[8], relhasoids
[8];
1405 SQLSMALLINT internal_asis_type
= SQL_C_CHAR
, cbSchemaName
;
1406 const char *szSchemaName
;
1408 mylog("%s: entering...stmt=%p scnm=%p len=%d colType=%d\n", func
,
1409 stmt
, NULL_IF_NULL(szTableOwner
), cbTableOwner
, fColType
);
1411 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
1413 conn
= SC_get_conn(stmt
);
1414 ci
= &(conn
->connInfo
);
1415 #ifdef UNICODE_SUPPORT
1416 if (CC_is_in_unicode_driver(conn
))
1417 internal_asis_type
= INTERNAL_ASIS_TYPE
;
1418 #endif /* UNICODE_SUPPORT */
1420 szSchemaName
= (const char *)szTableOwner
;
1421 cbSchemaName
= cbTableOwner
;
1424 simpleCatalogEscape(szTableName
, cbTableName
, NULL
, conn
);
1427 SC_set_error(stmt
, STMT_INVALID_NULL_ARG
,
1428 "The table name is required", func
);
1431 #define return DONT_CALL_RETURN_FROM_HERE???
1433 retry_public_schema
:
1435 free(escSchemaName
);
1437 simpleCatalogEscape((const UCHAR
*)szSchemaName
, cbSchemaName
, NULL
, conn
);
1439 * Create the query to find out if this is a view or not...
1441 strcpy(columns_query
, "select c.relhasrules, c.relkind");
1442 if (PG_VERSION_GE(conn
, 7.2))
1443 strcat(columns_query
, ", c.relhasoids");
1444 if (conn
->schema_support
)
1445 strcat(columns_query
, " from pg_catalog.pg_namespace u,"
1446 " pg_catalog.pg_class c where "
1447 "u.oid = c.relnamespace");
1449 strcat(columns_query
, " from pg_user u, pg_class c where "
1450 "u.usesysid = c.relowner");
1452 /* TableName cannot contain a string search pattern */
1453 /* my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName); */
1455 snprintf_add(columns_query
, sizeof(columns_query
),
1456 " and c.relname = '%s'", escTableName
);
1457 /* SchemaName cannot contain a string search pattern */
1458 if (conn
->schema_support
)
1459 schema_strcat(columns_query
, " and u.nspname = '%.*s'",
1460 escSchemaName
, SQL_NTS
, (const char *)szTableName
,
1463 my_strcat(columns_query
, " and u.usename = '%.*s'",
1464 escSchemaName
, SQL_NTS
);
1466 result
= PGAPI_AllocStmt(conn
, &hcol_stmt
);
1467 if (!SQL_SUCCEEDED(result
))
1469 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
1470 "Couldn't allocate statement for SQLSpecialColumns result.",
1475 col_stmt
= (StatementClass
*) hcol_stmt
;
1477 mylog("%s: hcol_stmt = %p, col_stmt = %p\n", func
, hcol_stmt
,
1480 result
= PGAPI_ExecDirect(hcol_stmt
, (const UCHAR
*)columns_query
, SQL_NTS
, 0);
1481 if (!SQL_SUCCEEDED(result
))
1483 SC_full_error_copy(stmt
, col_stmt
, FALSE
);
1489 if (conn
->schema_support
&&
1490 (res
= SC_get_Result(col_stmt
)) &&
1491 0 == QR_get_num_total_tuples(res
))
1493 const char *user
= CC_get_username(conn
);
1496 * If specified schema name == user_name and
1497 * the current schema is 'public',
1498 * retry the 'public' schema.
1501 (cbSchemaName
== SQL_NTS
||
1502 cbSchemaName
== (SQLSMALLINT
) strlen(user
)) &&
1503 strnicmp(szSchemaName
, user
, strlen(user
)) == 0 &&
1504 stricmp(CC_get_current_schema(conn
), pubstr
) == 0)
1506 PGAPI_FreeStmt(hcol_stmt
, SQL_DROP
);
1508 szSchemaName
= pubstr
;
1509 cbSchemaName
= SQL_NTS
;
1510 goto retry_public_schema
;
1514 result
= PGAPI_BindCol(hcol_stmt
, 1, internal_asis_type
,
1515 relhasrules
, sizeof(relhasrules
), NULL
);
1516 if (!SQL_SUCCEEDED(result
))
1518 SC_error_copy(stmt
, col_stmt
, TRUE
);
1523 result
= PGAPI_BindCol(hcol_stmt
, 2, internal_asis_type
,
1524 relkind
, sizeof(relkind
), NULL
);
1525 if (!SQL_SUCCEEDED(result
))
1527 SC_error_copy(stmt
, col_stmt
, TRUE
);
1531 relhasoids
[0] = '1';
1532 if (PG_VERSION_GE(conn
, 7.2))
1534 result
= PGAPI_BindCol(hcol_stmt
, 3, internal_asis_type
,
1535 relhasoids
, sizeof(relhasoids
), NULL
);
1536 if (!SQL_SUCCEEDED(result
))
1538 SC_error_copy(stmt
, col_stmt
, TRUE
);
1544 result
= PGAPI_Fetch(hcol_stmt
);
1545 if (PG_VERSION_GE(conn
, 7.1))
1546 relisaview
= (relkind
[0] == 'v');
1548 relisaview
= (relhasrules
[0] == '1');
1549 PGAPI_FreeStmt(hcol_stmt
, SQL_DROP
);
1552 res
= QR_Constructor();
1553 SC_set_Result(stmt
, res
);
1554 extend_column_bindings(SC_get_ARDF(stmt
), 8);
1556 stmt
->catalog_result
= TRUE
;
1557 QR_set_num_fields(res
, 8);
1558 QR_set_field_info_v(res
, 0, "SCOPE", PG_TYPE_INT2
, 2);
1559 QR_set_field_info_v(res
, 1, "COLUMN_NAME", PG_TYPE_VARCHAR
,
1561 QR_set_field_info_v(res
, 2, "DATA_TYPE", PG_TYPE_INT2
, 2);
1562 QR_set_field_info_v(res
, 3, "TYPE_NAME", PG_TYPE_VARCHAR
,
1564 QR_set_field_info_v(res
, 4, "PRECISION", PG_TYPE_INT4
, 4);
1565 QR_set_field_info_v(res
, 5, "LENGTH", PG_TYPE_INT4
, 4);
1566 QR_set_field_info_v(res
, 6, "SCALE", PG_TYPE_INT2
, 2);
1567 QR_set_field_info_v(res
, 7, "PSEUDO_COLUMN", PG_TYPE_INT2
, 2);
1571 /* there's no oid for views */
1572 if (fColType
== SQL_BEST_ROWID
)
1576 else if (fColType
== SQL_ROWVER
)
1578 Int2 the_type
= PG_TYPE_TID
;
1580 tuple
= QR_AddNew(res
);
1582 set_tuplefield_null(&tuple
[0]);
1583 set_tuplefield_string(&tuple
[1], "ctid");
1584 set_tuplefield_int2(&tuple
[2],
1585 pgtype_to_concise_type(stmt
, the_type
,
1587 set_tuplefield_string(&tuple
[3],
1588 pgtype_to_name(stmt
, the_type
,
1590 set_tuplefield_int4(&tuple
[4],
1591 pgtype_column_size(stmt
, the_type
,
1594 set_tuplefield_int4(&tuple
[5],
1595 pgtype_buffer_length(stmt
, the_type
,
1598 set_tuplefield_int2(&tuple
[6],
1599 pgtype_decimal_digits(stmt
, the_type
,
1601 set_tuplefield_int2(&tuple
[7], SQL_PC_NOT_PSEUDO
);
1602 inolog("Add ctid\n");
1607 /* use the oid value for the rowid */
1608 if (fColType
== SQL_BEST_ROWID
)
1610 Int2 the_type
= PG_TYPE_OID
;
1612 if (relhasoids
[0] != '1')
1616 tuple
= QR_AddNew(res
);
1618 set_tuplefield_int2(&tuple
[0], SQL_SCOPE_SESSION
);
1619 set_tuplefield_string(&tuple
[1], OID_NAME
);
1620 set_tuplefield_int2(&tuple
[2],
1621 pgtype_to_concise_type(stmt
, the_type
,
1623 set_tuplefield_string(&tuple
[3],
1624 pgtype_to_name(stmt
, the_type
, TRUE
));
1625 set_tuplefield_int4(&tuple
[4],
1626 pgtype_column_size(stmt
, the_type
,
1629 set_tuplefield_int4(&tuple
[5],
1630 pgtype_buffer_length(stmt
, the_type
,
1633 set_tuplefield_int2(&tuple
[6],
1634 pgtype_decimal_digits(stmt
, the_type
,
1636 set_tuplefield_int2(&tuple
[7], SQL_PC_PSEUDO
);
1638 else if (fColType
== SQL_ROWVER
)
1640 Int2 the_type
= PG_TYPE_XID
;
1642 /* if (atoi(ci->row_versioning)) */
1644 tuple
= QR_AddNew(res
);
1646 set_tuplefield_null(&tuple
[0]);
1647 set_tuplefield_string(&tuple
[1], "xmin");
1648 set_tuplefield_int2(&tuple
[2],
1649 pgtype_to_concise_type(stmt
,
1652 set_tuplefield_string(&tuple
[3],
1653 pgtype_to_name(stmt
, the_type
,
1655 set_tuplefield_int4(&tuple
[4],
1656 pgtype_column_size(stmt
, the_type
,
1659 set_tuplefield_int4(&tuple
[5],
1660 pgtype_buffer_length(stmt
, the_type
,
1663 set_tuplefield_int2(&tuple
[6],
1664 pgtype_decimal_digits(stmt
,
1667 set_tuplefield_int2(&tuple
[7], SQL_PC_PSEUDO
);
1675 free(escSchemaName
);
1678 stmt
->status
= STMT_FINISHED
;
1679 stmt
->currTuple
= -1;
1680 SC_set_rowset_start(stmt
, -1, FALSE
);
1681 SC_set_current_col(stmt
, -1);
1683 PGAPI_FreeStmt(hcol_stmt
, SQL_DROP
);
1685 result
= DiscardStatementSvp(stmt
, result
, FALSE
);
1686 mylog("%s: EXIT, stmt=%p\n", func
, stmt
);
1690 RETCODE SQL_API
PGAPI_Statistics(HSTMT hstmt
, const SQLCHAR FAR
* szTableQualifier
, /* OA X */
1691 SQLSMALLINT cbTableQualifier
, const SQLCHAR FAR
* szTableOwner
, /* OA E */
1692 SQLSMALLINT cbTableOwner
, const SQLCHAR FAR
* szTableName
, /* OA(R) E */
1693 SQLSMALLINT cbTableName
,
1694 SQLUSMALLINT fUnique
,
1695 SQLUSMALLINT fAccuracy
)
1697 CSTR func
= "PGAPI_Statistics";
1698 StatementClass
*stmt
= (StatementClass
*) hstmt
;
1699 ConnectionClass
*conn
;
1701 char index_query
[INFO_INQUIRY_LEN
];
1702 HSTMT hcol_stmt
= NULL
, hindx_stmt
= NULL
;
1703 RETCODE ret
= SQL_ERROR
, result
;
1704 char *escSchemaName
= NULL
, *table_name
= NULL
, *escTableName
=
1706 char index_name
[MAX_INFO_STRING
];
1707 short fields_vector
[INDEX_KEYS_STORAGE_COUNT
+ 1];
1708 char isunique
[10], isclustered
[10], ishash
[MAX_INFO_STRING
];
1709 SQLLEN index_name_len
, fields_vector_len
;
1712 StatementClass
*col_stmt
, *indx_stmt
;
1713 char column_name
[MAX_INFO_STRING
],
1714 table_schemaname
[MAX_INFO_STRING
], relhasrules
[10];
1715 struct columns_idx
{
1719 *column_names
= NULL
;
1720 /* char **column_names = NULL; */
1721 SQLLEN column_name_len
;
1722 int total_columns
= 0, alcount
;
1725 SQLSMALLINT internal_asis_type
=
1726 SQL_C_CHAR
, cbSchemaName
, field_number
;
1727 const char *szSchemaName
;
1730 mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func
, stmt
,
1731 NULL_IF_NULL(szTableOwner
), cbTableOwner
);
1733 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
1736 table_name
= make_string(szTableName
, cbTableName
, NULL
, 0);
1739 SC_set_error(stmt
, STMT_INVALID_NULL_ARG
,
1740 "The table name is required", func
);
1743 conn
= SC_get_conn(stmt
);
1744 ci
= &(conn
->connInfo
);
1745 #ifdef UNICODE_SUPPORT
1746 if (CC_is_in_unicode_driver(conn
))
1747 internal_asis_type
= INTERNAL_ASIS_TYPE
;
1748 #endif /* UNICODE_SUPPORT */
1750 if (res
= QR_Constructor(), !res
)
1752 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
1753 "Couldn't allocate memory for PGAPI_Statistics result.",
1757 SC_set_Result(stmt
, res
);
1759 /* the binding structure for a statement is not set up until */
1762 * a statement is actually executed, so we'll have to do this
1765 extend_column_bindings(SC_get_ARDF(stmt
), 13);
1767 stmt
->catalog_result
= TRUE
;
1768 /* set the field names */
1769 QR_set_num_fields(res
, NUM_OF_STATS_FIELDS
);
1770 QR_set_field_info_v(res
, STATS_CATALOG_NAME
, "TABLE_QUALIFIER",
1771 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
1772 QR_set_field_info_v(res
, STATS_SCHEMA_NAME
, "TABLE_OWNER",
1773 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
1774 QR_set_field_info_v(res
, STATS_TABLE_NAME
, "TABLE_NAME",
1775 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
1776 QR_set_field_info_v(res
, STATS_NON_UNIQUE
, "NON_UNIQUE",
1778 QR_set_field_info_v(res
, STATS_INDEX_QUALIFIER
, "INDEX_QUALIFIER",
1779 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
1780 QR_set_field_info_v(res
, STATS_INDEX_NAME
, "INDEX_NAME",
1781 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
1782 QR_set_field_info_v(res
, STATS_TYPE
, "TYPE", PG_TYPE_INT2
, 2);
1783 QR_set_field_info_v(res
, STATS_SEQ_IN_INDEX
, "SEQ_IN_INDEX",
1785 QR_set_field_info_v(res
, STATS_COLUMN_NAME
, "COLUMN_NAME",
1786 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
1787 QR_set_field_info_v(res
, STATS_COLLATION
, "COLLATION", PG_TYPE_CHAR
,
1789 QR_set_field_info_v(res
, STATS_CARDINALITY
, "CARDINALITY",
1791 QR_set_field_info_v(res
, STATS_PAGES
, "PAGES", PG_TYPE_INT4
, 4);
1792 QR_set_field_info_v(res
, STATS_FILTER_CONDITION
, "FILTER_CONDITION",
1793 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
1795 #define return DONT_CALL_RETURN_FROM_HERE???
1796 szSchemaName
= (const char *)szTableOwner
;
1797 cbSchemaName
= cbTableOwner
;
1799 table_schemaname
[0] = '\0';
1800 if (conn
->schema_support
)
1801 schema_strcat(table_schemaname
, "%.*s", szSchemaName
,
1802 cbSchemaName
, (const char *)szTableName
,
1806 * we need to get a list of the field names first, so we can return
1809 result
= PGAPI_AllocStmt(conn
, &hcol_stmt
);
1810 if (!SQL_SUCCEEDED(result
))
1812 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
1813 "PGAPI_AllocStmt failed in PGAPI_Statistics for columns.",
1818 col_stmt
= (StatementClass
*) hcol_stmt
;
1821 * "internal" prevents SQLColumns from returning the oid if it is
1822 * being shown. This would throw everything off.
1824 col_stmt
->internal
= TRUE
;
1826 * table_name parameter cannot contain a string search pattern.
1829 PGAPI_Columns(hcol_stmt
, NULL
, 0,
1830 (const UCHAR
*)table_schemaname
, SQL_NTS
,
1831 (const UCHAR
*)table_name
, SQL_NTS
, NULL
, 0,
1832 PODBC_NOT_SEARCH_PATTERN
|
1833 PODBC_SEARCH_PUBLIC_SCHEMA
, 0, 0);
1834 col_stmt
->internal
= FALSE
;
1836 if (!SQL_SUCCEEDED(result
))
1838 SC_error_copy(stmt
, col_stmt
, TRUE
);
1842 PGAPI_BindCol(hcol_stmt
, COLUMNS_COLUMN_NAME
+ 1,
1843 internal_asis_type
, column_name
,
1844 sizeof(column_name
), &column_name_len
);
1845 if (!SQL_SUCCEEDED(result
))
1847 SC_error_copy(stmt
, col_stmt
, TRUE
);
1851 PGAPI_BindCol(hcol_stmt
, COLUMNS_PHYSICAL_NUMBER
+ 1,
1852 SQL_C_SHORT
, &field_number
, sizeof(field_number
),
1854 if (!SQL_SUCCEEDED(result
))
1856 SC_error_copy(stmt
, col_stmt
, TRUE
);
1861 result
= PGAPI_Fetch(hcol_stmt
);
1862 while (SQL_SUCCEEDED(result
))
1864 if (0 == total_columns
)
1865 PGAPI_GetData(hcol_stmt
, 2, internal_asis_type
,
1866 table_schemaname
, sizeof(table_schemaname
),
1869 if (total_columns
>= alcount
)
1876 (struct columns_idx
*) realloc(column_names
,
1881 column_names
[total_columns
].col_name
=
1882 (char *) malloc(strlen(column_name
) + 1);
1883 strcpy(column_names
[total_columns
].col_name
, column_name
);
1884 column_names
[total_columns
].pnum
= field_number
;
1887 mylog("%s: column_name = '%s'\n", func
, column_name
);
1889 result
= PGAPI_Fetch(hcol_stmt
);
1892 if (result
!= SQL_NO_DATA_FOUND
)
1894 SC_full_error_copy(stmt
, col_stmt
, FALSE
);
1897 PGAPI_FreeStmt(hcol_stmt
, SQL_DROP
);
1899 if (total_columns
== 0)
1901 /* Couldn't get column names in SQLStatistics.; */
1906 /* get a list of indexes on this table */
1907 result
= PGAPI_AllocStmt(conn
, &hindx_stmt
);
1908 if (!SQL_SUCCEEDED(result
))
1910 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
1911 "PGAPI_AllocStmt failed in SQLStatistics for indices.",
1916 indx_stmt
= (StatementClass
*) hindx_stmt
;
1918 /* TableName cannot contain a string search pattern */
1919 escTableName
= simpleCatalogEscape(table_name
, SQL_NTS
, NULL
, conn
);
1920 if (conn
->schema_support
)
1923 simpleCatalogEscape(table_schemaname
, SQL_NTS
, NULL
, conn
);
1924 snprintf(index_query
, sizeof(index_query
),
1925 "select c.relname, i.indkey, i.indisunique"
1926 ", i.indisclustered, a.amname, c.relhasrules, n.nspname"
1928 " from pg_catalog.pg_index i, pg_catalog.pg_class c,"
1929 " pg_catalog.pg_class d, pg_catalog.pg_am a,"
1930 " pg_catalog.pg_namespace n" " where d.relname = '%s'"
1931 " and n.nspname = '%s'" " and n.oid = d.relnamespace"
1932 " and d.oid = i.indrelid" " and i.indexrelid = c.oid"
1933 " and c.relam = a.oid order by", escTableName
,
1937 snprintf(index_query
, sizeof(index_query
),
1938 "select c.relname, i.indkey, i.indisunique"
1939 ", i.indisclustered, a.amname, c.relhasrules, c.oid"
1940 " from pg_index i, pg_class c, pg_class d, pg_am a"
1941 " where d.relname = '%s'" " and d.oid = i.indrelid"
1942 " and i.indexrelid = c.oid"
1943 " and c.relam = a.oid order by", escTableName
);
1944 if (PG_VERSION_GT(SC_get_conn(stmt
), 6.4))
1945 strcat(index_query
, " i.indisprimary desc,");
1946 if (conn
->schema_support
)
1947 strcat(index_query
, " i.indisunique, n.nspname, c.relname");
1949 strcat(index_query
, " i.indisunique, c.relname");
1951 result
= PGAPI_ExecDirect(hindx_stmt
, (const UCHAR
*)index_query
, SQL_NTS
, 0);
1952 if (!SQL_SUCCEEDED(result
))
1955 * "Couldn't execute index query (w/SQLExecDirect) in
1958 SC_full_error_copy(stmt
, indx_stmt
, FALSE
);
1962 /* bind the index name column */
1963 result
= PGAPI_BindCol(hindx_stmt
, 1, internal_asis_type
,
1964 index_name
, MAX_INFO_STRING
,
1966 if (!SQL_SUCCEEDED(result
))
1968 SC_error_copy(stmt
, indx_stmt
, TRUE
); /* "Couldn't bind column
1969 * in SQLStatistics."; */
1973 /* bind the vector column */
1974 result
= PGAPI_BindCol(hindx_stmt
, 2, SQL_C_DEFAULT
,
1975 fields_vector
, sizeof(fields_vector
),
1976 &fields_vector_len
);
1977 if (!SQL_SUCCEEDED(result
))
1979 SC_error_copy(stmt
, indx_stmt
, TRUE
); /* "Couldn't bind column
1980 * in SQLStatistics."; */
1984 /* bind the "is unique" column */
1985 result
= PGAPI_BindCol(hindx_stmt
, 3, internal_asis_type
,
1986 isunique
, sizeof(isunique
), NULL
);
1987 if (!SQL_SUCCEEDED(result
))
1989 SC_error_copy(stmt
, indx_stmt
, TRUE
); /* "Couldn't bind column
1990 * in SQLStatistics."; */
1994 /* bind the "is clustered" column */
1995 result
= PGAPI_BindCol(hindx_stmt
, 4, internal_asis_type
,
1996 isclustered
, sizeof(isclustered
), NULL
);
1997 if (!SQL_SUCCEEDED(result
))
1999 SC_error_copy(stmt
, indx_stmt
, TRUE
); /* "Couldn't bind column *
2000 * in SQLStatistics."; */
2005 /* bind the "is hash" column */
2006 result
= PGAPI_BindCol(hindx_stmt
, 5, internal_asis_type
,
2007 ishash
, sizeof(ishash
), NULL
);
2008 if (!SQL_SUCCEEDED(result
))
2010 SC_error_copy(stmt
, indx_stmt
, TRUE
); /* "Couldn't bind column *
2011 * in SQLStatistics."; */
2016 result
= PGAPI_BindCol(hindx_stmt
, 6, internal_asis_type
,
2017 relhasrules
, sizeof(relhasrules
), NULL
);
2018 if (!SQL_SUCCEEDED(result
))
2020 SC_error_copy(stmt
, indx_stmt
, TRUE
);
2024 result
= PGAPI_BindCol(hindx_stmt
, 8, SQL_C_ULONG
,
2025 &ioid
, sizeof(ioid
), NULL
);
2026 if (!SQL_SUCCEEDED(result
))
2028 SC_error_copy(stmt
, indx_stmt
, TRUE
);
2032 relhasrules
[0] = '0';
2033 result
= PGAPI_Fetch(hindx_stmt
);
2034 /* fake index of OID */
2035 if (relhasrules
[0] != '1' && atoi(ci
->show_oid_column
)
2036 && atoi(ci
->fake_oid_index
))
2038 tuple
= QR_AddNew(res
);
2040 /* no table qualifier */
2041 set_tuplefield_string(&tuple
[STATS_CATALOG_NAME
],
2043 /* don't set the table owner, else Access tries to use it */
2044 set_tuplefield_string(&tuple
[STATS_SCHEMA_NAME
],
2045 GET_SCHEMA_NAME(table_schemaname
));
2046 set_tuplefield_string(&tuple
[STATS_TABLE_NAME
], table_name
);
2048 /* non-unique index? */
2049 set_tuplefield_int2(&tuple
[STATS_NON_UNIQUE
], (Int2
)FALSE
);
2051 /* no index qualifier */
2052 set_tuplefield_string(&tuple
[STATS_INDEX_QUALIFIER
],
2055 snprintf(buf
, sizeof(table_name
), "%s_idx_fake_oid",
2057 set_tuplefield_string(&tuple
[STATS_INDEX_NAME
], buf
);
2060 * Clustered/HASH index?
2062 set_tuplefield_int2(&tuple
[STATS_TYPE
], (Int2
) SQL_INDEX_OTHER
);
2063 set_tuplefield_int2(&tuple
[STATS_SEQ_IN_INDEX
], (Int2
) 1);
2065 set_tuplefield_string(&tuple
[STATS_COLUMN_NAME
], OID_NAME
);
2066 set_tuplefield_string(&tuple
[STATS_COLLATION
], "A");
2067 set_tuplefield_null(&tuple
[STATS_CARDINALITY
]);
2068 set_tuplefield_null(&tuple
[STATS_PAGES
]);
2069 set_tuplefield_null(&tuple
[STATS_FILTER_CONDITION
]);
2072 while (SQL_SUCCEEDED(result
))
2074 /* If only requesting unique indexs, then just return those. */
2075 if (fUnique
== SQL_INDEX_ALL
||
2076 (fUnique
== SQL_INDEX_UNIQUE
&& atoi(isunique
)))
2080 /* add a row in this table for each field in the index */
2081 colcnt
= fields_vector
[0];
2082 for (i
= 1; i
<= colcnt
; i
++)
2084 tuple
= QR_AddNew(res
);
2086 /* no table qualifier */
2087 set_tuplefield_string(&tuple
[STATS_CATALOG_NAME
],
2089 /* don't set the table owner, else Access tries to use it */
2090 set_tuplefield_string(&tuple
[STATS_SCHEMA_NAME
],
2092 (table_schemaname
));
2093 set_tuplefield_string(&tuple
[STATS_TABLE_NAME
],
2096 /* non-unique index? */
2097 set_tuplefield_int2(&tuple
[STATS_NON_UNIQUE
],
2098 (Int2
) (atoi(isunique
) ? FALSE
:
2101 /* no index qualifier */
2102 set_tuplefield_string(&tuple
[STATS_INDEX_QUALIFIER
],
2104 set_tuplefield_string(&tuple
[STATS_INDEX_NAME
],
2108 * Clustered/HASH index?
2110 set_tuplefield_int2(&tuple
[STATS_TYPE
], (Int2
)
2111 (atoi(isclustered
) ?
2113 : (!strncmp(ishash
, "hash", 4)) ?
2116 set_tuplefield_int2(&tuple
[STATS_SEQ_IN_INDEX
],
2119 attnum
= fields_vector
[i
];
2120 if (OID_ATTNUM
== attnum
)
2122 set_tuplefield_string(&tuple
[STATS_COLUMN_NAME
],
2124 mylog("%s: column name = oid\n", func
);
2126 else if (0 == attnum
)
2132 snprintf(cmd
, sizeof(cmd
),
2133 "select pg_get_indexdef(%u, %d, true)",
2136 CC_send_query(conn
, cmd
, NULL
,
2137 IGNORE_ABORT_ON_CONN
, stmt
);
2138 if (QR_command_maybe_successful(res
))
2139 set_tuplefield_string(&tuple
[STATS_COLUMN_NAME
],
2140 QR_get_value_backend_text
2147 BOOL unknownf
= TRUE
;
2151 for (j
= 0; j
< total_columns
; j
++)
2153 if (attnum
== column_names
[j
].pnum
)
2163 set_tuplefield_string(&tuple
[STATS_COLUMN_NAME
],
2165 mylog("%s: column name = UNKNOWN\n", func
);
2169 set_tuplefield_string(&tuple
[STATS_COLUMN_NAME
],
2170 column_names
[matchidx
].
2172 mylog("%s: column name = '%s'\n", func
,
2173 column_names
[matchidx
].col_name
);
2177 set_tuplefield_string(&tuple
[STATS_COLLATION
], "A");
2178 set_tuplefield_null(&tuple
[STATS_CARDINALITY
]);
2179 set_tuplefield_null(&tuple
[STATS_PAGES
]);
2180 set_tuplefield_null(&tuple
[STATS_FILTER_CONDITION
]);
2184 result
= PGAPI_Fetch(hindx_stmt
);
2186 if (result
!= SQL_NO_DATA_FOUND
)
2188 /* "SQLFetch failed in SQLStatistics."; */
2189 SC_full_error_copy(stmt
, indx_stmt
, FALSE
);
2197 * also, things need to think that this statement is finished so the
2198 * results can be retrieved.
2200 stmt
->status
= STMT_FINISHED
;
2203 PGAPI_FreeStmt(hcol_stmt
, SQL_DROP
);
2205 PGAPI_FreeStmt(hindx_stmt
, SQL_DROP
);
2206 /* These things should be freed on any error ALSO! */
2212 free(escSchemaName
);
2215 for (i
= 0; i
< total_columns
; i
++)
2216 free(column_names
[i
].col_name
);
2220 /* set up the current tuple pointer for SQLFetch */
2221 stmt
->currTuple
= -1;
2222 SC_set_rowset_start(stmt
, -1, FALSE
);
2223 SC_set_current_col(stmt
, -1);
2226 ret
= DiscardStatementSvp(stmt
, ret
, FALSE
);
2227 mylog("%s: EXIT, stmt=%p, ret=%d\n", func
, stmt
, ret
);
2232 RETCODE SQL_API
PGAPI_ColumnPrivileges(HSTMT hstmt
, const SQLCHAR FAR
* szTableQualifier
, /* OA X */
2233 SQLSMALLINT cbTableQualifier
, const SQLCHAR FAR
* szTableOwner
, /* OA E */
2234 SQLSMALLINT cbTableOwner
, const SQLCHAR FAR
* szTableName
, /* OA(R) E */
2235 SQLSMALLINT cbTableName
, const SQLCHAR FAR
* szColumnName
, /* PV E */
2236 SQLSMALLINT cbColumnName
,
2239 CSTR func
= "PGAPI_ColumnPrivileges";
2240 StatementClass
*stmt
= (StatementClass
*) hstmt
;
2241 ConnectionClass
*conn
= SC_get_conn(stmt
);
2242 RETCODE result
= SQL_ERROR
;
2243 char *escSchemaName
= NULL
, *escTableName
= NULL
, *escColumnName
=
2245 const char *like_or_eq
;
2246 char column_query
[INFO_INQUIRY_LEN
];
2247 size_t cq_len
, cq_size
;
2249 BOOL search_pattern
;
2252 mylog("%s: entering...\n", func
);
2254 /* Neither Access or Borland care about this. */
2256 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
2258 if (PG_VERSION_LT(conn
, 7.4))
2259 SC_set_error(stmt
, STMT_NOT_IMPLEMENTED_ERROR
,
2260 "Function not implementedyet", func
);
2262 simpleCatalogEscape(szTableOwner
, cbTableOwner
, NULL
, conn
);
2264 simpleCatalogEscape(szTableName
, cbTableName
, NULL
, conn
);
2265 search_pattern
= (0 == (flag
& PODBC_NOT_SEARCH_PATTERN
));
2268 like_or_eq
= likeop
;
2270 adjustLikePattern(szColumnName
, cbColumnName
,
2271 SEARCH_PATTERN_ESCAPE
, NULL
, conn
);
2277 simpleCatalogEscape(szColumnName
, cbColumnName
, NULL
, conn
);
2279 strcpy(column_query
,
2280 "select '' as TABLE_CAT, table_schema as TABLE_SCHEM,"
2281 " table_name, column_name, grantor, grantee,"
2282 " privilege_type as PRIVILEGE, is_grantable from"
2283 " information_schema.column_privileges where true");
2284 cq_len
= strlen(column_query
);
2285 cq_size
= sizeof(column_query
);
2286 col_query
= column_query
;
2289 col_query
+= cq_len
;
2291 cq_len
= snprintf_len(col_query
, cq_size
,
2292 " and table_schem = '%s'", escSchemaName
);
2297 col_query
+= cq_len
;
2299 cq_len
+= snprintf_len(col_query
, cq_size
,
2300 " and table_name = '%s'", escTableName
);
2304 col_query
+= cq_len
;
2306 cq_len
+= snprintf_len(col_query
, cq_size
,
2307 " and column_name %s '%s'", like_or_eq
,
2311 CC_send_query(conn
, column_query
, NULL
, IGNORE_ABORT_ON_CONN
,
2312 stmt
), !QR_command_maybe_successful(res
))
2314 SC_set_error(stmt
, STMT_EXEC_ERROR
,
2315 "PGAPI_ColumnPrivileges query error", func
);
2319 SC_set_Result(stmt
, res
);
2322 * also, things need to think that this statement is finished so the
2323 * results can be retrieved.
2325 extend_column_bindings(SC_get_ARDF(stmt
), 8);
2326 /* set up the current tuple pointer for SQLFetch */
2327 result
= SQL_SUCCESS
;
2329 /* set up the current tuple pointer for SQLFetch */
2330 stmt
->status
= STMT_FINISHED
;
2331 stmt
->currTuple
= -1;
2332 SC_set_rowset_start(stmt
, -1, FALSE
);
2334 free(escSchemaName
);
2338 free(escColumnName
);
2345 * Retrieve the primary key columns for the specified table.
2347 RETCODE SQL_API
PGAPI_PrimaryKeys(HSTMT hstmt
, const SQLCHAR FAR
* szTableQualifier
, /* OA X */
2348 SQLSMALLINT cbTableQualifier
, const SQLCHAR FAR
* szTableOwner
, /* OA E */
2349 SQLSMALLINT cbTableOwner
, const SQLCHAR FAR
* szTableName
, /* OA(R) E */
2350 SQLSMALLINT cbTableName
)
2352 CSTR func
= "PGAPI_PrimaryKeys";
2353 StatementClass
*stmt
= (StatementClass
*) hstmt
;
2355 ConnectionClass
*conn
;
2357 RETCODE ret
= SQL_SUCCESS
, result
;
2359 HSTMT htbl_stmt
= NULL
;
2360 StatementClass
*tbl_stmt
;
2361 char tables_query
[INFO_INQUIRY_LEN
];
2362 char attname
[MAX_INFO_STRING
];
2364 char *pktab
= NULL
, pkscm
[TABLE_NAME_STORAGE_LEN
+ 1];
2365 char pkname
[TABLE_NAME_STORAGE_LEN
+ 1];
2367 int qno
, qstart
, qend
;
2368 SQLSMALLINT internal_asis_type
= SQL_C_CHAR
, cbSchemaName
;
2369 const char *szSchemaName
;
2370 char *escSchemaName
= NULL
, *escTableName
= NULL
;
2372 mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func
, stmt
,
2373 NULL_IF_NULL(szTableOwner
), cbTableOwner
);
2375 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
2378 if (res
= QR_Constructor(), !res
)
2380 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
2381 "Couldn't allocate memory for PGAPI_PrimaryKeys result.",
2385 SC_set_Result(stmt
, res
);
2387 /* the binding structure for a statement is not set up until
2389 * a statement is actually executed, so we'll have to do this
2392 result_cols
= NUM_OF_PKS_FIELDS
;
2393 extend_column_bindings(SC_get_ARDF(stmt
), result_cols
);
2395 stmt
->catalog_result
= TRUE
;
2396 /* set the field names */
2397 QR_set_num_fields(res
, result_cols
);
2398 QR_set_field_info_v(res
, PKS_TABLE_CAT
, "TABLE_QUALIFIER",
2399 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2400 QR_set_field_info_v(res
, PKS_TABLE_SCHEM
, "TABLE_OWNER",
2401 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2402 QR_set_field_info_v(res
, PKS_TABLE_NAME
, "TABLE_NAME",
2403 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2404 QR_set_field_info_v(res
, PKS_COLUMN_NAME
, "COLUMN_NAME",
2405 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2406 QR_set_field_info_v(res
, PKS_KEY_SQ
, "KEY_SEQ", PG_TYPE_INT2
, 2);
2407 QR_set_field_info_v(res
, PKS_PK_NAME
, "PK_NAME", PG_TYPE_VARCHAR
,
2410 conn
= SC_get_conn(stmt
);
2411 result
= PGAPI_AllocStmt(conn
, &htbl_stmt
);
2412 if (!SQL_SUCCEEDED(result
))
2414 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
2415 "Couldn't allocate statement for Primary Key result.",
2420 tbl_stmt
= (StatementClass
*) htbl_stmt
;
2422 #ifdef UNICODE_SUPPORT
2423 if (CC_is_in_unicode_driver(conn
))
2424 internal_asis_type
= INTERNAL_ASIS_TYPE
;
2425 #endif /* UNICODE_SUPPORT */
2427 pktab
= make_string(szTableName
, cbTableName
, NULL
, 0);
2428 if (!pktab
|| pktab
[0] == '\0')
2430 SC_set_error(stmt
, STMT_INTERNAL_ERROR
,
2431 "No Table specified to PGAPI_PrimaryKeys.", func
);
2435 szSchemaName
= (const char *)szTableOwner
;
2436 cbSchemaName
= cbTableOwner
;
2438 #define return DONT_CALL_RETURN_FROM_HERE???
2440 simpleCatalogEscape(szTableName
, cbTableName
, NULL
, conn
);
2442 retry_public_schema
:
2444 free(escSchemaName
);
2446 simpleCatalogEscape(szSchemaName
, cbSchemaName
, NULL
, conn
);
2448 if (conn
->schema_support
)
2449 schema_strcat(pkscm
, "%.*s", escSchemaName
, SQL_NTS
,
2450 (const char *)szTableName
, cbTableName
, conn
);
2452 result
= PGAPI_BindCol(htbl_stmt
, 1, internal_asis_type
,
2453 attname
, MAX_INFO_STRING
, &attname_len
);
2454 if (!SQL_SUCCEEDED(result
))
2456 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
2460 result
= PGAPI_BindCol(htbl_stmt
, 3, internal_asis_type
,
2461 pkname
, TABLE_NAME_STORAGE_LEN
, NULL
);
2462 if (!SQL_SUCCEEDED(result
))
2464 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
2469 if (PG_VERSION_LE(conn
, 6.4))
2474 for (qno
= qstart
; qno
<= qend
; qno
++)
2481 * Simplified query to remove assumptions about number of
2482 * possible index columns. Courtesy of Tom Lane - thomas
2485 if (conn
->schema_support
)
2486 snprintf(tables_query
, sizeof(tables_query
),
2487 "select ta.attname, ia.attnum, ic.relname"
2488 " from pg_catalog.pg_attribute ta,"
2489 " pg_catalog.pg_attribute ia, pg_catalog.pg_class tc,"
2490 " pg_catalog.pg_index i, pg_catalog.pg_namespace n"
2491 ", pg_catalog.pg_class ic"
2492 " where tc.relname = '%s'"
2493 " AND n.nspname = '%s'"
2494 " AND tc.oid = i.indrelid"
2495 " AND n.oid = tc.relnamespace"
2496 " AND i.indisprimary = 't'"
2497 " AND ia.attrelid = i.indexrelid"
2498 " AND ta.attrelid = i.indrelid"
2499 " AND ta.attnum = i.indkey[ia.attnum-1]"
2500 " AND (NOT ta.attisdropped)"
2501 " AND (NOT ia.attisdropped)"
2502 " AND ic.oid = i.indexrelid"
2503 " order by ia.attnum", escTableName
, pkscm
);
2505 snprintf(tables_query
, sizeof(tables_query
),
2506 "select ta.attname, ia.attnum, ic.relname"
2507 " from pg_attribute ta, pg_attribute ia, pg_class tc, pg_index i, pg_class ic"
2508 " where tc.relname = '%s'"
2509 " AND tc.oid = i.indrelid"
2510 " AND i.indisprimary = 't'"
2511 " AND ia.attrelid = i.indexrelid"
2512 " AND ta.attrelid = i.indrelid"
2513 " AND ta.attnum = i.indkey[ia.attnum-1]"
2514 " AND ic.oid = i.indexrelid"
2515 " order by ia.attnum", escTableName
);
2520 * Simplified query to search old fashoned primary key
2522 if (conn
->schema_support
)
2523 snprintf(tables_query
, sizeof(tables_query
),
2524 "select ta.attname, ia.attnum, ic.relname"
2525 " from pg_catalog.pg_attribute ta,"
2526 " pg_catalog.pg_attribute ia, pg_catalog.pg_class ic,"
2527 " pg_catalog.pg_index i, pg_catalog.pg_namespace n"
2528 " where ic.relname = '%s_pkey'"
2529 " AND n.nspname = '%s'"
2530 " AND ic.oid = i.indexrelid"
2531 " AND n.oid = ic.relnamespace"
2532 " AND ia.attrelid = i.indexrelid"
2533 " AND ta.attrelid = i.indrelid"
2534 " AND ta.attnum = i.indkey[ia.attnum-1]"
2535 " AND (NOT ta.attisdropped)"
2536 " AND (NOT ia.attisdropped)"
2537 " order by ia.attnum", escTableName
, pkscm
);
2539 snprintf(tables_query
, sizeof(tables_query
),
2540 "select ta.attname, ia.attnum, ic.relname"
2541 " from pg_attribute ta, pg_attribute ia, pg_class ic, pg_index i"
2542 " where ic.relname = '%s_pkey'"
2543 " AND ic.oid = i.indexrelid"
2544 " AND ia.attrelid = i.indexrelid"
2545 " AND ta.attrelid = i.indrelid"
2546 " AND ta.attnum = i.indkey[ia.attnum-1]"
2547 " order by ia.attnum", escTableName
);
2550 mylog("%s: tables_query='%s'\n", func
, tables_query
);
2552 result
= PGAPI_ExecDirect(htbl_stmt
, (const UCHAR
*)tables_query
, SQL_NTS
, 0);
2553 if (!SQL_SUCCEEDED(result
))
2555 SC_full_error_copy(stmt
, tbl_stmt
, FALSE
);
2560 result
= PGAPI_Fetch(htbl_stmt
);
2561 if (result
!= SQL_NO_DATA_FOUND
)
2566 if (conn
->schema_support
&& SQL_NO_DATA_FOUND
== result
)
2568 const char *user
= CC_get_username(conn
);
2571 * If specified schema name == user_name and
2572 * the current schema is 'public',
2573 * retry the 'public' schema.
2576 (cbSchemaName
== SQL_NTS
||
2577 cbSchemaName
== (SQLSMALLINT
) strlen(user
)) &&
2578 strnicmp(szSchemaName
, user
, strlen(user
)) == 0 &&
2579 stricmp(CC_get_current_schema(conn
), pubstr
) == 0)
2581 szSchemaName
= pubstr
;
2582 cbSchemaName
= SQL_NTS
;
2583 goto retry_public_schema
;
2587 while (SQL_SUCCEEDED(result
))
2589 tuple
= QR_AddNew(res
);
2591 set_tuplefield_string(&tuple
[PKS_TABLE_CAT
], CurrCat(conn
));
2594 * I have to hide the table owner from Access, otherwise it
2595 * insists on referring to the table as 'owner.table'. (this is
2596 * valid according to the ODBC SQL grammar, but Postgres won't
2599 set_tuplefield_string(&tuple
[PKS_TABLE_SCHEM
],
2600 GET_SCHEMA_NAME(pkscm
));
2601 set_tuplefield_string(&tuple
[PKS_TABLE_NAME
], pktab
);
2602 set_tuplefield_string(&tuple
[PKS_COLUMN_NAME
], attname
);
2603 set_tuplefield_int2(&tuple
[PKS_KEY_SQ
], (Int2
) (++seq
));
2604 set_tuplefield_string(&tuple
[PKS_PK_NAME
], pkname
);
2607 (">> primaryKeys: pktab = '%s', attname = '%s', seq = %d\n",
2608 pktab
, attname
, seq
);
2610 result
= PGAPI_Fetch(htbl_stmt
);
2613 if (result
!= SQL_NO_DATA_FOUND
)
2615 SC_full_error_copy(stmt
, tbl_stmt
, FALSE
);
2624 * also, things need to think that this statement is finished so the
2625 * results can be retrieved.
2627 stmt
->status
= STMT_FINISHED
;
2630 PGAPI_FreeStmt(htbl_stmt
, SQL_DROP
);
2635 free(escSchemaName
);
2638 /* set up the current tuple pointer for SQLFetch */
2639 stmt
->currTuple
= -1;
2640 SC_set_rowset_start(stmt
, -1, FALSE
);
2641 SC_set_current_col(stmt
, -1);
2644 ret
= DiscardStatementSvp(stmt
, ret
, FALSE
);
2645 mylog("%s: EXIT, stmt=%p, ret=%d\n", func
, stmt
, ret
);
2650 * Multibyte support stuff for SQLForeignKeys().
2651 * There may be much more effective way in the
2652 * future version. The way is very forcible currently.
2654 static BOOL
isMultibyte(const UCHAR
* str
)
2663 static char *getClientColumnName(ConnectionClass
* conn
, UInt4 relid
,
2664 char *serverColumnName
,
2667 char query
[1024], saveattnum
[16], *ret
= serverColumnName
;
2668 BOOL continueExec
= TRUE
, bError
= FALSE
;
2669 QResultClass
*res
= NULL
;
2670 UWORD flag
= IGNORE_ABORT_ON_CONN
| ROLLBACK_ON_ERROR
;
2672 *nameAlloced
= FALSE
;
2673 if (!conn
->original_client_encoding
2674 || !isMultibyte((const UCHAR
*)serverColumnName
))
2676 if (!conn
->server_encoding
)
2679 CC_send_query(conn
, "select getdatabaseencoding()", NULL
,
2680 flag
, NULL
), QR_command_maybe_successful(res
))
2682 if (QR_get_num_cached_tuples(res
) > 0)
2683 conn
->server_encoding
=
2684 strdup(QR_get_value_backend_text(res
, 0, 0));
2689 if (!conn
->server_encoding
)
2691 snprintf(query
, sizeof(query
), "SET CLIENT_ENCODING TO '%s'",
2692 conn
->server_encoding
);
2694 (!QR_command_maybe_successful
2695 ((res
= CC_send_query(conn
, query
, NULL
, flag
, NULL
))));
2697 if (!bError
&& continueExec
)
2699 snprintf(query
, sizeof(query
),
2700 "select attnum from pg_attribute "
2701 "where attrelid = %u and attname = '%s'", relid
,
2704 CC_send_query(conn
, query
, NULL
, flag
, NULL
),
2705 QR_command_maybe_successful(res
))
2707 if (QR_get_num_cached_tuples(res
) > 0)
2710 QR_get_value_backend_text(res
, 0, 0));
2713 continueExec
= FALSE
;
2719 continueExec
= (continueExec
&& !bError
);
2720 /* restore the cleint encoding */
2721 snprintf(query
, sizeof(query
), "SET CLIENT_ENCODING TO '%s'",
2722 conn
->original_client_encoding
);
2724 (!QR_command_maybe_successful
2725 ((res
= CC_send_query(conn
, query
, NULL
, flag
, NULL
))));
2727 if (bError
|| !continueExec
)
2729 snprintf(query
, sizeof(query
),
2730 "select attname from pg_attribute where attrelid = %u and attnum = %s",
2733 CC_send_query(conn
, query
, NULL
, flag
, NULL
),
2734 QR_command_maybe_successful(res
))
2736 if (QR_get_num_cached_tuples(res
) > 0)
2738 ret
= strdup(QR_get_value_backend_text(res
, 0, 0));
2739 *nameAlloced
= TRUE
;
2746 RETCODE SQL_API
PGAPI_ForeignKeys(HSTMT hstmt
, const SQLCHAR FAR
* szPkTableQualifier
, /* OA X */
2747 SQLSMALLINT cbPkTableQualifier
, const SQLCHAR FAR
* szPkTableOwner
, /* OA E */
2748 SQLSMALLINT cbPkTableOwner
, const SQLCHAR FAR
* szPkTableName
, /* OA(R) E */
2749 SQLSMALLINT cbPkTableName
, const SQLCHAR FAR
* szFkTableQualifier
, /* OA X */
2750 SQLSMALLINT cbFkTableQualifier
, const SQLCHAR FAR
* szFkTableOwner
, /* OA E */
2751 SQLSMALLINT cbFkTableOwner
, const SQLCHAR FAR
* szFkTableName
, /* OA(R) E */
2752 SQLSMALLINT cbFkTableName
)
2754 CSTR func
= "PGAPI_ForeignKeys";
2755 StatementClass
*stmt
= (StatementClass
*) hstmt
;
2758 HSTMT htbl_stmt
= NULL
, hpkey_stmt
= NULL
;
2759 StatementClass
*tbl_stmt
;
2760 RETCODE ret
= SQL_ERROR
, result
, keyresult
;
2761 char tables_query
[INFO_INQUIRY_LEN
];
2762 char trig_deferrable
[2];
2763 char trig_initdeferred
[2];
2764 char trig_args
[1024];
2765 char upd_rule
[TABLE_NAME_STORAGE_LEN
],
2766 del_rule
[TABLE_NAME_STORAGE_LEN
];
2767 char *pk_table_needed
= NULL
, *escPkTableName
= NULL
;
2768 char fk_table_fetched
[TABLE_NAME_STORAGE_LEN
+ 1];
2769 char *fk_table_needed
= NULL
, *escFkTableName
= NULL
;
2770 char pk_table_fetched
[TABLE_NAME_STORAGE_LEN
+ 1];
2771 char schema_needed
[SCHEMA_NAME_STORAGE_LEN
+ 1];
2772 char schema_fetched
[SCHEMA_NAME_STORAGE_LEN
+ 1];
2773 char constrname
[NAMESTORAGELEN
+ 1],
2774 pkname
[TABLE_NAME_STORAGE_LEN
+ 1];
2775 char *pkey_ptr
, *pkey_text
= NULL
, *fkey_ptr
, *fkey_text
= NULL
;
2777 ConnectionClass
*conn
;
2778 BOOL pkey_alloced
, fkey_alloced
, got_pkname
;
2779 int i
, j
, k
, num_keys
;
2780 SQLSMALLINT trig_nargs
, upd_rule_type
= 0, del_rule_type
= 0;
2781 SQLSMALLINT internal_asis_type
= SQL_C_CHAR
;
2783 SQLSMALLINT defer_type
;
2784 char pkey
[MAX_INFO_STRING
];
2786 UInt4 relid1
, relid2
;
2788 mylog("%s: entering...stmt=%p\n", func
, stmt
);
2790 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
2793 if (res
= QR_Constructor(), !res
)
2795 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
2796 "Couldn't allocate memory for PGAPI_ForeignKeys result.",
2800 SC_set_Result(stmt
, res
);
2802 /* the binding structure for a statement is not set up until */
2805 * a statement is actually executed, so we'll have to do this
2808 result_cols
= NUM_OF_FKS_FIELDS
;
2809 extend_column_bindings(SC_get_ARDF(stmt
), result_cols
);
2811 stmt
->catalog_result
= TRUE
;
2812 /* set the field names */
2813 QR_set_num_fields(res
, result_cols
);
2814 QR_set_field_info_v(res
, FKS_PKTABLE_CAT
, "PKTABLE_QUALIFIER",
2815 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2816 QR_set_field_info_v(res
, FKS_PKTABLE_SCHEM
, "PKTABLE_OWNER",
2817 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2818 QR_set_field_info_v(res
, FKS_PKTABLE_NAME
, "PKTABLE_NAME",
2819 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2820 QR_set_field_info_v(res
, FKS_PKCOLUMN_NAME
, "PKCOLUMN_NAME",
2821 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2822 QR_set_field_info_v(res
, FKS_FKTABLE_CAT
, "FKTABLE_QUALIFIER",
2823 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2824 QR_set_field_info_v(res
, FKS_FKTABLE_SCHEM
, "FKTABLE_OWNER",
2825 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2826 QR_set_field_info_v(res
, FKS_FKTABLE_NAME
, "FKTABLE_NAME",
2827 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2828 QR_set_field_info_v(res
, FKS_FKCOLUMN_NAME
, "FKCOLUMN_NAME",
2829 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2830 QR_set_field_info_v(res
, FKS_KEY_SEQ
, "KEY_SEQ", PG_TYPE_INT2
, 2);
2831 QR_set_field_info_v(res
, FKS_UPDATE_RULE
, "UPDATE_RULE",
2833 QR_set_field_info_v(res
, FKS_DELETE_RULE
, "DELETE_RULE",
2835 QR_set_field_info_v(res
, FKS_FK_NAME
, "FK_NAME", PG_TYPE_VARCHAR
,
2837 QR_set_field_info_v(res
, FKS_PK_NAME
, "PK_NAME", PG_TYPE_VARCHAR
,
2839 QR_set_field_info_v(res
, FKS_DEFERRABILITY
, "DEFERRABILITY",
2841 QR_set_field_info_v(res
, FKS_TRIGGER_NAME
, "TRIGGER_NAME",
2842 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2845 * also, things need to think that this statement is finished so the
2846 * results can be retrieved.
2848 stmt
->status
= STMT_FINISHED
;
2850 /* set up the current tuple pointer for SQLFetch */
2851 stmt
->currTuple
= -1;
2852 SC_set_rowset_start(stmt
, -1, FALSE
);
2853 SC_set_current_col(stmt
, -1);
2855 conn
= SC_get_conn(stmt
);
2856 result
= PGAPI_AllocStmt(conn
, &htbl_stmt
);
2857 if (!SQL_SUCCEEDED(result
))
2859 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
2860 "Couldn't allocate statement for PGAPI_ForeignKeys result.",
2864 #define return DONT_CALL_RETURN_FROM_HERE???
2866 tbl_stmt
= (StatementClass
*) htbl_stmt
;
2867 schema_needed
[0] = '\0';
2868 schema_fetched
[0] = '\0';
2871 make_string(szPkTableName
, cbPkTableName
, NULL
, 0);
2873 make_string(szFkTableName
, cbFkTableName
, NULL
, 0);
2875 #ifdef UNICODE_SUPPORT
2876 if (CC_is_in_unicode_driver(conn
))
2877 internal_asis_type
= INTERNAL_ASIS_TYPE
;
2878 #endif /* UNICODE_SUPPORT */
2879 pkey_alloced
= fkey_alloced
= FALSE
;
2882 * Case #2 -- Get the foreign keys in the specified table (fktab) that
2883 * refer to the primary keys of other table(s).
2885 if (fk_table_needed
&& fk_table_needed
[0] != '\0')
2887 mylog("%s: entering Foreign Key Case #2", func
);
2889 simpleCatalogEscape(fk_table_needed
, SQL_NTS
, NULL
, conn
);
2890 if (conn
->schema_support
)
2892 char *escSchemaName
;
2894 schema_strcat(schema_needed
, "%.*s", (const char *)szFkTableOwner
,
2895 cbFkTableOwner
, (const char *)szFkTableName
,
2896 cbFkTableName
, conn
);
2898 simpleCatalogEscape(schema_needed
, SQL_NTS
, NULL
, conn
);
2899 snprintf(tables_query
, sizeof(tables_query
),
2900 "SELECT pt.tgargs, "
2902 " pt.tgdeferrable, "
2903 " pt.tginitdeferred, "
2909 " pt.tgconstrname, pn.nspname "
2910 "FROM pg_catalog.pg_class pc, "
2911 " pg_catalog.pg_proc pp1, "
2912 " pg_catalog.pg_proc pp2, "
2913 " pg_catalog.pg_trigger pt1, "
2914 " pg_catalog.pg_trigger pt2, "
2915 " pg_catalog.pg_proc pp, "
2916 " pg_catalog.pg_trigger pt, "
2917 " pg_catalog.pg_class pc1, "
2918 " pg_catalog.pg_namespace pn, "
2919 " pg_catalog.pg_namespace pn1 "
2920 "WHERE pt.tgrelid = pc.oid "
2921 "AND pp.oid = pt.tgfoid "
2922 "AND pt1.tgconstrrelid = pc.oid "
2923 "AND pp1.oid = pt1.tgfoid "
2924 "AND pt2.tgfoid = pp2.oid "
2925 "AND pt2.tgconstrrelid = pc.oid "
2926 "AND ((pc.relname='%s') "
2927 "AND (pn1.oid = pc.relnamespace) "
2928 "AND (pn1.nspname = '%s') "
2929 "AND (pp.proname LIKE '%%ins') "
2930 "AND (pp1.proname LIKE '%%upd') "
2931 "AND (pp1.proname not LIKE '%%check%%') "
2932 "AND (pp2.proname LIKE '%%del') "
2933 "AND (pt1.tgrelid=pt.tgconstrrelid) "
2934 "AND (pt1.tgconstrname=pt.tgconstrname) "
2935 "AND (pt2.tgrelid=pt.tgconstrrelid) "
2936 "AND (pt2.tgconstrname=pt.tgconstrname) "
2937 "AND (pt.tgconstrrelid=pc1.oid) "
2938 "AND (pc1.relnamespace=pn.oid))"
2939 " order by pt.tgconstrname",
2940 escFkTableName
, escSchemaName
);
2941 free(escSchemaName
);
2944 snprintf(tables_query
, sizeof(tables_query
),
2945 "SELECT pt.tgargs, "
2947 " pt.tgdeferrable, "
2948 " pt.tginitdeferred, "
2953 " pc1.relname, pt.tgconstrname "
2954 "FROM pg_class pc, "
2962 "WHERE pt.tgrelid = pc.oid "
2963 "AND pp.oid = pt.tgfoid "
2964 "AND pt1.tgconstrrelid = pc.oid "
2965 "AND pp1.oid = pt1.tgfoid "
2966 "AND pt2.tgfoid = pp2.oid "
2967 "AND pt2.tgconstrrelid = pc.oid "
2968 "AND ((pc.relname='%s') "
2969 "AND (pp.proname LIKE '%%ins') "
2970 "AND (pp1.proname LIKE '%%upd') "
2971 "AND (pp1.proname not LIKE '%%check%%') "
2972 "AND (pp2.proname LIKE '%%del') "
2973 "AND (pt1.tgrelid=pt.tgconstrrelid) "
2974 "AND (pt1.tgconstrname=pt.tgconstrname) "
2975 "AND (pt2.tgrelid=pt.tgconstrrelid) "
2976 "AND (pt2.tgconstrname=pt.tgconstrname) "
2977 "AND (pt.tgconstrrelid=pc1.oid)) "
2978 "order by pt.tgconstrname", escFkTableName
);
2980 result
= PGAPI_ExecDirect(htbl_stmt
,
2981 (const UCHAR
*)tables_query
, SQL_NTS
, 0);
2983 if (!SQL_SUCCEEDED(result
))
2985 SC_full_error_copy(stmt
, tbl_stmt
, FALSE
);
2989 result
= PGAPI_BindCol(htbl_stmt
, 1, SQL_C_BINARY
,
2990 trig_args
, sizeof(trig_args
), NULL
);
2991 if (!SQL_SUCCEEDED(result
))
2993 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
2997 result
= PGAPI_BindCol(htbl_stmt
, 2, SQL_C_SHORT
,
2998 &trig_nargs
, 0, NULL
);
2999 if (!SQL_SUCCEEDED(result
))
3001 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3005 result
= PGAPI_BindCol(htbl_stmt
, 3, internal_asis_type
,
3006 trig_deferrable
, sizeof(trig_deferrable
),
3008 if (!SQL_SUCCEEDED(result
))
3010 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3014 result
= PGAPI_BindCol(htbl_stmt
, 4, internal_asis_type
,
3016 sizeof(trig_initdeferred
), NULL
);
3017 if (!SQL_SUCCEEDED(result
))
3019 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3023 result
= PGAPI_BindCol(htbl_stmt
, 5, internal_asis_type
,
3024 upd_rule
, sizeof(upd_rule
), NULL
);
3025 if (!SQL_SUCCEEDED(result
))
3027 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3031 result
= PGAPI_BindCol(htbl_stmt
, 6, internal_asis_type
,
3032 del_rule
, sizeof(del_rule
), NULL
);
3033 if (!SQL_SUCCEEDED(result
))
3035 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3039 result
= PGAPI_BindCol(htbl_stmt
, 7, SQL_C_ULONG
,
3040 &relid1
, sizeof(relid1
), NULL
);
3041 if (!SQL_SUCCEEDED(result
))
3043 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3046 result
= PGAPI_BindCol(htbl_stmt
, 8, SQL_C_ULONG
,
3047 &relid2
, sizeof(relid2
), NULL
);
3048 if (!SQL_SUCCEEDED(result
))
3050 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3053 result
= PGAPI_BindCol(htbl_stmt
, 9, internal_asis_type
,
3054 pk_table_fetched
, TABLE_NAME_STORAGE_LEN
,
3056 if (!SQL_SUCCEEDED(result
))
3058 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3061 result
= PGAPI_BindCol(htbl_stmt
, 10, internal_asis_type
,
3062 constrname
, NAMESTORAGELEN
, NULL
);
3063 if (!SQL_SUCCEEDED(result
))
3065 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3069 if (conn
->schema_support
)
3071 result
= PGAPI_BindCol(htbl_stmt
, 11, internal_asis_type
,
3073 SCHEMA_NAME_STORAGE_LEN
, NULL
);
3074 if (!SQL_SUCCEEDED(result
))
3076 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3081 result
= PGAPI_Fetch(htbl_stmt
);
3082 if (result
== SQL_NO_DATA_FOUND
)
3088 if (result
!= SQL_SUCCESS
)
3090 SC_full_error_copy(stmt
, tbl_stmt
, FALSE
);
3094 keyresult
= PGAPI_AllocStmt(conn
, &hpkey_stmt
);
3095 if (!SQL_SUCCEEDED(keyresult
))
3097 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
3098 "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.",
3103 keyresult
= PGAPI_BindCol(hpkey_stmt
, 4, internal_asis_type
,
3104 pkey
, sizeof(pkey
), NULL
);
3105 if (keyresult
!= SQL_SUCCESS
)
3107 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
3108 "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.",
3113 while (result
== SQL_SUCCESS
)
3115 /* Compute the number of keyparts. */
3116 num_keys
= (trig_nargs
- 4) / 2;
3119 ("Foreign Key Case#2: trig_nargs = %d, num_keys = %d\n",
3120 trig_nargs
, num_keys
);
3122 /* If there is a pk table specified, then check it. */
3123 if (pk_table_needed
&& pk_table_needed
[0] != '\0')
3125 /* If it doesn't match, then continue */
3126 if (strcmp(pk_table_fetched
, pk_table_needed
))
3128 result
= PGAPI_Fetch(htbl_stmt
);
3135 PGAPI_PrimaryKeys(hpkey_stmt
, NULL
, 0,
3136 (const UCHAR
*)schema_fetched
,
3137 SQL_NTS
, (const UCHAR
*)pk_table_fetched
,
3139 if (keyresult
!= SQL_SUCCESS
)
3141 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
3142 "Couldn't get primary keys for PGAPI_ForeignKeys result.",
3147 /* Get to first primary key */
3148 pkey_ptr
= trig_args
;
3149 for (i
= 0; i
< 5; i
++)
3150 pkey_ptr
+= strlen(pkey_ptr
) + 1;
3152 for (k
= 0; k
< num_keys
; k
++)
3154 /* Check that the key listed is the primary key */
3155 keyresult
= PGAPI_Fetch(hpkey_stmt
);
3156 if (keyresult
!= SQL_SUCCESS
)
3163 PGAPI_GetData(hpkey_stmt
, 6, internal_asis_type
,
3164 pkname
, sizeof(pkname
), NULL
);
3168 getClientColumnName(conn
, relid2
, pkey_ptr
,
3170 mylog("%s: pkey_ptr='%s', pkey='%s'\n", func
, pkey_text
,
3172 if (strcmp(pkey_text
, pkey
))
3179 /* Get to next primary key */
3180 for (k
= 0; k
< 2; k
++)
3181 pkey_ptr
+= strlen(pkey_ptr
) + 1;
3184 PGAPI_FreeStmt(hpkey_stmt
, SQL_CLOSE
);
3186 /* Set to first fk column */
3187 fkey_ptr
= trig_args
;
3188 for (k
= 0; k
< 4; k
++)
3189 fkey_ptr
+= strlen(fkey_ptr
) + 1;
3191 /* Set update and delete actions for foreign keys */
3192 if (!strcmp(upd_rule
, "RI_FKey_cascade_upd"))
3193 upd_rule_type
= SQL_CASCADE
;
3194 else if (!strcmp(upd_rule
, "RI_FKey_noaction_upd"))
3195 upd_rule_type
= SQL_NO_ACTION
;
3196 else if (!strcmp(upd_rule
, "RI_FKey_restrict_upd"))
3197 upd_rule_type
= SQL_NO_ACTION
;
3198 else if (!strcmp(upd_rule
, "RI_FKey_setdefault_upd"))
3199 upd_rule_type
= SQL_SET_DEFAULT
;
3200 else if (!strcmp(upd_rule
, "RI_FKey_setnull_upd"))
3201 upd_rule_type
= SQL_SET_NULL
;
3203 if (!strcmp(del_rule
, "RI_FKey_cascade_del"))
3204 del_rule_type
= SQL_CASCADE
;
3205 else if (!strcmp(del_rule
, "RI_FKey_noaction_del"))
3206 del_rule_type
= SQL_NO_ACTION
;
3207 else if (!strcmp(del_rule
, "RI_FKey_restrict_del"))
3208 del_rule_type
= SQL_NO_ACTION
;
3209 else if (!strcmp(del_rule
, "RI_FKey_setdefault_del"))
3210 del_rule_type
= SQL_SET_DEFAULT
;
3211 else if (!strcmp(del_rule
, "RI_FKey_setnull_del"))
3212 del_rule_type
= SQL_SET_NULL
;
3214 /* Set deferrability type */
3215 if (!strcmp(trig_initdeferred
, "y"))
3216 defer_type
= SQL_INITIALLY_DEFERRED
;
3217 else if (!strcmp(trig_deferrable
, "y"))
3218 defer_type
= SQL_INITIALLY_IMMEDIATE
;
3220 defer_type
= SQL_NOT_DEFERRABLE
;
3222 /* Get to first primary key */
3223 pkey_ptr
= trig_args
;
3224 for (i
= 0; i
< 5; i
++)
3225 pkey_ptr
+= strlen(pkey_ptr
) + 1;
3227 for (k
= 0; k
< num_keys
; k
++)
3229 tuple
= QR_AddNew(res
);
3232 getClientColumnName(conn
, relid2
, pkey_ptr
,
3235 getClientColumnName(conn
, relid1
, fkey_ptr
,
3238 mylog("%s: pk_table = '%s', pkey_ptr = '%s'\n", func
,
3239 pk_table_fetched
, pkey_text
);
3240 set_tuplefield_string(&tuple
[FKS_PKTABLE_CAT
],
3242 set_tuplefield_string(&tuple
[FKS_PKTABLE_SCHEM
],
3243 GET_SCHEMA_NAME(schema_fetched
));
3244 set_tuplefield_string(&tuple
[FKS_PKTABLE_NAME
],
3246 set_tuplefield_string(&tuple
[FKS_PKCOLUMN_NAME
],
3249 mylog("%s: fk_table_needed = '%s', fkey_ptr = '%s'\n",
3250 func
, fk_table_needed
, fkey_text
);
3251 set_tuplefield_null(&tuple
[FKS_FKTABLE_CAT
]);
3252 set_tuplefield_string(&tuple
[FKS_FKTABLE_SCHEM
],
3253 GET_SCHEMA_NAME(schema_needed
));
3254 set_tuplefield_string(&tuple
[FKS_FKTABLE_NAME
],
3256 set_tuplefield_string(&tuple
[FKS_FKCOLUMN_NAME
],
3260 ("%s: upd_rule_type = '%i', del_rule_type = '%i'\n, trig_name = '%s'",
3261 func
, upd_rule_type
, del_rule_type
, trig_args
);
3262 set_tuplefield_int2(&tuple
[FKS_KEY_SEQ
],
3264 set_tuplefield_int2(&tuple
[FKS_UPDATE_RULE
],
3266 set_tuplefield_int2(&tuple
[FKS_DELETE_RULE
],
3268 set_tuplefield_string(&tuple
[FKS_FK_NAME
], constrname
);
3269 set_tuplefield_string(&tuple
[FKS_PK_NAME
], pkname
);
3270 set_tuplefield_int2(&tuple
[FKS_DEFERRABILITY
],
3272 set_tuplefield_string(&tuple
[FKS_TRIGGER_NAME
],
3277 fkey_alloced
= FALSE
;
3280 pkey_alloced
= FALSE
;
3281 /* next primary/foreign key */
3282 for (i
= 0; i
< 2; i
++)
3284 fkey_ptr
+= strlen(fkey_ptr
) + 1;
3285 pkey_ptr
+= strlen(pkey_ptr
) + 1;
3289 result
= PGAPI_Fetch(htbl_stmt
);
3294 * Case #1 -- Get the foreign keys in other tables that refer to the
3295 * primary key in the specified table (pktab). i.e., Who points to
3298 else if (pk_table_needed
[0] != '\0')
3301 simpleCatalogEscape(pk_table_needed
, SQL_NTS
, NULL
, conn
);
3302 if (conn
->schema_support
)
3304 char *escSchemaName
;
3306 schema_strcat(schema_needed
, "%.*s",
3307 (const char *)szPkTableOwner
,
3308 cbPkTableOwner
, (const char *)szPkTableName
,
3309 cbPkTableName
, conn
);
3311 simpleCatalogEscape(schema_needed
, SQL_NTS
, NULL
, conn
);
3312 snprintf(tables_query
, sizeof(tables_query
),
3313 "SELECT pt.tgargs, " " pt.tgnargs, "
3314 " pt.tgdeferrable, "
3315 " pt.tginitdeferred, " " pp1.proname, "
3320 " pt.tgconstrname, pn1.nspname "
3321 "FROM pg_catalog.pg_class pc, "
3322 " pg_catalog.pg_class pc1, "
3323 " pg_catalog.pg_proc pp, "
3324 " pg_catalog.pg_proc pp1, "
3325 " pg_catalog.pg_proc pp2, "
3326 " pg_catalog.pg_trigger pt, "
3327 " pg_catalog.pg_trigger pt1, "
3328 " pg_catalog.pg_trigger pt2, "
3329 " pg_catalog.pg_namespace pn, "
3330 " pg_catalog.pg_namespace pn1 "
3331 "WHERE pc.relname='%s' "
3332 " AND pn.nspname = '%s' "
3333 " AND pc.relnamespace = pn.oid "
3334 " AND pt.tgconstrrelid = pc.oid "
3335 " AND pp.oid = pt.tgfoid "
3336 " AND pp.proname Like '%%ins' "
3337 " AND pt1.tgconstrname = pt.tgconstrname "
3338 " AND pt1.tgconstrrelid = pt.tgrelid "
3339 " AND pt1.tgrelid = pc.oid "
3340 " AND pc1.oid = pt.tgrelid "
3341 " AND pp1.oid = pt1.tgfoid "
3342 " AND pp1.proname like '%%upd' "
3343 " AND (pp1.proname not like '%%check%%') "
3344 " AND pt2.tgconstrname = pt.tgconstrname "
3345 " AND pt2.tgconstrrelid = pt.tgrelid "
3346 " AND pt2.tgrelid = pc.oid "
3347 " AND pp2.oid = pt2.tgfoid "
3348 " AND pp2.proname Like '%%del' "
3349 " AND pn1.oid = pc1.relnamespace "
3350 " order by pt.tgconstrname",
3351 escPkTableName
, escSchemaName
);
3352 free(escSchemaName
);
3355 snprintf(tables_query
, sizeof(tables_query
),
3356 "SELECT pt.tgargs, " " pt.tgnargs, "
3357 " pt.tgdeferrable, "
3358 " pt.tginitdeferred, " " pp1.proname, "
3362 " pc1.relname, pt.tgconstrname "
3363 "FROM pg_class pc, "
3371 "WHERE pc.relname ='%s' "
3372 " AND pt.tgconstrrelid = pc.oid "
3373 " AND pp.oid = pt.tgfoid "
3374 " AND pp.proname Like '%%ins' "
3375 " AND pt1.tgconstrname = pt.tgconstrname "
3376 " AND pt1.tgconstrrelid = pt.tgrelid "
3377 " AND pt1.tgrelid = pc.oid "
3378 " AND pc1.oid = pt.tgrelid "
3379 " AND pp1.oid = pt1.tgfoid "
3380 " AND pp1.proname like '%%upd' "
3381 " AND pp1.(proname not like '%%check%%') "
3382 " AND pt2.tgconstrname = pt.tgconstrname "
3383 " AND pt2.tgconstrrelid = pt.tgrelid "
3384 " AND pt2.tgrelid = pc.oid "
3385 " AND pp2.oid = pt2.tgfoid "
3386 " AND pp2.proname Like '%%del'"
3387 " order by pt.tgconstrname", escPkTableName
);
3389 result
= PGAPI_ExecDirect(htbl_stmt
, (const UCHAR
*)tables_query
,
3391 if (!SQL_SUCCEEDED(result
))
3393 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3397 result
= PGAPI_BindCol(htbl_stmt
, 1, SQL_C_BINARY
,
3398 trig_args
, sizeof(trig_args
), NULL
);
3399 if (!SQL_SUCCEEDED(result
))
3401 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3405 result
= PGAPI_BindCol(htbl_stmt
, 2, SQL_C_SHORT
,
3406 &trig_nargs
, 0, NULL
);
3407 if (!SQL_SUCCEEDED(result
))
3409 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3413 result
= PGAPI_BindCol(htbl_stmt
, 3, internal_asis_type
,
3414 trig_deferrable
, sizeof(trig_deferrable
),
3416 if (!SQL_SUCCEEDED(result
))
3418 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3422 result
= PGAPI_BindCol(htbl_stmt
, 4, internal_asis_type
,
3424 sizeof(trig_initdeferred
), NULL
);
3425 if (!SQL_SUCCEEDED(result
))
3427 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3431 result
= PGAPI_BindCol(htbl_stmt
, 5, internal_asis_type
,
3432 upd_rule
, sizeof(upd_rule
), NULL
);
3433 if (!SQL_SUCCEEDED(result
))
3435 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3439 result
= PGAPI_BindCol(htbl_stmt
, 6, internal_asis_type
,
3440 del_rule
, sizeof(del_rule
), NULL
);
3441 if (!SQL_SUCCEEDED(result
))
3443 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3447 result
= PGAPI_BindCol(htbl_stmt
, 7, SQL_C_ULONG
,
3448 &relid1
, sizeof(relid1
), NULL
);
3449 if (!SQL_SUCCEEDED(result
))
3451 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3454 result
= PGAPI_BindCol(htbl_stmt
, 8, SQL_C_ULONG
,
3455 &relid2
, sizeof(relid2
), NULL
);
3456 if (!SQL_SUCCEEDED(result
))
3458 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3461 result
= PGAPI_BindCol(htbl_stmt
, 9, internal_asis_type
,
3462 fk_table_fetched
, TABLE_NAME_STORAGE_LEN
,
3464 if (!SQL_SUCCEEDED(result
))
3466 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3469 result
= PGAPI_BindCol(htbl_stmt
, 10, internal_asis_type
,
3470 constrname
, NAMESTORAGELEN
, NULL
);
3471 if (!SQL_SUCCEEDED(result
))
3473 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3477 if (conn
->schema_support
)
3479 result
= PGAPI_BindCol(htbl_stmt
, 11, internal_asis_type
,
3481 SCHEMA_NAME_STORAGE_LEN
, NULL
);
3482 if (!SQL_SUCCEEDED(result
))
3484 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3489 result
= PGAPI_Fetch(htbl_stmt
);
3490 if (result
== SQL_NO_DATA_FOUND
)
3496 if (result
!= SQL_SUCCESS
)
3498 SC_full_error_copy(stmt
, tbl_stmt
, FALSE
);
3505 keyresult
= PGAPI_AllocStmt(conn
, &hpkey_stmt
);
3506 if (!SQL_SUCCEEDED(keyresult
))
3508 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
3509 "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.",
3513 keyresult
= PGAPI_BindCol(hpkey_stmt
, 6, internal_asis_type
,
3514 pkname
, sizeof(pkname
), NULL
);
3515 if (keyresult
!= SQL_SUCCESS
)
3517 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
3518 "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.",
3523 PGAPI_PrimaryKeys(hpkey_stmt
, NULL
, 0,
3524 (const UCHAR
*)schema_needed
,
3525 SQL_NTS
, (const UCHAR
*)pk_table_needed
,
3527 if (keyresult
!= SQL_SUCCESS
)
3529 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
3530 "Couldn't get primary keys for PGAPI_ForeignKeys result.",
3535 keyresult
= PGAPI_Fetch(hpkey_stmt
);
3536 PGAPI_FreeStmt(hpkey_stmt
, SQL_CLOSE
);
3537 while (result
== SQL_SUCCESS
)
3539 /* Calculate the number of key parts */
3540 num_keys
= (trig_nargs
- 4) / 2;;
3542 /* Handle action (i.e., 'cascade', 'restrict', 'setnull') */
3543 if (!strcmp(upd_rule
, "RI_FKey_cascade_upd"))
3544 upd_rule_type
= SQL_CASCADE
;
3545 else if (!strcmp(upd_rule
, "RI_FKey_noaction_upd"))
3546 upd_rule_type
= SQL_NO_ACTION
;
3547 else if (!strcmp(upd_rule
, "RI_FKey_restrict_upd"))
3548 upd_rule_type
= SQL_NO_ACTION
;
3549 else if (!strcmp(upd_rule
, "RI_FKey_setdefault_upd"))
3550 upd_rule_type
= SQL_SET_DEFAULT
;
3551 else if (!strcmp(upd_rule
, "RI_FKey_setnull_upd"))
3552 upd_rule_type
= SQL_SET_NULL
;
3554 if (!strcmp(del_rule
, "RI_FKey_cascade_del"))
3555 del_rule_type
= SQL_CASCADE
;
3556 else if (!strcmp(del_rule
, "RI_FKey_noaction_del"))
3557 del_rule_type
= SQL_NO_ACTION
;
3558 else if (!strcmp(del_rule
, "RI_FKey_restrict_del"))
3559 del_rule_type
= SQL_NO_ACTION
;
3560 else if (!strcmp(del_rule
, "RI_FKey_setdefault_del"))
3561 del_rule_type
= SQL_SET_DEFAULT
;
3562 else if (!strcmp(del_rule
, "RI_FKey_setnull_del"))
3563 del_rule_type
= SQL_SET_NULL
;
3565 /* Set deferrability type */
3566 if (!strcmp(trig_initdeferred
, "y"))
3567 defer_type
= SQL_INITIALLY_DEFERRED
;
3568 else if (!strcmp(trig_deferrable
, "y"))
3569 defer_type
= SQL_INITIALLY_IMMEDIATE
;
3571 defer_type
= SQL_NOT_DEFERRABLE
;
3574 ("Foreign Key Case#1: trig_nargs = %d, num_keys = %d\n",
3575 trig_nargs
, num_keys
);
3577 /* Get to first primary key */
3578 pkey_ptr
= trig_args
;
3579 for (i
= 0; i
< 5; i
++)
3580 pkey_ptr
+= strlen(pkey_ptr
) + 1;
3582 /* Get to first foreign key */
3583 fkey_ptr
= trig_args
;
3584 for (k
= 0; k
< 4; k
++)
3585 fkey_ptr
+= strlen(fkey_ptr
) + 1;
3587 for (k
= 0; k
< num_keys
; k
++)
3590 getClientColumnName(conn
, relid1
, pkey_ptr
,
3593 getClientColumnName(conn
, relid2
, fkey_ptr
,
3597 ("pkey_ptr = '%s', fk_table = '%s', fkey_ptr = '%s'\n",
3598 pkey_text
, fk_table_fetched
, fkey_text
);
3600 tuple
= QR_AddNew(res
);
3602 mylog("pk_table_needed = '%s', pkey_ptr = '%s'\n",
3603 pk_table_needed
, pkey_text
);
3604 set_tuplefield_string(&tuple
[FKS_PKTABLE_CAT
],
3606 set_tuplefield_string(&tuple
[FKS_PKTABLE_SCHEM
],
3607 GET_SCHEMA_NAME(schema_needed
));
3608 set_tuplefield_string(&tuple
[FKS_PKTABLE_NAME
],
3610 set_tuplefield_string(&tuple
[FKS_PKCOLUMN_NAME
],
3613 mylog("fk_table = '%s', fkey_ptr = '%s'\n",
3614 fk_table_fetched
, fkey_text
);
3615 set_tuplefield_null(&tuple
[FKS_FKTABLE_CAT
]);
3616 set_tuplefield_string(&tuple
[FKS_FKTABLE_SCHEM
],
3617 GET_SCHEMA_NAME(schema_fetched
));
3618 set_tuplefield_string(&tuple
[FKS_FKTABLE_NAME
],
3620 set_tuplefield_string(&tuple
[FKS_FKCOLUMN_NAME
],
3623 set_tuplefield_int2(&tuple
[FKS_KEY_SEQ
],
3626 mylog("upd_rule = %d, del_rule= %d", upd_rule_type
,
3628 set_nullfield_int2(&tuple
[FKS_UPDATE_RULE
],
3630 set_nullfield_int2(&tuple
[FKS_DELETE_RULE
],
3633 set_tuplefield_string(&tuple
[FKS_FK_NAME
], constrname
);
3634 set_tuplefield_string(&tuple
[FKS_PK_NAME
], pkname
);
3636 set_tuplefield_string(&tuple
[FKS_TRIGGER_NAME
],
3639 mylog(" defer_type = %d\n", defer_type
);
3640 set_tuplefield_int2(&tuple
[FKS_DEFERRABILITY
],
3645 pkey_alloced
= FALSE
;
3648 fkey_alloced
= FALSE
;
3650 /* next primary/foreign key */
3651 for (j
= 0; j
< 2; j
++)
3653 pkey_ptr
+= strlen(pkey_ptr
) + 1;
3654 fkey_ptr
+= strlen(fkey_ptr
) + 1;
3657 result
= PGAPI_Fetch(htbl_stmt
);
3662 SC_set_error(stmt
, STMT_INTERNAL_ERROR
,
3663 "No tables specified to PGAPI_ForeignKeys.", func
);
3671 * also, things need to think that this statement is finished so the
3672 * results can be retrieved.
3674 stmt
->status
= STMT_FINISHED
;
3680 if (pk_table_needed
)
3681 free(pk_table_needed
);
3683 free(escPkTableName
);
3684 if (fk_table_needed
)
3685 free(fk_table_needed
);
3687 free(escFkTableName
);
3690 PGAPI_FreeStmt(htbl_stmt
, SQL_DROP
);
3692 PGAPI_FreeStmt(hpkey_stmt
, SQL_DROP
);
3694 /* set up the current tuple pointer for SQLFetch */
3695 stmt
->currTuple
= -1;
3696 SC_set_rowset_start(stmt
, -1, FALSE
);
3697 SC_set_current_col(stmt
, -1);
3700 ret
= DiscardStatementSvp(stmt
, ret
, FALSE
);
3701 mylog("%s(): EXIT, stmt=%p, ret=%d\n", func
, stmt
, ret
);
3705 RETCODE SQL_API
PGAPI_ProcedureColumns(HSTMT hstmt
, const SQLCHAR FAR
* szProcQualifier
, /* OA X */
3706 SQLSMALLINT cbProcQualifier
, const SQLCHAR FAR
* szProcOwner
, /* PV E */
3707 SQLSMALLINT cbProcOwner
, const SQLCHAR FAR
* szProcName
, /* PV E */
3708 SQLSMALLINT cbProcName
, const SQLCHAR FAR
* szColumnName
, /* PV X */
3709 SQLSMALLINT cbColumnName
,
3712 CSTR func
= "PGAPI_ProcedureColumns";
3713 StatementClass
*stmt
= (StatementClass
*) hstmt
;
3714 ConnectionClass
*conn
= SC_get_conn(stmt
);
3715 char proc_query
[INFO_INQUIRY_LEN
];
3718 const char *schema_name
, *procname
;
3719 char *escSchemaName
= NULL
, *escProcName
= NULL
;
3720 char *params
, *delim
= NULL
;
3721 char *atttypid
, *proargnames
, *proargmodes
;
3722 char *attname
, *column_name
;
3723 QResultClass
*res
, *tres
;
3726 Int4 paramcount
, i
, j
;
3728 BOOL search_pattern
, bRetset
;
3729 const char *like_or_eq
, *retset
;
3730 int ret_col
= -1, ext_pos
= -1, poid_pos
= -1, attid_pos
=
3731 -1, attname_pos
= -1;
3732 UInt4 poid
= 0, newpoid
;
3734 mylog("%s: entering...\n", func
);
3736 if (PG_VERSION_LT(conn
, 6.5))
3738 SC_set_error(stmt
, STMT_NOT_IMPLEMENTED_ERROR
,
3739 "Version is too old", func
);
3742 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
3744 search_pattern
= (0 == (flag
& PODBC_NOT_SEARCH_PATTERN
));
3747 like_or_eq
= likeop
;
3749 adjustLikePattern(szProcOwner
, cbProcOwner
,
3750 SEARCH_PATTERN_ESCAPE
, NULL
, conn
);
3752 adjustLikePattern(szProcName
, cbProcName
,
3753 SEARCH_PATTERN_ESCAPE
, NULL
, conn
);
3759 simpleCatalogEscape(szProcOwner
, cbProcOwner
, NULL
, conn
);
3761 simpleCatalogEscape(szProcName
, cbProcName
, NULL
, conn
);
3763 if (conn
->schema_support
)
3765 strcpy(proc_query
, "select proname, proretset, prorettype, "
3766 "pronargs, proargtypes, nspname, p.oid");
3767 ret_col
= ext_pos
= 7;
3769 strcat(proc_query
, ", atttypid, attname");
3770 attid_pos
= ext_pos
;
3771 attname_pos
= ext_pos
+ 1;
3774 if (PG_VERSION_GE(conn
, 8.0))
3776 strcat(proc_query
, ", proargnames");
3779 if (PG_VERSION_GE(conn
, 8.1))
3781 strcat(proc_query
, ", proargmodes, proallargtypes");
3785 " from ((pg_catalog.pg_namespace n inner join"
3786 " pg_catalog.pg_proc p on p.pronamespace = n.oid)"
3787 " inner join pg_type t on t.oid = p.prorettype)"
3788 " left outer join pg_attribute a on a.attrelid = t.typrelid "
3789 " and attnum > 0 and not attisdropped where");
3790 strcat(proc_query
, " has_function_privilege(p.oid, 'EXECUTE')");
3791 my_strcat1(proc_query
, " and nspname %s '%.*s'", like_or_eq
,
3792 escSchemaName
, SQL_NTS
);
3794 snprintf_add(proc_query
, sizeof(proc_query
),
3795 " and proname %s '%s'", like_or_eq
,
3797 strcat(proc_query
, " order by nspname, proname, p.oid, attnum");
3801 strcpy(proc_query
, "select proname, proretset, prorettype, "
3802 "pronargs, proargtypes from pg_proc where "
3806 snprintf_add(proc_query
, sizeof(proc_query
),
3807 " and proname %s '%s'", like_or_eq
,
3809 strcat(proc_query
, " order by proname, proretset");
3812 CC_send_query(conn
, proc_query
, NULL
, IGNORE_ABORT_ON_CONN
,
3813 stmt
), !QR_command_maybe_successful(tres
))
3815 SC_set_error(stmt
, STMT_EXEC_ERROR
,
3816 "PGAPI_ProcedureColumns query error", func
);
3817 QR_Destructor(tres
);
3821 if (res
= QR_Constructor(), !res
)
3823 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
3824 "Couldn't allocate memory for PGAPI_ProcedureColumns result.",
3828 SC_set_Result(stmt
, res
);
3831 * the binding structure for a statement is not set up until
3832 * a statement is actually executed, so we'll have to do this
3835 result_cols
= NUM_OF_PROCOLS_FIELDS
;
3836 extend_column_bindings(SC_get_ARDF(stmt
), result_cols
);
3838 /* set the field names */
3839 QR_set_num_fields(res
, result_cols
);
3840 QR_set_field_info_v(res
, PROCOLS_PROCEDURE_CAT
, "PROCEDURE_CAT",
3841 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3842 QR_set_field_info_v(res
, PROCOLS_PROCEDURE_SCHEM
, "PROCEDUR_SCHEM",
3843 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3844 QR_set_field_info_v(res
, PROCOLS_PROCEDURE_NAME
, "PROCEDURE_NAME",
3845 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3846 QR_set_field_info_v(res
, PROCOLS_COLUMN_NAME
, "COLUMN_NAME",
3847 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3848 QR_set_field_info_v(res
, PROCOLS_COLUMN_TYPE
, "COLUMN_TYPE",
3850 QR_set_field_info_v(res
, PROCOLS_DATA_TYPE
, "DATA_TYPE",
3852 QR_set_field_info_v(res
, PROCOLS_TYPE_NAME
, "TYPE_NAME",
3853 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3854 QR_set_field_info_v(res
, PROCOLS_COLUMN_SIZE
, "COLUMN_SIZE",
3856 QR_set_field_info_v(res
, PROCOLS_BUFFER_LENGTH
, "BUFFER_LENGTH",
3858 QR_set_field_info_v(res
, PROCOLS_DECIMAL_DIGITS
, "DECIMAL_DIGITS",
3860 QR_set_field_info_v(res
, PROCOLS_NUM_PREC_RADIX
, "NUM_PREC_RADIX",
3862 QR_set_field_info_v(res
, PROCOLS_NULLABLE
, "NULLABLE", PG_TYPE_INT2
,
3864 QR_set_field_info_v(res
, PROCOLS_REMARKS
, "REMARKS",
3865 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3866 QR_set_field_info_v(res
, PROCOLS_COLUMN_DEF
, "COLUMN_DEF",
3867 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3868 QR_set_field_info_v(res
, PROCOLS_SQL_DATA_TYPE
, "SQL_DATA_TYPE",
3870 QR_set_field_info_v(res
, PROCOLS_SQL_DATETIME_SUB
,
3871 "SQL_DATETIME_SUB", PG_TYPE_INT2
, 2);
3872 QR_set_field_info_v(res
, PROCOLS_CHAR_OCTET_LENGTH
,
3873 "CHAR_OCTET_LENGTH", PG_TYPE_INT4
, 4);
3874 QR_set_field_info_v(res
, PROCOLS_ORDINAL_POSITION
,
3875 "ORDINAL_POSITION", PG_TYPE_INT4
, 4);
3876 QR_set_field_info_v(res
, PROCOLS_IS_NULLABLE
, "IS_NULLABLE",
3877 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3879 column_name
= make_string(szColumnName
, cbColumnName
, NULL
, 0);
3880 if (column_name
) /* column_name is unavailable now */
3886 tcount
= QR_get_num_total_tuples(tres
);
3887 for (i
= 0, poid
= 0; i
< tcount
; i
++)
3889 if (conn
->schema_support
)
3891 GET_SCHEMA_NAME(QR_get_value_backend_text(tres
, i
, 5));
3894 procname
= QR_get_value_backend_text(tres
, i
, 0);
3895 retset
= QR_get_value_backend_text(tres
, i
, 1);
3896 pgtype
= QR_get_value_backend_int(tres
, i
, 2, NULL
);
3897 bRetset
= retset
&& (retset
[0] == 't' || retset
[0] == 'y');
3900 newpoid
= QR_get_value_backend_int(tres
, i
, poid_pos
, NULL
);
3901 mylog("newpoid=%d\n", newpoid
);
3905 atttypid
= (char *)QR_get_value_backend_text(tres
, i
, attid_pos
);
3906 mylog("atttypid=%s\n", atttypid
? atttypid
: "(null)");
3908 if (poid
== 0 || newpoid
!= poid
)
3915 if (PG_VERSION_GE(conn
, 8.0))
3916 proargnames
= (char *)
3917 QR_get_value_backend_text(tres
, i
, ext_pos
);
3918 if (PG_VERSION_GE(conn
, 8.1))
3919 proargmodes
= (char *)
3920 QR_get_value_backend_text(tres
, i
, ext_pos
+ 1);
3922 /* RETURN_VALUE info */
3923 if (0 != pgtype
&& PG_TYPE_VOID
!= pgtype
&& !bRetset
3924 && !atttypid
&& !proargmodes
)
3926 tuple
= QR_AddNew(res
);
3927 set_tuplefield_string(&tuple
[PROCOLS_PROCEDURE_CAT
],
3929 set_nullfield_string(&tuple
[PROCOLS_PROCEDURE_SCHEM
],
3931 set_tuplefield_string(&tuple
[PROCOLS_PROCEDURE_NAME
],
3933 set_tuplefield_string(&tuple
[PROCOLS_COLUMN_NAME
],
3935 set_tuplefield_int2(&tuple
[PROCOLS_COLUMN_TYPE
],
3937 set_tuplefield_int2(&tuple
[PROCOLS_DATA_TYPE
],
3938 pgtype_to_concise_type(stmt
, pgtype
,
3940 set_tuplefield_string(&tuple
[PROCOLS_TYPE_NAME
],
3941 pgtype_to_name(stmt
, pgtype
,
3943 set_nullfield_int4(&tuple
[PROCOLS_COLUMN_SIZE
],
3944 pgtype_column_size(stmt
, pgtype
,
3947 set_tuplefield_int4(&tuple
[PROCOLS_BUFFER_LENGTH
],
3948 pgtype_buffer_length(stmt
, pgtype
,
3951 set_nullfield_int2(&tuple
[PROCOLS_DECIMAL_DIGITS
],
3952 pgtype_decimal_digits(stmt
, pgtype
,
3954 set_nullfield_int2(&tuple
[PROCOLS_NUM_PREC_RADIX
],
3955 pgtype_radix(stmt
, pgtype
));
3956 set_tuplefield_int2(&tuple
[PROCOLS_NULLABLE
],
3957 SQL_NULLABLE_UNKNOWN
);
3958 set_tuplefield_null(&tuple
[PROCOLS_REMARKS
]);
3959 set_tuplefield_null(&tuple
[PROCOLS_COLUMN_DEF
]);
3960 set_nullfield_int2(&tuple
[PROCOLS_SQL_DATA_TYPE
],
3961 pgtype_to_sqldesctype(stmt
, pgtype
,
3963 set_nullfield_int2(&tuple
[PROCOLS_SQL_DATETIME_SUB
],
3964 pgtype_to_datetime_sub(stmt
,
3966 set_nullfield_int4(&tuple
[PROCOLS_CHAR_OCTET_LENGTH
],
3967 pgtype_transfer_octet_length(stmt
,
3971 set_tuplefield_int4(&tuple
[PROCOLS_ORDINAL_POSITION
],
3973 set_tuplefield_string(&tuple
[PROCOLS_IS_NULLABLE
],
3981 for (p
= proargmodes
; *p
; p
++)
3988 QR_get_value_backend_text(tres
, i
, ext_pos
+ 2);
3989 if ('{' == *proargmodes
)
3996 paramcount
= QR_get_value_backend_int(tres
, i
, 3, NULL
);
3997 params
= (char *)QR_get_value_backend_text(tres
, i
, 4);
4001 if ('{' == *proargnames
)
4004 /* PARAMETERS info */
4005 for (j
= 0; j
< paramcount
; j
++)
4007 /* PG type of parameters */
4011 while (isspace(*params
) || ',' == *params
)
4013 if ('\0' == *params
|| '}' == *params
)
4017 sscanf(params
, "%u", &pgtype
);
4018 while (isdigit(*params
))
4022 /* input/output type of parameters */
4025 while (isspace(*proargmodes
) || ',' == *proargmodes
)
4027 if ('\0' == *proargmodes
|| '}' == *proargmodes
)
4030 /* name of parameters */
4033 while (isspace(*proargnames
) || ',' == *proargnames
)
4035 if ('\0' == *proargnames
|| '}' == *proargnames
)
4037 else if ('"' == *proargnames
)
4040 for (delim
= proargnames
;
4041 *delim
&& *delim
!= '"'; delim
++)
4046 for (delim
= proargnames
;
4047 *delim
&& !isspace(*delim
) && ',' != *delim
4048 && '}' != *delim
; delim
++)
4051 if (proargnames
&& '\0' == *delim
) /* discard the incomplete name */
4055 tuple
= QR_AddNew(res
);
4056 set_tuplefield_string(&tuple
[PROCOLS_PROCEDURE_CAT
],
4058 set_nullfield_string(&tuple
[PROCOLS_PROCEDURE_SCHEM
],
4060 set_tuplefield_string(&tuple
[PROCOLS_PROCEDURE_NAME
],
4065 set_tuplefield_string(&tuple
[PROCOLS_COLUMN_NAME
],
4067 proargnames
= delim
+ 1;
4070 set_tuplefield_string(&tuple
[PROCOLS_COLUMN_NAME
],
4076 switch (*proargmodes
)
4079 ptype
= SQL_PARAM_OUTPUT
;
4082 ptype
= SQL_PARAM_INPUT_OUTPUT
;
4085 ptype
= SQL_PARAM_INPUT
;
4088 set_tuplefield_int2(&tuple
[PROCOLS_COLUMN_TYPE
],
4093 set_tuplefield_int2(&tuple
[PROCOLS_COLUMN_TYPE
],
4095 set_tuplefield_int2(&tuple
[PROCOLS_DATA_TYPE
],
4096 pgtype_to_concise_type(stmt
, pgtype
,
4098 set_tuplefield_string(&tuple
[PROCOLS_TYPE_NAME
],
4099 pgtype_to_name(stmt
, pgtype
,
4101 set_nullfield_int4(&tuple
[PROCOLS_COLUMN_SIZE
],
4102 pgtype_column_size(stmt
, pgtype
,
4105 set_tuplefield_int4(&tuple
[PROCOLS_BUFFER_LENGTH
],
4106 pgtype_buffer_length(stmt
, pgtype
,
4109 set_nullfield_int2(&tuple
[PROCOLS_DECIMAL_DIGITS
],
4110 pgtype_decimal_digits(stmt
, pgtype
,
4112 set_nullfield_int2(&tuple
[PROCOLS_NUM_PREC_RADIX
],
4113 pgtype_radix(stmt
, pgtype
));
4114 set_tuplefield_int2(&tuple
[PROCOLS_NULLABLE
],
4115 SQL_NULLABLE_UNKNOWN
);
4116 set_tuplefield_null(&tuple
[PROCOLS_REMARKS
]);
4117 set_tuplefield_null(&tuple
[PROCOLS_COLUMN_DEF
]);
4118 set_nullfield_int2(&tuple
[PROCOLS_SQL_DATA_TYPE
],
4119 pgtype_to_sqldesctype(stmt
, pgtype
,
4121 set_nullfield_int2(&tuple
[PROCOLS_SQL_DATETIME_SUB
],
4122 pgtype_to_datetime_sub(stmt
,
4124 set_nullfield_int4(&tuple
[PROCOLS_CHAR_OCTET_LENGTH
],
4125 pgtype_transfer_octet_length(stmt
,
4129 set_tuplefield_int4(&tuple
[PROCOLS_ORDINAL_POSITION
],
4131 set_tuplefield_string(&tuple
[PROCOLS_IS_NULLABLE
],
4135 /* RESULT Columns info */
4136 if (NULL
!= atttypid
|| bRetset
)
4147 typid
= atoi(atttypid
);
4149 QR_get_value_backend_text(tres
, i
, attname_pos
);
4151 tuple
= QR_AddNew(res
);
4152 set_tuplefield_string(&tuple
[PROCOLS_PROCEDURE_CAT
],
4154 set_nullfield_string(&tuple
[PROCOLS_PROCEDURE_SCHEM
],
4156 set_tuplefield_string(&tuple
[PROCOLS_PROCEDURE_NAME
],
4158 set_tuplefield_string(&tuple
[PROCOLS_COLUMN_NAME
], attname
);
4159 set_tuplefield_int2(&tuple
[PROCOLS_COLUMN_TYPE
],
4161 set_tuplefield_int2(&tuple
[PROCOLS_DATA_TYPE
],
4162 pgtype_to_concise_type(stmt
, typid
,
4164 set_tuplefield_string(&tuple
[PROCOLS_TYPE_NAME
],
4165 pgtype_to_name(stmt
, typid
, FALSE
));
4166 set_nullfield_int4(&tuple
[PROCOLS_COLUMN_SIZE
],
4167 pgtype_column_size(stmt
, typid
,
4170 set_tuplefield_int4(&tuple
[PROCOLS_BUFFER_LENGTH
],
4171 pgtype_buffer_length(stmt
, typid
,
4174 set_nullfield_int2(&tuple
[PROCOLS_DECIMAL_DIGITS
],
4175 pgtype_decimal_digits(stmt
, typid
,
4177 set_nullfield_int2(&tuple
[PROCOLS_NUM_PREC_RADIX
],
4178 pgtype_radix(stmt
, typid
));
4179 set_tuplefield_int2(&tuple
[PROCOLS_NULLABLE
],
4180 SQL_NULLABLE_UNKNOWN
);
4181 set_tuplefield_null(&tuple
[PROCOLS_REMARKS
]);
4182 set_tuplefield_null(&tuple
[PROCOLS_COLUMN_DEF
]);
4183 set_nullfield_int2(&tuple
[PROCOLS_SQL_DATA_TYPE
],
4184 pgtype_to_sqldesctype(stmt
, typid
,
4186 set_nullfield_int2(&tuple
[PROCOLS_SQL_DATETIME_SUB
],
4187 pgtype_to_datetime_sub(stmt
, typid
));
4188 set_nullfield_int4(&tuple
[PROCOLS_CHAR_OCTET_LENGTH
],
4189 pgtype_transfer_octet_length(stmt
, typid
,
4192 set_tuplefield_int4(&tuple
[PROCOLS_ORDINAL_POSITION
], 0);
4193 set_tuplefield_string(&tuple
[PROCOLS_IS_NULLABLE
],
4197 QR_Destructor(tres
);
4199 * also, things need to think that this statement is finished so the
4200 * results can be retrieved.
4203 free(escSchemaName
);
4206 stmt
->status
= STMT_FINISHED
;
4207 /* set up the current tuple pointer for SQLFetch */
4208 stmt
->currTuple
= -1;
4209 SC_set_rowset_start(stmt
, -1, FALSE
);
4210 SC_set_current_col(stmt
, -1);
4215 RETCODE SQL_API
PGAPI_Procedures(HSTMT hstmt
, const SQLCHAR FAR
* szProcQualifier
, /* OA X */
4216 SQLSMALLINT cbProcQualifier
, const SQLCHAR FAR
* szProcOwner
, /* PV E */
4217 SQLSMALLINT cbProcOwner
, const SQLCHAR FAR
* szProcName
, /* PV E */
4218 SQLSMALLINT cbProcName
, UWORD flag
)
4220 CSTR func
= "PGAPI_Procedures";
4221 StatementClass
*stmt
= (StatementClass
*) hstmt
;
4222 ConnectionClass
*conn
= SC_get_conn(stmt
);
4223 char proc_query
[INFO_INQUIRY_LEN
];
4224 char *escSchemaName
= NULL
, *escProcName
= NULL
;
4227 const char *like_or_eq
;
4228 BOOL search_pattern
;
4230 mylog("%s: entering... scnm=%p len=%d\n", func
, szProcOwner
,
4233 if (PG_VERSION_LT(conn
, 6.5))
4235 SC_set_error(stmt
, STMT_NOT_IMPLEMENTED_ERROR
,
4236 "Version is too old", func
);
4239 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
4242 search_pattern
= (0 == (flag
& PODBC_NOT_SEARCH_PATTERN
));
4245 like_or_eq
= likeop
;
4247 adjustLikePattern(szProcOwner
, cbProcOwner
,
4248 SEARCH_PATTERN_ESCAPE
, NULL
, conn
);
4250 adjustLikePattern(szProcName
, cbProcName
,
4251 SEARCH_PATTERN_ESCAPE
, NULL
, conn
);
4257 simpleCatalogEscape(szProcOwner
, cbProcOwner
, NULL
, conn
);
4259 simpleCatalogEscape(szProcName
, cbProcName
, NULL
, conn
);
4262 * The following seems the simplest implementation
4264 if (conn
->schema_support
)
4267 "select '' as " "PROCEDURE_CAT" ", nspname as "
4268 "PROCEDURE_SCHEM" "," " proname as " "PROCEDURE_NAME"
4269 ", '' as " "NUM_INPUT_PARAMS" "," " '' as "
4270 "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
4271 " '' as " "REMARKS" ","
4272 " case when prorettype = 0 then 1::int2 else 2::int2 end"
4273 " as " "PROCEDURE_TYPE" " from pg_catalog.pg_namespace,"
4274 " pg_catalog.pg_proc"
4275 " where pg_proc.pronamespace = pg_namespace.oid");
4276 schema_strcat1(proc_query
, " and nspname %s '%.*s'", like_or_eq
,
4277 escSchemaName
, SQL_NTS
,
4278 (const char *)szProcName
, cbProcName
, conn
);
4279 my_strcat1(proc_query
, " and proname %s '%.*s'", like_or_eq
,
4280 escProcName
, SQL_NTS
);
4285 "select '' as " "PROCEDURE_CAT" ", '' as "
4286 "PROCEDURE_SCHEM" "," " proname as " "PROCEDURE_NAME"
4287 ", '' as " "NUM_INPUT_PARAMS" "," " '' as "
4288 "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
4289 " '' as " "REMARKS" ","
4290 " case when prorettype = 0 then 1::int2 else 2::int2 end as "
4291 "PROCEDURE_TYPE" " from pg_proc");
4292 my_strcat1(proc_query
, " where proname %s '%.*s'", like_or_eq
,
4293 escSchemaName
, SQL_NTS
);
4297 CC_send_query(conn
, proc_query
, NULL
, IGNORE_ABORT_ON_CONN
,
4298 stmt
), !QR_command_maybe_successful(res
))
4300 SC_set_error(stmt
, STMT_EXEC_ERROR
,
4301 "PGAPI_Procedures query error", func
);
4305 SC_set_Result(stmt
, res
);
4308 * also, things need to think that this statement is finished so the
4309 * results can be retrieved.
4311 stmt
->status
= STMT_FINISHED
;
4312 extend_column_bindings(SC_get_ARDF(stmt
), 8);
4314 free(escSchemaName
);
4317 /* set up the current tuple pointer for SQLFetch */
4318 stmt
->currTuple
= -1;
4319 SC_set_rowset_start(stmt
, -1, FALSE
);
4320 SC_set_current_col(stmt
, -1);
4326 #define ALL_PRIVILIGES "arwdRxt"
4327 static int usracl_auth(char *usracl
, const char *auth
)
4329 int i
, j
, addcnt
= 0;
4331 for (i
= 0; auth
[i
]; i
++)
4333 for (j
= 0; j
< ACLMAX
; j
++)
4335 if (usracl
[j
] == auth
[i
])
4337 else if (!usracl
[j
])
4339 usracl
[j
] = auth
[i
];
4348 useracl_upd(char (*useracl
)[ACLMAX
], QResultClass
* allures
,
4349 const char *user
, const char *auth
)
4351 int usercount
= (int) QR_get_num_cached_tuples(allures
), i
, addcnt
=
4354 mylog("user=%s auth=%s\n", user
, auth
);
4356 for (i
= 0; i
< usercount
; i
++)
4358 if (strcmp(QR_get_value_backend_text(allures
, i
, 0), user
)
4361 addcnt
+= usracl_auth(useracl
[i
], auth
);
4366 for (i
= 0; i
< usercount
; i
++)
4368 addcnt
+= usracl_auth(useracl
[i
], auth
);
4370 mylog("addcnt=%d\n", addcnt
);
4373 RETCODE SQL_API
PGAPI_TablePrivileges(HSTMT hstmt
, const SQLCHAR FAR
* szTableQualifier
, /* OA X */
4374 SQLSMALLINT cbTableQualifier
, const SQLCHAR FAR
* szTableOwner
, /* PV E */
4375 SQLSMALLINT cbTableOwner
, const SQLCHAR FAR
* szTableName
, /* PV E */
4376 SQLSMALLINT cbTableName
,
4379 StatementClass
*stmt
= (StatementClass
*) hstmt
;
4380 CSTR func
= "PGAPI_TablePrivileges";
4381 ConnectionClass
*conn
= SC_get_conn(stmt
);
4383 char proc_query
[INFO_INQUIRY_LEN
];
4384 QResultClass
*res
, *wres
= NULL
, *allures
= NULL
;
4386 Int4 tablecount
, usercount
, i
, j
, k
;
4387 BOOL grpauth
, sys
, su
;
4388 char (*useracl
)[ACLMAX
] = NULL
, *acl
, *user
, *delim
, *auth
;
4389 const char *reln
, *owner
, *priv
, *schnm
= NULL
;
4390 RETCODE result
, ret
= SQL_SUCCESS
;
4391 const char *like_or_eq
;
4392 const char *szSchemaName
;
4393 SQLSMALLINT cbSchemaName
;
4394 char *escSchemaName
= NULL
, *escTableName
= NULL
;
4395 BOOL search_pattern
;
4397 mylog("%s: entering... scnm=%p len-%d\n", func
,
4398 NULL_IF_NULL(szTableOwner
), cbTableOwner
);
4399 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
4403 * a statement is actually executed, so we'll have to do this
4407 extend_column_bindings(SC_get_ARDF(stmt
), result_cols
);
4409 stmt
->catalog_result
= TRUE
;
4410 /* set the field names */
4411 res
= QR_Constructor();
4412 SC_set_Result(stmt
, res
);
4413 QR_set_num_fields(res
, result_cols
);
4414 QR_set_field_info_v(res
, 0, "TABLE_CAT", PG_TYPE_VARCHAR
,
4416 QR_set_field_info_v(res
, 1, "TABLE_SCHEM", PG_TYPE_VARCHAR
,
4418 QR_set_field_info_v(res
, 2, "TABLE_NAME", PG_TYPE_VARCHAR
,
4420 QR_set_field_info_v(res
, 3, "GRANTOR", PG_TYPE_VARCHAR
,
4422 QR_set_field_info_v(res
, 4, "GRANTEE", PG_TYPE_VARCHAR
,
4424 QR_set_field_info_v(res
, 5, "PRIVILEGE", PG_TYPE_VARCHAR
,
4426 QR_set_field_info_v(res
, 6, "IS_GRANTABLE", PG_TYPE_VARCHAR
,
4430 * also, things need to think that this statement is finished so the
4431 * results can be retrieved.
4433 stmt
->status
= STMT_FINISHED
;
4434 /* set up the current tuple pointer for SQLFetch */
4435 stmt
->currTuple
= -1;
4436 SC_set_rowset_start(stmt
, -1, FALSE
);
4437 SC_set_current_col(stmt
, -1);
4438 szSchemaName
= (const char *)szTableOwner
;
4439 cbSchemaName
= cbTableOwner
;
4441 #define return DONT_CALL_RETURN_FROM_HERE???
4442 search_pattern
= (0 == (flag
& PODBC_NOT_SEARCH_PATTERN
));
4445 like_or_eq
= likeop
;
4447 adjustLikePattern(szTableName
, cbTableName
,
4448 SEARCH_PATTERN_ESCAPE
, NULL
, conn
);
4454 simpleCatalogEscape(szTableName
, cbTableName
, NULL
, conn
);
4457 retry_public_schema
:
4459 free(escSchemaName
);
4462 adjustLikePattern(szSchemaName
, cbSchemaName
,
4463 SEARCH_PATTERN_ESCAPE
, NULL
, conn
);
4466 simpleCatalogEscape(szSchemaName
, cbSchemaName
, NULL
, conn
);
4467 if (conn
->schema_support
)
4468 strncpy_null(proc_query
,
4469 "select relname, usename, relacl, nspname"
4470 " from pg_catalog.pg_namespace, pg_catalog.pg_class ,"
4471 " pg_catalog.pg_user where", sizeof(proc_query
));
4473 strncpy_null(proc_query
, "select relname, usename, relacl"
4474 " from pg_class , pg_user where",
4475 sizeof(proc_query
));
4476 if (conn
->schema_support
)
4479 schema_strcat1(proc_query
, " nspname %s '%.*s' and",
4480 like_or_eq
, escSchemaName
, SQL_NTS
,
4481 (const char *)szTableName
, cbTableName
, conn
);
4484 snprintf_add(proc_query
, sizeof(proc_query
),
4485 " relname %s '%s' and", like_or_eq
, escTableName
);
4486 if (conn
->schema_support
)
4489 " pg_namespace.oid = relnamespace and relkind in ('r', 'v') and");
4490 if ((!escTableName
) && (!escSchemaName
))
4492 " nspname not in ('pg_catalog', 'information_schema') and");
4494 strcat(proc_query
, " pg_user.usesysid = relowner");
4496 CC_send_query(conn
, proc_query
, NULL
, IGNORE_ABORT_ON_CONN
,
4497 stmt
), !QR_command_maybe_successful(wres
))
4499 SC_set_error(stmt
, STMT_EXEC_ERROR
,
4500 "PGAPI_TablePrivileges query error", func
);
4504 tablecount
= (Int4
) QR_get_num_cached_tuples(wres
);
4506 if (conn
->schema_support
&&
4507 (flag
& PODBC_SEARCH_PUBLIC_SCHEMA
) != 0 && 0 == tablecount
)
4509 const char *user
= CC_get_username(conn
);
4512 * If specified schema name == user_name and
4513 * the current schema is 'public',
4514 * retry the 'public' schema.
4517 (cbSchemaName
== SQL_NTS
||
4518 cbSchemaName
== (SQLSMALLINT
) strlen(user
)) &&
4519 strnicmp(szSchemaName
, user
, strlen(user
)) == 0 &&
4520 stricmp(CC_get_current_schema(conn
), pubstr
) == 0)
4522 QR_Destructor(wres
);
4524 szSchemaName
= pubstr
;
4525 cbSchemaName
= SQL_NTS
;
4526 goto retry_public_schema
;
4530 strncpy_null(proc_query
,
4531 "select usename, usesysid, usesuper from pg_user",
4532 sizeof(proc_query
));
4534 CC_send_query(conn
, proc_query
, NULL
, IGNORE_ABORT_ON_CONN
,
4535 stmt
), !QR_command_maybe_successful(allures
))
4537 SC_set_error(stmt
, STMT_EXEC_ERROR
,
4538 "PGAPI_TablePrivileges query error", func
);
4542 usercount
= (Int4
) QR_get_num_cached_tuples(allures
);
4544 (char (*)[ACLMAX
]) malloc(usercount
* sizeof(char[ACLMAX
]));
4545 for (i
= 0; i
< tablecount
; i
++)
4547 memset(useracl
, 0, usercount
* sizeof(char[ACLMAX
]));
4548 acl
= (char *) QR_get_value_backend_text(wres
, i
, 2);
4549 if (acl
&& acl
[0] == '{')
4553 for (; user
&& *user
;)
4556 if (user
[0] == '"' && strncmp(user
+ 1, "group ", 6) == 0)
4561 if (delim
= strchr(user
, '='), !delim
)
4567 if (delim
= strchr(auth
, '"'), delim
)
4573 else if (delim
= strchr(auth
, ','), delim
)
4575 else if (delim
= strchr(auth
, '}'), delim
)
4577 if (grpauth
) /* handle group privilege */
4581 char *grolist
, *uid
, *delm
;
4583 snprintf(proc_query
, sizeof(proc_query
) - 1,
4584 "select grolist from pg_group where groname = '%s'",
4587 CC_send_query(conn
, proc_query
, NULL
,
4588 IGNORE_ABORT_ON_CONN
, stmt
),
4589 !QR_command_maybe_successful(gres
))
4591 grolist
= (char *)QR_get_value_backend_text(gres
, 0, 0);
4592 if (grolist
&& grolist
[0] == '{')
4594 for (uid
= grolist
+ 1; *uid
;)
4596 if (delm
= strchr(uid
, ','), delm
)
4598 else if (delm
= strchr(uid
, '}'), delm
)
4600 mylog("guid=%s\n", uid
);
4601 for (i
= 0; i
< usercount
; i
++)
4604 (QR_get_value_backend_text
4605 (allures
, i
, 1), uid
) == 0)
4606 useracl_upd(useracl
, allures
,
4607 QR_get_value_backend_text
4608 (allures
, i
, 0), auth
);
4614 QR_Destructor(gres
);
4617 useracl_upd(useracl
, allures
, user
, auth
);
4622 reln
= QR_get_value_backend_text(wres
, i
, 0);
4623 owner
= QR_get_value_backend_text(wres
, i
, 1);
4624 if (conn
->schema_support
)
4625 schnm
= QR_get_value_backend_text(wres
, i
, 3);
4626 /* The owner has all privileges */
4627 useracl_upd(useracl
, allures
, owner
, ALL_PRIVILIGES
);
4628 for (j
= 0; j
< usercount
; j
++)
4630 user
= (char *)QR_get_value_backend_text(allures
, j
, 0);
4631 su
= (strcmp(QR_get_value_backend_text(allures
, j
, 2), "t")
4633 sys
= (strcmp(user
, owner
) == 0);
4634 /* Super user has all privileges */
4636 useracl_upd(useracl
, allures
, user
, ALL_PRIVILIGES
);
4637 for (k
= 0; k
< ACLMAX
; k
++)
4641 switch (useracl
[j
][k
])
4643 case 'R': /* rule */
4644 case 't': /* trigger */
4647 tuple
= QR_AddNew(res
);
4648 set_tuplefield_string(&tuple
[0], CurrCat(conn
));
4649 if (conn
->schema_support
)
4650 set_tuplefield_string(&tuple
[1],
4651 GET_SCHEMA_NAME(schnm
));
4653 set_tuplefield_string(&tuple
[1], NULL_STRING
);
4654 set_tuplefield_string(&tuple
[2], reln
);
4656 set_tuplefield_string(&tuple
[3], "_SYSTEM");
4658 set_tuplefield_string(&tuple
[3], owner
);
4659 mylog("user=%s\n", user
);
4660 set_tuplefield_string(&tuple
[4], user
);
4661 switch (useracl
[j
][k
])
4676 priv
= "REFERENCES";
4681 set_tuplefield_string(&tuple
[5], priv
);
4682 /* The owner and the super user are grantable */
4684 set_tuplefield_string(&tuple
[6], "YES");
4686 set_tuplefield_string(&tuple
[6], "NO");
4693 free(escSchemaName
);
4699 QR_Destructor(wres
);
4701 QR_Destructor(allures
);
4703 ret
= DiscardStatementSvp(stmt
, ret
, FALSE
);