vxodbc: pretend to be SQLSRV32.DLL.
[versaplex.git] / vxodbc / info.cc
blob0c3ff03c1bd65a2848cebb4916b485a5ce237aac
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 = "SQLSRV32.DLL";
236 break;
238 case SQL_DRIVER_ODBC_VER:
239 p = "03.52";
240 break;
242 case SQL_DRIVER_VER: /* ODBC 1.0 */
243 p = "03.85.1132";
244 break;
246 case SQL_EXPRESSIONS_IN_ORDERBY: /* ODBC 1.0 */
247 p = "N";
248 break;
250 case SQL_FETCH_DIRECTION: /* ODBC 1.0 */
251 len = 4;
252 value = (SQL_FD_FETCH_NEXT |
253 SQL_FD_FETCH_NEXT |
254 SQL_FD_FETCH_FIRST |
255 SQL_FD_FETCH_LAST |
256 SQL_FD_FETCH_PRIOR |
257 SQL_FD_FETCH_ABSOLUTE |
258 SQL_FD_FETCH_RELATIVE | SQL_FD_FETCH_BOOKMARK);
259 break;
261 case SQL_FILE_USAGE: /* ODBC 2.0 */
262 len = 2;
263 value = SQL_FILE_NOT_SUPPORTED;
264 break;
266 case SQL_GETDATA_EXTENSIONS: /* ODBC 2.0 */
267 len = 4;
268 value =
269 (SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND |
270 SQL_GD_BLOCK);
271 break;
273 case SQL_GROUP_BY: /* ODBC 2.0 */
274 len = 2;
275 value = SQL_GB_GROUP_BY_EQUALS_SELECT;
276 break;
278 case SQL_IDENTIFIER_CASE: /* ODBC 1.0 */
281 * are identifiers case-sensitive (yes, but only when quoted.
282 * If not quoted, they default to lowercase)
284 len = 2;
285 value = SQL_IC_LOWER;
286 break;
288 case SQL_IDENTIFIER_QUOTE_CHAR: /* ODBC 1.0 */
289 /* the character used to quote "identifiers" */
290 p = PG_VERSION_LE(conn, 6.2) ? " " : "\"";
291 break;
293 case SQL_KEYWORDS: /* ODBC 2.0 */
294 p = NULL_STRING;
295 break;
297 case SQL_LIKE_ESCAPE_CLAUSE: /* ODBC 2.0 */
300 * is there a character that escapes '%' and '_' in a LIKE
301 * clause? not as far as I can tell
303 p = "N";
304 break;
306 case SQL_LOCK_TYPES: /* ODBC 2.0 */
307 len = 4;
308 value = SQL_LCK_NO_CHANGE;
309 break;
311 case SQL_MAX_BINARY_LITERAL_LEN: /* ODBC 2.0 */
312 len = 4;
313 value = 0;
314 break;
316 case SQL_MAX_CHAR_LITERAL_LEN: /* ODBC 2.0 */
317 len = 4;
318 value = 0;
319 break;
321 case SQL_MAX_COLUMNS_IN_GROUP_BY: /* ODBC 2.0 */
322 len = 2;
323 value = 0;
324 break;
326 case SQL_MAX_COLUMNS_IN_INDEX: /* ODBC 2.0 */
327 len = 2;
328 value = 0;
329 break;
331 case SQL_MAX_COLUMNS_IN_ORDER_BY: /* ODBC 2.0 */
332 len = 2;
333 value = 0;
334 break;
336 case SQL_MAX_COLUMNS_IN_SELECT: /* ODBC 2.0 */
337 len = 2;
338 value = 0;
339 break;
341 case SQL_MAX_COLUMNS_IN_TABLE: /* ODBC 2.0 */
342 len = 2;
343 value = 0;
344 break;
346 case SQL_MAX_CURSOR_NAME_LEN: /* ODBC 1.0 */
347 len = 2;
348 value = MAX_CURSOR_LEN;
349 break;
351 case SQL_MAX_SCHEMA_NAME_LEN:
352 case SQL_MAX_TABLE_NAME_LEN:
353 case SQL_MAX_COLUMN_NAME_LEN:
354 len = 2;
355 value = 128;
356 break;
358 case SQL_MAX_INDEX_SIZE: /* ODBC 2.0 */
359 len = 4;
360 value = 0;
361 break;
363 case SQL_MAX_PROCEDURE_NAME_LEN: /* ODBC 1.0 */
364 len = 2;
365 value = 0;
366 break;
368 case SQL_MAX_QUALIFIER_NAME_LEN: /* ODBC 1.0 */
369 len = 2;
370 value = 0;
371 break;
373 case SQL_MAX_ROW_SIZE: /* ODBC 2.0 */
374 len = 4;
375 if (PG_VERSION_GE(conn, 7.1))
377 /* Large Rowa in 7.1+ */
378 value = MAX_ROW_SIZE;
380 else
382 /* Without the Toaster we're limited to the blocksize */
383 value = BLCKSZ;
385 break;
387 case SQL_MAX_ROW_SIZE_INCLUDES_LONG: /* ODBC 2.0 */
390 * does the preceding value include LONGVARCHAR and
391 * LONGVARBINARY fields? Well, it does include longvarchar,
392 * but not longvarbinary.
394 p = "Y";
395 break;
397 case SQL_MAX_STATEMENT_LEN: /* ODBC 2.0 */
398 /* maybe this should be 0? */
399 len = 4;
400 value = CC_get_max_query_len(conn);
401 break;
403 case SQL_MAX_TABLES_IN_SELECT: /* ODBC 2.0 */
404 len = 2;
405 value = 0;
406 break;
408 case SQL_MAX_USER_NAME_LEN:
409 len = 2;
410 value = 0;
411 break;
413 case SQL_MULT_RESULT_SETS: /* ODBC 1.0 */
414 /* Don't support multiple result sets but say yes anyway? */
415 p = "Y";
416 break;
418 case SQL_MULTIPLE_ACTIVE_TXN: /* ODBC 1.0 */
419 p = "Y";
420 break;
422 case SQL_NEED_LONG_DATA_LEN: /* ODBC 2.0 */
425 * Don't need the length, SQLPutData can handle any size and
426 * multiple calls
428 p = "N";
429 break;
431 case SQL_NON_NULLABLE_COLUMNS: /* ODBC 1.0 */
432 len = 2;
433 value = SQL_NNC_NON_NULL;
434 break;
436 case SQL_NULL_COLLATION: /* ODBC 2.0 */
437 /* where are nulls sorted? */
438 len = 2;
439 if (PG_VERSION_GE(conn, 7.2))
440 value = SQL_NC_HIGH;
441 else
442 value = SQL_NC_END;
443 break;
445 case SQL_NUMERIC_FUNCTIONS: /* ODBC 1.0 */
446 len = 4;
447 value = 0;
448 break;
450 case SQL_ODBC_API_CONFORMANCE: /* ODBC 1.0 */
451 len = 2;
452 value = SQL_OAC_LEVEL1;
453 break;
455 case SQL_ODBC_SAG_CLI_CONFORMANCE: /* ODBC 1.0 */
456 len = 2;
457 value = SQL_OSCC_NOT_COMPLIANT;
458 break;
460 case SQL_ODBC_SQL_CONFORMANCE: /* ODBC 1.0 */
461 len = 2;
462 value = SQL_OSC_CORE;
463 break;
465 case SQL_ODBC_SQL_OPT_IEF: /* ODBC 1.0 */
466 p = "N";
467 break;
469 case SQL_OJ_CAPABILITIES: /* ODBC 2.01 */
470 len = 4;
471 if (PG_VERSION_GE(conn, 7.1))
473 /* OJs in 7.1+ */
474 value = (SQL_OJ_LEFT |
475 SQL_OJ_RIGHT |
476 SQL_OJ_FULL |
477 SQL_OJ_NESTED |
478 SQL_OJ_NOT_ORDERED |
479 SQL_OJ_INNER | SQL_OJ_ALL_COMPARISON_OPS);
481 else
482 /* OJs not in <7.1 */
483 value = 0;
484 break;
486 case SQL_ORDER_BY_COLUMNS_IN_SELECT: /* ODBC 2.0 */
487 p = (PG_VERSION_LE(conn, 6.3)) ? "Y" : "N";
488 break;
490 case SQL_OUTER_JOINS: /* ODBC 1.0 */
491 if (PG_VERSION_GE(conn, 7.1))
492 /* OJs in 7.1+ */
493 p = "Y";
494 else
495 /* OJs not in <7.1 */
496 p = "N";
497 break;
499 case SQL_OWNER_TERM: /* ODBC 1.0 */
500 if (conn->schema_support)
501 p = "schema";
502 else
503 p = "owner";
504 break;
506 case SQL_OWNER_USAGE: /* ODBC 2.0 */
507 len = 4;
508 value = 0;
509 if (conn->schema_support)
510 value = SQL_OU_DML_STATEMENTS
511 | SQL_OU_TABLE_DEFINITION
512 | SQL_OU_INDEX_DEFINITION | SQL_OU_PRIVILEGE_DEFINITION;
513 break;
515 case SQL_POS_OPERATIONS: /* ODBC 2.0 */
516 len = 4;
517 value = (SQL_POS_POSITION | SQL_POS_REFRESH);
518 if (0 != ci->updatable_cursors)
519 value |= (SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD);
520 break;
522 case SQL_POSITIONED_STATEMENTS: /* ODBC 2.0 */
523 len = 4;
524 value = 0;
525 break;
527 case SQL_PROCEDURE_TERM: /* ODBC 1.0 */
528 p = "procedure";
529 break;
531 case SQL_PROCEDURES: /* ODBC 1.0 */
532 p = "Y";
533 break;
535 case SQL_QUALIFIER_LOCATION: /* ODBC 2.0 */
536 len = 2;
537 if (CurrCat(conn))
538 value = SQL_QL_START;
539 else
540 value = 0;
541 break;
543 case SQL_QUALIFIER_NAME_SEPARATOR: /* ODBC 1.0 */
544 if (CurrCat(conn))
545 p = ".";
546 else
547 p = NULL_STRING;
548 break;
550 case SQL_QUALIFIER_TERM: /* ODBC 1.0 */
551 if (CurrCat(conn))
552 p = "catalog";
553 else
554 p = NULL_STRING;
555 break;
557 case SQL_QUALIFIER_USAGE: /* ODBC 2.0 */
558 len = 4;
559 if (CurrCat(conn))
560 value = SQL_CU_DML_STATEMENTS;
561 else
562 value = 0;
563 break;
565 case SQL_QUOTED_IDENTIFIER_CASE: /* ODBC 2.0 */
566 /* are "quoted" identifiers case-sensitive? YES! */
567 len = 2;
568 value = SQL_IC_SENSITIVE;
569 break;
571 case SQL_ROW_UPDATES: /* ODBC 1.0 */
574 * Driver doesn't support keyset-driven or mixed cursors, so
575 * not much point in saying row updates are supported
577 p = (0 != ci->updatable_cursors) ? "Y" : "N";
578 break;
580 case SQL_SCROLL_CONCURRENCY: /* ODBC 1.0 */
581 len = 4;
582 value = SQL_SCCO_READ_ONLY;
583 if (0 != ci->updatable_cursors)
584 value |= SQL_SCCO_OPT_ROWVER;
585 break;
587 case SQL_SCROLL_OPTIONS: /* ODBC 1.0 */
588 len = 4;
589 value = SQL_SO_FORWARD_ONLY | SQL_SO_STATIC;
590 if (0 != (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
591 value |= SQL_SO_KEYSET_DRIVEN;
592 break;
594 case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */
595 if (PG_VERSION_GE(conn, 6.5))
596 p = "\\";
597 else
598 p = NULL_STRING;
599 break;
601 case SQL_SERVER_NAME: /* ODBC 1.0 */
602 p = CC_get_server(conn);
603 break;
605 case SQL_SPECIAL_CHARACTERS: /* ODBC 2.0 */
606 p = "_";
607 break;
609 case SQL_STATIC_SENSITIVITY: /* ODBC 2.0 */
610 len = 4;
611 value = 0;
612 if (0 != ci->updatable_cursors)
613 value |=
614 (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES);
615 break;
617 case SQL_STRING_FUNCTIONS: /* ODBC 1.0 */
618 len = 4;
619 value = (SQL_FN_STR_CONCAT |
620 SQL_FN_STR_LCASE |
621 SQL_FN_STR_LENGTH |
622 SQL_FN_STR_LOCATE |
623 SQL_FN_STR_LTRIM |
624 SQL_FN_STR_RTRIM |
625 SQL_FN_STR_SUBSTRING | SQL_FN_STR_UCASE);
626 break;
628 case SQL_SUBQUERIES: /* ODBC 2.0 */
629 /* postgres 6.3 supports subqueries */
630 len = 4;
631 value = (SQL_SQ_QUANTIFIED |
632 SQL_SQ_IN | SQL_SQ_EXISTS | SQL_SQ_COMPARISON);
633 break;
635 case SQL_SYSTEM_FUNCTIONS: /* ODBC 1.0 */
636 len = 4;
637 value = 0;
638 break;
640 case SQL_TABLE_TERM: /* ODBC 1.0 */
641 p = "table";
642 break;
644 case SQL_TIMEDATE_ADD_INTERVALS: /* ODBC 2.0 */
645 len = 4;
646 value = 0;
647 break;
649 case SQL_TIMEDATE_DIFF_INTERVALS: /* ODBC 2.0 */
650 len = 4;
651 value = 0;
652 break;
654 case SQL_TIMEDATE_FUNCTIONS: /* ODBC 1.0 */
655 len = 4;
656 value = (SQL_FN_TD_NOW);
657 break;
659 case SQL_TXN_CAPABLE: /* ODBC 1.0 */
662 * Postgres can deal with create or drop table statements in a
663 * transaction
665 len = 2;
666 value = SQL_TC_ALL;
667 break;
669 case SQL_TXN_ISOLATION_OPTION: /* ODBC 1.0 */
670 len = 4;
671 if (PG_VERSION_LT(conn, 6.5))
672 value = SQL_TXN_SERIALIZABLE;
673 else if (PG_VERSION_GE(conn, 7.1))
674 value = SQL_TXN_READ_COMMITTED | SQL_TXN_SERIALIZABLE;
675 else
676 value = SQL_TXN_READ_COMMITTED;
677 break;
679 case SQL_UNION: /* ODBC 2.0 */
680 /* unions with all supported in postgres 6.3 */
681 len = 4;
682 value = (SQL_U_UNION | SQL_U_UNION_ALL);
683 break;
685 case SQL_USER_NAME: /* ODBC 1.0 */
686 p = CC_get_username(conn);
687 break;
689 default:
690 /* unrecognized key */
691 CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR,
692 "Unrecognized key passed to PGAPI_GetInfo.", NULL);
693 return SQL_ERROR;
696 result = SQL_SUCCESS;
698 mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func,
699 p ? p : "<NULL>", len, value, cbInfoValueMax);
702 * NOTE, that if rgbInfoValue is NULL, then no warnings or errors
703 * should result and just pcbInfoValue is returned, which indicates
704 * what length would be required if a real buffer had been passed in.
706 if (p)
708 /* char/binary data */
709 len = strlen(p);
711 if (rgbInfoValue)
713 if (CC_is_in_unicode_driver(conn))
715 len =
716 utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue,
717 cbInfoValueMax / WCLEN);
718 len *= WCLEN;
720 else
721 strncpy_null((char *) rgbInfoValue, p,
722 (size_t) cbInfoValueMax);
724 if (len >= cbInfoValueMax)
726 result = SQL_SUCCESS_WITH_INFO;
727 CC_set_error(conn, CONN_TRUNCATED,
728 "The buffer was too small for the InfoValue.",
729 func);
732 #ifdef UNICODE_SUPPORT
733 else if (CC_is_in_unicode_driver(conn))
734 len *= WCLEN;
735 #endif /* UNICODE_SUPPORT */
737 else
739 /* numeric data */
740 if (rgbInfoValue)
742 if (len == sizeof(SQLSMALLINT))
743 *((SQLUSMALLINT *) rgbInfoValue) = (SQLUSMALLINT) value;
744 else if (len == sizeof(SQLINTEGER))
745 *((SQLUINTEGER *) rgbInfoValue) = (SQLUINTEGER) value;
749 if (pcbInfoValue)
750 *pcbInfoValue = (SQLSMALLINT) len;
752 return result;
755 RETCODE SQL_API PGAPI_GetTypeInfo(HSTMT hstmt, SQLSMALLINT fSqlType)
757 CSTR func = "PGAPI_GetTypeInfo";
758 StatementClass *stmt = (StatementClass *) hstmt;
759 ConnectionClass *conn;
760 QResultClass *res;
761 TupleField *tuple;
762 int i, result_cols;
764 /* Int4 type; */
765 Int4 pgType;
766 Int2 sqlType;
767 RETCODE result = SQL_SUCCESS;
769 mylog("%s: entering...fSqlType = %d\n", func, fSqlType);
771 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
772 return result;
774 conn = SC_get_conn(stmt);
775 if (res = QR_Constructor(), !res)
777 SC_set_error(stmt, STMT_INTERNAL_ERROR,
778 "Error creating result.", func);
779 return SQL_ERROR;
781 SC_set_Result(stmt, res);
783 #define return DONT_CALL_RETURN_FROM_HERE???
784 result_cols = 19;
785 extend_column_bindings(SC_get_ARDF(stmt), result_cols);
787 stmt->catalog_result = TRUE;
788 QR_set_num_fields(res, result_cols);
789 QR_set_field_info_v(res, 0, "TYPE_NAME", PG_TYPE_VARCHAR,
790 MAX_INFO_STRING);
791 QR_set_field_info_v(res, 1, "DATA_TYPE", PG_TYPE_INT2, 2);
792 QR_set_field_info_v(res, 2, "PRECISION", PG_TYPE_INT4, 4);
793 QR_set_field_info_v(res, 3, "LITERAL_PREFIX", PG_TYPE_VARCHAR,
794 MAX_INFO_STRING);
795 QR_set_field_info_v(res, 4, "LITERAL_SUFFIX", PG_TYPE_VARCHAR,
796 MAX_INFO_STRING);
797 QR_set_field_info_v(res, 5, "CREATE_PARAMS", PG_TYPE_VARCHAR,
798 MAX_INFO_STRING);
799 QR_set_field_info_v(res, 6, "NULLABLE", PG_TYPE_INT2, 2);
800 QR_set_field_info_v(res, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2);
801 QR_set_field_info_v(res, 8, "SEARCHABLE", PG_TYPE_INT2, 2);
802 QR_set_field_info_v(res, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2);
803 QR_set_field_info_v(res, 10, "MONEY", PG_TYPE_INT2, 2);
804 QR_set_field_info_v(res, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2);
805 QR_set_field_info_v(res, 12, "LOCAL_TYPE_NAME", PG_TYPE_VARCHAR,
806 MAX_INFO_STRING);
807 QR_set_field_info_v(res, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
808 QR_set_field_info_v(res, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
809 QR_set_field_info_v(res, 15, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
810 QR_set_field_info_v(res, 16, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
811 QR_set_field_info_v(res, 17, "NUM_PREC_RADIX", PG_TYPE_INT4, 4);
812 QR_set_field_info_v(res, 18, "INTERVAL_PRECISION", PG_TYPE_INT2, 2);
814 for (i = 0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i])
816 pgType = sqltype_to_pgtype(stmt, sqlType);
818 if (sqlType == SQL_LONGVARBINARY)
820 ConnInfo *ci = &(conn->connInfo);
821 inolog("%d sqltype=%d -> pgtype=%d\n",
822 ci->bytea_as_longvarbinary, sqlType, pgType);
825 if (fSqlType == SQL_ALL_TYPES || fSqlType == sqlType)
827 int pgtcount = 1, aunq_match = -1, cnt;
829 /*if (SQL_INTEGER == sqlType || SQL_TINYINT == sqlType) */
830 if (SQL_INTEGER == sqlType)
832 mylog("sqlType=%d ms_jet=%d\n", sqlType, conn->ms_jet);
833 if (conn->ms_jet && PG_VERSION_GE(conn, 6.4))
835 aunq_match = 1;
836 pgtcount = 2;
838 mylog("aunq_match=%d pgtcount=%d\n", aunq_match,
839 pgtcount);
841 for (cnt = 0; cnt < pgtcount; cnt++)
843 tuple = QR_AddNew(res);
845 /* These values can't be NULL */
846 if (aunq_match == cnt)
848 set_tuplefield_string(&tuple[0],
849 pgtype_to_name(stmt, pgType,
850 TRUE));
851 set_tuplefield_int2(&tuple[6], SQL_NO_NULLS);
852 inolog("serial in\n");
854 else
856 set_tuplefield_string(&tuple[0],
857 pgtype_to_name(stmt, pgType,
858 FALSE));
859 set_tuplefield_int2(&tuple[6],
860 pgtype_nullable(stmt, pgType));
862 set_tuplefield_int2(&tuple[1], (Int2) sqlType);
863 set_tuplefield_int2(&tuple[7],
864 pgtype_case_sensitive(stmt,
865 pgType));
866 set_tuplefield_int2(&tuple[8],
867 pgtype_searchable(stmt, pgType));
868 set_tuplefield_int2(&tuple[10],
869 pgtype_money(stmt, pgType));
872 * Localized data-source dependent data type name (always
873 * NULL)
875 set_tuplefield_null(&tuple[12]);
877 /* These values can be NULL */
878 set_nullfield_int4(&tuple[2],
879 pgtype_column_size(stmt, pgType,
880 PG_STATIC,
881 PG_STATIC));
882 set_nullfield_string(&tuple[3],
883 pgtype_literal_prefix(stmt,
884 pgType));
885 set_nullfield_string(&tuple[4],
886 pgtype_literal_suffix(stmt,
887 pgType));
888 set_nullfield_string(&tuple[5],
889 pgtype_create_params(stmt,
890 pgType));
891 if (1 < pgtcount)
892 set_tuplefield_int2(&tuple[9], SQL_TRUE);
893 else
894 set_nullfield_int2(&tuple[9],
895 pgtype_unsigned(stmt, pgType));
896 if (aunq_match == cnt)
897 set_tuplefield_int2(&tuple[11], SQL_TRUE);
898 else
899 set_nullfield_int2(&tuple[11],
900 pgtype_auto_increment(stmt,
901 pgType));
902 set_nullfield_int2(&tuple[13],
903 pgtype_min_decimal_digits(stmt,
904 pgType));
905 set_nullfield_int2(&tuple[14],
906 pgtype_max_decimal_digits(stmt,
907 pgType));
908 set_nullfield_int2(&tuple[15],
909 pgtype_to_sqldesctype(stmt, pgType,
910 PG_STATIC));
911 set_nullfield_int2(&tuple[16],
912 pgtype_to_datetime_sub(stmt,
913 pgType));
914 set_nullfield_int4(&tuple[17],
915 pgtype_radix(stmt, pgType));
916 set_nullfield_int4(&tuple[18], 0);
921 #undef return
923 * also, things need to think that this statement is finished so the
924 * results can be retrieved.
926 stmt->status = STMT_FINISHED;
927 stmt->currTuple = -1;
928 SC_set_rowset_start(stmt, -1, FALSE);
929 SC_set_current_col(stmt, -1);
931 if (stmt->internal)
932 result = DiscardStatementSvp(stmt, result, FALSE);
933 return result;
936 RETCODE SQL_API
937 PGAPI_GetFunctions(HDBC hdbc,
938 SQLUSMALLINT fFunction, SQLUSMALLINT FAR * pfExists)
940 CSTR func = "PGAPI_GetFunctions";
941 ConnectionClass *conn = (ConnectionClass *) hdbc;
942 ConnInfo *ci = &(conn->connInfo);
944 mylog("%s: entering...%u\n", func, fFunction);
946 if (fFunction == SQL_API_ALL_FUNCTIONS)
949 memset(pfExists, 0, sizeof(pfExists[0]) * 100);
951 /* ODBC core functions */
952 pfExists[SQL_API_SQLALLOCCONNECT] = TRUE;
953 pfExists[SQL_API_SQLALLOCENV] = TRUE;
954 pfExists[SQL_API_SQLALLOCSTMT] = TRUE;
955 pfExists[SQL_API_SQLBINDCOL] = TRUE;
956 pfExists[SQL_API_SQLCANCEL] = TRUE;
957 pfExists[SQL_API_SQLCOLATTRIBUTES] = TRUE;
958 pfExists[SQL_API_SQLCONNECT] = TRUE;
959 pfExists[SQL_API_SQLDESCRIBECOL] = TRUE; /* partial */
960 pfExists[SQL_API_SQLDISCONNECT] = TRUE;
961 pfExists[SQL_API_SQLERROR] = TRUE;
962 pfExists[SQL_API_SQLEXECDIRECT] = TRUE;
963 pfExists[SQL_API_SQLEXECUTE] = TRUE;
964 pfExists[SQL_API_SQLFETCH] = TRUE;
965 pfExists[SQL_API_SQLFREECONNECT] = TRUE;
966 pfExists[SQL_API_SQLFREEENV] = TRUE;
967 pfExists[SQL_API_SQLFREESTMT] = TRUE;
968 pfExists[SQL_API_SQLGETCURSORNAME] = TRUE;
969 pfExists[SQL_API_SQLNUMRESULTCOLS] = TRUE;
970 pfExists[SQL_API_SQLPREPARE] = TRUE; /* complete? */
971 pfExists[SQL_API_SQLROWCOUNT] = TRUE;
972 pfExists[SQL_API_SQLSETCURSORNAME] = TRUE;
973 pfExists[SQL_API_SQLSETPARAM] = FALSE; /* odbc 1.0 */
974 pfExists[SQL_API_SQLTRANSACT] = TRUE;
976 /* ODBC level 1 functions */
977 pfExists[SQL_API_SQLBINDPARAMETER] = TRUE;
978 pfExists[SQL_API_SQLCOLUMNS] = TRUE;
979 pfExists[SQL_API_SQLDRIVERCONNECT] = TRUE;
980 pfExists[SQL_API_SQLGETCONNECTOPTION] = TRUE; /* partial */
981 pfExists[SQL_API_SQLGETDATA] = TRUE;
982 pfExists[SQL_API_SQLGETFUNCTIONS] = TRUE;
983 pfExists[SQL_API_SQLGETINFO] = TRUE;
984 pfExists[SQL_API_SQLGETSTMTOPTION] = TRUE; /* partial */
985 pfExists[SQL_API_SQLGETTYPEINFO] = TRUE;
986 pfExists[SQL_API_SQLPARAMDATA] = TRUE;
987 pfExists[SQL_API_SQLPUTDATA] = TRUE;
988 pfExists[SQL_API_SQLSETCONNECTOPTION] = TRUE; /* partial */
989 pfExists[SQL_API_SQLSETSTMTOPTION] = TRUE;
990 pfExists[SQL_API_SQLSPECIALCOLUMNS] = TRUE;
991 pfExists[SQL_API_SQLSTATISTICS] = TRUE;
992 pfExists[SQL_API_SQLTABLES] = TRUE;
994 /* ODBC level 2 functions */
995 pfExists[SQL_API_SQLBROWSECONNECT] = FALSE;
996 if (PG_VERSION_GE(conn, 7.4))
997 pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
998 else
999 pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
1000 pfExists[SQL_API_SQLDATASOURCES] = FALSE; /* only implemented by
1001 * DM */
1002 if (SUPPORT_DESCRIBE_PARAM(ci))
1003 pfExists[SQL_API_SQLDESCRIBEPARAM] = TRUE;
1004 else
1005 pfExists[SQL_API_SQLDESCRIBEPARAM] = FALSE; /* not properly
1006 * implemented */
1007 pfExists[SQL_API_SQLDRIVERS] = FALSE; /* only implemented by
1008 * DM */
1009 pfExists[SQL_API_SQLEXTENDEDFETCH] = TRUE;
1010 pfExists[SQL_API_SQLFOREIGNKEYS] = TRUE;
1011 pfExists[SQL_API_SQLMORERESULTS] = TRUE;
1012 pfExists[SQL_API_SQLNATIVESQL] = TRUE;
1013 pfExists[SQL_API_SQLNUMPARAMS] = TRUE;
1014 pfExists[SQL_API_SQLPARAMOPTIONS] = TRUE;
1015 pfExists[SQL_API_SQLPRIMARYKEYS] = TRUE;
1016 if (PG_VERSION_LT(conn, 6.5))
1017 pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE;
1018 else
1019 pfExists[SQL_API_SQLPROCEDURECOLUMNS] = TRUE;
1020 if (PG_VERSION_LT(conn, 6.5))
1021 pfExists[SQL_API_SQLPROCEDURES] = FALSE;
1022 else
1023 pfExists[SQL_API_SQLPROCEDURES] = TRUE;
1024 pfExists[SQL_API_SQLSETPOS] = TRUE;
1025 pfExists[SQL_API_SQLSETSCROLLOPTIONS] = TRUE; /* odbc 1.0 */
1026 pfExists[SQL_API_SQLTABLEPRIVILEGES] = TRUE;
1027 if (0 == ci->updatable_cursors)
1028 pfExists[SQL_API_SQLBULKOPERATIONS] = FALSE;
1029 else
1030 pfExists[SQL_API_SQLBULKOPERATIONS] = TRUE;
1033 else
1035 switch (fFunction)
1037 case SQL_API_SQLBINDCOL:
1038 *pfExists = TRUE;
1039 break;
1040 case SQL_API_SQLCANCEL:
1041 *pfExists = TRUE;
1042 break;
1043 case SQL_API_SQLCOLATTRIBUTE:
1044 *pfExists = TRUE;
1045 break;
1046 case SQL_API_SQLCONNECT:
1047 *pfExists = TRUE;
1048 break;
1049 case SQL_API_SQLDESCRIBECOL:
1050 *pfExists = TRUE;
1051 break; /* partial */
1052 case SQL_API_SQLDISCONNECT:
1053 *pfExists = TRUE;
1054 break;
1055 case SQL_API_SQLEXECDIRECT:
1056 *pfExists = TRUE;
1057 break;
1058 case SQL_API_SQLEXECUTE:
1059 *pfExists = TRUE;
1060 break;
1061 case SQL_API_SQLFETCH:
1062 *pfExists = TRUE;
1063 break;
1064 case SQL_API_SQLFREESTMT:
1065 *pfExists = TRUE;
1066 break;
1067 case SQL_API_SQLGETCURSORNAME:
1068 *pfExists = TRUE;
1069 break;
1070 case SQL_API_SQLNUMRESULTCOLS:
1071 *pfExists = TRUE;
1072 break;
1073 case SQL_API_SQLPREPARE:
1074 *pfExists = TRUE;
1075 break;
1076 case SQL_API_SQLROWCOUNT:
1077 *pfExists = TRUE;
1078 break;
1079 case SQL_API_SQLSETCURSORNAME:
1080 *pfExists = TRUE;
1081 break;
1083 /* ODBC level 1 functions */
1084 case SQL_API_SQLBINDPARAMETER:
1085 *pfExists = TRUE;
1086 break;
1087 case SQL_API_SQLCOLUMNS:
1088 *pfExists = TRUE;
1089 break;
1090 case SQL_API_SQLDRIVERCONNECT:
1091 *pfExists = TRUE;
1092 break;
1093 case SQL_API_SQLGETDATA:
1094 *pfExists = TRUE;
1095 break;
1096 case SQL_API_SQLGETFUNCTIONS:
1097 *pfExists = TRUE;
1098 break;
1099 case SQL_API_SQLGETINFO:
1100 *pfExists = TRUE;
1101 break;
1102 case SQL_API_SQLGETTYPEINFO:
1103 *pfExists = TRUE;
1104 break;
1105 case SQL_API_SQLPARAMDATA:
1106 *pfExists = TRUE;
1107 break;
1108 case SQL_API_SQLPUTDATA:
1109 *pfExists = TRUE;
1110 break;
1111 case SQL_API_SQLSPECIALCOLUMNS:
1112 *pfExists = TRUE;
1113 break;
1114 case SQL_API_SQLSTATISTICS:
1115 *pfExists = TRUE;
1116 break;
1117 case SQL_API_SQLTABLES:
1118 *pfExists = TRUE;
1119 break;
1121 /* ODBC level 2 functions */
1122 case SQL_API_SQLBROWSECONNECT:
1123 *pfExists = FALSE;
1124 break;
1125 case SQL_API_SQLCOLUMNPRIVILEGES:
1126 *pfExists = FALSE;
1127 break;
1128 case SQL_API_SQLDATASOURCES:
1129 *pfExists = FALSE;
1130 break; /* only implemented by DM */
1131 case SQL_API_SQLDESCRIBEPARAM:
1132 if (SUPPORT_DESCRIBE_PARAM(ci))
1133 *pfExists = TRUE;
1134 else
1135 *pfExists = FALSE;
1136 break; /* not properly implemented */
1137 case SQL_API_SQLDRIVERS:
1138 *pfExists = FALSE;
1139 break; /* only implemented by DM */
1140 case SQL_API_SQLEXTENDEDFETCH:
1141 *pfExists = TRUE;
1142 break;
1143 case SQL_API_SQLFOREIGNKEYS:
1144 *pfExists = TRUE;
1145 break;
1146 case SQL_API_SQLMORERESULTS:
1147 *pfExists = TRUE;
1148 break;
1149 case SQL_API_SQLNATIVESQL:
1150 *pfExists = TRUE;
1151 break;
1152 case SQL_API_SQLNUMPARAMS:
1153 *pfExists = TRUE;
1154 break;
1155 case SQL_API_SQLPRIMARYKEYS:
1156 *pfExists = TRUE;
1157 break;
1158 case SQL_API_SQLPROCEDURECOLUMNS:
1159 if (PG_VERSION_LT(conn, 6.5))
1160 *pfExists = FALSE;
1161 else
1162 *pfExists = TRUE;
1163 break;
1164 case SQL_API_SQLPROCEDURES:
1165 if (PG_VERSION_LT(conn, 6.5))
1166 *pfExists = FALSE;
1167 else
1168 *pfExists = TRUE;
1169 break;
1170 case SQL_API_SQLSETPOS:
1171 *pfExists = TRUE;
1172 break;
1173 case SQL_API_SQLTABLEPRIVILEGES:
1174 *pfExists = TRUE;
1175 break;
1176 case SQL_API_SQLBULKOPERATIONS: /* 24 */
1177 case SQL_API_SQLALLOCHANDLE: /* 1001 */
1178 case SQL_API_SQLBINDPARAM: /* 1002 */
1179 case SQL_API_SQLCLOSECURSOR: /* 1003 */
1180 case SQL_API_SQLENDTRAN: /* 1005 */
1181 case SQL_API_SQLFETCHSCROLL: /* 1021 */
1182 case SQL_API_SQLFREEHANDLE: /* 1006 */
1183 case SQL_API_SQLGETCONNECTATTR: /* 1007 */
1184 case SQL_API_SQLGETDESCFIELD: /* 1008 */
1185 case SQL_API_SQLGETDIAGFIELD: /* 1010 */
1186 case SQL_API_SQLGETDIAGREC: /* 1011 */
1187 case SQL_API_SQLGETENVATTR: /* 1012 */
1188 case SQL_API_SQLGETSTMTATTR: /* 1014 */
1189 case SQL_API_SQLSETCONNECTATTR: /* 1016 */
1190 case SQL_API_SQLSETDESCFIELD: /* 1017 */
1191 case SQL_API_SQLSETENVATTR: /* 1019 */
1192 case SQL_API_SQLSETSTMTATTR: /* 1020 */
1193 *pfExists = TRUE;
1194 break;
1195 case SQL_API_SQLGETDESCREC: /* 1009 */
1196 case SQL_API_SQLSETDESCREC: /* 1018 */
1197 case SQL_API_SQLCOPYDESC: /* 1004 */
1198 *pfExists = FALSE;
1199 break;
1200 default:
1201 *pfExists = FALSE;
1202 break;
1205 return SQL_SUCCESS;
1208 static char *simpleCatalogEscape(const void *_src, int srclen,
1209 int *result_len,
1210 const ConnectionClass * conn)
1212 int i, outlen;
1213 const char *src = (const char *)_src, *in;
1214 char *dest = NULL, escape_ch = CC_get_escape(conn);
1215 encoded_str encstr;
1217 if (result_len)
1218 *result_len = 0;
1219 if (!src || srclen == SQL_NULL_DATA)
1220 return dest;
1221 else if (srclen == SQL_NTS)
1222 srclen = (int) strlen(src);
1223 if (srclen <= 0)
1224 return dest;
1225 mylog("simple in=%s(%d)\n", src, srclen);
1226 encoded_str_constr(&encstr, conn->ccsc, src);
1227 dest = (char *)malloc(2 * srclen + 1);
1228 for (i = 0, in = src, outlen = 0; i < srclen; i++, in++)
1230 encoded_nextchar(&encstr);
1231 if (ENCODE_STATUS(encstr) != 0)
1233 dest[outlen++] = *in;
1234 continue;
1236 if (LITERAL_QUOTE == *in || escape_ch == *in)
1237 dest[outlen++] = *in;
1238 dest[outlen++] = *in;
1240 dest[outlen] = '\0';
1241 if (result_len)
1242 *result_len = outlen;
1243 mylog("simple output=%s(%d)\n", dest, outlen);
1244 return dest;
1248 * PostgreSQL needs 2 '\\' to escape '_' and '%'.
1250 static char *adjustLikePattern(const void *_src, int srclen,
1251 char escape_ch, int *result_len,
1252 const ConnectionClass * conn)
1254 int i, outlen;
1255 const char *src = (const char *)_src, *in;
1256 char *dest = NULL, escape_in_literal = CC_get_escape(conn);
1257 BOOL escape_in = FALSE;
1258 encoded_str encstr;
1260 if (result_len)
1261 *result_len = 0;
1262 if (!src || srclen == SQL_NULL_DATA)
1263 return dest;
1264 else if (srclen == SQL_NTS)
1265 srclen = (int) strlen(src);
1266 /* if (srclen <= 0) */
1267 if (srclen < 0)
1268 return dest;
1269 mylog("adjust in=%s(%d)\n", src, srclen);
1270 encoded_str_constr(&encstr, conn->ccsc, src);
1271 dest = (char *)malloc(2 * srclen + 1);
1272 for (i = 0, in = src, outlen = 0; i < srclen; i++, in++)
1274 encoded_nextchar(&encstr);
1275 if (ENCODE_STATUS(encstr) != 0)
1277 dest[outlen++] = *in;
1278 continue;
1280 if (escape_in)
1282 switch (*in)
1284 case '%':
1285 case '_':
1286 if (escape_ch == escape_in_literal)
1287 dest[outlen++] = escape_in_literal; /* and insert 1 more LEXER escape */
1288 dest[outlen++] = escape_ch;
1289 break;
1290 default:
1291 if (escape_ch == escape_in_literal)
1292 dest[outlen++] = escape_in_literal;
1293 dest[outlen++] = escape_ch;
1294 if (escape_ch == escape_in_literal)
1295 dest[outlen++] = escape_in_literal;
1296 dest[outlen++] = escape_ch;
1297 break;
1300 if (*in == escape_ch)
1301 escape_in = TRUE;
1302 else
1304 escape_in = FALSE;
1305 if (LITERAL_QUOTE == *in)
1306 dest[outlen++] = *in;
1307 dest[outlen++] = *in;
1310 dest[outlen] = '\0';
1311 if (result_len)
1312 *result_len = outlen;
1313 mylog("adjust output=%s(%d)\n", dest, outlen);
1314 return dest;
1319 * FIXME: we always return all tables, not parsing for wildcards, catalogs,
1320 * etc. This seems to be good enough for now but could easily explode in
1321 * some apps.
1323 RETCODE SQL_API PGAPI_Tables
1324 (HSTMT hstmt,
1325 const SQLCHAR FAR * szTableQualifier, /* PV X */
1326 SQLSMALLINT cbTableQualifier,
1327 const SQLCHAR FAR *szTableOwner, /* PV E */
1328 SQLSMALLINT cbTableOwner,
1329 const SQLCHAR FAR *szTableName, /* PV E */
1330 SQLSMALLINT cbTableName,
1331 const SQLCHAR FAR *szTableType,
1332 SQLSMALLINT cbTableType, UWORD flag)
1334 StatementClass *stmt = (StatementClass *)hstmt;
1336 VxStatement st(stmt);
1337 VxResultSet rs;
1338 st.reinit();
1339 rs.runquery(st.dbus(), "ExecChunkRecordset", "LIST TABLES");
1340 st.set_result(rs);
1341 stmt->catalog_result = TRUE;
1342 return st.retcode();
1346 RETCODE SQL_API PGAPI_Columns(HSTMT hstmt, const SQLCHAR FAR * szTableQualifier, /* OA X */
1347 SQLSMALLINT cbTableQualifier, const SQLCHAR FAR * szTableOwner, /* PV E */
1348 SQLSMALLINT cbTableOwner, const SQLCHAR FAR * szTableName, /* PV E */
1349 SQLSMALLINT cbTableName, const SQLCHAR FAR * szColumnName, /* PV E */
1350 SQLSMALLINT cbColumnName,
1351 UWORD flag, OID reloid, Int2 attnum)
1353 StatementClass *stmt = (StatementClass *)hstmt;
1355 VxStatement st(stmt);
1356 VxResultSet rs;
1357 st.reinit();
1358 rs.runquery(st.dbus(), "ExecChunkRecordset",
1359 WvString("LIST COLUMNS %s", (const char *)szTableName));
1360 st.set_result(rs);
1361 stmt->catalog_result = TRUE;
1362 return st.retcode();
1366 RETCODE SQL_API PGAPI_SpecialColumns(HSTMT hstmt, SQLUSMALLINT fColType, const SQLCHAR FAR * szTableQualifier, SQLSMALLINT cbTableQualifier, const SQLCHAR FAR * szTableOwner, /* OA E */
1367 SQLSMALLINT cbTableOwner, const SQLCHAR FAR * szTableName, /* OA(R) E */
1368 SQLSMALLINT cbTableName,
1369 SQLUSMALLINT fScope,
1370 SQLUSMALLINT fNullable)
1372 CSTR func = "PGAPI_SpecialColumns";
1373 TupleField *tuple;
1374 StatementClass *stmt = (StatementClass *) hstmt;
1375 ConnectionClass *conn;
1376 QResultClass *res;
1377 ConnInfo *ci;
1378 HSTMT hcol_stmt = NULL;
1379 StatementClass *col_stmt;
1380 char columns_query[INFO_INQUIRY_LEN];
1381 char *escSchemaName = NULL, *escTableName = NULL;
1382 RETCODE result = SQL_SUCCESS;
1383 char relhasrules[MAX_INFO_STRING], relkind[8], relhasoids[8];
1384 BOOL relisaview;
1385 SQLSMALLINT internal_asis_type = SQL_C_CHAR, cbSchemaName;
1386 const char *szSchemaName;
1388 mylog("%s: entering...stmt=%p scnm=%p len=%d colType=%d\n", func,
1389 stmt, NULL_IF_NULL(szTableOwner), cbTableOwner, fColType);
1391 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
1392 return result;
1393 conn = SC_get_conn(stmt);
1394 ci = &(conn->connInfo);
1395 #ifdef UNICODE_SUPPORT
1396 if (CC_is_in_unicode_driver(conn))
1397 internal_asis_type = INTERNAL_ASIS_TYPE;
1398 #endif /* UNICODE_SUPPORT */
1400 szSchemaName = (const char *)szTableOwner;
1401 cbSchemaName = cbTableOwner;
1403 escTableName =
1404 simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
1405 if (!escTableName)
1407 SC_set_error(stmt, STMT_INVALID_NULL_ARG,
1408 "The table name is required", func);
1409 return result;
1411 #define return DONT_CALL_RETURN_FROM_HERE???
1413 retry_public_schema:
1414 if (escSchemaName)
1415 free(escSchemaName);
1416 escSchemaName =
1417 simpleCatalogEscape((const UCHAR *)szSchemaName, cbSchemaName, NULL, conn);
1419 * Create the query to find out if this is a view or not...
1421 strcpy(columns_query, "select c.relhasrules, c.relkind");
1422 if (PG_VERSION_GE(conn, 7.2))
1423 strcat(columns_query, ", c.relhasoids");
1424 if (conn->schema_support)
1425 strcat(columns_query, " from pg_catalog.pg_namespace u,"
1426 " pg_catalog.pg_class c where "
1427 "u.oid = c.relnamespace");
1428 else
1429 strcat(columns_query, " from pg_user u, pg_class c where "
1430 "u.usesysid = c.relowner");
1432 /* TableName cannot contain a string search pattern */
1433 /* my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName); */
1434 if (escTableName)
1435 snprintf_add(columns_query, sizeof(columns_query),
1436 " and c.relname = '%s'", escTableName);
1437 /* SchemaName cannot contain a string search pattern */
1438 if (conn->schema_support)
1439 schema_strcat(columns_query, " and u.nspname = '%.*s'",
1440 escSchemaName, SQL_NTS, (const char *)szTableName,
1441 cbTableName, conn);
1442 else
1443 my_strcat(columns_query, " and u.usename = '%.*s'",
1444 escSchemaName, SQL_NTS);
1446 result = PGAPI_AllocStmt(conn, &hcol_stmt);
1447 if (!SQL_SUCCEEDED(result))
1449 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
1450 "Couldn't allocate statement for SQLSpecialColumns result.",
1451 func);
1452 result = SQL_ERROR;
1453 goto cleanup;
1455 col_stmt = (StatementClass *) hcol_stmt;
1457 mylog("%s: hcol_stmt = %p, col_stmt = %p\n", func, hcol_stmt,
1458 col_stmt);
1460 result = PGAPI_ExecDirect(hcol_stmt, (const UCHAR *)columns_query, SQL_NTS, 0);
1461 if (!SQL_SUCCEEDED(result))
1463 SC_full_error_copy(stmt, col_stmt, FALSE);
1464 result = SQL_ERROR;
1465 goto cleanup;
1468 /* If not found */
1469 if (conn->schema_support &&
1470 (res = SC_get_Result(col_stmt)) &&
1471 0 == QR_get_num_total_tuples(res))
1473 const char *user = CC_get_username(conn);
1476 * If specified schema name == user_name and
1477 * the current schema is 'public',
1478 * retry the 'public' schema.
1480 if (szSchemaName &&
1481 (cbSchemaName == SQL_NTS ||
1482 cbSchemaName == (SQLSMALLINT) strlen(user)) &&
1483 strnicmp(szSchemaName, user, strlen(user)) == 0 &&
1484 stricmp(CC_get_current_schema(conn), pubstr) == 0)
1486 PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
1487 hcol_stmt = NULL;
1488 szSchemaName = pubstr;
1489 cbSchemaName = SQL_NTS;
1490 goto retry_public_schema;
1494 result = PGAPI_BindCol(hcol_stmt, 1, internal_asis_type,
1495 relhasrules, sizeof(relhasrules), NULL);
1496 if (!SQL_SUCCEEDED(result))
1498 SC_error_copy(stmt, col_stmt, TRUE);
1499 result = SQL_ERROR;
1500 goto cleanup;
1503 result = PGAPI_BindCol(hcol_stmt, 2, internal_asis_type,
1504 relkind, sizeof(relkind), NULL);
1505 if (!SQL_SUCCEEDED(result))
1507 SC_error_copy(stmt, col_stmt, TRUE);
1508 result = SQL_ERROR;
1509 goto cleanup;
1511 relhasoids[0] = '1';
1512 if (PG_VERSION_GE(conn, 7.2))
1514 result = PGAPI_BindCol(hcol_stmt, 3, internal_asis_type,
1515 relhasoids, sizeof(relhasoids), NULL);
1516 if (!SQL_SUCCEEDED(result))
1518 SC_error_copy(stmt, col_stmt, TRUE);
1519 result = SQL_ERROR;
1520 goto cleanup;
1524 result = PGAPI_Fetch(hcol_stmt);
1525 if (PG_VERSION_GE(conn, 7.1))
1526 relisaview = (relkind[0] == 'v');
1527 else
1528 relisaview = (relhasrules[0] == '1');
1529 PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
1530 hcol_stmt = NULL;
1532 res = QR_Constructor();
1533 SC_set_Result(stmt, res);
1534 extend_column_bindings(SC_get_ARDF(stmt), 8);
1536 stmt->catalog_result = TRUE;
1537 QR_set_num_fields(res, 8);
1538 QR_set_field_info_v(res, 0, "SCOPE", PG_TYPE_INT2, 2);
1539 QR_set_field_info_v(res, 1, "COLUMN_NAME", PG_TYPE_VARCHAR,
1540 MAX_INFO_STRING);
1541 QR_set_field_info_v(res, 2, "DATA_TYPE", PG_TYPE_INT2, 2);
1542 QR_set_field_info_v(res, 3, "TYPE_NAME", PG_TYPE_VARCHAR,
1543 MAX_INFO_STRING);
1544 QR_set_field_info_v(res, 4, "PRECISION", PG_TYPE_INT4, 4);
1545 QR_set_field_info_v(res, 5, "LENGTH", PG_TYPE_INT4, 4);
1546 QR_set_field_info_v(res, 6, "SCALE", PG_TYPE_INT2, 2);
1547 QR_set_field_info_v(res, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2);
1549 if (relisaview)
1551 /* there's no oid for views */
1552 if (fColType == SQL_BEST_ROWID)
1554 goto cleanup;
1556 else if (fColType == SQL_ROWVER)
1558 Int2 the_type = PG_TYPE_TID;
1560 tuple = QR_AddNew(res);
1562 set_tuplefield_null(&tuple[0]);
1563 set_tuplefield_string(&tuple[1], "ctid");
1564 set_tuplefield_int2(&tuple[2],
1565 pgtype_to_concise_type(stmt, the_type,
1566 PG_STATIC));
1567 set_tuplefield_string(&tuple[3],
1568 pgtype_to_name(stmt, the_type,
1569 FALSE));
1570 set_tuplefield_int4(&tuple[4],
1571 pgtype_column_size(stmt, the_type,
1572 PG_STATIC,
1573 PG_STATIC));
1574 set_tuplefield_int4(&tuple[5],
1575 pgtype_buffer_length(stmt, the_type,
1576 PG_STATIC,
1577 PG_STATIC));
1578 set_tuplefield_int2(&tuple[6],
1579 pgtype_decimal_digits(stmt, the_type,
1580 PG_STATIC));
1581 set_tuplefield_int2(&tuple[7], SQL_PC_NOT_PSEUDO);
1582 inolog("Add ctid\n");
1585 else
1587 /* use the oid value for the rowid */
1588 if (fColType == SQL_BEST_ROWID)
1590 Int2 the_type = PG_TYPE_OID;
1592 if (relhasoids[0] != '1')
1594 goto cleanup;
1596 tuple = QR_AddNew(res);
1598 set_tuplefield_int2(&tuple[0], SQL_SCOPE_SESSION);
1599 set_tuplefield_string(&tuple[1], OID_NAME);
1600 set_tuplefield_int2(&tuple[2],
1601 pgtype_to_concise_type(stmt, the_type,
1602 PG_STATIC));
1603 set_tuplefield_string(&tuple[3],
1604 pgtype_to_name(stmt, the_type, TRUE));
1605 set_tuplefield_int4(&tuple[4],
1606 pgtype_column_size(stmt, the_type,
1607 PG_STATIC,
1608 PG_STATIC));
1609 set_tuplefield_int4(&tuple[5],
1610 pgtype_buffer_length(stmt, the_type,
1611 PG_STATIC,
1612 PG_STATIC));
1613 set_tuplefield_int2(&tuple[6],
1614 pgtype_decimal_digits(stmt, the_type,
1615 PG_STATIC));
1616 set_tuplefield_int2(&tuple[7], SQL_PC_PSEUDO);
1618 else if (fColType == SQL_ROWVER)
1620 Int2 the_type = PG_TYPE_XID;
1622 /* if (atoi(ci->row_versioning)) */
1624 tuple = QR_AddNew(res);
1626 set_tuplefield_null(&tuple[0]);
1627 set_tuplefield_string(&tuple[1], "xmin");
1628 set_tuplefield_int2(&tuple[2],
1629 pgtype_to_concise_type(stmt,
1630 the_type,
1631 PG_STATIC));
1632 set_tuplefield_string(&tuple[3],
1633 pgtype_to_name(stmt, the_type,
1634 FALSE));
1635 set_tuplefield_int4(&tuple[4],
1636 pgtype_column_size(stmt, the_type,
1637 PG_STATIC,
1638 PG_STATIC));
1639 set_tuplefield_int4(&tuple[5],
1640 pgtype_buffer_length(stmt, the_type,
1641 PG_STATIC,
1642 PG_STATIC));
1643 set_tuplefield_int2(&tuple[6],
1644 pgtype_decimal_digits(stmt,
1645 the_type,
1646 PG_STATIC));
1647 set_tuplefield_int2(&tuple[7], SQL_PC_PSEUDO);
1652 cleanup:
1653 #undef return
1654 if (escSchemaName)
1655 free(escSchemaName);
1656 if (escTableName)
1657 free(escTableName);
1658 stmt->status = STMT_FINISHED;
1659 stmt->currTuple = -1;
1660 SC_set_rowset_start(stmt, -1, FALSE);
1661 SC_set_current_col(stmt, -1);
1662 if (hcol_stmt)
1663 PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
1664 if (stmt->internal)
1665 result = DiscardStatementSvp(stmt, result, FALSE);
1666 mylog("%s: EXIT, stmt=%p\n", func, stmt);
1667 return result;
1670 RETCODE SQL_API PGAPI_Statistics(HSTMT hstmt, const SQLCHAR FAR * szTableQualifier, /* OA X */
1671 SQLSMALLINT cbTableQualifier, const SQLCHAR FAR * szTableOwner, /* OA E */
1672 SQLSMALLINT cbTableOwner, const SQLCHAR FAR * szTableName, /* OA(R) E */
1673 SQLSMALLINT cbTableName,
1674 SQLUSMALLINT fUnique,
1675 SQLUSMALLINT fAccuracy)
1677 CSTR func = "PGAPI_Statistics";
1678 StatementClass *stmt = (StatementClass *) hstmt;
1679 ConnectionClass *conn;
1680 QResultClass *res;
1681 char index_query[INFO_INQUIRY_LEN];
1682 HSTMT hcol_stmt = NULL, hindx_stmt = NULL;
1683 RETCODE ret = SQL_ERROR, result;
1684 char *escSchemaName = NULL, *table_name = NULL, *escTableName =
1685 NULL;
1686 char index_name[MAX_INFO_STRING];
1687 short fields_vector[INDEX_KEYS_STORAGE_COUNT + 1];
1688 char isunique[10], isclustered[10], ishash[MAX_INFO_STRING];
1689 SQLLEN index_name_len, fields_vector_len;
1690 TupleField *tuple;
1691 int i;
1692 StatementClass *col_stmt, *indx_stmt;
1693 char column_name[MAX_INFO_STRING],
1694 table_schemaname[MAX_INFO_STRING], relhasrules[10];
1695 struct columns_idx {
1696 int pnum;
1697 char *col_name;
1699 *column_names = NULL;
1700 /* char **column_names = NULL; */
1701 SQLLEN column_name_len;
1702 int total_columns = 0, alcount;
1703 ConnInfo *ci;
1704 char buf[256];
1705 SQLSMALLINT internal_asis_type =
1706 SQL_C_CHAR, cbSchemaName, field_number;
1707 const char *szSchemaName;
1708 OID ioid;
1710 mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func, stmt,
1711 NULL_IF_NULL(szTableOwner), cbTableOwner);
1713 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
1714 return result;
1716 table_name = make_string(szTableName, cbTableName, NULL, 0);
1717 if (!table_name)
1719 SC_set_error(stmt, STMT_INVALID_NULL_ARG,
1720 "The table name is required", func);
1721 return result;
1723 conn = SC_get_conn(stmt);
1724 ci = &(conn->connInfo);
1725 #ifdef UNICODE_SUPPORT
1726 if (CC_is_in_unicode_driver(conn))
1727 internal_asis_type = INTERNAL_ASIS_TYPE;
1728 #endif /* UNICODE_SUPPORT */
1730 if (res = QR_Constructor(), !res)
1732 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
1733 "Couldn't allocate memory for PGAPI_Statistics result.",
1734 func);
1735 return SQL_ERROR;
1737 SC_set_Result(stmt, res);
1739 /* the binding structure for a statement is not set up until */
1742 * a statement is actually executed, so we'll have to do this
1743 * ourselves.
1745 extend_column_bindings(SC_get_ARDF(stmt), 13);
1747 stmt->catalog_result = TRUE;
1748 /* set the field names */
1749 QR_set_num_fields(res, NUM_OF_STATS_FIELDS);
1750 QR_set_field_info_v(res, STATS_CATALOG_NAME, "TABLE_QUALIFIER",
1751 PG_TYPE_VARCHAR, MAX_INFO_STRING);
1752 QR_set_field_info_v(res, STATS_SCHEMA_NAME, "TABLE_OWNER",
1753 PG_TYPE_VARCHAR, MAX_INFO_STRING);
1754 QR_set_field_info_v(res, STATS_TABLE_NAME, "TABLE_NAME",
1755 PG_TYPE_VARCHAR, MAX_INFO_STRING);
1756 QR_set_field_info_v(res, STATS_NON_UNIQUE, "NON_UNIQUE",
1757 PG_TYPE_INT2, 2);
1758 QR_set_field_info_v(res, STATS_INDEX_QUALIFIER, "INDEX_QUALIFIER",
1759 PG_TYPE_VARCHAR, MAX_INFO_STRING);
1760 QR_set_field_info_v(res, STATS_INDEX_NAME, "INDEX_NAME",
1761 PG_TYPE_VARCHAR, MAX_INFO_STRING);
1762 QR_set_field_info_v(res, STATS_TYPE, "TYPE", PG_TYPE_INT2, 2);
1763 QR_set_field_info_v(res, STATS_SEQ_IN_INDEX, "SEQ_IN_INDEX",
1764 PG_TYPE_INT2, 2);
1765 QR_set_field_info_v(res, STATS_COLUMN_NAME, "COLUMN_NAME",
1766 PG_TYPE_VARCHAR, MAX_INFO_STRING);
1767 QR_set_field_info_v(res, STATS_COLLATION, "COLLATION", PG_TYPE_CHAR,
1769 QR_set_field_info_v(res, STATS_CARDINALITY, "CARDINALITY",
1770 PG_TYPE_INT4, 4);
1771 QR_set_field_info_v(res, STATS_PAGES, "PAGES", PG_TYPE_INT4, 4);
1772 QR_set_field_info_v(res, STATS_FILTER_CONDITION, "FILTER_CONDITION",
1773 PG_TYPE_VARCHAR, MAX_INFO_STRING);
1775 #define return DONT_CALL_RETURN_FROM_HERE???
1776 szSchemaName = (const char *)szTableOwner;
1777 cbSchemaName = cbTableOwner;
1779 table_schemaname[0] = '\0';
1780 if (conn->schema_support)
1781 schema_strcat(table_schemaname, "%.*s", szSchemaName,
1782 cbSchemaName, (const char *)szTableName,
1783 cbTableName, conn);
1786 * we need to get a list of the field names first, so we can return
1787 * them later.
1789 result = PGAPI_AllocStmt(conn, &hcol_stmt);
1790 if (!SQL_SUCCEEDED(result))
1792 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
1793 "PGAPI_AllocStmt failed in PGAPI_Statistics for columns.",
1794 func);
1795 goto cleanup;
1798 col_stmt = (StatementClass *) hcol_stmt;
1801 * "internal" prevents SQLColumns from returning the oid if it is
1802 * being shown. This would throw everything off.
1804 col_stmt->internal = TRUE;
1806 * table_name parameter cannot contain a string search pattern.
1808 result =
1809 PGAPI_Columns(hcol_stmt, NULL, 0,
1810 (const UCHAR *)table_schemaname, SQL_NTS,
1811 (const UCHAR *)table_name, SQL_NTS, NULL, 0,
1812 PODBC_NOT_SEARCH_PATTERN |
1813 PODBC_SEARCH_PUBLIC_SCHEMA, 0, 0);
1814 col_stmt->internal = FALSE;
1816 if (!SQL_SUCCEEDED(result))
1818 SC_error_copy(stmt, col_stmt, TRUE);
1819 goto cleanup;
1821 result =
1822 PGAPI_BindCol(hcol_stmt, COLUMNS_COLUMN_NAME + 1,
1823 internal_asis_type, column_name,
1824 sizeof(column_name), &column_name_len);
1825 if (!SQL_SUCCEEDED(result))
1827 SC_error_copy(stmt, col_stmt, TRUE);
1828 goto cleanup;
1830 result =
1831 PGAPI_BindCol(hcol_stmt, COLUMNS_PHYSICAL_NUMBER + 1,
1832 SQL_C_SHORT, &field_number, sizeof(field_number),
1833 NULL);
1834 if (!SQL_SUCCEEDED(result))
1836 SC_error_copy(stmt, col_stmt, TRUE);
1837 goto cleanup;
1840 alcount = 0;
1841 result = PGAPI_Fetch(hcol_stmt);
1842 while (SQL_SUCCEEDED(result))
1844 if (0 == total_columns)
1845 PGAPI_GetData(hcol_stmt, 2, internal_asis_type,
1846 table_schemaname, sizeof(table_schemaname),
1847 NULL);
1849 if (total_columns >= alcount)
1851 if (0 == alcount)
1852 alcount = 4;
1853 else
1854 alcount *= 2;
1855 column_names =
1856 (struct columns_idx *) realloc(column_names,
1857 alcount *
1858 sizeof(struct
1859 columns_idx));
1861 column_names[total_columns].col_name =
1862 (char *) malloc(strlen(column_name) + 1);
1863 strcpy(column_names[total_columns].col_name, column_name);
1864 column_names[total_columns].pnum = field_number;
1865 total_columns++;
1867 mylog("%s: column_name = '%s'\n", func, column_name);
1869 result = PGAPI_Fetch(hcol_stmt);
1872 if (result != SQL_NO_DATA_FOUND)
1874 SC_full_error_copy(stmt, col_stmt, FALSE);
1875 goto cleanup;
1877 PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
1878 hcol_stmt = NULL;
1879 if (total_columns == 0)
1881 /* Couldn't get column names in SQLStatistics.; */
1882 ret = SQL_SUCCESS;
1883 goto cleanup;
1886 /* get a list of indexes on this table */
1887 result = PGAPI_AllocStmt(conn, &hindx_stmt);
1888 if (!SQL_SUCCEEDED(result))
1890 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
1891 "PGAPI_AllocStmt failed in SQLStatistics for indices.",
1892 func);
1893 goto cleanup;
1896 indx_stmt = (StatementClass *) hindx_stmt;
1898 /* TableName cannot contain a string search pattern */
1899 escTableName = simpleCatalogEscape(table_name, SQL_NTS, NULL, conn);
1900 if (conn->schema_support)
1902 escSchemaName =
1903 simpleCatalogEscape(table_schemaname, SQL_NTS, NULL, conn);
1904 snprintf(index_query, sizeof(index_query),
1905 "select c.relname, i.indkey, i.indisunique"
1906 ", i.indisclustered, a.amname, c.relhasrules, n.nspname"
1907 ", c.oid"
1908 " from pg_catalog.pg_index i, pg_catalog.pg_class c,"
1909 " pg_catalog.pg_class d, pg_catalog.pg_am a,"
1910 " pg_catalog.pg_namespace n" " where d.relname = '%s'"
1911 " and n.nspname = '%s'" " and n.oid = d.relnamespace"
1912 " and d.oid = i.indrelid" " and i.indexrelid = c.oid"
1913 " and c.relam = a.oid order by", escTableName,
1914 escSchemaName);
1916 else
1917 snprintf(index_query, sizeof(index_query),
1918 "select c.relname, i.indkey, i.indisunique"
1919 ", i.indisclustered, a.amname, c.relhasrules, c.oid"
1920 " from pg_index i, pg_class c, pg_class d, pg_am a"
1921 " where d.relname = '%s'" " and d.oid = i.indrelid"
1922 " and i.indexrelid = c.oid"
1923 " and c.relam = a.oid order by", escTableName);
1924 if (PG_VERSION_GT(SC_get_conn(stmt), 6.4))
1925 strcat(index_query, " i.indisprimary desc,");
1926 if (conn->schema_support)
1927 strcat(index_query, " i.indisunique, n.nspname, c.relname");
1928 else
1929 strcat(index_query, " i.indisunique, c.relname");
1931 result = PGAPI_ExecDirect(hindx_stmt, (const UCHAR *)index_query, SQL_NTS, 0);
1932 if (!SQL_SUCCEEDED(result))
1935 * "Couldn't execute index query (w/SQLExecDirect) in
1936 * SQLStatistics.";
1938 SC_full_error_copy(stmt, indx_stmt, FALSE);
1939 goto cleanup;
1942 /* bind the index name column */
1943 result = PGAPI_BindCol(hindx_stmt, 1, internal_asis_type,
1944 index_name, MAX_INFO_STRING,
1945 &index_name_len);
1946 if (!SQL_SUCCEEDED(result))
1948 SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column
1949 * in SQLStatistics."; */
1950 goto cleanup;
1953 /* bind the vector column */
1954 result = PGAPI_BindCol(hindx_stmt, 2, SQL_C_DEFAULT,
1955 fields_vector, sizeof(fields_vector),
1956 &fields_vector_len);
1957 if (!SQL_SUCCEEDED(result))
1959 SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column
1960 * in SQLStatistics."; */
1961 goto cleanup;
1964 /* bind the "is unique" column */
1965 result = PGAPI_BindCol(hindx_stmt, 3, internal_asis_type,
1966 isunique, sizeof(isunique), NULL);
1967 if (!SQL_SUCCEEDED(result))
1969 SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column
1970 * in SQLStatistics."; */
1971 goto cleanup;
1974 /* bind the "is clustered" column */
1975 result = PGAPI_BindCol(hindx_stmt, 4, internal_asis_type,
1976 isclustered, sizeof(isclustered), NULL);
1977 if (!SQL_SUCCEEDED(result))
1979 SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column *
1980 * in SQLStatistics."; */
1981 goto cleanup;
1985 /* bind the "is hash" column */
1986 result = PGAPI_BindCol(hindx_stmt, 5, internal_asis_type,
1987 ishash, sizeof(ishash), NULL);
1988 if (!SQL_SUCCEEDED(result))
1990 SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column *
1991 * in SQLStatistics."; */
1992 goto cleanup;
1996 result = PGAPI_BindCol(hindx_stmt, 6, internal_asis_type,
1997 relhasrules, sizeof(relhasrules), NULL);
1998 if (!SQL_SUCCEEDED(result))
2000 SC_error_copy(stmt, indx_stmt, TRUE);
2001 goto cleanup;
2004 result = PGAPI_BindCol(hindx_stmt, 8, SQL_C_ULONG,
2005 &ioid, sizeof(ioid), NULL);
2006 if (!SQL_SUCCEEDED(result))
2008 SC_error_copy(stmt, indx_stmt, TRUE);
2009 goto cleanup;
2012 relhasrules[0] = '0';
2013 result = PGAPI_Fetch(hindx_stmt);
2014 /* fake index of OID */
2015 if (relhasrules[0] != '1' && atoi(ci->show_oid_column)
2016 && atoi(ci->fake_oid_index))
2018 tuple = QR_AddNew(res);
2020 /* no table qualifier */
2021 set_tuplefield_string(&tuple[STATS_CATALOG_NAME],
2022 CurrCat(conn));
2023 /* don't set the table owner, else Access tries to use it */
2024 set_tuplefield_string(&tuple[STATS_SCHEMA_NAME],
2025 GET_SCHEMA_NAME(table_schemaname));
2026 set_tuplefield_string(&tuple[STATS_TABLE_NAME], table_name);
2028 /* non-unique index? */
2029 set_tuplefield_int2(&tuple[STATS_NON_UNIQUE], (Int2)FALSE);
2031 /* no index qualifier */
2032 set_tuplefield_string(&tuple[STATS_INDEX_QUALIFIER],
2033 CurrCat(conn));
2035 snprintf(buf, sizeof(table_name), "%s_idx_fake_oid",
2036 table_name);
2037 set_tuplefield_string(&tuple[STATS_INDEX_NAME], buf);
2040 * Clustered/HASH index?
2042 set_tuplefield_int2(&tuple[STATS_TYPE], (Int2) SQL_INDEX_OTHER);
2043 set_tuplefield_int2(&tuple[STATS_SEQ_IN_INDEX], (Int2) 1);
2045 set_tuplefield_string(&tuple[STATS_COLUMN_NAME], OID_NAME);
2046 set_tuplefield_string(&tuple[STATS_COLLATION], "A");
2047 set_tuplefield_null(&tuple[STATS_CARDINALITY]);
2048 set_tuplefield_null(&tuple[STATS_PAGES]);
2049 set_tuplefield_null(&tuple[STATS_FILTER_CONDITION]);
2052 while (SQL_SUCCEEDED(result))
2054 /* If only requesting unique indexs, then just return those. */
2055 if (fUnique == SQL_INDEX_ALL ||
2056 (fUnique == SQL_INDEX_UNIQUE && atoi(isunique)))
2058 int colcnt, attnum;
2060 /* add a row in this table for each field in the index */
2061 colcnt = fields_vector[0];
2062 for (i = 1; i <= colcnt; i++)
2064 tuple = QR_AddNew(res);
2066 /* no table qualifier */
2067 set_tuplefield_string(&tuple[STATS_CATALOG_NAME],
2068 CurrCat(conn));
2069 /* don't set the table owner, else Access tries to use it */
2070 set_tuplefield_string(&tuple[STATS_SCHEMA_NAME],
2071 GET_SCHEMA_NAME
2072 (table_schemaname));
2073 set_tuplefield_string(&tuple[STATS_TABLE_NAME],
2074 table_name);
2076 /* non-unique index? */
2077 set_tuplefield_int2(&tuple[STATS_NON_UNIQUE],
2078 (Int2) (atoi(isunique) ? FALSE :
2079 TRUE));
2081 /* no index qualifier */
2082 set_tuplefield_string(&tuple[STATS_INDEX_QUALIFIER],
2083 CurrCat(conn));
2084 set_tuplefield_string(&tuple[STATS_INDEX_NAME],
2085 index_name);
2088 * Clustered/HASH index?
2090 set_tuplefield_int2(&tuple[STATS_TYPE], (Int2)
2091 (atoi(isclustered) ?
2092 SQL_INDEX_CLUSTERED
2093 : (!strncmp(ishash, "hash", 4)) ?
2094 SQL_INDEX_HASHED :
2095 SQL_INDEX_OTHER));
2096 set_tuplefield_int2(&tuple[STATS_SEQ_IN_INDEX],
2097 (Int2) i);
2099 attnum = fields_vector[i];
2100 if (OID_ATTNUM == attnum)
2102 set_tuplefield_string(&tuple[STATS_COLUMN_NAME],
2103 OID_NAME);
2104 mylog("%s: column name = oid\n", func);
2106 else if (0 == attnum)
2108 char cmd[64];
2110 QResultClass *res;
2112 snprintf(cmd, sizeof(cmd),
2113 "select pg_get_indexdef(%u, %d, true)",
2114 ioid, i);
2115 res =
2116 CC_send_query(conn, cmd, NULL,
2117 IGNORE_ABORT_ON_CONN, stmt);
2118 if (QR_command_maybe_successful(res))
2119 set_tuplefield_string(&tuple[STATS_COLUMN_NAME],
2120 QR_get_value_backend_text
2121 (res, 0, 0));
2122 QR_Destructor(res);
2124 else
2126 int j, matchidx;
2127 BOOL unknownf = TRUE;
2129 if (attnum > 0)
2131 for (j = 0; j < total_columns; j++)
2133 if (attnum == column_names[j].pnum)
2135 matchidx = j;
2136 unknownf = FALSE;
2137 break;
2141 if (unknownf)
2143 set_tuplefield_string(&tuple[STATS_COLUMN_NAME],
2144 "UNKNOWN");
2145 mylog("%s: column name = UNKNOWN\n", func);
2147 else
2149 set_tuplefield_string(&tuple[STATS_COLUMN_NAME],
2150 column_names[matchidx].
2151 col_name);
2152 mylog("%s: column name = '%s'\n", func,
2153 column_names[matchidx].col_name);
2157 set_tuplefield_string(&tuple[STATS_COLLATION], "A");
2158 set_tuplefield_null(&tuple[STATS_CARDINALITY]);
2159 set_tuplefield_null(&tuple[STATS_PAGES]);
2160 set_tuplefield_null(&tuple[STATS_FILTER_CONDITION]);
2164 result = PGAPI_Fetch(hindx_stmt);
2166 if (result != SQL_NO_DATA_FOUND)
2168 /* "SQLFetch failed in SQLStatistics."; */
2169 SC_full_error_copy(stmt, indx_stmt, FALSE);
2170 goto cleanup;
2172 ret = SQL_SUCCESS;
2174 cleanup:
2175 #undef return
2177 * also, things need to think that this statement is finished so the
2178 * results can be retrieved.
2180 stmt->status = STMT_FINISHED;
2182 if (hcol_stmt)
2183 PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
2184 if (hindx_stmt)
2185 PGAPI_FreeStmt(hindx_stmt, SQL_DROP);
2186 /* These things should be freed on any error ALSO! */
2187 if (table_name)
2188 free(table_name);
2189 if (escTableName)
2190 free(escTableName);
2191 if (escSchemaName)
2192 free(escSchemaName);
2193 if (column_names)
2195 for (i = 0; i < total_columns; i++)
2196 free(column_names[i].col_name);
2197 free(column_names);
2200 /* set up the current tuple pointer for SQLFetch */
2201 stmt->currTuple = -1;
2202 SC_set_rowset_start(stmt, -1, FALSE);
2203 SC_set_current_col(stmt, -1);
2205 if (stmt->internal)
2206 ret = DiscardStatementSvp(stmt, ret, FALSE);
2207 mylog("%s: EXIT, stmt=%p, ret=%d\n", func, stmt, ret);
2209 return ret;
2212 RETCODE SQL_API PGAPI_ColumnPrivileges(HSTMT hstmt, const SQLCHAR FAR * szTableQualifier, /* OA X */
2213 SQLSMALLINT cbTableQualifier, const SQLCHAR FAR * szTableOwner, /* OA E */
2214 SQLSMALLINT cbTableOwner, const SQLCHAR FAR * szTableName, /* OA(R) E */
2215 SQLSMALLINT cbTableName, const SQLCHAR FAR * szColumnName, /* PV E */
2216 SQLSMALLINT cbColumnName,
2217 UWORD flag)
2219 CSTR func = "PGAPI_ColumnPrivileges";
2220 StatementClass *stmt = (StatementClass *) hstmt;
2221 ConnectionClass *conn = SC_get_conn(stmt);
2222 RETCODE result = SQL_ERROR;
2223 char *escSchemaName = NULL, *escTableName = NULL, *escColumnName =
2224 NULL;
2225 const char *like_or_eq;
2226 char column_query[INFO_INQUIRY_LEN];
2227 size_t cq_len, cq_size;
2228 char *col_query;
2229 BOOL search_pattern;
2230 QResultClass *res;
2232 mylog("%s: entering...\n", func);
2234 /* Neither Access or Borland care about this. */
2236 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
2237 return result;
2238 if (PG_VERSION_LT(conn, 7.4))
2239 SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR,
2240 "Function not implementedyet", func);
2241 escSchemaName =
2242 simpleCatalogEscape(szTableOwner, cbTableOwner, NULL, conn);
2243 escTableName =
2244 simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
2245 search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
2246 if (search_pattern)
2248 like_or_eq = likeop;
2249 escColumnName =
2250 adjustLikePattern(szColumnName, cbColumnName,
2251 SEARCH_PATTERN_ESCAPE, NULL, conn);
2253 else
2255 like_or_eq = eqop;
2256 escColumnName =
2257 simpleCatalogEscape(szColumnName, cbColumnName, NULL, conn);
2259 strcpy(column_query,
2260 "select '' as TABLE_CAT, table_schema as TABLE_SCHEM,"
2261 " table_name, column_name, grantor, grantee,"
2262 " privilege_type as PRIVILEGE, is_grantable from"
2263 " information_schema.column_privileges where true");
2264 cq_len = strlen(column_query);
2265 cq_size = sizeof(column_query);
2266 col_query = column_query;
2267 if (escSchemaName)
2269 col_query += cq_len;
2270 cq_size -= cq_len;
2271 cq_len = snprintf_len(col_query, cq_size,
2272 " and table_schem = '%s'", escSchemaName);
2275 if (escTableName)
2277 col_query += cq_len;
2278 cq_size -= cq_len;
2279 cq_len += snprintf_len(col_query, cq_size,
2280 " and table_name = '%s'", escTableName);
2282 if (escColumnName)
2284 col_query += cq_len;
2285 cq_size -= cq_len;
2286 cq_len += snprintf_len(col_query, cq_size,
2287 " and column_name %s '%s'", like_or_eq,
2288 escColumnName);
2290 if (res =
2291 CC_send_query(conn, column_query, NULL, IGNORE_ABORT_ON_CONN,
2292 stmt), !QR_command_maybe_successful(res))
2294 SC_set_error(stmt, STMT_EXEC_ERROR,
2295 "PGAPI_ColumnPrivileges query error", func);
2296 QR_Destructor(res);
2297 return SQL_ERROR;
2299 SC_set_Result(stmt, res);
2302 * also, things need to think that this statement is finished so the
2303 * results can be retrieved.
2305 extend_column_bindings(SC_get_ARDF(stmt), 8);
2306 /* set up the current tuple pointer for SQLFetch */
2307 result = SQL_SUCCESS;
2309 /* set up the current tuple pointer for SQLFetch */
2310 stmt->status = STMT_FINISHED;
2311 stmt->currTuple = -1;
2312 SC_set_rowset_start(stmt, -1, FALSE);
2313 if (escSchemaName)
2314 free(escSchemaName);
2315 if (escTableName)
2316 free(escTableName);
2317 if (escColumnName)
2318 free(escColumnName);
2319 return result;
2323 * SQLPrimaryKeys()
2325 * Retrieve the primary key columns for the specified table.
2327 RETCODE SQL_API PGAPI_PrimaryKeys(HSTMT hstmt, const SQLCHAR FAR * szTableQualifier, /* OA X */
2328 SQLSMALLINT cbTableQualifier, const SQLCHAR FAR * szTableOwner, /* OA E */
2329 SQLSMALLINT cbTableOwner, const SQLCHAR FAR * szTableName, /* OA(R) E */
2330 SQLSMALLINT cbTableName)
2332 StatementClass *stmt = (StatementClass *)hstmt;
2334 VxStatement st(stmt);
2335 VxResultSet rs;
2336 st.reinit();
2337 rs.runquery(st.dbus(), "ExecChunkRecordset",
2338 WvString("sp_primary_keys_rowset '%s'",
2339 (const char *)szTableName));
2340 st.set_result(rs);
2341 stmt->catalog_result = TRUE;
2342 return st.retcode();
2346 * Multibyte support stuff for SQLForeignKeys().
2347 * There may be much more effective way in the
2348 * future version. The way is very forcible currently.
2350 static BOOL isMultibyte(const UCHAR * str)
2352 for (; *str; str++)
2354 if (*str >= 0x80)
2355 return TRUE;
2357 return FALSE;
2359 static char *getClientColumnName(ConnectionClass * conn, UInt4 relid,
2360 char *serverColumnName,
2361 BOOL * nameAlloced)
2363 char query[1024], saveattnum[16], *ret = serverColumnName;
2364 BOOL continueExec = TRUE, bError = FALSE;
2365 QResultClass *res = NULL;
2366 UWORD flag = IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR;
2368 *nameAlloced = FALSE;
2369 if (!conn->original_client_encoding
2370 || !isMultibyte((const UCHAR *)serverColumnName))
2371 return ret;
2372 if (!conn->server_encoding)
2374 if (res =
2375 CC_send_query(conn, "select getdatabaseencoding()", NULL,
2376 flag, NULL), QR_command_maybe_successful(res))
2378 if (QR_get_num_cached_tuples(res) > 0)
2379 conn->server_encoding =
2380 strdup(QR_get_value_backend_text(res, 0, 0));
2382 QR_Destructor(res);
2383 res = NULL;
2385 if (!conn->server_encoding)
2386 return ret;
2387 snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'",
2388 conn->server_encoding);
2389 bError =
2390 (!QR_command_maybe_successful
2391 ((res = CC_send_query(conn, query, NULL, flag, NULL))));
2392 QR_Destructor(res);
2393 if (!bError && continueExec)
2395 snprintf(query, sizeof(query),
2396 "select attnum from pg_attribute "
2397 "where attrelid = %u and attname = '%s'", relid,
2398 serverColumnName);
2399 if (res =
2400 CC_send_query(conn, query, NULL, flag, NULL),
2401 QR_command_maybe_successful(res))
2403 if (QR_get_num_cached_tuples(res) > 0)
2405 strcpy(saveattnum,
2406 QR_get_value_backend_text(res, 0, 0));
2408 else
2409 continueExec = FALSE;
2411 else
2412 bError = TRUE;
2413 QR_Destructor(res);
2415 continueExec = (continueExec && !bError);
2416 /* restore the cleint encoding */
2417 snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'",
2418 conn->original_client_encoding);
2419 bError =
2420 (!QR_command_maybe_successful
2421 ((res = CC_send_query(conn, query, NULL, flag, NULL))));
2422 QR_Destructor(res);
2423 if (bError || !continueExec)
2424 return ret;
2425 snprintf(query, sizeof(query),
2426 "select attname from pg_attribute where attrelid = %u and attnum = %s",
2427 relid, saveattnum);
2428 if (res =
2429 CC_send_query(conn, query, NULL, flag, NULL),
2430 QR_command_maybe_successful(res))
2432 if (QR_get_num_cached_tuples(res) > 0)
2434 ret = strdup(QR_get_value_backend_text(res, 0, 0));
2435 *nameAlloced = TRUE;
2438 QR_Destructor(res);
2439 return ret;
2442 RETCODE SQL_API PGAPI_ForeignKeys(HSTMT hstmt, const SQLCHAR FAR * szPkTableQualifier, /* OA X */
2443 SQLSMALLINT cbPkTableQualifier, const SQLCHAR FAR * szPkTableOwner, /* OA E */
2444 SQLSMALLINT cbPkTableOwner, const SQLCHAR FAR * szPkTableName, /* OA(R) E */
2445 SQLSMALLINT cbPkTableName, const SQLCHAR FAR * szFkTableQualifier, /* OA X */
2446 SQLSMALLINT cbFkTableQualifier, const SQLCHAR FAR * szFkTableOwner, /* OA E */
2447 SQLSMALLINT cbFkTableOwner, const SQLCHAR FAR * szFkTableName, /* OA(R) E */
2448 SQLSMALLINT cbFkTableName)
2450 CSTR func = "PGAPI_ForeignKeys";
2451 StatementClass *stmt = (StatementClass *) hstmt;
2452 QResultClass *res;
2453 TupleField *tuple;
2454 HSTMT htbl_stmt = NULL, hpkey_stmt = NULL;
2455 StatementClass *tbl_stmt;
2456 RETCODE ret = SQL_ERROR, result, keyresult;
2457 char tables_query[INFO_INQUIRY_LEN];
2458 char trig_deferrable[2];
2459 char trig_initdeferred[2];
2460 char trig_args[1024];
2461 char upd_rule[TABLE_NAME_STORAGE_LEN],
2462 del_rule[TABLE_NAME_STORAGE_LEN];
2463 char *pk_table_needed = NULL, *escPkTableName = NULL;
2464 char fk_table_fetched[TABLE_NAME_STORAGE_LEN + 1];
2465 char *fk_table_needed = NULL, *escFkTableName = NULL;
2466 char pk_table_fetched[TABLE_NAME_STORAGE_LEN + 1];
2467 char schema_needed[SCHEMA_NAME_STORAGE_LEN + 1];
2468 char schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1];
2469 char constrname[NAMESTORAGELEN + 1],
2470 pkname[TABLE_NAME_STORAGE_LEN + 1];
2471 char *pkey_ptr, *pkey_text = NULL, *fkey_ptr, *fkey_text = NULL;
2473 ConnectionClass *conn;
2474 BOOL pkey_alloced, fkey_alloced, got_pkname;
2475 int i, j, k, num_keys;
2476 SQLSMALLINT trig_nargs, upd_rule_type = 0, del_rule_type = 0;
2477 SQLSMALLINT internal_asis_type = SQL_C_CHAR;
2479 SQLSMALLINT defer_type;
2480 char pkey[MAX_INFO_STRING];
2481 Int2 result_cols;
2482 UInt4 relid1, relid2;
2484 mylog("%s: entering...stmt=%p\n", func, stmt);
2486 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
2487 return result;
2489 if (res = QR_Constructor(), !res)
2491 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
2492 "Couldn't allocate memory for PGAPI_ForeignKeys result.",
2493 func);
2494 return SQL_ERROR;
2496 SC_set_Result(stmt, res);
2498 /* the binding structure for a statement is not set up until */
2501 * a statement is actually executed, so we'll have to do this
2502 * ourselves.
2504 result_cols = NUM_OF_FKS_FIELDS;
2505 extend_column_bindings(SC_get_ARDF(stmt), result_cols);
2507 stmt->catalog_result = TRUE;
2508 /* set the field names */
2509 QR_set_num_fields(res, result_cols);
2510 QR_set_field_info_v(res, FKS_PKTABLE_CAT, "PKTABLE_QUALIFIER",
2511 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2512 QR_set_field_info_v(res, FKS_PKTABLE_SCHEM, "PKTABLE_OWNER",
2513 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2514 QR_set_field_info_v(res, FKS_PKTABLE_NAME, "PKTABLE_NAME",
2515 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2516 QR_set_field_info_v(res, FKS_PKCOLUMN_NAME, "PKCOLUMN_NAME",
2517 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2518 QR_set_field_info_v(res, FKS_FKTABLE_CAT, "FKTABLE_QUALIFIER",
2519 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2520 QR_set_field_info_v(res, FKS_FKTABLE_SCHEM, "FKTABLE_OWNER",
2521 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2522 QR_set_field_info_v(res, FKS_FKTABLE_NAME, "FKTABLE_NAME",
2523 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2524 QR_set_field_info_v(res, FKS_FKCOLUMN_NAME, "FKCOLUMN_NAME",
2525 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2526 QR_set_field_info_v(res, FKS_KEY_SEQ, "KEY_SEQ", PG_TYPE_INT2, 2);
2527 QR_set_field_info_v(res, FKS_UPDATE_RULE, "UPDATE_RULE",
2528 PG_TYPE_INT2, 2);
2529 QR_set_field_info_v(res, FKS_DELETE_RULE, "DELETE_RULE",
2530 PG_TYPE_INT2, 2);
2531 QR_set_field_info_v(res, FKS_FK_NAME, "FK_NAME", PG_TYPE_VARCHAR,
2532 MAX_INFO_STRING);
2533 QR_set_field_info_v(res, FKS_PK_NAME, "PK_NAME", PG_TYPE_VARCHAR,
2534 MAX_INFO_STRING);
2535 QR_set_field_info_v(res, FKS_DEFERRABILITY, "DEFERRABILITY",
2536 PG_TYPE_INT2, 2);
2537 QR_set_field_info_v(res, FKS_TRIGGER_NAME, "TRIGGER_NAME",
2538 PG_TYPE_VARCHAR, MAX_INFO_STRING);
2541 * also, things need to think that this statement is finished so the
2542 * results can be retrieved.
2544 stmt->status = STMT_FINISHED;
2546 /* set up the current tuple pointer for SQLFetch */
2547 stmt->currTuple = -1;
2548 SC_set_rowset_start(stmt, -1, FALSE);
2549 SC_set_current_col(stmt, -1);
2551 conn = SC_get_conn(stmt);
2552 result = PGAPI_AllocStmt(conn, &htbl_stmt);
2553 if (!SQL_SUCCEEDED(result))
2555 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
2556 "Couldn't allocate statement for PGAPI_ForeignKeys result.",
2557 func);
2558 return SQL_ERROR;
2560 #define return DONT_CALL_RETURN_FROM_HERE???
2562 tbl_stmt = (StatementClass *) htbl_stmt;
2563 schema_needed[0] = '\0';
2564 schema_fetched[0] = '\0';
2566 pk_table_needed =
2567 make_string(szPkTableName, cbPkTableName, NULL, 0);
2568 fk_table_needed =
2569 make_string(szFkTableName, cbFkTableName, NULL, 0);
2571 #ifdef UNICODE_SUPPORT
2572 if (CC_is_in_unicode_driver(conn))
2573 internal_asis_type = INTERNAL_ASIS_TYPE;
2574 #endif /* UNICODE_SUPPORT */
2575 pkey_alloced = fkey_alloced = FALSE;
2578 * Case #2 -- Get the foreign keys in the specified table (fktab) that
2579 * refer to the primary keys of other table(s).
2581 if (fk_table_needed && fk_table_needed[0] != '\0')
2583 mylog("%s: entering Foreign Key Case #2", func);
2584 escFkTableName =
2585 simpleCatalogEscape(fk_table_needed, SQL_NTS, NULL, conn);
2586 if (conn->schema_support)
2588 char *escSchemaName;
2590 schema_strcat(schema_needed, "%.*s", (const char *)szFkTableOwner,
2591 cbFkTableOwner, (const char *)szFkTableName,
2592 cbFkTableName, conn);
2593 escSchemaName =
2594 simpleCatalogEscape(schema_needed, SQL_NTS, NULL, conn);
2595 snprintf(tables_query, sizeof(tables_query),
2596 "SELECT pt.tgargs, "
2597 " pt.tgnargs, "
2598 " pt.tgdeferrable, "
2599 " pt.tginitdeferred, "
2600 " pp1.proname, "
2601 " pp2.proname, "
2602 " pc.oid, "
2603 " pc1.oid, "
2604 " pc1.relname, "
2605 " pt.tgconstrname, pn.nspname "
2606 "FROM pg_catalog.pg_class pc, "
2607 " pg_catalog.pg_proc pp1, "
2608 " pg_catalog.pg_proc pp2, "
2609 " pg_catalog.pg_trigger pt1, "
2610 " pg_catalog.pg_trigger pt2, "
2611 " pg_catalog.pg_proc pp, "
2612 " pg_catalog.pg_trigger pt, "
2613 " pg_catalog.pg_class pc1, "
2614 " pg_catalog.pg_namespace pn, "
2615 " pg_catalog.pg_namespace pn1 "
2616 "WHERE pt.tgrelid = pc.oid "
2617 "AND pp.oid = pt.tgfoid "
2618 "AND pt1.tgconstrrelid = pc.oid "
2619 "AND pp1.oid = pt1.tgfoid "
2620 "AND pt2.tgfoid = pp2.oid "
2621 "AND pt2.tgconstrrelid = pc.oid "
2622 "AND ((pc.relname='%s') "
2623 "AND (pn1.oid = pc.relnamespace) "
2624 "AND (pn1.nspname = '%s') "
2625 "AND (pp.proname LIKE '%%ins') "
2626 "AND (pp1.proname LIKE '%%upd') "
2627 "AND (pp1.proname not LIKE '%%check%%') "
2628 "AND (pp2.proname LIKE '%%del') "
2629 "AND (pt1.tgrelid=pt.tgconstrrelid) "
2630 "AND (pt1.tgconstrname=pt.tgconstrname) "
2631 "AND (pt2.tgrelid=pt.tgconstrrelid) "
2632 "AND (pt2.tgconstrname=pt.tgconstrname) "
2633 "AND (pt.tgconstrrelid=pc1.oid) "
2634 "AND (pc1.relnamespace=pn.oid))"
2635 " order by pt.tgconstrname",
2636 escFkTableName, escSchemaName);
2637 free(escSchemaName);
2639 else
2640 snprintf(tables_query, sizeof(tables_query),
2641 "SELECT pt.tgargs, "
2642 " pt.tgnargs, "
2643 " pt.tgdeferrable, "
2644 " pt.tginitdeferred, "
2645 " pp1.proname, "
2646 " pp2.proname, "
2647 " pc.oid, "
2648 " pc1.oid, "
2649 " pc1.relname, pt.tgconstrname "
2650 "FROM pg_class pc, "
2651 " pg_proc pp1, "
2652 " pg_proc pp2, "
2653 " pg_trigger pt1, "
2654 " pg_trigger pt2, "
2655 " pg_proc pp, "
2656 " pg_trigger pt, "
2657 " pg_class pc1 "
2658 "WHERE pt.tgrelid = pc.oid "
2659 "AND pp.oid = pt.tgfoid "
2660 "AND pt1.tgconstrrelid = pc.oid "
2661 "AND pp1.oid = pt1.tgfoid "
2662 "AND pt2.tgfoid = pp2.oid "
2663 "AND pt2.tgconstrrelid = pc.oid "
2664 "AND ((pc.relname='%s') "
2665 "AND (pp.proname LIKE '%%ins') "
2666 "AND (pp1.proname LIKE '%%upd') "
2667 "AND (pp1.proname not LIKE '%%check%%') "
2668 "AND (pp2.proname LIKE '%%del') "
2669 "AND (pt1.tgrelid=pt.tgconstrrelid) "
2670 "AND (pt1.tgconstrname=pt.tgconstrname) "
2671 "AND (pt2.tgrelid=pt.tgconstrrelid) "
2672 "AND (pt2.tgconstrname=pt.tgconstrname) "
2673 "AND (pt.tgconstrrelid=pc1.oid)) "
2674 "order by pt.tgconstrname", escFkTableName);
2676 result = PGAPI_ExecDirect(htbl_stmt,
2677 (const UCHAR *)tables_query, SQL_NTS, 0);
2679 if (!SQL_SUCCEEDED(result))
2681 SC_full_error_copy(stmt, tbl_stmt, FALSE);
2682 goto cleanup;
2685 result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_BINARY,
2686 trig_args, sizeof(trig_args), NULL);
2687 if (!SQL_SUCCEEDED(result))
2689 SC_error_copy(stmt, tbl_stmt, TRUE);
2690 goto cleanup;
2693 result = PGAPI_BindCol(htbl_stmt, 2, SQL_C_SHORT,
2694 &trig_nargs, 0, NULL);
2695 if (!SQL_SUCCEEDED(result))
2697 SC_error_copy(stmt, tbl_stmt, TRUE);
2698 goto cleanup;
2701 result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
2702 trig_deferrable, sizeof(trig_deferrable),
2703 NULL);
2704 if (!SQL_SUCCEEDED(result))
2706 SC_error_copy(stmt, tbl_stmt, TRUE);
2707 goto cleanup;
2710 result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type,
2711 trig_initdeferred,
2712 sizeof(trig_initdeferred), NULL);
2713 if (!SQL_SUCCEEDED(result))
2715 SC_error_copy(stmt, tbl_stmt, TRUE);
2716 goto cleanup;
2719 result = PGAPI_BindCol(htbl_stmt, 5, internal_asis_type,
2720 upd_rule, sizeof(upd_rule), NULL);
2721 if (!SQL_SUCCEEDED(result))
2723 SC_error_copy(stmt, tbl_stmt, TRUE);
2724 goto cleanup;
2727 result = PGAPI_BindCol(htbl_stmt, 6, internal_asis_type,
2728 del_rule, sizeof(del_rule), NULL);
2729 if (!SQL_SUCCEEDED(result))
2731 SC_error_copy(stmt, tbl_stmt, TRUE);
2732 goto cleanup;
2735 result = PGAPI_BindCol(htbl_stmt, 7, SQL_C_ULONG,
2736 &relid1, sizeof(relid1), NULL);
2737 if (!SQL_SUCCEEDED(result))
2739 SC_error_copy(stmt, tbl_stmt, TRUE);
2740 goto cleanup;
2742 result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG,
2743 &relid2, sizeof(relid2), NULL);
2744 if (!SQL_SUCCEEDED(result))
2746 SC_error_copy(stmt, tbl_stmt, TRUE);
2747 goto cleanup;
2749 result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type,
2750 pk_table_fetched, TABLE_NAME_STORAGE_LEN,
2751 NULL);
2752 if (!SQL_SUCCEEDED(result))
2754 SC_error_copy(stmt, tbl_stmt, TRUE);
2755 goto cleanup;
2757 result = PGAPI_BindCol(htbl_stmt, 10, internal_asis_type,
2758 constrname, NAMESTORAGELEN, NULL);
2759 if (!SQL_SUCCEEDED(result))
2761 SC_error_copy(stmt, tbl_stmt, TRUE);
2762 goto cleanup;
2765 if (conn->schema_support)
2767 result = PGAPI_BindCol(htbl_stmt, 11, internal_asis_type,
2768 schema_fetched,
2769 SCHEMA_NAME_STORAGE_LEN, NULL);
2770 if (!SQL_SUCCEEDED(result))
2772 SC_error_copy(stmt, tbl_stmt, TRUE);
2773 goto cleanup;
2777 result = PGAPI_Fetch(htbl_stmt);
2778 if (result == SQL_NO_DATA_FOUND)
2780 ret = SQL_SUCCESS;
2781 goto cleanup;
2784 if (result != SQL_SUCCESS)
2786 SC_full_error_copy(stmt, tbl_stmt, FALSE);
2787 goto cleanup;
2790 keyresult = PGAPI_AllocStmt(conn, &hpkey_stmt);
2791 if (!SQL_SUCCEEDED(keyresult))
2793 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
2794 "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.",
2795 func);
2796 goto cleanup;
2799 keyresult = PGAPI_BindCol(hpkey_stmt, 4, internal_asis_type,
2800 pkey, sizeof(pkey), NULL);
2801 if (keyresult != SQL_SUCCESS)
2803 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
2804 "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.",
2805 func);
2806 goto cleanup;
2809 while (result == SQL_SUCCESS)
2811 /* Compute the number of keyparts. */
2812 num_keys = (trig_nargs - 4) / 2;
2814 mylog
2815 ("Foreign Key Case#2: trig_nargs = %d, num_keys = %d\n",
2816 trig_nargs, num_keys);
2818 /* If there is a pk table specified, then check it. */
2819 if (pk_table_needed && pk_table_needed[0] != '\0')
2821 /* If it doesn't match, then continue */
2822 if (strcmp(pk_table_fetched, pk_table_needed))
2824 result = PGAPI_Fetch(htbl_stmt);
2825 continue;
2829 got_pkname = FALSE;
2830 keyresult =
2831 PGAPI_PrimaryKeys(hpkey_stmt, NULL, 0,
2832 (const UCHAR *)schema_fetched,
2833 SQL_NTS, (const UCHAR *)pk_table_fetched,
2834 SQL_NTS);
2835 if (keyresult != SQL_SUCCESS)
2837 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
2838 "Couldn't get primary keys for PGAPI_ForeignKeys result.",
2839 func);
2840 goto cleanup;
2843 /* Get to first primary key */
2844 pkey_ptr = trig_args;
2845 for (i = 0; i < 5; i++)
2846 pkey_ptr += strlen(pkey_ptr) + 1;
2848 for (k = 0; k < num_keys; k++)
2850 /* Check that the key listed is the primary key */
2851 keyresult = PGAPI_Fetch(hpkey_stmt);
2852 if (keyresult != SQL_SUCCESS)
2854 num_keys = 0;
2855 break;
2857 if (!got_pkname)
2859 PGAPI_GetData(hpkey_stmt, 6, internal_asis_type,
2860 pkname, sizeof(pkname), NULL);
2861 got_pkname = TRUE;
2863 pkey_text =
2864 getClientColumnName(conn, relid2, pkey_ptr,
2865 &pkey_alloced);
2866 mylog("%s: pkey_ptr='%s', pkey='%s'\n", func, pkey_text,
2867 pkey);
2868 if (strcmp(pkey_text, pkey))
2870 num_keys = 0;
2871 break;
2873 if (pkey_alloced)
2874 free(pkey_text);
2875 /* Get to next primary key */
2876 for (k = 0; k < 2; k++)
2877 pkey_ptr += strlen(pkey_ptr) + 1;
2880 PGAPI_FreeStmt(hpkey_stmt, SQL_CLOSE);
2882 /* Set to first fk column */
2883 fkey_ptr = trig_args;
2884 for (k = 0; k < 4; k++)
2885 fkey_ptr += strlen(fkey_ptr) + 1;
2887 /* Set update and delete actions for foreign keys */
2888 if (!strcmp(upd_rule, "RI_FKey_cascade_upd"))
2889 upd_rule_type = SQL_CASCADE;
2890 else if (!strcmp(upd_rule, "RI_FKey_noaction_upd"))
2891 upd_rule_type = SQL_NO_ACTION;
2892 else if (!strcmp(upd_rule, "RI_FKey_restrict_upd"))
2893 upd_rule_type = SQL_NO_ACTION;
2894 else if (!strcmp(upd_rule, "RI_FKey_setdefault_upd"))
2895 upd_rule_type = SQL_SET_DEFAULT;
2896 else if (!strcmp(upd_rule, "RI_FKey_setnull_upd"))
2897 upd_rule_type = SQL_SET_NULL;
2899 if (!strcmp(del_rule, "RI_FKey_cascade_del"))
2900 del_rule_type = SQL_CASCADE;
2901 else if (!strcmp(del_rule, "RI_FKey_noaction_del"))
2902 del_rule_type = SQL_NO_ACTION;
2903 else if (!strcmp(del_rule, "RI_FKey_restrict_del"))
2904 del_rule_type = SQL_NO_ACTION;
2905 else if (!strcmp(del_rule, "RI_FKey_setdefault_del"))
2906 del_rule_type = SQL_SET_DEFAULT;
2907 else if (!strcmp(del_rule, "RI_FKey_setnull_del"))
2908 del_rule_type = SQL_SET_NULL;
2910 /* Set deferrability type */
2911 if (!strcmp(trig_initdeferred, "y"))
2912 defer_type = SQL_INITIALLY_DEFERRED;
2913 else if (!strcmp(trig_deferrable, "y"))
2914 defer_type = SQL_INITIALLY_IMMEDIATE;
2915 else
2916 defer_type = SQL_NOT_DEFERRABLE;
2918 /* Get to first primary key */
2919 pkey_ptr = trig_args;
2920 for (i = 0; i < 5; i++)
2921 pkey_ptr += strlen(pkey_ptr) + 1;
2923 for (k = 0; k < num_keys; k++)
2925 tuple = QR_AddNew(res);
2927 pkey_text =
2928 getClientColumnName(conn, relid2, pkey_ptr,
2929 &pkey_alloced);
2930 fkey_text =
2931 getClientColumnName(conn, relid1, fkey_ptr,
2932 &fkey_alloced);
2934 mylog("%s: pk_table = '%s', pkey_ptr = '%s'\n", func,
2935 pk_table_fetched, pkey_text);
2936 set_tuplefield_string(&tuple[FKS_PKTABLE_CAT],
2937 CurrCat(conn));
2938 set_tuplefield_string(&tuple[FKS_PKTABLE_SCHEM],
2939 GET_SCHEMA_NAME(schema_fetched));
2940 set_tuplefield_string(&tuple[FKS_PKTABLE_NAME],
2941 pk_table_fetched);
2942 set_tuplefield_string(&tuple[FKS_PKCOLUMN_NAME],
2943 pkey_text);
2945 mylog("%s: fk_table_needed = '%s', fkey_ptr = '%s'\n",
2946 func, fk_table_needed, fkey_text);
2947 set_tuplefield_null(&tuple[FKS_FKTABLE_CAT]);
2948 set_tuplefield_string(&tuple[FKS_FKTABLE_SCHEM],
2949 GET_SCHEMA_NAME(schema_needed));
2950 set_tuplefield_string(&tuple[FKS_FKTABLE_NAME],
2951 fk_table_needed);
2952 set_tuplefield_string(&tuple[FKS_FKCOLUMN_NAME],
2953 fkey_text);
2955 mylog
2956 ("%s: upd_rule_type = '%i', del_rule_type = '%i'\n, trig_name = '%s'",
2957 func, upd_rule_type, del_rule_type, trig_args);
2958 set_tuplefield_int2(&tuple[FKS_KEY_SEQ],
2959 (Int2) (k + 1));
2960 set_tuplefield_int2(&tuple[FKS_UPDATE_RULE],
2961 upd_rule_type);
2962 set_tuplefield_int2(&tuple[FKS_DELETE_RULE],
2963 del_rule_type);
2964 set_tuplefield_string(&tuple[FKS_FK_NAME], constrname);
2965 set_tuplefield_string(&tuple[FKS_PK_NAME], pkname);
2966 set_tuplefield_int2(&tuple[FKS_DEFERRABILITY],
2967 defer_type);
2968 set_tuplefield_string(&tuple[FKS_TRIGGER_NAME],
2969 trig_args);
2971 if (fkey_alloced)
2972 free(fkey_text);
2973 fkey_alloced = FALSE;
2974 if (pkey_alloced)
2975 free(pkey_text);
2976 pkey_alloced = FALSE;
2977 /* next primary/foreign key */
2978 for (i = 0; i < 2; i++)
2980 fkey_ptr += strlen(fkey_ptr) + 1;
2981 pkey_ptr += strlen(pkey_ptr) + 1;
2985 result = PGAPI_Fetch(htbl_stmt);
2990 * Case #1 -- Get the foreign keys in other tables that refer to the
2991 * primary key in the specified table (pktab). i.e., Who points to
2992 * me?
2994 else if (pk_table_needed[0] != '\0')
2996 escPkTableName =
2997 simpleCatalogEscape(pk_table_needed, SQL_NTS, NULL, conn);
2998 if (conn->schema_support)
3000 char *escSchemaName;
3002 schema_strcat(schema_needed, "%.*s",
3003 (const char *)szPkTableOwner,
3004 cbPkTableOwner, (const char *)szPkTableName,
3005 cbPkTableName, conn);
3006 escSchemaName =
3007 simpleCatalogEscape(schema_needed, SQL_NTS, NULL, conn);
3008 snprintf(tables_query, sizeof(tables_query),
3009 "SELECT pt.tgargs, " " pt.tgnargs, "
3010 " pt.tgdeferrable, "
3011 " pt.tginitdeferred, " " pp1.proname, "
3012 " pp2.proname, "
3013 " pc.oid, "
3014 " pc1.oid, "
3015 " pc1.relname, "
3016 " pt.tgconstrname, pn1.nspname "
3017 "FROM pg_catalog.pg_class pc, "
3018 " pg_catalog.pg_class pc1, "
3019 " pg_catalog.pg_proc pp, "
3020 " pg_catalog.pg_proc pp1, "
3021 " pg_catalog.pg_proc pp2, "
3022 " pg_catalog.pg_trigger pt, "
3023 " pg_catalog.pg_trigger pt1, "
3024 " pg_catalog.pg_trigger pt2, "
3025 " pg_catalog.pg_namespace pn, "
3026 " pg_catalog.pg_namespace pn1 "
3027 "WHERE pc.relname='%s' "
3028 " AND pn.nspname = '%s' "
3029 " AND pc.relnamespace = pn.oid "
3030 " AND pt.tgconstrrelid = pc.oid "
3031 " AND pp.oid = pt.tgfoid "
3032 " AND pp.proname Like '%%ins' "
3033 " AND pt1.tgconstrname = pt.tgconstrname "
3034 " AND pt1.tgconstrrelid = pt.tgrelid "
3035 " AND pt1.tgrelid = pc.oid "
3036 " AND pc1.oid = pt.tgrelid "
3037 " AND pp1.oid = pt1.tgfoid "
3038 " AND pp1.proname like '%%upd' "
3039 " AND (pp1.proname not like '%%check%%') "
3040 " AND pt2.tgconstrname = pt.tgconstrname "
3041 " AND pt2.tgconstrrelid = pt.tgrelid "
3042 " AND pt2.tgrelid = pc.oid "
3043 " AND pp2.oid = pt2.tgfoid "
3044 " AND pp2.proname Like '%%del' "
3045 " AND pn1.oid = pc1.relnamespace "
3046 " order by pt.tgconstrname",
3047 escPkTableName, escSchemaName);
3048 free(escSchemaName);
3050 else
3051 snprintf(tables_query, sizeof(tables_query),
3052 "SELECT pt.tgargs, " " pt.tgnargs, "
3053 " pt.tgdeferrable, "
3054 " pt.tginitdeferred, " " pp1.proname, "
3055 " pp2.proname, "
3056 " pc.oid, "
3057 " pc1.oid, "
3058 " pc1.relname, pt.tgconstrname "
3059 "FROM pg_class pc, "
3060 " pg_class pc1, "
3061 " pg_proc pp, "
3062 " pg_proc pp1, "
3063 " pg_proc pp2, "
3064 " pg_trigger pt, "
3065 " pg_trigger pt1, "
3066 " pg_trigger pt2 "
3067 "WHERE pc.relname ='%s' "
3068 " AND pt.tgconstrrelid = pc.oid "
3069 " AND pp.oid = pt.tgfoid "
3070 " AND pp.proname Like '%%ins' "
3071 " AND pt1.tgconstrname = pt.tgconstrname "
3072 " AND pt1.tgconstrrelid = pt.tgrelid "
3073 " AND pt1.tgrelid = pc.oid "
3074 " AND pc1.oid = pt.tgrelid "
3075 " AND pp1.oid = pt1.tgfoid "
3076 " AND pp1.proname like '%%upd' "
3077 " AND pp1.(proname not like '%%check%%') "
3078 " AND pt2.tgconstrname = pt.tgconstrname "
3079 " AND pt2.tgconstrrelid = pt.tgrelid "
3080 " AND pt2.tgrelid = pc.oid "
3081 " AND pp2.oid = pt2.tgfoid "
3082 " AND pp2.proname Like '%%del'"
3083 " order by pt.tgconstrname", escPkTableName);
3085 result = PGAPI_ExecDirect(htbl_stmt, (const UCHAR *)tables_query,
3086 SQL_NTS, 0);
3087 if (!SQL_SUCCEEDED(result))
3089 SC_error_copy(stmt, tbl_stmt, TRUE);
3090 goto cleanup;
3093 result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_BINARY,
3094 trig_args, sizeof(trig_args), NULL);
3095 if (!SQL_SUCCEEDED(result))
3097 SC_error_copy(stmt, tbl_stmt, TRUE);
3098 goto cleanup;
3101 result = PGAPI_BindCol(htbl_stmt, 2, SQL_C_SHORT,
3102 &trig_nargs, 0, NULL);
3103 if (!SQL_SUCCEEDED(result))
3105 SC_error_copy(stmt, tbl_stmt, TRUE);
3106 goto cleanup;
3109 result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
3110 trig_deferrable, sizeof(trig_deferrable),
3111 NULL);
3112 if (!SQL_SUCCEEDED(result))
3114 SC_error_copy(stmt, tbl_stmt, TRUE);
3115 goto cleanup;
3118 result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type,
3119 trig_initdeferred,
3120 sizeof(trig_initdeferred), NULL);
3121 if (!SQL_SUCCEEDED(result))
3123 SC_error_copy(stmt, tbl_stmt, TRUE);
3124 goto cleanup;
3127 result = PGAPI_BindCol(htbl_stmt, 5, internal_asis_type,
3128 upd_rule, sizeof(upd_rule), NULL);
3129 if (!SQL_SUCCEEDED(result))
3131 SC_error_copy(stmt, tbl_stmt, TRUE);
3132 goto cleanup;
3135 result = PGAPI_BindCol(htbl_stmt, 6, internal_asis_type,
3136 del_rule, sizeof(del_rule), NULL);
3137 if (!SQL_SUCCEEDED(result))
3139 SC_error_copy(stmt, tbl_stmt, TRUE);
3140 goto cleanup;
3143 result = PGAPI_BindCol(htbl_stmt, 7, SQL_C_ULONG,
3144 &relid1, sizeof(relid1), NULL);
3145 if (!SQL_SUCCEEDED(result))
3147 SC_error_copy(stmt, tbl_stmt, TRUE);
3148 goto cleanup;
3150 result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG,
3151 &relid2, sizeof(relid2), NULL);
3152 if (!SQL_SUCCEEDED(result))
3154 SC_error_copy(stmt, tbl_stmt, TRUE);
3155 goto cleanup;
3157 result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type,
3158 fk_table_fetched, TABLE_NAME_STORAGE_LEN,
3159 NULL);
3160 if (!SQL_SUCCEEDED(result))
3162 SC_error_copy(stmt, tbl_stmt, TRUE);
3163 goto cleanup;
3165 result = PGAPI_BindCol(htbl_stmt, 10, internal_asis_type,
3166 constrname, NAMESTORAGELEN, NULL);
3167 if (!SQL_SUCCEEDED(result))
3169 SC_error_copy(stmt, tbl_stmt, TRUE);
3170 goto cleanup;
3173 if (conn->schema_support)
3175 result = PGAPI_BindCol(htbl_stmt, 11, internal_asis_type,
3176 schema_fetched,
3177 SCHEMA_NAME_STORAGE_LEN, NULL);
3178 if (!SQL_SUCCEEDED(result))
3180 SC_error_copy(stmt, tbl_stmt, TRUE);
3181 goto cleanup;
3185 result = PGAPI_Fetch(htbl_stmt);
3186 if (result == SQL_NO_DATA_FOUND)
3188 ret = SQL_SUCCESS;
3189 goto cleanup;
3192 if (result != SQL_SUCCESS)
3194 SC_full_error_copy(stmt, tbl_stmt, FALSE);
3195 goto cleanup;
3199 * get pk_name here
3201 keyresult = PGAPI_AllocStmt(conn, &hpkey_stmt);
3202 if (!SQL_SUCCEEDED(keyresult))
3204 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
3205 "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.",
3206 func);
3207 goto cleanup;
3209 keyresult = PGAPI_BindCol(hpkey_stmt, 6, internal_asis_type,
3210 pkname, sizeof(pkname), NULL);
3211 if (keyresult != SQL_SUCCESS)
3213 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
3214 "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.",
3215 func);
3216 goto cleanup;
3218 keyresult =
3219 PGAPI_PrimaryKeys(hpkey_stmt, NULL, 0,
3220 (const UCHAR *)schema_needed,
3221 SQL_NTS, (const UCHAR *)pk_table_needed,
3222 SQL_NTS);
3223 if (keyresult != SQL_SUCCESS)
3225 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
3226 "Couldn't get primary keys for PGAPI_ForeignKeys result.",
3227 func);
3228 goto cleanup;
3230 pkname[0] = '\0';
3231 keyresult = PGAPI_Fetch(hpkey_stmt);
3232 PGAPI_FreeStmt(hpkey_stmt, SQL_CLOSE);
3233 while (result == SQL_SUCCESS)
3235 /* Calculate the number of key parts */
3236 num_keys = (trig_nargs - 4) / 2;;
3238 /* Handle action (i.e., 'cascade', 'restrict', 'setnull') */
3239 if (!strcmp(upd_rule, "RI_FKey_cascade_upd"))
3240 upd_rule_type = SQL_CASCADE;
3241 else if (!strcmp(upd_rule, "RI_FKey_noaction_upd"))
3242 upd_rule_type = SQL_NO_ACTION;
3243 else if (!strcmp(upd_rule, "RI_FKey_restrict_upd"))
3244 upd_rule_type = SQL_NO_ACTION;
3245 else if (!strcmp(upd_rule, "RI_FKey_setdefault_upd"))
3246 upd_rule_type = SQL_SET_DEFAULT;
3247 else if (!strcmp(upd_rule, "RI_FKey_setnull_upd"))
3248 upd_rule_type = SQL_SET_NULL;
3250 if (!strcmp(del_rule, "RI_FKey_cascade_del"))
3251 del_rule_type = SQL_CASCADE;
3252 else if (!strcmp(del_rule, "RI_FKey_noaction_del"))
3253 del_rule_type = SQL_NO_ACTION;
3254 else if (!strcmp(del_rule, "RI_FKey_restrict_del"))
3255 del_rule_type = SQL_NO_ACTION;
3256 else if (!strcmp(del_rule, "RI_FKey_setdefault_del"))
3257 del_rule_type = SQL_SET_DEFAULT;
3258 else if (!strcmp(del_rule, "RI_FKey_setnull_del"))
3259 del_rule_type = SQL_SET_NULL;
3261 /* Set deferrability type */
3262 if (!strcmp(trig_initdeferred, "y"))
3263 defer_type = SQL_INITIALLY_DEFERRED;
3264 else if (!strcmp(trig_deferrable, "y"))
3265 defer_type = SQL_INITIALLY_IMMEDIATE;
3266 else
3267 defer_type = SQL_NOT_DEFERRABLE;
3269 mylog
3270 ("Foreign Key Case#1: trig_nargs = %d, num_keys = %d\n",
3271 trig_nargs, num_keys);
3273 /* Get to first primary key */
3274 pkey_ptr = trig_args;
3275 for (i = 0; i < 5; i++)
3276 pkey_ptr += strlen(pkey_ptr) + 1;
3278 /* Get to first foreign key */
3279 fkey_ptr = trig_args;
3280 for (k = 0; k < 4; k++)
3281 fkey_ptr += strlen(fkey_ptr) + 1;
3283 for (k = 0; k < num_keys; k++)
3285 pkey_text =
3286 getClientColumnName(conn, relid1, pkey_ptr,
3287 &pkey_alloced);
3288 fkey_text =
3289 getClientColumnName(conn, relid2, fkey_ptr,
3290 &fkey_alloced);
3292 mylog
3293 ("pkey_ptr = '%s', fk_table = '%s', fkey_ptr = '%s'\n",
3294 pkey_text, fk_table_fetched, fkey_text);
3296 tuple = QR_AddNew(res);
3298 mylog("pk_table_needed = '%s', pkey_ptr = '%s'\n",
3299 pk_table_needed, pkey_text);
3300 set_tuplefield_string(&tuple[FKS_PKTABLE_CAT],
3301 CurrCat(conn));
3302 set_tuplefield_string(&tuple[FKS_PKTABLE_SCHEM],
3303 GET_SCHEMA_NAME(schema_needed));
3304 set_tuplefield_string(&tuple[FKS_PKTABLE_NAME],
3305 pk_table_needed);
3306 set_tuplefield_string(&tuple[FKS_PKCOLUMN_NAME],
3307 pkey_text);
3309 mylog("fk_table = '%s', fkey_ptr = '%s'\n",
3310 fk_table_fetched, fkey_text);
3311 set_tuplefield_null(&tuple[FKS_FKTABLE_CAT]);
3312 set_tuplefield_string(&tuple[FKS_FKTABLE_SCHEM],
3313 GET_SCHEMA_NAME(schema_fetched));
3314 set_tuplefield_string(&tuple[FKS_FKTABLE_NAME],
3315 fk_table_fetched);
3316 set_tuplefield_string(&tuple[FKS_FKCOLUMN_NAME],
3317 fkey_text);
3319 set_tuplefield_int2(&tuple[FKS_KEY_SEQ],
3320 (Int2) (k + 1));
3322 mylog("upd_rule = %d, del_rule= %d", upd_rule_type,
3323 del_rule_type);
3324 set_nullfield_int2(&tuple[FKS_UPDATE_RULE],
3325 upd_rule_type);
3326 set_nullfield_int2(&tuple[FKS_DELETE_RULE],
3327 del_rule_type);
3329 set_tuplefield_string(&tuple[FKS_FK_NAME], constrname);
3330 set_tuplefield_string(&tuple[FKS_PK_NAME], pkname);
3332 set_tuplefield_string(&tuple[FKS_TRIGGER_NAME],
3333 trig_args);
3335 mylog(" defer_type = %d\n", defer_type);
3336 set_tuplefield_int2(&tuple[FKS_DEFERRABILITY],
3337 defer_type);
3339 if (pkey_alloced)
3340 free(pkey_text);
3341 pkey_alloced = FALSE;
3342 if (fkey_alloced)
3343 free(fkey_text);
3344 fkey_alloced = FALSE;
3346 /* next primary/foreign key */
3347 for (j = 0; j < 2; j++)
3349 pkey_ptr += strlen(pkey_ptr) + 1;
3350 fkey_ptr += strlen(fkey_ptr) + 1;
3353 result = PGAPI_Fetch(htbl_stmt);
3356 else
3358 SC_set_error(stmt, STMT_INTERNAL_ERROR,
3359 "No tables specified to PGAPI_ForeignKeys.", func);
3360 goto cleanup;
3362 ret = SQL_SUCCESS;
3364 cleanup:
3365 #undef return
3367 * also, things need to think that this statement is finished so the
3368 * results can be retrieved.
3370 stmt->status = STMT_FINISHED;
3372 if (pkey_alloced)
3373 free(pkey_text);
3374 if (fkey_alloced)
3375 free(fkey_text);
3376 if (pk_table_needed)
3377 free(pk_table_needed);
3378 if (escPkTableName)
3379 free(escPkTableName);
3380 if (fk_table_needed)
3381 free(fk_table_needed);
3382 if (escFkTableName)
3383 free(escFkTableName);
3385 if (htbl_stmt)
3386 PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
3387 if (hpkey_stmt)
3388 PGAPI_FreeStmt(hpkey_stmt, SQL_DROP);
3390 /* set up the current tuple pointer for SQLFetch */
3391 stmt->currTuple = -1;
3392 SC_set_rowset_start(stmt, -1, FALSE);
3393 SC_set_current_col(stmt, -1);
3395 if (stmt->internal)
3396 ret = DiscardStatementSvp(stmt, ret, FALSE);
3397 mylog("%s(): EXIT, stmt=%p, ret=%d\n", func, stmt, ret);
3398 return ret;
3401 RETCODE SQL_API PGAPI_ProcedureColumns(HSTMT hstmt, const SQLCHAR FAR * szProcQualifier, /* OA X */
3402 SQLSMALLINT cbProcQualifier, const SQLCHAR FAR * szProcOwner, /* PV E */
3403 SQLSMALLINT cbProcOwner, const SQLCHAR FAR * szProcName, /* PV E */
3404 SQLSMALLINT cbProcName, const SQLCHAR FAR * szColumnName, /* PV X */
3405 SQLSMALLINT cbColumnName,
3406 UWORD flag)
3408 CSTR func = "PGAPI_ProcedureColumns";
3409 StatementClass *stmt = (StatementClass *) hstmt;
3410 ConnectionClass *conn = SC_get_conn(stmt);
3411 char proc_query[INFO_INQUIRY_LEN];
3412 Int2 result_cols;
3413 TupleField *tuple;
3414 const char *schema_name, *procname;
3415 char *escSchemaName = NULL, *escProcName = NULL;
3416 char *params, *delim = NULL;
3417 char *atttypid, *proargnames, *proargmodes;
3418 char *attname, *column_name;
3419 QResultClass *res, *tres;
3420 SQLLEN tcount;
3421 OID pgtype;
3422 Int4 paramcount, i, j;
3423 RETCODE result;
3424 BOOL search_pattern, bRetset;
3425 const char *like_or_eq, *retset;
3426 int ret_col = -1, ext_pos = -1, poid_pos = -1, attid_pos =
3427 -1, attname_pos = -1;
3428 UInt4 poid = 0, newpoid;
3430 mylog("%s: entering...\n", func);
3432 if (PG_VERSION_LT(conn, 6.5))
3434 SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR,
3435 "Version is too old", func);
3436 return SQL_ERROR;
3438 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
3439 return result;
3440 search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
3441 if (search_pattern)
3443 like_or_eq = likeop;
3444 escSchemaName =
3445 adjustLikePattern(szProcOwner, cbProcOwner,
3446 SEARCH_PATTERN_ESCAPE, NULL, conn);
3447 escProcName =
3448 adjustLikePattern(szProcName, cbProcName,
3449 SEARCH_PATTERN_ESCAPE, NULL, conn);
3451 else
3453 like_or_eq = eqop;
3454 escSchemaName =
3455 simpleCatalogEscape(szProcOwner, cbProcOwner, NULL, conn);
3456 escProcName =
3457 simpleCatalogEscape(szProcName, cbProcName, NULL, conn);
3459 if (conn->schema_support)
3461 strcpy(proc_query, "select proname, proretset, prorettype, "
3462 "pronargs, proargtypes, nspname, p.oid");
3463 ret_col = ext_pos = 7;
3464 poid_pos = 6;
3465 strcat(proc_query, ", atttypid, attname");
3466 attid_pos = ext_pos;
3467 attname_pos = ext_pos + 1;
3468 ret_col += 2;
3469 ext_pos = ret_col;
3470 if (PG_VERSION_GE(conn, 8.0))
3472 strcat(proc_query, ", proargnames");
3473 ret_col++;
3475 if (PG_VERSION_GE(conn, 8.1))
3477 strcat(proc_query, ", proargmodes, proallargtypes");
3478 ret_col += 2;
3480 strcat(proc_query,
3481 " from ((pg_catalog.pg_namespace n inner join"
3482 " pg_catalog.pg_proc p on p.pronamespace = n.oid)"
3483 " inner join pg_type t on t.oid = p.prorettype)"
3484 " left outer join pg_attribute a on a.attrelid = t.typrelid "
3485 " and attnum > 0 and not attisdropped where");
3486 strcat(proc_query, " has_function_privilege(p.oid, 'EXECUTE')");
3487 my_strcat1(proc_query, " and nspname %s '%.*s'", like_or_eq,
3488 escSchemaName, SQL_NTS);
3489 if (escProcName)
3490 snprintf_add(proc_query, sizeof(proc_query),
3491 " and proname %s '%s'", like_or_eq,
3492 escProcName);
3493 strcat(proc_query, " order by nspname, proname, p.oid, attnum");
3495 else
3497 strcpy(proc_query, "select proname, proretset, prorettype, "
3498 "pronargs, proargtypes from pg_proc where "
3499 "(not proretset)");
3500 ret_col = 5;
3501 if (escProcName)
3502 snprintf_add(proc_query, sizeof(proc_query),
3503 " and proname %s '%s'", like_or_eq,
3504 escProcName);
3505 strcat(proc_query, " order by proname, proretset");
3507 if (tres =
3508 CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN,
3509 stmt), !QR_command_maybe_successful(tres))
3511 SC_set_error(stmt, STMT_EXEC_ERROR,
3512 "PGAPI_ProcedureColumns query error", func);
3513 QR_Destructor(tres);
3514 return SQL_ERROR;
3517 if (res = QR_Constructor(), !res)
3519 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
3520 "Couldn't allocate memory for PGAPI_ProcedureColumns result.",
3521 func);
3522 return SQL_ERROR;
3524 SC_set_Result(stmt, res);
3527 * the binding structure for a statement is not set up until
3528 * a statement is actually executed, so we'll have to do this
3529 * ourselves.
3531 result_cols = NUM_OF_PROCOLS_FIELDS;
3532 extend_column_bindings(SC_get_ARDF(stmt), result_cols);
3534 /* set the field names */
3535 QR_set_num_fields(res, result_cols);
3536 QR_set_field_info_v(res, PROCOLS_PROCEDURE_CAT, "PROCEDURE_CAT",
3537 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3538 QR_set_field_info_v(res, PROCOLS_PROCEDURE_SCHEM, "PROCEDUR_SCHEM",
3539 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3540 QR_set_field_info_v(res, PROCOLS_PROCEDURE_NAME, "PROCEDURE_NAME",
3541 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3542 QR_set_field_info_v(res, PROCOLS_COLUMN_NAME, "COLUMN_NAME",
3543 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3544 QR_set_field_info_v(res, PROCOLS_COLUMN_TYPE, "COLUMN_TYPE",
3545 PG_TYPE_INT2, 2);
3546 QR_set_field_info_v(res, PROCOLS_DATA_TYPE, "DATA_TYPE",
3547 PG_TYPE_INT2, 2);
3548 QR_set_field_info_v(res, PROCOLS_TYPE_NAME, "TYPE_NAME",
3549 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3550 QR_set_field_info_v(res, PROCOLS_COLUMN_SIZE, "COLUMN_SIZE",
3551 PG_TYPE_INT4, 4);
3552 QR_set_field_info_v(res, PROCOLS_BUFFER_LENGTH, "BUFFER_LENGTH",
3553 PG_TYPE_INT4, 4);
3554 QR_set_field_info_v(res, PROCOLS_DECIMAL_DIGITS, "DECIMAL_DIGITS",
3555 PG_TYPE_INT2, 2);
3556 QR_set_field_info_v(res, PROCOLS_NUM_PREC_RADIX, "NUM_PREC_RADIX",
3557 PG_TYPE_INT2, 2);
3558 QR_set_field_info_v(res, PROCOLS_NULLABLE, "NULLABLE", PG_TYPE_INT2,
3560 QR_set_field_info_v(res, PROCOLS_REMARKS, "REMARKS",
3561 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3562 QR_set_field_info_v(res, PROCOLS_COLUMN_DEF, "COLUMN_DEF",
3563 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3564 QR_set_field_info_v(res, PROCOLS_SQL_DATA_TYPE, "SQL_DATA_TYPE",
3565 PG_TYPE_INT2, 2);
3566 QR_set_field_info_v(res, PROCOLS_SQL_DATETIME_SUB,
3567 "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
3568 QR_set_field_info_v(res, PROCOLS_CHAR_OCTET_LENGTH,
3569 "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
3570 QR_set_field_info_v(res, PROCOLS_ORDINAL_POSITION,
3571 "ORDINAL_POSITION", PG_TYPE_INT4, 4);
3572 QR_set_field_info_v(res, PROCOLS_IS_NULLABLE, "IS_NULLABLE",
3573 PG_TYPE_VARCHAR, MAX_INFO_STRING);
3575 column_name = make_string(szColumnName, cbColumnName, NULL, 0);
3576 if (column_name) /* column_name is unavailable now */
3578 tcount = 0;
3579 free(column_name);
3581 else
3582 tcount = QR_get_num_total_tuples(tres);
3583 for (i = 0, poid = 0; i < tcount; i++)
3585 if (conn->schema_support)
3586 schema_name =
3587 GET_SCHEMA_NAME(QR_get_value_backend_text(tres, i, 5));
3588 else
3589 schema_name = NULL;
3590 procname = QR_get_value_backend_text(tres, i, 0);
3591 retset = QR_get_value_backend_text(tres, i, 1);
3592 pgtype = QR_get_value_backend_int(tres, i, 2, NULL);
3593 bRetset = retset && (retset[0] == 't' || retset[0] == 'y');
3594 newpoid = 0;
3595 if (poid_pos >= 0)
3596 newpoid = QR_get_value_backend_int(tres, i, poid_pos, NULL);
3597 mylog("newpoid=%d\n", newpoid);
3598 atttypid = NULL;
3599 if (attid_pos >= 0)
3601 atttypid = (char *)QR_get_value_backend_text(tres, i, attid_pos);
3602 mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
3604 if (poid == 0 || newpoid != poid)
3606 poid = newpoid;
3607 proargmodes = NULL;
3608 proargnames = NULL;
3609 if (ext_pos >= 0)
3611 if (PG_VERSION_GE(conn, 8.0))
3612 proargnames = (char *)
3613 QR_get_value_backend_text(tres, i, ext_pos);
3614 if (PG_VERSION_GE(conn, 8.1))
3615 proargmodes = (char *)
3616 QR_get_value_backend_text(tres, i, ext_pos + 1);
3618 /* RETURN_VALUE info */
3619 if (0 != pgtype && PG_TYPE_VOID != pgtype && !bRetset
3620 && !atttypid && !proargmodes)
3622 tuple = QR_AddNew(res);
3623 set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_CAT],
3624 CurrCat(conn));
3625 set_nullfield_string(&tuple[PROCOLS_PROCEDURE_SCHEM],
3626 schema_name);
3627 set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_NAME],
3628 procname);
3629 set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME],
3630 NULL_STRING);
3631 set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE],
3632 SQL_RETURN_VALUE);
3633 set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE],
3634 pgtype_to_concise_type(stmt, pgtype,
3635 PG_STATIC));
3636 set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME],
3637 pgtype_to_name(stmt, pgtype,
3638 FALSE));
3639 set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE],
3640 pgtype_column_size(stmt, pgtype,
3641 PG_STATIC,
3642 PG_STATIC));
3643 set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH],
3644 pgtype_buffer_length(stmt, pgtype,
3645 PG_STATIC,
3646 PG_STATIC));
3647 set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS],
3648 pgtype_decimal_digits(stmt, pgtype,
3649 PG_STATIC));
3650 set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX],
3651 pgtype_radix(stmt, pgtype));
3652 set_tuplefield_int2(&tuple[PROCOLS_NULLABLE],
3653 SQL_NULLABLE_UNKNOWN);
3654 set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
3655 set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
3656 set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE],
3657 pgtype_to_sqldesctype(stmt, pgtype,
3658 PG_STATIC));
3659 set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB],
3660 pgtype_to_datetime_sub(stmt,
3661 pgtype));
3662 set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH],
3663 pgtype_transfer_octet_length(stmt,
3664 pgtype,
3665 PG_STATIC,
3666 PG_STATIC));
3667 set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION],
3669 set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE],
3670 NULL_STRING);
3672 if (proargmodes)
3674 const char *p;
3676 paramcount = 0;
3677 for (p = proargmodes; *p; p++)
3679 if (',' == (*p))
3680 paramcount++;
3682 paramcount++;
3683 params = (char *)
3684 QR_get_value_backend_text(tres, i, ext_pos + 2);
3685 if ('{' == *proargmodes)
3686 proargmodes++;
3687 if ('{' == *params)
3688 params++;
3690 else
3692 paramcount = QR_get_value_backend_int(tres, i, 3, NULL);
3693 params = (char *)QR_get_value_backend_text(tres, i, 4);
3695 if (proargnames)
3697 if ('{' == *proargnames)
3698 proargnames++;
3700 /* PARAMETERS info */
3701 for (j = 0; j < paramcount; j++)
3703 /* PG type of parameters */
3704 pgtype = 0;
3705 if (params)
3707 while (isspace(*params) || ',' == *params)
3708 params++;
3709 if ('\0' == *params || '}' == *params)
3710 params = NULL;
3711 else
3713 sscanf(params, "%u", &pgtype);
3714 while (isdigit(*params))
3715 params++;
3718 /* input/output type of parameters */
3719 if (proargmodes)
3721 while (isspace(*proargmodes) || ',' == *proargmodes)
3722 proargmodes++;
3723 if ('\0' == *proargmodes || '}' == *proargmodes)
3724 proargmodes = NULL;
3726 /* name of parameters */
3727 if (proargnames)
3729 while (isspace(*proargnames) || ',' == *proargnames)
3730 proargnames++;
3731 if ('\0' == *proargnames || '}' == *proargnames)
3732 proargnames = NULL;
3733 else if ('"' == *proargnames)
3735 proargnames++;
3736 for (delim = proargnames;
3737 *delim && *delim != '"'; delim++)
3740 else
3742 for (delim = proargnames;
3743 *delim && !isspace(*delim) && ',' != *delim
3744 && '}' != *delim; delim++)
3747 if (proargnames && '\0' == *delim) /* discard the incomplete name */
3748 proargnames = NULL;
3751 tuple = QR_AddNew(res);
3752 set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_CAT],
3753 CurrCat(conn));
3754 set_nullfield_string(&tuple[PROCOLS_PROCEDURE_SCHEM],
3755 schema_name);
3756 set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_NAME],
3757 procname);
3758 if (proargnames)
3760 *delim = '\0';
3761 set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME],
3762 proargnames);
3763 proargnames = delim + 1;
3765 else
3766 set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME],
3767 NULL_STRING);
3768 if (proargmodes)
3770 int ptype;
3772 switch (*proargmodes)
3774 case 'o':
3775 ptype = SQL_PARAM_OUTPUT;
3776 break;
3777 case 'b':
3778 ptype = SQL_PARAM_INPUT_OUTPUT;
3779 break;
3780 default:
3781 ptype = SQL_PARAM_INPUT;
3782 break;
3784 set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE],
3785 ptype);
3786 proargmodes++;
3788 else
3789 set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE],
3790 SQL_PARAM_INPUT);
3791 set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE],
3792 pgtype_to_concise_type(stmt, pgtype,
3793 PG_STATIC));
3794 set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME],
3795 pgtype_to_name(stmt, pgtype,
3796 FALSE));
3797 set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE],
3798 pgtype_column_size(stmt, pgtype,
3799 PG_STATIC,
3800 PG_STATIC));
3801 set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH],
3802 pgtype_buffer_length(stmt, pgtype,
3803 PG_STATIC,
3804 PG_STATIC));
3805 set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS],
3806 pgtype_decimal_digits(stmt, pgtype,
3807 PG_STATIC));
3808 set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX],
3809 pgtype_radix(stmt, pgtype));
3810 set_tuplefield_int2(&tuple[PROCOLS_NULLABLE],
3811 SQL_NULLABLE_UNKNOWN);
3812 set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
3813 set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
3814 set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE],
3815 pgtype_to_sqldesctype(stmt, pgtype,
3816 PG_STATIC));
3817 set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB],
3818 pgtype_to_datetime_sub(stmt,
3819 pgtype));
3820 set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH],
3821 pgtype_transfer_octet_length(stmt,
3822 pgtype,
3823 PG_STATIC,
3824 PG_STATIC));
3825 set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION],
3826 j + 1);
3827 set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE],
3828 NULL_STRING);
3831 /* RESULT Columns info */
3832 if (NULL != atttypid || bRetset)
3834 int typid;
3836 if (bRetset)
3838 typid = pgtype;
3839 attname = NULL;
3841 else
3843 typid = atoi(atttypid);
3844 attname = (char *)
3845 QR_get_value_backend_text(tres, i, attname_pos);
3847 tuple = QR_AddNew(res);
3848 set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_CAT],
3849 CurrCat(conn));
3850 set_nullfield_string(&tuple[PROCOLS_PROCEDURE_SCHEM],
3851 schema_name);
3852 set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_NAME],
3853 procname);
3854 set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME], attname);
3855 set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE],
3856 SQL_RESULT_COL);
3857 set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE],
3858 pgtype_to_concise_type(stmt, typid,
3859 PG_STATIC));
3860 set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME],
3861 pgtype_to_name(stmt, typid, FALSE));
3862 set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE],
3863 pgtype_column_size(stmt, typid,
3864 PG_STATIC,
3865 PG_STATIC));
3866 set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH],
3867 pgtype_buffer_length(stmt, typid,
3868 PG_STATIC,
3869 PG_STATIC));
3870 set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS],
3871 pgtype_decimal_digits(stmt, typid,
3872 PG_STATIC));
3873 set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX],
3874 pgtype_radix(stmt, typid));
3875 set_tuplefield_int2(&tuple[PROCOLS_NULLABLE],
3876 SQL_NULLABLE_UNKNOWN);
3877 set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
3878 set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
3879 set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE],
3880 pgtype_to_sqldesctype(stmt, typid,
3881 PG_STATIC));
3882 set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB],
3883 pgtype_to_datetime_sub(stmt, typid));
3884 set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH],
3885 pgtype_transfer_octet_length(stmt, typid,
3886 PG_STATIC,
3887 PG_STATIC));
3888 set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION], 0);
3889 set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE],
3890 NULL_STRING);
3893 QR_Destructor(tres);
3895 * also, things need to think that this statement is finished so the
3896 * results can be retrieved.
3898 if (escSchemaName)
3899 free(escSchemaName);
3900 if (escProcName)
3901 free(escProcName);
3902 stmt->status = STMT_FINISHED;
3903 /* set up the current tuple pointer for SQLFetch */
3904 stmt->currTuple = -1;
3905 SC_set_rowset_start(stmt, -1, FALSE);
3906 SC_set_current_col(stmt, -1);
3908 return SQL_SUCCESS;
3911 RETCODE SQL_API PGAPI_Procedures(HSTMT hstmt, const SQLCHAR FAR * szProcQualifier, /* OA X */
3912 SQLSMALLINT cbProcQualifier, const SQLCHAR FAR * szProcOwner, /* PV E */
3913 SQLSMALLINT cbProcOwner, const SQLCHAR FAR * szProcName, /* PV E */
3914 SQLSMALLINT cbProcName, UWORD flag)
3916 CSTR func = "PGAPI_Procedures";
3917 StatementClass *stmt = (StatementClass *) hstmt;
3918 ConnectionClass *conn = SC_get_conn(stmt);
3919 char proc_query[INFO_INQUIRY_LEN];
3920 char *escSchemaName = NULL, *escProcName = NULL;
3921 QResultClass *res;
3922 RETCODE result;
3923 const char *like_or_eq;
3924 BOOL search_pattern;
3926 mylog("%s: entering... scnm=%p len=%d\n", func, szProcOwner,
3927 cbProcOwner);
3929 if (PG_VERSION_LT(conn, 6.5))
3931 SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR,
3932 "Version is too old", func);
3933 return SQL_ERROR;
3935 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
3936 return result;
3938 search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
3939 if (search_pattern)
3941 like_or_eq = likeop;
3942 escSchemaName =
3943 adjustLikePattern(szProcOwner, cbProcOwner,
3944 SEARCH_PATTERN_ESCAPE, NULL, conn);
3945 escProcName =
3946 adjustLikePattern(szProcName, cbProcName,
3947 SEARCH_PATTERN_ESCAPE, NULL, conn);
3949 else
3951 like_or_eq = eqop;
3952 escSchemaName =
3953 simpleCatalogEscape(szProcOwner, cbProcOwner, NULL, conn);
3954 escProcName =
3955 simpleCatalogEscape(szProcName, cbProcName, NULL, conn);
3958 * The following seems the simplest implementation
3960 if (conn->schema_support)
3962 strcpy(proc_query,
3963 "select '' as " "PROCEDURE_CAT" ", nspname as "
3964 "PROCEDURE_SCHEM" "," " proname as " "PROCEDURE_NAME"
3965 ", '' as " "NUM_INPUT_PARAMS" "," " '' as "
3966 "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
3967 " '' as " "REMARKS" ","
3968 " case when prorettype = 0 then 1::int2 else 2::int2 end"
3969 " as " "PROCEDURE_TYPE" " from pg_catalog.pg_namespace,"
3970 " pg_catalog.pg_proc"
3971 " where pg_proc.pronamespace = pg_namespace.oid");
3972 schema_strcat1(proc_query, " and nspname %s '%.*s'", like_or_eq,
3973 escSchemaName, SQL_NTS,
3974 (const char *)szProcName, cbProcName, conn);
3975 my_strcat1(proc_query, " and proname %s '%.*s'", like_or_eq,
3976 escProcName, SQL_NTS);
3978 else
3980 strcpy(proc_query,
3981 "select '' as " "PROCEDURE_CAT" ", '' as "
3982 "PROCEDURE_SCHEM" "," " proname as " "PROCEDURE_NAME"
3983 ", '' as " "NUM_INPUT_PARAMS" "," " '' as "
3984 "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
3985 " '' as " "REMARKS" ","
3986 " case when prorettype = 0 then 1::int2 else 2::int2 end as "
3987 "PROCEDURE_TYPE" " from pg_proc");
3988 my_strcat1(proc_query, " where proname %s '%.*s'", like_or_eq,
3989 escSchemaName, SQL_NTS);
3992 if (res =
3993 CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN,
3994 stmt), !QR_command_maybe_successful(res))
3996 SC_set_error(stmt, STMT_EXEC_ERROR,
3997 "PGAPI_Procedures query error", func);
3998 QR_Destructor(res);
3999 return SQL_ERROR;
4001 SC_set_Result(stmt, res);
4004 * also, things need to think that this statement is finished so the
4005 * results can be retrieved.
4007 stmt->status = STMT_FINISHED;
4008 extend_column_bindings(SC_get_ARDF(stmt), 8);
4009 if (escSchemaName)
4010 free(escSchemaName);
4011 if (escProcName)
4012 free(escProcName);
4013 /* set up the current tuple pointer for SQLFetch */
4014 stmt->currTuple = -1;
4015 SC_set_rowset_start(stmt, -1, FALSE);
4016 SC_set_current_col(stmt, -1);
4018 return SQL_SUCCESS;
4021 #define ACLMAX 8
4022 #define ALL_PRIVILIGES "arwdRxt"
4023 static int usracl_auth(char *usracl, const char *auth)
4025 int i, j, addcnt = 0;
4027 for (i = 0; auth[i]; i++)
4029 for (j = 0; j < ACLMAX; j++)
4031 if (usracl[j] == auth[i])
4032 break;
4033 else if (!usracl[j])
4035 usracl[j] = auth[i];
4036 addcnt++;
4037 break;
4041 return addcnt;
4043 static void
4044 useracl_upd(char (*useracl)[ACLMAX], QResultClass * allures,
4045 const char *user, const char *auth)
4047 int usercount = (int) QR_get_num_cached_tuples(allures), i, addcnt =
4050 mylog("user=%s auth=%s\n", user, auth);
4051 if (user[0])
4052 for (i = 0; i < usercount; i++)
4054 if (strcmp(QR_get_value_backend_text(allures, i, 0), user)
4055 == 0)
4057 addcnt += usracl_auth(useracl[i], auth);
4058 break;
4061 else
4062 for (i = 0; i < usercount; i++)
4064 addcnt += usracl_auth(useracl[i], auth);
4066 mylog("addcnt=%d\n", addcnt);
4069 RETCODE SQL_API PGAPI_TablePrivileges(HSTMT hstmt, const SQLCHAR FAR * szTableQualifier, /* OA X */
4070 SQLSMALLINT cbTableQualifier, const SQLCHAR FAR * szTableOwner, /* PV E */
4071 SQLSMALLINT cbTableOwner, const SQLCHAR FAR * szTableName, /* PV E */
4072 SQLSMALLINT cbTableName,
4073 UWORD flag)
4075 StatementClass *stmt = (StatementClass *) hstmt;
4076 CSTR func = "PGAPI_TablePrivileges";
4077 ConnectionClass *conn = SC_get_conn(stmt);
4078 Int2 result_cols;
4079 char proc_query[INFO_INQUIRY_LEN];
4080 QResultClass *res, *wres = NULL, *allures = NULL;
4081 TupleField *tuple;
4082 Int4 tablecount, usercount, i, j, k;
4083 BOOL grpauth, sys, su;
4084 char (*useracl)[ACLMAX] = NULL, *acl, *user, *delim, *auth;
4085 const char *reln, *owner, *priv, *schnm = NULL;
4086 RETCODE result, ret = SQL_SUCCESS;
4087 const char *like_or_eq;
4088 const char *szSchemaName;
4089 SQLSMALLINT cbSchemaName;
4090 char *escSchemaName = NULL, *escTableName = NULL;
4091 BOOL search_pattern;
4093 mylog("%s: entering... scnm=%p len-%d\n", func,
4094 NULL_IF_NULL(szTableOwner), cbTableOwner);
4095 if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
4096 return result;
4099 * a statement is actually executed, so we'll have to do this
4100 * ourselves.
4102 result_cols = 7;
4103 extend_column_bindings(SC_get_ARDF(stmt), result_cols);
4105 stmt->catalog_result = TRUE;
4106 /* set the field names */
4107 res = QR_Constructor();
4108 SC_set_Result(stmt, res);
4109 QR_set_num_fields(res, result_cols);
4110 QR_set_field_info_v(res, 0, "TABLE_CAT", PG_TYPE_VARCHAR,
4111 MAX_INFO_STRING);
4112 QR_set_field_info_v(res, 1, "TABLE_SCHEM", PG_TYPE_VARCHAR,
4113 MAX_INFO_STRING);
4114 QR_set_field_info_v(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR,
4115 MAX_INFO_STRING);
4116 QR_set_field_info_v(res, 3, "GRANTOR", PG_TYPE_VARCHAR,
4117 MAX_INFO_STRING);
4118 QR_set_field_info_v(res, 4, "GRANTEE", PG_TYPE_VARCHAR,
4119 MAX_INFO_STRING);
4120 QR_set_field_info_v(res, 5, "PRIVILEGE", PG_TYPE_VARCHAR,
4121 MAX_INFO_STRING);
4122 QR_set_field_info_v(res, 6, "IS_GRANTABLE", PG_TYPE_VARCHAR,
4123 MAX_INFO_STRING);
4126 * also, things need to think that this statement is finished so the
4127 * results can be retrieved.
4129 stmt->status = STMT_FINISHED;
4130 /* set up the current tuple pointer for SQLFetch */
4131 stmt->currTuple = -1;
4132 SC_set_rowset_start(stmt, -1, FALSE);
4133 SC_set_current_col(stmt, -1);
4134 szSchemaName = (const char *)szTableOwner;
4135 cbSchemaName = cbTableOwner;
4137 #define return DONT_CALL_RETURN_FROM_HERE???
4138 search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
4139 if (search_pattern)
4141 like_or_eq = likeop;
4142 escTableName =
4143 adjustLikePattern(szTableName, cbTableName,
4144 SEARCH_PATTERN_ESCAPE, NULL, conn);
4146 else
4148 like_or_eq = eqop;
4149 escTableName =
4150 simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
4153 retry_public_schema:
4154 if (escSchemaName)
4155 free(escSchemaName);
4156 if (search_pattern)
4157 escSchemaName =
4158 adjustLikePattern(szSchemaName, cbSchemaName,
4159 SEARCH_PATTERN_ESCAPE, NULL, conn);
4160 else
4161 escSchemaName =
4162 simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn);
4163 if (conn->schema_support)
4164 strncpy_null(proc_query,
4165 "select relname, usename, relacl, nspname"
4166 " from pg_catalog.pg_namespace, pg_catalog.pg_class ,"
4167 " pg_catalog.pg_user where", sizeof(proc_query));
4168 else
4169 strncpy_null(proc_query, "select relname, usename, relacl"
4170 " from pg_class , pg_user where",
4171 sizeof(proc_query));
4172 if (conn->schema_support)
4174 if (escSchemaName)
4175 schema_strcat1(proc_query, " nspname %s '%.*s' and",
4176 like_or_eq, escSchemaName, SQL_NTS,
4177 (const char *)szTableName, cbTableName, conn);
4179 if (escTableName)
4180 snprintf_add(proc_query, sizeof(proc_query),
4181 " relname %s '%s' and", like_or_eq, escTableName);
4182 if (conn->schema_support)
4184 strcat(proc_query,
4185 " pg_namespace.oid = relnamespace and relkind in ('r', 'v') and");
4186 if ((!escTableName) && (!escSchemaName))
4187 strcat(proc_query,
4188 " nspname not in ('pg_catalog', 'information_schema') and");
4190 strcat(proc_query, " pg_user.usesysid = relowner");
4191 if (wres =
4192 CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN,
4193 stmt), !QR_command_maybe_successful(wres))
4195 SC_set_error(stmt, STMT_EXEC_ERROR,
4196 "PGAPI_TablePrivileges query error", func);
4197 ret = SQL_ERROR;
4198 goto cleanup;
4200 tablecount = (Int4) QR_get_num_cached_tuples(wres);
4201 /* If not found */
4202 if (conn->schema_support &&
4203 (flag & PODBC_SEARCH_PUBLIC_SCHEMA) != 0 && 0 == tablecount)
4205 const char *user = CC_get_username(conn);
4208 * If specified schema name == user_name and
4209 * the current schema is 'public',
4210 * retry the 'public' schema.
4212 if (szSchemaName &&
4213 (cbSchemaName == SQL_NTS ||
4214 cbSchemaName == (SQLSMALLINT) strlen(user)) &&
4215 strnicmp(szSchemaName, user, strlen(user)) == 0 &&
4216 stricmp(CC_get_current_schema(conn), pubstr) == 0)
4218 QR_Destructor(wres);
4219 wres = NULL;
4220 szSchemaName = pubstr;
4221 cbSchemaName = SQL_NTS;
4222 goto retry_public_schema;
4226 strncpy_null(proc_query,
4227 "select usename, usesysid, usesuper from pg_user",
4228 sizeof(proc_query));
4229 if (allures =
4230 CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN,
4231 stmt), !QR_command_maybe_successful(allures))
4233 SC_set_error(stmt, STMT_EXEC_ERROR,
4234 "PGAPI_TablePrivileges query error", func);
4235 ret = SQL_ERROR;
4236 goto cleanup;
4238 usercount = (Int4) QR_get_num_cached_tuples(allures);
4239 useracl =
4240 (char (*)[ACLMAX]) malloc(usercount * sizeof(char[ACLMAX]));
4241 for (i = 0; i < tablecount; i++)
4243 memset(useracl, 0, usercount * sizeof(char[ACLMAX]));
4244 acl = (char *) QR_get_value_backend_text(wres, i, 2);
4245 if (acl && acl[0] == '{')
4246 user = acl + 1;
4247 else
4248 user = NULL;
4249 for (; user && *user;)
4251 grpauth = FALSE;
4252 if (user[0] == '"' && strncmp(user + 1, "group ", 6) == 0)
4254 user += 7;
4255 grpauth = TRUE;
4257 if (delim = strchr(user, '='), !delim)
4258 break;
4259 *delim = '\0';
4260 auth = delim + 1;
4261 if (grpauth)
4263 if (delim = strchr(auth, '"'), delim)
4265 *delim = '\0';
4266 delim++;
4269 else if (delim = strchr(auth, ','), delim)
4270 *delim = '\0';
4271 else if (delim = strchr(auth, '}'), delim)
4272 *delim = '\0';
4273 if (grpauth) /* handle group privilege */
4275 QResultClass *gres;
4276 int i;
4277 char *grolist, *uid, *delm;
4279 snprintf(proc_query, sizeof(proc_query) - 1,
4280 "select grolist from pg_group where groname = '%s'",
4281 user);
4282 if (gres =
4283 CC_send_query(conn, proc_query, NULL,
4284 IGNORE_ABORT_ON_CONN, stmt),
4285 !QR_command_maybe_successful(gres))
4287 grolist = (char *)QR_get_value_backend_text(gres, 0, 0);
4288 if (grolist && grolist[0] == '{')
4290 for (uid = grolist + 1; *uid;)
4292 if (delm = strchr(uid, ','), delm)
4293 *delm = '\0';
4294 else if (delm = strchr(uid, '}'), delm)
4295 *delm = '\0';
4296 mylog("guid=%s\n", uid);
4297 for (i = 0; i < usercount; i++)
4299 if (strcmp
4300 (QR_get_value_backend_text
4301 (allures, i, 1), uid) == 0)
4302 useracl_upd(useracl, allures,
4303 QR_get_value_backend_text
4304 (allures, i, 0), auth);
4306 uid = delm + 1;
4310 QR_Destructor(gres);
4312 else
4313 useracl_upd(useracl, allures, user, auth);
4314 if (!delim)
4315 break;
4316 user = delim + 1;
4318 reln = QR_get_value_backend_text(wres, i, 0);
4319 owner = QR_get_value_backend_text(wres, i, 1);
4320 if (conn->schema_support)
4321 schnm = QR_get_value_backend_text(wres, i, 3);
4322 /* The owner has all privileges */
4323 useracl_upd(useracl, allures, owner, ALL_PRIVILIGES);
4324 for (j = 0; j < usercount; j++)
4326 user = (char *)QR_get_value_backend_text(allures, j, 0);
4327 su = (strcmp(QR_get_value_backend_text(allures, j, 2), "t")
4328 == 0);
4329 sys = (strcmp(user, owner) == 0);
4330 /* Super user has all privileges */
4331 if (su)
4332 useracl_upd(useracl, allures, user, ALL_PRIVILIGES);
4333 for (k = 0; k < ACLMAX; k++)
4335 if (!useracl[j][k])
4336 break;
4337 switch (useracl[j][k])
4339 case 'R': /* rule */
4340 case 't': /* trigger */
4341 continue;
4343 tuple = QR_AddNew(res);
4344 set_tuplefield_string(&tuple[0], CurrCat(conn));
4345 if (conn->schema_support)
4346 set_tuplefield_string(&tuple[1],
4347 GET_SCHEMA_NAME(schnm));
4348 else
4349 set_tuplefield_string(&tuple[1], NULL_STRING);
4350 set_tuplefield_string(&tuple[2], reln);
4351 if (su || sys)
4352 set_tuplefield_string(&tuple[3], "_SYSTEM");
4353 else
4354 set_tuplefield_string(&tuple[3], owner);
4355 mylog("user=%s\n", user);
4356 set_tuplefield_string(&tuple[4], user);
4357 switch (useracl[j][k])
4359 case 'a':
4360 priv = "INSERT";
4361 break;
4362 case 'r':
4363 priv = "SELECT";
4364 break;
4365 case 'w':
4366 priv = "UPDATE";
4367 break;
4368 case 'd':
4369 priv = "DELETE";
4370 break;
4371 case 'x':
4372 priv = "REFERENCES";
4373 break;
4374 default:
4375 priv = NULL_STRING;
4377 set_tuplefield_string(&tuple[5], priv);
4378 /* The owner and the super user are grantable */
4379 if (sys || su)
4380 set_tuplefield_string(&tuple[6], "YES");
4381 else
4382 set_tuplefield_string(&tuple[6], "NO");
4386 cleanup:
4387 #undef return
4388 if (escSchemaName)
4389 free(escSchemaName);
4390 if (escTableName)
4391 free(escTableName);
4392 if (useracl)
4393 free(useracl);
4394 if (wres)
4395 QR_Destructor(wres);
4396 if (allures)
4397 QR_Destructor(allures);
4398 if (stmt->internal)
4399 ret = DiscardStatementSvp(stmt, ret, FALSE);
4400 return ret;