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 */
238 case SQL_DRIVER_ODBC_VER
:
242 case SQL_DRIVER_VER
: /* ODBC 1.0 */
246 case SQL_EXPRESSIONS_IN_ORDERBY
: /* ODBC 1.0 */
250 case SQL_FETCH_DIRECTION
: /* ODBC 1.0 */
252 value
= (SQL_FD_FETCH_NEXT
|
257 SQL_FD_FETCH_ABSOLUTE
|
258 SQL_FD_FETCH_RELATIVE
| SQL_FD_FETCH_BOOKMARK
);
261 case SQL_FILE_USAGE
: /* ODBC 2.0 */
263 value
= SQL_FILE_NOT_SUPPORTED
;
266 case SQL_GETDATA_EXTENSIONS
: /* ODBC 2.0 */
269 (SQL_GD_ANY_COLUMN
| SQL_GD_ANY_ORDER
| SQL_GD_BOUND
|
273 case SQL_GROUP_BY
: /* ODBC 2.0 */
275 value
= SQL_GB_GROUP_BY_EQUALS_SELECT
;
278 case SQL_IDENTIFIER_CASE
: /* ODBC 1.0 */
281 * are identifiers case-sensitive (yes, but only when quoted.
282 * If not quoted, they default to lowercase)
285 value
= SQL_IC_LOWER
;
288 case SQL_IDENTIFIER_QUOTE_CHAR
: /* ODBC 1.0 */
289 /* the character used to quote "identifiers" */
290 p
= PG_VERSION_LE(conn
, 6.2) ? " " : "\"";
293 case SQL_KEYWORDS
: /* ODBC 2.0 */
297 case SQL_LIKE_ESCAPE_CLAUSE
: /* ODBC 2.0 */
300 * is there a character that escapes '%' and '_' in a LIKE
301 * clause? not as far as I can tell
306 case SQL_LOCK_TYPES
: /* ODBC 2.0 */
308 value
= SQL_LCK_NO_CHANGE
;
311 case SQL_MAX_BINARY_LITERAL_LEN
: /* ODBC 2.0 */
316 case SQL_MAX_CHAR_LITERAL_LEN
: /* ODBC 2.0 */
321 case SQL_MAX_COLUMNS_IN_GROUP_BY
: /* ODBC 2.0 */
326 case SQL_MAX_COLUMNS_IN_INDEX
: /* ODBC 2.0 */
331 case SQL_MAX_COLUMNS_IN_ORDER_BY
: /* ODBC 2.0 */
336 case SQL_MAX_COLUMNS_IN_SELECT
: /* ODBC 2.0 */
341 case SQL_MAX_COLUMNS_IN_TABLE
: /* ODBC 2.0 */
346 case SQL_MAX_CURSOR_NAME_LEN
: /* ODBC 1.0 */
348 value
= MAX_CURSOR_LEN
;
351 case SQL_MAX_SCHEMA_NAME_LEN
:
352 case SQL_MAX_TABLE_NAME_LEN
:
353 case SQL_MAX_COLUMN_NAME_LEN
:
358 case SQL_MAX_INDEX_SIZE
: /* ODBC 2.0 */
363 case SQL_MAX_PROCEDURE_NAME_LEN
: /* ODBC 1.0 */
368 case SQL_MAX_QUALIFIER_NAME_LEN
: /* ODBC 1.0 */
373 case SQL_MAX_ROW_SIZE
: /* ODBC 2.0 */
375 if (PG_VERSION_GE(conn
, 7.1))
377 /* Large Rowa in 7.1+ */
378 value
= MAX_ROW_SIZE
;
382 /* Without the Toaster we're limited to the blocksize */
387 case SQL_MAX_ROW_SIZE_INCLUDES_LONG
: /* ODBC 2.0 */
390 * does the preceding value include LONGVARCHAR and
391 * LONGVARBINARY fields? Well, it does include longvarchar,
392 * but not longvarbinary.
397 case SQL_MAX_STATEMENT_LEN
: /* ODBC 2.0 */
398 /* maybe this should be 0? */
400 value
= CC_get_max_query_len(conn
);
403 case SQL_MAX_TABLES_IN_SELECT
: /* ODBC 2.0 */
408 case SQL_MAX_USER_NAME_LEN
:
413 case SQL_MULT_RESULT_SETS
: /* ODBC 1.0 */
414 /* Don't support multiple result sets but say yes anyway? */
418 case SQL_MULTIPLE_ACTIVE_TXN
: /* ODBC 1.0 */
422 case SQL_NEED_LONG_DATA_LEN
: /* ODBC 2.0 */
425 * Don't need the length, SQLPutData can handle any size and
431 case SQL_NON_NULLABLE_COLUMNS
: /* ODBC 1.0 */
433 value
= SQL_NNC_NON_NULL
;
436 case SQL_NULL_COLLATION
: /* ODBC 2.0 */
437 /* where are nulls sorted? */
439 if (PG_VERSION_GE(conn
, 7.2))
445 case SQL_NUMERIC_FUNCTIONS
: /* ODBC 1.0 */
450 case SQL_ODBC_API_CONFORMANCE
: /* ODBC 1.0 */
452 value
= SQL_OAC_LEVEL1
;
455 case SQL_ODBC_SAG_CLI_CONFORMANCE
: /* ODBC 1.0 */
457 value
= SQL_OSCC_NOT_COMPLIANT
;
460 case SQL_ODBC_SQL_CONFORMANCE
: /* ODBC 1.0 */
462 value
= SQL_OSC_CORE
;
465 case SQL_ODBC_SQL_OPT_IEF
: /* ODBC 1.0 */
469 case SQL_OJ_CAPABILITIES
: /* ODBC 2.01 */
471 if (PG_VERSION_GE(conn
, 7.1))
474 value
= (SQL_OJ_LEFT
|
479 SQL_OJ_INNER
| SQL_OJ_ALL_COMPARISON_OPS
);
482 /* OJs not in <7.1 */
486 case SQL_ORDER_BY_COLUMNS_IN_SELECT
: /* ODBC 2.0 */
487 p
= (PG_VERSION_LE(conn
, 6.3)) ? "Y" : "N";
490 case SQL_OUTER_JOINS
: /* ODBC 1.0 */
491 if (PG_VERSION_GE(conn
, 7.1))
495 /* OJs not in <7.1 */
499 case SQL_OWNER_TERM
: /* ODBC 1.0 */
500 if (conn
->schema_support
)
506 case SQL_OWNER_USAGE
: /* ODBC 2.0 */
509 if (conn
->schema_support
)
510 value
= SQL_OU_DML_STATEMENTS
511 | SQL_OU_TABLE_DEFINITION
512 | SQL_OU_INDEX_DEFINITION
| SQL_OU_PRIVILEGE_DEFINITION
;
515 case SQL_POS_OPERATIONS
: /* ODBC 2.0 */
517 value
= (SQL_POS_POSITION
| SQL_POS_REFRESH
);
518 if (0 != ci
->updatable_cursors
)
519 value
|= (SQL_POS_UPDATE
| SQL_POS_DELETE
| SQL_POS_ADD
);
522 case SQL_POSITIONED_STATEMENTS
: /* ODBC 2.0 */
527 case SQL_PROCEDURE_TERM
: /* ODBC 1.0 */
531 case SQL_PROCEDURES
: /* ODBC 1.0 */
535 case SQL_QUALIFIER_LOCATION
: /* ODBC 2.0 */
538 value
= SQL_QL_START
;
543 case SQL_QUALIFIER_NAME_SEPARATOR
: /* ODBC 1.0 */
550 case SQL_QUALIFIER_TERM
: /* ODBC 1.0 */
557 case SQL_QUALIFIER_USAGE
: /* ODBC 2.0 */
560 value
= SQL_CU_DML_STATEMENTS
;
565 case SQL_QUOTED_IDENTIFIER_CASE
: /* ODBC 2.0 */
566 /* are "quoted" identifiers case-sensitive? YES! */
568 value
= SQL_IC_SENSITIVE
;
571 case SQL_ROW_UPDATES
: /* ODBC 1.0 */
574 * Driver doesn't support keyset-driven or mixed cursors, so
575 * not much point in saying row updates are supported
577 p
= (0 != ci
->updatable_cursors
) ? "Y" : "N";
580 case SQL_SCROLL_CONCURRENCY
: /* ODBC 1.0 */
582 value
= SQL_SCCO_READ_ONLY
;
583 if (0 != ci
->updatable_cursors
)
584 value
|= SQL_SCCO_OPT_ROWVER
;
587 case SQL_SCROLL_OPTIONS
: /* ODBC 1.0 */
589 value
= SQL_SO_FORWARD_ONLY
| SQL_SO_STATIC
;
590 if (0 != (ci
->updatable_cursors
& ALLOW_KEYSET_DRIVEN_CURSORS
))
591 value
|= SQL_SO_KEYSET_DRIVEN
;
594 case SQL_SEARCH_PATTERN_ESCAPE
: /* ODBC 1.0 */
595 if (PG_VERSION_GE(conn
, 6.5))
601 case SQL_SERVER_NAME
: /* ODBC 1.0 */
602 p
= CC_get_server(conn
);
605 case SQL_SPECIAL_CHARACTERS
: /* ODBC 2.0 */
609 case SQL_STATIC_SENSITIVITY
: /* ODBC 2.0 */
612 if (0 != ci
->updatable_cursors
)
614 (SQL_SS_ADDITIONS
| SQL_SS_DELETIONS
| SQL_SS_UPDATES
);
617 case SQL_STRING_FUNCTIONS
: /* ODBC 1.0 */
619 value
= (SQL_FN_STR_CONCAT
|
625 SQL_FN_STR_SUBSTRING
| SQL_FN_STR_UCASE
);
628 case SQL_SUBQUERIES
: /* ODBC 2.0 */
629 /* postgres 6.3 supports subqueries */
631 value
= (SQL_SQ_QUANTIFIED
|
632 SQL_SQ_IN
| SQL_SQ_EXISTS
| SQL_SQ_COMPARISON
);
635 case SQL_SYSTEM_FUNCTIONS
: /* ODBC 1.0 */
640 case SQL_TABLE_TERM
: /* ODBC 1.0 */
644 case SQL_TIMEDATE_ADD_INTERVALS
: /* ODBC 2.0 */
649 case SQL_TIMEDATE_DIFF_INTERVALS
: /* ODBC 2.0 */
654 case SQL_TIMEDATE_FUNCTIONS
: /* ODBC 1.0 */
656 value
= (SQL_FN_TD_NOW
);
659 case SQL_TXN_CAPABLE
: /* ODBC 1.0 */
662 * Postgres can deal with create or drop table statements in a
669 case SQL_TXN_ISOLATION_OPTION
: /* ODBC 1.0 */
671 if (PG_VERSION_LT(conn
, 6.5))
672 value
= SQL_TXN_SERIALIZABLE
;
673 else if (PG_VERSION_GE(conn
, 7.1))
674 value
= SQL_TXN_READ_COMMITTED
| SQL_TXN_SERIALIZABLE
;
676 value
= SQL_TXN_READ_COMMITTED
;
679 case SQL_UNION
: /* ODBC 2.0 */
680 /* unions with all supported in postgres 6.3 */
682 value
= (SQL_U_UNION
| SQL_U_UNION_ALL
);
685 case SQL_USER_NAME
: /* ODBC 1.0 */
686 p
= CC_get_username(conn
);
690 /* unrecognized key */
691 CC_set_error(conn
, CONN_NOT_IMPLEMENTED_ERROR
,
692 "Unrecognized key passed to PGAPI_GetInfo.", NULL
);
696 result
= SQL_SUCCESS
;
698 mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func
,
699 p
? p
: "<NULL>", len
, value
, cbInfoValueMax
);
702 * NOTE, that if rgbInfoValue is NULL, then no warnings or errors
703 * should result and just pcbInfoValue is returned, which indicates
704 * what length would be required if a real buffer had been passed in.
708 /* char/binary data */
713 if (CC_is_in_unicode_driver(conn
))
716 utf8_to_ucs2(p
, len
, (SQLWCHAR
*) rgbInfoValue
,
717 cbInfoValueMax
/ WCLEN
);
721 strncpy_null((char *) rgbInfoValue
, p
,
722 (size_t) cbInfoValueMax
);
724 if (len
>= cbInfoValueMax
)
726 result
= SQL_SUCCESS_WITH_INFO
;
727 CC_set_error(conn
, CONN_TRUNCATED
,
728 "The buffer was too small for the InfoValue.",
732 #ifdef UNICODE_SUPPORT
733 else if (CC_is_in_unicode_driver(conn
))
735 #endif /* UNICODE_SUPPORT */
742 if (len
== sizeof(SQLSMALLINT
))
743 *((SQLUSMALLINT
*) rgbInfoValue
) = (SQLUSMALLINT
) value
;
744 else if (len
== sizeof(SQLINTEGER
))
745 *((SQLUINTEGER
*) rgbInfoValue
) = (SQLUINTEGER
) value
;
750 *pcbInfoValue
= (SQLSMALLINT
) len
;
755 RETCODE SQL_API
PGAPI_GetTypeInfo(HSTMT hstmt
, SQLSMALLINT fSqlType
)
757 CSTR func
= "PGAPI_GetTypeInfo";
758 StatementClass
*stmt
= (StatementClass
*) hstmt
;
759 ConnectionClass
*conn
;
767 RETCODE result
= SQL_SUCCESS
;
769 mylog("%s: entering...fSqlType = %d\n", func
, fSqlType
);
771 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
774 conn
= SC_get_conn(stmt
);
775 if (res
= QR_Constructor(), !res
)
777 SC_set_error(stmt
, STMT_INTERNAL_ERROR
,
778 "Error creating result.", func
);
781 SC_set_Result(stmt
, res
);
783 #define return DONT_CALL_RETURN_FROM_HERE???
785 extend_column_bindings(SC_get_ARDF(stmt
), result_cols
);
787 stmt
->catalog_result
= TRUE
;
788 QR_set_num_fields(res
, result_cols
);
789 QR_set_field_info_v(res
, 0, "TYPE_NAME", PG_TYPE_VARCHAR
,
791 QR_set_field_info_v(res
, 1, "DATA_TYPE", PG_TYPE_INT2
, 2);
792 QR_set_field_info_v(res
, 2, "PRECISION", PG_TYPE_INT4
, 4);
793 QR_set_field_info_v(res
, 3, "LITERAL_PREFIX", PG_TYPE_VARCHAR
,
795 QR_set_field_info_v(res
, 4, "LITERAL_SUFFIX", PG_TYPE_VARCHAR
,
797 QR_set_field_info_v(res
, 5, "CREATE_PARAMS", PG_TYPE_VARCHAR
,
799 QR_set_field_info_v(res
, 6, "NULLABLE", PG_TYPE_INT2
, 2);
800 QR_set_field_info_v(res
, 7, "CASE_SENSITIVE", PG_TYPE_INT2
, 2);
801 QR_set_field_info_v(res
, 8, "SEARCHABLE", PG_TYPE_INT2
, 2);
802 QR_set_field_info_v(res
, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2
, 2);
803 QR_set_field_info_v(res
, 10, "MONEY", PG_TYPE_INT2
, 2);
804 QR_set_field_info_v(res
, 11, "AUTO_INCREMENT", PG_TYPE_INT2
, 2);
805 QR_set_field_info_v(res
, 12, "LOCAL_TYPE_NAME", PG_TYPE_VARCHAR
,
807 QR_set_field_info_v(res
, 13, "MINIMUM_SCALE", PG_TYPE_INT2
, 2);
808 QR_set_field_info_v(res
, 14, "MAXIMUM_SCALE", PG_TYPE_INT2
, 2);
809 QR_set_field_info_v(res
, 15, "SQL_DATA_TYPE", PG_TYPE_INT2
, 2);
810 QR_set_field_info_v(res
, 16, "SQL_DATETIME_SUB", PG_TYPE_INT2
, 2);
811 QR_set_field_info_v(res
, 17, "NUM_PREC_RADIX", PG_TYPE_INT4
, 4);
812 QR_set_field_info_v(res
, 18, "INTERVAL_PRECISION", PG_TYPE_INT2
, 2);
814 for (i
= 0, sqlType
= sqlTypes
[0]; sqlType
; sqlType
= sqlTypes
[++i
])
816 pgType
= sqltype_to_pgtype(stmt
, sqlType
);
818 if (sqlType
== SQL_LONGVARBINARY
)
820 ConnInfo
*ci
= &(conn
->connInfo
);
821 inolog("%d sqltype=%d -> pgtype=%d\n",
822 ci
->bytea_as_longvarbinary
, sqlType
, pgType
);
825 if (fSqlType
== SQL_ALL_TYPES
|| fSqlType
== sqlType
)
827 int pgtcount
= 1, aunq_match
= -1, cnt
;
829 /*if (SQL_INTEGER == sqlType || SQL_TINYINT == sqlType) */
830 if (SQL_INTEGER
== sqlType
)
832 mylog("sqlType=%d ms_jet=%d\n", sqlType
, conn
->ms_jet
);
833 if (conn
->ms_jet
&& PG_VERSION_GE(conn
, 6.4))
838 mylog("aunq_match=%d pgtcount=%d\n", aunq_match
,
841 for (cnt
= 0; cnt
< pgtcount
; cnt
++)
843 tuple
= QR_AddNew(res
);
845 /* These values can't be NULL */
846 if (aunq_match
== cnt
)
848 set_tuplefield_string(&tuple
[0],
849 pgtype_to_name(stmt
, pgType
,
851 set_tuplefield_int2(&tuple
[6], SQL_NO_NULLS
);
852 inolog("serial in\n");
856 set_tuplefield_string(&tuple
[0],
857 pgtype_to_name(stmt
, pgType
,
859 set_tuplefield_int2(&tuple
[6],
860 pgtype_nullable(stmt
, pgType
));
862 set_tuplefield_int2(&tuple
[1], (Int2
) sqlType
);
863 set_tuplefield_int2(&tuple
[7],
864 pgtype_case_sensitive(stmt
,
866 set_tuplefield_int2(&tuple
[8],
867 pgtype_searchable(stmt
, pgType
));
868 set_tuplefield_int2(&tuple
[10],
869 pgtype_money(stmt
, pgType
));
872 * Localized data-source dependent data type name (always
875 set_tuplefield_null(&tuple
[12]);
877 /* These values can be NULL */
878 set_nullfield_int4(&tuple
[2],
879 pgtype_column_size(stmt
, pgType
,
882 set_nullfield_string(&tuple
[3],
883 pgtype_literal_prefix(stmt
,
885 set_nullfield_string(&tuple
[4],
886 pgtype_literal_suffix(stmt
,
888 set_nullfield_string(&tuple
[5],
889 pgtype_create_params(stmt
,
892 set_tuplefield_int2(&tuple
[9], SQL_TRUE
);
894 set_nullfield_int2(&tuple
[9],
895 pgtype_unsigned(stmt
, pgType
));
896 if (aunq_match
== cnt
)
897 set_tuplefield_int2(&tuple
[11], SQL_TRUE
);
899 set_nullfield_int2(&tuple
[11],
900 pgtype_auto_increment(stmt
,
902 set_nullfield_int2(&tuple
[13],
903 pgtype_min_decimal_digits(stmt
,
905 set_nullfield_int2(&tuple
[14],
906 pgtype_max_decimal_digits(stmt
,
908 set_nullfield_int2(&tuple
[15],
909 pgtype_to_sqldesctype(stmt
, pgType
,
911 set_nullfield_int2(&tuple
[16],
912 pgtype_to_datetime_sub(stmt
,
914 set_nullfield_int4(&tuple
[17],
915 pgtype_radix(stmt
, pgType
));
916 set_nullfield_int4(&tuple
[18], 0);
923 * also, things need to think that this statement is finished so the
924 * results can be retrieved.
926 stmt
->status
= STMT_FINISHED
;
927 stmt
->currTuple
= -1;
928 SC_set_rowset_start(stmt
, -1, FALSE
);
929 SC_set_current_col(stmt
, -1);
932 result
= DiscardStatementSvp(stmt
, result
, FALSE
);
937 PGAPI_GetFunctions(HDBC hdbc
,
938 SQLUSMALLINT fFunction
, SQLUSMALLINT FAR
* pfExists
)
940 CSTR func
= "PGAPI_GetFunctions";
941 ConnectionClass
*conn
= (ConnectionClass
*) hdbc
;
942 ConnInfo
*ci
= &(conn
->connInfo
);
944 mylog("%s: entering...%u\n", func
, fFunction
);
946 if (fFunction
== SQL_API_ALL_FUNCTIONS
)
949 memset(pfExists
, 0, sizeof(pfExists
[0]) * 100);
951 /* ODBC core functions */
952 pfExists
[SQL_API_SQLALLOCCONNECT
] = TRUE
;
953 pfExists
[SQL_API_SQLALLOCENV
] = TRUE
;
954 pfExists
[SQL_API_SQLALLOCSTMT
] = TRUE
;
955 pfExists
[SQL_API_SQLBINDCOL
] = TRUE
;
956 pfExists
[SQL_API_SQLCANCEL
] = TRUE
;
957 pfExists
[SQL_API_SQLCOLATTRIBUTES
] = TRUE
;
958 pfExists
[SQL_API_SQLCONNECT
] = TRUE
;
959 pfExists
[SQL_API_SQLDESCRIBECOL
] = TRUE
; /* partial */
960 pfExists
[SQL_API_SQLDISCONNECT
] = TRUE
;
961 pfExists
[SQL_API_SQLERROR
] = TRUE
;
962 pfExists
[SQL_API_SQLEXECDIRECT
] = TRUE
;
963 pfExists
[SQL_API_SQLEXECUTE
] = TRUE
;
964 pfExists
[SQL_API_SQLFETCH
] = TRUE
;
965 pfExists
[SQL_API_SQLFREECONNECT
] = TRUE
;
966 pfExists
[SQL_API_SQLFREEENV
] = TRUE
;
967 pfExists
[SQL_API_SQLFREESTMT
] = TRUE
;
968 pfExists
[SQL_API_SQLGETCURSORNAME
] = TRUE
;
969 pfExists
[SQL_API_SQLNUMRESULTCOLS
] = TRUE
;
970 pfExists
[SQL_API_SQLPREPARE
] = TRUE
; /* complete? */
971 pfExists
[SQL_API_SQLROWCOUNT
] = TRUE
;
972 pfExists
[SQL_API_SQLSETCURSORNAME
] = TRUE
;
973 pfExists
[SQL_API_SQLSETPARAM
] = FALSE
; /* odbc 1.0 */
974 pfExists
[SQL_API_SQLTRANSACT
] = TRUE
;
976 /* ODBC level 1 functions */
977 pfExists
[SQL_API_SQLBINDPARAMETER
] = TRUE
;
978 pfExists
[SQL_API_SQLCOLUMNS
] = TRUE
;
979 pfExists
[SQL_API_SQLDRIVERCONNECT
] = TRUE
;
980 pfExists
[SQL_API_SQLGETCONNECTOPTION
] = TRUE
; /* partial */
981 pfExists
[SQL_API_SQLGETDATA
] = TRUE
;
982 pfExists
[SQL_API_SQLGETFUNCTIONS
] = TRUE
;
983 pfExists
[SQL_API_SQLGETINFO
] = TRUE
;
984 pfExists
[SQL_API_SQLGETSTMTOPTION
] = TRUE
; /* partial */
985 pfExists
[SQL_API_SQLGETTYPEINFO
] = TRUE
;
986 pfExists
[SQL_API_SQLPARAMDATA
] = TRUE
;
987 pfExists
[SQL_API_SQLPUTDATA
] = TRUE
;
988 pfExists
[SQL_API_SQLSETCONNECTOPTION
] = TRUE
; /* partial */
989 pfExists
[SQL_API_SQLSETSTMTOPTION
] = TRUE
;
990 pfExists
[SQL_API_SQLSPECIALCOLUMNS
] = TRUE
;
991 pfExists
[SQL_API_SQLSTATISTICS
] = TRUE
;
992 pfExists
[SQL_API_SQLTABLES
] = TRUE
;
994 /* ODBC level 2 functions */
995 pfExists
[SQL_API_SQLBROWSECONNECT
] = FALSE
;
996 if (PG_VERSION_GE(conn
, 7.4))
997 pfExists
[SQL_API_SQLCOLUMNPRIVILEGES
] = FALSE
;
999 pfExists
[SQL_API_SQLCOLUMNPRIVILEGES
] = FALSE
;
1000 pfExists
[SQL_API_SQLDATASOURCES
] = FALSE
; /* only implemented by
1002 if (SUPPORT_DESCRIBE_PARAM(ci
))
1003 pfExists
[SQL_API_SQLDESCRIBEPARAM
] = TRUE
;
1005 pfExists
[SQL_API_SQLDESCRIBEPARAM
] = FALSE
; /* not properly
1007 pfExists
[SQL_API_SQLDRIVERS
] = FALSE
; /* only implemented by
1009 pfExists
[SQL_API_SQLEXTENDEDFETCH
] = TRUE
;
1010 pfExists
[SQL_API_SQLFOREIGNKEYS
] = TRUE
;
1011 pfExists
[SQL_API_SQLMORERESULTS
] = TRUE
;
1012 pfExists
[SQL_API_SQLNATIVESQL
] = TRUE
;
1013 pfExists
[SQL_API_SQLNUMPARAMS
] = TRUE
;
1014 pfExists
[SQL_API_SQLPARAMOPTIONS
] = TRUE
;
1015 pfExists
[SQL_API_SQLPRIMARYKEYS
] = TRUE
;
1016 if (PG_VERSION_LT(conn
, 6.5))
1017 pfExists
[SQL_API_SQLPROCEDURECOLUMNS
] = FALSE
;
1019 pfExists
[SQL_API_SQLPROCEDURECOLUMNS
] = TRUE
;
1020 if (PG_VERSION_LT(conn
, 6.5))
1021 pfExists
[SQL_API_SQLPROCEDURES
] = FALSE
;
1023 pfExists
[SQL_API_SQLPROCEDURES
] = TRUE
;
1024 pfExists
[SQL_API_SQLSETPOS
] = TRUE
;
1025 pfExists
[SQL_API_SQLSETSCROLLOPTIONS
] = TRUE
; /* odbc 1.0 */
1026 pfExists
[SQL_API_SQLTABLEPRIVILEGES
] = TRUE
;
1027 if (0 == ci
->updatable_cursors
)
1028 pfExists
[SQL_API_SQLBULKOPERATIONS
] = FALSE
;
1030 pfExists
[SQL_API_SQLBULKOPERATIONS
] = TRUE
;
1037 case SQL_API_SQLBINDCOL
:
1040 case SQL_API_SQLCANCEL
:
1043 case SQL_API_SQLCOLATTRIBUTE
:
1046 case SQL_API_SQLCONNECT
:
1049 case SQL_API_SQLDESCRIBECOL
:
1051 break; /* partial */
1052 case SQL_API_SQLDISCONNECT
:
1055 case SQL_API_SQLEXECDIRECT
:
1058 case SQL_API_SQLEXECUTE
:
1061 case SQL_API_SQLFETCH
:
1064 case SQL_API_SQLFREESTMT
:
1067 case SQL_API_SQLGETCURSORNAME
:
1070 case SQL_API_SQLNUMRESULTCOLS
:
1073 case SQL_API_SQLPREPARE
:
1076 case SQL_API_SQLROWCOUNT
:
1079 case SQL_API_SQLSETCURSORNAME
:
1083 /* ODBC level 1 functions */
1084 case SQL_API_SQLBINDPARAMETER
:
1087 case SQL_API_SQLCOLUMNS
:
1090 case SQL_API_SQLDRIVERCONNECT
:
1093 case SQL_API_SQLGETDATA
:
1096 case SQL_API_SQLGETFUNCTIONS
:
1099 case SQL_API_SQLGETINFO
:
1102 case SQL_API_SQLGETTYPEINFO
:
1105 case SQL_API_SQLPARAMDATA
:
1108 case SQL_API_SQLPUTDATA
:
1111 case SQL_API_SQLSPECIALCOLUMNS
:
1114 case SQL_API_SQLSTATISTICS
:
1117 case SQL_API_SQLTABLES
:
1121 /* ODBC level 2 functions */
1122 case SQL_API_SQLBROWSECONNECT
:
1125 case SQL_API_SQLCOLUMNPRIVILEGES
:
1128 case SQL_API_SQLDATASOURCES
:
1130 break; /* only implemented by DM */
1131 case SQL_API_SQLDESCRIBEPARAM
:
1132 if (SUPPORT_DESCRIBE_PARAM(ci
))
1136 break; /* not properly implemented */
1137 case SQL_API_SQLDRIVERS
:
1139 break; /* only implemented by DM */
1140 case SQL_API_SQLEXTENDEDFETCH
:
1143 case SQL_API_SQLFOREIGNKEYS
:
1146 case SQL_API_SQLMORERESULTS
:
1149 case SQL_API_SQLNATIVESQL
:
1152 case SQL_API_SQLNUMPARAMS
:
1155 case SQL_API_SQLPRIMARYKEYS
:
1158 case SQL_API_SQLPROCEDURECOLUMNS
:
1159 if (PG_VERSION_LT(conn
, 6.5))
1164 case SQL_API_SQLPROCEDURES
:
1165 if (PG_VERSION_LT(conn
, 6.5))
1170 case SQL_API_SQLSETPOS
:
1173 case SQL_API_SQLTABLEPRIVILEGES
:
1176 case SQL_API_SQLBULKOPERATIONS
: /* 24 */
1177 case SQL_API_SQLALLOCHANDLE
: /* 1001 */
1178 case SQL_API_SQLBINDPARAM
: /* 1002 */
1179 case SQL_API_SQLCLOSECURSOR
: /* 1003 */
1180 case SQL_API_SQLENDTRAN
: /* 1005 */
1181 case SQL_API_SQLFETCHSCROLL
: /* 1021 */
1182 case SQL_API_SQLFREEHANDLE
: /* 1006 */
1183 case SQL_API_SQLGETCONNECTATTR
: /* 1007 */
1184 case SQL_API_SQLGETDESCFIELD
: /* 1008 */
1185 case SQL_API_SQLGETDIAGFIELD
: /* 1010 */
1186 case SQL_API_SQLGETDIAGREC
: /* 1011 */
1187 case SQL_API_SQLGETENVATTR
: /* 1012 */
1188 case SQL_API_SQLGETSTMTATTR
: /* 1014 */
1189 case SQL_API_SQLSETCONNECTATTR
: /* 1016 */
1190 case SQL_API_SQLSETDESCFIELD
: /* 1017 */
1191 case SQL_API_SQLSETENVATTR
: /* 1019 */
1192 case SQL_API_SQLSETSTMTATTR
: /* 1020 */
1195 case SQL_API_SQLGETDESCREC
: /* 1009 */
1196 case SQL_API_SQLSETDESCREC
: /* 1018 */
1197 case SQL_API_SQLCOPYDESC
: /* 1004 */
1208 static char *simpleCatalogEscape(const void *_src
, int srclen
,
1210 const ConnectionClass
* conn
)
1213 const char *src
= (const char *)_src
, *in
;
1214 char *dest
= NULL
, escape_ch
= CC_get_escape(conn
);
1219 if (!src
|| srclen
== SQL_NULL_DATA
)
1221 else if (srclen
== SQL_NTS
)
1222 srclen
= (int) strlen(src
);
1225 mylog("simple in=%s(%d)\n", src
, srclen
);
1226 encoded_str_constr(&encstr
, conn
->ccsc
, src
);
1227 dest
= (char *)malloc(2 * srclen
+ 1);
1228 for (i
= 0, in
= src
, outlen
= 0; i
< srclen
; i
++, in
++)
1230 encoded_nextchar(&encstr
);
1231 if (ENCODE_STATUS(encstr
) != 0)
1233 dest
[outlen
++] = *in
;
1236 if (LITERAL_QUOTE
== *in
|| escape_ch
== *in
)
1237 dest
[outlen
++] = *in
;
1238 dest
[outlen
++] = *in
;
1240 dest
[outlen
] = '\0';
1242 *result_len
= outlen
;
1243 mylog("simple output=%s(%d)\n", dest
, outlen
);
1248 * PostgreSQL needs 2 '\\' to escape '_' and '%'.
1250 static char *adjustLikePattern(const void *_src
, int srclen
,
1251 char escape_ch
, int *result_len
,
1252 const ConnectionClass
* conn
)
1255 const char *src
= (const char *)_src
, *in
;
1256 char *dest
= NULL
, escape_in_literal
= CC_get_escape(conn
);
1257 BOOL escape_in
= FALSE
;
1262 if (!src
|| srclen
== SQL_NULL_DATA
)
1264 else if (srclen
== SQL_NTS
)
1265 srclen
= (int) strlen(src
);
1266 /* if (srclen <= 0) */
1269 mylog("adjust in=%s(%d)\n", src
, srclen
);
1270 encoded_str_constr(&encstr
, conn
->ccsc
, src
);
1271 dest
= (char *)malloc(2 * srclen
+ 1);
1272 for (i
= 0, in
= src
, outlen
= 0; i
< srclen
; i
++, in
++)
1274 encoded_nextchar(&encstr
);
1275 if (ENCODE_STATUS(encstr
) != 0)
1277 dest
[outlen
++] = *in
;
1286 if (escape_ch
== escape_in_literal
)
1287 dest
[outlen
++] = escape_in_literal
; /* and insert 1 more LEXER escape */
1288 dest
[outlen
++] = escape_ch
;
1291 if (escape_ch
== escape_in_literal
)
1292 dest
[outlen
++] = escape_in_literal
;
1293 dest
[outlen
++] = escape_ch
;
1294 if (escape_ch
== escape_in_literal
)
1295 dest
[outlen
++] = escape_in_literal
;
1296 dest
[outlen
++] = escape_ch
;
1300 if (*in
== escape_ch
)
1305 if (LITERAL_QUOTE
== *in
)
1306 dest
[outlen
++] = *in
;
1307 dest
[outlen
++] = *in
;
1310 dest
[outlen
] = '\0';
1312 *result_len
= outlen
;
1313 mylog("adjust output=%s(%d)\n", dest
, outlen
);
1319 * FIXME: we always return all tables, not parsing for wildcards, catalogs,
1320 * etc. This seems to be good enough for now but could easily explode in
1323 RETCODE SQL_API PGAPI_Tables
1325 const SQLCHAR FAR
* szTableQualifier
, /* PV X */
1326 SQLSMALLINT cbTableQualifier
,
1327 const SQLCHAR FAR
*szTableOwner
, /* PV E */
1328 SQLSMALLINT cbTableOwner
,
1329 const SQLCHAR FAR
*szTableName
, /* PV E */
1330 SQLSMALLINT cbTableName
,
1331 const SQLCHAR FAR
*szTableType
,
1332 SQLSMALLINT cbTableType
, UWORD flag
)
1334 StatementClass
*stmt
= (StatementClass
*)hstmt
;
1336 VxStatement
st(stmt
);
1339 rs
.runquery(st
.dbus(), "ExecChunkRecordset", "LIST TABLES");
1341 stmt
->catalog_result
= TRUE
;
1342 return st
.retcode();
1346 RETCODE SQL_API
PGAPI_Columns(HSTMT hstmt
, const SQLCHAR FAR
* szTableQualifier
, /* OA X */
1347 SQLSMALLINT cbTableQualifier
, const SQLCHAR FAR
* szTableOwner
, /* PV E */
1348 SQLSMALLINT cbTableOwner
, const SQLCHAR FAR
* szTableName
, /* PV E */
1349 SQLSMALLINT cbTableName
, const SQLCHAR FAR
* szColumnName
, /* PV E */
1350 SQLSMALLINT cbColumnName
,
1351 UWORD flag
, OID reloid
, Int2 attnum
)
1353 StatementClass
*stmt
= (StatementClass
*)hstmt
;
1355 VxStatement
st(stmt
);
1358 rs
.runquery(st
.dbus(), "ExecChunkRecordset",
1359 WvString("LIST COLUMNS %s", (const char *)szTableName
));
1361 stmt
->catalog_result
= TRUE
;
1362 return st
.retcode();
1366 RETCODE SQL_API
PGAPI_SpecialColumns(HSTMT hstmt
, SQLUSMALLINT fColType
, const SQLCHAR FAR
* szTableQualifier
, SQLSMALLINT cbTableQualifier
, const SQLCHAR FAR
* szTableOwner
, /* OA E */
1367 SQLSMALLINT cbTableOwner
, const SQLCHAR FAR
* szTableName
, /* OA(R) E */
1368 SQLSMALLINT cbTableName
,
1369 SQLUSMALLINT fScope
,
1370 SQLUSMALLINT fNullable
)
1372 CSTR func
= "PGAPI_SpecialColumns";
1374 StatementClass
*stmt
= (StatementClass
*) hstmt
;
1375 ConnectionClass
*conn
;
1378 HSTMT hcol_stmt
= NULL
;
1379 StatementClass
*col_stmt
;
1380 char columns_query
[INFO_INQUIRY_LEN
];
1381 char *escSchemaName
= NULL
, *escTableName
= NULL
;
1382 RETCODE result
= SQL_SUCCESS
;
1383 char relhasrules
[MAX_INFO_STRING
], relkind
[8], relhasoids
[8];
1385 SQLSMALLINT internal_asis_type
= SQL_C_CHAR
, cbSchemaName
;
1386 const char *szSchemaName
;
1388 mylog("%s: entering...stmt=%p scnm=%p len=%d colType=%d\n", func
,
1389 stmt
, NULL_IF_NULL(szTableOwner
), cbTableOwner
, fColType
);
1391 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
1393 conn
= SC_get_conn(stmt
);
1394 ci
= &(conn
->connInfo
);
1395 #ifdef UNICODE_SUPPORT
1396 if (CC_is_in_unicode_driver(conn
))
1397 internal_asis_type
= INTERNAL_ASIS_TYPE
;
1398 #endif /* UNICODE_SUPPORT */
1400 szSchemaName
= (const char *)szTableOwner
;
1401 cbSchemaName
= cbTableOwner
;
1404 simpleCatalogEscape(szTableName
, cbTableName
, NULL
, conn
);
1407 SC_set_error(stmt
, STMT_INVALID_NULL_ARG
,
1408 "The table name is required", func
);
1411 #define return DONT_CALL_RETURN_FROM_HERE???
1413 retry_public_schema
:
1415 free(escSchemaName
);
1417 simpleCatalogEscape((const UCHAR
*)szSchemaName
, cbSchemaName
, NULL
, conn
);
1419 * Create the query to find out if this is a view or not...
1421 strcpy(columns_query
, "select c.relhasrules, c.relkind");
1422 if (PG_VERSION_GE(conn
, 7.2))
1423 strcat(columns_query
, ", c.relhasoids");
1424 if (conn
->schema_support
)
1425 strcat(columns_query
, " from pg_catalog.pg_namespace u,"
1426 " pg_catalog.pg_class c where "
1427 "u.oid = c.relnamespace");
1429 strcat(columns_query
, " from pg_user u, pg_class c where "
1430 "u.usesysid = c.relowner");
1432 /* TableName cannot contain a string search pattern */
1433 /* my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName); */
1435 snprintf_add(columns_query
, sizeof(columns_query
),
1436 " and c.relname = '%s'", escTableName
);
1437 /* SchemaName cannot contain a string search pattern */
1438 if (conn
->schema_support
)
1439 schema_strcat(columns_query
, " and u.nspname = '%.*s'",
1440 escSchemaName
, SQL_NTS
, (const char *)szTableName
,
1443 my_strcat(columns_query
, " and u.usename = '%.*s'",
1444 escSchemaName
, SQL_NTS
);
1446 result
= PGAPI_AllocStmt(conn
, &hcol_stmt
);
1447 if (!SQL_SUCCEEDED(result
))
1449 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
1450 "Couldn't allocate statement for SQLSpecialColumns result.",
1455 col_stmt
= (StatementClass
*) hcol_stmt
;
1457 mylog("%s: hcol_stmt = %p, col_stmt = %p\n", func
, hcol_stmt
,
1460 result
= PGAPI_ExecDirect(hcol_stmt
, (const UCHAR
*)columns_query
, SQL_NTS
, 0);
1461 if (!SQL_SUCCEEDED(result
))
1463 SC_full_error_copy(stmt
, col_stmt
, FALSE
);
1469 if (conn
->schema_support
&&
1470 (res
= SC_get_Result(col_stmt
)) &&
1471 0 == QR_get_num_total_tuples(res
))
1473 const char *user
= CC_get_username(conn
);
1476 * If specified schema name == user_name and
1477 * the current schema is 'public',
1478 * retry the 'public' schema.
1481 (cbSchemaName
== SQL_NTS
||
1482 cbSchemaName
== (SQLSMALLINT
) strlen(user
)) &&
1483 strnicmp(szSchemaName
, user
, strlen(user
)) == 0 &&
1484 stricmp(CC_get_current_schema(conn
), pubstr
) == 0)
1486 PGAPI_FreeStmt(hcol_stmt
, SQL_DROP
);
1488 szSchemaName
= pubstr
;
1489 cbSchemaName
= SQL_NTS
;
1490 goto retry_public_schema
;
1494 result
= PGAPI_BindCol(hcol_stmt
, 1, internal_asis_type
,
1495 relhasrules
, sizeof(relhasrules
), NULL
);
1496 if (!SQL_SUCCEEDED(result
))
1498 SC_error_copy(stmt
, col_stmt
, TRUE
);
1503 result
= PGAPI_BindCol(hcol_stmt
, 2, internal_asis_type
,
1504 relkind
, sizeof(relkind
), NULL
);
1505 if (!SQL_SUCCEEDED(result
))
1507 SC_error_copy(stmt
, col_stmt
, TRUE
);
1511 relhasoids
[0] = '1';
1512 if (PG_VERSION_GE(conn
, 7.2))
1514 result
= PGAPI_BindCol(hcol_stmt
, 3, internal_asis_type
,
1515 relhasoids
, sizeof(relhasoids
), NULL
);
1516 if (!SQL_SUCCEEDED(result
))
1518 SC_error_copy(stmt
, col_stmt
, TRUE
);
1524 result
= PGAPI_Fetch(hcol_stmt
);
1525 if (PG_VERSION_GE(conn
, 7.1))
1526 relisaview
= (relkind
[0] == 'v');
1528 relisaview
= (relhasrules
[0] == '1');
1529 PGAPI_FreeStmt(hcol_stmt
, SQL_DROP
);
1532 res
= QR_Constructor();
1533 SC_set_Result(stmt
, res
);
1534 extend_column_bindings(SC_get_ARDF(stmt
), 8);
1536 stmt
->catalog_result
= TRUE
;
1537 QR_set_num_fields(res
, 8);
1538 QR_set_field_info_v(res
, 0, "SCOPE", PG_TYPE_INT2
, 2);
1539 QR_set_field_info_v(res
, 1, "COLUMN_NAME", PG_TYPE_VARCHAR
,
1541 QR_set_field_info_v(res
, 2, "DATA_TYPE", PG_TYPE_INT2
, 2);
1542 QR_set_field_info_v(res
, 3, "TYPE_NAME", PG_TYPE_VARCHAR
,
1544 QR_set_field_info_v(res
, 4, "PRECISION", PG_TYPE_INT4
, 4);
1545 QR_set_field_info_v(res
, 5, "LENGTH", PG_TYPE_INT4
, 4);
1546 QR_set_field_info_v(res
, 6, "SCALE", PG_TYPE_INT2
, 2);
1547 QR_set_field_info_v(res
, 7, "PSEUDO_COLUMN", PG_TYPE_INT2
, 2);
1551 /* there's no oid for views */
1552 if (fColType
== SQL_BEST_ROWID
)
1556 else if (fColType
== SQL_ROWVER
)
1558 Int2 the_type
= PG_TYPE_TID
;
1560 tuple
= QR_AddNew(res
);
1562 set_tuplefield_null(&tuple
[0]);
1563 set_tuplefield_string(&tuple
[1], "ctid");
1564 set_tuplefield_int2(&tuple
[2],
1565 pgtype_to_concise_type(stmt
, the_type
,
1567 set_tuplefield_string(&tuple
[3],
1568 pgtype_to_name(stmt
, the_type
,
1570 set_tuplefield_int4(&tuple
[4],
1571 pgtype_column_size(stmt
, the_type
,
1574 set_tuplefield_int4(&tuple
[5],
1575 pgtype_buffer_length(stmt
, the_type
,
1578 set_tuplefield_int2(&tuple
[6],
1579 pgtype_decimal_digits(stmt
, the_type
,
1581 set_tuplefield_int2(&tuple
[7], SQL_PC_NOT_PSEUDO
);
1582 inolog("Add ctid\n");
1587 /* use the oid value for the rowid */
1588 if (fColType
== SQL_BEST_ROWID
)
1590 Int2 the_type
= PG_TYPE_OID
;
1592 if (relhasoids
[0] != '1')
1596 tuple
= QR_AddNew(res
);
1598 set_tuplefield_int2(&tuple
[0], SQL_SCOPE_SESSION
);
1599 set_tuplefield_string(&tuple
[1], OID_NAME
);
1600 set_tuplefield_int2(&tuple
[2],
1601 pgtype_to_concise_type(stmt
, the_type
,
1603 set_tuplefield_string(&tuple
[3],
1604 pgtype_to_name(stmt
, the_type
, TRUE
));
1605 set_tuplefield_int4(&tuple
[4],
1606 pgtype_column_size(stmt
, the_type
,
1609 set_tuplefield_int4(&tuple
[5],
1610 pgtype_buffer_length(stmt
, the_type
,
1613 set_tuplefield_int2(&tuple
[6],
1614 pgtype_decimal_digits(stmt
, the_type
,
1616 set_tuplefield_int2(&tuple
[7], SQL_PC_PSEUDO
);
1618 else if (fColType
== SQL_ROWVER
)
1620 Int2 the_type
= PG_TYPE_XID
;
1622 /* if (atoi(ci->row_versioning)) */
1624 tuple
= QR_AddNew(res
);
1626 set_tuplefield_null(&tuple
[0]);
1627 set_tuplefield_string(&tuple
[1], "xmin");
1628 set_tuplefield_int2(&tuple
[2],
1629 pgtype_to_concise_type(stmt
,
1632 set_tuplefield_string(&tuple
[3],
1633 pgtype_to_name(stmt
, the_type
,
1635 set_tuplefield_int4(&tuple
[4],
1636 pgtype_column_size(stmt
, the_type
,
1639 set_tuplefield_int4(&tuple
[5],
1640 pgtype_buffer_length(stmt
, the_type
,
1643 set_tuplefield_int2(&tuple
[6],
1644 pgtype_decimal_digits(stmt
,
1647 set_tuplefield_int2(&tuple
[7], SQL_PC_PSEUDO
);
1655 free(escSchemaName
);
1658 stmt
->status
= STMT_FINISHED
;
1659 stmt
->currTuple
= -1;
1660 SC_set_rowset_start(stmt
, -1, FALSE
);
1661 SC_set_current_col(stmt
, -1);
1663 PGAPI_FreeStmt(hcol_stmt
, SQL_DROP
);
1665 result
= DiscardStatementSvp(stmt
, result
, FALSE
);
1666 mylog("%s: EXIT, stmt=%p\n", func
, stmt
);
1670 RETCODE SQL_API
PGAPI_Statistics(HSTMT hstmt
, const SQLCHAR FAR
* szTableQualifier
, /* OA X */
1671 SQLSMALLINT cbTableQualifier
, const SQLCHAR FAR
* szTableOwner
, /* OA E */
1672 SQLSMALLINT cbTableOwner
, const SQLCHAR FAR
* szTableName
, /* OA(R) E */
1673 SQLSMALLINT cbTableName
,
1674 SQLUSMALLINT fUnique
,
1675 SQLUSMALLINT fAccuracy
)
1677 CSTR func
= "PGAPI_Statistics";
1678 StatementClass
*stmt
= (StatementClass
*) hstmt
;
1679 ConnectionClass
*conn
;
1681 char index_query
[INFO_INQUIRY_LEN
];
1682 HSTMT hcol_stmt
= NULL
, hindx_stmt
= NULL
;
1683 RETCODE ret
= SQL_ERROR
, result
;
1684 char *escSchemaName
= NULL
, *table_name
= NULL
, *escTableName
=
1686 char index_name
[MAX_INFO_STRING
];
1687 short fields_vector
[INDEX_KEYS_STORAGE_COUNT
+ 1];
1688 char isunique
[10], isclustered
[10], ishash
[MAX_INFO_STRING
];
1689 SQLLEN index_name_len
, fields_vector_len
;
1692 StatementClass
*col_stmt
, *indx_stmt
;
1693 char column_name
[MAX_INFO_STRING
],
1694 table_schemaname
[MAX_INFO_STRING
], relhasrules
[10];
1695 struct columns_idx
{
1699 *column_names
= NULL
;
1700 /* char **column_names = NULL; */
1701 SQLLEN column_name_len
;
1702 int total_columns
= 0, alcount
;
1705 SQLSMALLINT internal_asis_type
=
1706 SQL_C_CHAR
, cbSchemaName
, field_number
;
1707 const char *szSchemaName
;
1710 mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func
, stmt
,
1711 NULL_IF_NULL(szTableOwner
), cbTableOwner
);
1713 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
1716 table_name
= make_string(szTableName
, cbTableName
, NULL
, 0);
1719 SC_set_error(stmt
, STMT_INVALID_NULL_ARG
,
1720 "The table name is required", func
);
1723 conn
= SC_get_conn(stmt
);
1724 ci
= &(conn
->connInfo
);
1725 #ifdef UNICODE_SUPPORT
1726 if (CC_is_in_unicode_driver(conn
))
1727 internal_asis_type
= INTERNAL_ASIS_TYPE
;
1728 #endif /* UNICODE_SUPPORT */
1730 if (res
= QR_Constructor(), !res
)
1732 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
1733 "Couldn't allocate memory for PGAPI_Statistics result.",
1737 SC_set_Result(stmt
, res
);
1739 /* the binding structure for a statement is not set up until */
1742 * a statement is actually executed, so we'll have to do this
1745 extend_column_bindings(SC_get_ARDF(stmt
), 13);
1747 stmt
->catalog_result
= TRUE
;
1748 /* set the field names */
1749 QR_set_num_fields(res
, NUM_OF_STATS_FIELDS
);
1750 QR_set_field_info_v(res
, STATS_CATALOG_NAME
, "TABLE_QUALIFIER",
1751 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
1752 QR_set_field_info_v(res
, STATS_SCHEMA_NAME
, "TABLE_OWNER",
1753 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
1754 QR_set_field_info_v(res
, STATS_TABLE_NAME
, "TABLE_NAME",
1755 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
1756 QR_set_field_info_v(res
, STATS_NON_UNIQUE
, "NON_UNIQUE",
1758 QR_set_field_info_v(res
, STATS_INDEX_QUALIFIER
, "INDEX_QUALIFIER",
1759 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
1760 QR_set_field_info_v(res
, STATS_INDEX_NAME
, "INDEX_NAME",
1761 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
1762 QR_set_field_info_v(res
, STATS_TYPE
, "TYPE", PG_TYPE_INT2
, 2);
1763 QR_set_field_info_v(res
, STATS_SEQ_IN_INDEX
, "SEQ_IN_INDEX",
1765 QR_set_field_info_v(res
, STATS_COLUMN_NAME
, "COLUMN_NAME",
1766 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
1767 QR_set_field_info_v(res
, STATS_COLLATION
, "COLLATION", PG_TYPE_CHAR
,
1769 QR_set_field_info_v(res
, STATS_CARDINALITY
, "CARDINALITY",
1771 QR_set_field_info_v(res
, STATS_PAGES
, "PAGES", PG_TYPE_INT4
, 4);
1772 QR_set_field_info_v(res
, STATS_FILTER_CONDITION
, "FILTER_CONDITION",
1773 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
1775 #define return DONT_CALL_RETURN_FROM_HERE???
1776 szSchemaName
= (const char *)szTableOwner
;
1777 cbSchemaName
= cbTableOwner
;
1779 table_schemaname
[0] = '\0';
1780 if (conn
->schema_support
)
1781 schema_strcat(table_schemaname
, "%.*s", szSchemaName
,
1782 cbSchemaName
, (const char *)szTableName
,
1786 * we need to get a list of the field names first, so we can return
1789 result
= PGAPI_AllocStmt(conn
, &hcol_stmt
);
1790 if (!SQL_SUCCEEDED(result
))
1792 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
1793 "PGAPI_AllocStmt failed in PGAPI_Statistics for columns.",
1798 col_stmt
= (StatementClass
*) hcol_stmt
;
1801 * "internal" prevents SQLColumns from returning the oid if it is
1802 * being shown. This would throw everything off.
1804 col_stmt
->internal
= TRUE
;
1806 * table_name parameter cannot contain a string search pattern.
1809 PGAPI_Columns(hcol_stmt
, NULL
, 0,
1810 (const UCHAR
*)table_schemaname
, SQL_NTS
,
1811 (const UCHAR
*)table_name
, SQL_NTS
, NULL
, 0,
1812 PODBC_NOT_SEARCH_PATTERN
|
1813 PODBC_SEARCH_PUBLIC_SCHEMA
, 0, 0);
1814 col_stmt
->internal
= FALSE
;
1816 if (!SQL_SUCCEEDED(result
))
1818 SC_error_copy(stmt
, col_stmt
, TRUE
);
1822 PGAPI_BindCol(hcol_stmt
, COLUMNS_COLUMN_NAME
+ 1,
1823 internal_asis_type
, column_name
,
1824 sizeof(column_name
), &column_name_len
);
1825 if (!SQL_SUCCEEDED(result
))
1827 SC_error_copy(stmt
, col_stmt
, TRUE
);
1831 PGAPI_BindCol(hcol_stmt
, COLUMNS_PHYSICAL_NUMBER
+ 1,
1832 SQL_C_SHORT
, &field_number
, sizeof(field_number
),
1834 if (!SQL_SUCCEEDED(result
))
1836 SC_error_copy(stmt
, col_stmt
, TRUE
);
1841 result
= PGAPI_Fetch(hcol_stmt
);
1842 while (SQL_SUCCEEDED(result
))
1844 if (0 == total_columns
)
1845 PGAPI_GetData(hcol_stmt
, 2, internal_asis_type
,
1846 table_schemaname
, sizeof(table_schemaname
),
1849 if (total_columns
>= alcount
)
1856 (struct columns_idx
*) realloc(column_names
,
1861 column_names
[total_columns
].col_name
=
1862 (char *) malloc(strlen(column_name
) + 1);
1863 strcpy(column_names
[total_columns
].col_name
, column_name
);
1864 column_names
[total_columns
].pnum
= field_number
;
1867 mylog("%s: column_name = '%s'\n", func
, column_name
);
1869 result
= PGAPI_Fetch(hcol_stmt
);
1872 if (result
!= SQL_NO_DATA_FOUND
)
1874 SC_full_error_copy(stmt
, col_stmt
, FALSE
);
1877 PGAPI_FreeStmt(hcol_stmt
, SQL_DROP
);
1879 if (total_columns
== 0)
1881 /* Couldn't get column names in SQLStatistics.; */
1886 /* get a list of indexes on this table */
1887 result
= PGAPI_AllocStmt(conn
, &hindx_stmt
);
1888 if (!SQL_SUCCEEDED(result
))
1890 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
1891 "PGAPI_AllocStmt failed in SQLStatistics for indices.",
1896 indx_stmt
= (StatementClass
*) hindx_stmt
;
1898 /* TableName cannot contain a string search pattern */
1899 escTableName
= simpleCatalogEscape(table_name
, SQL_NTS
, NULL
, conn
);
1900 if (conn
->schema_support
)
1903 simpleCatalogEscape(table_schemaname
, SQL_NTS
, NULL
, conn
);
1904 snprintf(index_query
, sizeof(index_query
),
1905 "select c.relname, i.indkey, i.indisunique"
1906 ", i.indisclustered, a.amname, c.relhasrules, n.nspname"
1908 " from pg_catalog.pg_index i, pg_catalog.pg_class c,"
1909 " pg_catalog.pg_class d, pg_catalog.pg_am a,"
1910 " pg_catalog.pg_namespace n" " where d.relname = '%s'"
1911 " and n.nspname = '%s'" " and n.oid = d.relnamespace"
1912 " and d.oid = i.indrelid" " and i.indexrelid = c.oid"
1913 " and c.relam = a.oid order by", escTableName
,
1917 snprintf(index_query
, sizeof(index_query
),
1918 "select c.relname, i.indkey, i.indisunique"
1919 ", i.indisclustered, a.amname, c.relhasrules, c.oid"
1920 " from pg_index i, pg_class c, pg_class d, pg_am a"
1921 " where d.relname = '%s'" " and d.oid = i.indrelid"
1922 " and i.indexrelid = c.oid"
1923 " and c.relam = a.oid order by", escTableName
);
1924 if (PG_VERSION_GT(SC_get_conn(stmt
), 6.4))
1925 strcat(index_query
, " i.indisprimary desc,");
1926 if (conn
->schema_support
)
1927 strcat(index_query
, " i.indisunique, n.nspname, c.relname");
1929 strcat(index_query
, " i.indisunique, c.relname");
1931 result
= PGAPI_ExecDirect(hindx_stmt
, (const UCHAR
*)index_query
, SQL_NTS
, 0);
1932 if (!SQL_SUCCEEDED(result
))
1935 * "Couldn't execute index query (w/SQLExecDirect) in
1938 SC_full_error_copy(stmt
, indx_stmt
, FALSE
);
1942 /* bind the index name column */
1943 result
= PGAPI_BindCol(hindx_stmt
, 1, internal_asis_type
,
1944 index_name
, MAX_INFO_STRING
,
1946 if (!SQL_SUCCEEDED(result
))
1948 SC_error_copy(stmt
, indx_stmt
, TRUE
); /* "Couldn't bind column
1949 * in SQLStatistics."; */
1953 /* bind the vector column */
1954 result
= PGAPI_BindCol(hindx_stmt
, 2, SQL_C_DEFAULT
,
1955 fields_vector
, sizeof(fields_vector
),
1956 &fields_vector_len
);
1957 if (!SQL_SUCCEEDED(result
))
1959 SC_error_copy(stmt
, indx_stmt
, TRUE
); /* "Couldn't bind column
1960 * in SQLStatistics."; */
1964 /* bind the "is unique" column */
1965 result
= PGAPI_BindCol(hindx_stmt
, 3, internal_asis_type
,
1966 isunique
, sizeof(isunique
), NULL
);
1967 if (!SQL_SUCCEEDED(result
))
1969 SC_error_copy(stmt
, indx_stmt
, TRUE
); /* "Couldn't bind column
1970 * in SQLStatistics."; */
1974 /* bind the "is clustered" column */
1975 result
= PGAPI_BindCol(hindx_stmt
, 4, internal_asis_type
,
1976 isclustered
, sizeof(isclustered
), NULL
);
1977 if (!SQL_SUCCEEDED(result
))
1979 SC_error_copy(stmt
, indx_stmt
, TRUE
); /* "Couldn't bind column *
1980 * in SQLStatistics."; */
1985 /* bind the "is hash" column */
1986 result
= PGAPI_BindCol(hindx_stmt
, 5, internal_asis_type
,
1987 ishash
, sizeof(ishash
), NULL
);
1988 if (!SQL_SUCCEEDED(result
))
1990 SC_error_copy(stmt
, indx_stmt
, TRUE
); /* "Couldn't bind column *
1991 * in SQLStatistics."; */
1996 result
= PGAPI_BindCol(hindx_stmt
, 6, internal_asis_type
,
1997 relhasrules
, sizeof(relhasrules
), NULL
);
1998 if (!SQL_SUCCEEDED(result
))
2000 SC_error_copy(stmt
, indx_stmt
, TRUE
);
2004 result
= PGAPI_BindCol(hindx_stmt
, 8, SQL_C_ULONG
,
2005 &ioid
, sizeof(ioid
), NULL
);
2006 if (!SQL_SUCCEEDED(result
))
2008 SC_error_copy(stmt
, indx_stmt
, TRUE
);
2012 relhasrules
[0] = '0';
2013 result
= PGAPI_Fetch(hindx_stmt
);
2014 /* fake index of OID */
2015 if (relhasrules
[0] != '1' && atoi(ci
->show_oid_column
)
2016 && atoi(ci
->fake_oid_index
))
2018 tuple
= QR_AddNew(res
);
2020 /* no table qualifier */
2021 set_tuplefield_string(&tuple
[STATS_CATALOG_NAME
],
2023 /* don't set the table owner, else Access tries to use it */
2024 set_tuplefield_string(&tuple
[STATS_SCHEMA_NAME
],
2025 GET_SCHEMA_NAME(table_schemaname
));
2026 set_tuplefield_string(&tuple
[STATS_TABLE_NAME
], table_name
);
2028 /* non-unique index? */
2029 set_tuplefield_int2(&tuple
[STATS_NON_UNIQUE
], (Int2
)FALSE
);
2031 /* no index qualifier */
2032 set_tuplefield_string(&tuple
[STATS_INDEX_QUALIFIER
],
2035 snprintf(buf
, sizeof(table_name
), "%s_idx_fake_oid",
2037 set_tuplefield_string(&tuple
[STATS_INDEX_NAME
], buf
);
2040 * Clustered/HASH index?
2042 set_tuplefield_int2(&tuple
[STATS_TYPE
], (Int2
) SQL_INDEX_OTHER
);
2043 set_tuplefield_int2(&tuple
[STATS_SEQ_IN_INDEX
], (Int2
) 1);
2045 set_tuplefield_string(&tuple
[STATS_COLUMN_NAME
], OID_NAME
);
2046 set_tuplefield_string(&tuple
[STATS_COLLATION
], "A");
2047 set_tuplefield_null(&tuple
[STATS_CARDINALITY
]);
2048 set_tuplefield_null(&tuple
[STATS_PAGES
]);
2049 set_tuplefield_null(&tuple
[STATS_FILTER_CONDITION
]);
2052 while (SQL_SUCCEEDED(result
))
2054 /* If only requesting unique indexs, then just return those. */
2055 if (fUnique
== SQL_INDEX_ALL
||
2056 (fUnique
== SQL_INDEX_UNIQUE
&& atoi(isunique
)))
2060 /* add a row in this table for each field in the index */
2061 colcnt
= fields_vector
[0];
2062 for (i
= 1; i
<= colcnt
; i
++)
2064 tuple
= QR_AddNew(res
);
2066 /* no table qualifier */
2067 set_tuplefield_string(&tuple
[STATS_CATALOG_NAME
],
2069 /* don't set the table owner, else Access tries to use it */
2070 set_tuplefield_string(&tuple
[STATS_SCHEMA_NAME
],
2072 (table_schemaname
));
2073 set_tuplefield_string(&tuple
[STATS_TABLE_NAME
],
2076 /* non-unique index? */
2077 set_tuplefield_int2(&tuple
[STATS_NON_UNIQUE
],
2078 (Int2
) (atoi(isunique
) ? FALSE
:
2081 /* no index qualifier */
2082 set_tuplefield_string(&tuple
[STATS_INDEX_QUALIFIER
],
2084 set_tuplefield_string(&tuple
[STATS_INDEX_NAME
],
2088 * Clustered/HASH index?
2090 set_tuplefield_int2(&tuple
[STATS_TYPE
], (Int2
)
2091 (atoi(isclustered
) ?
2093 : (!strncmp(ishash
, "hash", 4)) ?
2096 set_tuplefield_int2(&tuple
[STATS_SEQ_IN_INDEX
],
2099 attnum
= fields_vector
[i
];
2100 if (OID_ATTNUM
== attnum
)
2102 set_tuplefield_string(&tuple
[STATS_COLUMN_NAME
],
2104 mylog("%s: column name = oid\n", func
);
2106 else if (0 == attnum
)
2112 snprintf(cmd
, sizeof(cmd
),
2113 "select pg_get_indexdef(%u, %d, true)",
2116 CC_send_query(conn
, cmd
, NULL
,
2117 IGNORE_ABORT_ON_CONN
, stmt
);
2118 if (QR_command_maybe_successful(res
))
2119 set_tuplefield_string(&tuple
[STATS_COLUMN_NAME
],
2120 QR_get_value_backend_text
2127 BOOL unknownf
= TRUE
;
2131 for (j
= 0; j
< total_columns
; j
++)
2133 if (attnum
== column_names
[j
].pnum
)
2143 set_tuplefield_string(&tuple
[STATS_COLUMN_NAME
],
2145 mylog("%s: column name = UNKNOWN\n", func
);
2149 set_tuplefield_string(&tuple
[STATS_COLUMN_NAME
],
2150 column_names
[matchidx
].
2152 mylog("%s: column name = '%s'\n", func
,
2153 column_names
[matchidx
].col_name
);
2157 set_tuplefield_string(&tuple
[STATS_COLLATION
], "A");
2158 set_tuplefield_null(&tuple
[STATS_CARDINALITY
]);
2159 set_tuplefield_null(&tuple
[STATS_PAGES
]);
2160 set_tuplefield_null(&tuple
[STATS_FILTER_CONDITION
]);
2164 result
= PGAPI_Fetch(hindx_stmt
);
2166 if (result
!= SQL_NO_DATA_FOUND
)
2168 /* "SQLFetch failed in SQLStatistics."; */
2169 SC_full_error_copy(stmt
, indx_stmt
, FALSE
);
2177 * also, things need to think that this statement is finished so the
2178 * results can be retrieved.
2180 stmt
->status
= STMT_FINISHED
;
2183 PGAPI_FreeStmt(hcol_stmt
, SQL_DROP
);
2185 PGAPI_FreeStmt(hindx_stmt
, SQL_DROP
);
2186 /* These things should be freed on any error ALSO! */
2192 free(escSchemaName
);
2195 for (i
= 0; i
< total_columns
; i
++)
2196 free(column_names
[i
].col_name
);
2200 /* set up the current tuple pointer for SQLFetch */
2201 stmt
->currTuple
= -1;
2202 SC_set_rowset_start(stmt
, -1, FALSE
);
2203 SC_set_current_col(stmt
, -1);
2206 ret
= DiscardStatementSvp(stmt
, ret
, FALSE
);
2207 mylog("%s: EXIT, stmt=%p, ret=%d\n", func
, stmt
, ret
);
2212 RETCODE SQL_API
PGAPI_ColumnPrivileges(HSTMT hstmt
, const SQLCHAR FAR
* szTableQualifier
, /* OA X */
2213 SQLSMALLINT cbTableQualifier
, const SQLCHAR FAR
* szTableOwner
, /* OA E */
2214 SQLSMALLINT cbTableOwner
, const SQLCHAR FAR
* szTableName
, /* OA(R) E */
2215 SQLSMALLINT cbTableName
, const SQLCHAR FAR
* szColumnName
, /* PV E */
2216 SQLSMALLINT cbColumnName
,
2219 CSTR func
= "PGAPI_ColumnPrivileges";
2220 StatementClass
*stmt
= (StatementClass
*) hstmt
;
2221 ConnectionClass
*conn
= SC_get_conn(stmt
);
2222 RETCODE result
= SQL_ERROR
;
2223 char *escSchemaName
= NULL
, *escTableName
= NULL
, *escColumnName
=
2225 const char *like_or_eq
;
2226 char column_query
[INFO_INQUIRY_LEN
];
2227 size_t cq_len
, cq_size
;
2229 BOOL search_pattern
;
2232 mylog("%s: entering...\n", func
);
2234 /* Neither Access or Borland care about this. */
2236 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
2238 if (PG_VERSION_LT(conn
, 7.4))
2239 SC_set_error(stmt
, STMT_NOT_IMPLEMENTED_ERROR
,
2240 "Function not implementedyet", func
);
2242 simpleCatalogEscape(szTableOwner
, cbTableOwner
, NULL
, conn
);
2244 simpleCatalogEscape(szTableName
, cbTableName
, NULL
, conn
);
2245 search_pattern
= (0 == (flag
& PODBC_NOT_SEARCH_PATTERN
));
2248 like_or_eq
= likeop
;
2250 adjustLikePattern(szColumnName
, cbColumnName
,
2251 SEARCH_PATTERN_ESCAPE
, NULL
, conn
);
2257 simpleCatalogEscape(szColumnName
, cbColumnName
, NULL
, conn
);
2259 strcpy(column_query
,
2260 "select '' as TABLE_CAT, table_schema as TABLE_SCHEM,"
2261 " table_name, column_name, grantor, grantee,"
2262 " privilege_type as PRIVILEGE, is_grantable from"
2263 " information_schema.column_privileges where true");
2264 cq_len
= strlen(column_query
);
2265 cq_size
= sizeof(column_query
);
2266 col_query
= column_query
;
2269 col_query
+= cq_len
;
2271 cq_len
= snprintf_len(col_query
, cq_size
,
2272 " and table_schem = '%s'", escSchemaName
);
2277 col_query
+= cq_len
;
2279 cq_len
+= snprintf_len(col_query
, cq_size
,
2280 " and table_name = '%s'", escTableName
);
2284 col_query
+= cq_len
;
2286 cq_len
+= snprintf_len(col_query
, cq_size
,
2287 " and column_name %s '%s'", like_or_eq
,
2291 CC_send_query(conn
, column_query
, NULL
, IGNORE_ABORT_ON_CONN
,
2292 stmt
), !QR_command_maybe_successful(res
))
2294 SC_set_error(stmt
, STMT_EXEC_ERROR
,
2295 "PGAPI_ColumnPrivileges query error", func
);
2299 SC_set_Result(stmt
, res
);
2302 * also, things need to think that this statement is finished so the
2303 * results can be retrieved.
2305 extend_column_bindings(SC_get_ARDF(stmt
), 8);
2306 /* set up the current tuple pointer for SQLFetch */
2307 result
= SQL_SUCCESS
;
2309 /* set up the current tuple pointer for SQLFetch */
2310 stmt
->status
= STMT_FINISHED
;
2311 stmt
->currTuple
= -1;
2312 SC_set_rowset_start(stmt
, -1, FALSE
);
2314 free(escSchemaName
);
2318 free(escColumnName
);
2325 * Retrieve the primary key columns for the specified table.
2327 RETCODE SQL_API
PGAPI_PrimaryKeys(HSTMT hstmt
, const SQLCHAR FAR
* szTableQualifier
, /* OA X */
2328 SQLSMALLINT cbTableQualifier
, const SQLCHAR FAR
* szTableOwner
, /* OA E */
2329 SQLSMALLINT cbTableOwner
, const SQLCHAR FAR
* szTableName
, /* OA(R) E */
2330 SQLSMALLINT cbTableName
)
2332 StatementClass
*stmt
= (StatementClass
*)hstmt
;
2334 VxStatement
st(stmt
);
2337 rs
.runquery(st
.dbus(), "ExecChunkRecordset",
2338 WvString("sp_primary_keys_rowset '%s'",
2339 (const char *)szTableName
));
2341 stmt
->catalog_result
= TRUE
;
2342 return st
.retcode();
2346 * Multibyte support stuff for SQLForeignKeys().
2347 * There may be much more effective way in the
2348 * future version. The way is very forcible currently.
2350 static BOOL
isMultibyte(const UCHAR
* str
)
2359 static char *getClientColumnName(ConnectionClass
* conn
, UInt4 relid
,
2360 char *serverColumnName
,
2363 char query
[1024], saveattnum
[16], *ret
= serverColumnName
;
2364 BOOL continueExec
= TRUE
, bError
= FALSE
;
2365 QResultClass
*res
= NULL
;
2366 UWORD flag
= IGNORE_ABORT_ON_CONN
| ROLLBACK_ON_ERROR
;
2368 *nameAlloced
= FALSE
;
2369 if (!conn
->original_client_encoding
2370 || !isMultibyte((const UCHAR
*)serverColumnName
))
2372 if (!conn
->server_encoding
)
2375 CC_send_query(conn
, "select getdatabaseencoding()", NULL
,
2376 flag
, NULL
), QR_command_maybe_successful(res
))
2378 if (QR_get_num_cached_tuples(res
) > 0)
2379 conn
->server_encoding
=
2380 strdup(QR_get_value_backend_text(res
, 0, 0));
2385 if (!conn
->server_encoding
)
2387 snprintf(query
, sizeof(query
), "SET CLIENT_ENCODING TO '%s'",
2388 conn
->server_encoding
);
2390 (!QR_command_maybe_successful
2391 ((res
= CC_send_query(conn
, query
, NULL
, flag
, NULL
))));
2393 if (!bError
&& continueExec
)
2395 snprintf(query
, sizeof(query
),
2396 "select attnum from pg_attribute "
2397 "where attrelid = %u and attname = '%s'", relid
,
2400 CC_send_query(conn
, query
, NULL
, flag
, NULL
),
2401 QR_command_maybe_successful(res
))
2403 if (QR_get_num_cached_tuples(res
) > 0)
2406 QR_get_value_backend_text(res
, 0, 0));
2409 continueExec
= FALSE
;
2415 continueExec
= (continueExec
&& !bError
);
2416 /* restore the cleint encoding */
2417 snprintf(query
, sizeof(query
), "SET CLIENT_ENCODING TO '%s'",
2418 conn
->original_client_encoding
);
2420 (!QR_command_maybe_successful
2421 ((res
= CC_send_query(conn
, query
, NULL
, flag
, NULL
))));
2423 if (bError
|| !continueExec
)
2425 snprintf(query
, sizeof(query
),
2426 "select attname from pg_attribute where attrelid = %u and attnum = %s",
2429 CC_send_query(conn
, query
, NULL
, flag
, NULL
),
2430 QR_command_maybe_successful(res
))
2432 if (QR_get_num_cached_tuples(res
) > 0)
2434 ret
= strdup(QR_get_value_backend_text(res
, 0, 0));
2435 *nameAlloced
= TRUE
;
2442 RETCODE SQL_API
PGAPI_ForeignKeys(HSTMT hstmt
, const SQLCHAR FAR
* szPkTableQualifier
, /* OA X */
2443 SQLSMALLINT cbPkTableQualifier
, const SQLCHAR FAR
* szPkTableOwner
, /* OA E */
2444 SQLSMALLINT cbPkTableOwner
, const SQLCHAR FAR
* szPkTableName
, /* OA(R) E */
2445 SQLSMALLINT cbPkTableName
, const SQLCHAR FAR
* szFkTableQualifier
, /* OA X */
2446 SQLSMALLINT cbFkTableQualifier
, const SQLCHAR FAR
* szFkTableOwner
, /* OA E */
2447 SQLSMALLINT cbFkTableOwner
, const SQLCHAR FAR
* szFkTableName
, /* OA(R) E */
2448 SQLSMALLINT cbFkTableName
)
2450 CSTR func
= "PGAPI_ForeignKeys";
2451 StatementClass
*stmt
= (StatementClass
*) hstmt
;
2454 HSTMT htbl_stmt
= NULL
, hpkey_stmt
= NULL
;
2455 StatementClass
*tbl_stmt
;
2456 RETCODE ret
= SQL_ERROR
, result
, keyresult
;
2457 char tables_query
[INFO_INQUIRY_LEN
];
2458 char trig_deferrable
[2];
2459 char trig_initdeferred
[2];
2460 char trig_args
[1024];
2461 char upd_rule
[TABLE_NAME_STORAGE_LEN
],
2462 del_rule
[TABLE_NAME_STORAGE_LEN
];
2463 char *pk_table_needed
= NULL
, *escPkTableName
= NULL
;
2464 char fk_table_fetched
[TABLE_NAME_STORAGE_LEN
+ 1];
2465 char *fk_table_needed
= NULL
, *escFkTableName
= NULL
;
2466 char pk_table_fetched
[TABLE_NAME_STORAGE_LEN
+ 1];
2467 char schema_needed
[SCHEMA_NAME_STORAGE_LEN
+ 1];
2468 char schema_fetched
[SCHEMA_NAME_STORAGE_LEN
+ 1];
2469 char constrname
[NAMESTORAGELEN
+ 1],
2470 pkname
[TABLE_NAME_STORAGE_LEN
+ 1];
2471 char *pkey_ptr
, *pkey_text
= NULL
, *fkey_ptr
, *fkey_text
= NULL
;
2473 ConnectionClass
*conn
;
2474 BOOL pkey_alloced
, fkey_alloced
, got_pkname
;
2475 int i
, j
, k
, num_keys
;
2476 SQLSMALLINT trig_nargs
, upd_rule_type
= 0, del_rule_type
= 0;
2477 SQLSMALLINT internal_asis_type
= SQL_C_CHAR
;
2479 SQLSMALLINT defer_type
;
2480 char pkey
[MAX_INFO_STRING
];
2482 UInt4 relid1
, relid2
;
2484 mylog("%s: entering...stmt=%p\n", func
, stmt
);
2486 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
2489 if (res
= QR_Constructor(), !res
)
2491 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
2492 "Couldn't allocate memory for PGAPI_ForeignKeys result.",
2496 SC_set_Result(stmt
, res
);
2498 /* the binding structure for a statement is not set up until */
2501 * a statement is actually executed, so we'll have to do this
2504 result_cols
= NUM_OF_FKS_FIELDS
;
2505 extend_column_bindings(SC_get_ARDF(stmt
), result_cols
);
2507 stmt
->catalog_result
= TRUE
;
2508 /* set the field names */
2509 QR_set_num_fields(res
, result_cols
);
2510 QR_set_field_info_v(res
, FKS_PKTABLE_CAT
, "PKTABLE_QUALIFIER",
2511 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2512 QR_set_field_info_v(res
, FKS_PKTABLE_SCHEM
, "PKTABLE_OWNER",
2513 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2514 QR_set_field_info_v(res
, FKS_PKTABLE_NAME
, "PKTABLE_NAME",
2515 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2516 QR_set_field_info_v(res
, FKS_PKCOLUMN_NAME
, "PKCOLUMN_NAME",
2517 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2518 QR_set_field_info_v(res
, FKS_FKTABLE_CAT
, "FKTABLE_QUALIFIER",
2519 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2520 QR_set_field_info_v(res
, FKS_FKTABLE_SCHEM
, "FKTABLE_OWNER",
2521 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2522 QR_set_field_info_v(res
, FKS_FKTABLE_NAME
, "FKTABLE_NAME",
2523 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2524 QR_set_field_info_v(res
, FKS_FKCOLUMN_NAME
, "FKCOLUMN_NAME",
2525 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2526 QR_set_field_info_v(res
, FKS_KEY_SEQ
, "KEY_SEQ", PG_TYPE_INT2
, 2);
2527 QR_set_field_info_v(res
, FKS_UPDATE_RULE
, "UPDATE_RULE",
2529 QR_set_field_info_v(res
, FKS_DELETE_RULE
, "DELETE_RULE",
2531 QR_set_field_info_v(res
, FKS_FK_NAME
, "FK_NAME", PG_TYPE_VARCHAR
,
2533 QR_set_field_info_v(res
, FKS_PK_NAME
, "PK_NAME", PG_TYPE_VARCHAR
,
2535 QR_set_field_info_v(res
, FKS_DEFERRABILITY
, "DEFERRABILITY",
2537 QR_set_field_info_v(res
, FKS_TRIGGER_NAME
, "TRIGGER_NAME",
2538 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
2541 * also, things need to think that this statement is finished so the
2542 * results can be retrieved.
2544 stmt
->status
= STMT_FINISHED
;
2546 /* set up the current tuple pointer for SQLFetch */
2547 stmt
->currTuple
= -1;
2548 SC_set_rowset_start(stmt
, -1, FALSE
);
2549 SC_set_current_col(stmt
, -1);
2551 conn
= SC_get_conn(stmt
);
2552 result
= PGAPI_AllocStmt(conn
, &htbl_stmt
);
2553 if (!SQL_SUCCEEDED(result
))
2555 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
2556 "Couldn't allocate statement for PGAPI_ForeignKeys result.",
2560 #define return DONT_CALL_RETURN_FROM_HERE???
2562 tbl_stmt
= (StatementClass
*) htbl_stmt
;
2563 schema_needed
[0] = '\0';
2564 schema_fetched
[0] = '\0';
2567 make_string(szPkTableName
, cbPkTableName
, NULL
, 0);
2569 make_string(szFkTableName
, cbFkTableName
, NULL
, 0);
2571 #ifdef UNICODE_SUPPORT
2572 if (CC_is_in_unicode_driver(conn
))
2573 internal_asis_type
= INTERNAL_ASIS_TYPE
;
2574 #endif /* UNICODE_SUPPORT */
2575 pkey_alloced
= fkey_alloced
= FALSE
;
2578 * Case #2 -- Get the foreign keys in the specified table (fktab) that
2579 * refer to the primary keys of other table(s).
2581 if (fk_table_needed
&& fk_table_needed
[0] != '\0')
2583 mylog("%s: entering Foreign Key Case #2", func
);
2585 simpleCatalogEscape(fk_table_needed
, SQL_NTS
, NULL
, conn
);
2586 if (conn
->schema_support
)
2588 char *escSchemaName
;
2590 schema_strcat(schema_needed
, "%.*s", (const char *)szFkTableOwner
,
2591 cbFkTableOwner
, (const char *)szFkTableName
,
2592 cbFkTableName
, conn
);
2594 simpleCatalogEscape(schema_needed
, SQL_NTS
, NULL
, conn
);
2595 snprintf(tables_query
, sizeof(tables_query
),
2596 "SELECT pt.tgargs, "
2598 " pt.tgdeferrable, "
2599 " pt.tginitdeferred, "
2605 " pt.tgconstrname, pn.nspname "
2606 "FROM pg_catalog.pg_class pc, "
2607 " pg_catalog.pg_proc pp1, "
2608 " pg_catalog.pg_proc pp2, "
2609 " pg_catalog.pg_trigger pt1, "
2610 " pg_catalog.pg_trigger pt2, "
2611 " pg_catalog.pg_proc pp, "
2612 " pg_catalog.pg_trigger pt, "
2613 " pg_catalog.pg_class pc1, "
2614 " pg_catalog.pg_namespace pn, "
2615 " pg_catalog.pg_namespace pn1 "
2616 "WHERE pt.tgrelid = pc.oid "
2617 "AND pp.oid = pt.tgfoid "
2618 "AND pt1.tgconstrrelid = pc.oid "
2619 "AND pp1.oid = pt1.tgfoid "
2620 "AND pt2.tgfoid = pp2.oid "
2621 "AND pt2.tgconstrrelid = pc.oid "
2622 "AND ((pc.relname='%s') "
2623 "AND (pn1.oid = pc.relnamespace) "
2624 "AND (pn1.nspname = '%s') "
2625 "AND (pp.proname LIKE '%%ins') "
2626 "AND (pp1.proname LIKE '%%upd') "
2627 "AND (pp1.proname not LIKE '%%check%%') "
2628 "AND (pp2.proname LIKE '%%del') "
2629 "AND (pt1.tgrelid=pt.tgconstrrelid) "
2630 "AND (pt1.tgconstrname=pt.tgconstrname) "
2631 "AND (pt2.tgrelid=pt.tgconstrrelid) "
2632 "AND (pt2.tgconstrname=pt.tgconstrname) "
2633 "AND (pt.tgconstrrelid=pc1.oid) "
2634 "AND (pc1.relnamespace=pn.oid))"
2635 " order by pt.tgconstrname",
2636 escFkTableName
, escSchemaName
);
2637 free(escSchemaName
);
2640 snprintf(tables_query
, sizeof(tables_query
),
2641 "SELECT pt.tgargs, "
2643 " pt.tgdeferrable, "
2644 " pt.tginitdeferred, "
2649 " pc1.relname, pt.tgconstrname "
2650 "FROM pg_class pc, "
2658 "WHERE pt.tgrelid = pc.oid "
2659 "AND pp.oid = pt.tgfoid "
2660 "AND pt1.tgconstrrelid = pc.oid "
2661 "AND pp1.oid = pt1.tgfoid "
2662 "AND pt2.tgfoid = pp2.oid "
2663 "AND pt2.tgconstrrelid = pc.oid "
2664 "AND ((pc.relname='%s') "
2665 "AND (pp.proname LIKE '%%ins') "
2666 "AND (pp1.proname LIKE '%%upd') "
2667 "AND (pp1.proname not LIKE '%%check%%') "
2668 "AND (pp2.proname LIKE '%%del') "
2669 "AND (pt1.tgrelid=pt.tgconstrrelid) "
2670 "AND (pt1.tgconstrname=pt.tgconstrname) "
2671 "AND (pt2.tgrelid=pt.tgconstrrelid) "
2672 "AND (pt2.tgconstrname=pt.tgconstrname) "
2673 "AND (pt.tgconstrrelid=pc1.oid)) "
2674 "order by pt.tgconstrname", escFkTableName
);
2676 result
= PGAPI_ExecDirect(htbl_stmt
,
2677 (const UCHAR
*)tables_query
, SQL_NTS
, 0);
2679 if (!SQL_SUCCEEDED(result
))
2681 SC_full_error_copy(stmt
, tbl_stmt
, FALSE
);
2685 result
= PGAPI_BindCol(htbl_stmt
, 1, SQL_C_BINARY
,
2686 trig_args
, sizeof(trig_args
), NULL
);
2687 if (!SQL_SUCCEEDED(result
))
2689 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
2693 result
= PGAPI_BindCol(htbl_stmt
, 2, SQL_C_SHORT
,
2694 &trig_nargs
, 0, NULL
);
2695 if (!SQL_SUCCEEDED(result
))
2697 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
2701 result
= PGAPI_BindCol(htbl_stmt
, 3, internal_asis_type
,
2702 trig_deferrable
, sizeof(trig_deferrable
),
2704 if (!SQL_SUCCEEDED(result
))
2706 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
2710 result
= PGAPI_BindCol(htbl_stmt
, 4, internal_asis_type
,
2712 sizeof(trig_initdeferred
), NULL
);
2713 if (!SQL_SUCCEEDED(result
))
2715 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
2719 result
= PGAPI_BindCol(htbl_stmt
, 5, internal_asis_type
,
2720 upd_rule
, sizeof(upd_rule
), NULL
);
2721 if (!SQL_SUCCEEDED(result
))
2723 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
2727 result
= PGAPI_BindCol(htbl_stmt
, 6, internal_asis_type
,
2728 del_rule
, sizeof(del_rule
), NULL
);
2729 if (!SQL_SUCCEEDED(result
))
2731 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
2735 result
= PGAPI_BindCol(htbl_stmt
, 7, SQL_C_ULONG
,
2736 &relid1
, sizeof(relid1
), NULL
);
2737 if (!SQL_SUCCEEDED(result
))
2739 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
2742 result
= PGAPI_BindCol(htbl_stmt
, 8, SQL_C_ULONG
,
2743 &relid2
, sizeof(relid2
), NULL
);
2744 if (!SQL_SUCCEEDED(result
))
2746 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
2749 result
= PGAPI_BindCol(htbl_stmt
, 9, internal_asis_type
,
2750 pk_table_fetched
, TABLE_NAME_STORAGE_LEN
,
2752 if (!SQL_SUCCEEDED(result
))
2754 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
2757 result
= PGAPI_BindCol(htbl_stmt
, 10, internal_asis_type
,
2758 constrname
, NAMESTORAGELEN
, NULL
);
2759 if (!SQL_SUCCEEDED(result
))
2761 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
2765 if (conn
->schema_support
)
2767 result
= PGAPI_BindCol(htbl_stmt
, 11, internal_asis_type
,
2769 SCHEMA_NAME_STORAGE_LEN
, NULL
);
2770 if (!SQL_SUCCEEDED(result
))
2772 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
2777 result
= PGAPI_Fetch(htbl_stmt
);
2778 if (result
== SQL_NO_DATA_FOUND
)
2784 if (result
!= SQL_SUCCESS
)
2786 SC_full_error_copy(stmt
, tbl_stmt
, FALSE
);
2790 keyresult
= PGAPI_AllocStmt(conn
, &hpkey_stmt
);
2791 if (!SQL_SUCCEEDED(keyresult
))
2793 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
2794 "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.",
2799 keyresult
= PGAPI_BindCol(hpkey_stmt
, 4, internal_asis_type
,
2800 pkey
, sizeof(pkey
), NULL
);
2801 if (keyresult
!= SQL_SUCCESS
)
2803 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
2804 "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.",
2809 while (result
== SQL_SUCCESS
)
2811 /* Compute the number of keyparts. */
2812 num_keys
= (trig_nargs
- 4) / 2;
2815 ("Foreign Key Case#2: trig_nargs = %d, num_keys = %d\n",
2816 trig_nargs
, num_keys
);
2818 /* If there is a pk table specified, then check it. */
2819 if (pk_table_needed
&& pk_table_needed
[0] != '\0')
2821 /* If it doesn't match, then continue */
2822 if (strcmp(pk_table_fetched
, pk_table_needed
))
2824 result
= PGAPI_Fetch(htbl_stmt
);
2831 PGAPI_PrimaryKeys(hpkey_stmt
, NULL
, 0,
2832 (const UCHAR
*)schema_fetched
,
2833 SQL_NTS
, (const UCHAR
*)pk_table_fetched
,
2835 if (keyresult
!= SQL_SUCCESS
)
2837 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
2838 "Couldn't get primary keys for PGAPI_ForeignKeys result.",
2843 /* Get to first primary key */
2844 pkey_ptr
= trig_args
;
2845 for (i
= 0; i
< 5; i
++)
2846 pkey_ptr
+= strlen(pkey_ptr
) + 1;
2848 for (k
= 0; k
< num_keys
; k
++)
2850 /* Check that the key listed is the primary key */
2851 keyresult
= PGAPI_Fetch(hpkey_stmt
);
2852 if (keyresult
!= SQL_SUCCESS
)
2859 PGAPI_GetData(hpkey_stmt
, 6, internal_asis_type
,
2860 pkname
, sizeof(pkname
), NULL
);
2864 getClientColumnName(conn
, relid2
, pkey_ptr
,
2866 mylog("%s: pkey_ptr='%s', pkey='%s'\n", func
, pkey_text
,
2868 if (strcmp(pkey_text
, pkey
))
2875 /* Get to next primary key */
2876 for (k
= 0; k
< 2; k
++)
2877 pkey_ptr
+= strlen(pkey_ptr
) + 1;
2880 PGAPI_FreeStmt(hpkey_stmt
, SQL_CLOSE
);
2882 /* Set to first fk column */
2883 fkey_ptr
= trig_args
;
2884 for (k
= 0; k
< 4; k
++)
2885 fkey_ptr
+= strlen(fkey_ptr
) + 1;
2887 /* Set update and delete actions for foreign keys */
2888 if (!strcmp(upd_rule
, "RI_FKey_cascade_upd"))
2889 upd_rule_type
= SQL_CASCADE
;
2890 else if (!strcmp(upd_rule
, "RI_FKey_noaction_upd"))
2891 upd_rule_type
= SQL_NO_ACTION
;
2892 else if (!strcmp(upd_rule
, "RI_FKey_restrict_upd"))
2893 upd_rule_type
= SQL_NO_ACTION
;
2894 else if (!strcmp(upd_rule
, "RI_FKey_setdefault_upd"))
2895 upd_rule_type
= SQL_SET_DEFAULT
;
2896 else if (!strcmp(upd_rule
, "RI_FKey_setnull_upd"))
2897 upd_rule_type
= SQL_SET_NULL
;
2899 if (!strcmp(del_rule
, "RI_FKey_cascade_del"))
2900 del_rule_type
= SQL_CASCADE
;
2901 else if (!strcmp(del_rule
, "RI_FKey_noaction_del"))
2902 del_rule_type
= SQL_NO_ACTION
;
2903 else if (!strcmp(del_rule
, "RI_FKey_restrict_del"))
2904 del_rule_type
= SQL_NO_ACTION
;
2905 else if (!strcmp(del_rule
, "RI_FKey_setdefault_del"))
2906 del_rule_type
= SQL_SET_DEFAULT
;
2907 else if (!strcmp(del_rule
, "RI_FKey_setnull_del"))
2908 del_rule_type
= SQL_SET_NULL
;
2910 /* Set deferrability type */
2911 if (!strcmp(trig_initdeferred
, "y"))
2912 defer_type
= SQL_INITIALLY_DEFERRED
;
2913 else if (!strcmp(trig_deferrable
, "y"))
2914 defer_type
= SQL_INITIALLY_IMMEDIATE
;
2916 defer_type
= SQL_NOT_DEFERRABLE
;
2918 /* Get to first primary key */
2919 pkey_ptr
= trig_args
;
2920 for (i
= 0; i
< 5; i
++)
2921 pkey_ptr
+= strlen(pkey_ptr
) + 1;
2923 for (k
= 0; k
< num_keys
; k
++)
2925 tuple
= QR_AddNew(res
);
2928 getClientColumnName(conn
, relid2
, pkey_ptr
,
2931 getClientColumnName(conn
, relid1
, fkey_ptr
,
2934 mylog("%s: pk_table = '%s', pkey_ptr = '%s'\n", func
,
2935 pk_table_fetched
, pkey_text
);
2936 set_tuplefield_string(&tuple
[FKS_PKTABLE_CAT
],
2938 set_tuplefield_string(&tuple
[FKS_PKTABLE_SCHEM
],
2939 GET_SCHEMA_NAME(schema_fetched
));
2940 set_tuplefield_string(&tuple
[FKS_PKTABLE_NAME
],
2942 set_tuplefield_string(&tuple
[FKS_PKCOLUMN_NAME
],
2945 mylog("%s: fk_table_needed = '%s', fkey_ptr = '%s'\n",
2946 func
, fk_table_needed
, fkey_text
);
2947 set_tuplefield_null(&tuple
[FKS_FKTABLE_CAT
]);
2948 set_tuplefield_string(&tuple
[FKS_FKTABLE_SCHEM
],
2949 GET_SCHEMA_NAME(schema_needed
));
2950 set_tuplefield_string(&tuple
[FKS_FKTABLE_NAME
],
2952 set_tuplefield_string(&tuple
[FKS_FKCOLUMN_NAME
],
2956 ("%s: upd_rule_type = '%i', del_rule_type = '%i'\n, trig_name = '%s'",
2957 func
, upd_rule_type
, del_rule_type
, trig_args
);
2958 set_tuplefield_int2(&tuple
[FKS_KEY_SEQ
],
2960 set_tuplefield_int2(&tuple
[FKS_UPDATE_RULE
],
2962 set_tuplefield_int2(&tuple
[FKS_DELETE_RULE
],
2964 set_tuplefield_string(&tuple
[FKS_FK_NAME
], constrname
);
2965 set_tuplefield_string(&tuple
[FKS_PK_NAME
], pkname
);
2966 set_tuplefield_int2(&tuple
[FKS_DEFERRABILITY
],
2968 set_tuplefield_string(&tuple
[FKS_TRIGGER_NAME
],
2973 fkey_alloced
= FALSE
;
2976 pkey_alloced
= FALSE
;
2977 /* next primary/foreign key */
2978 for (i
= 0; i
< 2; i
++)
2980 fkey_ptr
+= strlen(fkey_ptr
) + 1;
2981 pkey_ptr
+= strlen(pkey_ptr
) + 1;
2985 result
= PGAPI_Fetch(htbl_stmt
);
2990 * Case #1 -- Get the foreign keys in other tables that refer to the
2991 * primary key in the specified table (pktab). i.e., Who points to
2994 else if (pk_table_needed
[0] != '\0')
2997 simpleCatalogEscape(pk_table_needed
, SQL_NTS
, NULL
, conn
);
2998 if (conn
->schema_support
)
3000 char *escSchemaName
;
3002 schema_strcat(schema_needed
, "%.*s",
3003 (const char *)szPkTableOwner
,
3004 cbPkTableOwner
, (const char *)szPkTableName
,
3005 cbPkTableName
, conn
);
3007 simpleCatalogEscape(schema_needed
, SQL_NTS
, NULL
, conn
);
3008 snprintf(tables_query
, sizeof(tables_query
),
3009 "SELECT pt.tgargs, " " pt.tgnargs, "
3010 " pt.tgdeferrable, "
3011 " pt.tginitdeferred, " " pp1.proname, "
3016 " pt.tgconstrname, pn1.nspname "
3017 "FROM pg_catalog.pg_class pc, "
3018 " pg_catalog.pg_class pc1, "
3019 " pg_catalog.pg_proc pp, "
3020 " pg_catalog.pg_proc pp1, "
3021 " pg_catalog.pg_proc pp2, "
3022 " pg_catalog.pg_trigger pt, "
3023 " pg_catalog.pg_trigger pt1, "
3024 " pg_catalog.pg_trigger pt2, "
3025 " pg_catalog.pg_namespace pn, "
3026 " pg_catalog.pg_namespace pn1 "
3027 "WHERE pc.relname='%s' "
3028 " AND pn.nspname = '%s' "
3029 " AND pc.relnamespace = pn.oid "
3030 " AND pt.tgconstrrelid = pc.oid "
3031 " AND pp.oid = pt.tgfoid "
3032 " AND pp.proname Like '%%ins' "
3033 " AND pt1.tgconstrname = pt.tgconstrname "
3034 " AND pt1.tgconstrrelid = pt.tgrelid "
3035 " AND pt1.tgrelid = pc.oid "
3036 " AND pc1.oid = pt.tgrelid "
3037 " AND pp1.oid = pt1.tgfoid "
3038 " AND pp1.proname like '%%upd' "
3039 " AND (pp1.proname not like '%%check%%') "
3040 " AND pt2.tgconstrname = pt.tgconstrname "
3041 " AND pt2.tgconstrrelid = pt.tgrelid "
3042 " AND pt2.tgrelid = pc.oid "
3043 " AND pp2.oid = pt2.tgfoid "
3044 " AND pp2.proname Like '%%del' "
3045 " AND pn1.oid = pc1.relnamespace "
3046 " order by pt.tgconstrname",
3047 escPkTableName
, escSchemaName
);
3048 free(escSchemaName
);
3051 snprintf(tables_query
, sizeof(tables_query
),
3052 "SELECT pt.tgargs, " " pt.tgnargs, "
3053 " pt.tgdeferrable, "
3054 " pt.tginitdeferred, " " pp1.proname, "
3058 " pc1.relname, pt.tgconstrname "
3059 "FROM pg_class pc, "
3067 "WHERE pc.relname ='%s' "
3068 " AND pt.tgconstrrelid = pc.oid "
3069 " AND pp.oid = pt.tgfoid "
3070 " AND pp.proname Like '%%ins' "
3071 " AND pt1.tgconstrname = pt.tgconstrname "
3072 " AND pt1.tgconstrrelid = pt.tgrelid "
3073 " AND pt1.tgrelid = pc.oid "
3074 " AND pc1.oid = pt.tgrelid "
3075 " AND pp1.oid = pt1.tgfoid "
3076 " AND pp1.proname like '%%upd' "
3077 " AND pp1.(proname not like '%%check%%') "
3078 " AND pt2.tgconstrname = pt.tgconstrname "
3079 " AND pt2.tgconstrrelid = pt.tgrelid "
3080 " AND pt2.tgrelid = pc.oid "
3081 " AND pp2.oid = pt2.tgfoid "
3082 " AND pp2.proname Like '%%del'"
3083 " order by pt.tgconstrname", escPkTableName
);
3085 result
= PGAPI_ExecDirect(htbl_stmt
, (const UCHAR
*)tables_query
,
3087 if (!SQL_SUCCEEDED(result
))
3089 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3093 result
= PGAPI_BindCol(htbl_stmt
, 1, SQL_C_BINARY
,
3094 trig_args
, sizeof(trig_args
), NULL
);
3095 if (!SQL_SUCCEEDED(result
))
3097 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3101 result
= PGAPI_BindCol(htbl_stmt
, 2, SQL_C_SHORT
,
3102 &trig_nargs
, 0, NULL
);
3103 if (!SQL_SUCCEEDED(result
))
3105 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3109 result
= PGAPI_BindCol(htbl_stmt
, 3, internal_asis_type
,
3110 trig_deferrable
, sizeof(trig_deferrable
),
3112 if (!SQL_SUCCEEDED(result
))
3114 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3118 result
= PGAPI_BindCol(htbl_stmt
, 4, internal_asis_type
,
3120 sizeof(trig_initdeferred
), NULL
);
3121 if (!SQL_SUCCEEDED(result
))
3123 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3127 result
= PGAPI_BindCol(htbl_stmt
, 5, internal_asis_type
,
3128 upd_rule
, sizeof(upd_rule
), NULL
);
3129 if (!SQL_SUCCEEDED(result
))
3131 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3135 result
= PGAPI_BindCol(htbl_stmt
, 6, internal_asis_type
,
3136 del_rule
, sizeof(del_rule
), NULL
);
3137 if (!SQL_SUCCEEDED(result
))
3139 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3143 result
= PGAPI_BindCol(htbl_stmt
, 7, SQL_C_ULONG
,
3144 &relid1
, sizeof(relid1
), NULL
);
3145 if (!SQL_SUCCEEDED(result
))
3147 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3150 result
= PGAPI_BindCol(htbl_stmt
, 8, SQL_C_ULONG
,
3151 &relid2
, sizeof(relid2
), NULL
);
3152 if (!SQL_SUCCEEDED(result
))
3154 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3157 result
= PGAPI_BindCol(htbl_stmt
, 9, internal_asis_type
,
3158 fk_table_fetched
, TABLE_NAME_STORAGE_LEN
,
3160 if (!SQL_SUCCEEDED(result
))
3162 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3165 result
= PGAPI_BindCol(htbl_stmt
, 10, internal_asis_type
,
3166 constrname
, NAMESTORAGELEN
, NULL
);
3167 if (!SQL_SUCCEEDED(result
))
3169 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3173 if (conn
->schema_support
)
3175 result
= PGAPI_BindCol(htbl_stmt
, 11, internal_asis_type
,
3177 SCHEMA_NAME_STORAGE_LEN
, NULL
);
3178 if (!SQL_SUCCEEDED(result
))
3180 SC_error_copy(stmt
, tbl_stmt
, TRUE
);
3185 result
= PGAPI_Fetch(htbl_stmt
);
3186 if (result
== SQL_NO_DATA_FOUND
)
3192 if (result
!= SQL_SUCCESS
)
3194 SC_full_error_copy(stmt
, tbl_stmt
, FALSE
);
3201 keyresult
= PGAPI_AllocStmt(conn
, &hpkey_stmt
);
3202 if (!SQL_SUCCEEDED(keyresult
))
3204 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
3205 "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.",
3209 keyresult
= PGAPI_BindCol(hpkey_stmt
, 6, internal_asis_type
,
3210 pkname
, sizeof(pkname
), NULL
);
3211 if (keyresult
!= SQL_SUCCESS
)
3213 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
3214 "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.",
3219 PGAPI_PrimaryKeys(hpkey_stmt
, NULL
, 0,
3220 (const UCHAR
*)schema_needed
,
3221 SQL_NTS
, (const UCHAR
*)pk_table_needed
,
3223 if (keyresult
!= SQL_SUCCESS
)
3225 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
3226 "Couldn't get primary keys for PGAPI_ForeignKeys result.",
3231 keyresult
= PGAPI_Fetch(hpkey_stmt
);
3232 PGAPI_FreeStmt(hpkey_stmt
, SQL_CLOSE
);
3233 while (result
== SQL_SUCCESS
)
3235 /* Calculate the number of key parts */
3236 num_keys
= (trig_nargs
- 4) / 2;;
3238 /* Handle action (i.e., 'cascade', 'restrict', 'setnull') */
3239 if (!strcmp(upd_rule
, "RI_FKey_cascade_upd"))
3240 upd_rule_type
= SQL_CASCADE
;
3241 else if (!strcmp(upd_rule
, "RI_FKey_noaction_upd"))
3242 upd_rule_type
= SQL_NO_ACTION
;
3243 else if (!strcmp(upd_rule
, "RI_FKey_restrict_upd"))
3244 upd_rule_type
= SQL_NO_ACTION
;
3245 else if (!strcmp(upd_rule
, "RI_FKey_setdefault_upd"))
3246 upd_rule_type
= SQL_SET_DEFAULT
;
3247 else if (!strcmp(upd_rule
, "RI_FKey_setnull_upd"))
3248 upd_rule_type
= SQL_SET_NULL
;
3250 if (!strcmp(del_rule
, "RI_FKey_cascade_del"))
3251 del_rule_type
= SQL_CASCADE
;
3252 else if (!strcmp(del_rule
, "RI_FKey_noaction_del"))
3253 del_rule_type
= SQL_NO_ACTION
;
3254 else if (!strcmp(del_rule
, "RI_FKey_restrict_del"))
3255 del_rule_type
= SQL_NO_ACTION
;
3256 else if (!strcmp(del_rule
, "RI_FKey_setdefault_del"))
3257 del_rule_type
= SQL_SET_DEFAULT
;
3258 else if (!strcmp(del_rule
, "RI_FKey_setnull_del"))
3259 del_rule_type
= SQL_SET_NULL
;
3261 /* Set deferrability type */
3262 if (!strcmp(trig_initdeferred
, "y"))
3263 defer_type
= SQL_INITIALLY_DEFERRED
;
3264 else if (!strcmp(trig_deferrable
, "y"))
3265 defer_type
= SQL_INITIALLY_IMMEDIATE
;
3267 defer_type
= SQL_NOT_DEFERRABLE
;
3270 ("Foreign Key Case#1: trig_nargs = %d, num_keys = %d\n",
3271 trig_nargs
, num_keys
);
3273 /* Get to first primary key */
3274 pkey_ptr
= trig_args
;
3275 for (i
= 0; i
< 5; i
++)
3276 pkey_ptr
+= strlen(pkey_ptr
) + 1;
3278 /* Get to first foreign key */
3279 fkey_ptr
= trig_args
;
3280 for (k
= 0; k
< 4; k
++)
3281 fkey_ptr
+= strlen(fkey_ptr
) + 1;
3283 for (k
= 0; k
< num_keys
; k
++)
3286 getClientColumnName(conn
, relid1
, pkey_ptr
,
3289 getClientColumnName(conn
, relid2
, fkey_ptr
,
3293 ("pkey_ptr = '%s', fk_table = '%s', fkey_ptr = '%s'\n",
3294 pkey_text
, fk_table_fetched
, fkey_text
);
3296 tuple
= QR_AddNew(res
);
3298 mylog("pk_table_needed = '%s', pkey_ptr = '%s'\n",
3299 pk_table_needed
, pkey_text
);
3300 set_tuplefield_string(&tuple
[FKS_PKTABLE_CAT
],
3302 set_tuplefield_string(&tuple
[FKS_PKTABLE_SCHEM
],
3303 GET_SCHEMA_NAME(schema_needed
));
3304 set_tuplefield_string(&tuple
[FKS_PKTABLE_NAME
],
3306 set_tuplefield_string(&tuple
[FKS_PKCOLUMN_NAME
],
3309 mylog("fk_table = '%s', fkey_ptr = '%s'\n",
3310 fk_table_fetched
, fkey_text
);
3311 set_tuplefield_null(&tuple
[FKS_FKTABLE_CAT
]);
3312 set_tuplefield_string(&tuple
[FKS_FKTABLE_SCHEM
],
3313 GET_SCHEMA_NAME(schema_fetched
));
3314 set_tuplefield_string(&tuple
[FKS_FKTABLE_NAME
],
3316 set_tuplefield_string(&tuple
[FKS_FKCOLUMN_NAME
],
3319 set_tuplefield_int2(&tuple
[FKS_KEY_SEQ
],
3322 mylog("upd_rule = %d, del_rule= %d", upd_rule_type
,
3324 set_nullfield_int2(&tuple
[FKS_UPDATE_RULE
],
3326 set_nullfield_int2(&tuple
[FKS_DELETE_RULE
],
3329 set_tuplefield_string(&tuple
[FKS_FK_NAME
], constrname
);
3330 set_tuplefield_string(&tuple
[FKS_PK_NAME
], pkname
);
3332 set_tuplefield_string(&tuple
[FKS_TRIGGER_NAME
],
3335 mylog(" defer_type = %d\n", defer_type
);
3336 set_tuplefield_int2(&tuple
[FKS_DEFERRABILITY
],
3341 pkey_alloced
= FALSE
;
3344 fkey_alloced
= FALSE
;
3346 /* next primary/foreign key */
3347 for (j
= 0; j
< 2; j
++)
3349 pkey_ptr
+= strlen(pkey_ptr
) + 1;
3350 fkey_ptr
+= strlen(fkey_ptr
) + 1;
3353 result
= PGAPI_Fetch(htbl_stmt
);
3358 SC_set_error(stmt
, STMT_INTERNAL_ERROR
,
3359 "No tables specified to PGAPI_ForeignKeys.", func
);
3367 * also, things need to think that this statement is finished so the
3368 * results can be retrieved.
3370 stmt
->status
= STMT_FINISHED
;
3376 if (pk_table_needed
)
3377 free(pk_table_needed
);
3379 free(escPkTableName
);
3380 if (fk_table_needed
)
3381 free(fk_table_needed
);
3383 free(escFkTableName
);
3386 PGAPI_FreeStmt(htbl_stmt
, SQL_DROP
);
3388 PGAPI_FreeStmt(hpkey_stmt
, SQL_DROP
);
3390 /* set up the current tuple pointer for SQLFetch */
3391 stmt
->currTuple
= -1;
3392 SC_set_rowset_start(stmt
, -1, FALSE
);
3393 SC_set_current_col(stmt
, -1);
3396 ret
= DiscardStatementSvp(stmt
, ret
, FALSE
);
3397 mylog("%s(): EXIT, stmt=%p, ret=%d\n", func
, stmt
, ret
);
3401 RETCODE SQL_API
PGAPI_ProcedureColumns(HSTMT hstmt
, const SQLCHAR FAR
* szProcQualifier
, /* OA X */
3402 SQLSMALLINT cbProcQualifier
, const SQLCHAR FAR
* szProcOwner
, /* PV E */
3403 SQLSMALLINT cbProcOwner
, const SQLCHAR FAR
* szProcName
, /* PV E */
3404 SQLSMALLINT cbProcName
, const SQLCHAR FAR
* szColumnName
, /* PV X */
3405 SQLSMALLINT cbColumnName
,
3408 CSTR func
= "PGAPI_ProcedureColumns";
3409 StatementClass
*stmt
= (StatementClass
*) hstmt
;
3410 ConnectionClass
*conn
= SC_get_conn(stmt
);
3411 char proc_query
[INFO_INQUIRY_LEN
];
3414 const char *schema_name
, *procname
;
3415 char *escSchemaName
= NULL
, *escProcName
= NULL
;
3416 char *params
, *delim
= NULL
;
3417 char *atttypid
, *proargnames
, *proargmodes
;
3418 char *attname
, *column_name
;
3419 QResultClass
*res
, *tres
;
3422 Int4 paramcount
, i
, j
;
3424 BOOL search_pattern
, bRetset
;
3425 const char *like_or_eq
, *retset
;
3426 int ret_col
= -1, ext_pos
= -1, poid_pos
= -1, attid_pos
=
3427 -1, attname_pos
= -1;
3428 UInt4 poid
= 0, newpoid
;
3430 mylog("%s: entering...\n", func
);
3432 if (PG_VERSION_LT(conn
, 6.5))
3434 SC_set_error(stmt
, STMT_NOT_IMPLEMENTED_ERROR
,
3435 "Version is too old", func
);
3438 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
3440 search_pattern
= (0 == (flag
& PODBC_NOT_SEARCH_PATTERN
));
3443 like_or_eq
= likeop
;
3445 adjustLikePattern(szProcOwner
, cbProcOwner
,
3446 SEARCH_PATTERN_ESCAPE
, NULL
, conn
);
3448 adjustLikePattern(szProcName
, cbProcName
,
3449 SEARCH_PATTERN_ESCAPE
, NULL
, conn
);
3455 simpleCatalogEscape(szProcOwner
, cbProcOwner
, NULL
, conn
);
3457 simpleCatalogEscape(szProcName
, cbProcName
, NULL
, conn
);
3459 if (conn
->schema_support
)
3461 strcpy(proc_query
, "select proname, proretset, prorettype, "
3462 "pronargs, proargtypes, nspname, p.oid");
3463 ret_col
= ext_pos
= 7;
3465 strcat(proc_query
, ", atttypid, attname");
3466 attid_pos
= ext_pos
;
3467 attname_pos
= ext_pos
+ 1;
3470 if (PG_VERSION_GE(conn
, 8.0))
3472 strcat(proc_query
, ", proargnames");
3475 if (PG_VERSION_GE(conn
, 8.1))
3477 strcat(proc_query
, ", proargmodes, proallargtypes");
3481 " from ((pg_catalog.pg_namespace n inner join"
3482 " pg_catalog.pg_proc p on p.pronamespace = n.oid)"
3483 " inner join pg_type t on t.oid = p.prorettype)"
3484 " left outer join pg_attribute a on a.attrelid = t.typrelid "
3485 " and attnum > 0 and not attisdropped where");
3486 strcat(proc_query
, " has_function_privilege(p.oid, 'EXECUTE')");
3487 my_strcat1(proc_query
, " and nspname %s '%.*s'", like_or_eq
,
3488 escSchemaName
, SQL_NTS
);
3490 snprintf_add(proc_query
, sizeof(proc_query
),
3491 " and proname %s '%s'", like_or_eq
,
3493 strcat(proc_query
, " order by nspname, proname, p.oid, attnum");
3497 strcpy(proc_query
, "select proname, proretset, prorettype, "
3498 "pronargs, proargtypes from pg_proc where "
3502 snprintf_add(proc_query
, sizeof(proc_query
),
3503 " and proname %s '%s'", like_or_eq
,
3505 strcat(proc_query
, " order by proname, proretset");
3508 CC_send_query(conn
, proc_query
, NULL
, IGNORE_ABORT_ON_CONN
,
3509 stmt
), !QR_command_maybe_successful(tres
))
3511 SC_set_error(stmt
, STMT_EXEC_ERROR
,
3512 "PGAPI_ProcedureColumns query error", func
);
3513 QR_Destructor(tres
);
3517 if (res
= QR_Constructor(), !res
)
3519 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
3520 "Couldn't allocate memory for PGAPI_ProcedureColumns result.",
3524 SC_set_Result(stmt
, res
);
3527 * the binding structure for a statement is not set up until
3528 * a statement is actually executed, so we'll have to do this
3531 result_cols
= NUM_OF_PROCOLS_FIELDS
;
3532 extend_column_bindings(SC_get_ARDF(stmt
), result_cols
);
3534 /* set the field names */
3535 QR_set_num_fields(res
, result_cols
);
3536 QR_set_field_info_v(res
, PROCOLS_PROCEDURE_CAT
, "PROCEDURE_CAT",
3537 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3538 QR_set_field_info_v(res
, PROCOLS_PROCEDURE_SCHEM
, "PROCEDUR_SCHEM",
3539 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3540 QR_set_field_info_v(res
, PROCOLS_PROCEDURE_NAME
, "PROCEDURE_NAME",
3541 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3542 QR_set_field_info_v(res
, PROCOLS_COLUMN_NAME
, "COLUMN_NAME",
3543 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3544 QR_set_field_info_v(res
, PROCOLS_COLUMN_TYPE
, "COLUMN_TYPE",
3546 QR_set_field_info_v(res
, PROCOLS_DATA_TYPE
, "DATA_TYPE",
3548 QR_set_field_info_v(res
, PROCOLS_TYPE_NAME
, "TYPE_NAME",
3549 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3550 QR_set_field_info_v(res
, PROCOLS_COLUMN_SIZE
, "COLUMN_SIZE",
3552 QR_set_field_info_v(res
, PROCOLS_BUFFER_LENGTH
, "BUFFER_LENGTH",
3554 QR_set_field_info_v(res
, PROCOLS_DECIMAL_DIGITS
, "DECIMAL_DIGITS",
3556 QR_set_field_info_v(res
, PROCOLS_NUM_PREC_RADIX
, "NUM_PREC_RADIX",
3558 QR_set_field_info_v(res
, PROCOLS_NULLABLE
, "NULLABLE", PG_TYPE_INT2
,
3560 QR_set_field_info_v(res
, PROCOLS_REMARKS
, "REMARKS",
3561 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3562 QR_set_field_info_v(res
, PROCOLS_COLUMN_DEF
, "COLUMN_DEF",
3563 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3564 QR_set_field_info_v(res
, PROCOLS_SQL_DATA_TYPE
, "SQL_DATA_TYPE",
3566 QR_set_field_info_v(res
, PROCOLS_SQL_DATETIME_SUB
,
3567 "SQL_DATETIME_SUB", PG_TYPE_INT2
, 2);
3568 QR_set_field_info_v(res
, PROCOLS_CHAR_OCTET_LENGTH
,
3569 "CHAR_OCTET_LENGTH", PG_TYPE_INT4
, 4);
3570 QR_set_field_info_v(res
, PROCOLS_ORDINAL_POSITION
,
3571 "ORDINAL_POSITION", PG_TYPE_INT4
, 4);
3572 QR_set_field_info_v(res
, PROCOLS_IS_NULLABLE
, "IS_NULLABLE",
3573 PG_TYPE_VARCHAR
, MAX_INFO_STRING
);
3575 column_name
= make_string(szColumnName
, cbColumnName
, NULL
, 0);
3576 if (column_name
) /* column_name is unavailable now */
3582 tcount
= QR_get_num_total_tuples(tres
);
3583 for (i
= 0, poid
= 0; i
< tcount
; i
++)
3585 if (conn
->schema_support
)
3587 GET_SCHEMA_NAME(QR_get_value_backend_text(tres
, i
, 5));
3590 procname
= QR_get_value_backend_text(tres
, i
, 0);
3591 retset
= QR_get_value_backend_text(tres
, i
, 1);
3592 pgtype
= QR_get_value_backend_int(tres
, i
, 2, NULL
);
3593 bRetset
= retset
&& (retset
[0] == 't' || retset
[0] == 'y');
3596 newpoid
= QR_get_value_backend_int(tres
, i
, poid_pos
, NULL
);
3597 mylog("newpoid=%d\n", newpoid
);
3601 atttypid
= (char *)QR_get_value_backend_text(tres
, i
, attid_pos
);
3602 mylog("atttypid=%s\n", atttypid
? atttypid
: "(null)");
3604 if (poid
== 0 || newpoid
!= poid
)
3611 if (PG_VERSION_GE(conn
, 8.0))
3612 proargnames
= (char *)
3613 QR_get_value_backend_text(tres
, i
, ext_pos
);
3614 if (PG_VERSION_GE(conn
, 8.1))
3615 proargmodes
= (char *)
3616 QR_get_value_backend_text(tres
, i
, ext_pos
+ 1);
3618 /* RETURN_VALUE info */
3619 if (0 != pgtype
&& PG_TYPE_VOID
!= pgtype
&& !bRetset
3620 && !atttypid
&& !proargmodes
)
3622 tuple
= QR_AddNew(res
);
3623 set_tuplefield_string(&tuple
[PROCOLS_PROCEDURE_CAT
],
3625 set_nullfield_string(&tuple
[PROCOLS_PROCEDURE_SCHEM
],
3627 set_tuplefield_string(&tuple
[PROCOLS_PROCEDURE_NAME
],
3629 set_tuplefield_string(&tuple
[PROCOLS_COLUMN_NAME
],
3631 set_tuplefield_int2(&tuple
[PROCOLS_COLUMN_TYPE
],
3633 set_tuplefield_int2(&tuple
[PROCOLS_DATA_TYPE
],
3634 pgtype_to_concise_type(stmt
, pgtype
,
3636 set_tuplefield_string(&tuple
[PROCOLS_TYPE_NAME
],
3637 pgtype_to_name(stmt
, pgtype
,
3639 set_nullfield_int4(&tuple
[PROCOLS_COLUMN_SIZE
],
3640 pgtype_column_size(stmt
, pgtype
,
3643 set_tuplefield_int4(&tuple
[PROCOLS_BUFFER_LENGTH
],
3644 pgtype_buffer_length(stmt
, pgtype
,
3647 set_nullfield_int2(&tuple
[PROCOLS_DECIMAL_DIGITS
],
3648 pgtype_decimal_digits(stmt
, pgtype
,
3650 set_nullfield_int2(&tuple
[PROCOLS_NUM_PREC_RADIX
],
3651 pgtype_radix(stmt
, pgtype
));
3652 set_tuplefield_int2(&tuple
[PROCOLS_NULLABLE
],
3653 SQL_NULLABLE_UNKNOWN
);
3654 set_tuplefield_null(&tuple
[PROCOLS_REMARKS
]);
3655 set_tuplefield_null(&tuple
[PROCOLS_COLUMN_DEF
]);
3656 set_nullfield_int2(&tuple
[PROCOLS_SQL_DATA_TYPE
],
3657 pgtype_to_sqldesctype(stmt
, pgtype
,
3659 set_nullfield_int2(&tuple
[PROCOLS_SQL_DATETIME_SUB
],
3660 pgtype_to_datetime_sub(stmt
,
3662 set_nullfield_int4(&tuple
[PROCOLS_CHAR_OCTET_LENGTH
],
3663 pgtype_transfer_octet_length(stmt
,
3667 set_tuplefield_int4(&tuple
[PROCOLS_ORDINAL_POSITION
],
3669 set_tuplefield_string(&tuple
[PROCOLS_IS_NULLABLE
],
3677 for (p
= proargmodes
; *p
; p
++)
3684 QR_get_value_backend_text(tres
, i
, ext_pos
+ 2);
3685 if ('{' == *proargmodes
)
3692 paramcount
= QR_get_value_backend_int(tres
, i
, 3, NULL
);
3693 params
= (char *)QR_get_value_backend_text(tres
, i
, 4);
3697 if ('{' == *proargnames
)
3700 /* PARAMETERS info */
3701 for (j
= 0; j
< paramcount
; j
++)
3703 /* PG type of parameters */
3707 while (isspace(*params
) || ',' == *params
)
3709 if ('\0' == *params
|| '}' == *params
)
3713 sscanf(params
, "%u", &pgtype
);
3714 while (isdigit(*params
))
3718 /* input/output type of parameters */
3721 while (isspace(*proargmodes
) || ',' == *proargmodes
)
3723 if ('\0' == *proargmodes
|| '}' == *proargmodes
)
3726 /* name of parameters */
3729 while (isspace(*proargnames
) || ',' == *proargnames
)
3731 if ('\0' == *proargnames
|| '}' == *proargnames
)
3733 else if ('"' == *proargnames
)
3736 for (delim
= proargnames
;
3737 *delim
&& *delim
!= '"'; delim
++)
3742 for (delim
= proargnames
;
3743 *delim
&& !isspace(*delim
) && ',' != *delim
3744 && '}' != *delim
; delim
++)
3747 if (proargnames
&& '\0' == *delim
) /* discard the incomplete name */
3751 tuple
= QR_AddNew(res
);
3752 set_tuplefield_string(&tuple
[PROCOLS_PROCEDURE_CAT
],
3754 set_nullfield_string(&tuple
[PROCOLS_PROCEDURE_SCHEM
],
3756 set_tuplefield_string(&tuple
[PROCOLS_PROCEDURE_NAME
],
3761 set_tuplefield_string(&tuple
[PROCOLS_COLUMN_NAME
],
3763 proargnames
= delim
+ 1;
3766 set_tuplefield_string(&tuple
[PROCOLS_COLUMN_NAME
],
3772 switch (*proargmodes
)
3775 ptype
= SQL_PARAM_OUTPUT
;
3778 ptype
= SQL_PARAM_INPUT_OUTPUT
;
3781 ptype
= SQL_PARAM_INPUT
;
3784 set_tuplefield_int2(&tuple
[PROCOLS_COLUMN_TYPE
],
3789 set_tuplefield_int2(&tuple
[PROCOLS_COLUMN_TYPE
],
3791 set_tuplefield_int2(&tuple
[PROCOLS_DATA_TYPE
],
3792 pgtype_to_concise_type(stmt
, pgtype
,
3794 set_tuplefield_string(&tuple
[PROCOLS_TYPE_NAME
],
3795 pgtype_to_name(stmt
, pgtype
,
3797 set_nullfield_int4(&tuple
[PROCOLS_COLUMN_SIZE
],
3798 pgtype_column_size(stmt
, pgtype
,
3801 set_tuplefield_int4(&tuple
[PROCOLS_BUFFER_LENGTH
],
3802 pgtype_buffer_length(stmt
, pgtype
,
3805 set_nullfield_int2(&tuple
[PROCOLS_DECIMAL_DIGITS
],
3806 pgtype_decimal_digits(stmt
, pgtype
,
3808 set_nullfield_int2(&tuple
[PROCOLS_NUM_PREC_RADIX
],
3809 pgtype_radix(stmt
, pgtype
));
3810 set_tuplefield_int2(&tuple
[PROCOLS_NULLABLE
],
3811 SQL_NULLABLE_UNKNOWN
);
3812 set_tuplefield_null(&tuple
[PROCOLS_REMARKS
]);
3813 set_tuplefield_null(&tuple
[PROCOLS_COLUMN_DEF
]);
3814 set_nullfield_int2(&tuple
[PROCOLS_SQL_DATA_TYPE
],
3815 pgtype_to_sqldesctype(stmt
, pgtype
,
3817 set_nullfield_int2(&tuple
[PROCOLS_SQL_DATETIME_SUB
],
3818 pgtype_to_datetime_sub(stmt
,
3820 set_nullfield_int4(&tuple
[PROCOLS_CHAR_OCTET_LENGTH
],
3821 pgtype_transfer_octet_length(stmt
,
3825 set_tuplefield_int4(&tuple
[PROCOLS_ORDINAL_POSITION
],
3827 set_tuplefield_string(&tuple
[PROCOLS_IS_NULLABLE
],
3831 /* RESULT Columns info */
3832 if (NULL
!= atttypid
|| bRetset
)
3843 typid
= atoi(atttypid
);
3845 QR_get_value_backend_text(tres
, i
, attname_pos
);
3847 tuple
= QR_AddNew(res
);
3848 set_tuplefield_string(&tuple
[PROCOLS_PROCEDURE_CAT
],
3850 set_nullfield_string(&tuple
[PROCOLS_PROCEDURE_SCHEM
],
3852 set_tuplefield_string(&tuple
[PROCOLS_PROCEDURE_NAME
],
3854 set_tuplefield_string(&tuple
[PROCOLS_COLUMN_NAME
], attname
);
3855 set_tuplefield_int2(&tuple
[PROCOLS_COLUMN_TYPE
],
3857 set_tuplefield_int2(&tuple
[PROCOLS_DATA_TYPE
],
3858 pgtype_to_concise_type(stmt
, typid
,
3860 set_tuplefield_string(&tuple
[PROCOLS_TYPE_NAME
],
3861 pgtype_to_name(stmt
, typid
, FALSE
));
3862 set_nullfield_int4(&tuple
[PROCOLS_COLUMN_SIZE
],
3863 pgtype_column_size(stmt
, typid
,
3866 set_tuplefield_int4(&tuple
[PROCOLS_BUFFER_LENGTH
],
3867 pgtype_buffer_length(stmt
, typid
,
3870 set_nullfield_int2(&tuple
[PROCOLS_DECIMAL_DIGITS
],
3871 pgtype_decimal_digits(stmt
, typid
,
3873 set_nullfield_int2(&tuple
[PROCOLS_NUM_PREC_RADIX
],
3874 pgtype_radix(stmt
, typid
));
3875 set_tuplefield_int2(&tuple
[PROCOLS_NULLABLE
],
3876 SQL_NULLABLE_UNKNOWN
);
3877 set_tuplefield_null(&tuple
[PROCOLS_REMARKS
]);
3878 set_tuplefield_null(&tuple
[PROCOLS_COLUMN_DEF
]);
3879 set_nullfield_int2(&tuple
[PROCOLS_SQL_DATA_TYPE
],
3880 pgtype_to_sqldesctype(stmt
, typid
,
3882 set_nullfield_int2(&tuple
[PROCOLS_SQL_DATETIME_SUB
],
3883 pgtype_to_datetime_sub(stmt
, typid
));
3884 set_nullfield_int4(&tuple
[PROCOLS_CHAR_OCTET_LENGTH
],
3885 pgtype_transfer_octet_length(stmt
, typid
,
3888 set_tuplefield_int4(&tuple
[PROCOLS_ORDINAL_POSITION
], 0);
3889 set_tuplefield_string(&tuple
[PROCOLS_IS_NULLABLE
],
3893 QR_Destructor(tres
);
3895 * also, things need to think that this statement is finished so the
3896 * results can be retrieved.
3899 free(escSchemaName
);
3902 stmt
->status
= STMT_FINISHED
;
3903 /* set up the current tuple pointer for SQLFetch */
3904 stmt
->currTuple
= -1;
3905 SC_set_rowset_start(stmt
, -1, FALSE
);
3906 SC_set_current_col(stmt
, -1);
3911 RETCODE SQL_API
PGAPI_Procedures(HSTMT hstmt
, const SQLCHAR FAR
* szProcQualifier
, /* OA X */
3912 SQLSMALLINT cbProcQualifier
, const SQLCHAR FAR
* szProcOwner
, /* PV E */
3913 SQLSMALLINT cbProcOwner
, const SQLCHAR FAR
* szProcName
, /* PV E */
3914 SQLSMALLINT cbProcName
, UWORD flag
)
3916 CSTR func
= "PGAPI_Procedures";
3917 StatementClass
*stmt
= (StatementClass
*) hstmt
;
3918 ConnectionClass
*conn
= SC_get_conn(stmt
);
3919 char proc_query
[INFO_INQUIRY_LEN
];
3920 char *escSchemaName
= NULL
, *escProcName
= NULL
;
3923 const char *like_or_eq
;
3924 BOOL search_pattern
;
3926 mylog("%s: entering... scnm=%p len=%d\n", func
, szProcOwner
,
3929 if (PG_VERSION_LT(conn
, 6.5))
3931 SC_set_error(stmt
, STMT_NOT_IMPLEMENTED_ERROR
,
3932 "Version is too old", func
);
3935 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
3938 search_pattern
= (0 == (flag
& PODBC_NOT_SEARCH_PATTERN
));
3941 like_or_eq
= likeop
;
3943 adjustLikePattern(szProcOwner
, cbProcOwner
,
3944 SEARCH_PATTERN_ESCAPE
, NULL
, conn
);
3946 adjustLikePattern(szProcName
, cbProcName
,
3947 SEARCH_PATTERN_ESCAPE
, NULL
, conn
);
3953 simpleCatalogEscape(szProcOwner
, cbProcOwner
, NULL
, conn
);
3955 simpleCatalogEscape(szProcName
, cbProcName
, NULL
, conn
);
3958 * The following seems the simplest implementation
3960 if (conn
->schema_support
)
3963 "select '' as " "PROCEDURE_CAT" ", nspname as "
3964 "PROCEDURE_SCHEM" "," " proname as " "PROCEDURE_NAME"
3965 ", '' as " "NUM_INPUT_PARAMS" "," " '' as "
3966 "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
3967 " '' as " "REMARKS" ","
3968 " case when prorettype = 0 then 1::int2 else 2::int2 end"
3969 " as " "PROCEDURE_TYPE" " from pg_catalog.pg_namespace,"
3970 " pg_catalog.pg_proc"
3971 " where pg_proc.pronamespace = pg_namespace.oid");
3972 schema_strcat1(proc_query
, " and nspname %s '%.*s'", like_or_eq
,
3973 escSchemaName
, SQL_NTS
,
3974 (const char *)szProcName
, cbProcName
, conn
);
3975 my_strcat1(proc_query
, " and proname %s '%.*s'", like_or_eq
,
3976 escProcName
, SQL_NTS
);
3981 "select '' as " "PROCEDURE_CAT" ", '' as "
3982 "PROCEDURE_SCHEM" "," " proname as " "PROCEDURE_NAME"
3983 ", '' as " "NUM_INPUT_PARAMS" "," " '' as "
3984 "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
3985 " '' as " "REMARKS" ","
3986 " case when prorettype = 0 then 1::int2 else 2::int2 end as "
3987 "PROCEDURE_TYPE" " from pg_proc");
3988 my_strcat1(proc_query
, " where proname %s '%.*s'", like_or_eq
,
3989 escSchemaName
, SQL_NTS
);
3993 CC_send_query(conn
, proc_query
, NULL
, IGNORE_ABORT_ON_CONN
,
3994 stmt
), !QR_command_maybe_successful(res
))
3996 SC_set_error(stmt
, STMT_EXEC_ERROR
,
3997 "PGAPI_Procedures query error", func
);
4001 SC_set_Result(stmt
, res
);
4004 * also, things need to think that this statement is finished so the
4005 * results can be retrieved.
4007 stmt
->status
= STMT_FINISHED
;
4008 extend_column_bindings(SC_get_ARDF(stmt
), 8);
4010 free(escSchemaName
);
4013 /* set up the current tuple pointer for SQLFetch */
4014 stmt
->currTuple
= -1;
4015 SC_set_rowset_start(stmt
, -1, FALSE
);
4016 SC_set_current_col(stmt
, -1);
4022 #define ALL_PRIVILIGES "arwdRxt"
4023 static int usracl_auth(char *usracl
, const char *auth
)
4025 int i
, j
, addcnt
= 0;
4027 for (i
= 0; auth
[i
]; i
++)
4029 for (j
= 0; j
< ACLMAX
; j
++)
4031 if (usracl
[j
] == auth
[i
])
4033 else if (!usracl
[j
])
4035 usracl
[j
] = auth
[i
];
4044 useracl_upd(char (*useracl
)[ACLMAX
], QResultClass
* allures
,
4045 const char *user
, const char *auth
)
4047 int usercount
= (int) QR_get_num_cached_tuples(allures
), i
, addcnt
=
4050 mylog("user=%s auth=%s\n", user
, auth
);
4052 for (i
= 0; i
< usercount
; i
++)
4054 if (strcmp(QR_get_value_backend_text(allures
, i
, 0), user
)
4057 addcnt
+= usracl_auth(useracl
[i
], auth
);
4062 for (i
= 0; i
< usercount
; i
++)
4064 addcnt
+= usracl_auth(useracl
[i
], auth
);
4066 mylog("addcnt=%d\n", addcnt
);
4069 RETCODE SQL_API
PGAPI_TablePrivileges(HSTMT hstmt
, const SQLCHAR FAR
* szTableQualifier
, /* OA X */
4070 SQLSMALLINT cbTableQualifier
, const SQLCHAR FAR
* szTableOwner
, /* PV E */
4071 SQLSMALLINT cbTableOwner
, const SQLCHAR FAR
* szTableName
, /* PV E */
4072 SQLSMALLINT cbTableName
,
4075 StatementClass
*stmt
= (StatementClass
*) hstmt
;
4076 CSTR func
= "PGAPI_TablePrivileges";
4077 ConnectionClass
*conn
= SC_get_conn(stmt
);
4079 char proc_query
[INFO_INQUIRY_LEN
];
4080 QResultClass
*res
, *wres
= NULL
, *allures
= NULL
;
4082 Int4 tablecount
, usercount
, i
, j
, k
;
4083 BOOL grpauth
, sys
, su
;
4084 char (*useracl
)[ACLMAX
] = NULL
, *acl
, *user
, *delim
, *auth
;
4085 const char *reln
, *owner
, *priv
, *schnm
= NULL
;
4086 RETCODE result
, ret
= SQL_SUCCESS
;
4087 const char *like_or_eq
;
4088 const char *szSchemaName
;
4089 SQLSMALLINT cbSchemaName
;
4090 char *escSchemaName
= NULL
, *escTableName
= NULL
;
4091 BOOL search_pattern
;
4093 mylog("%s: entering... scnm=%p len-%d\n", func
,
4094 NULL_IF_NULL(szTableOwner
), cbTableOwner
);
4095 if (result
= SC_initialize_and_recycle(stmt
), SQL_SUCCESS
!= result
)
4099 * a statement is actually executed, so we'll have to do this
4103 extend_column_bindings(SC_get_ARDF(stmt
), result_cols
);
4105 stmt
->catalog_result
= TRUE
;
4106 /* set the field names */
4107 res
= QR_Constructor();
4108 SC_set_Result(stmt
, res
);
4109 QR_set_num_fields(res
, result_cols
);
4110 QR_set_field_info_v(res
, 0, "TABLE_CAT", PG_TYPE_VARCHAR
,
4112 QR_set_field_info_v(res
, 1, "TABLE_SCHEM", PG_TYPE_VARCHAR
,
4114 QR_set_field_info_v(res
, 2, "TABLE_NAME", PG_TYPE_VARCHAR
,
4116 QR_set_field_info_v(res
, 3, "GRANTOR", PG_TYPE_VARCHAR
,
4118 QR_set_field_info_v(res
, 4, "GRANTEE", PG_TYPE_VARCHAR
,
4120 QR_set_field_info_v(res
, 5, "PRIVILEGE", PG_TYPE_VARCHAR
,
4122 QR_set_field_info_v(res
, 6, "IS_GRANTABLE", PG_TYPE_VARCHAR
,
4126 * also, things need to think that this statement is finished so the
4127 * results can be retrieved.
4129 stmt
->status
= STMT_FINISHED
;
4130 /* set up the current tuple pointer for SQLFetch */
4131 stmt
->currTuple
= -1;
4132 SC_set_rowset_start(stmt
, -1, FALSE
);
4133 SC_set_current_col(stmt
, -1);
4134 szSchemaName
= (const char *)szTableOwner
;
4135 cbSchemaName
= cbTableOwner
;
4137 #define return DONT_CALL_RETURN_FROM_HERE???
4138 search_pattern
= (0 == (flag
& PODBC_NOT_SEARCH_PATTERN
));
4141 like_or_eq
= likeop
;
4143 adjustLikePattern(szTableName
, cbTableName
,
4144 SEARCH_PATTERN_ESCAPE
, NULL
, conn
);
4150 simpleCatalogEscape(szTableName
, cbTableName
, NULL
, conn
);
4153 retry_public_schema
:
4155 free(escSchemaName
);
4158 adjustLikePattern(szSchemaName
, cbSchemaName
,
4159 SEARCH_PATTERN_ESCAPE
, NULL
, conn
);
4162 simpleCatalogEscape(szSchemaName
, cbSchemaName
, NULL
, conn
);
4163 if (conn
->schema_support
)
4164 strncpy_null(proc_query
,
4165 "select relname, usename, relacl, nspname"
4166 " from pg_catalog.pg_namespace, pg_catalog.pg_class ,"
4167 " pg_catalog.pg_user where", sizeof(proc_query
));
4169 strncpy_null(proc_query
, "select relname, usename, relacl"
4170 " from pg_class , pg_user where",
4171 sizeof(proc_query
));
4172 if (conn
->schema_support
)
4175 schema_strcat1(proc_query
, " nspname %s '%.*s' and",
4176 like_or_eq
, escSchemaName
, SQL_NTS
,
4177 (const char *)szTableName
, cbTableName
, conn
);
4180 snprintf_add(proc_query
, sizeof(proc_query
),
4181 " relname %s '%s' and", like_or_eq
, escTableName
);
4182 if (conn
->schema_support
)
4185 " pg_namespace.oid = relnamespace and relkind in ('r', 'v') and");
4186 if ((!escTableName
) && (!escSchemaName
))
4188 " nspname not in ('pg_catalog', 'information_schema') and");
4190 strcat(proc_query
, " pg_user.usesysid = relowner");
4192 CC_send_query(conn
, proc_query
, NULL
, IGNORE_ABORT_ON_CONN
,
4193 stmt
), !QR_command_maybe_successful(wres
))
4195 SC_set_error(stmt
, STMT_EXEC_ERROR
,
4196 "PGAPI_TablePrivileges query error", func
);
4200 tablecount
= (Int4
) QR_get_num_cached_tuples(wres
);
4202 if (conn
->schema_support
&&
4203 (flag
& PODBC_SEARCH_PUBLIC_SCHEMA
) != 0 && 0 == tablecount
)
4205 const char *user
= CC_get_username(conn
);
4208 * If specified schema name == user_name and
4209 * the current schema is 'public',
4210 * retry the 'public' schema.
4213 (cbSchemaName
== SQL_NTS
||
4214 cbSchemaName
== (SQLSMALLINT
) strlen(user
)) &&
4215 strnicmp(szSchemaName
, user
, strlen(user
)) == 0 &&
4216 stricmp(CC_get_current_schema(conn
), pubstr
) == 0)
4218 QR_Destructor(wres
);
4220 szSchemaName
= pubstr
;
4221 cbSchemaName
= SQL_NTS
;
4222 goto retry_public_schema
;
4226 strncpy_null(proc_query
,
4227 "select usename, usesysid, usesuper from pg_user",
4228 sizeof(proc_query
));
4230 CC_send_query(conn
, proc_query
, NULL
, IGNORE_ABORT_ON_CONN
,
4231 stmt
), !QR_command_maybe_successful(allures
))
4233 SC_set_error(stmt
, STMT_EXEC_ERROR
,
4234 "PGAPI_TablePrivileges query error", func
);
4238 usercount
= (Int4
) QR_get_num_cached_tuples(allures
);
4240 (char (*)[ACLMAX
]) malloc(usercount
* sizeof(char[ACLMAX
]));
4241 for (i
= 0; i
< tablecount
; i
++)
4243 memset(useracl
, 0, usercount
* sizeof(char[ACLMAX
]));
4244 acl
= (char *) QR_get_value_backend_text(wres
, i
, 2);
4245 if (acl
&& acl
[0] == '{')
4249 for (; user
&& *user
;)
4252 if (user
[0] == '"' && strncmp(user
+ 1, "group ", 6) == 0)
4257 if (delim
= strchr(user
, '='), !delim
)
4263 if (delim
= strchr(auth
, '"'), delim
)
4269 else if (delim
= strchr(auth
, ','), delim
)
4271 else if (delim
= strchr(auth
, '}'), delim
)
4273 if (grpauth
) /* handle group privilege */
4277 char *grolist
, *uid
, *delm
;
4279 snprintf(proc_query
, sizeof(proc_query
) - 1,
4280 "select grolist from pg_group where groname = '%s'",
4283 CC_send_query(conn
, proc_query
, NULL
,
4284 IGNORE_ABORT_ON_CONN
, stmt
),
4285 !QR_command_maybe_successful(gres
))
4287 grolist
= (char *)QR_get_value_backend_text(gres
, 0, 0);
4288 if (grolist
&& grolist
[0] == '{')
4290 for (uid
= grolist
+ 1; *uid
;)
4292 if (delm
= strchr(uid
, ','), delm
)
4294 else if (delm
= strchr(uid
, '}'), delm
)
4296 mylog("guid=%s\n", uid
);
4297 for (i
= 0; i
< usercount
; i
++)
4300 (QR_get_value_backend_text
4301 (allures
, i
, 1), uid
) == 0)
4302 useracl_upd(useracl
, allures
,
4303 QR_get_value_backend_text
4304 (allures
, i
, 0), auth
);
4310 QR_Destructor(gres
);
4313 useracl_upd(useracl
, allures
, user
, auth
);
4318 reln
= QR_get_value_backend_text(wres
, i
, 0);
4319 owner
= QR_get_value_backend_text(wres
, i
, 1);
4320 if (conn
->schema_support
)
4321 schnm
= QR_get_value_backend_text(wres
, i
, 3);
4322 /* The owner has all privileges */
4323 useracl_upd(useracl
, allures
, owner
, ALL_PRIVILIGES
);
4324 for (j
= 0; j
< usercount
; j
++)
4326 user
= (char *)QR_get_value_backend_text(allures
, j
, 0);
4327 su
= (strcmp(QR_get_value_backend_text(allures
, j
, 2), "t")
4329 sys
= (strcmp(user
, owner
) == 0);
4330 /* Super user has all privileges */
4332 useracl_upd(useracl
, allures
, user
, ALL_PRIVILIGES
);
4333 for (k
= 0; k
< ACLMAX
; k
++)
4337 switch (useracl
[j
][k
])
4339 case 'R': /* rule */
4340 case 't': /* trigger */
4343 tuple
= QR_AddNew(res
);
4344 set_tuplefield_string(&tuple
[0], CurrCat(conn
));
4345 if (conn
->schema_support
)
4346 set_tuplefield_string(&tuple
[1],
4347 GET_SCHEMA_NAME(schnm
));
4349 set_tuplefield_string(&tuple
[1], NULL_STRING
);
4350 set_tuplefield_string(&tuple
[2], reln
);
4352 set_tuplefield_string(&tuple
[3], "_SYSTEM");
4354 set_tuplefield_string(&tuple
[3], owner
);
4355 mylog("user=%s\n", user
);
4356 set_tuplefield_string(&tuple
[4], user
);
4357 switch (useracl
[j
][k
])
4372 priv
= "REFERENCES";
4377 set_tuplefield_string(&tuple
[5], priv
);
4378 /* The owner and the super user are grantable */
4380 set_tuplefield_string(&tuple
[6], "YES");
4382 set_tuplefield_string(&tuple
[6], "NO");
4389 free(escSchemaName
);
4395 QR_Destructor(wres
);
4397 QR_Destructor(allures
);
4399 ret
= DiscardStatementSvp(stmt
, ret
, FALSE
);