FIXME: toplevel Makefile: 'make ntest' doesn't run versaplexd for now.
[versaplex.git] / vxodbc / info.cc
blob3eba33fcb330d8ef3aa30412d176e452c5695da1
1 /*
2 * Description: This module contains routines related to
3 * ODBC informational functions.
4 */
6 #include "psqlodbc.h"
8 #include <string.h>
9 #include <stdio.h>
10 #include <ctype.h>
12 #include "tuple.h"
13 #include "pgtypes.h"
14 #include "dlg_specific.h"
16 #include "environ.h"
17 #include "connection.h"
18 #include "statement.h"
19 #include "qresult.h"
20 #include "bind.h"
21 #include "misc.h"
22 #include "pgtypes.h"
23 #include "pgapifunc.h"
24 #include "multibyte.h"
25 #include "catfunc.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";
40 CSTR likeop = "like";
41 CSTR eqop = "=";
43 RETCODE SQL_API
44 PGAPI_GetInfo(HDBC hdbc,
45 SQLUSMALLINT fInfoType,
46 PTR rgbInfoValue,
47 SQLSMALLINT cbInfoValueMax,
48 SQLSMALLINT FAR * pcbInfoValue)
50 CSTR func = "PGAPI_GetInfo";
51 ConnectionClass *conn = (ConnectionClass *) hdbc;
52 ConnInfo *ci;
53 const char *p = NULL;
54 char tmp[MAX_INFO_STRING];
55 SQLULEN len = 0, value = 0;
56 RETCODE result;
57 char odbcver[16];
58 int i_odbcver;
60 mylog("%s: entering...fInfoType=%d\n", func, fInfoType);
62 if (!conn)
64 CC_log_error(func, NULL_STRING, NULL);
65 return SQL_INVALID_HANDLE;
68 ci = &(conn->connInfo);
70 switch (fInfoType)
72 case SQL_ACCESSIBLE_PROCEDURES: /* ODBC 1.0 */
73 p = "N";
74 break;
76 case SQL_ACCESSIBLE_TABLES: /* ODBC 1.0 */
77 p = "N";
78 break;
80 case SQL_ACTIVE_CONNECTIONS: /* ODBC 1.0 */
81 len = 2;
82 value = MAX_CONNECTIONS;
83 break;
85 case SQL_ACTIVE_STATEMENTS: /* ODBC 1.0 */
86 len = 2;
87 value = 0;
88 break;
90 case SQL_ALTER_TABLE: /* ODBC 2.0 */
91 len = 4;
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;
107 break;
109 case SQL_BOOKMARK_PERSISTENCE: /* ODBC 2.0 */
110 /* very simple bookmark support */
111 len = 4;
112 value = 0;
113 break;
115 case SQL_COLUMN_ALIAS: /* ODBC 2.0 */
116 p = "N";
117 break;
119 case SQL_CONCAT_NULL_BEHAVIOR: /* ODBC 1.0 */
120 len = 2;
121 value = SQL_CB_NON_NULL;
122 break;
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);
132 break;
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 */
152 break;
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);
158 break;
160 case SQL_CORRELATION_NAME: /* ODBC 1.0 */
163 * Saying no correlation name makes Query not work right.
164 * value = SQL_CN_NONE;
166 len = 2;
167 value = SQL_CN_ANY;
168 break;
170 case SQL_CURSOR_COMMIT_BEHAVIOR: /* ODBC 1.0 */
171 len = 2;
172 value = SQL_CB_PRESERVE;
173 break;
175 case SQL_CURSOR_ROLLBACK_BEHAVIOR: /* ODBC 1.0 */
176 len = 2;
177 value = SQL_CB_PRESERVE;
178 break;
180 case SQL_DATA_SOURCE_NAME: /* ODBC 1.0 */
181 p = CC_get_DSN(conn);
182 break;
184 case SQL_DATA_SOURCE_READ_ONLY: /* ODBC 1.0 */
185 p = CC_is_onlyread(conn) ? "Y" : "N";
186 break;
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
193 * bad3"
195 * p = CC_get_database(conn);
197 p = CurrCatString(conn);
198 break;
200 case SQL_DBMS_NAME: /* ODBC 1.0 */
201 if (CC_fake_mss(conn))
202 p = "Microsoft SQL Server";
203 else
204 p = "PostgreSQL";
205 break;
207 case SQL_DBMS_VER: /* ODBC 1.0 */
210 * The ODBC spec wants ##.##.#### ...whatever... so prepend
211 * the driver
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))
218 p = "09.00.1399";
219 else
221 strncpy_null(tmp, conn->pg_version, sizeof(tmp));
222 p = tmp;
224 break;
226 case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */
227 len = 4;
228 if (PG_VERSION_LT(conn, 6.5))
229 value = SQL_TXN_SERIALIZABLE;
230 else
231 value = SQL_TXN_READ_COMMITTED;
232 break;
234 case SQL_DRIVER_NAME: /* ODBC 1.0 */
235 p = DRIVER_FILE_NAME;
236 break;
238 case SQL_DRIVER_ODBC_VER:
239 i_odbcver = conn->driver_version;
240 snprintf(odbcver, sizeof(odbcver), "%02x.%02x", i_odbcver / 256,
241 i_odbcver % 256);
242 /* p = DRIVER_ODBC_VER; */
243 p = odbcver;
244 break;
246 case SQL_DRIVER_VER: /* ODBC 1.0 */
247 p = VXODBCDRIVERVERSION;
248 break;
250 case SQL_EXPRESSIONS_IN_ORDERBY: /* ODBC 1.0 */
251 p = "N";
252 break;
254 case SQL_FETCH_DIRECTION: /* ODBC 1.0 */
255 len = 4;
256 value = (SQL_FD_FETCH_NEXT |
257 SQL_FD_FETCH_NEXT |
258 SQL_FD_FETCH_FIRST |
259 SQL_FD_FETCH_LAST |
260 SQL_FD_FETCH_PRIOR |
261 SQL_FD_FETCH_ABSOLUTE |
262 SQL_FD_FETCH_RELATIVE | SQL_FD_FETCH_BOOKMARK);
263 break;
265 case SQL_FILE_USAGE: /* ODBC 2.0 */
266 len = 2;
267 value = SQL_FILE_NOT_SUPPORTED;
268 break;
270 case SQL_GETDATA_EXTENSIONS: /* ODBC 2.0 */
271 len = 4;
272 value =
273 (SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND |
274 SQL_GD_BLOCK);
275 break;
277 case SQL_GROUP_BY: /* ODBC 2.0 */
278 len = 2;
279 value = SQL_GB_GROUP_BY_EQUALS_SELECT;
280 break;
282 case SQL_IDENTIFIER_CASE: /* ODBC 1.0 */
285 * are identifiers case-sensitive (yes, but only when quoted.
286 * If not quoted, they default to lowercase)
288 len = 2;
289 value = SQL_IC_LOWER;
290 break;
292 case SQL_IDENTIFIER_QUOTE_CHAR: /* ODBC 1.0 */
293 /* the character used to quote "identifiers" */
294 p = PG_VERSION_LE(conn, 6.2) ? " " : "\"";
295 break;
297 case SQL_KEYWORDS: /* ODBC 2.0 */
298 p = NULL_STRING;
299 break;
301 case SQL_LIKE_ESCAPE_CLAUSE: /* ODBC 2.0 */
304 * is there a character that escapes '%' and '_' in a LIKE
305 * clause? not as far as I can tell
307 p = "N";
308 break;
310 case SQL_LOCK_TYPES: /* ODBC 2.0 */
311 len = 4;
312 value = SQL_LCK_NO_CHANGE;
313 break;
315 case SQL_MAX_BINARY_LITERAL_LEN: /* ODBC 2.0 */
316 len = 4;
317 value = 0;
318 break;
320 case SQL_MAX_CHAR_LITERAL_LEN: /* ODBC 2.0 */
321 len = 4;
322 value = 0;
323 break;
325 case SQL_MAX_COLUMN_NAME_LEN: /* ODBC 1.0 */
326 // TODO: Look into MAX_COLUMN_LEN - is it sensible?
327 CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR,
328 "SQL_MAX_COLUMN_NAME_LEN not yet implemented.", NULL);
329 return SQL_ERROR;
330 break;
332 case SQL_MAX_COLUMNS_IN_GROUP_BY: /* ODBC 2.0 */
333 len = 2;
334 value = 0;
335 break;
337 case SQL_MAX_COLUMNS_IN_INDEX: /* ODBC 2.0 */
338 len = 2;
339 value = 0;
340 break;
342 case SQL_MAX_COLUMNS_IN_ORDER_BY: /* ODBC 2.0 */
343 len = 2;
344 value = 0;
345 break;
347 case SQL_MAX_COLUMNS_IN_SELECT: /* ODBC 2.0 */
348 len = 2;
349 value = 0;
350 break;
352 case SQL_MAX_COLUMNS_IN_TABLE: /* ODBC 2.0 */
353 len = 2;
354 value = 0;
355 break;
357 case SQL_MAX_CURSOR_NAME_LEN: /* ODBC 1.0 */
358 len = 2;
359 value = MAX_CURSOR_LEN;
360 break;
362 case SQL_MAX_INDEX_SIZE: /* ODBC 2.0 */
363 len = 4;
364 value = 0;
365 break;
367 case SQL_MAX_OWNER_NAME_LEN: /* ODBC 1.0 */
368 // TODO: Look into MAX_SCHEMA_LEN - is it sensible?
369 CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR,
370 "SQL_MAX_OWNER_NAME_LEN not yet implemented.", NULL);
371 return SQL_ERROR;
373 case SQL_MAX_PROCEDURE_NAME_LEN: /* ODBC 1.0 */
374 len = 2;
375 value = 0;
376 break;
378 case SQL_MAX_QUALIFIER_NAME_LEN: /* ODBC 1.0 */
379 len = 2;
380 value = 0;
381 break;
383 case SQL_MAX_ROW_SIZE: /* ODBC 2.0 */
384 len = 4;
385 if (PG_VERSION_GE(conn, 7.1))
387 /* Large Rowa in 7.1+ */
388 value = MAX_ROW_SIZE;
390 else
392 /* Without the Toaster we're limited to the blocksize */
393 value = BLCKSZ;
395 break;
397 case SQL_MAX_ROW_SIZE_INCLUDES_LONG: /* ODBC 2.0 */
400 * does the preceding value include LONGVARCHAR and
401 * LONGVARBINARY fields? Well, it does include longvarchar,
402 * but not longvarbinary.
404 p = "Y";
405 break;
407 case SQL_MAX_STATEMENT_LEN: /* ODBC 2.0 */
408 /* maybe this should be 0? */
409 len = 4;
410 value = CC_get_max_query_len(conn);
411 break;
413 case SQL_MAX_TABLE_NAME_LEN: /* ODBC 1.0 */
414 // TODO: Look into MAX_TABLE_LEN - is it sensible?
415 CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR,
416 "SQL_MAX_TABLE_NAME_LEN not yet implemented.", NULL);
417 return SQL_ERROR;
419 case SQL_MAX_TABLES_IN_SELECT: /* ODBC 2.0 */
420 len = 2;
421 value = 0;
422 break;
424 case SQL_MAX_USER_NAME_LEN:
425 len = 2;
426 value = 0;
427 break;
429 case SQL_MULT_RESULT_SETS: /* ODBC 1.0 */
430 /* Don't support multiple result sets but say yes anyway? */
431 p = "Y";
432 break;
434 case SQL_MULTIPLE_ACTIVE_TXN: /* ODBC 1.0 */
435 p = "Y";
436 break;
438 case SQL_NEED_LONG_DATA_LEN: /* ODBC 2.0 */
441 * Don't need the length, SQLPutData can handle any size and
442 * multiple calls
444 p = "N";
445 break;
447 case SQL_NON_NULLABLE_COLUMNS: /* ODBC 1.0 */
448 len = 2;
449 value = SQL_NNC_NON_NULL;
450 break;
452 case SQL_NULL_COLLATION: /* ODBC 2.0 */
453 /* where are nulls sorted? */
454 len = 2;
455 if (PG_VERSION_GE(conn, 7.2))
456 value = SQL_NC_HIGH;
457 else
458 value = SQL_NC_END;
459 break;
461 case SQL_NUMERIC_FUNCTIONS: /* ODBC 1.0 */
462 len = 4;
463 value = 0;
464 break;
466 case SQL_ODBC_API_CONFORMANCE: /* ODBC 1.0 */
467 len = 2;
468 value = SQL_OAC_LEVEL1;
469 break;
471 case SQL_ODBC_SAG_CLI_CONFORMANCE: /* ODBC 1.0 */
472 len = 2;
473 value = SQL_OSCC_NOT_COMPLIANT;
474 break;
476 case SQL_ODBC_SQL_CONFORMANCE: /* ODBC 1.0 */
477 len = 2;
478 value = SQL_OSC_CORE;
479 break;
481 case SQL_ODBC_SQL_OPT_IEF: /* ODBC 1.0 */
482 p = "N";
483 break;
485 case SQL_OJ_CAPABILITIES: /* ODBC 2.01 */
486 len = 4;
487 if (PG_VERSION_GE(conn, 7.1))
489 /* OJs in 7.1+ */
490 value = (SQL_OJ_LEFT |
491 SQL_OJ_RIGHT |
492 SQL_OJ_FULL |
493 SQL_OJ_NESTED |
494 SQL_OJ_NOT_ORDERED |
495 SQL_OJ_INNER | SQL_OJ_ALL_COMPARISON_OPS);
497 else
498 /* OJs not in <7.1 */
499 value = 0;
500 break;
502 case SQL_ORDER_BY_COLUMNS_IN_SELECT: /* ODBC 2.0 */
503 p = (PG_VERSION_LE(conn, 6.3)) ? "Y" : "N";
504 break;
506 case SQL_OUTER_JOINS: /* ODBC 1.0 */
507 if (PG_VERSION_GE(conn, 7.1))
508 /* OJs in 7.1+ */
509 p = "Y";
510 else
511 /* OJs not in <7.1 */
512 p = "N";
513 break;
515 case SQL_OWNER_TERM: /* ODBC 1.0 */
516 if (conn->schema_support)
517 p = "schema";
518 else
519 p = "owner";
520 break;
522 case SQL_OWNER_USAGE: /* ODBC 2.0 */
523 len = 4;
524 value = 0;
525 if (conn->schema_support)
526 value = SQL_OU_DML_STATEMENTS
527 | SQL_OU_TABLE_DEFINITION
528 | SQL_OU_INDEX_DEFINITION | SQL_OU_PRIVILEGE_DEFINITION;
529 break;
531 case SQL_POS_OPERATIONS: /* ODBC 2.0 */
532 len = 4;
533 value = (SQL_POS_POSITION | SQL_POS_REFRESH);
534 if (0 != ci->updatable_cursors)
535 value |= (SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD);
536 break;
538 case SQL_POSITIONED_STATEMENTS: /* ODBC 2.0 */
539 len = 4;
540 value = 0;
541 break;
543 case SQL_PROCEDURE_TERM: /* ODBC 1.0 */
544 p = "procedure";
545 break;
547 case SQL_PROCEDURES: /* ODBC 1.0 */
548 p = "Y";
549 break;
551 case SQL_QUALIFIER_LOCATION: /* ODBC 2.0 */
552 len = 2;
553 if (CurrCat(conn))
554 value = SQL_QL_START;
555 else
556 value = 0;
557 break;
559 case SQL_QUALIFIER_NAME_SEPARATOR: /* ODBC 1.0 */
560 if (CurrCat(conn))
561 p = ".";
562 else
563 p = NULL_STRING;
564 break;
566 case SQL_QUALIFIER_TERM: /* ODBC 1.0 */
567 if (CurrCat(conn))
568 p = "catalog";
569 else
570 p = NULL_STRING;
571 break;
573 case SQL_QUALIFIER_USAGE: /* ODBC 2.0 */
574 len = 4;
575 if (CurrCat(conn))
576 value = SQL_CU_DML_STATEMENTS;
577 else
578 value = 0;
579 break;
581 case SQL_QUOTED_IDENTIFIER_CASE: /* ODBC 2.0 */
582 /* are "quoted" identifiers case-sensitive? YES! */
583 len = 2;
584 value = SQL_IC_SENSITIVE;
585 break;
587 case SQL_ROW_UPDATES: /* ODBC 1.0 */
590 * Driver doesn't support keyset-driven or mixed cursors, so
591 * not much point in saying row updates are supported
593 p = (0 != ci->updatable_cursors) ? "Y" : "N";
594 break;
596 case SQL_SCROLL_CONCURRENCY: /* ODBC 1.0 */
597 len = 4;
598 value = SQL_SCCO_READ_ONLY;
599 if (0 != ci->updatable_cursors)
600 value |= SQL_SCCO_OPT_ROWVER;
601 break;
603 case SQL_SCROLL_OPTIONS: /* ODBC 1.0 */
604 len = 4;
605 value = SQL_SO_FORWARD_ONLY | SQL_SO_STATIC;
606 if (0 != (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
607 value |= SQL_SO_KEYSET_DRIVEN;
608 break;
610 case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */
611 if (PG_VERSION_GE(conn, 6.5))
612 p = "\\";
613 else
614 p = NULL_STRING;
615 break;
617 case SQL_SERVER_NAME: /* ODBC 1.0 */
618 p = CC_get_server(conn);
619 break;
621 case SQL_SPECIAL_CHARACTERS: /* ODBC 2.0 */
622 p = "_";
623 break;
625 case SQL_STATIC_SENSITIVITY: /* ODBC 2.0 */
626 len = 4;
627 value = 0;
628 if (0 != ci->updatable_cursors)
629 value |=
630 (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES);
631 break;
633 case SQL_STRING_FUNCTIONS: /* ODBC 1.0 */
634 len = 4;
635 value = (SQL_FN_STR_CONCAT |
636 SQL_FN_STR_LCASE |
637 SQL_FN_STR_LENGTH |
638 SQL_FN_STR_LOCATE |
639 SQL_FN_STR_LTRIM |
640 SQL_FN_STR_RTRIM |
641 SQL_FN_STR_SUBSTRING | SQL_FN_STR_UCASE);
642 break;
644 case SQL_SUBQUERIES: /* ODBC 2.0 */
645 /* postgres 6.3 supports subqueries */
646 len = 4;
647 value = (SQL_SQ_QUANTIFIED |
648 SQL_SQ_IN | SQL_SQ_EXISTS | SQL_SQ_COMPARISON);
649 break;
651 case SQL_SYSTEM_FUNCTIONS: /* ODBC 1.0 */
652 len = 4;
653 value = 0;
654 break;
656 case SQL_TABLE_TERM: /* ODBC 1.0 */
657 p = "table";
658 break;
660 case SQL_TIMEDATE_ADD_INTERVALS: /* ODBC 2.0 */
661 len = 4;
662 value = 0;
663 break;
665 case SQL_TIMEDATE_DIFF_INTERVALS: /* ODBC 2.0 */
666 len = 4;
667 value = 0;
668 break;
670 case SQL_TIMEDATE_FUNCTIONS: /* ODBC 1.0 */
671 len = 4;
672 value = (SQL_FN_TD_NOW);
673 break;
675 case SQL_TXN_CAPABLE: /* ODBC 1.0 */
678 * Postgres can deal with create or drop table statements in a
679 * transaction
681 len = 2;
682 value = SQL_TC_ALL;
683 break;
685 case SQL_TXN_ISOLATION_OPTION: /* ODBC 1.0 */
686 len = 4;
687 if (PG_VERSION_LT(conn, 6.5))
688 value = SQL_TXN_SERIALIZABLE;
689 else if (PG_VERSION_GE(conn, 7.1))
690 value = SQL_TXN_READ_COMMITTED | SQL_TXN_SERIALIZABLE;
691 else
692 value = SQL_TXN_READ_COMMITTED;
693 break;
695 case SQL_UNION: /* ODBC 2.0 */
696 /* unions with all supported in postgres 6.3 */
697 len = 4;
698 value = (SQL_U_UNION | SQL_U_UNION_ALL);
699 break;
701 case SQL_USER_NAME: /* ODBC 1.0 */
702 p = CC_get_username(conn);
703 break;
705 default:
706 /* unrecognized key */
707 CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR,
708 "Unrecognized key passed to PGAPI_GetInfo.", NULL);
709 return SQL_ERROR;
712 result = SQL_SUCCESS;
714 mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func,
715 p ? p : "<NULL>", len, value, cbInfoValueMax);
718 * NOTE, that if rgbInfoValue is NULL, then no warnings or errors
719 * should result and just pcbInfoValue is returned, which indicates
720 * what length would be required if a real buffer had been passed in.
722 if (p)
724 /* char/binary data */
725 len = strlen(p);
727 if (rgbInfoValue)
729 if (CC_is_in_unicode_driver(conn))
731 len =
732 utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue,
733 cbInfoValueMax / WCLEN);
734 len *= WCLEN;
736 else
737 strncpy_null((char *) rgbInfoValue, p,
738 (size_t) cbInfoValueMax);
740 if (len >= cbInfoValueMax)
742 result = SQL_SUCCESS_WITH_INFO;
743 CC_set_error(conn, CONN_TRUNCATED,
744 "The buffer was too small for the InfoValue.",
745 func);
748 #ifdef UNICODE_SUPPORT
749 else if (CC_is_in_unicode_driver(conn))
750 len *= WCLEN;
751 #endif /* UNICODE_SUPPORT */
753 else
755 /* numeric data */
756 if (rgbInfoValue)
758 if (len == sizeof(SQLSMALLINT))
759 *((SQLUSMALLINT *) rgbInfoValue) = (SQLUSMALLINT) value;
760 else if (len == sizeof(SQLINTEGER))
761 *((SQLUINTEGER *) rgbInfoValue) = (SQLUINTEGER) value;
765 if (pcbInfoValue)
766 *pcbInfoValue = (SQLSMALLINT) len;
768 return result;
771 RETCODE SQL_API PGAPI_GetTypeInfo(HSTMT hstmt, SQLSMALLINT fSqlType)
773 CSTR func = "PGAPI_GetTypeInfo";
774 StatementClass *stmt = (StatementClass *) hstmt;
775 ConnectionClass *conn;
776 QResultClass *res;
777 TupleField *tuple;
778 int i, result_cols;
780 /* Int4 type; */
781 Int4 pgType;
782 Int2 sqlType;
783 RETCODE result = SQL_SUCCESS;
785 mylog("%s: entering...fSqlType = %d\n", func, fSqlType);
787 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
788 return result;
790 conn = SC_get_conn(stmt);
791 if (res = QR_Constructor(), !res)
793 SC_set_error(stmt, STMT_INTERNAL_ERROR,
794 "Error creating result.", func);
795 return SQL_ERROR;
797 SC_set_Result(stmt, res);
799 #define return DONT_CALL_RETURN_FROM_HERE???
800 result_cols = 19;
801 extend_column_bindings(SC_get_ARDF(stmt), result_cols);
803 stmt->catalog_result = TRUE;
804 QR_set_num_fields(res, result_cols);
805 QR_set_field_info_v(res, 0, "TYPE_NAME", PG_TYPE_VARCHAR,
806 MAX_INFO_STRING);
807 QR_set_field_info_v(res, 1, "DATA_TYPE", PG_TYPE_INT2, 2);
808 QR_set_field_info_v(res, 2, "PRECISION", PG_TYPE_INT4, 4);
809 QR_set_field_info_v(res, 3, "LITERAL_PREFIX", PG_TYPE_VARCHAR,
810 MAX_INFO_STRING);
811 QR_set_field_info_v(res, 4, "LITERAL_SUFFIX", PG_TYPE_VARCHAR,
812 MAX_INFO_STRING);
813 QR_set_field_info_v(res, 5, "CREATE_PARAMS", PG_TYPE_VARCHAR,
814 MAX_INFO_STRING);
815 QR_set_field_info_v(res, 6, "NULLABLE", PG_TYPE_INT2, 2);
816 QR_set_field_info_v(res, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2);
817 QR_set_field_info_v(res, 8, "SEARCHABLE", PG_TYPE_INT2, 2);
818 QR_set_field_info_v(res, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2);
819 QR_set_field_info_v(res, 10, "MONEY", PG_TYPE_INT2, 2);
820 QR_set_field_info_v(res, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2);
821 QR_set_field_info_v(res, 12, "LOCAL_TYPE_NAME", PG_TYPE_VARCHAR,
822 MAX_INFO_STRING);
823 QR_set_field_info_v(res, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
824 QR_set_field_info_v(res, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
825 QR_set_field_info_v(res, 15, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
826 QR_set_field_info_v(res, 16, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
827 QR_set_field_info_v(res, 17, "NUM_PREC_RADIX", PG_TYPE_INT4, 4);
828 QR_set_field_info_v(res, 18, "INTERVAL_PRECISION", PG_TYPE_INT2, 2);
830 for (i = 0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i])
832 pgType = sqltype_to_pgtype(stmt, sqlType);
834 if (sqlType == SQL_LONGVARBINARY)
836 ConnInfo *ci = &(conn->connInfo);
837 inolog("%d sqltype=%d -> pgtype=%d\n",
838 ci->bytea_as_longvarbinary, sqlType, pgType);
841 if (fSqlType == SQL_ALL_TYPES || fSqlType == sqlType)
843 int pgtcount = 1, aunq_match = -1, cnt;
845 /*if (SQL_INTEGER == sqlType || SQL_TINYINT == sqlType) */
846 if (SQL_INTEGER == sqlType)
848 mylog("sqlType=%d ms_jet=%d\n", sqlType, conn->ms_jet);
849 if (conn->ms_jet && PG_VERSION_GE(conn, 6.4))
851 aunq_match = 1;
852 pgtcount = 2;
854 mylog("aunq_match=%d pgtcount=%d\n", aunq_match,
855 pgtcount);
857 for (cnt = 0; cnt < pgtcount; cnt++)
859 tuple = QR_AddNew(res);
861 /* These values can't be NULL */
862 if (aunq_match == cnt)
864 set_tuplefield_string(&tuple[0],
865 pgtype_to_name(stmt, pgType,
866 TRUE));
867 set_tuplefield_int2(&tuple[6], SQL_NO_NULLS);
868 inolog("serial in\n");
870 else
872 set_tuplefield_string(&tuple[0],
873 pgtype_to_name(stmt, pgType,
874 FALSE));
875 set_tuplefield_int2(&tuple[6],
876 pgtype_nullable(stmt, pgType));
878 set_tuplefield_int2(&tuple[1], (Int2) sqlType);
879 set_tuplefield_int2(&tuple[7],
880 pgtype_case_sensitive(stmt,
881 pgType));
882 set_tuplefield_int2(&tuple[8],
883 pgtype_searchable(stmt, pgType));
884 set_tuplefield_int2(&tuple[10],
885 pgtype_money(stmt, pgType));
888 * Localized data-source dependent data type name (always
889 * NULL)
891 set_tuplefield_null(&tuple[12]);
893 /* These values can be NULL */
894 set_nullfield_int4(&tuple[2],
895 pgtype_column_size(stmt, pgType,
896 PG_STATIC,
897 PG_STATIC));
898 set_nullfield_string(&tuple[3],
899 pgtype_literal_prefix(stmt,
900 pgType));
901 set_nullfield_string(&tuple[4],
902 pgtype_literal_suffix(stmt,
903 pgType));
904 set_nullfield_string(&tuple[5],
905 pgtype_create_params(stmt,
906 pgType));
907 if (1 < pgtcount)
908 set_tuplefield_int2(&tuple[9], SQL_TRUE);
909 else
910 set_nullfield_int2(&tuple[9],
911 pgtype_unsigned(stmt, pgType));
912 if (aunq_match == cnt)
913 set_tuplefield_int2(&tuple[11], SQL_TRUE);
914 else
915 set_nullfield_int2(&tuple[11],
916 pgtype_auto_increment(stmt,
917 pgType));
918 set_nullfield_int2(&tuple[13],
919 pgtype_min_decimal_digits(stmt,
920 pgType));
921 set_nullfield_int2(&tuple[14],
922 pgtype_max_decimal_digits(stmt,
923 pgType));
924 set_nullfield_int2(&tuple[15],
925 pgtype_to_sqldesctype(stmt, pgType,
926 PG_STATIC));
927 set_nullfield_int2(&tuple[16],
928 pgtype_to_datetime_sub(stmt,
929 pgType));
930 set_nullfield_int4(&tuple[17],
931 pgtype_radix(stmt, pgType));
932 set_nullfield_int4(&tuple[18], 0);
937 #undef return
939 * also, things need to think that this statement is finished so the
940 * results can be retrieved.
942 stmt->status = STMT_FINISHED;
943 stmt->currTuple = -1;
944 SC_set_rowset_start(stmt, -1, FALSE);
945 SC_set_current_col(stmt, -1);
947 if (stmt->internal)
948 result = DiscardStatementSvp(stmt, result, FALSE);
949 return result;
952 RETCODE SQL_API
953 PGAPI_GetFunctions(HDBC hdbc,
954 SQLUSMALLINT fFunction, SQLUSMALLINT FAR * pfExists)
956 CSTR func = "PGAPI_GetFunctions";
957 ConnectionClass *conn = (ConnectionClass *) hdbc;
958 ConnInfo *ci = &(conn->connInfo);
960 mylog("%s: entering...%u\n", func, fFunction);
962 if (fFunction == SQL_API_ALL_FUNCTIONS)
965 memset(pfExists, 0, sizeof(pfExists[0]) * 100);
967 /* ODBC core functions */
968 pfExists[SQL_API_SQLALLOCCONNECT] = TRUE;
969 pfExists[SQL_API_SQLALLOCENV] = TRUE;
970 pfExists[SQL_API_SQLALLOCSTMT] = TRUE;
971 pfExists[SQL_API_SQLBINDCOL] = TRUE;
972 pfExists[SQL_API_SQLCANCEL] = TRUE;
973 pfExists[SQL_API_SQLCOLATTRIBUTES] = TRUE;
974 pfExists[SQL_API_SQLCONNECT] = TRUE;
975 pfExists[SQL_API_SQLDESCRIBECOL] = TRUE; /* partial */
976 pfExists[SQL_API_SQLDISCONNECT] = TRUE;
977 pfExists[SQL_API_SQLERROR] = TRUE;
978 pfExists[SQL_API_SQLEXECDIRECT] = TRUE;
979 pfExists[SQL_API_SQLEXECUTE] = TRUE;
980 pfExists[SQL_API_SQLFETCH] = TRUE;
981 pfExists[SQL_API_SQLFREECONNECT] = TRUE;
982 pfExists[SQL_API_SQLFREEENV] = TRUE;
983 pfExists[SQL_API_SQLFREESTMT] = TRUE;
984 pfExists[SQL_API_SQLGETCURSORNAME] = TRUE;
985 pfExists[SQL_API_SQLNUMRESULTCOLS] = TRUE;
986 pfExists[SQL_API_SQLPREPARE] = TRUE; /* complete? */
987 pfExists[SQL_API_SQLROWCOUNT] = TRUE;
988 pfExists[SQL_API_SQLSETCURSORNAME] = TRUE;
989 pfExists[SQL_API_SQLSETPARAM] = FALSE; /* odbc 1.0 */
990 pfExists[SQL_API_SQLTRANSACT] = TRUE;
992 /* ODBC level 1 functions */
993 pfExists[SQL_API_SQLBINDPARAMETER] = TRUE;
994 pfExists[SQL_API_SQLCOLUMNS] = TRUE;
995 pfExists[SQL_API_SQLDRIVERCONNECT] = TRUE;
996 pfExists[SQL_API_SQLGETCONNECTOPTION] = TRUE; /* partial */
997 pfExists[SQL_API_SQLGETDATA] = TRUE;
998 pfExists[SQL_API_SQLGETFUNCTIONS] = TRUE;
999 pfExists[SQL_API_SQLGETINFO] = TRUE;
1000 pfExists[SQL_API_SQLGETSTMTOPTION] = TRUE; /* partial */
1001 pfExists[SQL_API_SQLGETTYPEINFO] = TRUE;
1002 pfExists[SQL_API_SQLPARAMDATA] = TRUE;
1003 pfExists[SQL_API_SQLPUTDATA] = TRUE;
1004 pfExists[SQL_API_SQLSETCONNECTOPTION] = TRUE; /* partial */
1005 pfExists[SQL_API_SQLSETSTMTOPTION] = TRUE;
1006 pfExists[SQL_API_SQLSPECIALCOLUMNS] = TRUE;
1007 pfExists[SQL_API_SQLSTATISTICS] = TRUE;
1008 pfExists[SQL_API_SQLTABLES] = TRUE;
1010 /* ODBC level 2 functions */
1011 pfExists[SQL_API_SQLBROWSECONNECT] = FALSE;
1012 if (PG_VERSION_GE(conn, 7.4))
1013 pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
1014 else
1015 pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
1016 pfExists[SQL_API_SQLDATASOURCES] = FALSE; /* only implemented by
1017 * DM */
1018 if (SUPPORT_DESCRIBE_PARAM(ci))
1019 pfExists[SQL_API_SQLDESCRIBEPARAM] = TRUE;
1020 else
1021 pfExists[SQL_API_SQLDESCRIBEPARAM] = FALSE; /* not properly
1022 * implemented */
1023 pfExists[SQL_API_SQLDRIVERS] = FALSE; /* only implemented by
1024 * DM */
1025 pfExists[SQL_API_SQLEXTENDEDFETCH] = TRUE;
1026 pfExists[SQL_API_SQLFOREIGNKEYS] = TRUE;
1027 pfExists[SQL_API_SQLMORERESULTS] = TRUE;
1028 pfExists[SQL_API_SQLNATIVESQL] = TRUE;
1029 pfExists[SQL_API_SQLNUMPARAMS] = TRUE;
1030 pfExists[SQL_API_SQLPARAMOPTIONS] = TRUE;
1031 pfExists[SQL_API_SQLPRIMARYKEYS] = TRUE;
1032 if (PG_VERSION_LT(conn, 6.5))
1033 pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE;
1034 else
1035 pfExists[SQL_API_SQLPROCEDURECOLUMNS] = TRUE;
1036 if (PG_VERSION_LT(conn, 6.5))
1037 pfExists[SQL_API_SQLPROCEDURES] = FALSE;
1038 else
1039 pfExists[SQL_API_SQLPROCEDURES] = TRUE;
1040 pfExists[SQL_API_SQLSETPOS] = TRUE;
1041 pfExists[SQL_API_SQLSETSCROLLOPTIONS] = TRUE; /* odbc 1.0 */
1042 pfExists[SQL_API_SQLTABLEPRIVILEGES] = TRUE;
1043 if (0 == ci->updatable_cursors)
1044 pfExists[SQL_API_SQLBULKOPERATIONS] = FALSE;
1045 else
1046 pfExists[SQL_API_SQLBULKOPERATIONS] = TRUE;
1049 else
1051 switch (fFunction)
1053 case SQL_API_SQLBINDCOL:
1054 *pfExists = TRUE;
1055 break;
1056 case SQL_API_SQLCANCEL:
1057 *pfExists = TRUE;
1058 break;
1059 case SQL_API_SQLCOLATTRIBUTE:
1060 *pfExists = TRUE;
1061 break;
1062 case SQL_API_SQLCONNECT:
1063 *pfExists = TRUE;
1064 break;
1065 case SQL_API_SQLDESCRIBECOL:
1066 *pfExists = TRUE;
1067 break; /* partial */
1068 case SQL_API_SQLDISCONNECT:
1069 *pfExists = TRUE;
1070 break;
1071 case SQL_API_SQLEXECDIRECT:
1072 *pfExists = TRUE;
1073 break;
1074 case SQL_API_SQLEXECUTE:
1075 *pfExists = TRUE;
1076 break;
1077 case SQL_API_SQLFETCH:
1078 *pfExists = TRUE;
1079 break;
1080 case SQL_API_SQLFREESTMT:
1081 *pfExists = TRUE;
1082 break;
1083 case SQL_API_SQLGETCURSORNAME:
1084 *pfExists = TRUE;
1085 break;
1086 case SQL_API_SQLNUMRESULTCOLS:
1087 *pfExists = TRUE;
1088 break;
1089 case SQL_API_SQLPREPARE:
1090 *pfExists = TRUE;
1091 break;
1092 case SQL_API_SQLROWCOUNT:
1093 *pfExists = TRUE;
1094 break;
1095 case SQL_API_SQLSETCURSORNAME:
1096 *pfExists = TRUE;
1097 break;
1099 /* ODBC level 1 functions */
1100 case SQL_API_SQLBINDPARAMETER:
1101 *pfExists = TRUE;
1102 break;
1103 case SQL_API_SQLCOLUMNS:
1104 *pfExists = TRUE;
1105 break;
1106 case SQL_API_SQLDRIVERCONNECT:
1107 *pfExists = TRUE;
1108 break;
1109 case SQL_API_SQLGETDATA:
1110 *pfExists = TRUE;
1111 break;
1112 case SQL_API_SQLGETFUNCTIONS:
1113 *pfExists = TRUE;
1114 break;
1115 case SQL_API_SQLGETINFO:
1116 *pfExists = TRUE;
1117 break;
1118 case SQL_API_SQLGETTYPEINFO:
1119 *pfExists = TRUE;
1120 break;
1121 case SQL_API_SQLPARAMDATA:
1122 *pfExists = TRUE;
1123 break;
1124 case SQL_API_SQLPUTDATA:
1125 *pfExists = TRUE;
1126 break;
1127 case SQL_API_SQLSPECIALCOLUMNS:
1128 *pfExists = TRUE;
1129 break;
1130 case SQL_API_SQLSTATISTICS:
1131 *pfExists = TRUE;
1132 break;
1133 case SQL_API_SQLTABLES:
1134 *pfExists = TRUE;
1135 break;
1137 /* ODBC level 2 functions */
1138 case SQL_API_SQLBROWSECONNECT:
1139 *pfExists = FALSE;
1140 break;
1141 case SQL_API_SQLCOLUMNPRIVILEGES:
1142 *pfExists = FALSE;
1143 break;
1144 case SQL_API_SQLDATASOURCES:
1145 *pfExists = FALSE;
1146 break; /* only implemented by DM */
1147 case SQL_API_SQLDESCRIBEPARAM:
1148 if (SUPPORT_DESCRIBE_PARAM(ci))
1149 *pfExists = TRUE;
1150 else
1151 *pfExists = FALSE;
1152 break; /* not properly implemented */
1153 case SQL_API_SQLDRIVERS:
1154 *pfExists = FALSE;
1155 break; /* only implemented by DM */
1156 case SQL_API_SQLEXTENDEDFETCH:
1157 *pfExists = TRUE;
1158 break;
1159 case SQL_API_SQLFOREIGNKEYS:
1160 *pfExists = TRUE;
1161 break;
1162 case SQL_API_SQLMORERESULTS:
1163 *pfExists = TRUE;
1164 break;
1165 case SQL_API_SQLNATIVESQL:
1166 *pfExists = TRUE;
1167 break;
1168 case SQL_API_SQLNUMPARAMS:
1169 *pfExists = TRUE;
1170 break;
1171 case SQL_API_SQLPRIMARYKEYS:
1172 *pfExists = TRUE;
1173 break;
1174 case SQL_API_SQLPROCEDURECOLUMNS:
1175 if (PG_VERSION_LT(conn, 6.5))
1176 *pfExists = FALSE;
1177 else
1178 *pfExists = TRUE;
1179 break;
1180 case SQL_API_SQLPROCEDURES:
1181 if (PG_VERSION_LT(conn, 6.5))
1182 *pfExists = FALSE;
1183 else
1184 *pfExists = TRUE;
1185 break;
1186 case SQL_API_SQLSETPOS:
1187 *pfExists = TRUE;
1188 break;
1189 case SQL_API_SQLTABLEPRIVILEGES:
1190 *pfExists = TRUE;
1191 break;
1192 case SQL_API_SQLBULKOPERATIONS: /* 24 */
1193 case SQL_API_SQLALLOCHANDLE: /* 1001 */
1194 case SQL_API_SQLBINDPARAM: /* 1002 */
1195 case SQL_API_SQLCLOSECURSOR: /* 1003 */
1196 case SQL_API_SQLENDTRAN: /* 1005 */
1197 case SQL_API_SQLFETCHSCROLL: /* 1021 */
1198 case SQL_API_SQLFREEHANDLE: /* 1006 */
1199 case SQL_API_SQLGETCONNECTATTR: /* 1007 */
1200 case SQL_API_SQLGETDESCFIELD: /* 1008 */
1201 case SQL_API_SQLGETDIAGFIELD: /* 1010 */
1202 case SQL_API_SQLGETDIAGREC: /* 1011 */
1203 case SQL_API_SQLGETENVATTR: /* 1012 */
1204 case SQL_API_SQLGETSTMTATTR: /* 1014 */
1205 case SQL_API_SQLSETCONNECTATTR: /* 1016 */
1206 case SQL_API_SQLSETDESCFIELD: /* 1017 */
1207 case SQL_API_SQLSETENVATTR: /* 1019 */
1208 case SQL_API_SQLSETSTMTATTR: /* 1020 */
1209 *pfExists = TRUE;
1210 break;
1211 case SQL_API_SQLGETDESCREC: /* 1009 */
1212 case SQL_API_SQLSETDESCREC: /* 1018 */
1213 case SQL_API_SQLCOPYDESC: /* 1004 */
1214 *pfExists = FALSE;
1215 break;
1216 default:
1217 *pfExists = FALSE;
1218 break;
1221 return SQL_SUCCESS;
1224 static char *simpleCatalogEscape(const void *_src, int srclen,
1225 int *result_len,
1226 const ConnectionClass * conn)
1228 int i, outlen;
1229 const char *src = (const char *)_src, *in;
1230 char *dest = NULL, escape_ch = CC_get_escape(conn);
1231 encoded_str encstr;
1233 if (result_len)
1234 *result_len = 0;
1235 if (!src || srclen == SQL_NULL_DATA)
1236 return dest;
1237 else if (srclen == SQL_NTS)
1238 srclen = (int) strlen(src);
1239 if (srclen <= 0)
1240 return dest;
1241 mylog("simple in=%s(%d)\n", src, srclen);
1242 encoded_str_constr(&encstr, conn->ccsc, src);
1243 dest = (char *)malloc(2 * srclen + 1);
1244 for (i = 0, in = src, outlen = 0; i < srclen; i++, in++)
1246 encoded_nextchar(&encstr);
1247 if (ENCODE_STATUS(encstr) != 0)
1249 dest[outlen++] = *in;
1250 continue;
1252 if (LITERAL_QUOTE == *in || escape_ch == *in)
1253 dest[outlen++] = *in;
1254 dest[outlen++] = *in;
1256 dest[outlen] = '\0';
1257 if (result_len)
1258 *result_len = outlen;
1259 mylog("simple output=%s(%d)\n", dest, outlen);
1260 return dest;
1264 * PostgreSQL needs 2 '\\' to escape '_' and '%'.
1266 static char *adjustLikePattern(const void *_src, int srclen,
1267 char escape_ch, int *result_len,
1268 const ConnectionClass * conn)
1270 int i, outlen;
1271 const char *src = (const char *)_src, *in;
1272 char *dest = NULL, escape_in_literal = CC_get_escape(conn);
1273 BOOL escape_in = FALSE;
1274 encoded_str encstr;
1276 if (result_len)
1277 *result_len = 0;
1278 if (!src || srclen == SQL_NULL_DATA)
1279 return dest;
1280 else if (srclen == SQL_NTS)
1281 srclen = (int) strlen(src);
1282 /* if (srclen <= 0) */
1283 if (srclen < 0)
1284 return dest;
1285 mylog("adjust in=%s(%d)\n", src, srclen);
1286 encoded_str_constr(&encstr, conn->ccsc, src);
1287 dest = (char *)malloc(2 * srclen + 1);
1288 for (i = 0, in = src, outlen = 0; i < srclen; i++, in++)
1290 encoded_nextchar(&encstr);
1291 if (ENCODE_STATUS(encstr) != 0)
1293 dest[outlen++] = *in;
1294 continue;
1296 if (escape_in)
1298 switch (*in)
1300 case '%':
1301 case '_':
1302 if (escape_ch == escape_in_literal)
1303 dest[outlen++] = escape_in_literal; /* and insert 1 more LEXER escape */
1304 dest[outlen++] = escape_ch;
1305 break;
1306 default:
1307 if (escape_ch == escape_in_literal)
1308 dest[outlen++] = escape_in_literal;
1309 dest[outlen++] = escape_ch;
1310 if (escape_ch == escape_in_literal)
1311 dest[outlen++] = escape_in_literal;
1312 dest[outlen++] = escape_ch;
1313 break;
1316 if (*in == escape_ch)
1317 escape_in = TRUE;
1318 else
1320 escape_in = FALSE;
1321 if (LITERAL_QUOTE == *in)
1322 dest[outlen++] = *in;
1323 dest[outlen++] = *in;
1326 dest[outlen] = '\0';
1327 if (result_len)
1328 *result_len = outlen;
1329 mylog("adjust output=%s(%d)\n", dest, outlen);
1330 return dest;
1335 * FIXME: we always return all tables, not parsing for wildcards, catalogs,
1336 * etc. This seems to be good enough for now but could easily explode in
1337 * some apps.
1339 RETCODE SQL_API PGAPI_Tables
1340 (HSTMT hstmt,
1341 const SQLCHAR FAR * szTableQualifier, /* PV X */
1342 SQLSMALLINT cbTableQualifier,
1343 const SQLCHAR FAR *szTableOwner, /* PV E */
1344 SQLSMALLINT cbTableOwner,
1345 const SQLCHAR FAR *szTableName, /* PV E */
1346 SQLSMALLINT cbTableName,
1347 const SQLCHAR FAR *szTableType,
1348 SQLSMALLINT cbTableType, UWORD flag)
1350 StatementClass *stmt = (StatementClass *)hstmt;
1352 VxStatement st(stmt);
1353 VxResultSet rs;
1354 st.reinit();
1355 rs.runquery(st.dbus(), "ExecChunkRecordset", "LIST TABLES");
1356 st.set_result(rs);
1357 stmt->catalog_result = TRUE;
1359 cleanup:
1360 return st.retcode();
1364 RETCODE SQL_API PGAPI_Columns(HSTMT hstmt, const SQLCHAR FAR * szTableQualifier, /* OA X */
1365 SQLSMALLINT cbTableQualifier, const SQLCHAR FAR * szTableOwner, /* PV E */
1366 SQLSMALLINT cbTableOwner, const SQLCHAR FAR * szTableName, /* PV E */
1367 SQLSMALLINT cbTableName, const SQLCHAR FAR * szColumnName, /* PV E */
1368 SQLSMALLINT cbColumnName,
1369 UWORD flag, OID reloid, Int2 attnum)
1371 StatementClass *stmt = (StatementClass *)hstmt;
1373 VxStatement st(stmt);
1374 VxResultSet rs;
1375 st.reinit();
1376 rs.runquery(st.dbus(), "ExecChunkRecordset",
1377 WvString("LIST COLUMNS %s", (const char *)szTableName));
1378 st.set_result(rs);
1379 stmt->catalog_result = TRUE;
1381 cleanup:
1382 return st.retcode();
1386 RETCODE SQL_API PGAPI_SpecialColumns(HSTMT hstmt, SQLUSMALLINT fColType, const SQLCHAR FAR * szTableQualifier, SQLSMALLINT cbTableQualifier, const SQLCHAR FAR * szTableOwner, /* OA E */
1387 SQLSMALLINT cbTableOwner, const SQLCHAR FAR * szTableName, /* OA(R) E */
1388 SQLSMALLINT cbTableName,
1389 SQLUSMALLINT fScope,
1390 SQLUSMALLINT fNullable)
1392 CSTR func = "PGAPI_SpecialColumns";
1393 TupleField *tuple;
1394 StatementClass *stmt = (StatementClass *) hstmt;
1395 ConnectionClass *conn;
1396 QResultClass *res;
1397 ConnInfo *ci;
1398 HSTMT hcol_stmt = NULL;
1399 StatementClass *col_stmt;
1400 char columns_query[INFO_INQUIRY_LEN];
1401 char *escSchemaName = NULL, *escTableName = NULL;
1402 RETCODE result = SQL_SUCCESS;
1403 char relhasrules[MAX_INFO_STRING], relkind[8], relhasoids[8];
1404 BOOL relisaview;
1405 SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName;
1406 const char *szSchemaName;
1408 mylog("%s: entering...stmt=%p scnm=%p len=%d colType=%d\n", func,
1409 stmt, NULL_IF_NULL(szTableOwner), cbTableOwner, fColType);
1411 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
1412 return result;
1413 conn = SC_get_conn(stmt);
1414 ci = &(conn->connInfo);
1415 #ifdef UNICODE_SUPPORT
1416 if (CC_is_in_unicode_driver(conn))
1417 internal_asis_type = INTERNAL_ASIS_TYPE;
1418 #endif /* UNICODE_SUPPORT */
1420 szSchemaName = (const char *)szTableOwner;
1421 cbSchemaName = cbTableOwner;
1423 escTableName =
1424 simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
1425 if (!escTableName)
1427 SC_set_error(stmt, STMT_INVALID_NULL_ARG,
1428 "The table name is required", func);
1429 return result;
1431 #define return DONT_CALL_RETURN_FROM_HERE???
1433 retry_public_schema:
1434 if (escSchemaName)
1435 free(escSchemaName);
1436 escSchemaName =
1437 simpleCatalogEscape((const UCHAR *)szSchemaName, cbSchemaName, NULL, conn);
1439 * Create the query to find out if this is a view or not...
1441 strcpy(columns_query, "select c.relhasrules, c.relkind");
1442 if (PG_VERSION_GE(conn, 7.2))
1443 strcat(columns_query, ", c.relhasoids");
1444 if (conn->schema_support)
1445 strcat(columns_query, " from pg_catalog.pg_namespace u,"
1446 " pg_catalog.pg_class c where "
1447 "u.oid = c.relnamespace");
1448 else
1449 strcat(columns_query, " from pg_user u, pg_class c where "
1450 "u.usesysid = c.relowner");
1452 /* TableName cannot contain a string search pattern */
1453 /* my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName); */
1454 if (escTableName)
1455 snprintf_add(columns_query, sizeof(columns_query),
1456 " and c.relname = '%s'", escTableName);
1457 /* SchemaName cannot contain a string search pattern */
1458 if (conn->schema_support)
1459 schema_strcat(columns_query, " and u.nspname = '%.*s'",
1460 escSchemaName, SQL_NTS, (const char *)szTableName,
1461 cbTableName, conn);
1462 else
1463 my_strcat(columns_query, " and u.usename = '%.*s'",
1464 escSchemaName, SQL_NTS);
1466 result = PGAPI_AllocStmt(conn, &hcol_stmt);
1467 if (!SQL_SUCCEEDED(result))
1469 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
1470 "Couldn't allocate statement for SQLSpecialColumns result.",
1471 func);
1472 result = SQL_ERROR;
1473 goto cleanup;
1475 col_stmt = (StatementClass *) hcol_stmt;
1477 mylog("%s: hcol_stmt = %p, col_stmt = %p\n", func, hcol_stmt,
1478 col_stmt);
1480 result = PGAPI_ExecDirect(hcol_stmt, (const UCHAR *)columns_query, SQL_NTS, 0);
1481 if (!SQL_SUCCEEDED(result))
1483 SC_full_error_copy(stmt, col_stmt, FALSE);
1484 result = SQL_ERROR;
1485 goto cleanup;
1488 /* If not found */
1489 if (conn->schema_support &&
1490 (res = SC_get_Result(col_stmt)) &&
1491 0 == QR_get_num_total_tuples(res))
1493 const char *user = CC_get_username(conn);
1496 * If specified schema name == user_name and
1497 * the current schema is 'public',
1498 * retry the 'public' schema.
1500 if (szSchemaName &&
1501 (cbSchemaName == SQL_NTS ||
1502 cbSchemaName == (SQLSMALLINT) strlen(user)) &&
1503 strnicmp(szSchemaName, user, strlen(user)) == 0 &&
1504 stricmp(CC_get_current_schema(conn), pubstr) == 0)
1506 PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
1507 hcol_stmt = NULL;
1508 szSchemaName = pubstr;
1509 cbSchemaName = SQL_NTS;
1510 goto retry_public_schema;
1514 result = PGAPI_BindCol(hcol_stmt, 1, internal_asis_type,
1515 relhasrules, sizeof(relhasrules), NULL);
1516 if (!SQL_SUCCEEDED(result))
1518 SC_error_copy(stmt, col_stmt, TRUE);
1519 result = SQL_ERROR;
1520 goto cleanup;
1523 result = PGAPI_BindCol(hcol_stmt, 2, internal_asis_type,
1524 relkind, sizeof(relkind), NULL);
1525 if (!SQL_SUCCEEDED(result))
1527 SC_error_copy(stmt, col_stmt, TRUE);
1528 result = SQL_ERROR;
1529 goto cleanup;
1531 relhasoids[0] = '1';
1532 if (PG_VERSION_GE(conn, 7.2))
1534 result = PGAPI_BindCol(hcol_stmt, 3, internal_asis_type,
1535 relhasoids, sizeof(relhasoids), NULL);
1536 if (!SQL_SUCCEEDED(result))
1538 SC_error_copy(stmt, col_stmt, TRUE);
1539 result = SQL_ERROR;
1540 goto cleanup;
1544 result = PGAPI_Fetch(hcol_stmt);
1545 if (PG_VERSION_GE(conn, 7.1))
1546 relisaview = (relkind[0] == 'v');
1547 else
1548 relisaview = (relhasrules[0] == '1');
1549 PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
1550 hcol_stmt = NULL;
1552 res = QR_Constructor();
1553 SC_set_Result(stmt, res);
1554 extend_column_bindings(SC_get_ARDF(stmt), 8);
1556 stmt->catalog_result = TRUE;
1557 QR_set_num_fields(res, 8);
1558 QR_set_field_info_v(res, 0, "SCOPE", PG_TYPE_INT2, 2);
1559 QR_set_field_info_v(res, 1, "COLUMN_NAME", PG_TYPE_VARCHAR,
1560 MAX_INFO_STRING);
1561 QR_set_field_info_v(res, 2, "DATA_TYPE", PG_TYPE_INT2, 2);
1562 QR_set_field_info_v(res, 3, "TYPE_NAME", PG_TYPE_VARCHAR,
1563 MAX_INFO_STRING);
1564 QR_set_field_info_v(res, 4, "PRECISION", PG_TYPE_INT4, 4);
1565 QR_set_field_info_v(res, 5, "LENGTH", PG_TYPE_INT4, 4);
1566 QR_set_field_info_v(res, 6, "SCALE", PG_TYPE_INT2, 2);
1567 QR_set_field_info_v(res, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2);
1569 if (relisaview)
1571 /* there's no oid for views */
1572 if (fColType == SQL_BEST_ROWID)
1574 goto cleanup;
1576 else if (fColType == SQL_ROWVER)
1578 Int2 the_type = PG_TYPE_TID;
1580 tuple = QR_AddNew(res);
1582 set_tuplefield_null(&tuple[0]);
1583 set_tuplefield_string(&tuple[1], "ctid");
1584 set_tuplefield_int2(&tuple[2],
1585 pgtype_to_concise_type(stmt, the_type,
1586 PG_STATIC));
1587 set_tuplefield_string(&tuple[3],
1588 pgtype_to_name(stmt, the_type,
1589 FALSE));
1590 set_tuplefield_int4(&tuple[4],
1591 pgtype_column_size(stmt, the_type,
1592 PG_STATIC,
1593 PG_STATIC));
1594 set_tuplefield_int4(&tuple[5],
1595 pgtype_buffer_length(stmt, the_type,
1596 PG_STATIC,
1597 PG_STATIC));
1598 set_tuplefield_int2(&tuple[6],
1599 pgtype_decimal_digits(stmt, the_type,
1600 PG_STATIC));
1601 set_tuplefield_int2(&tuple[7], SQL_PC_NOT_PSEUDO);
1602 inolog("Add ctid\n");
1605 else
1607 /* use the oid value for the rowid */
1608 if (fColType == SQL_BEST_ROWID)
1610 Int2 the_type = PG_TYPE_OID;
1612 if (relhasoids[0] != '1')
1614 goto cleanup;
1616 tuple = QR_AddNew(res);
1618 set_tuplefield_int2(&tuple[0], SQL_SCOPE_SESSION);
1619 set_tuplefield_string(&tuple[1], OID_NAME);
1620 set_tuplefield_int2(&tuple[2],
1621 pgtype_to_concise_type(stmt, the_type,
1622 PG_STATIC));
1623 set_tuplefield_string(&tuple[3],
1624 pgtype_to_name(stmt, the_type, TRUE));
1625 set_tuplefield_int4(&tuple[4],
1626 pgtype_column_size(stmt, the_type,
1627 PG_STATIC,
1628 PG_STATIC));
1629 set_tuplefield_int4(&tuple[5],
1630 pgtype_buffer_length(stmt, the_type,
1631 PG_STATIC,
1632 PG_STATIC));
1633 set_tuplefield_int2(&tuple[6],
1634 pgtype_decimal_digits(stmt, the_type,
1635 PG_STATIC));
1636 set_tuplefield_int2(&tuple[7], SQL_PC_PSEUDO);
1638 else if (fColType == SQL_ROWVER)
1640 Int2 the_type = PG_TYPE_XID;
1642 /* if (atoi(ci->row_versioning)) */
1644 tuple = QR_AddNew(res);
1646 set_tuplefield_null(&tuple[0]);
1647 set_tuplefield_string(&tuple[1], "xmin");
1648 set_tuplefield_int2(&tuple[2],
1649 pgtype_to_concise_type(stmt,
1650 the_type,
1651 PG_STATIC));
1652 set_tuplefield_string(&tuple[3],
1653 pgtype_to_name(stmt, the_type,
1654 FALSE));
1655 set_tuplefield_int4(&tuple[4],
1656 pgtype_column_size(stmt, the_type,
1657 PG_STATIC,
1658 PG_STATIC));
1659 set_tuplefield_int4(&tuple[5],
1660 pgtype_buffer_length(stmt, the_type,
1661 PG_STATIC,
1662 PG_STATIC));
1663 set_tuplefield_int2(&tuple[6],
1664 pgtype_decimal_digits(stmt,
1665 the_type,
1666 PG_STATIC));
1667 set_tuplefield_int2(&tuple[7], SQL_PC_PSEUDO);
1672 cleanup:
1673 #undef return
1674 if (escSchemaName)
1675 free(escSchemaName);
1676 if (escTableName)
1677 free(escTableName);
1678 stmt->status = STMT_FINISHED;
1679 stmt->currTuple = -1;
1680 SC_set_rowset_start(stmt, -1, FALSE);
1681 SC_set_current_col(stmt, -1);
1682 if (hcol_stmt)
1683 PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
1684 if (stmt->internal)
1685 result = DiscardStatementSvp(stmt, result, FALSE);
1686 mylog("%s: EXIT, stmt=%p\n", func, stmt);
1687 return result;
1690 RETCODE SQL_API PGAPI_Statistics(HSTMT hstmt, const SQLCHAR FAR * szTableQualifier, /* OA X */
1691 SQLSMALLINT cbTableQualifier, const SQLCHAR FAR * szTableOwner, /* OA E */
1692 SQLSMALLINT cbTableOwner, const SQLCHAR FAR * szTableName, /* OA(R) E */
1693 SQLSMALLINT cbTableName,
1694 SQLUSMALLINT fUnique,
1695 SQLUSMALLINT fAccuracy)
1697 CSTR func = "PGAPI_Statistics";
1698 StatementClass *stmt = (StatementClass *) hstmt;
1699 ConnectionClass *conn;
1700 QResultClass *res;
1701 char index_query[INFO_INQUIRY_LEN];
1702 HSTMT hcol_stmt = NULL, hindx_stmt = NULL;
1703 RETCODE ret = SQL_ERROR, result;
1704 char *escSchemaName = NULL, *table_name = NULL, *escTableName =
1705 NULL;
1706 char index_name[MAX_INFO_STRING];
1707 short fields_vector[INDEX_KEYS_STORAGE_COUNT + 1];
1708 char isunique[10], isclustered[10], ishash[MAX_INFO_STRING];
1709 SQLLEN index_name_len, fields_vector_len;
1710 TupleField *tuple;
1711 int i;
1712 StatementClass *col_stmt, *indx_stmt;
1713 char column_name[MAX_INFO_STRING],
1714 table_schemaname[MAX_INFO_STRING], relhasrules[10];
1715 struct columns_idx {
1716 int pnum;
1717 char *col_name;
1719 *column_names = NULL;
1720 /* char **column_names = NULL; */
1721 SQLLEN column_name_len;
1722 int total_columns = 0, alcount;
1723 ConnInfo *ci;
1724 char buf[256];
1725 SQLSMALLINT internal_asis_type =
1726 SQL_C_CHAR, cbSchemaName, field_number;
1727 const char *szSchemaName;
1728 OID ioid;
1730 mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func, stmt,
1731 NULL_IF_NULL(szTableOwner), cbTableOwner);
1733 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
1734 return result;
1736 table_name = make_string(szTableName, cbTableName, NULL, 0);
1737 if (!table_name)
1739 SC_set_error(stmt, STMT_INVALID_NULL_ARG,
1740 "The table name is required", func);
1741 return result;
1743 conn = SC_get_conn(stmt);
1744 ci = &(conn->connInfo);
1745 #ifdef UNICODE_SUPPORT
1746 if (CC_is_in_unicode_driver(conn))
1747 internal_asis_type = INTERNAL_ASIS_TYPE;
1748 #endif /* UNICODE_SUPPORT */
1750 if (res = QR_Constructor(), !res)
1752 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
1753 "Couldn't allocate memory for PGAPI_Statistics result.",
1754 func);
1755 return SQL_ERROR;
1757 SC_set_Result(stmt, res);
1759 /* the binding structure for a statement is not set up until */
1762 * a statement is actually executed, so we'll have to do this
1763 * ourselves.
1765 extend_column_bindings(SC_get_ARDF(stmt), 13);
1767 stmt->catalog_result = TRUE;
1768 /* set the field names */
1769 QR_set_num_fields(res, NUM_OF_STATS_FIELDS);
1770 QR_set_field_info_v(res, STATS_CATALOG_NAME, "TABLE_QUALIFIER",
1771 PG_TYPE_VARCHAR, MAX_INFO_STRING);
1772 QR_set_field_info_v(res, STATS_SCHEMA_NAME, "TABLE_OWNER",
1773 PG_TYPE_VARCHAR, MAX_INFO_STRING);
1774 QR_set_field_info_v(res, STATS_TABLE_NAME, "TABLE_NAME",
1775 PG_TYPE_VARCHAR, MAX_INFO_STRING);
1776 QR_set_field_info_v(res, STATS_NON_UNIQUE, "NON_UNIQUE",
1777 PG_TYPE_INT2, 2);
1778 QR_set_field_info_v(res, STATS_INDEX_QUALIFIER, "INDEX_QUALIFIER",
1779 PG_TYPE_VARCHAR, MAX_INFO_STRING);
1780 QR_set_field_info_v(res, STATS_INDEX_NAME, "INDEX_NAME",
1781 PG_TYPE_VARCHAR, MAX_INFO_STRING);
1782 QR_set_field_info_v(res, STATS_TYPE, "TYPE", PG_TYPE_INT2, 2);
1783 QR_set_field_info_v(res, STATS_SEQ_IN_INDEX, "SEQ_IN_INDEX",
1784 PG_TYPE_INT2, 2);
1785 QR_set_field_info_v(res, STATS_COLUMN_NAME, "COLUMN_NAME",
1786 PG_TYPE_VARCHAR, MAX_INFO_STRING);
1787 QR_set_field_info_v(res, STATS_COLLATION, "COLLATION", PG_TYPE_CHAR,
1789 QR_set_field_info_v(res, STATS_CARDINALITY, "CARDINALITY",
1790 PG_TYPE_INT4, 4);
1791 QR_set_field_info_v(res, STATS_PAGES, "PAGES", PG_TYPE_INT4, 4);
1792 QR_set_field_info_v(res, STATS_FILTER_CONDITION, "FILTER_CONDITION",
1793 PG_TYPE_VARCHAR, MAX_INFO_STRING);
1795 #define return DONT_CALL_RETURN_FROM_HERE???
1796 szSchemaName = (const char *)szTableOwner;
1797 cbSchemaName = cbTableOwner;
1799 table_schemaname[0] = '\0';
1800 if (conn->schema_support)
1801 schema_strcat(table_schemaname, "%.*s", szSchemaName,
1802 cbSchemaName, (const char *)szTableName,
1803 cbTableName, conn);
1806 * we need to get a list of the field names first, so we can return
1807 * them later.
1809 result = PGAPI_AllocStmt(conn, &hcol_stmt);
1810 if (!SQL_SUCCEEDED(result))
1812 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
1813 "PGAPI_AllocStmt failed in PGAPI_Statistics for columns.",
1814 func);
1815 goto cleanup;
1818 col_stmt = (StatementClass *) hcol_stmt;
1821 * "internal" prevents SQLColumns from returning the oid if it is
1822 * being shown. This would throw everything off.
1824 col_stmt->internal = TRUE;
1826 * table_name parameter cannot contain a string search pattern.
1828 result =
1829 PGAPI_Columns(hcol_stmt, NULL, 0,
1830 (const UCHAR *)table_schemaname, SQL_NTS,
1831 (const UCHAR *)table_name, SQL_NTS, NULL, 0,
1832 PODBC_NOT_SEARCH_PATTERN |
1833 PODBC_SEARCH_PUBLIC_SCHEMA, 0, 0);
1834 col_stmt->internal = FALSE;
1836 if (!SQL_SUCCEEDED(result))
1838 SC_error_copy(stmt, col_stmt, TRUE);
1839 goto cleanup;
1841 result =
1842 PGAPI_BindCol(hcol_stmt, COLUMNS_COLUMN_NAME + 1,
1843 internal_asis_type, column_name,
1844 sizeof(column_name), &column_name_len);
1845 if (!SQL_SUCCEEDED(result))
1847 SC_error_copy(stmt, col_stmt, TRUE);
1848 goto cleanup;
1850 result =
1851 PGAPI_BindCol(hcol_stmt, COLUMNS_PHYSICAL_NUMBER + 1,
1852 SQL_C_SHORT, &field_number, sizeof(field_number),
1853 NULL);
1854 if (!SQL_SUCCEEDED(result))
1856 SC_error_copy(stmt, col_stmt, TRUE);
1857 goto cleanup;
1860 alcount = 0;
1861 result = PGAPI_Fetch(hcol_stmt);
1862 while (SQL_SUCCEEDED(result))
1864 if (0 == total_columns)
1865 PGAPI_GetData(hcol_stmt, 2, internal_asis_type,
1866 table_schemaname, sizeof(table_schemaname),
1867 NULL);
1869 if (total_columns >= alcount)
1871 if (0 == alcount)
1872 alcount = 4;
1873 else
1874 alcount *= 2;
1875 column_names =
1876 (struct columns_idx *) realloc(column_names,
1877 alcount *
1878 sizeof(struct
1879 columns_idx));
1881 column_names[total_columns].col_name =
1882 (char *) malloc(strlen(column_name) + 1);
1883 strcpy(column_names[total_columns].col_name, column_name);
1884 column_names[total_columns].pnum = field_number;
1885 total_columns++;
1887 mylog("%s: column_name = '%s'\n", func, column_name);
1889 result = PGAPI_Fetch(hcol_stmt);
1892 if (result != SQL_NO_DATA_FOUND)
1894 SC_full_error_copy(stmt, col_stmt, FALSE);
1895 goto cleanup;
1897 PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
1898 hcol_stmt = NULL;
1899 if (total_columns == 0)
1901 /* Couldn't get column names in SQLStatistics.; */
1902 ret = SQL_SUCCESS;
1903 goto cleanup;
1906 /* get a list of indexes on this table */
1907 result = PGAPI_AllocStmt(conn, &hindx_stmt);
1908 if (!SQL_SUCCEEDED(result))
1910 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
1911 "PGAPI_AllocStmt failed in SQLStatistics for indices.",
1912 func);
1913 goto cleanup;
1916 indx_stmt = (StatementClass *) hindx_stmt;
1918 /* TableName cannot contain a string search pattern */
1919 escTableName = simpleCatalogEscape(table_name, SQL_NTS, NULL, conn);
1920 if (conn->schema_support)
1922 escSchemaName =
1923 simpleCatalogEscape(table_schemaname, SQL_NTS, NULL, conn);
1924 snprintf(index_query, sizeof(index_query),
1925 "select c.relname, i.indkey, i.indisunique"
1926 ", i.indisclustered, a.amname, c.relhasrules, n.nspname"
1927 ", c.oid"
1928 " from pg_catalog.pg_index i, pg_catalog.pg_class c,"
1929 " pg_catalog.pg_class d, pg_catalog.pg_am a,"
1930 " pg_catalog.pg_namespace n" " where d.relname = '%s'"
1931 " and n.nspname = '%s'" " and n.oid = d.relnamespace"
1932 " and d.oid = i.indrelid" " and i.indexrelid = c.oid"
1933 " and c.relam = a.oid order by", escTableName,
1934 escSchemaName);
1936 else
1937 snprintf(index_query, sizeof(index_query),
1938 "select c.relname, i.indkey, i.indisunique"
1939 ", i.indisclustered, a.amname, c.relhasrules, c.oid"
1940 " from pg_index i, pg_class c, pg_class d, pg_am a"
1941 " where d.relname = '%s'" " and d.oid = i.indrelid"
1942 " and i.indexrelid = c.oid"
1943 " and c.relam = a.oid order by", escTableName);
1944 if (PG_VERSION_GT(SC_get_conn(stmt), 6.4))
1945 strcat(index_query, " i.indisprimary desc,");
1946 if (conn->schema_support)
1947 strcat(index_query, " i.indisunique, n.nspname, c.relname");
1948 else
1949 strcat(index_query, " i.indisunique, c.relname");
1951 result = PGAPI_ExecDirect(hindx_stmt, (const UCHAR *)index_query, SQL_NTS, 0);
1952 if (!SQL_SUCCEEDED(result))
1955 * "Couldn't execute index query (w/SQLExecDirect) in
1956 * SQLStatistics.";
1958 SC_full_error_copy(stmt, indx_stmt, FALSE);
1959 goto cleanup;
1962 /* bind the index name column */
1963 result = PGAPI_BindCol(hindx_stmt, 1, internal_asis_type,
1964 index_name, MAX_INFO_STRING,
1965 &index_name_len);
1966 if (!SQL_SUCCEEDED(result))
1968 SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column
1969 * in SQLStatistics."; */
1970 goto cleanup;
1973 /* bind the vector column */
1974 result = PGAPI_BindCol(hindx_stmt, 2, SQL_C_DEFAULT,
1975 fields_vector, sizeof(fields_vector),
1976 &fields_vector_len);
1977 if (!SQL_SUCCEEDED(result))
1979 SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column
1980 * in SQLStatistics."; */
1981 goto cleanup;
1984 /* bind the "is unique" column */
1985 result = PGAPI_BindCol(hindx_stmt, 3, internal_asis_type,
1986 isunique, sizeof(isunique), NULL);
1987 if (!SQL_SUCCEEDED(result))
1989 SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column
1990 * in SQLStatistics."; */
1991 goto cleanup;
1994 /* bind the "is clustered" column */
1995 result = PGAPI_BindCol(hindx_stmt, 4, internal_asis_type,
1996 isclustered, sizeof(isclustered), NULL);
1997 if (!SQL_SUCCEEDED(result))
1999 SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column *
2000 * in SQLStatistics."; */
2001 goto cleanup;
2005 /* bind the "is hash" column */
2006 result = PGAPI_BindCol(hindx_stmt, 5, internal_asis_type,
2007 ishash, sizeof(ishash), NULL);
2008 if (!SQL_SUCCEEDED(result))
2010 SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column *
2011 * in SQLStatistics."; */
2012 goto cleanup;
2016 result = PGAPI_BindCol(hindx_stmt, 6, internal_asis_type,
2017 relhasrules, sizeof(relhasrules), NULL);
2018 if (!SQL_SUCCEEDED(result))
2020 SC_error_copy(stmt, indx_stmt, TRUE);
2021 goto cleanup;
2024 result = PGAPI_BindCol(hindx_stmt, 8, SQL_C_ULONG,
2025 &ioid, sizeof(ioid), NULL);
2026 if (!SQL_SUCCEEDED(result))
2028 SC_error_copy(stmt, indx_stmt, TRUE);
2029 goto cleanup;
2032 relhasrules[0] = '0';
2033 result = PGAPI_Fetch(hindx_stmt);
2034 /* fake index of OID */
2035 if (relhasrules[0] != '1' && atoi(ci->show_oid_column)
2036 && atoi(ci->fake_oid_index))
2038 tuple = QR_AddNew(res);
2040 /* no table qualifier */
2041 set_tuplefield_string(&tuple[STATS_CATALOG_NAME],
2042 CurrCat(conn));
2043 /* don't set the table owner, else Access tries to use it */
2044 set_tuplefield_string(&tuple[STATS_SCHEMA_NAME],
2045 GET_SCHEMA_NAME(table_schemaname));
2046 set_tuplefield_string(&tuple[STATS_TABLE_NAME], table_name);
2048 /* non-unique index? */
2049 set_tuplefield_int2(&tuple[STATS_NON_UNIQUE], (Int2)FALSE);
2051 /* no index qualifier */
2052 set_tuplefield_string(&tuple[STATS_INDEX_QUALIFIER],
2053 CurrCat(conn));
2055 snprintf(buf, sizeof(table_name), "%s_idx_fake_oid",
2056 table_name);
2057 set_tuplefield_string(&tuple[STATS_INDEX_NAME], buf);
2060 * Clustered/HASH index?
2062 set_tuplefield_int2(&tuple[STATS_TYPE], (Int2) SQL_INDEX_OTHER);
2063 set_tuplefield_int2(&tuple[STATS_SEQ_IN_INDEX], (Int2) 1);
2065 set_tuplefield_string(&tuple[STATS_COLUMN_NAME], OID_NAME);
2066 set_tuplefield_string(&tuple[STATS_COLLATION], "A");
2067 set_tuplefield_null(&tuple[STATS_CARDINALITY]);
2068 set_tuplefield_null(&tuple[STATS_PAGES]);
2069 set_tuplefield_null(&tuple[STATS_FILTER_CONDITION]);
2072 while (SQL_SUCCEEDED(result))
2074 /* If only requesting unique indexs, then just return those. */
2075 if (fUnique == SQL_INDEX_ALL ||
2076 (fUnique == SQL_INDEX_UNIQUE && atoi(isunique)))
2078 int colcnt, attnum;
2080 /* add a row in this table for each field in the index */
2081 colcnt = fields_vector[0];
2082 for (i = 1; i <= colcnt; i++)
2084 tuple = QR_AddNew(res);
2086 /* no table qualifier */
2087 set_tuplefield_string(&tuple[STATS_CATALOG_NAME],
2088 CurrCat(conn));
2089 /* don't set the table owner, else Access tries to use it */
2090 set_tuplefield_string(&tuple[STATS_SCHEMA_NAME],
2091 GET_SCHEMA_NAME
2092 (table_schemaname));
2093 set_tuplefield_string(&tuple[STATS_TABLE_NAME],
2094 table_name);
2096 /* non-unique index? */
2097 set_tuplefield_int2(&tuple[STATS_NON_UNIQUE],
2098 (Int2) (atoi(isunique) ? FALSE :
2099 TRUE));
2101 /* no index qualifier */
2102 set_tuplefield_string(&tuple[STATS_INDEX_QUALIFIER],
2103 CurrCat(conn));
2104 set_tuplefield_string(&tuple[STATS_INDEX_NAME],
2105 index_name);
2108 * Clustered/HASH index?
2110 set_tuplefield_int2(&tuple[STATS_TYPE], (Int2)
2111 (atoi(isclustered) ?
2112 SQL_INDEX_CLUSTERED
2113 : (!strncmp(ishash, "hash", 4)) ?
2114 SQL_INDEX_HASHED :
2115 SQL_INDEX_OTHER));
2116 set_tuplefield_int2(&tuple[STATS_SEQ_IN_INDEX],
2117 (Int2) i);
2119 attnum = fields_vector[i];
2120 if (OID_ATTNUM == attnum)
2122 set_tuplefield_string(&tuple[STATS_COLUMN_NAME],
2123 OID_NAME);
2124 mylog("%s: column name = oid\n", func);
2126 else if (0 == attnum)
2128 char cmd[64];
2130 QResultClass *res;
2132 snprintf(cmd, sizeof(cmd),
2133 "select pg_get_indexdef(%u, %d, true)",
2134 ioid, i);
2135 res =
2136 CC_send_query(conn, cmd, NULL,
2137 IGNORE_ABORT_ON_CONN, stmt);
2138 if (QR_command_maybe_successful(res))
2139 set_tuplefield_string(&tuple[STATS_COLUMN_NAME],
2140 QR_get_value_backend_text
2141 (res, 0, 0));
2142 QR_Destructor(res);
2144 else
2146 int j, matchidx;
2147 BOOL unknownf = TRUE;
2149 if (attnum > 0)
2151 for (j = 0; j < total_columns; j++)
2153 if (attnum == column_names[j].pnum)
2155 matchidx = j;
2156 unknownf = FALSE;
2157 break;
2161 if (unknownf)
2163 set_tuplefield_string(&tuple[STATS_COLUMN_NAME],
2164 "UNKNOWN");
2165 mylog("%s: column name = UNKNOWN\n", func);
2167 else
2169 set_tuplefield_string(&tuple[STATS_COLUMN_NAME],
2170 column_names[matchidx].
2171 col_name);
2172 mylog("%s: column name = '%s'\n", func,
2173 column_names[matchidx].col_name);
2177 set_tuplefield_string(&tuple[STATS_COLLATION], "A");
2178 set_tuplefield_null(&tuple[STATS_CARDINALITY]);
2179 set_tuplefield_null(&tuple[STATS_PAGES]);
2180 set_tuplefield_null(&tuple[STATS_FILTER_CONDITION]);
2184 result = PGAPI_Fetch(hindx_stmt);
2186 if (result != SQL_NO_DATA_FOUND)
2188 /* "SQLFetch failed in SQLStatistics."; */
2189 SC_full_error_copy(stmt, indx_stmt, FALSE);
2190 goto cleanup;
2192 ret = SQL_SUCCESS;
2194 cleanup:
2195 #undef return
2197 * also, things need to think that this statement is finished so the
2198 * results can be retrieved.
2200 stmt->status = STMT_FINISHED;
2202 if (hcol_stmt)
2203 PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
2204 if (hindx_stmt)
2205 PGAPI_FreeStmt(hindx_stmt, SQL_DROP);
2206 /* These things should be freed on any error ALSO! */
2207 if (table_name)
2208 free(table_name);
2209 if (escTableName)
2210 free(escTableName);
2211 if (escSchemaName)
2212 free(escSchemaName);
2213 if (column_names)
2215 for (i = 0; i < total_columns; i++)
2216 free(column_names[i].col_name);
2217 free(column_names);
2220 /* set up the current tuple pointer for SQLFetch */
2221 stmt->currTuple = -1;
2222 SC_set_rowset_start(stmt, -1, FALSE);
2223 SC_set_current_col(stmt, -1);
2225 if (stmt->internal)
2226 ret = DiscardStatementSvp(stmt, ret, FALSE);
2227 mylog("%s: EXIT, stmt=%p, ret=%d\n", func, stmt, ret);
2229 return ret;
2232 RETCODE SQL_API PGAPI_ColumnPrivileges(HSTMT hstmt, const SQLCHAR FAR * szTableQualifier, /* OA X */
2233 SQLSMALLINT cbTableQualifier, const SQLCHAR FAR * szTableOwner, /* OA E */
2234 SQLSMALLINT cbTableOwner, const SQLCHAR FAR * szTableName, /* OA(R) E */
2235 SQLSMALLINT cbTableName, const SQLCHAR FAR * szColumnName, /* PV E */
2236 SQLSMALLINT cbColumnName,
2237 UWORD flag)
2239 CSTR func = "PGAPI_ColumnPrivileges";
2240 StatementClass *stmt = (StatementClass *) hstmt;
2241 ConnectionClass *conn = SC_get_conn(stmt);
2242 RETCODE result = SQL_ERROR;
2243 char *escSchemaName = NULL, *escTableName = NULL, *escColumnName =
2244 NULL;
2245 const char *like_or_eq;
2246 char column_query[INFO_INQUIRY_LEN];
2247 size_t cq_len, cq_size;
2248 char *col_query;
2249 BOOL search_pattern;
2250 QResultClass *res;
2252 mylog("%s: entering...\n", func);
2254 /* Neither Access or Borland care about this. */
2256 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
2257 return result;
2258 if (PG_VERSION_LT(conn, 7.4))
2259 SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR,
2260 "Function not implementedyet", func);
2261 escSchemaName =
2262 simpleCatalogEscape(szTableOwner, cbTableOwner, NULL, conn);
2263 escTableName =
2264 simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
2265 search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
2266 if (search_pattern)
2268 like_or_eq = likeop;
2269 escColumnName =
2270 adjustLikePattern(szColumnName, cbColumnName,
2271 SEARCH_PATTERN_ESCAPE, NULL, conn);
2273 else
2275 like_or_eq = eqop;
2276 escColumnName =
2277 simpleCatalogEscape(szColumnName, cbColumnName, NULL, conn);
2279 strcpy(column_query,
2280 "select '' as TABLE_CAT, table_schema as TABLE_SCHEM,"
2281 " table_name, column_name, grantor, grantee,"
2282 " privilege_type as PRIVILEGE, is_grantable from"
2283 " information_schema.column_privileges where true");
2284 cq_len = strlen(column_query);
2285 cq_size = sizeof(column_query);
2286 col_query = column_query;
2287 if (escSchemaName)
2289 col_query += cq_len;
2290 cq_size -= cq_len;
2291 cq_len = snprintf_len(col_query, cq_size,
2292 " and table_schem = '%s'", escSchemaName);
2295 if (escTableName)
2297 col_query += cq_len;
2298 cq_size -= cq_len;
2299 cq_len += snprintf_len(col_query, cq_size,
2300 " and table_name = '%s'", escTableName);
2302 if (escColumnName)
2304 col_query += cq_len;
2305 cq_size -= cq_len;
2306 cq_len += snprintf_len(col_query, cq_size,
2307 " and column_name %s '%s'", like_or_eq,
2308 escColumnName);
2310 if (res =
2311 CC_send_query(conn, column_query, NULL, IGNORE_ABORT_ON_CONN,
2312 stmt), !QR_command_maybe_successful(res))
2314 SC_set_error(stmt, STMT_EXEC_ERROR,
2315 "PGAPI_ColumnPrivileges query error", func);
2316 QR_Destructor(res);
2317 return SQL_ERROR;
2319 SC_set_Result(stmt, res);
2322 * also, things need to think that this statement is finished so the
2323 * results can be retrieved.
2325 extend_column_bindings(SC_get_ARDF(stmt), 8);
2326 /* set up the current tuple pointer for SQLFetch */
2327 result = SQL_SUCCESS;
2329 /* set up the current tuple pointer for SQLFetch */
2330 stmt->status = STMT_FINISHED;
2331 stmt->currTuple = -1;
2332 SC_set_rowset_start(stmt, -1, FALSE);
2333 if (escSchemaName)
2334 free(escSchemaName);
2335 if (escTableName)
2336 free(escTableName);
2337 if (escColumnName)
2338 free(escColumnName);
2339 return result;
2343 * SQLPrimaryKeys()
2345 * Retrieve the primary key columns for the specified table.
2347 RETCODE SQL_API PGAPI_PrimaryKeys(HSTMT hstmt, const SQLCHAR FAR * szTableQualifier, /* OA X */
2348 SQLSMALLINT cbTableQualifier, const SQLCHAR FAR * szTableOwner, /* OA E */
2349 SQLSMALLINT cbTableOwner, const SQLCHAR FAR * szTableName, /* OA(R) E */
2350 SQLSMALLINT cbTableName)
2352 CSTR func = "PGAPI_PrimaryKeys";
2353 StatementClass *stmt = (StatementClass *) hstmt;
2354 QResultClass *res;
2355 ConnectionClass *conn;
2356 TupleField *tuple;
2357 RETCODE ret = SQL_SUCCESS, result;
2358 int seq = 0;
2359 HSTMT htbl_stmt = NULL;
2360 StatementClass *tbl_stmt;
2361 char tables_query[INFO_INQUIRY_LEN];
2362 char attname[MAX_INFO_STRING];
2363 SQLLEN attname_len;
2364 char *pktab = NULL, pkscm[TABLE_NAME_STORAGE_LEN + 1];
2365 char pkname[TABLE_NAME_STORAGE_LEN + 1];
2366 Int2 result_cols;
2367 int qno, qstart, qend;
2368 SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName;
2369 const char *szSchemaName;
2370 char *escSchemaName = NULL, *escTableName = NULL;
2372 mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func, stmt,
2373 NULL_IF_NULL(szTableOwner), cbTableOwner);
2375 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
2376 return result;
2378 if (res = QR_Constructor(), !res)
2380 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
2381 "Couldn't allocate memory for PGAPI_PrimaryKeys result.",
2382 func);
2383 return SQL_ERROR;
2385 SC_set_Result(stmt, res);
2387 /* the binding structure for a statement is not set up until
2389 * a statement is actually executed, so we'll have to do this
2390 * ourselves.
2392 result_cols = NUM_OF_PKS_FIELDS;
2393 extend_column_bindings(SC_get_ARDF(stmt), result_cols);
2395 stmt->catalog_result = TRUE;
2396 /* set the field names */
2397 QR_set_num_fields(res, result_cols);
2398 QR_set_field_info_v(res, PKS_TABLE_CAT, "TABLE_QUALIFIER",
2399 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2400 QR_set_field_info_v(res, PKS_TABLE_SCHEM, "TABLE_OWNER",
2401 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2402 QR_set_field_info_v(res, PKS_TABLE_NAME, "TABLE_NAME",
2403 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2404 QR_set_field_info_v(res, PKS_COLUMN_NAME, "COLUMN_NAME",
2405 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2406 QR_set_field_info_v(res, PKS_KEY_SQ, "KEY_SEQ", PG_TYPE_INT2, 2);
2407 QR_set_field_info_v(res, PKS_PK_NAME, "PK_NAME", PG_TYPE_VARCHAR,
2408 MAX_INFO_STRING);
2410 conn = SC_get_conn(stmt);
2411 result = PGAPI_AllocStmt(conn, &htbl_stmt);
2412 if (!SQL_SUCCEEDED(result))
2414 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
2415 "Couldn't allocate statement for Primary Key result.",
2416 func);
2417 ret = SQL_ERROR;
2418 goto cleanup;
2420 tbl_stmt = (StatementClass *) htbl_stmt;
2422 #ifdef UNICODE_SUPPORT
2423 if (CC_is_in_unicode_driver(conn))
2424 internal_asis_type = INTERNAL_ASIS_TYPE;
2425 #endif /* UNICODE_SUPPORT */
2427 pktab = make_string(szTableName, cbTableName, NULL, 0);
2428 if (!pktab || pktab[0] == '\0')
2430 SC_set_error(stmt, STMT_INTERNAL_ERROR,
2431 "No Table specified to PGAPI_PrimaryKeys.", func);
2432 ret = SQL_ERROR;
2433 goto cleanup;
2435 szSchemaName = (const char *)szTableOwner;
2436 cbSchemaName = cbTableOwner;
2438 #define return DONT_CALL_RETURN_FROM_HERE???
2439 escTableName =
2440 simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
2442 retry_public_schema:
2443 if (escSchemaName)
2444 free(escSchemaName);
2445 escSchemaName =
2446 simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn);
2447 pkscm[0] = '\0';
2448 if (conn->schema_support)
2449 schema_strcat(pkscm, "%.*s", escSchemaName, SQL_NTS,
2450 (const char *)szTableName, cbTableName, conn);
2452 result = PGAPI_BindCol(htbl_stmt, 1, internal_asis_type,
2453 attname, MAX_INFO_STRING, &attname_len);
2454 if (!SQL_SUCCEEDED(result))
2456 SC_error_copy(stmt, tbl_stmt, TRUE);
2457 ret = SQL_ERROR;
2458 goto cleanup;
2460 result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
2461 pkname, TABLE_NAME_STORAGE_LEN, NULL);
2462 if (!SQL_SUCCEEDED(result))
2464 SC_error_copy(stmt, tbl_stmt, TRUE);
2465 ret = SQL_ERROR;
2466 goto cleanup;
2469 if (PG_VERSION_LE(conn, 6.4))
2470 qstart = 2;
2471 else
2472 qstart = 1;
2473 qend = 2;
2474 for (qno = qstart; qno <= qend; qno++)
2476 switch (qno)
2478 case 1:
2481 * Simplified query to remove assumptions about number of
2482 * possible index columns. Courtesy of Tom Lane - thomas
2483 * 2000-03-21
2485 if (conn->schema_support)
2486 snprintf(tables_query, sizeof(tables_query),
2487 "select ta.attname, ia.attnum, ic.relname"
2488 " from pg_catalog.pg_attribute ta,"
2489 " pg_catalog.pg_attribute ia, pg_catalog.pg_class tc,"
2490 " pg_catalog.pg_index i, pg_catalog.pg_namespace n"
2491 ", pg_catalog.pg_class ic"
2492 " where tc.relname = '%s'"
2493 " AND n.nspname = '%s'"
2494 " AND tc.oid = i.indrelid"
2495 " AND n.oid = tc.relnamespace"
2496 " AND i.indisprimary = 't'"
2497 " AND ia.attrelid = i.indexrelid"
2498 " AND ta.attrelid = i.indrelid"
2499 " AND ta.attnum = i.indkey[ia.attnum-1]"
2500 " AND (NOT ta.attisdropped)"
2501 " AND (NOT ia.attisdropped)"
2502 " AND ic.oid = i.indexrelid"
2503 " order by ia.attnum", escTableName, pkscm);
2504 else
2505 snprintf(tables_query, sizeof(tables_query),
2506 "select ta.attname, ia.attnum, ic.relname"
2507 " from pg_attribute ta, pg_attribute ia, pg_class tc, pg_index i, pg_class ic"
2508 " where tc.relname = '%s'"
2509 " AND tc.oid = i.indrelid"
2510 " AND i.indisprimary = 't'"
2511 " AND ia.attrelid = i.indexrelid"
2512 " AND ta.attrelid = i.indrelid"
2513 " AND ta.attnum = i.indkey[ia.attnum-1]"
2514 " AND ic.oid = i.indexrelid"
2515 " order by ia.attnum", escTableName);
2516 break;
2517 case 2:
2520 * Simplified query to search old fashoned primary key
2522 if (conn->schema_support)
2523 snprintf(tables_query, sizeof(tables_query),
2524 "select ta.attname, ia.attnum, ic.relname"
2525 " from pg_catalog.pg_attribute ta,"
2526 " pg_catalog.pg_attribute ia, pg_catalog.pg_class ic,"
2527 " pg_catalog.pg_index i, pg_catalog.pg_namespace n"
2528 " where ic.relname = '%s_pkey'"
2529 " AND n.nspname = '%s'"
2530 " AND ic.oid = i.indexrelid"
2531 " AND n.oid = ic.relnamespace"
2532 " AND ia.attrelid = i.indexrelid"
2533 " AND ta.attrelid = i.indrelid"
2534 " AND ta.attnum = i.indkey[ia.attnum-1]"
2535 " AND (NOT ta.attisdropped)"
2536 " AND (NOT ia.attisdropped)"
2537 " order by ia.attnum", escTableName, pkscm);
2538 else
2539 snprintf(tables_query, sizeof(tables_query),
2540 "select ta.attname, ia.attnum, ic.relname"
2541 " from pg_attribute ta, pg_attribute ia, pg_class ic, pg_index i"
2542 " where ic.relname = '%s_pkey'"
2543 " AND ic.oid = i.indexrelid"
2544 " AND ia.attrelid = i.indexrelid"
2545 " AND ta.attrelid = i.indrelid"
2546 " AND ta.attnum = i.indkey[ia.attnum-1]"
2547 " order by ia.attnum", escTableName);
2548 break;
2550 mylog("%s: tables_query='%s'\n", func, tables_query);
2552 result = PGAPI_ExecDirect(htbl_stmt, (const UCHAR *)tables_query, SQL_NTS, 0);
2553 if (!SQL_SUCCEEDED(result))
2555 SC_full_error_copy(stmt, tbl_stmt, FALSE);
2556 ret = SQL_ERROR;
2557 goto cleanup;
2560 result = PGAPI_Fetch(htbl_stmt);
2561 if (result != SQL_NO_DATA_FOUND)
2562 break;
2565 /* If not found */
2566 if (conn->schema_support && SQL_NO_DATA_FOUND == result)
2568 const char *user = CC_get_username(conn);
2571 * If specified schema name == user_name and
2572 * the current schema is 'public',
2573 * retry the 'public' schema.
2575 if (szSchemaName &&
2576 (cbSchemaName == SQL_NTS ||
2577 cbSchemaName == (SQLSMALLINT) strlen(user)) &&
2578 strnicmp(szSchemaName, user, strlen(user)) == 0 &&
2579 stricmp(CC_get_current_schema(conn), pubstr) == 0)
2581 szSchemaName = pubstr;
2582 cbSchemaName = SQL_NTS;
2583 goto retry_public_schema;
2587 while (SQL_SUCCEEDED(result))
2589 tuple = QR_AddNew(res);
2591 set_tuplefield_string(&tuple[PKS_TABLE_CAT], CurrCat(conn));
2594 * I have to hide the table owner from Access, otherwise it
2595 * insists on referring to the table as 'owner.table'. (this is
2596 * valid according to the ODBC SQL grammar, but Postgres won't
2597 * support it.)
2599 set_tuplefield_string(&tuple[PKS_TABLE_SCHEM],
2600 GET_SCHEMA_NAME(pkscm));
2601 set_tuplefield_string(&tuple[PKS_TABLE_NAME], pktab);
2602 set_tuplefield_string(&tuple[PKS_COLUMN_NAME], attname);
2603 set_tuplefield_int2(&tuple[PKS_KEY_SQ], (Int2) (++seq));
2604 set_tuplefield_string(&tuple[PKS_PK_NAME], pkname);
2606 mylog
2607 (">> primaryKeys: pktab = '%s', attname = '%s', seq = %d\n",
2608 pktab, attname, seq);
2610 result = PGAPI_Fetch(htbl_stmt);
2613 if (result != SQL_NO_DATA_FOUND)
2615 SC_full_error_copy(stmt, tbl_stmt, FALSE);
2616 ret = SQL_ERROR;
2617 goto cleanup;
2619 ret = SQL_SUCCESS;
2621 cleanup:
2622 #undef return
2624 * also, things need to think that this statement is finished so the
2625 * results can be retrieved.
2627 stmt->status = STMT_FINISHED;
2629 if (htbl_stmt)
2630 PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
2632 if (pktab)
2633 free(pktab);
2634 if (escSchemaName)
2635 free(escSchemaName);
2636 if (escTableName)
2637 free(escTableName);
2638 /* set up the current tuple pointer for SQLFetch */
2639 stmt->currTuple = -1;
2640 SC_set_rowset_start(stmt, -1, FALSE);
2641 SC_set_current_col(stmt, -1);
2643 if (stmt->internal)
2644 ret = DiscardStatementSvp(stmt, ret, FALSE);
2645 mylog("%s: EXIT, stmt=%p, ret=%d\n", func, stmt, ret);
2646 return ret;
2650 * Multibyte support stuff for SQLForeignKeys().
2651 * There may be much more effective way in the
2652 * future version. The way is very forcible currently.
2654 static BOOL isMultibyte(const UCHAR * str)
2656 for (; *str; str++)
2658 if (*str >= 0x80)
2659 return TRUE;
2661 return FALSE;
2663 static char *getClientColumnName(ConnectionClass * conn, UInt4 relid,
2664 char *serverColumnName,
2665 BOOL * nameAlloced)
2667 char query[1024], saveattnum[16], *ret = serverColumnName;
2668 BOOL continueExec = TRUE, bError = FALSE;
2669 QResultClass *res = NULL;
2670 UWORD flag = IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR;
2672 *nameAlloced = FALSE;
2673 if (!conn->original_client_encoding
2674 || !isMultibyte((const UCHAR *)serverColumnName))
2675 return ret;
2676 if (!conn->server_encoding)
2678 if (res =
2679 CC_send_query(conn, "select getdatabaseencoding()", NULL,
2680 flag, NULL), QR_command_maybe_successful(res))
2682 if (QR_get_num_cached_tuples(res) > 0)
2683 conn->server_encoding =
2684 strdup(QR_get_value_backend_text(res, 0, 0));
2686 QR_Destructor(res);
2687 res = NULL;
2689 if (!conn->server_encoding)
2690 return ret;
2691 snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'",
2692 conn->server_encoding);
2693 bError =
2694 (!QR_command_maybe_successful
2695 ((res = CC_send_query(conn, query, NULL, flag, NULL))));
2696 QR_Destructor(res);
2697 if (!bError && continueExec)
2699 snprintf(query, sizeof(query),
2700 "select attnum from pg_attribute "
2701 "where attrelid = %u and attname = '%s'", relid,
2702 serverColumnName);
2703 if (res =
2704 CC_send_query(conn, query, NULL, flag, NULL),
2705 QR_command_maybe_successful(res))
2707 if (QR_get_num_cached_tuples(res) > 0)
2709 strcpy(saveattnum,
2710 QR_get_value_backend_text(res, 0, 0));
2712 else
2713 continueExec = FALSE;
2715 else
2716 bError = TRUE;
2717 QR_Destructor(res);
2719 continueExec = (continueExec && !bError);
2720 /* restore the cleint encoding */
2721 snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'",
2722 conn->original_client_encoding);
2723 bError =
2724 (!QR_command_maybe_successful
2725 ((res = CC_send_query(conn, query, NULL, flag, NULL))));
2726 QR_Destructor(res);
2727 if (bError || !continueExec)
2728 return ret;
2729 snprintf(query, sizeof(query),
2730 "select attname from pg_attribute where attrelid = %u and attnum = %s",
2731 relid, saveattnum);
2732 if (res =
2733 CC_send_query(conn, query, NULL, flag, NULL),
2734 QR_command_maybe_successful(res))
2736 if (QR_get_num_cached_tuples(res) > 0)
2738 ret = strdup(QR_get_value_backend_text(res, 0, 0));
2739 *nameAlloced = TRUE;
2742 QR_Destructor(res);
2743 return ret;
2746 RETCODE SQL_API PGAPI_ForeignKeys(HSTMT hstmt, const SQLCHAR FAR * szPkTableQualifier, /* OA X */
2747 SQLSMALLINT cbPkTableQualifier, const SQLCHAR FAR * szPkTableOwner, /* OA E */
2748 SQLSMALLINT cbPkTableOwner, const SQLCHAR FAR * szPkTableName, /* OA(R) E */
2749 SQLSMALLINT cbPkTableName, const SQLCHAR FAR * szFkTableQualifier, /* OA X */
2750 SQLSMALLINT cbFkTableQualifier, const SQLCHAR FAR * szFkTableOwner, /* OA E */
2751 SQLSMALLINT cbFkTableOwner, const SQLCHAR FAR * szFkTableName, /* OA(R) E */
2752 SQLSMALLINT cbFkTableName)
2754 CSTR func = "PGAPI_ForeignKeys";
2755 StatementClass *stmt = (StatementClass *) hstmt;
2756 QResultClass *res;
2757 TupleField *tuple;
2758 HSTMT htbl_stmt = NULL, hpkey_stmt = NULL;
2759 StatementClass *tbl_stmt;
2760 RETCODE ret = SQL_ERROR, result, keyresult;
2761 char tables_query[INFO_INQUIRY_LEN];
2762 char trig_deferrable[2];
2763 char trig_initdeferred[2];
2764 char trig_args[1024];
2765 char upd_rule[TABLE_NAME_STORAGE_LEN],
2766 del_rule[TABLE_NAME_STORAGE_LEN];
2767 char *pk_table_needed = NULL, *escPkTableName = NULL;
2768 char fk_table_fetched[TABLE_NAME_STORAGE_LEN + 1];
2769 char *fk_table_needed = NULL, *escFkTableName = NULL;
2770 char pk_table_fetched[TABLE_NAME_STORAGE_LEN + 1];
2771 char schema_needed[SCHEMA_NAME_STORAGE_LEN + 1];
2772 char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1];
2773 char constrname[NAMESTORAGELEN + 1],
2774 pkname[TABLE_NAME_STORAGE_LEN + 1];
2775 char *pkey_ptr, *pkey_text = NULL, *fkey_ptr, *fkey_text = NULL;
2777 ConnectionClass *conn;
2778 BOOL pkey_alloced, fkey_alloced, got_pkname;
2779 int i, j, k, num_keys;
2780 SQLSMALLINT trig_nargs, upd_rule_type = 0, del_rule_type = 0;
2781 SQLSMALLINT internal_asis_type = SQL_C_CHAR;
2783 SQLSMALLINT defer_type;
2784 char pkey[MAX_INFO_STRING];
2785 Int2 result_cols;
2786 UInt4 relid1, relid2;
2788 mylog("%s: entering...stmt=%p\n", func, stmt);
2790 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
2791 return result;
2793 if (res = QR_Constructor(), !res)
2795 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
2796 "Couldn't allocate memory for PGAPI_ForeignKeys result.",
2797 func);
2798 return SQL_ERROR;
2800 SC_set_Result(stmt, res);
2802 /* the binding structure for a statement is not set up until */
2805 * a statement is actually executed, so we'll have to do this
2806 * ourselves.
2808 result_cols = NUM_OF_FKS_FIELDS;
2809 extend_column_bindings(SC_get_ARDF(stmt), result_cols);
2811 stmt->catalog_result = TRUE;
2812 /* set the field names */
2813 QR_set_num_fields(res, result_cols);
2814 QR_set_field_info_v(res, FKS_PKTABLE_CAT, "PKTABLE_QUALIFIER",
2815 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2816 QR_set_field_info_v(res, FKS_PKTABLE_SCHEM, "PKTABLE_OWNER",
2817 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2818 QR_set_field_info_v(res, FKS_PKTABLE_NAME, "PKTABLE_NAME",
2819 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2820 QR_set_field_info_v(res, FKS_PKCOLUMN_NAME, "PKCOLUMN_NAME",
2821 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2822 QR_set_field_info_v(res, FKS_FKTABLE_CAT, "FKTABLE_QUALIFIER",
2823 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2824 QR_set_field_info_v(res, FKS_FKTABLE_SCHEM, "FKTABLE_OWNER",
2825 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2826 QR_set_field_info_v(res, FKS_FKTABLE_NAME, "FKTABLE_NAME",
2827 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2828 QR_set_field_info_v(res, FKS_FKCOLUMN_NAME, "FKCOLUMN_NAME",
2829 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2830 QR_set_field_info_v(res, FKS_KEY_SEQ, "KEY_SEQ", PG_TYPE_INT2, 2);
2831 QR_set_field_info_v(res, FKS_UPDATE_RULE, "UPDATE_RULE",
2832 PG_TYPE_INT2, 2);
2833 QR_set_field_info_v(res, FKS_DELETE_RULE, "DELETE_RULE",
2834 PG_TYPE_INT2, 2);
2835 QR_set_field_info_v(res, FKS_FK_NAME, "FK_NAME", PG_TYPE_VARCHAR,
2836 MAX_INFO_STRING);
2837 QR_set_field_info_v(res, FKS_PK_NAME, "PK_NAME", PG_TYPE_VARCHAR,
2838 MAX_INFO_STRING);
2839 QR_set_field_info_v(res, FKS_DEFERRABILITY, "DEFERRABILITY",
2840 PG_TYPE_INT2, 2);
2841 QR_set_field_info_v(res, FKS_TRIGGER_NAME, "TRIGGER_NAME",
2842 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2845 * also, things need to think that this statement is finished so the
2846 * results can be retrieved.
2848 stmt->status = STMT_FINISHED;
2850 /* set up the current tuple pointer for SQLFetch */
2851 stmt->currTuple = -1;
2852 SC_set_rowset_start(stmt, -1, FALSE);
2853 SC_set_current_col(stmt, -1);
2855 conn = SC_get_conn(stmt);
2856 result = PGAPI_AllocStmt(conn, &htbl_stmt);
2857 if (!SQL_SUCCEEDED(result))
2859 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
2860 "Couldn't allocate statement for PGAPI_ForeignKeys result.",
2861 func);
2862 return SQL_ERROR;
2864 #define return DONT_CALL_RETURN_FROM_HERE???
2866 tbl_stmt = (StatementClass *) htbl_stmt;
2867 schema_needed[0] = '\0';
2868 schema_fetched[0] = '\0';
2870 pk_table_needed =
2871 make_string(szPkTableName, cbPkTableName, NULL, 0);
2872 fk_table_needed =
2873 make_string(szFkTableName, cbFkTableName, NULL, 0);
2875 #ifdef UNICODE_SUPPORT
2876 if (CC_is_in_unicode_driver(conn))
2877 internal_asis_type = INTERNAL_ASIS_TYPE;
2878 #endif /* UNICODE_SUPPORT */
2879 pkey_alloced = fkey_alloced = FALSE;
2882 * Case #2 -- Get the foreign keys in the specified table (fktab) that
2883 * refer to the primary keys of other table(s).
2885 if (fk_table_needed && fk_table_needed[0] != '\0')
2887 mylog("%s: entering Foreign Key Case #2", func);
2888 escFkTableName =
2889 simpleCatalogEscape(fk_table_needed, SQL_NTS, NULL, conn);
2890 if (conn->schema_support)
2892 char *escSchemaName;
2894 schema_strcat(schema_needed, "%.*s", (const char *)szFkTableOwner,
2895 cbFkTableOwner, (const char *)szFkTableName,
2896 cbFkTableName, conn);
2897 escSchemaName =
2898 simpleCatalogEscape(schema_needed, SQL_NTS, NULL, conn);
2899 snprintf(tables_query, sizeof(tables_query),
2900 "SELECT pt.tgargs, "
2901 " pt.tgnargs, "
2902 " pt.tgdeferrable, "
2903 " pt.tginitdeferred, "
2904 " pp1.proname, "
2905 " pp2.proname, "
2906 " pc.oid, "
2907 " pc1.oid, "
2908 " pc1.relname, "
2909 " pt.tgconstrname, pn.nspname "
2910 "FROM pg_catalog.pg_class pc, "
2911 " pg_catalog.pg_proc pp1, "
2912 " pg_catalog.pg_proc pp2, "
2913 " pg_catalog.pg_trigger pt1, "
2914 " pg_catalog.pg_trigger pt2, "
2915 " pg_catalog.pg_proc pp, "
2916 " pg_catalog.pg_trigger pt, "
2917 " pg_catalog.pg_class pc1, "
2918 " pg_catalog.pg_namespace pn, "
2919 " pg_catalog.pg_namespace pn1 "
2920 "WHERE pt.tgrelid = pc.oid "
2921 "AND pp.oid = pt.tgfoid "
2922 "AND pt1.tgconstrrelid = pc.oid "
2923 "AND pp1.oid = pt1.tgfoid "
2924 "AND pt2.tgfoid = pp2.oid "
2925 "AND pt2.tgconstrrelid = pc.oid "
2926 "AND ((pc.relname='%s') "
2927 "AND (pn1.oid = pc.relnamespace) "
2928 "AND (pn1.nspname = '%s') "
2929 "AND (pp.proname LIKE '%%ins') "
2930 "AND (pp1.proname LIKE '%%upd') "
2931 "AND (pp1.proname not LIKE '%%check%%') "
2932 "AND (pp2.proname LIKE '%%del') "
2933 "AND (pt1.tgrelid=pt.tgconstrrelid) "
2934 "AND (pt1.tgconstrname=pt.tgconstrname) "
2935 "AND (pt2.tgrelid=pt.tgconstrrelid) "
2936 "AND (pt2.tgconstrname=pt.tgconstrname) "
2937 "AND (pt.tgconstrrelid=pc1.oid) "
2938 "AND (pc1.relnamespace=pn.oid))"
2939 " order by pt.tgconstrname",
2940 escFkTableName, escSchemaName);
2941 free(escSchemaName);
2943 else
2944 snprintf(tables_query, sizeof(tables_query),
2945 "SELECT pt.tgargs, "
2946 " pt.tgnargs, "
2947 " pt.tgdeferrable, "
2948 " pt.tginitdeferred, "
2949 " pp1.proname, "
2950 " pp2.proname, "
2951 " pc.oid, "
2952 " pc1.oid, "
2953 " pc1.relname, pt.tgconstrname "
2954 "FROM pg_class pc, "
2955 " pg_proc pp1, "
2956 " pg_proc pp2, "
2957 " pg_trigger pt1, "
2958 " pg_trigger pt2, "
2959 " pg_proc pp, "
2960 " pg_trigger pt, "
2961 " pg_class pc1 "
2962 "WHERE pt.tgrelid = pc.oid "
2963 "AND pp.oid = pt.tgfoid "
2964 "AND pt1.tgconstrrelid = pc.oid "
2965 "AND pp1.oid = pt1.tgfoid "
2966 "AND pt2.tgfoid = pp2.oid "
2967 "AND pt2.tgconstrrelid = pc.oid "
2968 "AND ((pc.relname='%s') "
2969 "AND (pp.proname LIKE '%%ins') "
2970 "AND (pp1.proname LIKE '%%upd') "
2971 "AND (pp1.proname not LIKE '%%check%%') "
2972 "AND (pp2.proname LIKE '%%del') "
2973 "AND (pt1.tgrelid=pt.tgconstrrelid) "
2974 "AND (pt1.tgconstrname=pt.tgconstrname) "
2975 "AND (pt2.tgrelid=pt.tgconstrrelid) "
2976 "AND (pt2.tgconstrname=pt.tgconstrname) "
2977 "AND (pt.tgconstrrelid=pc1.oid)) "
2978 "order by pt.tgconstrname", escFkTableName);
2980 result = PGAPI_ExecDirect(htbl_stmt,
2981 (const UCHAR *)tables_query, SQL_NTS, 0);
2983 if (!SQL_SUCCEEDED(result))
2985 SC_full_error_copy(stmt, tbl_stmt, FALSE);
2986 goto cleanup;
2989 result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_BINARY,
2990 trig_args, sizeof(trig_args), NULL);
2991 if (!SQL_SUCCEEDED(result))
2993 SC_error_copy(stmt, tbl_stmt, TRUE);
2994 goto cleanup;
2997 result = PGAPI_BindCol(htbl_stmt, 2, SQL_C_SHORT,
2998 &trig_nargs, 0, NULL);
2999 if (!SQL_SUCCEEDED(result))
3001 SC_error_copy(stmt, tbl_stmt, TRUE);
3002 goto cleanup;
3005 result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
3006 trig_deferrable, sizeof(trig_deferrable),
3007 NULL);
3008 if (!SQL_SUCCEEDED(result))
3010 SC_error_copy(stmt, tbl_stmt, TRUE);
3011 goto cleanup;
3014 result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type,
3015 trig_initdeferred,
3016 sizeof(trig_initdeferred), NULL);
3017 if (!SQL_SUCCEEDED(result))
3019 SC_error_copy(stmt, tbl_stmt, TRUE);
3020 goto cleanup;
3023 result = PGAPI_BindCol(htbl_stmt, 5, internal_asis_type,
3024 upd_rule, sizeof(upd_rule), NULL);
3025 if (!SQL_SUCCEEDED(result))
3027 SC_error_copy(stmt, tbl_stmt, TRUE);
3028 goto cleanup;
3031 result = PGAPI_BindCol(htbl_stmt, 6, internal_asis_type,
3032 del_rule, sizeof(del_rule), NULL);
3033 if (!SQL_SUCCEEDED(result))
3035 SC_error_copy(stmt, tbl_stmt, TRUE);
3036 goto cleanup;
3039 result = PGAPI_BindCol(htbl_stmt, 7, SQL_C_ULONG,
3040 &relid1, sizeof(relid1), NULL);
3041 if (!SQL_SUCCEEDED(result))
3043 SC_error_copy(stmt, tbl_stmt, TRUE);
3044 goto cleanup;
3046 result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG,
3047 &relid2, sizeof(relid2), NULL);
3048 if (!SQL_SUCCEEDED(result))
3050 SC_error_copy(stmt, tbl_stmt, TRUE);
3051 goto cleanup;
3053 result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type,
3054 pk_table_fetched, TABLE_NAME_STORAGE_LEN,
3055 NULL);
3056 if (!SQL_SUCCEEDED(result))
3058 SC_error_copy(stmt, tbl_stmt, TRUE);
3059 goto cleanup;
3061 result = PGAPI_BindCol(htbl_stmt, 10, internal_asis_type,
3062 constrname, NAMESTORAGELEN, NULL);
3063 if (!SQL_SUCCEEDED(result))
3065 SC_error_copy(stmt, tbl_stmt, TRUE);
3066 goto cleanup;
3069 if (conn->schema_support)
3071 result = PGAPI_BindCol(htbl_stmt, 11, internal_asis_type,
3072 schema_fetched,
3073 SCHEMA_NAME_STORAGE_LEN, NULL);
3074 if (!SQL_SUCCEEDED(result))
3076 SC_error_copy(stmt, tbl_stmt, TRUE);
3077 goto cleanup;
3081 result = PGAPI_Fetch(htbl_stmt);
3082 if (result == SQL_NO_DATA_FOUND)
3084 ret = SQL_SUCCESS;
3085 goto cleanup;
3088 if (result != SQL_SUCCESS)
3090 SC_full_error_copy(stmt, tbl_stmt, FALSE);
3091 goto cleanup;
3094 keyresult = PGAPI_AllocStmt(conn, &hpkey_stmt);
3095 if (!SQL_SUCCEEDED(keyresult))
3097 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
3098 "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.",
3099 func);
3100 goto cleanup;
3103 keyresult = PGAPI_BindCol(hpkey_stmt, 4, internal_asis_type,
3104 pkey, sizeof(pkey), NULL);
3105 if (keyresult != SQL_SUCCESS)
3107 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
3108 "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.",
3109 func);
3110 goto cleanup;
3113 while (result == SQL_SUCCESS)
3115 /* Compute the number of keyparts. */
3116 num_keys = (trig_nargs - 4) / 2;
3118 mylog
3119 ("Foreign Key Case#2: trig_nargs = %d, num_keys = %d\n",
3120 trig_nargs, num_keys);
3122 /* If there is a pk table specified, then check it. */
3123 if (pk_table_needed && pk_table_needed[0] != '\0')
3125 /* If it doesn't match, then continue */
3126 if (strcmp(pk_table_fetched, pk_table_needed))
3128 result = PGAPI_Fetch(htbl_stmt);
3129 continue;
3133 got_pkname = FALSE;
3134 keyresult =
3135 PGAPI_PrimaryKeys(hpkey_stmt, NULL, 0,
3136 (const UCHAR *)schema_fetched,
3137 SQL_NTS, (const UCHAR *)pk_table_fetched,
3138 SQL_NTS);
3139 if (keyresult != SQL_SUCCESS)
3141 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
3142 "Couldn't get primary keys for PGAPI_ForeignKeys result.",
3143 func);
3144 goto cleanup;
3147 /* Get to first primary key */
3148 pkey_ptr = trig_args;
3149 for (i = 0; i < 5; i++)
3150 pkey_ptr += strlen(pkey_ptr) + 1;
3152 for (k = 0; k < num_keys; k++)
3154 /* Check that the key listed is the primary key */
3155 keyresult = PGAPI_Fetch(hpkey_stmt);
3156 if (keyresult != SQL_SUCCESS)
3158 num_keys = 0;
3159 break;
3161 if (!got_pkname)
3163 PGAPI_GetData(hpkey_stmt, 6, internal_asis_type,
3164 pkname, sizeof(pkname), NULL);
3165 got_pkname = TRUE;
3167 pkey_text =
3168 getClientColumnName(conn, relid2, pkey_ptr,
3169 &pkey_alloced);
3170 mylog("%s: pkey_ptr='%s', pkey='%s'\n", func, pkey_text,
3171 pkey);
3172 if (strcmp(pkey_text, pkey))
3174 num_keys = 0;
3175 break;
3177 if (pkey_alloced)
3178 free(pkey_text);
3179 /* Get to next primary key */
3180 for (k = 0; k < 2; k++)
3181 pkey_ptr += strlen(pkey_ptr) + 1;
3184 PGAPI_FreeStmt(hpkey_stmt, SQL_CLOSE);
3186 /* Set to first fk column */
3187 fkey_ptr = trig_args;
3188 for (k = 0; k < 4; k++)
3189 fkey_ptr += strlen(fkey_ptr) + 1;
3191 /* Set update and delete actions for foreign keys */
3192 if (!strcmp(upd_rule, "RI_FKey_cascade_upd"))
3193 upd_rule_type = SQL_CASCADE;
3194 else if (!strcmp(upd_rule, "RI_FKey_noaction_upd"))
3195 upd_rule_type = SQL_NO_ACTION;
3196 else if (!strcmp(upd_rule, "RI_FKey_restrict_upd"))
3197 upd_rule_type = SQL_NO_ACTION;
3198 else if (!strcmp(upd_rule, "RI_FKey_setdefault_upd"))
3199 upd_rule_type = SQL_SET_DEFAULT;
3200 else if (!strcmp(upd_rule, "RI_FKey_setnull_upd"))
3201 upd_rule_type = SQL_SET_NULL;
3203 if (!strcmp(del_rule, "RI_FKey_cascade_del"))
3204 del_rule_type = SQL_CASCADE;
3205 else if (!strcmp(del_rule, "RI_FKey_noaction_del"))
3206 del_rule_type = SQL_NO_ACTION;
3207 else if (!strcmp(del_rule, "RI_FKey_restrict_del"))
3208 del_rule_type = SQL_NO_ACTION;
3209 else if (!strcmp(del_rule, "RI_FKey_setdefault_del"))
3210 del_rule_type = SQL_SET_DEFAULT;
3211 else if (!strcmp(del_rule, "RI_FKey_setnull_del"))
3212 del_rule_type = SQL_SET_NULL;
3214 /* Set deferrability type */
3215 if (!strcmp(trig_initdeferred, "y"))
3216 defer_type = SQL_INITIALLY_DEFERRED;
3217 else if (!strcmp(trig_deferrable, "y"))
3218 defer_type = SQL_INITIALLY_IMMEDIATE;
3219 else
3220 defer_type = SQL_NOT_DEFERRABLE;
3222 /* Get to first primary key */
3223 pkey_ptr = trig_args;
3224 for (i = 0; i < 5; i++)
3225 pkey_ptr += strlen(pkey_ptr) + 1;
3227 for (k = 0; k < num_keys; k++)
3229 tuple = QR_AddNew(res);
3231 pkey_text =
3232 getClientColumnName(conn, relid2, pkey_ptr,
3233 &pkey_alloced);
3234 fkey_text =
3235 getClientColumnName(conn, relid1, fkey_ptr,
3236 &fkey_alloced);
3238 mylog("%s: pk_table = '%s', pkey_ptr = '%s'\n", func,
3239 pk_table_fetched, pkey_text);
3240 set_tuplefield_string(&tuple[FKS_PKTABLE_CAT],
3241 CurrCat(conn));
3242 set_tuplefield_string(&tuple[FKS_PKTABLE_SCHEM],
3243 GET_SCHEMA_NAME(schema_fetched));
3244 set_tuplefield_string(&tuple[FKS_PKTABLE_NAME],
3245 pk_table_fetched);
3246 set_tuplefield_string(&tuple[FKS_PKCOLUMN_NAME],
3247 pkey_text);
3249 mylog("%s: fk_table_needed = '%s', fkey_ptr = '%s'\n",
3250 func, fk_table_needed, fkey_text);
3251 set_tuplefield_null(&tuple[FKS_FKTABLE_CAT]);
3252 set_tuplefield_string(&tuple[FKS_FKTABLE_SCHEM],
3253 GET_SCHEMA_NAME(schema_needed));
3254 set_tuplefield_string(&tuple[FKS_FKTABLE_NAME],
3255 fk_table_needed);
3256 set_tuplefield_string(&tuple[FKS_FKCOLUMN_NAME],
3257 fkey_text);
3259 mylog
3260 ("%s: upd_rule_type = '%i', del_rule_type = '%i'\n, trig_name = '%s'",
3261 func, upd_rule_type, del_rule_type, trig_args);
3262 set_tuplefield_int2(&tuple[FKS_KEY_SEQ],
3263 (Int2) (k + 1));
3264 set_tuplefield_int2(&tuple[FKS_UPDATE_RULE],
3265 upd_rule_type);
3266 set_tuplefield_int2(&tuple[FKS_DELETE_RULE],
3267 del_rule_type);
3268 set_tuplefield_string(&tuple[FKS_FK_NAME], constrname);
3269 set_tuplefield_string(&tuple[FKS_PK_NAME], pkname);
3270 set_tuplefield_int2(&tuple[FKS_DEFERRABILITY],
3271 defer_type);
3272 set_tuplefield_string(&tuple[FKS_TRIGGER_NAME],
3273 trig_args);
3275 if (fkey_alloced)
3276 free(fkey_text);
3277 fkey_alloced = FALSE;
3278 if (pkey_alloced)
3279 free(pkey_text);
3280 pkey_alloced = FALSE;
3281 /* next primary/foreign key */
3282 for (i = 0; i < 2; i++)
3284 fkey_ptr += strlen(fkey_ptr) + 1;
3285 pkey_ptr += strlen(pkey_ptr) + 1;
3289 result = PGAPI_Fetch(htbl_stmt);
3294 * Case #1 -- Get the foreign keys in other tables that refer to the
3295 * primary key in the specified table (pktab). i.e., Who points to
3296 * me?
3298 else if (pk_table_needed[0] != '\0')
3300 escPkTableName =
3301 simpleCatalogEscape(pk_table_needed, SQL_NTS, NULL, conn);
3302 if (conn->schema_support)
3304 char *escSchemaName;
3306 schema_strcat(schema_needed, "%.*s",
3307 (const char *)szPkTableOwner,
3308 cbPkTableOwner, (const char *)szPkTableName,
3309 cbPkTableName, conn);
3310 escSchemaName =
3311 simpleCatalogEscape(schema_needed, SQL_NTS, NULL, conn);
3312 snprintf(tables_query, sizeof(tables_query),
3313 "SELECT pt.tgargs, " " pt.tgnargs, "
3314 " pt.tgdeferrable, "
3315 " pt.tginitdeferred, " " pp1.proname, "
3316 " pp2.proname, "
3317 " pc.oid, "
3318 " pc1.oid, "
3319 " pc1.relname, "
3320 " pt.tgconstrname, pn1.nspname "
3321 "FROM pg_catalog.pg_class pc, "
3322 " pg_catalog.pg_class pc1, "
3323 " pg_catalog.pg_proc pp, "
3324 " pg_catalog.pg_proc pp1, "
3325 " pg_catalog.pg_proc pp2, "
3326 " pg_catalog.pg_trigger pt, "
3327 " pg_catalog.pg_trigger pt1, "
3328 " pg_catalog.pg_trigger pt2, "
3329 " pg_catalog.pg_namespace pn, "
3330 " pg_catalog.pg_namespace pn1 "
3331 "WHERE pc.relname='%s' "
3332 " AND pn.nspname = '%s' "
3333 " AND pc.relnamespace = pn.oid "
3334 " AND pt.tgconstrrelid = pc.oid "
3335 " AND pp.oid = pt.tgfoid "
3336 " AND pp.proname Like '%%ins' "
3337 " AND pt1.tgconstrname = pt.tgconstrname "
3338 " AND pt1.tgconstrrelid = pt.tgrelid "
3339 " AND pt1.tgrelid = pc.oid "
3340 " AND pc1.oid = pt.tgrelid "
3341 " AND pp1.oid = pt1.tgfoid "
3342 " AND pp1.proname like '%%upd' "
3343 " AND (pp1.proname not like '%%check%%') "
3344 " AND pt2.tgconstrname = pt.tgconstrname "
3345 " AND pt2.tgconstrrelid = pt.tgrelid "
3346 " AND pt2.tgrelid = pc.oid "
3347 " AND pp2.oid = pt2.tgfoid "
3348 " AND pp2.proname Like '%%del' "
3349 " AND pn1.oid = pc1.relnamespace "
3350 " order by pt.tgconstrname",
3351 escPkTableName, escSchemaName);
3352 free(escSchemaName);
3354 else
3355 snprintf(tables_query, sizeof(tables_query),
3356 "SELECT pt.tgargs, " " pt.tgnargs, "
3357 " pt.tgdeferrable, "
3358 " pt.tginitdeferred, " " pp1.proname, "
3359 " pp2.proname, "
3360 " pc.oid, "
3361 " pc1.oid, "
3362 " pc1.relname, pt.tgconstrname "
3363 "FROM pg_class pc, "
3364 " pg_class pc1, "
3365 " pg_proc pp, "
3366 " pg_proc pp1, "
3367 " pg_proc pp2, "
3368 " pg_trigger pt, "
3369 " pg_trigger pt1, "
3370 " pg_trigger pt2 "
3371 "WHERE pc.relname ='%s' "
3372 " AND pt.tgconstrrelid = pc.oid "
3373 " AND pp.oid = pt.tgfoid "
3374 " AND pp.proname Like '%%ins' "
3375 " AND pt1.tgconstrname = pt.tgconstrname "
3376 " AND pt1.tgconstrrelid = pt.tgrelid "
3377 " AND pt1.tgrelid = pc.oid "
3378 " AND pc1.oid = pt.tgrelid "
3379 " AND pp1.oid = pt1.tgfoid "
3380 " AND pp1.proname like '%%upd' "
3381 " AND pp1.(proname not like '%%check%%') "
3382 " AND pt2.tgconstrname = pt.tgconstrname "
3383 " AND pt2.tgconstrrelid = pt.tgrelid "
3384 " AND pt2.tgrelid = pc.oid "
3385 " AND pp2.oid = pt2.tgfoid "
3386 " AND pp2.proname Like '%%del'"
3387 " order by pt.tgconstrname", escPkTableName);
3389 result = PGAPI_ExecDirect(htbl_stmt, (const UCHAR *)tables_query,
3390 SQL_NTS, 0);
3391 if (!SQL_SUCCEEDED(result))
3393 SC_error_copy(stmt, tbl_stmt, TRUE);
3394 goto cleanup;
3397 result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_BINARY,
3398 trig_args, sizeof(trig_args), NULL);
3399 if (!SQL_SUCCEEDED(result))
3401 SC_error_copy(stmt, tbl_stmt, TRUE);
3402 goto cleanup;
3405 result = PGAPI_BindCol(htbl_stmt, 2, SQL_C_SHORT,
3406 &trig_nargs, 0, NULL);
3407 if (!SQL_SUCCEEDED(result))
3409 SC_error_copy(stmt, tbl_stmt, TRUE);
3410 goto cleanup;
3413 result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
3414 trig_deferrable, sizeof(trig_deferrable),
3415 NULL);
3416 if (!SQL_SUCCEEDED(result))
3418 SC_error_copy(stmt, tbl_stmt, TRUE);
3419 goto cleanup;
3422 result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type,
3423 trig_initdeferred,
3424 sizeof(trig_initdeferred), NULL);
3425 if (!SQL_SUCCEEDED(result))
3427 SC_error_copy(stmt, tbl_stmt, TRUE);
3428 goto cleanup;
3431 result = PGAPI_BindCol(htbl_stmt, 5, internal_asis_type,
3432 upd_rule, sizeof(upd_rule), NULL);
3433 if (!SQL_SUCCEEDED(result))
3435 SC_error_copy(stmt, tbl_stmt, TRUE);
3436 goto cleanup;
3439 result = PGAPI_BindCol(htbl_stmt, 6, internal_asis_type,
3440 del_rule, sizeof(del_rule), NULL);
3441 if (!SQL_SUCCEEDED(result))
3443 SC_error_copy(stmt, tbl_stmt, TRUE);
3444 goto cleanup;
3447 result = PGAPI_BindCol(htbl_stmt, 7, SQL_C_ULONG,
3448 &relid1, sizeof(relid1), NULL);
3449 if (!SQL_SUCCEEDED(result))
3451 SC_error_copy(stmt, tbl_stmt, TRUE);
3452 goto cleanup;
3454 result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG,
3455 &relid2, sizeof(relid2), NULL);
3456 if (!SQL_SUCCEEDED(result))
3458 SC_error_copy(stmt, tbl_stmt, TRUE);
3459 goto cleanup;
3461 result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type,
3462 fk_table_fetched, TABLE_NAME_STORAGE_LEN,
3463 NULL);
3464 if (!SQL_SUCCEEDED(result))
3466 SC_error_copy(stmt, tbl_stmt, TRUE);
3467 goto cleanup;
3469 result = PGAPI_BindCol(htbl_stmt, 10, internal_asis_type,
3470 constrname, NAMESTORAGELEN, NULL);
3471 if (!SQL_SUCCEEDED(result))
3473 SC_error_copy(stmt, tbl_stmt, TRUE);
3474 goto cleanup;
3477 if (conn->schema_support)
3479 result = PGAPI_BindCol(htbl_stmt, 11, internal_asis_type,
3480 schema_fetched,
3481 SCHEMA_NAME_STORAGE_LEN, NULL);
3482 if (!SQL_SUCCEEDED(result))
3484 SC_error_copy(stmt, tbl_stmt, TRUE);
3485 goto cleanup;
3489 result = PGAPI_Fetch(htbl_stmt);
3490 if (result == SQL_NO_DATA_FOUND)
3492 ret = SQL_SUCCESS;
3493 goto cleanup;
3496 if (result != SQL_SUCCESS)
3498 SC_full_error_copy(stmt, tbl_stmt, FALSE);
3499 goto cleanup;
3503 * get pk_name here
3505 keyresult = PGAPI_AllocStmt(conn, &hpkey_stmt);
3506 if (!SQL_SUCCEEDED(keyresult))
3508 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
3509 "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.",
3510 func);
3511 goto cleanup;
3513 keyresult = PGAPI_BindCol(hpkey_stmt, 6, internal_asis_type,
3514 pkname, sizeof(pkname), NULL);
3515 if (keyresult != SQL_SUCCESS)
3517 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
3518 "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.",
3519 func);
3520 goto cleanup;
3522 keyresult =
3523 PGAPI_PrimaryKeys(hpkey_stmt, NULL, 0,
3524 (const UCHAR *)schema_needed,
3525 SQL_NTS, (const UCHAR *)pk_table_needed,
3526 SQL_NTS);
3527 if (keyresult != SQL_SUCCESS)
3529 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
3530 "Couldn't get primary keys for PGAPI_ForeignKeys result.",
3531 func);
3532 goto cleanup;
3534 pkname[0] = '\0';
3535 keyresult = PGAPI_Fetch(hpkey_stmt);
3536 PGAPI_FreeStmt(hpkey_stmt, SQL_CLOSE);
3537 while (result == SQL_SUCCESS)
3539 /* Calculate the number of key parts */
3540 num_keys = (trig_nargs - 4) / 2;;
3542 /* Handle action (i.e., 'cascade', 'restrict', 'setnull') */
3543 if (!strcmp(upd_rule, "RI_FKey_cascade_upd"))
3544 upd_rule_type = SQL_CASCADE;
3545 else if (!strcmp(upd_rule, "RI_FKey_noaction_upd"))
3546 upd_rule_type = SQL_NO_ACTION;
3547 else if (!strcmp(upd_rule, "RI_FKey_restrict_upd"))
3548 upd_rule_type = SQL_NO_ACTION;
3549 else if (!strcmp(upd_rule, "RI_FKey_setdefault_upd"))
3550 upd_rule_type = SQL_SET_DEFAULT;
3551 else if (!strcmp(upd_rule, "RI_FKey_setnull_upd"))
3552 upd_rule_type = SQL_SET_NULL;
3554 if (!strcmp(del_rule, "RI_FKey_cascade_del"))
3555 del_rule_type = SQL_CASCADE;
3556 else if (!strcmp(del_rule, "RI_FKey_noaction_del"))
3557 del_rule_type = SQL_NO_ACTION;
3558 else if (!strcmp(del_rule, "RI_FKey_restrict_del"))
3559 del_rule_type = SQL_NO_ACTION;
3560 else if (!strcmp(del_rule, "RI_FKey_setdefault_del"))
3561 del_rule_type = SQL_SET_DEFAULT;
3562 else if (!strcmp(del_rule, "RI_FKey_setnull_del"))
3563 del_rule_type = SQL_SET_NULL;
3565 /* Set deferrability type */
3566 if (!strcmp(trig_initdeferred, "y"))
3567 defer_type = SQL_INITIALLY_DEFERRED;
3568 else if (!strcmp(trig_deferrable, "y"))
3569 defer_type = SQL_INITIALLY_IMMEDIATE;
3570 else
3571 defer_type = SQL_NOT_DEFERRABLE;
3573 mylog
3574 ("Foreign Key Case#1: trig_nargs = %d, num_keys = %d\n",
3575 trig_nargs, num_keys);
3577 /* Get to first primary key */
3578 pkey_ptr = trig_args;
3579 for (i = 0; i < 5; i++)
3580 pkey_ptr += strlen(pkey_ptr) + 1;
3582 /* Get to first foreign key */
3583 fkey_ptr = trig_args;
3584 for (k = 0; k < 4; k++)
3585 fkey_ptr += strlen(fkey_ptr) + 1;
3587 for (k = 0; k < num_keys; k++)
3589 pkey_text =
3590 getClientColumnName(conn, relid1, pkey_ptr,
3591 &pkey_alloced);
3592 fkey_text =
3593 getClientColumnName(conn, relid2, fkey_ptr,
3594 &fkey_alloced);
3596 mylog
3597 ("pkey_ptr = '%s', fk_table = '%s', fkey_ptr = '%s'\n",
3598 pkey_text, fk_table_fetched, fkey_text);
3600 tuple = QR_AddNew(res);
3602 mylog("pk_table_needed = '%s', pkey_ptr = '%s'\n",
3603 pk_table_needed, pkey_text);
3604 set_tuplefield_string(&tuple[FKS_PKTABLE_CAT],
3605 CurrCat(conn));
3606 set_tuplefield_string(&tuple[FKS_PKTABLE_SCHEM],
3607 GET_SCHEMA_NAME(schema_needed));
3608 set_tuplefield_string(&tuple[FKS_PKTABLE_NAME],
3609 pk_table_needed);
3610 set_tuplefield_string(&tuple[FKS_PKCOLUMN_NAME],
3611 pkey_text);
3613 mylog("fk_table = '%s', fkey_ptr = '%s'\n",
3614 fk_table_fetched, fkey_text);
3615 set_tuplefield_null(&tuple[FKS_FKTABLE_CAT]);
3616 set_tuplefield_string(&tuple[FKS_FKTABLE_SCHEM],
3617 GET_SCHEMA_NAME(schema_fetched));
3618 set_tuplefield_string(&tuple[FKS_FKTABLE_NAME],
3619 fk_table_fetched);
3620 set_tuplefield_string(&tuple[FKS_FKCOLUMN_NAME],
3621 fkey_text);
3623 set_tuplefield_int2(&tuple[FKS_KEY_SEQ],
3624 (Int2) (k + 1));
3626 mylog("upd_rule = %d, del_rule= %d", upd_rule_type,
3627 del_rule_type);
3628 set_nullfield_int2(&tuple[FKS_UPDATE_RULE],
3629 upd_rule_type);
3630 set_nullfield_int2(&tuple[FKS_DELETE_RULE],
3631 del_rule_type);
3633 set_tuplefield_string(&tuple[FKS_FK_NAME], constrname);
3634 set_tuplefield_string(&tuple[FKS_PK_NAME], pkname);
3636 set_tuplefield_string(&tuple[FKS_TRIGGER_NAME],
3637 trig_args);
3639 mylog(" defer_type = %d\n", defer_type);
3640 set_tuplefield_int2(&tuple[FKS_DEFERRABILITY],
3641 defer_type);
3643 if (pkey_alloced)
3644 free(pkey_text);
3645 pkey_alloced = FALSE;
3646 if (fkey_alloced)
3647 free(fkey_text);
3648 fkey_alloced = FALSE;
3650 /* next primary/foreign key */
3651 for (j = 0; j < 2; j++)
3653 pkey_ptr += strlen(pkey_ptr) + 1;
3654 fkey_ptr += strlen(fkey_ptr) + 1;
3657 result = PGAPI_Fetch(htbl_stmt);
3660 else
3662 SC_set_error(stmt, STMT_INTERNAL_ERROR,
3663 "No tables specified to PGAPI_ForeignKeys.", func);
3664 goto cleanup;
3666 ret = SQL_SUCCESS;
3668 cleanup:
3669 #undef return
3671 * also, things need to think that this statement is finished so the
3672 * results can be retrieved.
3674 stmt->status = STMT_FINISHED;
3676 if (pkey_alloced)
3677 free(pkey_text);
3678 if (fkey_alloced)
3679 free(fkey_text);
3680 if (pk_table_needed)
3681 free(pk_table_needed);
3682 if (escPkTableName)
3683 free(escPkTableName);
3684 if (fk_table_needed)
3685 free(fk_table_needed);
3686 if (escFkTableName)
3687 free(escFkTableName);
3689 if (htbl_stmt)
3690 PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
3691 if (hpkey_stmt)
3692 PGAPI_FreeStmt(hpkey_stmt, SQL_DROP);
3694 /* set up the current tuple pointer for SQLFetch */
3695 stmt->currTuple = -1;
3696 SC_set_rowset_start(stmt, -1, FALSE);
3697 SC_set_current_col(stmt, -1);
3699 if (stmt->internal)
3700 ret = DiscardStatementSvp(stmt, ret, FALSE);
3701 mylog("%s(): EXIT, stmt=%p, ret=%d\n", func, stmt, ret);
3702 return ret;
3705 RETCODE SQL_API PGAPI_ProcedureColumns(HSTMT hstmt, const SQLCHAR FAR * szProcQualifier, /* OA X */
3706 SQLSMALLINT cbProcQualifier, const SQLCHAR FAR * szProcOwner, /* PV E */
3707 SQLSMALLINT cbProcOwner, const SQLCHAR FAR * szProcName, /* PV E */
3708 SQLSMALLINT cbProcName, const SQLCHAR FAR * szColumnName, /* PV X */
3709 SQLSMALLINT cbColumnName,
3710 UWORD flag)
3712 CSTR func = "PGAPI_ProcedureColumns";
3713 StatementClass *stmt = (StatementClass *) hstmt;
3714 ConnectionClass *conn = SC_get_conn(stmt);
3715 char proc_query[INFO_INQUIRY_LEN];
3716 Int2 result_cols;
3717 TupleField *tuple;
3718 const char *schema_name, *procname;
3719 char *escSchemaName = NULL, *escProcName = NULL;
3720 char *params, *delim = NULL;
3721 char *atttypid, *proargnames, *proargmodes;
3722 char *attname, *column_name;
3723 QResultClass *res, *tres;
3724 SQLLEN tcount;
3725 OID pgtype;
3726 Int4 paramcount, i, j;
3727 RETCODE result;
3728 BOOL search_pattern, bRetset;
3729 const char *like_or_eq, *retset;
3730 int ret_col = -1, ext_pos = -1, poid_pos = -1, attid_pos =
3731 -1, attname_pos = -1;
3732 UInt4 poid = 0, newpoid;
3734 mylog("%s: entering...\n", func);
3736 if (PG_VERSION_LT(conn, 6.5))
3738 SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR,
3739 "Version is too old", func);
3740 return SQL_ERROR;
3742 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
3743 return result;
3744 search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
3745 if (search_pattern)
3747 like_or_eq = likeop;
3748 escSchemaName =
3749 adjustLikePattern(szProcOwner, cbProcOwner,
3750 SEARCH_PATTERN_ESCAPE, NULL, conn);
3751 escProcName =
3752 adjustLikePattern(szProcName, cbProcName,
3753 SEARCH_PATTERN_ESCAPE, NULL, conn);
3755 else
3757 like_or_eq = eqop;
3758 escSchemaName =
3759 simpleCatalogEscape(szProcOwner, cbProcOwner, NULL, conn);
3760 escProcName =
3761 simpleCatalogEscape(szProcName, cbProcName, NULL, conn);
3763 if (conn->schema_support)
3765 strcpy(proc_query, "select proname, proretset, prorettype, "
3766 "pronargs, proargtypes, nspname, p.oid");
3767 ret_col = ext_pos = 7;
3768 poid_pos = 6;
3769 strcat(proc_query, ", atttypid, attname");
3770 attid_pos = ext_pos;
3771 attname_pos = ext_pos + 1;
3772 ret_col += 2;
3773 ext_pos = ret_col;
3774 if (PG_VERSION_GE(conn, 8.0))
3776 strcat(proc_query, ", proargnames");
3777 ret_col++;
3779 if (PG_VERSION_GE(conn, 8.1))
3781 strcat(proc_query, ", proargmodes, proallargtypes");
3782 ret_col += 2;
3784 strcat(proc_query,
3785 " from ((pg_catalog.pg_namespace n inner join"
3786 " pg_catalog.pg_proc p on p.pronamespace = n.oid)"
3787 " inner join pg_type t on t.oid = p.prorettype)"
3788 " left outer join pg_attribute a on a.attrelid = t.typrelid "
3789 " and attnum > 0 and not attisdropped where");
3790 strcat(proc_query, " has_function_privilege(p.oid, 'EXECUTE')");
3791 my_strcat1(proc_query, " and nspname %s '%.*s'", like_or_eq,
3792 escSchemaName, SQL_NTS);
3793 if (escProcName)
3794 snprintf_add(proc_query, sizeof(proc_query),
3795 " and proname %s '%s'", like_or_eq,
3796 escProcName);
3797 strcat(proc_query, " order by nspname, proname, p.oid, attnum");
3799 else
3801 strcpy(proc_query, "select proname, proretset, prorettype, "
3802 "pronargs, proargtypes from pg_proc where "
3803 "(not proretset)");
3804 ret_col = 5;
3805 if (escProcName)
3806 snprintf_add(proc_query, sizeof(proc_query),
3807 " and proname %s '%s'", like_or_eq,
3808 escProcName);
3809 strcat(proc_query, " order by proname, proretset");
3811 if (tres =
3812 CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN,
3813 stmt), !QR_command_maybe_successful(tres))
3815 SC_set_error(stmt, STMT_EXEC_ERROR,
3816 "PGAPI_ProcedureColumns query error", func);
3817 QR_Destructor(tres);
3818 return SQL_ERROR;
3821 if (res = QR_Constructor(), !res)
3823 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
3824 "Couldn't allocate memory for PGAPI_ProcedureColumns result.",
3825 func);
3826 return SQL_ERROR;
3828 SC_set_Result(stmt, res);
3831 * the binding structure for a statement is not set up until
3832 * a statement is actually executed, so we'll have to do this
3833 * ourselves.
3835 result_cols = NUM_OF_PROCOLS_FIELDS;
3836 extend_column_bindings(SC_get_ARDF(stmt), result_cols);
3838 /* set the field names */
3839 QR_set_num_fields(res, result_cols);
3840 QR_set_field_info_v(res, PROCOLS_PROCEDURE_CAT, "PROCEDURE_CAT",
3841 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3842 QR_set_field_info_v(res, PROCOLS_PROCEDURE_SCHEM, "PROCEDUR_SCHEM",
3843 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3844 QR_set_field_info_v(res, PROCOLS_PROCEDURE_NAME, "PROCEDURE_NAME",
3845 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3846 QR_set_field_info_v(res, PROCOLS_COLUMN_NAME, "COLUMN_NAME",
3847 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3848 QR_set_field_info_v(res, PROCOLS_COLUMN_TYPE, "COLUMN_TYPE",
3849 PG_TYPE_INT2, 2);
3850 QR_set_field_info_v(res, PROCOLS_DATA_TYPE, "DATA_TYPE",
3851 PG_TYPE_INT2, 2);
3852 QR_set_field_info_v(res, PROCOLS_TYPE_NAME, "TYPE_NAME",
3853 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3854 QR_set_field_info_v(res, PROCOLS_COLUMN_SIZE, "COLUMN_SIZE",
3855 PG_TYPE_INT4, 4);
3856 QR_set_field_info_v(res, PROCOLS_BUFFER_LENGTH, "BUFFER_LENGTH",
3857 PG_TYPE_INT4, 4);
3858 QR_set_field_info_v(res, PROCOLS_DECIMAL_DIGITS, "DECIMAL_DIGITS",
3859 PG_TYPE_INT2, 2);
3860 QR_set_field_info_v(res, PROCOLS_NUM_PREC_RADIX, "NUM_PREC_RADIX",
3861 PG_TYPE_INT2, 2);
3862 QR_set_field_info_v(res, PROCOLS_NULLABLE, "NULLABLE", PG_TYPE_INT2,
3864 QR_set_field_info_v(res, PROCOLS_REMARKS, "REMARKS",
3865 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3866 QR_set_field_info_v(res, PROCOLS_COLUMN_DEF, "COLUMN_DEF",
3867 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3868 QR_set_field_info_v(res, PROCOLS_SQL_DATA_TYPE, "SQL_DATA_TYPE",
3869 PG_TYPE_INT2, 2);
3870 QR_set_field_info_v(res, PROCOLS_SQL_DATETIME_SUB,
3871 "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
3872 QR_set_field_info_v(res, PROCOLS_CHAR_OCTET_LENGTH,
3873 "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
3874 QR_set_field_info_v(res, PROCOLS_ORDINAL_POSITION,
3875 "ORDINAL_POSITION", PG_TYPE_INT4, 4);
3876 QR_set_field_info_v(res, PROCOLS_IS_NULLABLE, "IS_NULLABLE",
3877 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3879 column_name = make_string(szColumnName, cbColumnName, NULL, 0);
3880 if (column_name) /* column_name is unavailable now */
3882 tcount = 0;
3883 free(column_name);
3885 else
3886 tcount = QR_get_num_total_tuples(tres);
3887 for (i = 0, poid = 0; i < tcount; i++)
3889 if (conn->schema_support)
3890 schema_name =
3891 GET_SCHEMA_NAME(QR_get_value_backend_text(tres, i, 5));
3892 else
3893 schema_name = NULL;
3894 procname = QR_get_value_backend_text(tres, i, 0);
3895 retset = QR_get_value_backend_text(tres, i, 1);
3896 pgtype = QR_get_value_backend_int(tres, i, 2, NULL);
3897 bRetset = retset && (retset[0] == 't' || retset[0] == 'y');
3898 newpoid = 0;
3899 if (poid_pos >= 0)
3900 newpoid = QR_get_value_backend_int(tres, i, poid_pos, NULL);
3901 mylog("newpoid=%d\n", newpoid);
3902 atttypid = NULL;
3903 if (attid_pos >= 0)
3905 atttypid = (char *)QR_get_value_backend_text(tres, i, attid_pos);
3906 mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
3908 if (poid == 0 || newpoid != poid)
3910 poid = newpoid;
3911 proargmodes = NULL;
3912 proargnames = NULL;
3913 if (ext_pos >= 0)
3915 if (PG_VERSION_GE(conn, 8.0))
3916 proargnames = (char *)
3917 QR_get_value_backend_text(tres, i, ext_pos);
3918 if (PG_VERSION_GE(conn, 8.1))
3919 proargmodes = (char *)
3920 QR_get_value_backend_text(tres, i, ext_pos + 1);
3922 /* RETURN_VALUE info */
3923 if (0 != pgtype && PG_TYPE_VOID != pgtype && !bRetset
3924 && !atttypid && !proargmodes)
3926 tuple = QR_AddNew(res);
3927 set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_CAT],
3928 CurrCat(conn));
3929 set_nullfield_string(&tuple[PROCOLS_PROCEDURE_SCHEM],
3930 schema_name);
3931 set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_NAME],
3932 procname);
3933 set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME],
3934 NULL_STRING);
3935 set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE],
3936 SQL_RETURN_VALUE);
3937 set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE],
3938 pgtype_to_concise_type(stmt, pgtype,
3939 PG_STATIC));
3940 set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME],
3941 pgtype_to_name(stmt, pgtype,
3942 FALSE));
3943 set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE],
3944 pgtype_column_size(stmt, pgtype,
3945 PG_STATIC,
3946 PG_STATIC));
3947 set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH],
3948 pgtype_buffer_length(stmt, pgtype,
3949 PG_STATIC,
3950 PG_STATIC));
3951 set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS],
3952 pgtype_decimal_digits(stmt, pgtype,
3953 PG_STATIC));
3954 set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX],
3955 pgtype_radix(stmt, pgtype));
3956 set_tuplefield_int2(&tuple[PROCOLS_NULLABLE],
3957 SQL_NULLABLE_UNKNOWN);
3958 set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
3959 set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
3960 set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE],
3961 pgtype_to_sqldesctype(stmt, pgtype,
3962 PG_STATIC));
3963 set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB],
3964 pgtype_to_datetime_sub(stmt,
3965 pgtype));
3966 set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH],
3967 pgtype_transfer_octet_length(stmt,
3968 pgtype,
3969 PG_STATIC,
3970 PG_STATIC));
3971 set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION],
3973 set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE],
3974 NULL_STRING);
3976 if (proargmodes)
3978 const char *p;
3980 paramcount = 0;
3981 for (p = proargmodes; *p; p++)
3983 if (',' == (*p))
3984 paramcount++;
3986 paramcount++;
3987 params = (char *)
3988 QR_get_value_backend_text(tres, i, ext_pos + 2);
3989 if ('{' == *proargmodes)
3990 proargmodes++;
3991 if ('{' == *params)
3992 params++;
3994 else
3996 paramcount = QR_get_value_backend_int(tres, i, 3, NULL);
3997 params = (char *)QR_get_value_backend_text(tres, i, 4);
3999 if (proargnames)
4001 if ('{' == *proargnames)
4002 proargnames++;
4004 /* PARAMETERS info */
4005 for (j = 0; j < paramcount; j++)
4007 /* PG type of parameters */
4008 pgtype = 0;
4009 if (params)
4011 while (isspace(*params) || ',' == *params)
4012 params++;
4013 if ('\0' == *params || '}' == *params)
4014 params = NULL;
4015 else
4017 sscanf(params, "%u", &pgtype);
4018 while (isdigit(*params))
4019 params++;
4022 /* input/output type of parameters */
4023 if (proargmodes)
4025 while (isspace(*proargmodes) || ',' == *proargmodes)
4026 proargmodes++;
4027 if ('\0' == *proargmodes || '}' == *proargmodes)
4028 proargmodes = NULL;
4030 /* name of parameters */
4031 if (proargnames)
4033 while (isspace(*proargnames) || ',' == *proargnames)
4034 proargnames++;
4035 if ('\0' == *proargnames || '}' == *proargnames)
4036 proargnames = NULL;
4037 else if ('"' == *proargnames)
4039 proargnames++;
4040 for (delim = proargnames;
4041 *delim && *delim != '"'; delim++)
4044 else
4046 for (delim = proargnames;
4047 *delim && !isspace(*delim) && ',' != *delim
4048 && '}' != *delim; delim++)
4051 if (proargnames && '\0' == *delim) /* discard the incomplete name */
4052 proargnames = NULL;
4055 tuple = QR_AddNew(res);
4056 set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_CAT],
4057 CurrCat(conn));
4058 set_nullfield_string(&tuple[PROCOLS_PROCEDURE_SCHEM],
4059 schema_name);
4060 set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_NAME],
4061 procname);
4062 if (proargnames)
4064 *delim = '\0';
4065 set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME],
4066 proargnames);
4067 proargnames = delim + 1;
4069 else
4070 set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME],
4071 NULL_STRING);
4072 if (proargmodes)
4074 int ptype;
4076 switch (*proargmodes)
4078 case 'o':
4079 ptype = SQL_PARAM_OUTPUT;
4080 break;
4081 case 'b':
4082 ptype = SQL_PARAM_INPUT_OUTPUT;
4083 break;
4084 default:
4085 ptype = SQL_PARAM_INPUT;
4086 break;
4088 set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE],
4089 ptype);
4090 proargmodes++;
4092 else
4093 set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE],
4094 SQL_PARAM_INPUT);
4095 set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE],
4096 pgtype_to_concise_type(stmt, pgtype,
4097 PG_STATIC));
4098 set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME],
4099 pgtype_to_name(stmt, pgtype,
4100 FALSE));
4101 set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE],
4102 pgtype_column_size(stmt, pgtype,
4103 PG_STATIC,
4104 PG_STATIC));
4105 set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH],
4106 pgtype_buffer_length(stmt, pgtype,
4107 PG_STATIC,
4108 PG_STATIC));
4109 set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS],
4110 pgtype_decimal_digits(stmt, pgtype,
4111 PG_STATIC));
4112 set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX],
4113 pgtype_radix(stmt, pgtype));
4114 set_tuplefield_int2(&tuple[PROCOLS_NULLABLE],
4115 SQL_NULLABLE_UNKNOWN);
4116 set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
4117 set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
4118 set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE],
4119 pgtype_to_sqldesctype(stmt, pgtype,
4120 PG_STATIC));
4121 set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB],
4122 pgtype_to_datetime_sub(stmt,
4123 pgtype));
4124 set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH],
4125 pgtype_transfer_octet_length(stmt,
4126 pgtype,
4127 PG_STATIC,
4128 PG_STATIC));
4129 set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION],
4130 j + 1);
4131 set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE],
4132 NULL_STRING);
4135 /* RESULT Columns info */
4136 if (NULL != atttypid || bRetset)
4138 int typid;
4140 if (bRetset)
4142 typid = pgtype;
4143 attname = NULL;
4145 else
4147 typid = atoi(atttypid);
4148 attname = (char *)
4149 QR_get_value_backend_text(tres, i, attname_pos);
4151 tuple = QR_AddNew(res);
4152 set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_CAT],
4153 CurrCat(conn));
4154 set_nullfield_string(&tuple[PROCOLS_PROCEDURE_SCHEM],
4155 schema_name);
4156 set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_NAME],
4157 procname);
4158 set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME], attname);
4159 set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE],
4160 SQL_RESULT_COL);
4161 set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE],
4162 pgtype_to_concise_type(stmt, typid,
4163 PG_STATIC));
4164 set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME],
4165 pgtype_to_name(stmt, typid, FALSE));
4166 set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE],
4167 pgtype_column_size(stmt, typid,
4168 PG_STATIC,
4169 PG_STATIC));
4170 set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH],
4171 pgtype_buffer_length(stmt, typid,
4172 PG_STATIC,
4173 PG_STATIC));
4174 set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS],
4175 pgtype_decimal_digits(stmt, typid,
4176 PG_STATIC));
4177 set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX],
4178 pgtype_radix(stmt, typid));
4179 set_tuplefield_int2(&tuple[PROCOLS_NULLABLE],
4180 SQL_NULLABLE_UNKNOWN);
4181 set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
4182 set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
4183 set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE],
4184 pgtype_to_sqldesctype(stmt, typid,
4185 PG_STATIC));
4186 set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB],
4187 pgtype_to_datetime_sub(stmt, typid));
4188 set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH],
4189 pgtype_transfer_octet_length(stmt, typid,
4190 PG_STATIC,
4191 PG_STATIC));
4192 set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION], 0);
4193 set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE],
4194 NULL_STRING);
4197 QR_Destructor(tres);
4199 * also, things need to think that this statement is finished so the
4200 * results can be retrieved.
4202 if (escSchemaName)
4203 free(escSchemaName);
4204 if (escProcName)
4205 free(escProcName);
4206 stmt->status = STMT_FINISHED;
4207 /* set up the current tuple pointer for SQLFetch */
4208 stmt->currTuple = -1;
4209 SC_set_rowset_start(stmt, -1, FALSE);
4210 SC_set_current_col(stmt, -1);
4212 return SQL_SUCCESS;
4215 RETCODE SQL_API PGAPI_Procedures(HSTMT hstmt, const SQLCHAR FAR * szProcQualifier, /* OA X */
4216 SQLSMALLINT cbProcQualifier, const SQLCHAR FAR * szProcOwner, /* PV E */
4217 SQLSMALLINT cbProcOwner, const SQLCHAR FAR * szProcName, /* PV E */
4218 SQLSMALLINT cbProcName, UWORD flag)
4220 CSTR func = "PGAPI_Procedures";
4221 StatementClass *stmt = (StatementClass *) hstmt;
4222 ConnectionClass *conn = SC_get_conn(stmt);
4223 char proc_query[INFO_INQUIRY_LEN];
4224 char *escSchemaName = NULL, *escProcName = NULL;
4225 QResultClass *res;
4226 RETCODE result;
4227 const char *like_or_eq;
4228 BOOL search_pattern;
4230 mylog("%s: entering... scnm=%p len=%d\n", func, szProcOwner,
4231 cbProcOwner);
4233 if (PG_VERSION_LT(conn, 6.5))
4235 SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR,
4236 "Version is too old", func);
4237 return SQL_ERROR;
4239 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
4240 return result;
4242 search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
4243 if (search_pattern)
4245 like_or_eq = likeop;
4246 escSchemaName =
4247 adjustLikePattern(szProcOwner, cbProcOwner,
4248 SEARCH_PATTERN_ESCAPE, NULL, conn);
4249 escProcName =
4250 adjustLikePattern(szProcName, cbProcName,
4251 SEARCH_PATTERN_ESCAPE, NULL, conn);
4253 else
4255 like_or_eq = eqop;
4256 escSchemaName =
4257 simpleCatalogEscape(szProcOwner, cbProcOwner, NULL, conn);
4258 escProcName =
4259 simpleCatalogEscape(szProcName, cbProcName, NULL, conn);
4262 * The following seems the simplest implementation
4264 if (conn->schema_support)
4266 strcpy(proc_query,
4267 "select '' as " "PROCEDURE_CAT" ", nspname as "
4268 "PROCEDURE_SCHEM" "," " proname as " "PROCEDURE_NAME"
4269 ", '' as " "NUM_INPUT_PARAMS" "," " '' as "
4270 "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
4271 " '' as " "REMARKS" ","
4272 " case when prorettype = 0 then 1::int2 else 2::int2 end"
4273 " as " "PROCEDURE_TYPE" " from pg_catalog.pg_namespace,"
4274 " pg_catalog.pg_proc"
4275 " where pg_proc.pronamespace = pg_namespace.oid");
4276 schema_strcat1(proc_query, " and nspname %s '%.*s'", like_or_eq,
4277 escSchemaName, SQL_NTS,
4278 (const char *)szProcName, cbProcName, conn);
4279 my_strcat1(proc_query, " and proname %s '%.*s'", like_or_eq,
4280 escProcName, SQL_NTS);
4282 else
4284 strcpy(proc_query,
4285 "select '' as " "PROCEDURE_CAT" ", '' as "
4286 "PROCEDURE_SCHEM" "," " proname as " "PROCEDURE_NAME"
4287 ", '' as " "NUM_INPUT_PARAMS" "," " '' as "
4288 "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
4289 " '' as " "REMARKS" ","
4290 " case when prorettype = 0 then 1::int2 else 2::int2 end as "
4291 "PROCEDURE_TYPE" " from pg_proc");
4292 my_strcat1(proc_query, " where proname %s '%.*s'", like_or_eq,
4293 escSchemaName, SQL_NTS);
4296 if (res =
4297 CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN,
4298 stmt), !QR_command_maybe_successful(res))
4300 SC_set_error(stmt, STMT_EXEC_ERROR,
4301 "PGAPI_Procedures query error", func);
4302 QR_Destructor(res);
4303 return SQL_ERROR;
4305 SC_set_Result(stmt, res);
4308 * also, things need to think that this statement is finished so the
4309 * results can be retrieved.
4311 stmt->status = STMT_FINISHED;
4312 extend_column_bindings(SC_get_ARDF(stmt), 8);
4313 if (escSchemaName)
4314 free(escSchemaName);
4315 if (escProcName)
4316 free(escProcName);
4317 /* set up the current tuple pointer for SQLFetch */
4318 stmt->currTuple = -1;
4319 SC_set_rowset_start(stmt, -1, FALSE);
4320 SC_set_current_col(stmt, -1);
4322 return SQL_SUCCESS;
4325 #define ACLMAX 8
4326 #define ALL_PRIVILIGES "arwdRxt"
4327 static int usracl_auth(char *usracl, const char *auth)
4329 int i, j, addcnt = 0;
4331 for (i = 0; auth[i]; i++)
4333 for (j = 0; j < ACLMAX; j++)
4335 if (usracl[j] == auth[i])
4336 break;
4337 else if (!usracl[j])
4339 usracl[j] = auth[i];
4340 addcnt++;
4341 break;
4345 return addcnt;
4347 static void
4348 useracl_upd(char (*useracl)[ACLMAX], QResultClass * allures,
4349 const char *user, const char *auth)
4351 int usercount = (int) QR_get_num_cached_tuples(allures), i, addcnt =
4354 mylog("user=%s auth=%s\n", user, auth);
4355 if (user[0])
4356 for (i = 0; i < usercount; i++)
4358 if (strcmp(QR_get_value_backend_text(allures, i, 0), user)
4359 == 0)
4361 addcnt += usracl_auth(useracl[i], auth);
4362 break;
4365 else
4366 for (i = 0; i < usercount; i++)
4368 addcnt += usracl_auth(useracl[i], auth);
4370 mylog("addcnt=%d\n", addcnt);
4373 RETCODE SQL_API PGAPI_TablePrivileges(HSTMT hstmt, const SQLCHAR FAR * szTableQualifier, /* OA X */
4374 SQLSMALLINT cbTableQualifier, const SQLCHAR FAR * szTableOwner, /* PV E */
4375 SQLSMALLINT cbTableOwner, const SQLCHAR FAR * szTableName, /* PV E */
4376 SQLSMALLINT cbTableName,
4377 UWORD flag)
4379 StatementClass *stmt = (StatementClass *) hstmt;
4380 CSTR func = "PGAPI_TablePrivileges";
4381 ConnectionClass *conn = SC_get_conn(stmt);
4382 Int2 result_cols;
4383 char proc_query[INFO_INQUIRY_LEN];
4384 QResultClass *res, *wres = NULL, *allures = NULL;
4385 TupleField *tuple;
4386 Int4 tablecount, usercount, i, j, k;
4387 BOOL grpauth, sys, su;
4388 char (*useracl)[ACLMAX] = NULL, *acl, *user, *delim, *auth;
4389 const char *reln, *owner, *priv, *schnm = NULL;
4390 RETCODE result, ret = SQL_SUCCESS;
4391 const char *like_or_eq;
4392 const char *szSchemaName;
4393 SQLSMALLINT cbSchemaName;
4394 char *escSchemaName = NULL, *escTableName = NULL;
4395 BOOL search_pattern;
4397 mylog("%s: entering... scnm=%p len-%d\n", func,
4398 NULL_IF_NULL(szTableOwner), cbTableOwner);
4399 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
4400 return result;
4403 * a statement is actually executed, so we'll have to do this
4404 * ourselves.
4406 result_cols = 7;
4407 extend_column_bindings(SC_get_ARDF(stmt), result_cols);
4409 stmt->catalog_result = TRUE;
4410 /* set the field names */
4411 res = QR_Constructor();
4412 SC_set_Result(stmt, res);
4413 QR_set_num_fields(res, result_cols);
4414 QR_set_field_info_v(res, 0, "TABLE_CAT", PG_TYPE_VARCHAR,
4415 MAX_INFO_STRING);
4416 QR_set_field_info_v(res, 1, "TABLE_SCHEM", PG_TYPE_VARCHAR,
4417 MAX_INFO_STRING);
4418 QR_set_field_info_v(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR,
4419 MAX_INFO_STRING);
4420 QR_set_field_info_v(res, 3, "GRANTOR", PG_TYPE_VARCHAR,
4421 MAX_INFO_STRING);
4422 QR_set_field_info_v(res, 4, "GRANTEE", PG_TYPE_VARCHAR,
4423 MAX_INFO_STRING);
4424 QR_set_field_info_v(res, 5, "PRIVILEGE", PG_TYPE_VARCHAR,
4425 MAX_INFO_STRING);
4426 QR_set_field_info_v(res, 6, "IS_GRANTABLE", PG_TYPE_VARCHAR,
4427 MAX_INFO_STRING);
4430 * also, things need to think that this statement is finished so the
4431 * results can be retrieved.
4433 stmt->status = STMT_FINISHED;
4434 /* set up the current tuple pointer for SQLFetch */
4435 stmt->currTuple = -1;
4436 SC_set_rowset_start(stmt, -1, FALSE);
4437 SC_set_current_col(stmt, -1);
4438 szSchemaName = (const char *)szTableOwner;
4439 cbSchemaName = cbTableOwner;
4441 #define return DONT_CALL_RETURN_FROM_HERE???
4442 search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
4443 if (search_pattern)
4445 like_or_eq = likeop;
4446 escTableName =
4447 adjustLikePattern(szTableName, cbTableName,
4448 SEARCH_PATTERN_ESCAPE, NULL, conn);
4450 else
4452 like_or_eq = eqop;
4453 escTableName =
4454 simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
4457 retry_public_schema:
4458 if (escSchemaName)
4459 free(escSchemaName);
4460 if (search_pattern)
4461 escSchemaName =
4462 adjustLikePattern(szSchemaName, cbSchemaName,
4463 SEARCH_PATTERN_ESCAPE, NULL, conn);
4464 else
4465 escSchemaName =
4466 simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn);
4467 if (conn->schema_support)
4468 strncpy_null(proc_query,
4469 "select relname, usename, relacl, nspname"
4470 " from pg_catalog.pg_namespace, pg_catalog.pg_class ,"
4471 " pg_catalog.pg_user where", sizeof(proc_query));
4472 else
4473 strncpy_null(proc_query, "select relname, usename, relacl"
4474 " from pg_class , pg_user where",
4475 sizeof(proc_query));
4476 if (conn->schema_support)
4478 if (escSchemaName)
4479 schema_strcat1(proc_query, " nspname %s '%.*s' and",
4480 like_or_eq, escSchemaName, SQL_NTS,
4481 (const char *)szTableName, cbTableName, conn);
4483 if (escTableName)
4484 snprintf_add(proc_query, sizeof(proc_query),
4485 " relname %s '%s' and", like_or_eq, escTableName);
4486 if (conn->schema_support)
4488 strcat(proc_query,
4489 " pg_namespace.oid = relnamespace and relkind in ('r', 'v') and");
4490 if ((!escTableName) && (!escSchemaName))
4491 strcat(proc_query,
4492 " nspname not in ('pg_catalog', 'information_schema') and");
4494 strcat(proc_query, " pg_user.usesysid = relowner");
4495 if (wres =
4496 CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN,
4497 stmt), !QR_command_maybe_successful(wres))
4499 SC_set_error(stmt, STMT_EXEC_ERROR,
4500 "PGAPI_TablePrivileges query error", func);
4501 ret = SQL_ERROR;
4502 goto cleanup;
4504 tablecount = (Int4) QR_get_num_cached_tuples(wres);
4505 /* If not found */
4506 if (conn->schema_support &&
4507 (flag & PODBC_SEARCH_PUBLIC_SCHEMA) != 0 && 0 == tablecount)
4509 const char *user = CC_get_username(conn);
4512 * If specified schema name == user_name and
4513 * the current schema is 'public',
4514 * retry the 'public' schema.
4516 if (szSchemaName &&
4517 (cbSchemaName == SQL_NTS ||
4518 cbSchemaName == (SQLSMALLINT) strlen(user)) &&
4519 strnicmp(szSchemaName, user, strlen(user)) == 0 &&
4520 stricmp(CC_get_current_schema(conn), pubstr) == 0)
4522 QR_Destructor(wres);
4523 wres = NULL;
4524 szSchemaName = pubstr;
4525 cbSchemaName = SQL_NTS;
4526 goto retry_public_schema;
4530 strncpy_null(proc_query,
4531 "select usename, usesysid, usesuper from pg_user",
4532 sizeof(proc_query));
4533 if (allures =
4534 CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN,
4535 stmt), !QR_command_maybe_successful(allures))
4537 SC_set_error(stmt, STMT_EXEC_ERROR,
4538 "PGAPI_TablePrivileges query error", func);
4539 ret = SQL_ERROR;
4540 goto cleanup;
4542 usercount = (Int4) QR_get_num_cached_tuples(allures);
4543 useracl =
4544 (char (*)[ACLMAX]) malloc(usercount * sizeof(char[ACLMAX]));
4545 for (i = 0; i < tablecount; i++)
4547 memset(useracl, 0, usercount * sizeof(char[ACLMAX]));
4548 acl = (char *) QR_get_value_backend_text(wres, i, 2);
4549 if (acl && acl[0] == '{')
4550 user = acl + 1;
4551 else
4552 user = NULL;
4553 for (; user && *user;)
4555 grpauth = FALSE;
4556 if (user[0] == '"' && strncmp(user + 1, "group ", 6) == 0)
4558 user += 7;
4559 grpauth = TRUE;
4561 if (delim = strchr(user, '='), !delim)
4562 break;
4563 *delim = '\0';
4564 auth = delim + 1;
4565 if (grpauth)
4567 if (delim = strchr(auth, '"'), delim)
4569 *delim = '\0';
4570 delim++;
4573 else if (delim = strchr(auth, ','), delim)
4574 *delim = '\0';
4575 else if (delim = strchr(auth, '}'), delim)
4576 *delim = '\0';
4577 if (grpauth) /* handle group privilege */
4579 QResultClass *gres;
4580 int i;
4581 char *grolist, *uid, *delm;
4583 snprintf(proc_query, sizeof(proc_query) - 1,
4584 "select grolist from pg_group where groname = '%s'",
4585 user);
4586 if (gres =
4587 CC_send_query(conn, proc_query, NULL,
4588 IGNORE_ABORT_ON_CONN, stmt),
4589 !QR_command_maybe_successful(gres))
4591 grolist = (char *)QR_get_value_backend_text(gres, 0, 0);
4592 if (grolist && grolist[0] == '{')
4594 for (uid = grolist + 1; *uid;)
4596 if (delm = strchr(uid, ','), delm)
4597 *delm = '\0';
4598 else if (delm = strchr(uid, '}'), delm)
4599 *delm = '\0';
4600 mylog("guid=%s\n", uid);
4601 for (i = 0; i < usercount; i++)
4603 if (strcmp
4604 (QR_get_value_backend_text
4605 (allures, i, 1), uid) == 0)
4606 useracl_upd(useracl, allures,
4607 QR_get_value_backend_text
4608 (allures, i, 0), auth);
4610 uid = delm + 1;
4614 QR_Destructor(gres);
4616 else
4617 useracl_upd(useracl, allures, user, auth);
4618 if (!delim)
4619 break;
4620 user = delim + 1;
4622 reln = QR_get_value_backend_text(wres, i, 0);
4623 owner = QR_get_value_backend_text(wres, i, 1);
4624 if (conn->schema_support)
4625 schnm = QR_get_value_backend_text(wres, i, 3);
4626 /* The owner has all privileges */
4627 useracl_upd(useracl, allures, owner, ALL_PRIVILIGES);
4628 for (j = 0; j < usercount; j++)
4630 user = (char *)QR_get_value_backend_text(allures, j, 0);
4631 su = (strcmp(QR_get_value_backend_text(allures, j, 2), "t")
4632 == 0);
4633 sys = (strcmp(user, owner) == 0);
4634 /* Super user has all privileges */
4635 if (su)
4636 useracl_upd(useracl, allures, user, ALL_PRIVILIGES);
4637 for (k = 0; k < ACLMAX; k++)
4639 if (!useracl[j][k])
4640 break;
4641 switch (useracl[j][k])
4643 case 'R': /* rule */
4644 case 't': /* trigger */
4645 continue;
4647 tuple = QR_AddNew(res);
4648 set_tuplefield_string(&tuple[0], CurrCat(conn));
4649 if (conn->schema_support)
4650 set_tuplefield_string(&tuple[1],
4651 GET_SCHEMA_NAME(schnm));
4652 else
4653 set_tuplefield_string(&tuple[1], NULL_STRING);
4654 set_tuplefield_string(&tuple[2], reln);
4655 if (su || sys)
4656 set_tuplefield_string(&tuple[3], "_SYSTEM");
4657 else
4658 set_tuplefield_string(&tuple[3], owner);
4659 mylog("user=%s\n", user);
4660 set_tuplefield_string(&tuple[4], user);
4661 switch (useracl[j][k])
4663 case 'a':
4664 priv = "INSERT";
4665 break;
4666 case 'r':
4667 priv = "SELECT";
4668 break;
4669 case 'w':
4670 priv = "UPDATE";
4671 break;
4672 case 'd':
4673 priv = "DELETE";
4674 break;
4675 case 'x':
4676 priv = "REFERENCES";
4677 break;
4678 default:
4679 priv = NULL_STRING;
4681 set_tuplefield_string(&tuple[5], priv);
4682 /* The owner and the super user are grantable */
4683 if (sys || su)
4684 set_tuplefield_string(&tuple[6], "YES");
4685 else
4686 set_tuplefield_string(&tuple[6], "NO");
4690 cleanup:
4691 #undef return
4692 if (escSchemaName)
4693 free(escSchemaName);
4694 if (escTableName)
4695 free(escTableName);
4696 if (useracl)
4697 free(useracl);
4698 if (wres)
4699 QR_Destructor(wres);
4700 if (allures)
4701 QR_Destructor(allures);
4702 if (stmt->internal)
4703 ret = DiscardStatementSvp(stmt, ret, FALSE);
4704 return ret;