4 * Description: This module contains routines related to
5 * ODBC informational functions.
9 * API functions: SQLGetInfo, SQLGetTypeInfo, SQLGetFunctions,
10 * SQLTables, SQLColumns, SQLStatistics, SQLSpecialColumns,
11 * SQLPrimaryKeys, SQLForeignKeys,
12 * SQLProcedureColumns(NI), SQLProcedures(NI),
13 * SQLTablePrivileges(NI), SQLColumnPrivileges(NI)
15 * Comments: See "notice.txt" for copyright and license information.
41 #include "connection.h"
42 #include "statement.h"
49 extern GLOBAL_VALUES globals;
53 RETCODE SQL_API SQLGetInfo(
58 SWORD FAR *pcbInfoValue)
60 char *func = "SQLGetInfo";
61 ConnectionClass *conn = (ConnectionClass *) hdbc;
65 CC_log_error(func, "", NULL);
66 return SQL_INVALID_HANDLE;
69 if (NULL == (char *)rgbInfoValue) {
70 CC_log_error(func, "Bad rgbInfoValue", conn);
71 return SQL_INVALID_HANDLE;
76 case SQL_ACCESSIBLE_PROCEDURES: /* ODBC 1.0 */
77 // can the user call all functions returned by SQLProcedures?
78 // I assume access permissions could prevent this in some cases(?)
79 // anyway, SQLProcedures doesn't exist yet.
80 if (pcbInfoValue) *pcbInfoValue = 1;
81 strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
84 case SQL_ACCESSIBLE_TABLES: /* ODBC 1.0 */
85 // is the user guaranteed "SELECT" on every table?
86 if (pcbInfoValue) *pcbInfoValue = 1;
87 strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
90 case SQL_ACTIVE_CONNECTIONS: /* ODBC 1.0 */
91 // how many simultaneous connections do we support?
92 *((WORD *)rgbInfoValue) = MAX_CONNECTIONS;
93 if(pcbInfoValue) { *pcbInfoValue = 2; }
96 case SQL_ACTIVE_STATEMENTS: /* ODBC 1.0 */
97 // no limit on the number of active statements.
98 *((WORD *)rgbInfoValue) = (WORD)0;
99 if(pcbInfoValue) { *pcbInfoValue = 2; }
102 case SQL_ALTER_TABLE: /* ODBC 2.0 */
103 // what does 'alter table' support? (bitmask)
104 // postgres doesn't seem to let you drop columns.
105 *((DWORD *)rgbInfoValue) = SQL_AT_ADD_COLUMN;
106 if(pcbInfoValue) { *pcbInfoValue = 4; }
109 case SQL_BOOKMARK_PERSISTENCE: /* ODBC 2.0 */
110 // through what operations do bookmarks persist? (bitmask)
111 // bookmarks don't exist yet, so they're not very persistent.
112 *((DWORD *)rgbInfoValue) = 0;
113 if(pcbInfoValue) { *pcbInfoValue = 4; }
116 case SQL_COLUMN_ALIAS: /* ODBC 2.0 */
117 // do we support column aliases? guess not.
118 if (pcbInfoValue) *pcbInfoValue = 1;
119 strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
122 case SQL_CONCAT_NULL_BEHAVIOR: /* ODBC 1.0 */
123 // how does concatenation work with NULL columns?
124 // not sure how you do concatentation, but this way seems
126 *((WORD *)rgbInfoValue) = SQL_CB_NON_NULL;
127 if(pcbInfoValue) { *pcbInfoValue = 2; }
130 // which types of data-conversion do we support?
131 // currently we don't support any, except converting a type
133 case SQL_CONVERT_BIGINT:
134 case SQL_CONVERT_BINARY:
135 case SQL_CONVERT_BIT:
136 case SQL_CONVERT_CHAR:
137 case SQL_CONVERT_DATE:
138 case SQL_CONVERT_DECIMAL:
139 case SQL_CONVERT_DOUBLE:
140 case SQL_CONVERT_FLOAT:
141 case SQL_CONVERT_INTEGER:
142 case SQL_CONVERT_LONGVARBINARY:
143 case SQL_CONVERT_LONGVARCHAR:
144 case SQL_CONVERT_NUMERIC:
145 case SQL_CONVERT_REAL:
146 case SQL_CONVERT_SMALLINT:
147 case SQL_CONVERT_TIME:
148 case SQL_CONVERT_TIMESTAMP:
149 case SQL_CONVERT_TINYINT:
150 case SQL_CONVERT_VARBINARY:
151 case SQL_CONVERT_VARCHAR: /* ODBC 1.0 */
152 // only return the type we were called with (bitmask)
153 *((DWORD *)rgbInfoValue) = fInfoType;
154 if(pcbInfoValue) { *pcbInfoValue = 4; }
157 case SQL_CONVERT_FUNCTIONS: /* ODBC 1.0 */
158 // which conversion functions do we support? (bitmask)
159 *((DWORD *)rgbInfoValue) = 0;
160 if(pcbInfoValue) { *pcbInfoValue = 4; }
163 case SQL_CORRELATION_NAME: /* ODBC 1.0 */
164 // I don't know what a correlation name is, so I guess we don't
167 // *((WORD *)rgbInfoValue) = (WORD)SQL_CN_NONE;
169 // well, let's just say we do--otherwise Query won't work.
170 *((WORD *)rgbInfoValue) = (WORD)SQL_CN_ANY;
171 if(pcbInfoValue) { *pcbInfoValue = 2; }
175 case SQL_CURSOR_COMMIT_BEHAVIOR: /* ODBC 1.0 */
176 // postgres definitely closes cursors when a transaction ends,
177 // but you shouldn't have to re-prepare a statement after
178 // commiting a transaction (I don't think)
179 *((WORD *)rgbInfoValue) = (WORD)SQL_CB_CLOSE;
180 if(pcbInfoValue) { *pcbInfoValue = 2; }
183 case SQL_CURSOR_ROLLBACK_BEHAVIOR: /* ODBC 1.0 */
185 *((WORD *)rgbInfoValue) = (WORD)SQL_CB_CLOSE;
186 if(pcbInfoValue) { *pcbInfoValue = 2; }
189 case SQL_DATA_SOURCE_NAME: /* ODBC 1.0 */
190 p = CC_get_DSN(conn);
191 if (pcbInfoValue) *pcbInfoValue = strlen(p);
192 strncpy_null((char *)rgbInfoValue, p, (size_t)cbInfoValueMax);
195 case SQL_DATA_SOURCE_READ_ONLY: /* ODBC 1.0 */
196 if (pcbInfoValue) *pcbInfoValue = 1;
197 sprintf((char *)rgbInfoValue, "%c", CC_is_readonly(conn) ? 'Y' : 'N');
200 case SQL_DATABASE_NAME: /* Support for old ODBC 1.0 Apps */
201 // case SQL_CURRENT_QUALIFIER:
202 // this tag doesn't seem to be in ODBC 2.0, and it conflicts
203 // with a valid tag (SQL_TIMEDATE_ADD_INTERVALS).
205 /* Returning the database name causes problems in MS Query.
206 It generates query like: "SELECT DISTINCT a FROM byronncrap3 crap3"
208 p = ""; // CC_get_database(conn);
209 if (pcbInfoValue) *pcbInfoValue = strlen(p);
210 strncpy_null((char *)rgbInfoValue, p, (size_t)cbInfoValueMax);
213 case SQL_DBMS_NAME: /* ODBC 1.0 */
214 if (pcbInfoValue) *pcbInfoValue = 10;
215 strncpy_null((char *)rgbInfoValue, DBMS_NAME, (size_t)cbInfoValueMax);
218 case SQL_DBMS_VER: /* ODBC 1.0 */
219 if (pcbInfoValue) *pcbInfoValue = 25;
220 strncpy_null((char *)rgbInfoValue, DBMS_VERSION, (size_t)cbInfoValueMax);
223 case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */
224 // are dirty reads, non-repeatable reads, and phantoms possible? (bitmask)
225 // by direct experimentation they are not. postgres forces
226 // the newer transaction to wait before doing something that
227 // would cause one of these problems.
228 *((DWORD *)rgbInfoValue) = SQL_TXN_SERIALIZABLE;
229 if(pcbInfoValue) { *pcbInfoValue = 4; }
232 case SQL_DRIVER_NAME: /* ODBC 1.0 */
233 // this should be the actual filename of the driver
234 p = DRIVER_FILE_NAME;
235 if (pcbInfoValue) *pcbInfoValue = strlen(p);
236 strncpy_null((char *)rgbInfoValue, p, (size_t)cbInfoValueMax);
239 case SQL_DRIVER_ODBC_VER:
240 if (pcbInfoValue) *pcbInfoValue = 5;
241 strncpy_null((char *)rgbInfoValue, "02.00", (size_t)cbInfoValueMax);
244 case SQL_DRIVER_VER: /* ODBC 1.0 */
245 p = POSTGRESDRIVERVERSION;
246 if (pcbInfoValue) *pcbInfoValue = strlen(p);
247 strncpy_null((char *)rgbInfoValue, p, (size_t)cbInfoValueMax);
250 case SQL_EXPRESSIONS_IN_ORDERBY: /* ODBC 1.0 */
251 // can you have expressions in an 'order by' clause?
252 // not sure about this. say no for now.
253 if (pcbInfoValue) *pcbInfoValue = 1;
254 strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
257 case SQL_FETCH_DIRECTION: /* ODBC 1.0 */
258 // which fetch directions are supported? (bitmask)
259 *((DWORD *)rgbInfoValue) = globals.use_declarefetch ? 0 : (SQL_FD_FETCH_NEXT |
263 SQL_FD_FETCH_ABSOLUTE);
264 if(pcbInfoValue) { *pcbInfoValue = 4; }
267 case SQL_FILE_USAGE: /* ODBC 2.0 */
268 // we are a two-tier driver, not a file-based one.
269 *((WORD *)rgbInfoValue) = (WORD)SQL_FILE_NOT_SUPPORTED;
270 if(pcbInfoValue) { *pcbInfoValue = 2; }
273 case SQL_GETDATA_EXTENSIONS: /* ODBC 2.0 */
275 *((DWORD *)rgbInfoValue) = (SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND);
276 if(pcbInfoValue) { *pcbInfoValue = 4; }
279 case SQL_GROUP_BY: /* ODBC 2.0 */
280 // how do the columns selected affect the columns you can group by?
281 *((WORD *)rgbInfoValue) = SQL_GB_GROUP_BY_EQUALS_SELECT;
282 if(pcbInfoValue) { *pcbInfoValue = 2; }
285 case SQL_IDENTIFIER_CASE: /* ODBC 1.0 */
286 // are identifiers case-sensitive (yes)
287 *((WORD *)rgbInfoValue) = SQL_IC_SENSITIVE;
288 if(pcbInfoValue) { *pcbInfoValue = 2; }
291 case SQL_IDENTIFIER_QUOTE_CHAR: /* ODBC 1.0 */
292 // the character used to quote "identifiers" (what are they?)
293 // the manual index lists 'owner names' and 'qualifiers' as
294 // examples of identifiers. it says return a blank for no
295 // quote character, we'll try that...
296 if (pcbInfoValue) *pcbInfoValue = 1;
297 strncpy_null((char *)rgbInfoValue, "\"", (size_t)cbInfoValueMax);
300 case SQL_KEYWORDS: /* ODBC 2.0 */
302 conn->errormsg = "SQL_KEYWORDS parameter to SQLGetInfo not implemented.";
303 conn->errornumber = CONN_NOT_IMPLEMENTED_ERROR;
304 CC_log_error(func, "", conn);
308 case SQL_LIKE_ESCAPE_CLAUSE: /* ODBC 2.0 */
309 // is there a character that escapes '%' and '_' in a LIKE clause?
310 // not as far as I can tell
311 if (pcbInfoValue) *pcbInfoValue = 1;
312 strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
315 case SQL_LOCK_TYPES: /* ODBC 2.0 */
316 // which lock types does SQLSetPos support? (bitmask)
317 // SQLSetPos doesn't exist yet
318 *((DWORD *)rgbInfoValue) = globals.lie ? (SQL_LCK_NO_CHANGE | SQL_LCK_EXCLUSIVE | SQL_LCK_UNLOCK) : 0;
319 if(pcbInfoValue) { *pcbInfoValue = 4; }
322 case SQL_MAX_BINARY_LITERAL_LEN: /* ODBC 2.0 */
323 // the maximum length of a query is 2k, so maybe we should
324 // set the maximum length of all these literals to that value?
325 // for now just use zero for 'unknown or no limit'
327 // maximum length of a binary literal
328 *((DWORD *)rgbInfoValue) = 0;
329 if(pcbInfoValue) { *pcbInfoValue = 4; }
332 case SQL_MAX_CHAR_LITERAL_LEN: /* ODBC 2.0 */
333 // maximum length of a character literal
334 *((DWORD *)rgbInfoValue) = 0;
335 if(pcbInfoValue) { *pcbInfoValue = 4; }
338 case SQL_MAX_COLUMN_NAME_LEN: /* ODBC 1.0 */
339 // maximum length of a column name
340 *((WORD *)rgbInfoValue) = MAX_COLUMN_LEN;
341 if(pcbInfoValue) { *pcbInfoValue = 2; }
344 case SQL_MAX_COLUMNS_IN_GROUP_BY: /* ODBC 2.0 */
345 // maximum number of columns in a 'group by' clause
346 *((WORD *)rgbInfoValue) = 0;
347 if(pcbInfoValue) { *pcbInfoValue = 2; }
350 case SQL_MAX_COLUMNS_IN_INDEX: /* ODBC 2.0 */
351 // maximum number of columns in an index
352 *((WORD *)rgbInfoValue) = 0;
353 if(pcbInfoValue) { *pcbInfoValue = 2; }
356 case SQL_MAX_COLUMNS_IN_ORDER_BY: /* ODBC 2.0 */
357 // maximum number of columns in an ORDER BY statement
358 *((WORD *)rgbInfoValue) = 0;
359 if(pcbInfoValue) { *pcbInfoValue = 2; }
362 case SQL_MAX_COLUMNS_IN_SELECT: /* ODBC 2.0 */
363 *((WORD *)rgbInfoValue) = 0;
364 if(pcbInfoValue) { *pcbInfoValue = 2; }
367 case SQL_MAX_COLUMNS_IN_TABLE: /* ODBC 2.0 */
368 *((WORD *)rgbInfoValue) = 0;
369 if(pcbInfoValue) { *pcbInfoValue = 2; }
372 case SQL_MAX_CURSOR_NAME_LEN: /* ODBC 1.0 */
373 *((WORD *)rgbInfoValue) = MAX_CURSOR_LEN;
374 if(pcbInfoValue) { *pcbInfoValue = 2; }
377 case SQL_MAX_INDEX_SIZE: /* ODBC 2.0 */
378 *((DWORD *)rgbInfoValue) = 0;
379 if(pcbInfoValue) { *pcbInfoValue = 4; }
382 case SQL_MAX_OWNER_NAME_LEN: /* ODBC 1.0 */
383 // the maximum length of a table owner's name. (0 == none)
384 // (maybe this should be 8)
385 *((WORD *)rgbInfoValue) = (WORD)0;
386 if(pcbInfoValue) { *pcbInfoValue = 2; }
389 case SQL_MAX_PROCEDURE_NAME_LEN: /* ODBC 1.0 */
390 *((WORD *)rgbInfoValue) = 0;
391 if(pcbInfoValue) { *pcbInfoValue = 2; }
394 case SQL_MAX_QUALIFIER_NAME_LEN: /* ODBC 1.0 */
395 *((WORD *)rgbInfoValue) = 0;
396 if(pcbInfoValue) { *pcbInfoValue = 2; }
399 case SQL_MAX_ROW_SIZE: /* ODBC 2.0 */
400 // the maximum size of one row
401 // here I do know a definite value
402 *((DWORD *)rgbInfoValue) = 8192;
403 if(pcbInfoValue) { *pcbInfoValue = 4; }
406 case SQL_MAX_ROW_SIZE_INCLUDES_LONG: /* ODBC 2.0 */
407 // does the preceding value include LONGVARCHAR and LONGVARBINARY
408 // fields? Well, it does include longvarchar, but not longvarbinary.
409 if (pcbInfoValue) *pcbInfoValue = 1;
410 strncpy_null((char *)rgbInfoValue, "Y", (size_t)cbInfoValueMax);
413 case SQL_MAX_STATEMENT_LEN: /* ODBC 2.0 */
414 // there should be a definite value here (2k?)
415 *((DWORD *)rgbInfoValue) = 0;
416 if(pcbInfoValue) { *pcbInfoValue = 4; }
419 case SQL_MAX_TABLE_NAME_LEN: /* ODBC 1.0 */
420 *((WORD *)rgbInfoValue) = MAX_TABLE_LEN;
421 if(pcbInfoValue) { *pcbInfoValue = 2; }
424 case SQL_MAX_TABLES_IN_SELECT: /* ODBC 2.0 */
425 *((WORD *)rgbInfoValue) = 0;
426 if(pcbInfoValue) { *pcbInfoValue = 2; }
429 case SQL_MAX_USER_NAME_LEN:
430 *(SWORD FAR *)rgbInfoValue = 0;
431 if(pcbInfoValue) { *pcbInfoValue = 2; }
434 case SQL_MULT_RESULT_SETS: /* ODBC 1.0 */
435 // do we support multiple result sets? Not really, but say yes anyway?
436 if (pcbInfoValue) *pcbInfoValue = 1;
437 strncpy_null((char *)rgbInfoValue, "Y", (size_t)cbInfoValueMax);
440 case SQL_MULTIPLE_ACTIVE_TXN: /* ODBC 1.0 */
441 // do we support multiple simultaneous transactions?
442 if (pcbInfoValue) *pcbInfoValue = 1;
443 strncpy_null((char *)rgbInfoValue, "Y", (size_t)cbInfoValueMax);
446 case SQL_NEED_LONG_DATA_LEN: /* ODBC 2.0 */
447 if (pcbInfoValue) *pcbInfoValue = 1;
448 /* Dont need the length, SQLPutData can handle any size and multiple calls */
449 strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
452 case SQL_NON_NULLABLE_COLUMNS: /* ODBC 1.0 */
453 *((WORD *)rgbInfoValue) = (WORD)SQL_NNC_NON_NULL;
454 if(pcbInfoValue) { *pcbInfoValue = 2; }
457 case SQL_NULL_COLLATION: /* ODBC 2.0 */
458 // where are nulls sorted?
459 *((WORD *)rgbInfoValue) = (WORD)SQL_NC_END;
460 if(pcbInfoValue) { *pcbInfoValue = 2; }
463 case SQL_NUMERIC_FUNCTIONS: /* ODBC 1.0 */
464 // what numeric functions are supported? (bitmask)
465 // I'm not sure if any of these are actually supported
466 *((DWORD *)rgbInfoValue) = 0;
467 if(pcbInfoValue) { *pcbInfoValue = 4; }
470 case SQL_ODBC_API_CONFORMANCE: /* ODBC 1.0 */
471 *((WORD *)rgbInfoValue) = SQL_OAC_LEVEL1;
472 if(pcbInfoValue) { *pcbInfoValue = 2; }
475 case SQL_ODBC_SAG_CLI_CONFORMANCE: /* ODBC 1.0 */
476 // can't find any reference to SAG in the ODBC reference manual
477 // (although it's in the index, it doesn't actually appear on
478 // the pages referenced)
479 *((WORD *)rgbInfoValue) = SQL_OSCC_NOT_COMPLIANT;
480 if(pcbInfoValue) { *pcbInfoValue = 2; }
483 case SQL_ODBC_SQL_CONFORMANCE: /* ODBC 1.0 */
484 *((WORD *)rgbInfoValue) = SQL_OSC_CORE;
485 if(pcbInfoValue) { *pcbInfoValue = 2; }
488 case SQL_ODBC_SQL_OPT_IEF: /* ODBC 1.0 */
489 // do we support the "Integrity Enhancement Facility" (?)
490 // (something to do with referential integrity?)
491 if (pcbInfoValue) *pcbInfoValue = 1;
492 strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
495 case SQL_ORDER_BY_COLUMNS_IN_SELECT: /* ODBC 2.0 */
496 // do the columns sorted by have to be in the list of
498 if (pcbInfoValue) *pcbInfoValue = 1;
499 strncpy_null((char *)rgbInfoValue, "Y", (size_t)cbInfoValueMax);
502 case SQL_OUTER_JOINS: /* ODBC 1.0 */
503 // do we support outer joins?
504 if (pcbInfoValue) *pcbInfoValue = 1;
505 strncpy_null((char *)rgbInfoValue, "N", (size_t)cbInfoValueMax);
508 case SQL_OWNER_TERM: /* ODBC 1.0 */
509 // what we call an owner
510 if (pcbInfoValue) *pcbInfoValue = 5;
511 strncpy_null((char *)rgbInfoValue, "owner", (size_t)cbInfoValueMax);
514 case SQL_OWNER_USAGE: /* ODBC 2.0 */
515 // in which statements can "owners be used"? (what does that mean?
516 // specifying 'owner.table' instead of just 'table' or something?)
518 *((DWORD *)rgbInfoValue) = 0;
519 if(pcbInfoValue) { *pcbInfoValue = 4; }
522 case SQL_POS_OPERATIONS: /* ODBC 2.0 */
523 // what functions does SQLSetPos support? (bitmask)
524 // SQLSetPos does not exist yet
525 *((DWORD *)rgbInfoValue) = globals.lie ? (SQL_POS_POSITION | SQL_POS_REFRESH | SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD) : 0;
526 if(pcbInfoValue) { *pcbInfoValue = 4; }
529 case SQL_POSITIONED_STATEMENTS: /* ODBC 2.0 */
530 // what 'positioned' functions are supported? (bitmask)
531 *((DWORD *)rgbInfoValue) = globals.lie ? (SQL_PS_POSITIONED_DELETE |
532 SQL_PS_POSITIONED_UPDATE |
533 SQL_PS_SELECT_FOR_UPDATE) : 0;
534 if(pcbInfoValue) { *pcbInfoValue = 4; }
537 case SQL_PROCEDURE_TERM: /* ODBC 1.0 */
538 // what do we call a procedure?
539 if (pcbInfoValue) *pcbInfoValue = 9;
540 strncpy_null((char *)rgbInfoValue, "procedure", (size_t)cbInfoValueMax);
543 case SQL_PROCEDURES: /* ODBC 1.0 */
544 // do we support procedures?
545 if (pcbInfoValue) *pcbInfoValue = 1;
546 strncpy_null((char *)rgbInfoValue, "Y", (size_t)cbInfoValueMax);
549 case SQL_QUALIFIER_LOCATION: /* ODBC 2.0 */
550 // where does the qualifier go (before or after the table name?)
551 // we don't really use qualifiers, so...
552 *((WORD *)rgbInfoValue) = SQL_QL_START;
553 if(pcbInfoValue) { *pcbInfoValue = 2; }
556 case SQL_QUALIFIER_NAME_SEPARATOR: /* ODBC 1.0 */
557 // not really too sure what a qualifier is supposed to do either
558 // (specify the name of a database in certain cases?), so nix
560 if (pcbInfoValue) *pcbInfoValue = 0;
561 strncpy_null((char *)rgbInfoValue, "", (size_t)cbInfoValueMax);
564 case SQL_QUALIFIER_TERM: /* ODBC 1.0 */
565 // what we call a qualifier
566 if (pcbInfoValue) *pcbInfoValue = 0;
567 strncpy_null((char *)rgbInfoValue, "", (size_t)cbInfoValueMax);
570 case SQL_QUALIFIER_USAGE: /* ODBC 2.0 */
571 // where can qualifiers be used? (bitmask)
573 *((DWORD *)rgbInfoValue) = 0;
574 if(pcbInfoValue) { *pcbInfoValue = 4; }
577 case SQL_QUOTED_IDENTIFIER_CASE: /* ODBC 2.0 */
578 // are "quoted" identifiers case-sensitive?
579 // well, we don't really let you quote identifiers, so...
580 *((WORD *)rgbInfoValue) = SQL_IC_SENSITIVE;
581 if(pcbInfoValue) { *pcbInfoValue = 2; }
584 case SQL_ROW_UPDATES: /* ODBC 1.0 */
585 // Driver doesn't support keyset-driven or mixed cursors, so
586 // not much point in saying row updates are supported
587 if (pcbInfoValue) *pcbInfoValue = 1;
588 strncpy_null((char *)rgbInfoValue, globals.lie ? "Y" : "N", (size_t)cbInfoValueMax);
591 case SQL_SCROLL_CONCURRENCY: /* ODBC 1.0 */
592 // what concurrency options are supported BY THE CURSOR? (bitmask)
593 *((DWORD *)rgbInfoValue) = globals.lie ? (SQL_SCCO_READ_ONLY |
595 SQL_SCCO_OPT_ROWVER |
596 SQL_SCCO_OPT_VALUES) : (SQL_SCCO_READ_ONLY);
597 if(pcbInfoValue) { *pcbInfoValue = 4; }
600 case SQL_SCROLL_OPTIONS: /* ODBC 1.0 */
601 // what options are supported for scrollable cursors? (bitmask)
602 // for declare/fetch, only FORWARD scrolling is allowed
603 // otherwise, the result set is STATIC (to SQLExtendedFetch for example)
604 *((DWORD *)rgbInfoValue) = globals.lie ? (SQL_SO_FORWARD_ONLY |
606 SQL_SO_KEYSET_DRIVEN |
608 SQL_SO_MIXED) : (globals.use_declarefetch ? SQL_SO_FORWARD_ONLY : (SQL_SO_FORWARD_ONLY | SQL_SO_STATIC));
609 if(pcbInfoValue) { *pcbInfoValue = 4; }
612 case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */
613 // this is supposed to be the character that escapes '_' or '%'
614 // in LIKE clauses. as far as I can tell postgres doesn't have one
615 // (backslash generates an error). returning an empty string means
616 // no escape character is supported.
617 if (pcbInfoValue) *pcbInfoValue = 0;
618 strncpy_null((char *)rgbInfoValue, "", (size_t)cbInfoValueMax);
621 case SQL_SERVER_NAME: /* ODBC 1.0 */
622 p = CC_get_server(conn);
623 if (pcbInfoValue) *pcbInfoValue = strlen(p);
624 strncpy_null((char *)rgbInfoValue, p, (size_t)cbInfoValueMax);
627 case SQL_SPECIAL_CHARACTERS: /* ODBC 2.0 */
628 // what special characters can be used in table and column names, etc.?
629 // probably more than just this...
630 if (pcbInfoValue) *pcbInfoValue = 1;
631 strncpy_null((char *)rgbInfoValue, "_", (size_t)cbInfoValueMax);
634 case SQL_STATIC_SENSITIVITY: /* ODBC 2.0 */
635 // can changes made inside a cursor be detected? (or something like that)
637 // only applies to SQLSetPos, which doesn't exist yet.
638 *((DWORD *)rgbInfoValue) = globals.lie ? (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES) : 0;
639 if(pcbInfoValue) { *pcbInfoValue = 4; }
642 case SQL_STRING_FUNCTIONS: /* ODBC 1.0 */
643 // what string functions exist? (bitmask)
644 *((DWORD *)rgbInfoValue) = (SQL_FN_STR_CONCAT |
650 SQL_FN_STR_SUBSTRING |
652 if(pcbInfoValue) { *pcbInfoValue = 4; }
655 case SQL_SUBQUERIES: /* ODBC 2.0 */
656 /* postgres 6.3 supports subqueries */
657 *((DWORD *)rgbInfoValue) = (SQL_SQ_QUANTIFIED |
661 if(pcbInfoValue) { *pcbInfoValue = 4; }
664 case SQL_SYSTEM_FUNCTIONS: /* ODBC 1.0 */
665 // what system functions are supported? (bitmask)
666 // none of these seem to be supported, either
667 *((DWORD *)rgbInfoValue) = 0;
668 if(pcbInfoValue) { *pcbInfoValue = 4; }
671 case SQL_TABLE_TERM: /* ODBC 1.0 */
672 // what we call a table
673 if (pcbInfoValue) *pcbInfoValue = 5;
674 strncpy_null((char *)rgbInfoValue, "table", (size_t)cbInfoValueMax);
677 case SQL_TIMEDATE_ADD_INTERVALS: /* ODBC 2.0 */
678 // what resolutions are supported by the "TIMESTAMPADD scalar
679 // function" (whatever that is)? (bitmask)
680 *((DWORD *)rgbInfoValue) = 0;
681 if(pcbInfoValue) { *pcbInfoValue = 4; }
684 case SQL_TIMEDATE_DIFF_INTERVALS: /* ODBC 2.0 */
685 // what resolutions are supported by the "TIMESTAMPDIFF scalar
686 // function" (whatever that is)? (bitmask)
687 *((DWORD *)rgbInfoValue) = 0;
688 if(pcbInfoValue) { *pcbInfoValue = 4; }
691 case SQL_TIMEDATE_FUNCTIONS: /* ODBC 1.0 */
692 // what time and date functions are supported? (bitmask)
693 *((DWORD *)rgbInfoValue) = (SQL_FN_TD_NOW);
694 if(pcbInfoValue) { *pcbInfoValue = 4; }
697 case SQL_TXN_CAPABLE: /* ODBC 1.0 */
698 *((WORD *)rgbInfoValue) = (WORD)SQL_TC_ALL;
699 // Postgres can deal with create or drop table statements in a transaction
700 if(pcbInfoValue) { *pcbInfoValue = 2; }
703 case SQL_TXN_ISOLATION_OPTION: /* ODBC 1.0 */
704 // what transaction isolation options are available? (bitmask)
705 // only the default--serializable transactions.
706 *((DWORD *)rgbInfoValue) = SQL_TXN_SERIALIZABLE;
707 if(pcbInfoValue) { *pcbInfoValue = 4; }
710 case SQL_UNION: /* ODBC 2.0 */
711 /* unions with all supported in postgres 6.3 */
712 *((DWORD *)rgbInfoValue) = (SQL_U_UNION | SQL_U_UNION_ALL);
713 if(pcbInfoValue) { *pcbInfoValue = 4; }
716 case SQL_USER_NAME: /* ODBC 1.0 */
717 p = CC_get_username(conn);
718 if (pcbInfoValue) *pcbInfoValue = strlen(p);
719 strncpy_null((char *)rgbInfoValue, p, (size_t)cbInfoValueMax);
723 /* unrecognized key */
724 conn->errormsg = "Unrecognized key passed to SQLGetInfo.";
725 conn->errornumber = CONN_NOT_IMPLEMENTED_ERROR;
726 CC_log_error(func, "", conn);
736 RETCODE SQL_API SQLGetTypeInfo(
740 char *func = "SQLGetTypeInfo";
741 StatementClass *stmt = (StatementClass *) hstmt;
746 mylog("**** in SQLGetTypeInfo: fSqlType = %d\n", fSqlType);
749 SC_log_error(func, "", NULL);
750 return SQL_INVALID_HANDLE;
753 stmt->manual_result = TRUE;
754 stmt->result = QR_Constructor();
755 if( ! stmt->result) {
756 SC_log_error(func, "Error creating result.", stmt);
760 extend_bindings(stmt, 15);
762 QR_set_num_fields(stmt->result, 15);
763 QR_set_field_info(stmt->result, 0, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
764 QR_set_field_info(stmt->result, 1, "DATA_TYPE", PG_TYPE_INT2, 2);
765 QR_set_field_info(stmt->result, 2, "PRECISION", PG_TYPE_INT4, 4);
766 QR_set_field_info(stmt->result, 3, "LITERAL_PREFIX", PG_TYPE_TEXT, MAX_INFO_STRING);
767 QR_set_field_info(stmt->result, 4, "LITERAL_SUFFIX", PG_TYPE_TEXT, MAX_INFO_STRING);
768 QR_set_field_info(stmt->result, 5, "CREATE_PARAMS", PG_TYPE_TEXT, MAX_INFO_STRING);
769 QR_set_field_info(stmt->result, 6, "NULLABLE", PG_TYPE_INT2, 2);
770 QR_set_field_info(stmt->result, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2);
771 QR_set_field_info(stmt->result, 8, "SEARCHABLE", PG_TYPE_INT2, 2);
772 QR_set_field_info(stmt->result, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2);
773 QR_set_field_info(stmt->result, 10, "MONEY", PG_TYPE_INT2, 2);
774 QR_set_field_info(stmt->result, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2);
775 QR_set_field_info(stmt->result, 12, "LOCAL_TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
776 QR_set_field_info(stmt->result, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
777 QR_set_field_info(stmt->result, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
779 // cycle through the types
780 for(i=0, type = pgtypes_defined[0]; type; type = pgtypes_defined[++i]) {
782 if(fSqlType == SQL_ALL_TYPES || fSqlType == pgtype_to_sqltype(stmt, type)) {
784 row = (TupleNode *)malloc(sizeof(TupleNode) + (15 - 1)*sizeof(TupleField));
786 /* These values can't be NULL */
787 set_tuplefield_string(&row->tuple[0], pgtype_to_name(stmt, type));
788 set_tuplefield_int2(&row->tuple[1], pgtype_to_sqltype(stmt, type));
789 set_tuplefield_int2(&row->tuple[6], pgtype_nullable(stmt, type));
790 set_tuplefield_int2(&row->tuple[7], pgtype_case_sensitive(stmt, type));
791 set_tuplefield_int2(&row->tuple[8], pgtype_searchable(stmt, type));
792 set_tuplefield_int2(&row->tuple[10], pgtype_money(stmt, type));
794 /* Localized data-source dependent data type name (always NULL) */
795 set_tuplefield_null(&row->tuple[12]);
797 /* These values can be NULL */
798 set_nullfield_int4(&row->tuple[2], pgtype_precision(stmt, type, PG_STATIC, PG_STATIC));
799 set_nullfield_string(&row->tuple[3], pgtype_literal_prefix(stmt, type));
800 set_nullfield_string(&row->tuple[4], pgtype_literal_suffix(stmt, type));
801 set_nullfield_string(&row->tuple[5], pgtype_create_params(stmt, type));
802 set_nullfield_int2(&row->tuple[9], pgtype_unsigned(stmt, type));
803 set_nullfield_int2(&row->tuple[11], pgtype_auto_increment(stmt, type));
804 set_nullfield_int2(&row->tuple[13], pgtype_scale(stmt, type));
805 set_nullfield_int2(&row->tuple[14], pgtype_scale(stmt, type));
807 QR_add_tuple(stmt->result, row);
811 stmt->status = STMT_FINISHED;
812 stmt->currTuple = -1;
813 stmt->current_col = -1;
820 RETCODE SQL_API SQLGetFunctions(
825 if (fFunction == SQL_API_ALL_FUNCTIONS) {
829 memset(pfExists, 0, sizeof(UWORD)*100);
831 pfExists[SQL_API_SQLALLOCENV] = TRUE;
832 pfExists[SQL_API_SQLFREEENV] = TRUE;
833 for (i = SQL_API_SQLALLOCCONNECT; i <= SQL_NUM_FUNCTIONS; i++)
835 for (i = SQL_EXT_API_START; i <= SQL_EXT_API_LAST; i++)
839 memset(pfExists, 0, sizeof(UWORD)*100);
841 // ODBC core functions
842 pfExists[SQL_API_SQLALLOCCONNECT] = TRUE;
843 pfExists[SQL_API_SQLALLOCENV] = TRUE;
844 pfExists[SQL_API_SQLALLOCSTMT] = TRUE;
845 pfExists[SQL_API_SQLBINDCOL] = TRUE;
846 pfExists[SQL_API_SQLCANCEL] = TRUE;
847 pfExists[SQL_API_SQLCOLATTRIBUTES] = TRUE;
848 pfExists[SQL_API_SQLCONNECT] = TRUE;
849 pfExists[SQL_API_SQLDESCRIBECOL] = TRUE; // partial
850 pfExists[SQL_API_SQLDISCONNECT] = TRUE;
851 pfExists[SQL_API_SQLERROR] = TRUE;
852 pfExists[SQL_API_SQLEXECDIRECT] = TRUE;
853 pfExists[SQL_API_SQLEXECUTE] = TRUE;
854 pfExists[SQL_API_SQLFETCH] = TRUE;
855 pfExists[SQL_API_SQLFREECONNECT] = TRUE;
856 pfExists[SQL_API_SQLFREEENV] = TRUE;
857 pfExists[SQL_API_SQLFREESTMT] = TRUE;
858 pfExists[SQL_API_SQLGETCURSORNAME] = TRUE;
859 pfExists[SQL_API_SQLNUMRESULTCOLS] = TRUE;
860 pfExists[SQL_API_SQLPREPARE] = TRUE; // complete?
861 pfExists[SQL_API_SQLROWCOUNT] = TRUE;
862 pfExists[SQL_API_SQLSETCURSORNAME] = TRUE;
863 pfExists[SQL_API_SQLSETPARAM] = FALSE; // odbc 1.0
864 pfExists[SQL_API_SQLTRANSACT] = TRUE;
866 // ODBC level 1 functions
867 pfExists[SQL_API_SQLBINDPARAMETER] = TRUE;
868 pfExists[SQL_API_SQLCOLUMNS] = TRUE;
869 pfExists[SQL_API_SQLDRIVERCONNECT] = TRUE;
870 pfExists[SQL_API_SQLGETCONNECTOPTION] = TRUE; // partial
871 pfExists[SQL_API_SQLGETDATA] = TRUE;
872 pfExists[SQL_API_SQLGETFUNCTIONS] = TRUE;
873 pfExists[SQL_API_SQLGETINFO] = TRUE;
874 pfExists[SQL_API_SQLGETSTMTOPTION] = TRUE; // partial
875 pfExists[SQL_API_SQLGETTYPEINFO] = TRUE;
876 pfExists[SQL_API_SQLPARAMDATA] = TRUE;
877 pfExists[SQL_API_SQLPUTDATA] = TRUE;
878 pfExists[SQL_API_SQLSETCONNECTOPTION] = TRUE; // partial
879 pfExists[SQL_API_SQLSETSTMTOPTION] = TRUE;
880 pfExists[SQL_API_SQLSPECIALCOLUMNS] = TRUE;
881 pfExists[SQL_API_SQLSTATISTICS] = TRUE;
882 pfExists[SQL_API_SQLTABLES] = TRUE;
884 // ODBC level 2 functions
885 pfExists[SQL_API_SQLBROWSECONNECT] = FALSE;
886 pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
887 pfExists[SQL_API_SQLDATASOURCES] = FALSE; // only implemented by DM
888 pfExists[SQL_API_SQLDESCRIBEPARAM] = FALSE; // not properly implemented
889 pfExists[SQL_API_SQLDRIVERS] = FALSE; // only implemented by DM
890 pfExists[SQL_API_SQLEXTENDEDFETCH] = globals.use_declarefetch ? FALSE : TRUE;
891 pfExists[SQL_API_SQLFOREIGNKEYS] = TRUE;
892 pfExists[SQL_API_SQLMORERESULTS] = TRUE;
893 pfExists[SQL_API_SQLNATIVESQL] = TRUE;
894 pfExists[SQL_API_SQLNUMPARAMS] = TRUE;
895 pfExists[SQL_API_SQLPARAMOPTIONS] = FALSE;
896 pfExists[SQL_API_SQLPRIMARYKEYS] = TRUE;
897 pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE;
898 pfExists[SQL_API_SQLPROCEDURES] = FALSE;
899 pfExists[SQL_API_SQLSETPOS] = FALSE;
900 pfExists[SQL_API_SQLSETSCROLLOPTIONS] = FALSE; // odbc 1.0
901 pfExists[SQL_API_SQLTABLEPRIVILEGES] = FALSE;
911 case SQL_API_SQLALLOCCONNECT: *pfExists = TRUE; break;
912 case SQL_API_SQLALLOCENV: *pfExists = TRUE; break;
913 case SQL_API_SQLALLOCSTMT: *pfExists = TRUE; break;
914 case SQL_API_SQLBINDCOL: *pfExists = TRUE; break;
915 case SQL_API_SQLCANCEL: *pfExists = TRUE; break;
916 case SQL_API_SQLCOLATTRIBUTES: *pfExists = TRUE; break;
917 case SQL_API_SQLCONNECT: *pfExists = TRUE; break;
918 case SQL_API_SQLDESCRIBECOL: *pfExists = TRUE; break; // partial
919 case SQL_API_SQLDISCONNECT: *pfExists = TRUE; break;
920 case SQL_API_SQLERROR: *pfExists = TRUE; break;
921 case SQL_API_SQLEXECDIRECT: *pfExists = TRUE; break;
922 case SQL_API_SQLEXECUTE: *pfExists = TRUE; break;
923 case SQL_API_SQLFETCH: *pfExists = TRUE; break;
924 case SQL_API_SQLFREECONNECT: *pfExists = TRUE; break;
925 case SQL_API_SQLFREEENV: *pfExists = TRUE; break;
926 case SQL_API_SQLFREESTMT: *pfExists = TRUE; break;
927 case SQL_API_SQLGETCURSORNAME: *pfExists = TRUE; break;
928 case SQL_API_SQLNUMRESULTCOLS: *pfExists = TRUE; break;
929 case SQL_API_SQLPREPARE: *pfExists = TRUE; break;
930 case SQL_API_SQLROWCOUNT: *pfExists = TRUE; break;
931 case SQL_API_SQLSETCURSORNAME: *pfExists = TRUE; break;
932 case SQL_API_SQLSETPARAM: *pfExists = FALSE; break; // odbc 1.0
933 case SQL_API_SQLTRANSACT: *pfExists = TRUE; break;
935 // ODBC level 1 functions
936 case SQL_API_SQLBINDPARAMETER: *pfExists = TRUE; break;
937 case SQL_API_SQLCOLUMNS: *pfExists = TRUE; break;
938 case SQL_API_SQLDRIVERCONNECT: *pfExists = TRUE; break;
939 case SQL_API_SQLGETCONNECTOPTION: *pfExists = TRUE; break; // partial
940 case SQL_API_SQLGETDATA: *pfExists = TRUE; break;
941 case SQL_API_SQLGETFUNCTIONS: *pfExists = TRUE; break;
942 case SQL_API_SQLGETINFO: *pfExists = TRUE; break;
943 case SQL_API_SQLGETSTMTOPTION: *pfExists = TRUE; break; // partial
944 case SQL_API_SQLGETTYPEINFO: *pfExists = TRUE; break;
945 case SQL_API_SQLPARAMDATA: *pfExists = TRUE; break;
946 case SQL_API_SQLPUTDATA: *pfExists = TRUE; break;
947 case SQL_API_SQLSETCONNECTOPTION: *pfExists = TRUE; break; // partial
948 case SQL_API_SQLSETSTMTOPTION: *pfExists = TRUE; break;
949 case SQL_API_SQLSPECIALCOLUMNS: *pfExists = TRUE; break;
950 case SQL_API_SQLSTATISTICS: *pfExists = TRUE; break;
951 case SQL_API_SQLTABLES: *pfExists = TRUE; break;
953 // ODBC level 2 functions
954 case SQL_API_SQLBROWSECONNECT: *pfExists = FALSE; break;
955 case SQL_API_SQLCOLUMNPRIVILEGES: *pfExists = FALSE; break;
956 case SQL_API_SQLDATASOURCES: *pfExists = FALSE; break; // only implemented by DM
957 case SQL_API_SQLDESCRIBEPARAM: *pfExists = FALSE; break; // not properly implemented
958 case SQL_API_SQLDRIVERS: *pfExists = FALSE; break; // only implemented by DM
959 case SQL_API_SQLEXTENDEDFETCH: *pfExists = globals.use_declarefetch ? FALSE : TRUE; break;
960 case SQL_API_SQLFOREIGNKEYS: *pfExists = TRUE; break;
961 case SQL_API_SQLMORERESULTS: *pfExists = TRUE; break;
962 case SQL_API_SQLNATIVESQL: *pfExists = TRUE; break;
963 case SQL_API_SQLNUMPARAMS: *pfExists = TRUE; break;
964 case SQL_API_SQLPARAMOPTIONS: *pfExists = FALSE; break;
965 case SQL_API_SQLPRIMARYKEYS: *pfExists = TRUE; break;
966 case SQL_API_SQLPROCEDURECOLUMNS: *pfExists = FALSE; break;
967 case SQL_API_SQLPROCEDURES: *pfExists = FALSE; break;
968 case SQL_API_SQLSETPOS: *pfExists = FALSE; break;
969 case SQL_API_SQLSETSCROLLOPTIONS: *pfExists = FALSE; break; // odbc 1.0
970 case SQL_API_SQLTABLEPRIVILEGES: *pfExists = FALSE; break;
980 RETCODE SQL_API SQLTables(
982 UCHAR FAR * szTableQualifier,
983 SWORD cbTableQualifier,
984 UCHAR FAR * szTableOwner,
986 UCHAR FAR * szTableName,
988 UCHAR FAR * szTableType,
991 char *func = "SQLTables";
992 StatementClass *stmt = (StatementClass *) hstmt;
993 StatementClass *tbl_stmt;
998 char tables_query[MAX_STATEMENT_LEN];
999 char table_name[MAX_INFO_STRING], table_owner[MAX_INFO_STRING], relhasrules[MAX_INFO_STRING];
1001 char *prefix[32], prefixes[MEDIUM_REGISTRY_LEN];
1002 char *table_type[32], table_types[MAX_INFO_STRING];
1003 char show_system_tables, show_regular_tables, show_views;
1004 char regular_table, view, systable;
1007 mylog("**** SQLTables(): ENTER, stmt=%u\n", stmt);
1010 SC_log_error(func, "", NULL);
1011 return SQL_INVALID_HANDLE;
1014 stmt->manual_result = TRUE;
1015 stmt->errormsg_created = TRUE;
1017 ci = &stmt->hdbc->connInfo;
1019 result = SQLAllocStmt( stmt->hdbc, &htbl_stmt);
1020 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1021 stmt->errornumber = STMT_NO_MEMORY_ERROR;
1022 stmt->errormsg = "Couldn't allocate statement for SQLTables result.";
1023 SC_log_error(func, "", stmt);
1026 tbl_stmt = (StatementClass *) htbl_stmt;
1028 // **********************************************************************
1029 // Create the query to find out the tables
1030 // **********************************************************************
1032 strcpy(tables_query, "select relname, usename, relhasrules from pg_class, pg_user where relkind = 'r' ");
1034 my_strcat(tables_query, " and usename like '%.*s'", szTableOwner, cbTableOwner);
1035 my_strcat(tables_query, " and relname like '%.*s'", szTableName, cbTableName);
1038 // Parse the extra systable prefix
1039 strcpy(prefixes, globals.extra_systable_prefixes);
1041 prefix[i] = strtok(prefixes, ";");
1042 while (prefix[i] && i<32) {
1043 prefix[++i] = strtok(NULL, ";");
1046 /* Parse the desired table types to return */
1047 show_system_tables = FALSE;
1048 show_regular_tables = FALSE;
1051 /* make_string mallocs memory */
1052 tableType = make_string(szTableType, cbTableType, NULL);
1054 strcpy(table_types, tableType);
1057 table_type[i] = strtok(table_types, ",");
1058 while (table_type[i] && i<32) {
1059 table_type[++i] = strtok(NULL, ",");
1062 /* Check for desired table types to return */
1064 while (table_type[i]) {
1065 if ( strstr(table_type[i], "SYSTEM TABLE"))
1066 show_system_tables = TRUE;
1067 else if ( strstr(table_type[i], "TABLE"))
1068 show_regular_tables = TRUE;
1069 else if ( strstr(table_type[i], "VIEW"))
1076 show_regular_tables = TRUE;
1080 /* If not interested in SYSTEM TABLES then filter them out
1081 to save some time on the query. If treating system tables
1082 as regular tables, then dont filter either.
1084 if ( ! atoi(ci->show_system_tables) && ! show_system_tables) {
1085 strcat(tables_query, " and relname !~ '^" POSTGRES_SYS_PREFIX);
1087 /* Also filter out user-defined system table types */
1090 strcat(tables_query, "|^");
1091 strcat(tables_query, prefix[i]);
1095 strcat(tables_query, "'");
1099 /* filter out large objects unconditionally (they are not system tables) and match users */
1100 strcat(tables_query, " and relname !~ '^xinv[0-9]+' and int4out(usesysid) = int4out(relowner) order by relname");
1102 // **********************************************************************
1104 result = SQLExecDirect(htbl_stmt, tables_query, strlen(tables_query));
1105 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1106 stmt->errormsg = SC_create_errormsg(htbl_stmt);
1107 stmt->errornumber = tbl_stmt->errornumber;
1108 SC_log_error(func, "", stmt);
1109 SQLFreeStmt(htbl_stmt, SQL_DROP);
1113 result = SQLBindCol(htbl_stmt, 1, SQL_C_CHAR,
1114 table_name, MAX_INFO_STRING, NULL);
1115 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1116 stmt->errormsg = tbl_stmt->errormsg;
1117 stmt->errornumber = tbl_stmt->errornumber;
1118 SC_log_error(func, "", stmt);
1119 SQLFreeStmt(htbl_stmt, SQL_DROP);
1123 result = SQLBindCol(htbl_stmt, 2, SQL_C_CHAR,
1124 table_owner, MAX_INFO_STRING, NULL);
1125 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1126 stmt->errormsg = tbl_stmt->errormsg;
1127 stmt->errornumber = tbl_stmt->errornumber;
1128 SC_log_error(func, "", stmt);
1129 SQLFreeStmt(htbl_stmt, SQL_DROP);
1132 result = SQLBindCol(htbl_stmt, 3, SQL_C_CHAR,
1133 relhasrules, MAX_INFO_STRING, NULL);
1134 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1135 stmt->errormsg = tbl_stmt->errormsg;
1136 stmt->errornumber = tbl_stmt->errornumber;
1137 SC_log_error(func, "", stmt);
1138 SQLFreeStmt(htbl_stmt, SQL_DROP);
1142 stmt->result = QR_Constructor();
1144 stmt->errormsg = "Couldn't allocate memory for SQLTables result.";
1145 stmt->errornumber = STMT_NO_MEMORY_ERROR;
1146 SC_log_error(func, "", stmt);
1147 SQLFreeStmt(htbl_stmt, SQL_DROP);
1151 // the binding structure for a statement is not set up until
1152 // a statement is actually executed, so we'll have to do this ourselves.
1153 extend_bindings(stmt, 5);
1155 // set the field names
1156 QR_set_num_fields(stmt->result, 5);
1157 QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
1158 QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
1159 QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
1160 QR_set_field_info(stmt->result, 3, "TABLE_TYPE", PG_TYPE_TEXT, MAX_INFO_STRING);
1161 QR_set_field_info(stmt->result, 4, "REMARKS", PG_TYPE_TEXT, 254);
1164 result = SQLFetch(htbl_stmt);
1165 while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
1167 /* Determine if this table name is a system table.
1168 If treating system tables as regular tables, then
1169 no need to do this test.
1172 if( ! atoi(ci->show_system_tables)) {
1174 if ( strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0)
1177 else { /* Check extra system table prefixes */
1180 mylog("table_name='%s', prefix[%d]='%s'\n", table_name, i, prefix[i]);
1181 if (strncmp(table_name, prefix[i], strlen(prefix[i])) == 0) {
1190 /* Determine if the table name is a view */
1191 view = (relhasrules[0] == '1');
1193 /* It must be a regular table */
1194 regular_table = ( ! systable && ! view);
1197 /* Include the row in the result set if meets all criteria */
1198 /* NOTE: Unsupported table types (i.e., LOCAL TEMPORARY, ALIAS, etc)
1199 will return nothing */
1200 if ( (systable && show_system_tables) ||
1201 (view && show_views) ||
1202 (regular_table && show_regular_tables)) {
1204 row = (TupleNode *)malloc(sizeof(TupleNode) + (5 - 1) * sizeof(TupleField));
1206 set_tuplefield_string(&row->tuple[0], "");
1208 // I have to hide the table owner from Access, otherwise it
1209 // insists on referring to the table as 'owner.table'.
1210 // (this is valid according to the ODBC SQL grammar, but
1211 // Postgres won't support it.)
1212 // set_tuplefield_string(&row->tuple[1], table_owner);
1214 mylog("SQLTables: table_name = '%s'\n", table_name);
1216 set_tuplefield_string(&row->tuple[1], "");
1217 set_tuplefield_string(&row->tuple[2], table_name);
1218 set_tuplefield_string(&row->tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE"));
1219 set_tuplefield_string(&row->tuple[4], "");
1221 QR_add_tuple(stmt->result, row);
1223 result = SQLFetch(htbl_stmt);
1225 if(result != SQL_NO_DATA_FOUND) {
1226 stmt->errormsg = SC_create_errormsg(htbl_stmt);
1227 stmt->errornumber = tbl_stmt->errornumber;
1228 SC_log_error(func, "", stmt);
1229 SQLFreeStmt(htbl_stmt, SQL_DROP);
1233 // also, things need to think that this statement is finished so
1234 // the results can be retrieved.
1235 stmt->status = STMT_FINISHED;
1237 // set up the current tuple pointer for SQLFetch
1238 stmt->currTuple = -1;
1239 stmt->current_col = -1;
1241 SQLFreeStmt(htbl_stmt, SQL_DROP);
1242 mylog("SQLTables(): EXIT, stmt=%u\n", stmt);
1249 RETCODE SQL_API SQLColumns(
1251 UCHAR FAR * szTableQualifier,
1252 SWORD cbTableQualifier,
1253 UCHAR FAR * szTableOwner,
1255 UCHAR FAR * szTableName,
1257 UCHAR FAR * szColumnName,
1260 char *func = "SQLColumns";
1261 StatementClass *stmt = (StatementClass *) hstmt;
1264 StatementClass *col_stmt;
1265 char columns_query[MAX_STATEMENT_LEN];
1267 char table_owner[MAX_INFO_STRING], table_name[MAX_INFO_STRING], field_name[MAX_INFO_STRING], field_type_name[MAX_INFO_STRING];
1268 Int2 field_number, field_length, mod_length, result_cols;
1269 Int4 field_type, the_type;
1270 char not_null[MAX_INFO_STRING];
1275 mylog("**** SQLColumns(): ENTER, stmt=%u\n", stmt);
1278 SC_log_error(func, "", NULL);
1279 return SQL_INVALID_HANDLE;
1282 stmt->manual_result = TRUE;
1283 stmt->errormsg_created = TRUE;
1285 ci = &stmt->hdbc->connInfo;
1287 // **********************************************************************
1288 // Create the query to find out the columns (Note: pre 6.3 did not have the atttypmod field)
1289 // **********************************************************************
1290 sprintf(columns_query, "select u.usename, c.relname, a.attname, a.atttypid,t.typname, a.attnum, a.attlen, %s, a.attnotnull from pg_user u, pg_class c, pg_attribute a, pg_type t where "
1291 "int4out(u.usesysid) = int4out(c.relowner) and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)",
1292 PROTOCOL_62(ci) ? "a.attlen" : "a.atttypmod");
1294 my_strcat(columns_query, " and c.relname like '%.*s'", szTableName, cbTableName);
1295 my_strcat(columns_query, " and u.usename like '%.*s'", szTableOwner, cbTableOwner);
1296 my_strcat(columns_query, " and a.attname like '%.*s'", szColumnName, cbColumnName);
1298 // give the output in the order the columns were defined
1299 // when the table was created
1300 strcat(columns_query, " order by attnum");
1301 // **********************************************************************
1303 result = SQLAllocStmt( stmt->hdbc, &hcol_stmt);
1304 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1305 stmt->errornumber = STMT_NO_MEMORY_ERROR;
1306 stmt->errormsg = "Couldn't allocate statement for SQLColumns result.";
1307 SC_log_error(func, "", stmt);
1310 col_stmt = (StatementClass *) hcol_stmt;
1312 result = SQLExecDirect(hcol_stmt, columns_query,
1313 strlen(columns_query));
1314 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1315 stmt->errormsg = SC_create_errormsg(hcol_stmt);
1316 stmt->errornumber = col_stmt->errornumber;
1317 SC_log_error(func, "", stmt);
1318 SQLFreeStmt(hcol_stmt, SQL_DROP);
1322 result = SQLBindCol(hcol_stmt, 1, SQL_C_CHAR,
1323 table_owner, MAX_INFO_STRING, NULL);
1324 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1325 stmt->errormsg = col_stmt->errormsg;
1326 stmt->errornumber = col_stmt->errornumber;
1327 SC_log_error(func, "", stmt);
1328 SQLFreeStmt(hcol_stmt, SQL_DROP);
1332 result = SQLBindCol(hcol_stmt, 2, SQL_C_CHAR,
1333 table_name, MAX_INFO_STRING, NULL);
1334 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1335 stmt->errormsg = col_stmt->errormsg;
1336 stmt->errornumber = col_stmt->errornumber;
1337 SC_log_error(func, "", stmt);
1338 SQLFreeStmt(hcol_stmt, SQL_DROP);
1342 result = SQLBindCol(hcol_stmt, 3, SQL_C_CHAR,
1343 field_name, MAX_INFO_STRING, NULL);
1344 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1345 stmt->errormsg = col_stmt->errormsg;
1346 stmt->errornumber = col_stmt->errornumber;
1347 SC_log_error(func, "", stmt);
1348 SQLFreeStmt(hcol_stmt, SQL_DROP);
1352 result = SQLBindCol(hcol_stmt, 4, SQL_C_DEFAULT,
1353 &field_type, 4, NULL);
1354 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1355 stmt->errormsg = col_stmt->errormsg;
1356 stmt->errornumber = col_stmt->errornumber;
1357 SC_log_error(func, "", stmt);
1358 SQLFreeStmt(hcol_stmt, SQL_DROP);
1362 result = SQLBindCol(hcol_stmt, 5, SQL_C_CHAR,
1363 field_type_name, MAX_INFO_STRING, NULL);
1364 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1365 stmt->errormsg = col_stmt->errormsg;
1366 stmt->errornumber = col_stmt->errornumber;
1367 SC_log_error(func, "", stmt);
1368 SQLFreeStmt(hcol_stmt, SQL_DROP);
1372 result = SQLBindCol(hcol_stmt, 6, SQL_C_DEFAULT,
1373 &field_number, MAX_INFO_STRING, NULL);
1374 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1375 stmt->errormsg = col_stmt->errormsg;
1376 stmt->errornumber = col_stmt->errornumber;
1377 SC_log_error(func, "", stmt);
1378 SQLFreeStmt(hcol_stmt, SQL_DROP);
1382 result = SQLBindCol(hcol_stmt, 7, SQL_C_DEFAULT,
1383 &field_length, MAX_INFO_STRING, NULL);
1384 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1385 stmt->errormsg = col_stmt->errormsg;
1386 stmt->errornumber = col_stmt->errornumber;
1387 SC_log_error(func, "", stmt);
1388 SQLFreeStmt(hcol_stmt, SQL_DROP);
1392 result = SQLBindCol(hcol_stmt, 8, SQL_C_DEFAULT,
1393 &mod_length, MAX_INFO_STRING, NULL);
1394 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1395 stmt->errormsg = col_stmt->errormsg;
1396 stmt->errornumber = col_stmt->errornumber;
1397 SC_log_error(func, "", stmt);
1398 SQLFreeStmt(hcol_stmt, SQL_DROP);
1402 result = SQLBindCol(hcol_stmt, 9, SQL_C_CHAR,
1403 not_null, MAX_INFO_STRING, NULL);
1404 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1405 stmt->errormsg = col_stmt->errormsg;
1406 stmt->errornumber = col_stmt->errornumber;
1407 SC_log_error(func, "", stmt);
1408 SQLFreeStmt(hcol_stmt, SQL_DROP);
1412 stmt->result = QR_Constructor();
1414 stmt->errormsg = "Couldn't allocate memory for SQLColumns result.";
1415 stmt->errornumber = STMT_NO_MEMORY_ERROR;
1416 SC_log_error(func, "", stmt);
1417 SQLFreeStmt(hcol_stmt, SQL_DROP);
1421 // the binding structure for a statement is not set up until
1422 // a statement is actually executed, so we'll have to do this ourselves.
1424 extend_bindings(stmt, result_cols);
1426 // set the field names
1427 QR_set_num_fields(stmt->result, result_cols);
1428 QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
1429 QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
1430 QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
1431 QR_set_field_info(stmt->result, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
1432 QR_set_field_info(stmt->result, 4, "DATA_TYPE", PG_TYPE_INT2, 2);
1433 QR_set_field_info(stmt->result, 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
1434 QR_set_field_info(stmt->result, 6, "PRECISION", PG_TYPE_INT4, 4);
1435 QR_set_field_info(stmt->result, 7, "LENGTH", PG_TYPE_INT4, 4);
1436 QR_set_field_info(stmt->result, 8, "SCALE", PG_TYPE_INT2, 2);
1437 QR_set_field_info(stmt->result, 9, "RADIX", PG_TYPE_INT2, 2);
1438 QR_set_field_info(stmt->result, 10, "NULLABLE", PG_TYPE_INT2, 2);
1439 QR_set_field_info(stmt->result, 11, "REMARKS", PG_TYPE_TEXT, 254);
1441 // User defined fields
1442 QR_set_field_info(stmt->result, 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
1443 QR_set_field_info(stmt->result, 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
1446 result = SQLFetch(hcol_stmt);
1448 /* Only show oid if option AND there are other columns AND
1449 its not being called by SQLStatistics .
1450 Always show OID if its a system table
1453 if (result != SQL_ERROR && ! stmt->internal) {
1455 if (atoi(ci->show_oid_column) || strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0) {
1457 /* For OID fields */
1458 the_type = PG_TYPE_OID;
1459 row = (TupleNode *)malloc(sizeof(TupleNode) +
1460 (result_cols - 1) * sizeof(TupleField));
1462 set_tuplefield_string(&row->tuple[0], "");
1463 // see note in SQLTables()
1464 // set_tuplefield_string(&row->tuple[1], table_owner);
1465 set_tuplefield_string(&row->tuple[1], "");
1466 set_tuplefield_string(&row->tuple[2], table_name);
1467 set_tuplefield_string(&row->tuple[3], "oid");
1468 set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, the_type));
1469 set_tuplefield_string(&row->tuple[5], "OID");
1471 set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
1472 set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, the_type, PG_STATIC, PG_STATIC));
1474 set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, the_type));
1475 set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, the_type));
1476 set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS);
1477 set_tuplefield_string(&row->tuple[11], "");
1479 set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
1480 set_tuplefield_int4(&row->tuple[13], the_type);
1482 QR_add_tuple(stmt->result, row);
1487 while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
1488 row = (TupleNode *)malloc(sizeof(TupleNode) +
1489 (result_cols - 1) * sizeof(TupleField));
1491 set_tuplefield_string(&row->tuple[0], "");
1492 // see note in SQLTables()
1493 // set_tuplefield_string(&row->tuple[1], table_owner);
1494 set_tuplefield_string(&row->tuple[1], "");
1495 set_tuplefield_string(&row->tuple[2], table_name);
1496 set_tuplefield_string(&row->tuple[3], field_name);
1497 set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, field_type));
1498 set_tuplefield_string(&row->tuple[5], field_type_name);
1501 /* Some Notes about Postgres Data Types:
1503 VARCHAR - the length is stored in the pg_attribute.atttypmod field
1504 BPCHAR - the length is also stored as varchar is
1507 if((field_type == PG_TYPE_VARCHAR) ||
1508 (field_type == PG_TYPE_BPCHAR)) {
1510 if (mod_length >= 4)
1511 mod_length -= 4; // the length is in atttypmod - 4
1513 if (mod_length > globals.max_varchar_size || mod_length <= 0)
1514 mod_length = globals.max_varchar_size;
1516 mylog("SQLColumns: field type is VARCHAR,BPCHAR: field_type = %d, mod_length = %d\n", field_type, mod_length);
1518 set_tuplefield_int4(&row->tuple[7], mod_length);
1519 set_tuplefield_int4(&row->tuple[6], mod_length);
1520 set_tuplefield_int4(&row->tuple[12], mod_length);
1522 mylog("SQLColumns: field type is OTHER: field_type = %d, pgtype_length = %d\n", field_type, pgtype_length(stmt, field_type, PG_STATIC, PG_STATIC));
1524 set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, field_type, PG_STATIC, PG_STATIC));
1525 set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, field_type, PG_STATIC, PG_STATIC));
1526 set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, field_type, PG_STATIC, PG_STATIC));
1530 set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, field_type));
1531 set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, field_type));
1532 set_tuplefield_int2(&row->tuple[10], (Int2) (not_null[0] == '1' ? SQL_NO_NULLS : pgtype_nullable(stmt, field_type)));
1533 set_tuplefield_string(&row->tuple[11], "");
1534 set_tuplefield_int4(&row->tuple[13], field_type);
1536 QR_add_tuple(stmt->result, row);
1538 result = SQLFetch(hcol_stmt);
1540 if(result != SQL_NO_DATA_FOUND) {
1541 stmt->errormsg = SC_create_errormsg(hcol_stmt);
1542 stmt->errornumber = col_stmt->errornumber;
1543 SC_log_error(func, "", stmt);
1544 SQLFreeStmt(hcol_stmt, SQL_DROP);
1548 // Put the row version column at the end so it might not be
1549 // mistaken for a key field.
1550 if ( ! stmt->internal && atoi(ci->row_versioning)) {
1551 /* For Row Versioning fields */
1552 the_type = PG_TYPE_INT4;
1554 row = (TupleNode *)malloc(sizeof(TupleNode) +
1555 (result_cols - 1) * sizeof(TupleField));
1557 set_tuplefield_string(&row->tuple[0], "");
1558 set_tuplefield_string(&row->tuple[1], "");
1559 set_tuplefield_string(&row->tuple[2], table_name);
1560 set_tuplefield_string(&row->tuple[3], "xmin");
1561 set_tuplefield_int2(&row->tuple[4], pgtype_to_sqltype(stmt, the_type));
1562 set_tuplefield_string(&row->tuple[5], pgtype_to_name(stmt, the_type));
1563 set_tuplefield_int4(&row->tuple[6], pgtype_precision(stmt, the_type, PG_STATIC, PG_STATIC));
1564 set_tuplefield_int4(&row->tuple[7], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
1565 set_nullfield_int2(&row->tuple[8], pgtype_scale(stmt, the_type));
1566 set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, the_type));
1567 set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS);
1568 set_tuplefield_string(&row->tuple[11], "");
1569 set_tuplefield_int4(&row->tuple[12], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
1570 set_tuplefield_int4(&row->tuple[13], the_type);
1572 QR_add_tuple(stmt->result, row);
1575 // also, things need to think that this statement is finished so
1576 // the results can be retrieved.
1577 stmt->status = STMT_FINISHED;
1579 // set up the current tuple pointer for SQLFetch
1580 stmt->currTuple = -1;
1581 stmt->current_col = -1;
1583 SQLFreeStmt(hcol_stmt, SQL_DROP);
1584 mylog("SQLColumns(): EXIT, stmt=%u\n", stmt);
1588 RETCODE SQL_API SQLSpecialColumns(
1591 UCHAR FAR * szTableQualifier,
1592 SWORD cbTableQualifier,
1593 UCHAR FAR * szTableOwner,
1595 UCHAR FAR * szTableName,
1600 char *func = "SQLSpecialColumns";
1602 StatementClass *stmt = (StatementClass *) hstmt;
1606 mylog("**** SQLSpecialColumns(): ENTER, stmt=%u\n", stmt);
1609 SC_log_error(func, "", NULL);
1610 return SQL_INVALID_HANDLE;
1612 ci = &stmt->hdbc->connInfo;
1614 stmt->manual_result = TRUE;
1615 stmt->result = QR_Constructor();
1616 extend_bindings(stmt, 8);
1618 QR_set_num_fields(stmt->result, 8);
1619 QR_set_field_info(stmt->result, 0, "SCOPE", PG_TYPE_INT2, 2);
1620 QR_set_field_info(stmt->result, 1, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
1621 QR_set_field_info(stmt->result, 2, "DATA_TYPE", PG_TYPE_INT2, 2);
1622 QR_set_field_info(stmt->result, 3, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
1623 QR_set_field_info(stmt->result, 4, "PRECISION", PG_TYPE_INT4, 4);
1624 QR_set_field_info(stmt->result, 5, "LENGTH", PG_TYPE_INT4, 4);
1625 QR_set_field_info(stmt->result, 6, "SCALE", PG_TYPE_INT2, 2);
1626 QR_set_field_info(stmt->result, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2);
1628 /* use the oid value for the rowid */
1629 if(fColType == SQL_BEST_ROWID) {
1630 row = (TupleNode *)malloc(sizeof(TupleNode) + (8 - 1) * sizeof(TupleField));
1632 set_tuplefield_int2(&row->tuple[0], SQL_SCOPE_SESSION);
1633 set_tuplefield_string(&row->tuple[1], "oid");
1634 set_tuplefield_int2(&row->tuple[2], pgtype_to_sqltype(stmt, PG_TYPE_OID));
1635 set_tuplefield_string(&row->tuple[3], "OID");
1636 set_tuplefield_int4(&row->tuple[4], pgtype_precision(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
1637 set_tuplefield_int4(&row->tuple[5], pgtype_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
1638 set_tuplefield_int2(&row->tuple[6], pgtype_scale(stmt, PG_TYPE_OID));
1639 set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
1641 QR_add_tuple(stmt->result, row);
1643 } else if(fColType == SQL_ROWVER) {
1645 Int2 the_type = PG_TYPE_INT4;
1647 if (atoi(ci->row_versioning)) {
1648 row = (TupleNode *)malloc(sizeof(TupleNode) + (8 - 1) * sizeof(TupleField));
1650 set_tuplefield_null(&row->tuple[0]);
1651 set_tuplefield_string(&row->tuple[1], "xmin");
1652 set_tuplefield_int2(&row->tuple[2], pgtype_to_sqltype(stmt, the_type));
1653 set_tuplefield_string(&row->tuple[3], pgtype_to_name(stmt, the_type));
1654 set_tuplefield_int4(&row->tuple[4], pgtype_precision(stmt, the_type, PG_STATIC, PG_STATIC));
1655 set_tuplefield_int4(&row->tuple[5], pgtype_length(stmt, the_type, PG_STATIC, PG_STATIC));
1656 set_tuplefield_int2(&row->tuple[6], pgtype_scale(stmt, the_type));
1657 set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
1659 QR_add_tuple(stmt->result, row);
1662 stmt->status = STMT_FINISHED;
1663 stmt->currTuple = -1;
1664 stmt->current_col = -1;
1666 mylog("SQLSpecialColumns(): EXIT, stmt=%u\n", stmt);
1670 RETCODE SQL_API SQLStatistics(
1672 UCHAR FAR * szTableQualifier,
1673 SWORD cbTableQualifier,
1674 UCHAR FAR * szTableOwner,
1676 UCHAR FAR * szTableName,
1681 char *func="SQLStatistics";
1682 StatementClass *stmt = (StatementClass *) hstmt;
1683 char index_query[MAX_STATEMENT_LEN];
1687 char index_name[MAX_INFO_STRING];
1688 short fields_vector[8];
1689 char isunique[10], isclustered[10];
1690 SDWORD index_name_len, fields_vector_len;
1694 StatementClass *col_stmt, *indx_stmt;
1695 char column_name[MAX_INFO_STRING];
1696 char **column_names = 0;
1697 Int4 column_name_len;
1698 int total_columns = 0;
1703 mylog("**** SQLStatistics(): ENTER, stmt=%u\n", stmt);
1706 SC_log_error(func, "", NULL);
1707 return SQL_INVALID_HANDLE;
1710 stmt->manual_result = TRUE;
1711 stmt->errormsg_created = TRUE;
1713 ci = &stmt->hdbc->connInfo;
1715 stmt->result = QR_Constructor();
1717 stmt->errormsg = "Couldn't allocate memory for SQLStatistics result.";
1718 stmt->errornumber = STMT_NO_MEMORY_ERROR;
1719 SC_log_error(func, "", stmt);
1723 // the binding structure for a statement is not set up until
1724 // a statement is actually executed, so we'll have to do this ourselves.
1725 extend_bindings(stmt, 13);
1727 // set the field names
1728 QR_set_num_fields(stmt->result, 13);
1729 QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
1730 QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
1731 QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
1732 QR_set_field_info(stmt->result, 3, "NON_UNIQUE", PG_TYPE_INT2, 2);
1733 QR_set_field_info(stmt->result, 4, "INDEX_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
1734 QR_set_field_info(stmt->result, 5, "INDEX_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
1735 QR_set_field_info(stmt->result, 6, "TYPE", PG_TYPE_INT2, 2);
1736 QR_set_field_info(stmt->result, 7, "SEQ_IN_INDEX", PG_TYPE_INT2, 2);
1737 QR_set_field_info(stmt->result, 8, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
1738 QR_set_field_info(stmt->result, 9, "COLLATION", PG_TYPE_CHAR, 1);
1739 QR_set_field_info(stmt->result, 10, "CARDINALITY", PG_TYPE_INT4, 4);
1740 QR_set_field_info(stmt->result, 11, "PAGES", PG_TYPE_INT4, 4);
1741 QR_set_field_info(stmt->result, 12, "FILTER_CONDITION", PG_TYPE_TEXT, MAX_INFO_STRING);
1744 // only use the table name... the owner should be redundant, and
1745 // we never use qualifiers.
1746 table_name = make_string(szTableName, cbTableName, NULL);
1747 if ( ! table_name) {
1748 stmt->errormsg = "No table name passed to SQLStatistics.";
1749 stmt->errornumber = STMT_INTERNAL_ERROR;
1750 SC_log_error(func, "", stmt);
1754 // we need to get a list of the field names first,
1755 // so we can return them later.
1756 result = SQLAllocStmt( stmt->hdbc, &hcol_stmt);
1757 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1758 stmt->errormsg = "SQLAllocStmt failed in SQLStatistics for columns.";
1759 stmt->errornumber = STMT_NO_MEMORY_ERROR;
1763 col_stmt = (StatementClass *) hcol_stmt;
1765 /* "internal" prevents SQLColumns from returning the oid if it is being shown.
1766 This would throw everything off.
1768 col_stmt->internal = TRUE;
1769 result = SQLColumns(hcol_stmt, "", 0, "", 0,
1770 table_name, (SWORD) strlen(table_name), "", 0);
1771 col_stmt->internal = FALSE;
1773 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1774 stmt->errormsg = col_stmt->errormsg; // "SQLColumns failed in SQLStatistics.";
1775 stmt->errornumber = col_stmt->errornumber; // STMT_EXEC_ERROR;
1776 SQLFreeStmt(hcol_stmt, SQL_DROP);
1779 result = SQLBindCol(hcol_stmt, 4, SQL_C_CHAR,
1780 column_name, MAX_INFO_STRING, &column_name_len);
1781 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1782 stmt->errormsg = col_stmt->errormsg;
1783 stmt->errornumber = col_stmt->errornumber;
1784 SQLFreeStmt(hcol_stmt, SQL_DROP);
1789 result = SQLFetch(hcol_stmt);
1790 while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
1794 (char **)realloc(column_names,
1795 total_columns * sizeof(char *));
1796 column_names[total_columns-1] =
1797 (char *)malloc(strlen(column_name)+1);
1798 strcpy(column_names[total_columns-1], column_name);
1800 mylog("SQLStatistics: column_name = '%s'\n", column_name);
1802 result = SQLFetch(hcol_stmt);
1804 if(result != SQL_NO_DATA_FOUND || total_columns == 0) {
1805 stmt->errormsg = SC_create_errormsg(hcol_stmt); // "Couldn't get column names in SQLStatistics.";
1806 stmt->errornumber = col_stmt->errornumber;
1807 SQLFreeStmt(hcol_stmt, SQL_DROP);
1812 SQLFreeStmt(hcol_stmt, SQL_DROP);
1814 // get a list of indexes on this table
1815 result = SQLAllocStmt( stmt->hdbc, &hindx_stmt);
1816 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1817 stmt->errormsg = "SQLAllocStmt failed in SQLStatistics for indices.";
1818 stmt->errornumber = STMT_NO_MEMORY_ERROR;
1822 indx_stmt = (StatementClass *) hindx_stmt;
1824 sprintf(index_query, "select c.relname, i.indkey, i.indisunique, i.indisclustered from pg_index i, pg_class c, pg_class d where c.oid = i.indexrelid and d.relname = '%s' and d.oid = i.indrelid",
1827 result = SQLExecDirect(hindx_stmt, index_query, strlen(index_query));
1828 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1829 stmt->errormsg = SC_create_errormsg(hindx_stmt); // "Couldn't execute index query (w/SQLExecDirect) in SQLStatistics.";
1830 stmt->errornumber = indx_stmt->errornumber;
1831 SQLFreeStmt(hindx_stmt, SQL_DROP);
1836 // bind the index name column
1837 result = SQLBindCol(hindx_stmt, 1, SQL_C_CHAR,
1838 index_name, MAX_INFO_STRING, &index_name_len);
1839 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1840 stmt->errormsg = indx_stmt->errormsg; // "Couldn't bind column in SQLStatistics.";
1841 stmt->errornumber = indx_stmt->errornumber;
1842 SQLFreeStmt(hindx_stmt, SQL_DROP);
1846 // bind the vector column
1847 result = SQLBindCol(hindx_stmt, 2, SQL_C_DEFAULT,
1848 fields_vector, 16, &fields_vector_len);
1849 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1850 stmt->errormsg = indx_stmt->errormsg; // "Couldn't bind column in SQLStatistics.";
1851 stmt->errornumber = indx_stmt->errornumber;
1852 SQLFreeStmt(hindx_stmt, SQL_DROP);
1856 // bind the "is unique" column
1857 result = SQLBindCol(hindx_stmt, 3, SQL_C_CHAR,
1858 isunique, sizeof(isunique), NULL);
1859 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1860 stmt->errormsg = indx_stmt->errormsg; // "Couldn't bind column in SQLStatistics.";
1861 stmt->errornumber = indx_stmt->errornumber;
1862 SQLFreeStmt(hindx_stmt, SQL_DROP);
1866 // bind the "is clustered" column
1867 result = SQLBindCol(hindx_stmt, 4, SQL_C_CHAR,
1868 isclustered, sizeof(isclustered), NULL);
1869 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
1870 stmt->errormsg = indx_stmt->errormsg; // "Couldn't bind column in SQLStatistics.";
1871 stmt->errornumber = indx_stmt->errornumber;
1872 SQLFreeStmt(hindx_stmt, SQL_DROP);
1877 /* fake index of OID */
1878 if (atoi(ci->show_oid_column) && atoi(ci->fake_oid_index)) {
1879 row = (TupleNode *)malloc(sizeof(TupleNode) +
1880 (13 - 1) * sizeof(TupleField));
1882 // no table qualifier
1883 set_tuplefield_string(&row->tuple[0], "");
1884 // don't set the table owner, else Access tries to use it
1885 set_tuplefield_string(&row->tuple[1], "");
1886 set_tuplefield_string(&row->tuple[2], table_name);
1888 // non-unique index?
1889 set_tuplefield_int2(&row->tuple[3], (Int2) (globals.unique_index ? FALSE : TRUE));
1891 // no index qualifier
1892 set_tuplefield_string(&row->tuple[4], "");
1894 sprintf(buf, "%s_idx_fake_oid", table_name);
1895 set_tuplefield_string(&row->tuple[5], buf);
1897 // Clustered index? I think non-clustered should be type OTHER not HASHED
1898 set_tuplefield_int2(&row->tuple[6], (Int2) SQL_INDEX_OTHER);
1899 set_tuplefield_int2(&row->tuple[7], (Int2) 1);
1901 set_tuplefield_string(&row->tuple[8], "oid");
1902 set_tuplefield_string(&row->tuple[9], "A");
1903 set_tuplefield_null(&row->tuple[10]);
1904 set_tuplefield_null(&row->tuple[11]);
1905 set_tuplefield_null(&row->tuple[12]);
1907 QR_add_tuple(stmt->result, row);
1910 result = SQLFetch(hindx_stmt);
1911 while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
1913 // If only requesting unique indexs, then just return those.
1914 if (fUnique == SQL_INDEX_ALL ||
1915 (fUnique == SQL_INDEX_UNIQUE && atoi(isunique))) {
1917 // add a row in this table for each field in the index
1918 while(i < 8 && fields_vector[i] != 0) {
1920 row = (TupleNode *)malloc(sizeof(TupleNode) +
1921 (13 - 1) * sizeof(TupleField));
1923 // no table qualifier
1924 set_tuplefield_string(&row->tuple[0], "");
1925 // don't set the table owner, else Access tries to use it
1926 set_tuplefield_string(&row->tuple[1], "");
1927 set_tuplefield_string(&row->tuple[2], table_name);
1929 // non-unique index?
1930 if (globals.unique_index)
1931 set_tuplefield_int2(&row->tuple[3], (Int2) (atoi(isunique) ? FALSE : TRUE));
1933 set_tuplefield_int2(&row->tuple[3], TRUE);
1935 // no index qualifier
1936 set_tuplefield_string(&row->tuple[4], "");
1937 set_tuplefield_string(&row->tuple[5], index_name);
1939 // Clustered index? I think non-clustered should be type OTHER not HASHED
1940 set_tuplefield_int2(&row->tuple[6], (Int2) (atoi(isclustered) ? SQL_INDEX_CLUSTERED : SQL_INDEX_OTHER));
1941 set_tuplefield_int2(&row->tuple[7], (Int2) (i+1));
1943 if(fields_vector[i] == OID_ATTNUM) {
1944 set_tuplefield_string(&row->tuple[8], "oid");
1945 mylog("SQLStatistics: column name = oid\n");
1947 else if(fields_vector[i] < 0 || fields_vector[i] > total_columns) {
1948 set_tuplefield_string(&row->tuple[8], "UNKNOWN");
1949 mylog("SQLStatistics: column name = UNKNOWN\n");
1952 set_tuplefield_string(&row->tuple[8], column_names[fields_vector[i]-1]);
1953 mylog("SQLStatistics: column name = '%s'\n", column_names[fields_vector[i]-1]);
1956 set_tuplefield_string(&row->tuple[9], "A");
1957 set_tuplefield_null(&row->tuple[10]);
1958 set_tuplefield_null(&row->tuple[11]);
1959 set_tuplefield_null(&row->tuple[12]);
1961 QR_add_tuple(stmt->result, row);
1966 result = SQLFetch(hindx_stmt);
1968 if(result != SQL_NO_DATA_FOUND) {
1969 stmt->errormsg = SC_create_errormsg(hindx_stmt); // "SQLFetch failed in SQLStatistics.";
1970 stmt->errornumber = indx_stmt->errornumber;
1971 SQLFreeStmt(hindx_stmt, SQL_DROP);
1975 SQLFreeStmt(hindx_stmt, SQL_DROP);
1977 // also, things need to think that this statement is finished so
1978 // the results can be retrieved.
1979 stmt->status = STMT_FINISHED;
1981 // set up the current tuple pointer for SQLFetch
1982 stmt->currTuple = -1;
1983 stmt->current_col = -1;
1988 /* These things should be freed on any error ALSO! */
1990 for(i = 0; i < total_columns; i++) {
1991 free(column_names[i]);
1995 mylog("SQLStatistics(): EXIT, %s, stmt=%u\n", error ? "error" : "success", stmt);
1998 SC_log_error(func, "", stmt);
2005 RETCODE SQL_API SQLColumnPrivileges(
2007 UCHAR FAR * szTableQualifier,
2008 SWORD cbTableQualifier,
2009 UCHAR FAR * szTableOwner,
2011 UCHAR FAR * szTableName,
2013 UCHAR FAR * szColumnName,
2016 char *func="SQLColumnPrivileges";
2017 /* Neither Access or Borland care about this. */
2019 SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
2024 getPrimaryKeyString(StatementClass *stmt, char *szTableName, SWORD cbTableName, char *svKey, int *nKey)
2026 char *func = "getPrimaryKeyString";
2028 StatementClass *tbl_stmt;
2030 char tables_query[MAX_STATEMENT_LEN];
2031 char attname[MAX_INFO_STRING];
2040 stmt->errormsg_created = TRUE;
2042 result = SQLAllocStmt( stmt->hdbc, &htbl_stmt);
2043 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
2044 stmt->errornumber = STMT_NO_MEMORY_ERROR;
2045 stmt->errormsg = "Couldn't allocate statement for Primary Key result.";
2046 SC_log_error(func, "", stmt);
2049 tbl_stmt = (StatementClass *) htbl_stmt;
2051 tables_query[0] = '\0';
2052 if ( ! my_strcat(tables_query, "select distinct on attnum a2.attname, a2.attnum from pg_attribute a1, pg_attribute a2, pg_class c, pg_index i where c.relname = '%.*s_pkey' AND c.oid = i.indexrelid AND a1.attrelid = c.oid AND a2.attrelid = c.oid AND (i.indkey[0] = a1.attnum OR i.indkey[1] = a1.attnum OR i.indkey[2] = a1.attnum OR i.indkey[3] = a1.attnum OR i.indkey[4] = a1.attnum OR i.indkey[5] = a1.attnum OR i.indkey[6] = a1.attnum OR i.indkey[7] = a1.attnum) order by a2.attnum",
2053 szTableName, cbTableName)) {
2055 stmt->errormsg = "No Table specified to getPrimaryKeyString.";
2056 stmt->errornumber = STMT_INTERNAL_ERROR;
2057 SC_log_error(func, "", stmt);
2058 SQLFreeStmt(htbl_stmt, SQL_DROP);
2062 mylog("getPrimaryKeyString: tables_query='%s'\n", tables_query);
2064 result = SQLExecDirect(htbl_stmt, tables_query, strlen(tables_query));
2065 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
2066 stmt->errormsg = SC_create_errormsg(htbl_stmt);
2067 stmt->errornumber = tbl_stmt->errornumber;
2068 SC_log_error(func, "", stmt);
2069 SQLFreeStmt(htbl_stmt, SQL_DROP);
2073 result = SQLBindCol(htbl_stmt, 1, SQL_C_CHAR,
2074 attname, MAX_INFO_STRING, &attname_len);
2075 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
2076 stmt->errormsg = tbl_stmt->errormsg;
2077 stmt->errornumber = tbl_stmt->errornumber;
2078 SC_log_error(func, "", stmt);
2079 SQLFreeStmt(htbl_stmt, SQL_DROP);
2083 result = SQLFetch(htbl_stmt);
2084 while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
2086 if (strlen(svKey) > 0)
2088 strcat(svKey, attname);
2090 result = SQLFetch(htbl_stmt);
2094 if(result != SQL_NO_DATA_FOUND) {
2095 stmt->errormsg = SC_create_errormsg(htbl_stmt);
2096 stmt->errornumber = tbl_stmt->errornumber;
2097 SC_log_error(func, "", stmt);
2098 SQLFreeStmt(htbl_stmt, SQL_DROP);
2102 SQLFreeStmt(htbl_stmt, SQL_DROP);
2107 mylog(">> getPrimaryKeyString: returning nKey=%d, svKey='%s'\n", nk, svKey);
2112 getPrimaryKeyArray(StatementClass *stmt, char *szTableName, SWORD cbTableName, char keyArray[][MAX_INFO_STRING], int *nKey)
2115 char svKey[MAX_KEYLEN], *svKeyPtr;
2118 result = getPrimaryKeyString(stmt, szTableName, cbTableName, svKey, nKey);
2119 if (result != SQL_SUCCESS && result != SQL_NO_DATA_FOUND)
2120 // error passed from above
2123 // If no keys, return NO_DATA_FOUND
2124 if (svKey[0] == '\0') {
2125 mylog("!!!!!! getPrimaryKeyArray: svKey was null\n");
2126 return SQL_NO_DATA_FOUND;
2129 // mylog(">> primarykeyArray: nKey=%d, svKey='%s'\n", *nKey, svKey);
2131 svKeyPtr = strtok(svKey, "+");
2132 while (svKeyPtr != NULL && i < MAX_KEYPARTS) {
2133 strcpy(keyArray[i++], svKeyPtr);
2134 svKeyPtr = strtok(NULL, "+");
2138 for (i = 0; i < *nKey; i++)
2139 mylog(">> keyArray[%d] = '%s'\n", i, keyArray[i]);
2146 RETCODE SQL_API SQLPrimaryKeys(
2148 UCHAR FAR * szTableQualifier,
2149 SWORD cbTableQualifier,
2150 UCHAR FAR * szTableOwner,
2152 UCHAR FAR * szTableName,
2155 char *func = "SQLPrimaryKeys";
2156 StatementClass *stmt = (StatementClass *) hstmt;
2159 char svKey[MAX_KEYLEN], *ptr;
2160 int seq = 1, nkeys = 0;
2162 mylog("**** SQLPrimaryKeys(): ENTER, stmt=%u\n", stmt);
2165 SC_log_error(func, "", NULL);
2166 return SQL_INVALID_HANDLE;
2168 stmt->manual_result = TRUE;
2170 result = getPrimaryKeyString(stmt, szTableName, cbTableName, svKey, &nkeys);
2172 mylog(">> PrimaryKeys: getPrimaryKeyString() returned %d, nkeys=%d, svKey = '%s'\n", result, nkeys, svKey);
2174 if (result != SQL_SUCCESS && result != SQL_NO_DATA_FOUND) {
2175 // error msg passed from above
2179 // I'm not sure if this is correct to return when there are no keys or
2180 // if an empty result set would be better.
2182 stmt->errornumber = STMT_INFO_ONLY;
2183 stmt->errormsg = "No primary keys for this table.";
2184 return SQL_SUCCESS_WITH_INFO;
2187 stmt->result = QR_Constructor();
2189 stmt->errormsg = "Couldn't allocate memory for SQLPrimaryKeys result.";
2190 stmt->errornumber = STMT_NO_MEMORY_ERROR;
2191 SC_log_error(func, "", stmt);
2196 // the binding structure for a statement is not set up until
2197 // a statement is actually executed, so we'll have to do this ourselves.
2198 extend_bindings(stmt, 6);
2200 // set the field names
2201 QR_set_num_fields(stmt->result, 6);
2202 QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
2203 QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
2204 QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
2205 QR_set_field_info(stmt->result, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
2206 QR_set_field_info(stmt->result, 4, "KEY_SEQ", PG_TYPE_INT2, 2);
2207 QR_set_field_info(stmt->result, 5, "PK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
2210 ptr = strtok(svKey, "+");
2211 while( ptr != NULL) {
2212 row = (TupleNode *)malloc(sizeof(TupleNode) + (6 - 1) * sizeof(TupleField));
2214 set_tuplefield_string(&row->tuple[0], "");
2216 // I have to hide the table owner from Access, otherwise it
2217 // insists on referring to the table as 'owner.table'.
2218 // (this is valid according to the ODBC SQL grammar, but
2219 // Postgres won't support it.)
2221 mylog(">> primaryKeys: ptab = '%s', seq = %d\n", ptr, seq);
2223 set_tuplefield_string(&row->tuple[1], "");
2224 set_tuplefield_string(&row->tuple[2], szTableName);
2225 set_tuplefield_string(&row->tuple[3], ptr);
2226 set_tuplefield_int2(&row->tuple[4], (Int2) (seq++));
2227 set_tuplefield_null(&row->tuple[5]);
2229 QR_add_tuple(stmt->result, row);
2231 ptr = strtok(NULL, "+");
2234 // also, things need to think that this statement is finished so
2235 // the results can be retrieved.
2236 stmt->status = STMT_FINISHED;
2238 // set up the current tuple pointer for SQLFetch
2239 stmt->currTuple = -1;
2240 stmt->current_col = -1;
2242 mylog("SQLPrimaryKeys(): EXIT, stmt=%u\n", stmt);
2246 RETCODE SQL_API SQLForeignKeys(
2248 UCHAR FAR * szPkTableQualifier,
2249 SWORD cbPkTableQualifier,
2250 UCHAR FAR * szPkTableOwner,
2251 SWORD cbPkTableOwner,
2252 UCHAR FAR * szPkTableName,
2253 SWORD cbPkTableName,
2254 UCHAR FAR * szFkTableQualifier,
2255 SWORD cbFkTableQualifier,
2256 UCHAR FAR * szFkTableOwner,
2257 SWORD cbFkTableOwner,
2258 UCHAR FAR * szFkTableName,
2259 SWORD cbFkTableName)
2261 char *func = "SQLForeignKeys";
2262 StatementClass *stmt = (StatementClass *) hstmt;
2265 StatementClass *tbl_stmt;
2267 char tables_query[MAX_STATEMENT_LEN];
2268 char relname[MAX_INFO_STRING], attnames[MAX_INFO_STRING], frelname[MAX_INFO_STRING];
2269 SDWORD relname_len, attnames_len, frelname_len;
2270 char *pktab, *fktab;
2272 char primaryKey[MAX_KEYPARTS][MAX_INFO_STRING];
2276 mylog("**** SQLForeignKeys(): ENTER, stmt=%u\n", stmt);
2278 memset(primaryKey, 0, sizeof(primaryKey));
2281 SC_log_error(func, "", NULL);
2282 return SQL_INVALID_HANDLE;
2284 stmt->manual_result = TRUE;
2285 stmt->errormsg_created = TRUE;
2287 result = SQLAllocStmt( stmt->hdbc, &htbl_stmt);
2288 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
2289 stmt->errornumber = STMT_NO_MEMORY_ERROR;
2290 stmt->errormsg = "Couldn't allocate statement for SQLForeignKeys result.";
2291 SC_log_error(func, "", stmt);
2295 tbl_stmt = (StatementClass *) htbl_stmt;
2297 pktab = make_string(szPkTableName, cbPkTableName, NULL);
2298 fktab = make_string(szFkTableName, cbFkTableName, NULL);
2300 if (pktab && fktab) {
2301 // Get the primary key of the table listed in szPkTable
2302 result = getPrimaryKeyArray(stmt, pktab, (SWORD) strlen(pktab), primaryKey, &pkeys);
2303 if (result != SQL_SUCCESS && result != SQL_NO_DATA_FOUND) {
2304 // error msg passed from above
2305 SQLFreeStmt(htbl_stmt, SQL_DROP);
2306 free(pktab); free(fktab);
2310 stmt->errornumber = STMT_INFO_ONLY;
2311 stmt->errormsg = "No primary keys for this table.";
2312 SQLFreeStmt(htbl_stmt, SQL_DROP);
2313 free(pktab); free(fktab);
2314 return SQL_SUCCESS_WITH_INFO;
2317 sprintf(tables_query, "select relname, attnames, frelname from %s where relname='%s' AND frelname='%s'", KEYS_TABLE, fktab, pktab);
2318 free(pktab); free(fktab);
2321 // Get the primary key of the table listed in szPkTable
2322 result = getPrimaryKeyArray(stmt, pktab, (SWORD) strlen(pktab), primaryKey, &pkeys);
2323 if (result != SQL_SUCCESS && result != SQL_NO_DATA_FOUND) {
2324 // error msg passed from above
2325 SQLFreeStmt(htbl_stmt, SQL_DROP);
2330 stmt->errornumber = STMT_INFO_ONLY;
2331 stmt->errormsg = "No primary keys for this table.";
2332 SQLFreeStmt(htbl_stmt, SQL_DROP);
2334 return SQL_SUCCESS_WITH_INFO;
2337 sprintf(tables_query, "select relname, attnames, frelname from %s where frelname='%s'", KEYS_TABLE, pktab);
2341 // This query could involve multiple calls to getPrimaryKey()
2342 // so put that off till we know what pktables we need.
2345 sprintf(tables_query, "select relname, attnames, frelname from %s where relname='%s'", KEYS_TABLE, fktab);
2349 stmt->errormsg = "No tables specified to SQLForeignKeys.";
2350 stmt->errornumber = STMT_INTERNAL_ERROR;
2351 SC_log_error(func, "", stmt);
2352 SQLFreeStmt(htbl_stmt, SQL_DROP);
2356 result = SQLExecDirect(htbl_stmt, tables_query, strlen(tables_query));
2357 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
2358 stmt->errormsg = SC_create_errormsg(htbl_stmt);
2359 stmt->errornumber = tbl_stmt->errornumber;
2360 SC_log_error(func, "", stmt);
2361 SQLFreeStmt(htbl_stmt, SQL_DROP);
2365 result = SQLBindCol(htbl_stmt, 1, SQL_C_CHAR,
2366 relname, MAX_INFO_STRING, &relname_len);
2367 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
2368 stmt->errormsg = tbl_stmt->errormsg;
2369 stmt->errornumber = tbl_stmt->errornumber;
2370 SC_log_error(func, "", stmt);
2371 SQLFreeStmt(htbl_stmt, SQL_DROP);
2374 result = SQLBindCol(htbl_stmt, 2, SQL_C_CHAR,
2375 attnames, MAX_INFO_STRING, &attnames_len);
2376 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
2377 stmt->errormsg = tbl_stmt->errormsg;
2378 stmt->errornumber = tbl_stmt->errornumber;
2379 SC_log_error(func, "", stmt);
2380 SQLFreeStmt(htbl_stmt, SQL_DROP);
2384 result = SQLBindCol(htbl_stmt, 3, SQL_C_CHAR,
2385 frelname, MAX_INFO_STRING, &frelname_len);
2386 if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
2387 stmt->errormsg = tbl_stmt->errormsg;
2388 stmt->errornumber = tbl_stmt->errornumber;
2389 SC_log_error(func, "", stmt);
2390 SQLFreeStmt(htbl_stmt, SQL_DROP);
2394 stmt->result = QR_Constructor();
2396 stmt->errormsg = "Couldn't allocate memory for SQLForeignKeys result.";
2397 stmt->errornumber = STMT_NO_MEMORY_ERROR;
2398 SC_log_error(func, "", stmt);
2399 SQLFreeStmt(htbl_stmt, SQL_DROP);
2403 // the binding structure for a statement is not set up until
2404 // a statement is actually executed, so we'll have to do this ourselves.
2405 extend_bindings(stmt, 13);
2407 // set the field names
2408 QR_set_num_fields(stmt->result, 13);
2409 QR_set_field_info(stmt->result, 0, "PKTABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
2410 QR_set_field_info(stmt->result, 1, "PKTABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
2411 QR_set_field_info(stmt->result, 2, "PKTABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
2412 QR_set_field_info(stmt->result, 3, "PKCOLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
2413 QR_set_field_info(stmt->result, 4, "FKTABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
2414 QR_set_field_info(stmt->result, 5, "FKTABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
2415 QR_set_field_info(stmt->result, 6, "FKTABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
2416 QR_set_field_info(stmt->result, 7, "FKCOLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
2417 QR_set_field_info(stmt->result, 8, "KEY_SEQ", PG_TYPE_INT2, 2);
2418 QR_set_field_info(stmt->result, 9, "UPDATE_RULE", PG_TYPE_INT2, 2);
2419 QR_set_field_info(stmt->result, 10, "DELETE_RULE", PG_TYPE_INT2, 2);
2420 QR_set_field_info(stmt->result, 11, "FK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
2421 QR_set_field_info(stmt->result, 12, "PK_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
2424 result = SQLFetch(htbl_stmt);
2426 while((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO)) {
2429 result = getPrimaryKeyArray(stmt, frelname, (SWORD) strlen(frelname), primaryKey, &pkeys);
2431 // mylog(">> getPrimaryKeyArray: frelname = '%s', pkeys = %d, result = %d\n", frelname, pkeys, result);
2433 // If an error occurs or for some reason there is no primary key for a
2434 // table that is a foreign key, then skip that one.
2435 if ((result != SQL_SUCCESS && result != SQL_NO_DATA_FOUND) || pkeys == 0) {
2436 result = SQLFetch(htbl_stmt);
2441 for (i = 0; i< pkeys; i++)
2442 mylog(">> fkey: pkeys=%d, primaryKey[%d] = '%s'\n", pkeys, i, primaryKey[i]);
2443 mylog(">> !!!!!!!!! pkeys = %d\n", pkeys);
2447 // mylog(">> attnames='%s'\n", attnames);
2449 attnamePtr = strtok(attnames, "+");
2452 while (attnamePtr != NULL && seq < pkeys) {
2454 row = (TupleNode *)malloc(sizeof(TupleNode) + (13 - 1) * sizeof(TupleField));
2456 set_tuplefield_null(&row->tuple[0]);
2458 // I have to hide the table owner from Access, otherwise it
2459 // insists on referring to the table as 'owner.table'.
2460 // (this is valid according to the ODBC SQL grammar, but
2461 // Postgres won't support it.)
2463 mylog(">> foreign keys: pktab='%s' patt='%s' fktab='%s' fatt='%s' seq=%d\n",
2464 frelname, primaryKey[seq], relname, attnamePtr, (seq+1));
2466 set_tuplefield_string(&row->tuple[1], "");
2467 set_tuplefield_string(&row->tuple[2], frelname);
2468 set_tuplefield_string(&row->tuple[3], primaryKey[seq]);
2469 set_tuplefield_null(&row->tuple[4]);
2470 set_tuplefield_string(&row->tuple[5], "");
2471 set_tuplefield_string(&row->tuple[6], relname);
2472 set_tuplefield_string(&row->tuple[7], attnamePtr);
2473 set_tuplefield_int2(&row->tuple[8], (Int2) (++seq));
2474 set_tuplefield_null(&row->tuple[9]);
2475 set_tuplefield_null(&row->tuple[10]);
2476 set_tuplefield_null(&row->tuple[11]);
2477 set_tuplefield_null(&row->tuple[12]);
2479 QR_add_tuple(stmt->result, row);
2481 attnamePtr = strtok(NULL, "+");
2483 result = SQLFetch(htbl_stmt);
2486 if(result != SQL_NO_DATA_FOUND) {
2487 stmt->errormsg = SC_create_errormsg(htbl_stmt);
2488 stmt->errornumber = tbl_stmt->errornumber;
2489 SC_log_error(func, "", stmt);
2490 SQLFreeStmt(htbl_stmt, SQL_DROP);
2494 SQLFreeStmt(htbl_stmt, SQL_DROP);
2496 // also, things need to think that this statement is finished so
2497 // the results can be retrieved.
2498 stmt->status = STMT_FINISHED;
2500 // set up the current tuple pointer for SQLFetch
2501 stmt->currTuple = -1;
2502 stmt->current_col = -1;
2504 mylog("SQLForeignKeys(): EXIT, stmt=%u\n", stmt);
2510 RETCODE SQL_API SQLProcedureColumns(
2512 UCHAR FAR * szProcQualifier,
2513 SWORD cbProcQualifier,
2514 UCHAR FAR * szProcOwner,
2516 UCHAR FAR * szProcName,
2518 UCHAR FAR * szColumnName,
2521 char *func="SQLProcedureColumns";
2523 SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
2527 RETCODE SQL_API SQLProcedures(
2529 UCHAR FAR * szProcQualifier,
2530 SWORD cbProcQualifier,
2531 UCHAR FAR * szProcOwner,
2533 UCHAR FAR * szProcName,
2536 char *func="SQLProcedures";
2538 SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);
2542 RETCODE SQL_API SQLTablePrivileges(
2544 UCHAR FAR * szTableQualifier,
2545 SWORD cbTableQualifier,
2546 UCHAR FAR * szTableOwner,
2548 UCHAR FAR * szTableName,
2551 char *func="SQLTablePrivileges";
2553 SC_log_error(func, "Function not implemented", (StatementClass *) hstmt);