~ubuntu-branches/ubuntu/natty/psqlodbc/natty

« back to all changes in this revision

Viewing changes to info.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-05-13 10:47:36 UTC
  • Revision ID: james.westby@ubuntu.com-20040513104736-a530gmn0p3knep89
Tags: upstream-07.03.0200
ImportĀ upstreamĀ versionĀ 07.03.0200

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*--------
 
2
 * Module:                      info.c
 
3
 *
 
4
 * Description:         This module contains routines related to
 
5
 *                                      ODBC informational functions.
 
6
 *
 
7
 * Classes:                     n/a
 
8
 *
 
9
 * API functions:       SQLGetInfo, SQLGetTypeInfo, SQLGetFunctions,
 
10
 *                                      SQLTables, SQLColumns, SQLStatistics, SQLSpecialColumns,
 
11
 *                                      SQLPrimaryKeys, SQLForeignKeys,
 
12
 *                                      SQLProcedureColumns(NI), SQLProcedures,
 
13
 *                                      SQLTablePrivileges, SQLColumnPrivileges(NI)
 
14
 *
 
15
 * Comments:            See "notice.txt" for copyright and license information.
 
16
 *--------
 
17
 */
 
18
 
 
19
#include "psqlodbc.h"
 
20
 
 
21
#include <string.h>
 
22
#include <stdio.h>
 
23
 
 
24
#ifndef WIN32
 
25
#include <ctype.h>
 
26
#endif
 
27
 
 
28
#include "tuple.h"
 
29
#include "pgtypes.h"
 
30
#include "dlg_specific.h"
 
31
 
 
32
#include "environ.h"
 
33
#include "connection.h"
 
34
#include "statement.h"
 
35
#include "qresult.h"
 
36
#include "bind.h"
 
37
#include "misc.h"
 
38
#include "pgtypes.h"
 
39
#include "pgapifunc.h"
 
40
#include "multibyte.h"
 
41
 
 
42
 
 
43
/*      Trigger related stuff for SQLForeign Keys */
 
44
#define TRIGGER_SHIFT 3
 
45
#define TRIGGER_MASK   0x03
 
46
#define TRIGGER_DELETE 0x01
 
47
#define TRIGGER_UPDATE 0x02
 
48
 
 
49
 
 
50
/* extern GLOBAL_VALUES globals; */
 
51
 
 
52
 
 
53
 
 
54
RETCODE         SQL_API
 
55
PGAPI_GetInfo(
 
56
                          HDBC hdbc,
 
57
                          UWORD fInfoType,
 
58
                          PTR rgbInfoValue,
 
59
                          SWORD cbInfoValueMax,
 
60
                          SWORD FAR * pcbInfoValue)
 
61
{
 
62
        CSTR func = "PGAPI_GetInfo";
 
63
        ConnectionClass *conn = (ConnectionClass *) hdbc;
 
64
        ConnInfo   *ci;
 
65
        char       *p = NULL,
 
66
                                tmp[MAX_INFO_STRING];
 
67
        int                     len = 0,
 
68
                                value = 0;
 
69
        RETCODE         result;
 
70
 
 
71
        mylog("%s: entering...fInfoType=%d\n", func, fInfoType);
 
72
 
 
73
        if (!conn)
 
74
        {
 
75
                CC_log_error(func, "", NULL);
 
76
                return SQL_INVALID_HANDLE;
 
77
        }
 
78
 
 
79
        ci = &(conn->connInfo);
 
80
 
 
81
        switch (fInfoType)
 
82
        {
 
83
                case SQL_ACCESSIBLE_PROCEDURES: /* ODBC 1.0 */
 
84
                        p = "N";
 
85
                        break;
 
86
 
 
87
                case SQL_ACCESSIBLE_TABLES:             /* ODBC 1.0 */
 
88
                        p = "N";
 
89
                        break;
 
90
 
 
91
                case SQL_ACTIVE_CONNECTIONS:    /* ODBC 1.0 */
 
92
                        len = 2;
 
93
                        value = MAX_CONNECTIONS;
 
94
                        break;
 
95
 
 
96
                case SQL_ACTIVE_STATEMENTS:             /* ODBC 1.0 */
 
97
                        len = 2;
 
98
                        value = 0;
 
99
                        break;
 
100
 
 
101
                case SQL_ALTER_TABLE:   /* ODBC 2.0 */
 
102
                        len = 4;
 
103
                        value = SQL_AT_ADD_COLUMN;
 
104
                        if (PG_VERSION_GE(conn, 7.3))
 
105
                                value |= SQL_AT_DROP_COLUMN;
 
106
#if (ODBCVER >= 0x0300)
 
107
                        value |= SQL_AT_ADD_COLUMN_SINGLE;
 
108
                        if (PG_VERSION_GE(conn, 7.1))
 
109
                                value |= SQL_AT_ADD_CONSTRAINT
 
110
                                        | SQL_AT_ADD_TABLE_CONSTRAINT
 
111
                                        | SQL_AT_CONSTRAINT_INITIALLY_DEFERRED
 
112
                                        | SQL_AT_CONSTRAINT_INITIALLY_IMMEDIATE
 
113
                                        | SQL_AT_CONSTRAINT_DEFERRABLE;
 
114
                        if (PG_VERSION_GE(conn, 7.3))
 
115
                                value |= SQL_AT_DROP_TABLE_CONSTRAINT_RESTRICT
 
116
                                        | SQL_AT_DROP_TABLE_CONSTRAINT_CASCADE
 
117
                                        | SQL_AT_DROP_COLUMN_RESTRICT
 
118
                                        | SQL_AT_DROP_COLUMN_CASCADE;
 
119
#endif /* ODBCVER */
 
120
                        break;
 
121
 
 
122
                case SQL_BOOKMARK_PERSISTENCE:  /* ODBC 2.0 */
 
123
                        /* very simple bookmark support */
 
124
                        len = 4;
 
125
                        value = ci->drivers.use_declarefetch ? 0 : (SQL_BP_SCROLL | SQL_BP_DELETE | SQL_BP_UPDATE | SQL_BP_TRANSACTION);
 
126
                        break;
 
127
 
 
128
                case SQL_COLUMN_ALIAS:  /* ODBC 2.0 */
 
129
                        p = "N";
 
130
                        break;
 
131
 
 
132
                case SQL_CONCAT_NULL_BEHAVIOR:  /* ODBC 1.0 */
 
133
                        len = 2;
 
134
                        value = SQL_CB_NON_NULL;
 
135
                        break;
 
136
 
 
137
                case SQL_CONVERT_BIGINT:
 
138
                case SQL_CONVERT_BINARY:
 
139
                case SQL_CONVERT_BIT:
 
140
                case SQL_CONVERT_CHAR:
 
141
                case SQL_CONVERT_DATE:
 
142
                case SQL_CONVERT_DECIMAL:
 
143
                case SQL_CONVERT_DOUBLE:
 
144
                case SQL_CONVERT_FLOAT:
 
145
                case SQL_CONVERT_INTEGER:
 
146
                case SQL_CONVERT_LONGVARBINARY:
 
147
                case SQL_CONVERT_LONGVARCHAR:
 
148
                case SQL_CONVERT_NUMERIC:
 
149
                case SQL_CONVERT_REAL:
 
150
                case SQL_CONVERT_SMALLINT:
 
151
                case SQL_CONVERT_TIME:
 
152
                case SQL_CONVERT_TIMESTAMP:
 
153
                case SQL_CONVERT_TINYINT:
 
154
                case SQL_CONVERT_VARBINARY:
 
155
                case SQL_CONVERT_VARCHAR:               /* ODBC 1.0 */
 
156
                        len = 4;
 
157
                        value = fInfoType;
 
158
                        break;
 
159
 
 
160
                case SQL_CONVERT_FUNCTIONS:             /* ODBC 1.0 */
 
161
                        len = 4;
 
162
                        value = 0;
 
163
                        break;
 
164
 
 
165
                case SQL_CORRELATION_NAME:              /* ODBC 1.0 */
 
166
 
 
167
                        /*
 
168
                         * Saying no correlation name makes Query not work right.
 
169
                         * value = SQL_CN_NONE;
 
170
                         */
 
171
                        len = 2;
 
172
                        value = SQL_CN_ANY;
 
173
                        break;
 
174
 
 
175
                case SQL_CURSOR_COMMIT_BEHAVIOR:                /* ODBC 1.0 */
 
176
                        len = 2;
 
177
                        value = SQL_CB_CLOSE;
 
178
                        if (!ci->drivers.use_declarefetch)
 
179
                                value = SQL_CB_PRESERVE;
 
180
                        break;
 
181
 
 
182
                case SQL_CURSOR_ROLLBACK_BEHAVIOR:              /* ODBC 1.0 */
 
183
                        len = 2;
 
184
                        value = SQL_CB_CLOSE;
 
185
                        if (!ci->drivers.use_declarefetch)
 
186
                                value = SQL_CB_PRESERVE;
 
187
                        break;
 
188
 
 
189
                case SQL_DATA_SOURCE_NAME:              /* ODBC 1.0 */
 
190
                        p = CC_get_DSN(conn);
 
191
                        break;
 
192
 
 
193
                case SQL_DATA_SOURCE_READ_ONLY: /* ODBC 1.0 */
 
194
                        p = CC_is_onlyread(conn) ? "Y" : "N";
 
195
                        break;
 
196
 
 
197
                case SQL_DATABASE_NAME: /* Support for old ODBC 1.0 Apps */
 
198
 
 
199
                        /*
 
200
                         * Returning the database name causes problems in MS Query. It
 
201
                         * generates query like: "SELECT DISTINCT a FROM byronnbad3
 
202
                         * bad3"
 
203
                         *
 
204
                         * p = CC_get_database(conn);
 
205
                         */
 
206
                        p = "";
 
207
                        break;
 
208
 
 
209
                case SQL_DBMS_NAME:             /* ODBC 1.0 */
 
210
                        p = DBMS_NAME;
 
211
                        break;
 
212
 
 
213
                case SQL_DBMS_VER:              /* ODBC 1.0 */
 
214
 
 
215
                        /*
 
216
                         * The ODBC spec wants ##.##.#### ...whatever... so prepend
 
217
                         * the driver
 
218
                         */
 
219
                        /* version number to the dbms version string */
 
220
                        snprintf(tmp, sizeof(tmp) - 1, "%s %s", POSTGRESDRIVERVERSION, conn->pg_version);
 
221
                        tmp[sizeof(tmp) - 1] = '\0';
 
222
                        p = tmp;
 
223
                        break;
 
224
 
 
225
                case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */
 
226
                        len = 4;
 
227
                        if (PG_VERSION_LT(conn, 6.5))
 
228
                                value = SQL_TXN_SERIALIZABLE;
 
229
                        else
 
230
                                value = SQL_TXN_READ_COMMITTED;
 
231
                        break;
 
232
 
 
233
                case SQL_DRIVER_NAME:   /* ODBC 1.0 */
 
234
                        p = DRIVER_FILE_NAME;
 
235
                        break;
 
236
 
 
237
                case SQL_DRIVER_ODBC_VER:
 
238
                        p = DRIVER_ODBC_VER;
 
239
                        break;
 
240
 
 
241
                case SQL_DRIVER_VER:    /* ODBC 1.0 */
 
242
                        p = POSTGRESDRIVERVERSION;
 
243
                        break;
 
244
 
 
245
                case SQL_EXPRESSIONS_IN_ORDERBY:                /* ODBC 1.0 */
 
246
                        p = "N";
 
247
                        break;
 
248
 
 
249
                case SQL_FETCH_DIRECTION:               /* ODBC 1.0 */
 
250
                        len = 4;
 
251
                        value = ci->drivers.use_declarefetch ? (SQL_FD_FETCH_NEXT) :
 
252
                         (SQL_FD_FETCH_NEXT | 
 
253
                         SQL_FD_FETCH_FIRST |
 
254
                         SQL_FD_FETCH_LAST |
 
255
                         SQL_FD_FETCH_PRIOR |
 
256
                         SQL_FD_FETCH_ABSOLUTE |
 
257
                         SQL_FD_FETCH_RELATIVE |
 
258
                         SQL_FD_FETCH_BOOKMARK);
 
259
                        break;
 
260
 
 
261
                case SQL_FILE_USAGE:    /* ODBC 2.0 */
 
262
                        len = 2;
 
263
                        value = SQL_FILE_NOT_SUPPORTED;
 
264
                        break;
 
265
 
 
266
                case SQL_GETDATA_EXTENSIONS:    /* ODBC 2.0 */
 
267
                        len = 4;
 
268
                        value = (SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND | SQL_GD_BLOCK);
 
269
                        break;
 
270
 
 
271
                case SQL_GROUP_BY:              /* ODBC 2.0 */
 
272
                        len = 2;
 
273
                        value = SQL_GB_GROUP_BY_EQUALS_SELECT;
 
274
                        break;
 
275
 
 
276
                case SQL_IDENTIFIER_CASE:               /* ODBC 1.0 */
 
277
 
 
278
                        /*
 
279
                         * are identifiers case-sensitive (yes, but only when quoted.
 
280
                         * If not quoted, they default to lowercase)
 
281
                         */
 
282
                        len = 2;
 
283
                        value = SQL_IC_LOWER;
 
284
                        break;
 
285
 
 
286
                case SQL_IDENTIFIER_QUOTE_CHAR: /* ODBC 1.0 */
 
287
                        /* the character used to quote "identifiers" */
 
288
                        p = PG_VERSION_LE(conn, 6.2) ? " " : "\"";
 
289
                        break;
 
290
 
 
291
                case SQL_KEYWORDS:              /* ODBC 2.0 */
 
292
                        p = "";
 
293
                        break;
 
294
 
 
295
                case SQL_LIKE_ESCAPE_CLAUSE:    /* ODBC 2.0 */
 
296
 
 
297
                        /*
 
298
                         * is there a character that escapes '%' and '_' in a LIKE
 
299
                         * clause? not as far as I can tell
 
300
                         */
 
301
                        p = "N";
 
302
                        break;
 
303
 
 
304
                case SQL_LOCK_TYPES:    /* ODBC 2.0 */
 
305
                        len = 4;
 
306
                        value = ci->drivers.lie ? (SQL_LCK_NO_CHANGE | SQL_LCK_EXCLUSIVE | SQL_LCK_UNLOCK) : SQL_LCK_NO_CHANGE;
 
307
                        break;
 
308
 
 
309
                case SQL_MAX_BINARY_LITERAL_LEN:                /* ODBC 2.0 */
 
310
                        len = 4;
 
311
                        value = 0;
 
312
                        break;
 
313
 
 
314
                case SQL_MAX_CHAR_LITERAL_LEN:  /* ODBC 2.0 */
 
315
                        len = 4;
 
316
                        value = 0;
 
317
                        break;
 
318
 
 
319
                case SQL_MAX_COLUMN_NAME_LEN:   /* ODBC 1.0 */
 
320
                        len = 2;
 
321
#ifdef  MAX_COLUMN_LEN
 
322
                        value = MAX_COLUMN_LEN;
 
323
#endif /* MAX_COLUMN_LEN */
 
324
                        if (0 == value)
 
325
                        {
 
326
                                if (PG_VERSION_GE(conn, 7.3))
 
327
                                        value = NAMEDATALEN_V73;
 
328
                                else
 
329
                                        value = NAMEDATALEN_V72;
 
330
                        }
 
331
                        break;
 
332
 
 
333
                case SQL_MAX_COLUMNS_IN_GROUP_BY:               /* ODBC 2.0 */
 
334
                        len = 2;
 
335
                        value = 0;
 
336
                        break;
 
337
 
 
338
                case SQL_MAX_COLUMNS_IN_INDEX:  /* ODBC 2.0 */
 
339
                        len = 2;
 
340
                        value = 0;
 
341
                        break;
 
342
 
 
343
                case SQL_MAX_COLUMNS_IN_ORDER_BY:               /* ODBC 2.0 */
 
344
                        len = 2;
 
345
                        value = 0;
 
346
                        break;
 
347
 
 
348
                case SQL_MAX_COLUMNS_IN_SELECT: /* ODBC 2.0 */
 
349
                        len = 2;
 
350
                        value = 0;
 
351
                        break;
 
352
 
 
353
                case SQL_MAX_COLUMNS_IN_TABLE:  /* ODBC 2.0 */
 
354
                        len = 2;
 
355
                        value = 0;
 
356
                        break;
 
357
 
 
358
                case SQL_MAX_CURSOR_NAME_LEN:   /* ODBC 1.0 */
 
359
                        len = 2;
 
360
                        value = MAX_CURSOR_LEN;
 
361
                        break;
 
362
 
 
363
                case SQL_MAX_INDEX_SIZE:                /* ODBC 2.0 */
 
364
                        len = 4;
 
365
                        value = 0;
 
366
                        break;
 
367
 
 
368
                case SQL_MAX_OWNER_NAME_LEN:    /* ODBC 1.0 */
 
369
                        len = 2;
 
370
                        value = 0;
 
371
#ifdef  MAX_SCHEMA_LEN
 
372
                        if (conn->schema_support)
 
373
                                value = MAX_SCHEMA_LEN;
 
374
#endif /* MAX_SCHEMA_LEN */
 
375
                        if (0 == value)
 
376
                        {
 
377
                                if (PG_VERSION_GE(conn, 7.3))
 
378
                                        value = NAMEDATALEN_V73;
 
379
                        }
 
380
                        break;
 
381
 
 
382
                case SQL_MAX_PROCEDURE_NAME_LEN:                /* ODBC 1.0 */
 
383
                        len = 2;
 
384
                        value = 0;
 
385
                        break;
 
386
 
 
387
                case SQL_MAX_QUALIFIER_NAME_LEN:                /* ODBC 1.0 */
 
388
                        len = 2;
 
389
                        value = 0;
 
390
                        break;
 
391
 
 
392
                case SQL_MAX_ROW_SIZE:  /* ODBC 2.0 */
 
393
                        len = 4;
 
394
                        if (PG_VERSION_GE(conn, 7.1))
 
395
                        {
 
396
                                /* Large Rowa in 7.1+ */
 
397
                                value = MAX_ROW_SIZE;
 
398
                        }
 
399
                        else
 
400
                        {
 
401
                                /* Without the Toaster we're limited to the blocksize */
 
402
                                value = BLCKSZ;
 
403
                        }
 
404
                        break;
 
405
 
 
406
                case SQL_MAX_ROW_SIZE_INCLUDES_LONG:    /* ODBC 2.0 */
 
407
 
 
408
                        /*
 
409
                         * does the preceding value include LONGVARCHAR and
 
410
                         * LONGVARBINARY fields?   Well, it does include longvarchar,
 
411
                         * but not longvarbinary.
 
412
                         */
 
413
                        p = "Y";
 
414
                        break;
 
415
 
 
416
                case SQL_MAX_STATEMENT_LEN:             /* ODBC 2.0 */
 
417
                        /* maybe this should be 0? */
 
418
                        len = 4;
 
419
                        value = CC_get_max_query_len(conn);
 
420
                        break;
 
421
 
 
422
                case SQL_MAX_TABLE_NAME_LEN:    /* ODBC 1.0 */
 
423
                        len = 2;
 
424
#ifdef  MAX_TABLE_LEN
 
425
                        value = MAX_TABLE_LEN;
 
426
#endif /* MAX_TABLE_LEN */
 
427
                        if (0 == value)
 
428
                        {
 
429
                                if (PG_VERSION_GE(conn, 7.3))
 
430
                                        value = NAMEDATALEN_V73;
 
431
                                else
 
432
                                        value = NAMEDATALEN_V72;
 
433
                        }
 
434
                        break;
 
435
 
 
436
                case SQL_MAX_TABLES_IN_SELECT:  /* ODBC 2.0 */
 
437
                        len = 2;
 
438
                        value = 0;
 
439
                        break;
 
440
 
 
441
                case SQL_MAX_USER_NAME_LEN:
 
442
                        len = 2;
 
443
                        value = 0;
 
444
                        break;
 
445
 
 
446
                case SQL_MULT_RESULT_SETS:              /* ODBC 1.0 */
 
447
                        /* Don't support multiple result sets but say yes anyway? */
 
448
                        p = "Y";
 
449
                        break;
 
450
 
 
451
                case SQL_MULTIPLE_ACTIVE_TXN:   /* ODBC 1.0 */
 
452
                        p = "Y";
 
453
                        break;
 
454
 
 
455
                case SQL_NEED_LONG_DATA_LEN:    /* ODBC 2.0 */
 
456
 
 
457
                        /*
 
458
                         * Don't need the length, SQLPutData can handle any size and
 
459
                         * multiple calls
 
460
                         */
 
461
                        p = "N";
 
462
                        break;
 
463
 
 
464
                case SQL_NON_NULLABLE_COLUMNS:  /* ODBC 1.0 */
 
465
                        len = 2;
 
466
                        value = SQL_NNC_NON_NULL;
 
467
                        break;
 
468
 
 
469
                case SQL_NULL_COLLATION:                /* ODBC 2.0 */
 
470
                        /* where are nulls sorted? */
 
471
                        len = 2;
 
472
                        value = SQL_NC_END;
 
473
                        break;
 
474
 
 
475
                case SQL_NUMERIC_FUNCTIONS:             /* ODBC 1.0 */
 
476
                        len = 4;
 
477
                        value = 0;
 
478
                        break;
 
479
 
 
480
                case SQL_ODBC_API_CONFORMANCE:  /* ODBC 1.0 */
 
481
                        len = 2;
 
482
                        value = SQL_OAC_LEVEL1;
 
483
                        break;
 
484
 
 
485
                case SQL_ODBC_SAG_CLI_CONFORMANCE:              /* ODBC 1.0 */
 
486
                        len = 2;
 
487
                        value = SQL_OSCC_NOT_COMPLIANT;
 
488
                        break;
 
489
 
 
490
                case SQL_ODBC_SQL_CONFORMANCE:  /* ODBC 1.0 */
 
491
                        len = 2;
 
492
                        value = SQL_OSC_CORE;
 
493
                        break;
 
494
 
 
495
                case SQL_ODBC_SQL_OPT_IEF:              /* ODBC 1.0 */
 
496
                        p = "N";
 
497
                        break;
 
498
 
 
499
                case SQL_OJ_CAPABILITIES:               /* ODBC 2.01 */
 
500
                        len = 4;
 
501
                        if (PG_VERSION_GE(conn, 7.1))
 
502
                        {
 
503
                                /* OJs in 7.1+ */
 
504
                                value = (SQL_OJ_LEFT |
 
505
                                                 SQL_OJ_RIGHT |
 
506
                                                 SQL_OJ_FULL |
 
507
                                                 SQL_OJ_NESTED |
 
508
                                                 SQL_OJ_NOT_ORDERED |
 
509
                                                 SQL_OJ_INNER |
 
510
                                                 SQL_OJ_ALL_COMPARISON_OPS);
 
511
                        }
 
512
                        else
 
513
                                /* OJs not in <7.1 */
 
514
                                value = 0;
 
515
                        break;
 
516
 
 
517
                case SQL_ORDER_BY_COLUMNS_IN_SELECT:    /* ODBC 2.0 */
 
518
                        p = (PG_VERSION_LE(conn, 6.3)) ? "Y" : "N";
 
519
                        break;
 
520
 
 
521
                case SQL_OUTER_JOINS:   /* ODBC 1.0 */
 
522
                        if (PG_VERSION_GE(conn, 7.1))
 
523
                                /* OJs in 7.1+ */
 
524
                                p = "Y";
 
525
                        else
 
526
                                /* OJs not in <7.1 */
 
527
                                p = "N";
 
528
                        break;
 
529
 
 
530
                case SQL_OWNER_TERM:    /* ODBC 1.0 */
 
531
                        if (conn->schema_support)
 
532
                                p = "schema";
 
533
                        else
 
534
                                p = "owner";
 
535
                        break;
 
536
 
 
537
                case SQL_OWNER_USAGE:   /* ODBC 2.0 */
 
538
                        len = 4;
 
539
                        value = 0;
 
540
                        if (conn->schema_support)
 
541
                                value = SQL_OU_DML_STATEMENTS
 
542
                                        | SQL_OU_TABLE_DEFINITION
 
543
                                        | SQL_OU_INDEX_DEFINITION
 
544
                                        | SQL_OU_PRIVILEGE_DEFINITION
 
545
                                        ;
 
546
                        break;
 
547
 
 
548
                case SQL_POS_OPERATIONS:                /* ODBC 2.0 */
 
549
                        len = 4;
 
550
                        value = (SQL_POS_POSITION | SQL_POS_REFRESH);
 
551
#ifdef  DRIVER_CURSOR_IMPLEMENT
 
552
                        if (ci->updatable_cursors)
 
553
                                value |= (SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD);
 
554
#endif /* DRIVER_CURSOR_IMPLEMENT */
 
555
                        break;
 
556
 
 
557
                case SQL_POSITIONED_STATEMENTS: /* ODBC 2.0 */
 
558
                        len = 4;
 
559
                        value = ci->drivers.lie ? (SQL_PS_POSITIONED_DELETE |
 
560
                                                                           SQL_PS_POSITIONED_UPDATE |
 
561
                                                                           SQL_PS_SELECT_FOR_UPDATE) : 0;
 
562
                        break;
 
563
 
 
564
                case SQL_PROCEDURE_TERM:                /* ODBC 1.0 */
 
565
                        p = "procedure";
 
566
                        break;
 
567
 
 
568
                case SQL_PROCEDURES:    /* ODBC 1.0 */
 
569
                        p = "Y";
 
570
                        break;
 
571
 
 
572
                case SQL_QUALIFIER_LOCATION:    /* ODBC 2.0 */
 
573
                        len = 2;
 
574
                        value = SQL_QL_START;
 
575
                        break;
 
576
 
 
577
                case SQL_QUALIFIER_NAME_SEPARATOR:              /* ODBC 1.0 */
 
578
                        p = "";
 
579
                        break;
 
580
 
 
581
                case SQL_QUALIFIER_TERM:                /* ODBC 1.0 */
 
582
                        p = "";
 
583
                        break;
 
584
 
 
585
                case SQL_QUALIFIER_USAGE:               /* ODBC 2.0 */
 
586
                        len = 4;
 
587
                        value = 0;
 
588
                        break;
 
589
 
 
590
                case SQL_QUOTED_IDENTIFIER_CASE:                /* ODBC 2.0 */
 
591
                        /* are "quoted" identifiers case-sensitive?  YES! */
 
592
                        len = 2;
 
593
                        value = SQL_IC_SENSITIVE;
 
594
                        break;
 
595
 
 
596
                case SQL_ROW_UPDATES:   /* ODBC 1.0 */
 
597
 
 
598
                        /*
 
599
                         * Driver doesn't support keyset-driven or mixed cursors, so
 
600
                         * not much point in saying row updates are supported
 
601
                         */
 
602
                        p = (ci->updatable_cursors) ? "Y" : "N";
 
603
                        break;
 
604
 
 
605
                case SQL_SCROLL_CONCURRENCY:    /* ODBC 1.0 */
 
606
                        len = 4;
 
607
                        value = SQL_SCCO_READ_ONLY;
 
608
#ifdef  DRIVER_CURSOR_IMPLEMENT
 
609
                        if (ci->updatable_cursors)
 
610
                                value |= SQL_SCCO_OPT_ROWVER;
 
611
#endif /* DRIVER_CURSOR_IMPLEMENT */
 
612
                        if (ci->drivers.lie)
 
613
                                value |= (SQL_SCCO_LOCK | SQL_SCCO_OPT_VALUES);
 
614
                        break;
 
615
 
 
616
                case SQL_SCROLL_OPTIONS:                /* ODBC 1.0 */
 
617
                        len = 4;
 
618
                        value = SQL_SO_FORWARD_ONLY;
 
619
#ifdef  DECLAREFETCH_FORWARDONLY
 
620
                        if (!ci->drivers.use_declarefetch)
 
621
#endif /* DECLAREFETCH_FORWARDONLY */
 
622
                                value |= SQL_SO_STATIC;
 
623
                        if (ci->updatable_cursors)
 
624
                                value |= SQL_SO_KEYSET_DRIVEN;
 
625
                        if (ci->drivers.lie)
 
626
                                value |= (SQL_SO_DYNAMIC | SQL_SO_MIXED);
 
627
                        break;
 
628
 
 
629
                case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */
 
630
                        if (PG_VERSION_GE(conn, 6.5))
 
631
                                p = "\\";
 
632
                        else
 
633
                                p = "";
 
634
                        break;
 
635
 
 
636
                case SQL_SERVER_NAME:   /* ODBC 1.0 */
 
637
                        p = CC_get_server(conn);
 
638
                        break;
 
639
 
 
640
                case SQL_SPECIAL_CHARACTERS:    /* ODBC 2.0 */
 
641
                        p = "_";
 
642
                        break;
 
643
 
 
644
                case SQL_STATIC_SENSITIVITY:    /* ODBC 2.0 */
 
645
                        len = 4;
 
646
                        value = 0;
 
647
#ifdef  DRIVER_CURSOR_IMPLEMENT
 
648
                        if (ci->updatable_cursors)
 
649
                                value |= (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES);
 
650
#endif /* DRIVER_CURSOR_IMPLEMENT */
 
651
                        break;
 
652
 
 
653
                case SQL_STRING_FUNCTIONS:              /* ODBC 1.0 */
 
654
                        len = 4;
 
655
                        value = (SQL_FN_STR_CONCAT |
 
656
                                         SQL_FN_STR_LCASE |
 
657
                                         SQL_FN_STR_LENGTH |
 
658
                                         SQL_FN_STR_LOCATE |
 
659
                                         SQL_FN_STR_LTRIM |
 
660
                                         SQL_FN_STR_RTRIM |
 
661
                                         SQL_FN_STR_SUBSTRING |
 
662
                                         SQL_FN_STR_UCASE);
 
663
                        break;
 
664
 
 
665
                case SQL_SUBQUERIES:    /* ODBC 2.0 */
 
666
                        /* postgres 6.3 supports subqueries */
 
667
                        len = 4;
 
668
                        value = (SQL_SQ_QUANTIFIED |
 
669
                                         SQL_SQ_IN |
 
670
                                         SQL_SQ_EXISTS |
 
671
                                         SQL_SQ_COMPARISON);
 
672
                        break;
 
673
 
 
674
                case SQL_SYSTEM_FUNCTIONS:              /* ODBC 1.0 */
 
675
                        len = 4;
 
676
                        value = 0;
 
677
                        break;
 
678
 
 
679
                case SQL_TABLE_TERM:    /* ODBC 1.0 */
 
680
                        p = "table";
 
681
                        break;
 
682
 
 
683
                case SQL_TIMEDATE_ADD_INTERVALS:                /* ODBC 2.0 */
 
684
                        len = 4;
 
685
                        value = 0;
 
686
                        break;
 
687
 
 
688
                case SQL_TIMEDATE_DIFF_INTERVALS:               /* ODBC 2.0 */
 
689
                        len = 4;
 
690
                        value = 0;
 
691
                        break;
 
692
 
 
693
                case SQL_TIMEDATE_FUNCTIONS:    /* ODBC 1.0 */
 
694
                        len = 4;
 
695
                        value = (SQL_FN_TD_NOW);
 
696
                        break;
 
697
 
 
698
                case SQL_TXN_CAPABLE:   /* ODBC 1.0 */
 
699
 
 
700
                        /*
 
701
                         * Postgres can deal with create or drop table statements in a
 
702
                         * transaction
 
703
                         */
 
704
                        len = 2;
 
705
                        value = SQL_TC_ALL;
 
706
                        break;
 
707
 
 
708
                case SQL_TXN_ISOLATION_OPTION:  /* ODBC 1.0 */
 
709
                        len = 4;
 
710
                        if (PG_VERSION_LT(conn, 6.5))
 
711
                                value = SQL_TXN_SERIALIZABLE;
 
712
                        else if (PG_VERSION_GE(conn, 7.1))
 
713
                                value = SQL_TXN_READ_COMMITTED | SQL_TXN_SERIALIZABLE;
 
714
                        else
 
715
                                value = SQL_TXN_READ_COMMITTED;
 
716
                        break;
 
717
 
 
718
                case SQL_UNION: /* ODBC 2.0 */
 
719
                        /* unions with all supported in postgres 6.3 */
 
720
                        len = 4;
 
721
                        value = (SQL_U_UNION | SQL_U_UNION_ALL);
 
722
                        break;
 
723
 
 
724
                case SQL_USER_NAME:             /* ODBC 1.0 */
 
725
                        p = CC_get_username(conn);
 
726
                        break;
 
727
 
 
728
                default:
 
729
                        /* unrecognized key */
 
730
                        CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Unrecognized key passed to PGAPI_GetInfo.");
 
731
                        return SQL_ERROR;
 
732
        }
 
733
 
 
734
        result = SQL_SUCCESS;
 
735
 
 
736
        mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func, p ? p : "<NULL>", len, value, cbInfoValueMax);
 
737
 
 
738
        /*
 
739
         * NOTE, that if rgbInfoValue is NULL, then no warnings or errors
 
740
         * should result and just pcbInfoValue is returned, which indicates
 
741
         * what length would be required if a real buffer had been passed in.
 
742
         */
 
743
        if (p)
 
744
        {
 
745
                /* char/binary data */
 
746
                len = strlen(p);
 
747
 
 
748
                if (rgbInfoValue)
 
749
                {
 
750
#ifdef  UNICODE_SUPPORT
 
751
                        if (conn->unicode)
 
752
                        {
 
753
                                len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / 2);
 
754
                                len *= 2;
 
755
                        }
 
756
                        else
 
757
#endif /* UNICODE_SUPPORT */
 
758
                        strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax);
 
759
 
 
760
                        if (len >= cbInfoValueMax)
 
761
                        {
 
762
                                result = SQL_SUCCESS_WITH_INFO;
 
763
                                CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for tthe InfoValue.");
 
764
                        }
 
765
                }
 
766
        }
 
767
        else
 
768
        {
 
769
                /* numeric data */
 
770
                if (rgbInfoValue)
 
771
                {
 
772
                        if (len == 2)
 
773
                                *((WORD *) rgbInfoValue) = (WORD) value;
 
774
                        else if (len == 4)
 
775
                                *((DWORD *) rgbInfoValue) = (DWORD) value;
 
776
                }
 
777
        }
 
778
 
 
779
        if (pcbInfoValue)
 
780
                *pcbInfoValue = len;
 
781
 
 
782
        return result;
 
783
}
 
784
 
 
785
 
 
786
RETCODE         SQL_API
 
787
PGAPI_GetTypeInfo(
 
788
                                  HSTMT hstmt,
 
789
                                  SWORD fSqlType)
 
790
{
 
791
        CSTR func = "PGAPI_GetTypeInfo";
 
792
        StatementClass *stmt = (StatementClass *) hstmt;
 
793
        QResultClass    *res;
 
794
        TupleNode  *row;
 
795
        int                     i, result_cols;
 
796
 
 
797
        /* Int4 type; */
 
798
        Int4            pgType;
 
799
        Int2            sqlType;
 
800
 
 
801
        mylog("%s: entering...fSqlType = %d\n", func, fSqlType);
 
802
 
 
803
        if (!stmt)
 
804
        {
 
805
                SC_log_error(func, "", NULL);
 
806
                return SQL_INVALID_HANDLE;
 
807
        }
 
808
 
 
809
        stmt->manual_result = TRUE;
 
810
        if (res = QR_Constructor(), !res)
 
811
        {
 
812
                SC_log_error(func, "Error creating result.", stmt);
 
813
                return SQL_ERROR;
 
814
        }
 
815
        SC_set_Result(stmt, res);
 
816
 
 
817
#if (ODBCVER >= 0x0300)
 
818
        result_cols = 19;
 
819
#else
 
820
        result_cols = 15;
 
821
#endif /* ODBCVER */
 
822
        extend_column_bindings(SC_get_ARD(stmt), result_cols);
 
823
 
 
824
        QR_set_num_fields(res, result_cols);
 
825
        QR_set_field_info(res, 0, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
826
        QR_set_field_info(res, 1, "DATA_TYPE", PG_TYPE_INT2, 2);
 
827
        QR_set_field_info(res, 2, "PRECISION", PG_TYPE_INT4, 4);
 
828
        QR_set_field_info(res, 3, "LITERAL_PREFIX", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
829
        QR_set_field_info(res, 4, "LITERAL_SUFFIX", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
830
        QR_set_field_info(res, 5, "CREATE_PARAMS", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
831
        QR_set_field_info(res, 6, "NULLABLE", PG_TYPE_INT2, 2);
 
832
        QR_set_field_info(res, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2);
 
833
        QR_set_field_info(res, 8, "SEARCHABLE", PG_TYPE_INT2, 2);
 
834
        QR_set_field_info(res, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2);
 
835
        QR_set_field_info(res, 10, "MONEY", PG_TYPE_INT2, 2);
 
836
        QR_set_field_info(res, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2);
 
837
        QR_set_field_info(res, 12, "LOCAL_TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
838
        QR_set_field_info(res, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
 
839
        QR_set_field_info(res, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
 
840
#if (ODBCVER >=0x0300)
 
841
        QR_set_field_info(res, 15, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
 
842
        QR_set_field_info(res, 16, "SQL_DATATIME_SUB", PG_TYPE_INT2, 2);
 
843
        QR_set_field_info(res, 17, "NUM_PREC_RADIX", PG_TYPE_INT4, 4);
 
844
        QR_set_field_info(res, 18, "INTERVAL_PRECISION", PG_TYPE_INT2, 2);
 
845
#endif /* ODBCVER */
 
846
 
 
847
        for (i = 0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i])
 
848
        {
 
849
                pgType = sqltype_to_pgtype(stmt, sqlType);
 
850
 
 
851
                if (fSqlType == SQL_ALL_TYPES || fSqlType == sqlType)
 
852
                {
 
853
                        int     pgtcount = 1, cnt;
 
854
 
 
855
                        if (SQL_INTEGER == sqlType && PG_VERSION_GE(SC_get_conn(stmt), 6.4))
 
856
                                pgtcount = 2;
 
857
                        for (cnt = 0; cnt < pgtcount; cnt ++)
 
858
                        {
 
859
 
 
860
                        row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) * sizeof(TupleField));
 
861
 
 
862
                        /* These values can't be NULL */
 
863
                        if (1 == cnt)
 
864
                        {
 
865
                                set_tuplefield_string(&row->tuple[0], "serial");
 
866
                                set_tuplefield_int2(&row->tuple[6], SQL_NO_NULLS);
 
867
inolog("serial in\n");
 
868
                        }
 
869
                        else
 
870
                        {
 
871
                                set_tuplefield_string(&row->tuple[0], pgtype_to_name(stmt, pgType));
 
872
                                set_tuplefield_int2(&row->tuple[6], pgtype_nullable(stmt, pgType));
 
873
                        }
 
874
                        set_tuplefield_int2(&row->tuple[1], (Int2) sqlType);
 
875
                        set_tuplefield_int2(&row->tuple[7], pgtype_case_sensitive(stmt, pgType));
 
876
                        set_tuplefield_int2(&row->tuple[8], pgtype_searchable(stmt, pgType));
 
877
                        set_tuplefield_int2(&row->tuple[10], pgtype_money(stmt, pgType));
 
878
 
 
879
                        /*
 
880
                         * Localized data-source dependent data type name (always
 
881
                         * NULL)
 
882
                         */
 
883
                        set_tuplefield_null(&row->tuple[12]);
 
884
 
 
885
                        /* These values can be NULL */
 
886
                        set_nullfield_int4(&row->tuple[2], pgtype_column_size(stmt, pgType, PG_STATIC, PG_STATIC));
 
887
                        set_nullfield_string(&row->tuple[3], pgtype_literal_prefix(stmt, pgType));
 
888
                        set_nullfield_string(&row->tuple[4], pgtype_literal_suffix(stmt, pgType));
 
889
                        set_nullfield_string(&row->tuple[5], pgtype_create_params(stmt, pgType));
 
890
                        if (1 == cnt)
 
891
                        {
 
892
                                set_nullfield_int2(&row->tuple[9], TRUE);
 
893
                                set_nullfield_int2(&row->tuple[11], TRUE);
 
894
                        }
 
895
                        else
 
896
                        {
 
897
                                set_nullfield_int2(&row->tuple[9], pgtype_unsigned(stmt, pgType));
 
898
                                set_nullfield_int2(&row->tuple[11], pgtype_auto_increment(stmt, pgType));
 
899
                        }
 
900
                        set_nullfield_int2(&row->tuple[13], pgtype_scale(stmt, pgType, PG_STATIC));
 
901
                        set_nullfield_int2(&row->tuple[14], pgtype_scale(stmt, pgType, PG_STATIC));
 
902
#if (ODBCVER >=0x0300)
 
903
                        set_nullfield_int2(&row->tuple[15], pgtype_to_sqldesctype(stmt, pgType));
 
904
                        set_nullfield_int2(&row->tuple[16], pgtype_to_datetime_sub(stmt, pgType));
 
905
                        set_nullfield_int4(&row->tuple[17], pgtype_radix(stmt, pgType));
 
906
                        set_nullfield_int4(&row->tuple[18], 0);
 
907
#endif /* ODBCVER */
 
908
 
 
909
                        QR_add_tuple(res, row);
 
910
 
 
911
                        }
 
912
                }
 
913
        }
 
914
 
 
915
        stmt->status = STMT_FINISHED;
 
916
        stmt->currTuple = -1;
 
917
        stmt->rowset_start = -1;
 
918
        stmt->current_col = -1;
 
919
 
 
920
        return SQL_SUCCESS;
 
921
}
 
922
 
 
923
 
 
924
RETCODE         SQL_API
 
925
PGAPI_GetFunctions(
 
926
                                   HDBC hdbc,
 
927
                                   UWORD fFunction,
 
928
                                   UWORD FAR * pfExists)
 
929
{
 
930
        CSTR func = "PGAPI_GetFunctions";
 
931
        ConnectionClass *conn = (ConnectionClass *) hdbc;
 
932
        ConnInfo   *ci = &(conn->connInfo);
 
933
 
 
934
        mylog("%s: entering...%u\n", func, fFunction);
 
935
 
 
936
        if (fFunction == SQL_API_ALL_FUNCTIONS)
 
937
        {
 
938
#if (ODBCVER < 0x0300)
 
939
                if (ci->drivers.lie)
 
940
                {
 
941
                        int                     i;
 
942
 
 
943
                        memset(pfExists, 0, sizeof(UWORD) * 100);
 
944
 
 
945
                        pfExists[SQL_API_SQLALLOCENV] = TRUE;
 
946
                        pfExists[SQL_API_SQLFREEENV] = TRUE;
 
947
                        for (i = SQL_API_SQLALLOCCONNECT; i <= SQL_NUM_FUNCTIONS; i++)
 
948
                                pfExists[i] = TRUE;
 
949
                        for (i = SQL_EXT_API_START; i <= SQL_EXT_API_LAST; i++)
 
950
                                pfExists[i] = TRUE;
 
951
                }
 
952
                else
 
953
#endif
 
954
                {
 
955
                        memset(pfExists, 0, sizeof(UWORD) * 100);
 
956
 
 
957
                        /* ODBC core functions */
 
958
                        pfExists[SQL_API_SQLALLOCCONNECT] = TRUE;
 
959
                        pfExists[SQL_API_SQLALLOCENV] = TRUE;
 
960
                        pfExists[SQL_API_SQLALLOCSTMT] = TRUE;
 
961
                        pfExists[SQL_API_SQLBINDCOL] = TRUE;
 
962
                        pfExists[SQL_API_SQLCANCEL] = TRUE;
 
963
                        pfExists[SQL_API_SQLCOLATTRIBUTES] = TRUE;
 
964
                        pfExists[SQL_API_SQLCONNECT] = TRUE;
 
965
                        pfExists[SQL_API_SQLDESCRIBECOL] = TRUE;        /* partial */
 
966
                        pfExists[SQL_API_SQLDISCONNECT] = TRUE;
 
967
                        pfExists[SQL_API_SQLERROR] = TRUE;
 
968
                        pfExists[SQL_API_SQLEXECDIRECT] = TRUE;
 
969
                        pfExists[SQL_API_SQLEXECUTE] = TRUE;
 
970
                        pfExists[SQL_API_SQLFETCH] = TRUE;
 
971
                        pfExists[SQL_API_SQLFREECONNECT] = TRUE;
 
972
                        pfExists[SQL_API_SQLFREEENV] = TRUE;
 
973
                        pfExists[SQL_API_SQLFREESTMT] = TRUE;
 
974
                        pfExists[SQL_API_SQLGETCURSORNAME] = TRUE;
 
975
                        pfExists[SQL_API_SQLNUMRESULTCOLS] = TRUE;
 
976
                        pfExists[SQL_API_SQLPREPARE] = TRUE;            /* complete? */
 
977
                        pfExists[SQL_API_SQLROWCOUNT] = TRUE;
 
978
                        pfExists[SQL_API_SQLSETCURSORNAME] = TRUE;
 
979
                        pfExists[SQL_API_SQLSETPARAM] = FALSE;          /* odbc 1.0 */
 
980
                        pfExists[SQL_API_SQLTRANSACT] = TRUE;
 
981
 
 
982
                        /* ODBC level 1 functions */
 
983
                        pfExists[SQL_API_SQLBINDPARAMETER] = TRUE;
 
984
                        pfExists[SQL_API_SQLCOLUMNS] = TRUE;
 
985
                        pfExists[SQL_API_SQLDRIVERCONNECT] = TRUE;
 
986
                        pfExists[SQL_API_SQLGETCONNECTOPTION] = TRUE;           /* partial */
 
987
                        pfExists[SQL_API_SQLGETDATA] = TRUE;
 
988
                        pfExists[SQL_API_SQLGETFUNCTIONS] = TRUE;
 
989
                        pfExists[SQL_API_SQLGETINFO] = TRUE;
 
990
                        pfExists[SQL_API_SQLGETSTMTOPTION] = TRUE;      /* partial */
 
991
                        pfExists[SQL_API_SQLGETTYPEINFO] = TRUE;
 
992
                        pfExists[SQL_API_SQLPARAMDATA] = TRUE;
 
993
                        pfExists[SQL_API_SQLPUTDATA] = TRUE;
 
994
                        pfExists[SQL_API_SQLSETCONNECTOPTION] = TRUE;           /* partial */
 
995
                        pfExists[SQL_API_SQLSETSTMTOPTION] = TRUE;
 
996
                        pfExists[SQL_API_SQLSPECIALCOLUMNS] = TRUE;
 
997
                        pfExists[SQL_API_SQLSTATISTICS] = TRUE;
 
998
                        pfExists[SQL_API_SQLTABLES] = TRUE;
 
999
 
 
1000
                        /* ODBC level 2 functions */
 
1001
                        pfExists[SQL_API_SQLBROWSECONNECT] = FALSE;
 
1002
                        pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
 
1003
                        pfExists[SQL_API_SQLDATASOURCES] = FALSE;       /* only implemented by
 
1004
                                                                                                                 * DM */
 
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 (ODBCVER >= 0x0300)
 
1028
                        pfExists[SQL_API_SQLBULKOPERATIONS] = TRUE;
 
1029
#endif /* ODBCVER */
 
1030
                }
 
1031
        }
 
1032
        else
 
1033
        {
 
1034
                if (ci->drivers.lie)
 
1035
                        *pfExists = TRUE;
 
1036
                else
 
1037
                {
 
1038
                        switch (fFunction)
 
1039
                        {
 
1040
#if (ODBCVER < 0x0300)
 
1041
                                case SQL_API_SQLALLOCCONNECT:
 
1042
                                        *pfExists = TRUE;
 
1043
                                        break;
 
1044
                                case SQL_API_SQLALLOCENV:
 
1045
                                        *pfExists = TRUE;
 
1046
                                        break;
 
1047
                                case SQL_API_SQLALLOCSTMT:
 
1048
                                        *pfExists = TRUE;
 
1049
                                        break;
 
1050
#endif /* ODBCVER */
 
1051
                                case SQL_API_SQLBINDCOL:
 
1052
                                        *pfExists = TRUE;
 
1053
                                        break;
 
1054
                                case SQL_API_SQLCANCEL:
 
1055
                                        *pfExists = TRUE;
 
1056
                                        break;
 
1057
#if (ODBCVER >= 0x0300)
 
1058
                                case SQL_API_SQLCOLATTRIBUTE:
 
1059
#else
 
1060
                                case SQL_API_SQLCOLATTRIBUTES:
 
1061
#endif /* ODBCVER */
 
1062
                                        *pfExists = TRUE;
 
1063
                                        break;
 
1064
                                case SQL_API_SQLCONNECT:
 
1065
                                        *pfExists = TRUE;
 
1066
                                        break;
 
1067
                                case SQL_API_SQLDESCRIBECOL:
 
1068
                                        *pfExists = TRUE;
 
1069
                                        break;          /* partial */
 
1070
                                case SQL_API_SQLDISCONNECT:
 
1071
                                        *pfExists = TRUE;
 
1072
                                        break;
 
1073
#if (ODBCVER < 0x0300)
 
1074
                                case SQL_API_SQLERROR:
 
1075
                                        *pfExists = TRUE;
 
1076
                                        break;
 
1077
#endif /* ODBCVER */
 
1078
                                case SQL_API_SQLEXECDIRECT:
 
1079
                                        *pfExists = TRUE;
 
1080
                                        break;
 
1081
                                case SQL_API_SQLEXECUTE:
 
1082
                                        *pfExists = TRUE;
 
1083
                                        break;
 
1084
                                case SQL_API_SQLFETCH:
 
1085
                                        *pfExists = TRUE;
 
1086
                                        break;
 
1087
#if (ODBCVER < 0x0300)
 
1088
                                case SQL_API_SQLFREECONNECT:
 
1089
                                        *pfExists = TRUE;
 
1090
                                        break;
 
1091
                                case SQL_API_SQLFREEENV:
 
1092
                                        *pfExists = TRUE;
 
1093
                                        break;
 
1094
#endif /* ODBCVER */
 
1095
                                case SQL_API_SQLFREESTMT:
 
1096
                                        *pfExists = TRUE;
 
1097
                                        break;
 
1098
                                case SQL_API_SQLGETCURSORNAME:
 
1099
                                        *pfExists = TRUE;
 
1100
                                        break;
 
1101
                                case SQL_API_SQLNUMRESULTCOLS:
 
1102
                                        *pfExists = TRUE;
 
1103
                                        break;
 
1104
                                case SQL_API_SQLPREPARE:
 
1105
                                        *pfExists = TRUE;
 
1106
                                        break;
 
1107
                                case SQL_API_SQLROWCOUNT:
 
1108
                                        *pfExists = TRUE;
 
1109
                                        break;
 
1110
                                case SQL_API_SQLSETCURSORNAME:
 
1111
                                        *pfExists = TRUE;
 
1112
                                        break;
 
1113
                                case SQL_API_SQLSETPARAM:
 
1114
                                        *pfExists = FALSE;
 
1115
                                        break;          /* odbc 1.0 */
 
1116
                                case SQL_API_SQLTRANSACT:
 
1117
                                        *pfExists = TRUE;
 
1118
                                        break;
 
1119
 
 
1120
                                        /* ODBC level 1 functions */
 
1121
                                case SQL_API_SQLBINDPARAMETER:
 
1122
                                        *pfExists = TRUE;
 
1123
                                        break;
 
1124
                                case SQL_API_SQLCOLUMNS:
 
1125
                                        *pfExists = TRUE;
 
1126
                                        break;
 
1127
                                case SQL_API_SQLDRIVERCONNECT:
 
1128
                                        *pfExists = TRUE;
 
1129
                                        break;
 
1130
#if (ODBCVER < 0x0300)
 
1131
                                case SQL_API_SQLGETCONNECTOPTION:
 
1132
                                        *pfExists = TRUE;
 
1133
                                        break;          /* partial */
 
1134
#endif /* ODBCVER */
 
1135
                                case SQL_API_SQLGETDATA:
 
1136
                                        *pfExists = TRUE;
 
1137
                                        break;
 
1138
                                case SQL_API_SQLGETFUNCTIONS:
 
1139
                                        *pfExists = TRUE;
 
1140
                                        break;
 
1141
                                case SQL_API_SQLGETINFO:
 
1142
                                        *pfExists = TRUE;
 
1143
                                        break;
 
1144
#if (ODBCVER < 0x0300)
 
1145
                                case SQL_API_SQLGETSTMTOPTION:
 
1146
                                        *pfExists = TRUE;
 
1147
                                        break;          /* partial */
 
1148
#endif /* ODBCVER */
 
1149
                                case SQL_API_SQLGETTYPEINFO:
 
1150
                                        *pfExists = TRUE;
 
1151
                                        break;
 
1152
                                case SQL_API_SQLPARAMDATA:
 
1153
                                        *pfExists = TRUE;
 
1154
                                        break;
 
1155
                                case SQL_API_SQLPUTDATA:
 
1156
                                        *pfExists = TRUE;
 
1157
                                        break;
 
1158
#if (ODBCVER < 0x0300)
 
1159
                                case SQL_API_SQLSETCONNECTOPTION:
 
1160
                                        *pfExists = TRUE;
 
1161
                                        break;          /* partial */
 
1162
                                case SQL_API_SQLSETSTMTOPTION:
 
1163
                                        *pfExists = TRUE;
 
1164
                                        break;
 
1165
#endif /* ODBCVER */
 
1166
                                case SQL_API_SQLSPECIALCOLUMNS:
 
1167
                                        *pfExists = TRUE;
 
1168
                                        break;
 
1169
                                case SQL_API_SQLSTATISTICS:
 
1170
                                        *pfExists = TRUE;
 
1171
                                        break;
 
1172
                                case SQL_API_SQLTABLES:
 
1173
                                        *pfExists = TRUE;
 
1174
                                        break;
 
1175
 
 
1176
                                        /* ODBC level 2 functions */
 
1177
                                case SQL_API_SQLBROWSECONNECT:
 
1178
                                        *pfExists = FALSE;
 
1179
                                        break;
 
1180
                                case SQL_API_SQLCOLUMNPRIVILEGES:
 
1181
                                        *pfExists = FALSE;
 
1182
                                        break;
 
1183
                                case SQL_API_SQLDATASOURCES:
 
1184
                                        *pfExists = FALSE;
 
1185
                                        break;          /* only implemented by DM */
 
1186
                                case SQL_API_SQLDESCRIBEPARAM:
 
1187
                                        *pfExists = FALSE;
 
1188
                                        break;          /* not properly implemented */
 
1189
                                case SQL_API_SQLDRIVERS:
 
1190
                                        *pfExists = FALSE;
 
1191
                                        break;          /* only implemented by DM */
 
1192
                                case SQL_API_SQLEXTENDEDFETCH:
 
1193
                                        *pfExists = TRUE;
 
1194
                                        break;
 
1195
                                case SQL_API_SQLFOREIGNKEYS:
 
1196
                                        *pfExists = TRUE;
 
1197
                                        break;
 
1198
                                case SQL_API_SQLMORERESULTS:
 
1199
                                        *pfExists = TRUE;
 
1200
                                        break;
 
1201
                                case SQL_API_SQLNATIVESQL:
 
1202
                                        *pfExists = TRUE;
 
1203
                                        break;
 
1204
                                case SQL_API_SQLNUMPARAMS:
 
1205
                                        *pfExists = TRUE;
 
1206
                                        break;
 
1207
                                case SQL_API_SQLPARAMOPTIONS:
 
1208
                                        *pfExists = TRUE;
 
1209
                                        break;
 
1210
                                case SQL_API_SQLPRIMARYKEYS:
 
1211
                                        *pfExists = TRUE;
 
1212
                                        break;
 
1213
                                case SQL_API_SQLPROCEDURECOLUMNS:
 
1214
                                        if (PG_VERSION_LT(conn, 6.5))
 
1215
                                                *pfExists = FALSE;
 
1216
                                        else
 
1217
                                                *pfExists = TRUE;
 
1218
                                        break;
 
1219
                                case SQL_API_SQLPROCEDURES:
 
1220
                                        if (PG_VERSION_LT(conn, 6.5))
 
1221
                                                *pfExists = FALSE;
 
1222
                                        else
 
1223
                                                *pfExists = TRUE;
 
1224
                                        break;
 
1225
                                case SQL_API_SQLSETPOS:
 
1226
                                        *pfExists = TRUE;
 
1227
                                        break;
 
1228
                                case SQL_API_SQLSETSCROLLOPTIONS:
 
1229
                                        *pfExists = TRUE;
 
1230
                                        break;          /* odbc 1.0 */
 
1231
                                case SQL_API_SQLTABLEPRIVILEGES:
 
1232
                                        *pfExists = TRUE;
 
1233
                                        break;
 
1234
#if (ODBCVER >= 0x0300)
 
1235
                                case SQL_API_SQLBULKOPERATIONS: /* 24 */
 
1236
                                case SQL_API_SQLALLOCHANDLE:    /* 1001 */
 
1237
                                case SQL_API_SQLBINDPARAM:      /* 1002 */
 
1238
                                case SQL_API_SQLCLOSECURSOR:    /* 1003 */
 
1239
                                case SQL_API_SQLENDTRAN:        /* 1005 */
 
1240
                                case SQL_API_SQLFETCHSCROLL:    /* 1021 */
 
1241
                                case SQL_API_SQLFREEHANDLE:     /* 1006 */
 
1242
                                case SQL_API_SQLGETCONNECTATTR: /* 1007 */
 
1243
                                case SQL_API_SQLGETDESCFIELD:   /* 1008 */
 
1244
                                case SQL_API_SQLGETDIAGFIELD:   /* 1010 */
 
1245
                                case SQL_API_SQLGETDIAGREC:     /* 1011 */
 
1246
                                case SQL_API_SQLGETENVATTR:     /* 1012 */
 
1247
                                case SQL_API_SQLGETSTMTATTR:    /* 1014 */
 
1248
                                case SQL_API_SQLSETCONNECTATTR: /* 1016 */
 
1249
                                case SQL_API_SQLSETDESCFIELD:   /* 1017 */
 
1250
                                case SQL_API_SQLSETENVATTR:     /* 1019 */
 
1251
                                case SQL_API_SQLSETSTMTATTR:    /* 1020 */
 
1252
                                        *pfExists = TRUE;
 
1253
                                        break;
 
1254
                                case SQL_API_SQLGETDESCREC:     /* 1009 */
 
1255
                                case SQL_API_SQLSETDESCREC:     /* 1018 */
 
1256
                                case SQL_API_SQLCOPYDESC:       /* 1004 */
 
1257
                                        *pfExists = FALSE;
 
1258
                                        break;
 
1259
#endif /* ODBCVER */
 
1260
                                default:
 
1261
                                        *pfExists = FALSE;
 
1262
                                        break;
 
1263
                        }
 
1264
                }
 
1265
        }
 
1266
        return SQL_SUCCESS;
 
1267
}
 
1268
 
 
1269
 
 
1270
#define CSTR_SYS_TABLE  "SYSTEM TABLE"
 
1271
#define CSTR_TABLE      "TABLE"
 
1272
#define CSTR_VIEW       "VIEW"
 
1273
 
 
1274
RETCODE         SQL_API
 
1275
PGAPI_Tables(
 
1276
                         HSTMT hstmt,
 
1277
                         UCHAR FAR * szTableQualifier,
 
1278
                         SWORD cbTableQualifier,
 
1279
                         UCHAR FAR * szTableOwner,
 
1280
                         SWORD cbTableOwner,
 
1281
                         UCHAR FAR * szTableName,
 
1282
                         SWORD cbTableName,
 
1283
                         UCHAR FAR * szTableType,
 
1284
                         SWORD cbTableType)
 
1285
{
 
1286
        CSTR func = "PGAPI_Tables";
 
1287
        StatementClass *stmt = (StatementClass *) hstmt;
 
1288
        StatementClass *tbl_stmt;
 
1289
        QResultClass    *res;
 
1290
        TupleNode  *row;
 
1291
        HSTMT           htbl_stmt;
 
1292
        RETCODE         result;
 
1293
        char       *tableType;
 
1294
        char            tables_query[INFO_INQUIRY_LEN];
 
1295
        char            table_name[MAX_INFO_STRING],
 
1296
                                table_owner[MAX_INFO_STRING],
 
1297
                                relkind_or_hasrules[MAX_INFO_STRING];
 
1298
#ifdef  HAVE_STRTOK_R
 
1299
        char            *last;
 
1300
#endif /* HAVE_STRTOK_R */
 
1301
        ConnectionClass *conn;
 
1302
        ConnInfo   *ci;
 
1303
        char       *prefix[32],
 
1304
                                prefixes[MEDIUM_REGISTRY_LEN];
 
1305
        char       *table_type[32],
 
1306
                                table_types[MAX_INFO_STRING];
 
1307
        char            show_system_tables,
 
1308
                                show_regular_tables,
 
1309
                                show_views;
 
1310
        char            regular_table,
 
1311
                                view,
 
1312
                                systable;
 
1313
        int                     i;
 
1314
        SWORD                   internal_asis_type = SQL_C_CHAR;
 
1315
        const char *likeeq = "like";
 
1316
 
 
1317
        mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
 
1318
 
 
1319
        if (!stmt)
 
1320
        {
 
1321
                SC_log_error(func, "", NULL);
 
1322
                return SQL_INVALID_HANDLE;
 
1323
        }
 
1324
 
 
1325
        stmt->manual_result = TRUE;
 
1326
        stmt->errormsg_created = TRUE;
 
1327
 
 
1328
        conn = SC_get_conn(stmt);
 
1329
        ci = &(conn->connInfo);
 
1330
 
 
1331
        result = PGAPI_AllocStmt(stmt->hdbc, &htbl_stmt);
 
1332
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1333
        {
 
1334
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_Tables result.");
 
1335
                SC_log_error(func, "", stmt);
 
1336
                return SQL_ERROR;
 
1337
        }
 
1338
        tbl_stmt = (StatementClass *) htbl_stmt;
 
1339
 
 
1340
        /*
 
1341
         * Create the query to find out the tables
 
1342
         */
 
1343
        if (conn->schema_support)
 
1344
        {
 
1345
                /* view is represented by its relkind since 7.1 */
 
1346
                strcpy(tables_query, "select relname, nspname, relkind"
 
1347
                " from pg_catalog.pg_class, pg_catalog.pg_namespace");
 
1348
                strcat(tables_query, " where relkind in ('r', 'v')");
 
1349
        }
 
1350
        else if (PG_VERSION_GE(conn, 7.1))
 
1351
        {
 
1352
                /* view is represented by its relkind since 7.1 */
 
1353
                strcpy(tables_query, "select relname, usename, relkind"
 
1354
                " from pg_class, pg_user");
 
1355
                strcat(tables_query, " where relkind in ('r', 'v')");
 
1356
        }
 
1357
        else
 
1358
        {
 
1359
                strcpy(tables_query, "select relname, usename, relhasrules from pg_class, pg_user");
 
1360
                strcat(tables_query, " where relkind = 'r'");
 
1361
        }
 
1362
 
 
1363
        if (conn->schema_support)
 
1364
                schema_strcat1(tables_query, " and nspname %s '%.*s'", likeeq, szTableOwner, cbTableOwner, szTableName, cbTableName, conn);
 
1365
        else
 
1366
                my_strcat1(tables_query, " and usename %s '%.*s'", likeeq, szTableOwner, cbTableOwner);
 
1367
        my_strcat1(tables_query, " and relname %s '%.*s'", likeeq, szTableName, cbTableName);
 
1368
 
 
1369
        /* Parse the extra systable prefix      */
 
1370
        strcpy(prefixes, ci->drivers.extra_systable_prefixes);
 
1371
        i = 0;
 
1372
#ifdef  HAVE_STRTOK_R
 
1373
        prefix[i] = strtok_r(prefixes, ";", &last);
 
1374
#else
 
1375
        prefix[i] = strtok(prefixes, ";");
 
1376
#endif /* HAVE_STRTOK_R */
 
1377
        while (prefix[i] && i < sizeof(prefix))
 
1378
#ifdef  HAVE_STRTOK_R
 
1379
                prefix[++i] = strtok_r(NULL, ";", &last);
 
1380
#else
 
1381
                prefix[++i] = strtok(NULL, ";");
 
1382
#endif /* HAVE_STRTOK_R */
 
1383
 
 
1384
        /* Parse the desired table types to return */
 
1385
        show_system_tables = FALSE;
 
1386
        show_regular_tables = FALSE;
 
1387
        show_views = FALSE;
 
1388
 
 
1389
        /* make_string mallocs memory */
 
1390
        tableType = make_string(szTableType, cbTableType, NULL);
 
1391
        if (tableType)
 
1392
        {
 
1393
                strcpy(table_types, tableType);
 
1394
                free(tableType);
 
1395
                i = 0;
 
1396
#ifdef  HAVE_STRTOK_R
 
1397
                table_type[i] = strtok_r(table_types, ",", &last);
 
1398
#else
 
1399
                table_type[i] = strtok(table_types, ",");
 
1400
#endif /* HAVE_STRTOK_R */
 
1401
                while (table_type[i] && i < 32)
 
1402
#ifdef  HAVE_STRTOK_R
 
1403
                        table_type[++i] = strtok_r(NULL, ",", &last);
 
1404
#else
 
1405
                        table_type[++i] = strtok(NULL, ",");
 
1406
#endif /* HAVE_STRTOK_R */
 
1407
 
 
1408
                /* Check for desired table types to return */
 
1409
                i = 0;
 
1410
                while (table_type[i])
 
1411
                {
 
1412
                        char *typestr = table_type[i];
 
1413
 
 
1414
                        while (isspace(*typestr))
 
1415
                                typestr++;
 
1416
                        if (*typestr == '\'')
 
1417
                                typestr++;
 
1418
                        if (strnicmp(typestr, CSTR_SYS_TABLE, strlen(CSTR_SYS_TABLE)) == 0)
 
1419
                                show_system_tables = TRUE;
 
1420
                        else if (strnicmp(typestr, CSTR_TABLE, strlen(CSTR_TABLE)) == 0)
 
1421
                                show_regular_tables = TRUE;
 
1422
                        else if (strnicmp(typestr, CSTR_VIEW, strlen(CSTR_VIEW)) == 0)
 
1423
                                show_views = TRUE;
 
1424
                        i++;
 
1425
                }
 
1426
        }
 
1427
        else
 
1428
        {
 
1429
                show_regular_tables = TRUE;
 
1430
                show_views = TRUE;
 
1431
        }
 
1432
 
 
1433
        /*
 
1434
         * If not interested in SYSTEM TABLES then filter them out to save
 
1435
         * some time on the query.      If treating system tables as regular
 
1436
         * tables, then dont filter either.
 
1437
         */
 
1438
        if (!atoi(ci->show_system_tables) && !show_system_tables)
 
1439
        {
 
1440
                strcat(tables_query, " and relname !~ '^" POSTGRES_SYS_PREFIX);
 
1441
 
 
1442
                /* Also filter out user-defined system table types */
 
1443
                i = 0;
 
1444
                while (prefix[i])
 
1445
                {
 
1446
                        strcat(tables_query, "|^");
 
1447
                        strcat(tables_query, prefix[i]);
 
1448
                        i++;
 
1449
                }
 
1450
                strcat(tables_query, "'");
 
1451
        }
 
1452
 
 
1453
        /* match users */
 
1454
        if (PG_VERSION_LT(conn, 7.1))
 
1455
                /* filter out large objects in older versions */
 
1456
                strcat(tables_query, " and relname !~ '^xinv[0-9]+'");
 
1457
 
 
1458
        if (conn->schema_support)
 
1459
                strcat(tables_query, " and pg_namespace.oid = relnamespace order by nspname, relname");
 
1460
        else
 
1461
                strcat(tables_query, " and usesysid = relowner order by relname");
 
1462
 
 
1463
        result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query));
 
1464
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1465
        {
 
1466
                SC_full_error_copy(stmt, htbl_stmt);
 
1467
                SC_log_error(func, "", stmt);
 
1468
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
1469
                return SQL_ERROR;
 
1470
        }
 
1471
 
 
1472
#ifdef  UNICODE_SUPPORT
 
1473
        if (conn->unicode)
 
1474
                internal_asis_type = INTERNAL_ASIS_TYPE;
 
1475
#endif /* UNICODE_SUPPORT */
 
1476
        result = PGAPI_BindCol(htbl_stmt, 1, internal_asis_type,
 
1477
                                                   table_name, MAX_INFO_STRING, NULL);
 
1478
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1479
        {
 
1480
                SC_error_copy(stmt, tbl_stmt);
 
1481
                SC_log_error(func, "", stmt);
 
1482
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
1483
                return SQL_ERROR;
 
1484
        }
 
1485
 
 
1486
        result = PGAPI_BindCol(htbl_stmt, 2, internal_asis_type,
 
1487
                                                   table_owner, MAX_INFO_STRING, NULL);
 
1488
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1489
        {
 
1490
                SC_error_copy(stmt, tbl_stmt);
 
1491
                SC_log_error(func, "", stmt);
 
1492
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
1493
                return SQL_ERROR;
 
1494
        }
 
1495
        result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
 
1496
                                                   relkind_or_hasrules, MAX_INFO_STRING, NULL);
 
1497
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1498
        {
 
1499
                SC_error_copy(stmt, tbl_stmt);
 
1500
                SC_log_error(func, "", stmt);
 
1501
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
1502
                return SQL_ERROR;
 
1503
        }
 
1504
 
 
1505
        if (res = QR_Constructor(), !res)
 
1506
        {
 
1507
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Tables result.");
 
1508
                SC_log_error(func, "", stmt);
 
1509
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
1510
                return SQL_ERROR;
 
1511
        }
 
1512
        SC_set_Result(stmt, res);
 
1513
 
 
1514
        /* the binding structure for a statement is not set up until */
 
1515
 
 
1516
        /*
 
1517
         * a statement is actually executed, so we'll have to do this
 
1518
         * ourselves.
 
1519
         */
 
1520
        extend_column_bindings(SC_get_ARD(stmt), 5);
 
1521
 
 
1522
        /* set the field names */
 
1523
        QR_set_num_fields(res, 5);
 
1524
        QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
1525
        QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
1526
        QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
1527
        QR_set_field_info(res, 3, "TABLE_TYPE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
1528
        QR_set_field_info(res, 4, "REMARKS", PG_TYPE_VARCHAR, 254);
 
1529
 
 
1530
        /* add the tuples */
 
1531
        result = PGAPI_Fetch(htbl_stmt);
 
1532
        while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO))
 
1533
        {
 
1534
                /*
 
1535
                 * Determine if this table name is a system table. If treating
 
1536
                 * system tables as regular tables, then no need to do this test.
 
1537
                 */
 
1538
                systable = FALSE;
 
1539
                if (!atoi(ci->show_system_tables))
 
1540
                {
 
1541
                        if (strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0)
 
1542
                                systable = TRUE;
 
1543
 
 
1544
                        else
 
1545
                        {
 
1546
                                /* Check extra system table prefixes */
 
1547
                                i = 0;
 
1548
                                while (prefix[i])
 
1549
                                {
 
1550
                                        mylog("table_name='%s', prefix[%d]='%s'\n", table_name, i, prefix[i]);
 
1551
                                        if (strncmp(table_name, prefix[i], strlen(prefix[i])) == 0)
 
1552
                                        {
 
1553
                                                systable = TRUE;
 
1554
                                                break;
 
1555
                                        }
 
1556
                                        i++;
 
1557
                                }
 
1558
                        }
 
1559
                }
 
1560
 
 
1561
                /* Determine if the table name is a view */
 
1562
                if (PG_VERSION_GE(conn, 7.1))
 
1563
                        /* view is represented by its relkind since 7.1 */
 
1564
                        view = (relkind_or_hasrules[0] == 'v');
 
1565
                else
 
1566
                        view = (relkind_or_hasrules[0] == '1');
 
1567
 
 
1568
                /* It must be a regular table */
 
1569
                regular_table = (!systable && !view);
 
1570
 
 
1571
 
 
1572
                /* Include the row in the result set if meets all criteria */
 
1573
 
 
1574
                /*
 
1575
                 * NOTE: Unsupported table types (i.e., LOCAL TEMPORARY, ALIAS,
 
1576
                 * etc) will return nothing
 
1577
                 */
 
1578
                if ((systable && show_system_tables) ||
 
1579
                        (view && show_views) ||
 
1580
                        (regular_table && show_regular_tables))
 
1581
                {
 
1582
                        row = (TupleNode *) malloc(sizeof(TupleNode) + (5 - 1) *sizeof(TupleField));
 
1583
 
 
1584
                        /*set_tuplefield_string(&row->tuple[0], "");*/
 
1585
                        set_tuplefield_null(&row->tuple[0]);
 
1586
 
 
1587
                        /*
 
1588
                         * I have to hide the table owner from Access, otherwise it
 
1589
                         * insists on referring to the table as 'owner.table'. (this
 
1590
                         * is valid according to the ODBC SQL grammar, but Postgres
 
1591
                         * won't support it.)
 
1592
                         *
 
1593
                         * set_tuplefield_string(&row->tuple[1], table_owner);
 
1594
                         */
 
1595
 
 
1596
                        mylog("%s: table_name = '%s'\n", func, table_name);
 
1597
 
 
1598
                        if (conn->schema_support)
 
1599
                                set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
 
1600
                        else
 
1601
                                set_tuplefield_null(&row->tuple[1]);
 
1602
                        set_tuplefield_string(&row->tuple[2], table_name);
 
1603
                        set_tuplefield_string(&row->tuple[3], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE"));
 
1604
                        set_tuplefield_string(&row->tuple[4], "");
 
1605
                        /*** set_tuplefield_string(&row->tuple[4], "TABLE"); ***/
 
1606
 
 
1607
                        QR_add_tuple(res, row);
 
1608
                }
 
1609
                result = PGAPI_Fetch(htbl_stmt);
 
1610
        }
 
1611
        if (result != SQL_NO_DATA_FOUND)
 
1612
        {
 
1613
                SC_full_error_copy(stmt, htbl_stmt);
 
1614
                SC_log_error(func, "", stmt);
 
1615
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
1616
                return SQL_ERROR;
 
1617
        }
 
1618
 
 
1619
        /*
 
1620
         * also, things need to think that this statement is finished so the
 
1621
         * results can be retrieved.
 
1622
         */
 
1623
        stmt->status = STMT_FINISHED;
 
1624
 
 
1625
        /* set up the current tuple pointer for SQLFetch */
 
1626
        stmt->currTuple = -1;
 
1627
        stmt->rowset_start = -1;
 
1628
        stmt->current_col = -1;
 
1629
 
 
1630
        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
1631
        mylog("%s: EXIT,  stmt=%u\n", func, stmt);
 
1632
        return SQL_SUCCESS;
 
1633
}
 
1634
 
 
1635
 
 
1636
/*
 
1637
 *      PostgreSQL needs 2 '\\' to escape '_' and '%'. 
 
1638
 */
 
1639
static int
 
1640
reallyEscapeCatalogEscapes(const char *src, int srclen, char *dest, int dst_len, int ccsc)
 
1641
{
 
1642
        int     i, outlen;
 
1643
        const char *in;
 
1644
        BOOL    escape_in = FALSE;
 
1645
        encoded_str     encstr;
 
1646
 
 
1647
        if (srclen == SQL_NULL_DATA)
 
1648
        {
 
1649
                dest[0] = '\0';
 
1650
                return STRCPY_NULL;
 
1651
        }
 
1652
        else if (srclen == SQL_NTS)
 
1653
                srclen = strlen(src);
 
1654
        if (srclen <= 0)
 
1655
                return STRCPY_FAIL;
 
1656
        encoded_str_constr(&encstr, ccsc, src);
 
1657
        for (i = 0, in = src, outlen = 0; i < srclen && outlen < dst_len; i++, in++)
 
1658
        {
 
1659
                encoded_nextchar(&encstr);
 
1660
                if (ENCODE_STATUS(encstr) != 0)
 
1661
                {
 
1662
                        dest[outlen++] = *in;
 
1663
                        continue;
 
1664
                }
 
1665
                if (escape_in)
 
1666
                {
 
1667
                        switch (*in)
 
1668
                        {
 
1669
                                case '%':
 
1670
                                case '_':
 
1671
                                        dest[outlen++] = '\\'; /* needs 1 more */
 
1672
                                        break;
 
1673
                                default:
 
1674
                                        dest[outlen++] = '\\';
 
1675
                                        if (outlen < dst_len)
 
1676
                                                dest[outlen++] = '\\';
 
1677
                                        if (outlen < dst_len)
 
1678
                                                dest[outlen++] = '\\';
 
1679
                                        break;
 
1680
                        }
 
1681
                }
 
1682
                if (*in == '\\')
 
1683
                        escape_in = TRUE;
 
1684
                else
 
1685
                        escape_in = FALSE;
 
1686
                if (outlen < dst_len)
 
1687
                        dest[outlen++] = *in;
 
1688
        }
 
1689
        if (outlen < dst_len)
 
1690
                dest[outlen] = '\0';
 
1691
        return outlen;
 
1692
}
 
1693
 
 
1694
RETCODE         SQL_API
 
1695
PGAPI_Columns(
 
1696
                          HSTMT hstmt,
 
1697
                          UCHAR FAR * szTableQualifier,
 
1698
                          SWORD cbTableQualifier,
 
1699
                          UCHAR FAR * szTableOwner,
 
1700
                          SWORD cbTableOwner,
 
1701
                          UCHAR FAR * szTableName,
 
1702
                          SWORD cbTableName,
 
1703
                          UCHAR FAR * szColumnName,
 
1704
                          SWORD cbColumnName,
 
1705
                          UWORD flag)
 
1706
{
 
1707
        CSTR func = "PGAPI_Columns";
 
1708
        StatementClass *stmt = (StatementClass *) hstmt;
 
1709
        QResultClass    *res;
 
1710
        TupleNode  *row;
 
1711
        HSTMT           hcol_stmt;
 
1712
        StatementClass *col_stmt;
 
1713
        char            columns_query[INFO_INQUIRY_LEN];
 
1714
        RETCODE         result;
 
1715
        char            table_owner[MAX_INFO_STRING],
 
1716
                                table_name[MAX_INFO_STRING],
 
1717
                                field_name[MAX_INFO_STRING],
 
1718
                                field_type_name[MAX_INFO_STRING];
 
1719
        Int2            field_number, sqltype,
 
1720
                                reserved_cols,
 
1721
                                result_cols,
 
1722
                                decimal_digits;
 
1723
        Int4            field_type,
 
1724
                                the_type,
 
1725
                                field_length,
 
1726
                                mod_length,
 
1727
                                column_size,
 
1728
                                ordinal;
 
1729
        char            useStaticPrecision;
 
1730
        char            not_null[MAX_INFO_STRING],
 
1731
                                relhasrules[MAX_INFO_STRING], relkind[8];
 
1732
        BOOL            relisaview;
 
1733
        ConnInfo   *ci;
 
1734
        ConnectionClass *conn;
 
1735
        SWORD           internal_asis_type = SQL_C_CHAR;
 
1736
        const char *likeeq = "like";
 
1737
        const char *mzTableOwner = szTableOwner, *mzTableName = szTableName,
 
1738
                *mzColumnName = szColumnName;
 
1739
 
 
1740
        mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
 
1741
 
 
1742
        if (!stmt)
 
1743
        {
 
1744
                SC_log_error(func, "", NULL);
 
1745
                return SQL_INVALID_HANDLE;
 
1746
        }
 
1747
 
 
1748
        stmt->manual_result = TRUE;
 
1749
        stmt->errormsg_created = TRUE;
 
1750
 
 
1751
        conn = SC_get_conn(stmt);
 
1752
        ci = &(conn->connInfo);
 
1753
#ifdef  UNICODE_SUPPORT
 
1754
        if (conn->unicode)
 
1755
                internal_asis_type = INTERNAL_ASIS_TYPE;
 
1756
#endif /* UNICODE_SUPPORT */
 
1757
 
 
1758
        /*
 
1759
         * Create the query to find out the columns (Note: pre 6.3 did not
 
1760
         * have the atttypmod field)
 
1761
         */
 
1762
        if (conn->schema_support)
 
1763
                sprintf(columns_query, "select u.nspname, c.relname, a.attname, a.atttypid"
 
1764
           ", t.typname, a.attnum, a.attlen, %s, a.attnotnull, c.relhasrules, c.relkind"
 
1765
                        " from pg_catalog.pg_namespace u, pg_catalog.pg_class c,"
 
1766
                        " pg_catalog.pg_attribute a, pg_catalog.pg_type t"
 
1767
                        " where u.oid = c.relnamespace"
 
1768
                        " and (not a.attisdropped)"
 
1769
                        " and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)",
 
1770
                        "a.atttypmod");
 
1771
        else
 
1772
                sprintf(columns_query, "select u.usename, c.relname, a.attname, a.atttypid"
 
1773
           ", t.typname, a.attnum, a.attlen, %s, a.attnotnull, c.relhasrules, c.relkind"
 
1774
                        " from pg_user u, pg_class c, pg_attribute a, pg_type t"
 
1775
                        " where u.usesysid = c.relowner"
 
1776
          " and c.oid= a.attrelid and a.atttypid = t.oid and (a.attnum > 0)",
 
1777
                        PG_VERSION_LE(conn, 6.2) ? "a.attlen" : "a.atttypmod");
 
1778
 
 
1779
        if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0) 
 
1780
        {
 
1781
                likeeq = "=";
 
1782
        }
 
1783
        else
 
1784
        {
 
1785
        }
 
1786
        if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0) 
 
1787
        {
 
1788
                my_strcat1(columns_query, " and c.relname %s '%.*s'", likeeq, mzTableName, cbTableName);
 
1789
                if (conn->schema_support)
 
1790
                        schema_strcat1(columns_query, " and u.nspname %s '%.*s'", likeeq, mzTableOwner, cbTableOwner, mzTableName, cbTableName, conn);
 
1791
                else
 
1792
                        my_strcat1(columns_query, " and u.usename %s '%.*s'", likeeq, mzTableOwner, cbTableOwner);
 
1793
                my_strcat1(columns_query, " and a.attname %s '%.*s'", likeeq, mzColumnName, cbColumnName);
 
1794
        }
 
1795
        else
 
1796
        {
 
1797
                char    esc_table_name[TABLE_NAME_STORAGE_LEN * 2];
 
1798
                int     escTbnamelen;
 
1799
 
 
1800
                escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc);
 
1801
                mzTableName = esc_table_name;
 
1802
                my_strcat1(columns_query, " and c.relname %s '%.*s'", likeeq, mzTableName, escTbnamelen);
 
1803
                if (conn->schema_support)
 
1804
                        schema_strcat1(columns_query, " and u.nspname %s '%.*s'", likeeq, szTableOwner, cbTableOwner, mzTableName, cbTableName, conn);
 
1805
                else
 
1806
                        my_strcat1(columns_query, " and u.usename %s '%.*s'", likeeq, mzTableOwner, cbTableOwner);
 
1807
                my_strcat1(columns_query, " and a.attname %s '%.*s'", likeeq, mzColumnName, cbColumnName);
 
1808
        }
 
1809
 
 
1810
        /*
 
1811
         * give the output in the order the columns were defined when the
 
1812
         * table was created
 
1813
         */
 
1814
        if (conn->schema_support)
 
1815
                strcat(columns_query, " order by u.nspname, c.relname, attnum");
 
1816
        else
 
1817
                strcat(columns_query, " order by c.relname, attnum");
 
1818
 
 
1819
        result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
 
1820
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1821
        {
 
1822
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_Columns result.");
 
1823
                SC_log_error(func, "", stmt);
 
1824
                return SQL_ERROR;
 
1825
        }
 
1826
        col_stmt = (StatementClass *) hcol_stmt;
 
1827
 
 
1828
        mylog("%s: hcol_stmt = %u, col_stmt = %u\n", func, hcol_stmt, col_stmt);
 
1829
 
 
1830
        result = PGAPI_ExecDirect(hcol_stmt, columns_query,
 
1831
                                                          strlen(columns_query));
 
1832
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1833
        {
 
1834
                SC_full_error_copy(stmt, col_stmt);
 
1835
                SC_log_error(func, "", stmt);
 
1836
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
1837
                return SQL_ERROR;
 
1838
        }
 
1839
 
 
1840
        result = PGAPI_BindCol(hcol_stmt, 1, internal_asis_type,
 
1841
                                                   table_owner, MAX_INFO_STRING, NULL);
 
1842
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1843
        {
 
1844
                SC_error_copy(stmt, col_stmt);
 
1845
                SC_log_error(func, "", stmt);
 
1846
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
1847
                return SQL_ERROR;
 
1848
        }
 
1849
 
 
1850
        result = PGAPI_BindCol(hcol_stmt, 2, internal_asis_type,
 
1851
                                                   table_name, MAX_INFO_STRING, NULL);
 
1852
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1853
        {
 
1854
                SC_error_copy(stmt, col_stmt);
 
1855
                SC_log_error(func, "", stmt);
 
1856
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
1857
                return SQL_ERROR;
 
1858
        }
 
1859
 
 
1860
        result = PGAPI_BindCol(hcol_stmt, 3, internal_asis_type,
 
1861
                                                   field_name, MAX_INFO_STRING, NULL);
 
1862
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1863
        {
 
1864
                SC_error_copy(stmt, col_stmt);
 
1865
                SC_log_error(func, "", stmt);
 
1866
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
1867
                return SQL_ERROR;
 
1868
        }
 
1869
 
 
1870
        result = PGAPI_BindCol(hcol_stmt, 4, SQL_C_LONG,
 
1871
                                                   &field_type, 4, NULL);
 
1872
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1873
        {
 
1874
                SC_error_copy(stmt, col_stmt);
 
1875
                SC_log_error(func, "", stmt);
 
1876
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
1877
                return SQL_ERROR;
 
1878
        }
 
1879
 
 
1880
        result = PGAPI_BindCol(hcol_stmt, 5, internal_asis_type,
 
1881
                                                   field_type_name, MAX_INFO_STRING, NULL);
 
1882
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1883
        {
 
1884
                SC_error_copy(stmt, col_stmt);
 
1885
                SC_log_error(func, "", stmt);
 
1886
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
1887
                return SQL_ERROR;
 
1888
        }
 
1889
 
 
1890
        result = PGAPI_BindCol(hcol_stmt, 6, SQL_C_SHORT,
 
1891
                                                   &field_number, MAX_INFO_STRING, NULL);
 
1892
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1893
        {
 
1894
                SC_error_copy(stmt, col_stmt);
 
1895
                SC_log_error(func, "", stmt);
 
1896
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
1897
                return SQL_ERROR;
 
1898
        }
 
1899
 
 
1900
        result = PGAPI_BindCol(hcol_stmt, 7, SQL_C_LONG,
 
1901
                                                   &field_length, MAX_INFO_STRING, NULL);
 
1902
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1903
        {
 
1904
                SC_error_copy(stmt, col_stmt);
 
1905
                SC_log_error(func, "", stmt);
 
1906
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
1907
                return SQL_ERROR;
 
1908
        }
 
1909
 
 
1910
        result = PGAPI_BindCol(hcol_stmt, 8, SQL_C_LONG,
 
1911
                                                   &mod_length, MAX_INFO_STRING, NULL);
 
1912
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1913
        {
 
1914
                SC_error_copy(stmt, col_stmt);
 
1915
                SC_log_error(func, "", stmt);
 
1916
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
1917
                return SQL_ERROR;
 
1918
        }
 
1919
 
 
1920
        result = PGAPI_BindCol(hcol_stmt, 9, internal_asis_type,
 
1921
                                                   not_null, MAX_INFO_STRING, NULL);
 
1922
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1923
        {
 
1924
                SC_error_copy(stmt, col_stmt);
 
1925
                SC_log_error(func, "", stmt);
 
1926
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
1927
                return SQL_ERROR;
 
1928
        }
 
1929
 
 
1930
        result = PGAPI_BindCol(hcol_stmt, 10, internal_asis_type,
 
1931
                                                   relhasrules, MAX_INFO_STRING, NULL);
 
1932
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1933
        {
 
1934
                SC_error_copy(stmt, col_stmt);
 
1935
                SC_log_error(func, "", stmt);
 
1936
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
1937
                return SQL_ERROR;
 
1938
        }
 
1939
 
 
1940
        result = PGAPI_BindCol(hcol_stmt, 11, internal_asis_type,
 
1941
                                                   relkind, sizeof(relkind), NULL);
 
1942
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
1943
        {
 
1944
                SC_error_copy(stmt, col_stmt);
 
1945
                SC_log_error(func, "", stmt);
 
1946
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
1947
                return SQL_ERROR;
 
1948
        }
 
1949
 
 
1950
        if (res = QR_Constructor(), !res)
 
1951
        {
 
1952
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Columns result.");
 
1953
                SC_log_error(func, "", stmt);
 
1954
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
1955
                return SQL_ERROR;
 
1956
        }
 
1957
        SC_set_Result(stmt, res);
 
1958
 
 
1959
        /* the binding structure for a statement is not set up until */
 
1960
 
 
1961
        /*
 
1962
         * a statement is actually executed, so we'll have to do this
 
1963
         * ourselves.
 
1964
         */
 
1965
#if (ODBCVER >= 0x0300)
 
1966
        reserved_cols = 18;
 
1967
#else
 
1968
        reserved_cols = 12;
 
1969
#endif /* ODBCVER */
 
1970
        result_cols = reserved_cols + 2;
 
1971
        extend_column_bindings(SC_get_ARD(stmt), result_cols);
 
1972
 
 
1973
        /* set the field names */
 
1974
        QR_set_num_fields(res, result_cols);
 
1975
        QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
1976
        QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
1977
        QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
1978
        QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
1979
        QR_set_field_info(res, 4, "DATA_TYPE", PG_TYPE_INT2, 2);
 
1980
        QR_set_field_info(res, 5, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
1981
        QR_set_field_info(res, 6, "PRECISION", PG_TYPE_INT4, 4); /* COLUMN_SIZE */
 
1982
        QR_set_field_info(res, 7, "LENGTH", PG_TYPE_INT4, 4); /* BUFFER_LENGTH */
 
1983
        QR_set_field_info(res, 8, "SCALE", PG_TYPE_INT2, 2); /* DECIMAL_DIGITS ***/
 
1984
        QR_set_field_info(res, 9, "RADIX", PG_TYPE_INT2, 2);
 
1985
        QR_set_field_info(res, 10, "NULLABLE", PG_TYPE_INT2, 2);
 
1986
        QR_set_field_info(res, 11, "REMARKS", PG_TYPE_VARCHAR, 254);
 
1987
 
 
1988
        /* User defined fields */
 
1989
#if (ODBCVER >= 0x0300)
 
1990
        QR_set_field_info(res, 12, "COLUMN_DEF", PG_TYPE_INT4, 254);
 
1991
        QR_set_field_info(res, 13, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
 
1992
        QR_set_field_info(res, 14, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
 
1993
        QR_set_field_info(res, 15, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
 
1994
        QR_set_field_info(res, 16, "ORDINAL_POSITION", PG_TYPE_INT4, 4);
 
1995
        QR_set_field_info(res, 17, "IS_NULLABLE", PG_TYPE_VARCHAR, 254);
 
1996
#endif /* ODBCVER */
 
1997
        QR_set_field_info(res, reserved_cols, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
 
1998
        QR_set_field_info(res, reserved_cols + 1, "FIELD_TYPE", PG_TYPE_INT4, 4);
 
1999
 
 
2000
        ordinal = 1;
 
2001
        result = PGAPI_Fetch(hcol_stmt);
 
2002
 
 
2003
        /*
 
2004
         * Only show oid if option AND there are other columns AND it's not
 
2005
         * being called by SQLStatistics . Always show OID if it's a system
 
2006
         * table
 
2007
         */
 
2008
 
 
2009
        if (PG_VERSION_GE(conn, 7.1))
 
2010
                relisaview = (relkind[0] == 'v');
 
2011
        else
 
2012
                relisaview = (relhasrules[0] == '1');
 
2013
        if (result != SQL_ERROR && !stmt->internal)
 
2014
        {
 
2015
                if (!relisaview &&
 
2016
                        (atoi(ci->show_oid_column) ||
 
2017
                         strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0))
 
2018
                {
 
2019
                        /* For OID fields */
 
2020
                        the_type = PG_TYPE_OID;
 
2021
                        row = (TupleNode *) malloc(sizeof(TupleNode) +
 
2022
                                                                  (result_cols - 1) *sizeof(TupleField));
 
2023
 
 
2024
                        set_tuplefield_string(&row->tuple[0], "");
 
2025
                        /* see note in SQLTables() */
 
2026
                        if (conn->schema_support)
 
2027
                                set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
 
2028
                        else
 
2029
                                set_tuplefield_string(&row->tuple[1], "");
 
2030
                        set_tuplefield_string(&row->tuple[2], table_name);
 
2031
                        set_tuplefield_string(&row->tuple[3], "oid");
 
2032
                        sqltype = pgtype_to_concise_type(stmt, the_type);
 
2033
                        set_tuplefield_int2(&row->tuple[4], sqltype);
 
2034
                        set_tuplefield_string(&row->tuple[5], "OID");
 
2035
 
 
2036
                        set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
 
2037
                        set_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
 
2038
                        set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
 
2039
                        set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, the_type));
 
2040
                        set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS);
 
2041
                        set_tuplefield_string(&row->tuple[11], "");
 
2042
 
 
2043
#if (ODBCVER >= 0x0300)
 
2044
                        set_tuplefield_null(&row->tuple[12]);
 
2045
                        set_tuplefield_int2(&row->tuple[13], sqltype);
 
2046
                        set_tuplefield_null(&row->tuple[14]);
 
2047
                        set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, the_type, PG_STATIC, PG_STATIC));
 
2048
                        set_tuplefield_int4(&row->tuple[16], ordinal);
 
2049
                        set_tuplefield_string(&row->tuple[17], "No");
 
2050
#endif /* ODBCVER */
 
2051
                        set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
 
2052
                        set_tuplefield_int4(&row->tuple[reserved_cols + 1], the_type);
 
2053
 
 
2054
                        QR_add_tuple(res, row);
 
2055
                        ordinal++;
 
2056
                }
 
2057
        }
 
2058
 
 
2059
        while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO))
 
2060
        {
 
2061
                row = (TupleNode *) malloc(sizeof(TupleNode) +
 
2062
                                                                   (result_cols - 1) *sizeof(TupleField));
 
2063
 
 
2064
 
 
2065
                set_tuplefield_string(&row->tuple[0], "");
 
2066
                /* see note in SQLTables() */
 
2067
                if (conn->schema_support)
 
2068
                        set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
 
2069
                else
 
2070
                        set_tuplefield_string(&row->tuple[1], "");
 
2071
                set_tuplefield_string(&row->tuple[2], table_name);
 
2072
                set_tuplefield_string(&row->tuple[3], field_name);
 
2073
                sqltype = pgtype_to_concise_type(stmt, field_type);
 
2074
                set_tuplefield_int2(&row->tuple[4], sqltype);
 
2075
                set_tuplefield_string(&row->tuple[5], field_type_name);
 
2076
 
 
2077
 
 
2078
                /*----------
 
2079
                 * Some Notes about Postgres Data Types:
 
2080
                 *
 
2081
                 * VARCHAR - the length is stored in the pg_attribute.atttypmod field
 
2082
                 * BPCHAR  - the length is also stored as varchar is
 
2083
                 *
 
2084
                 * NUMERIC - the decimal_digits is stored in atttypmod as follows:
 
2085
                 *
 
2086
                 *      column_size =((atttypmod - VARHDRSZ) >> 16) & 0xffff
 
2087
                 *      decimal_digits   = (atttypmod - VARHDRSZ) & 0xffff
 
2088
                 *
 
2089
                 *----------
 
2090
                 */
 
2091
                qlog("PGAPI_Columns: table='%s',field_name='%s',type=%d,name='%s'\n",
 
2092
                         table_name, field_name, field_type, field_type_name);
 
2093
 
 
2094
                useStaticPrecision = TRUE;
 
2095
 
 
2096
                if (field_type == PG_TYPE_NUMERIC)
 
2097
                {
 
2098
                        if (mod_length >= 4)
 
2099
                                mod_length -= 4;        /* the length is in atttypmod - 4 */
 
2100
 
 
2101
                        if (mod_length >= 0)
 
2102
                        {
 
2103
                                useStaticPrecision = FALSE;
 
2104
 
 
2105
                                column_size = (mod_length >> 16) & 0xffff;
 
2106
                                decimal_digits = mod_length & 0xffff;
 
2107
 
 
2108
                                mylog("%s: field type is NUMERIC: field_type = %d, mod_length=%d, precision=%d, scale=%d\n", func, field_type, mod_length, column_size, decimal_digits);
 
2109
 
 
2110
                                set_tuplefield_int4(&row->tuple[6], column_size);
 
2111
                                set_tuplefield_int4(&row->tuple[7], column_size + 2);           /* sign+dec.point */
 
2112
                                set_nullfield_int2(&row->tuple[8], decimal_digits);
 
2113
#if (ODBCVER >= 0x0300)
 
2114
                                set_tuplefield_null(&row->tuple[15]);
 
2115
#endif /* ODBCVER */
 
2116
                                set_tuplefield_int4(&row->tuple[reserved_cols], column_size + 2);       /* sign+dec.point */
 
2117
                        }
 
2118
                }
 
2119
 
 
2120
                if ((field_type == PG_TYPE_VARCHAR) ||
 
2121
                        (field_type == PG_TYPE_BPCHAR))
 
2122
                {
 
2123
                        useStaticPrecision = FALSE;
 
2124
 
 
2125
                        if (mod_length >= 4)
 
2126
                                mod_length -= 4;        /* the length is in atttypmod - 4 */
 
2127
 
 
2128
                        if (mod_length > ci->drivers.max_varchar_size || mod_length <= 0)
 
2129
                                mod_length = ci->drivers.max_varchar_size;
 
2130
 
 
2131
                        mylog("%s: field type is VARCHAR,BPCHAR: field_type = %d, mod_length = %d\n", func, field_type, mod_length);
 
2132
 
 
2133
                        set_tuplefield_int4(&row->tuple[6], mod_length);
 
2134
                        set_tuplefield_int4(&row->tuple[7], mod_length);
 
2135
                        set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, field_type, PG_STATIC));
 
2136
#if (ODBCVER >= 0x0300)
 
2137
                        set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, field_type, PG_STATIC, PG_STATIC));
 
2138
#endif /* ODBCVER */
 
2139
                        set_tuplefield_int4(&row->tuple[reserved_cols], mod_length);
 
2140
                }
 
2141
 
 
2142
                if (useStaticPrecision)
 
2143
                {
 
2144
                        mylog("%s: field type is OTHER: field_type = %d, pgtype_length = %d\n", func, field_type, pgtype_buffer_length(stmt, field_type, PG_STATIC, PG_STATIC));
 
2145
 
 
2146
                        set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, field_type, PG_STATIC, PG_STATIC));
 
2147
                        set_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, field_type, PG_STATIC, PG_STATIC));
 
2148
                        set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, field_type, PG_STATIC));
 
2149
#if (ODBCVER >= 0x0300)
 
2150
                        set_tuplefield_null(&row->tuple[15]);
 
2151
#endif /* ODBCVER */
 
2152
                        set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, field_type, PG_STATIC, PG_STATIC));
 
2153
                }
 
2154
 
 
2155
                set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, field_type));
 
2156
                set_tuplefield_int2(&row->tuple[10], (Int2) (not_null[0] == '1' ? SQL_NO_NULLS : pgtype_nullable(stmt, field_type)));
 
2157
                set_tuplefield_string(&row->tuple[11], "");
 
2158
#if (ODBCVER >= 0x0300)
 
2159
                set_tuplefield_null(&row->tuple[12]);
 
2160
                set_tuplefield_int2(&row->tuple[13], pgtype_to_sqldesctype(stmt, field_type));
 
2161
                set_nullfield_int2(&row->tuple[14], pgtype_to_datetime_sub(stmt, field_type));
 
2162
                set_tuplefield_int4(&row->tuple[16], ordinal);
 
2163
                set_tuplefield_null(&row->tuple[17]);
 
2164
#endif /* ODBCVER */
 
2165
                set_tuplefield_int4(&row->tuple[reserved_cols + 1], field_type);
 
2166
 
 
2167
                QR_add_tuple(res, row);
 
2168
                ordinal++;
 
2169
 
 
2170
                result = PGAPI_Fetch(hcol_stmt);
 
2171
 
 
2172
        }
 
2173
        if (result != SQL_NO_DATA_FOUND)
 
2174
        {
 
2175
                SC_full_error_copy(stmt, col_stmt);
 
2176
                SC_log_error(func, "", stmt);
 
2177
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2178
                return SQL_ERROR;
 
2179
        }
 
2180
 
 
2181
        /*
 
2182
         * Put the row version column at the end so it might not be mistaken
 
2183
         * for a key field.
 
2184
         */
 
2185
        if (!relisaview && !stmt->internal && atoi(ci->row_versioning))
 
2186
        {
 
2187
                /* For Row Versioning fields */
 
2188
                the_type = PG_TYPE_INT4;
 
2189
 
 
2190
                row = (TupleNode *) malloc(sizeof(TupleNode) +
 
2191
                                                                   (result_cols - 1) *sizeof(TupleField));
 
2192
 
 
2193
                set_tuplefield_string(&row->tuple[0], "");
 
2194
                if (conn->schema_support)
 
2195
                        set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_owner));
 
2196
                else
 
2197
                        set_tuplefield_string(&row->tuple[1], "");
 
2198
                set_tuplefield_string(&row->tuple[2], table_name);
 
2199
                set_tuplefield_string(&row->tuple[3], "xmin");
 
2200
                sqltype = pgtype_to_concise_type(stmt, the_type);
 
2201
                set_tuplefield_int2(&row->tuple[4], sqltype);
 
2202
                set_tuplefield_string(&row->tuple[5], pgtype_to_name(stmt, the_type));
 
2203
                set_tuplefield_int4(&row->tuple[6], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
 
2204
                set_tuplefield_int4(&row->tuple[7], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
 
2205
                set_nullfield_int2(&row->tuple[8], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
 
2206
                set_nullfield_int2(&row->tuple[9], pgtype_radix(stmt, the_type));
 
2207
                set_tuplefield_int2(&row->tuple[10], SQL_NO_NULLS);
 
2208
                set_tuplefield_string(&row->tuple[11], "");
 
2209
#if (ODBCVER >= 0x0300)
 
2210
                set_tuplefield_null(&row->tuple[12]);
 
2211
                set_tuplefield_int2(&row->tuple[13], sqltype);
 
2212
                set_tuplefield_null(&row->tuple[14]);
 
2213
                set_tuplefield_int4(&row->tuple[15], pgtype_transfer_octet_length(stmt, the_type, PG_STATIC, PG_STATIC));
 
2214
                set_tuplefield_int4(&row->tuple[16], ordinal);
 
2215
                set_tuplefield_string(&row->tuple[17], "No");
 
2216
#endif /* ODBCVER */
 
2217
                set_tuplefield_int4(&row->tuple[reserved_cols], pgtype_display_size(stmt, the_type, PG_STATIC, PG_STATIC));
 
2218
                set_tuplefield_int4(&row->tuple[reserved_cols + 1], the_type);
 
2219
 
 
2220
                QR_add_tuple(res, row);
 
2221
                ordinal++;
 
2222
        }
 
2223
 
 
2224
        /*
 
2225
         * also, things need to think that this statement is finished so the
 
2226
         * results can be retrieved.
 
2227
         */
 
2228
        stmt->status = STMT_FINISHED;
 
2229
 
 
2230
        /* set up the current tuple pointer for SQLFetch */
 
2231
        stmt->currTuple = -1;
 
2232
        stmt->rowset_start = -1;
 
2233
        stmt->current_col = -1;
 
2234
 
 
2235
        PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2236
        mylog("%s: EXIT,  stmt=%u\n", func, stmt);
 
2237
        return SQL_SUCCESS;
 
2238
}
 
2239
 
 
2240
 
 
2241
RETCODE         SQL_API
 
2242
PGAPI_SpecialColumns(
 
2243
                                         HSTMT hstmt,
 
2244
                                         UWORD fColType,
 
2245
                                         UCHAR FAR * szTableQualifier,
 
2246
                                         SWORD cbTableQualifier,
 
2247
                                         UCHAR FAR * szTableOwner,
 
2248
                                         SWORD cbTableOwner,
 
2249
                                         UCHAR FAR * szTableName,
 
2250
                                         SWORD cbTableName,
 
2251
                                         UWORD fScope,
 
2252
                                         UWORD fNullable)
 
2253
{
 
2254
        CSTR func = "PGAPI_SpecialColumns";
 
2255
        TupleNode  *row;
 
2256
        StatementClass *stmt = (StatementClass *) hstmt;
 
2257
        ConnectionClass *conn;
 
2258
        QResultClass    *res;
 
2259
        ConnInfo   *ci;
 
2260
        HSTMT           hcol_stmt;
 
2261
        StatementClass *col_stmt;
 
2262
        char            columns_query[INFO_INQUIRY_LEN];
 
2263
        RETCODE         result;
 
2264
        char            relhasrules[MAX_INFO_STRING], relkind[8], relhasoids[8];
 
2265
        BOOL            relisaview;
 
2266
        SWORD           internal_asis_type = SQL_C_CHAR;
 
2267
 
 
2268
        mylog("%s: entering...stmt=%u scnm=%x len=%d colType=%d\n", func, stmt, szTableOwner, cbTableOwner, fColType);
 
2269
 
 
2270
        if (!stmt)
 
2271
        {
 
2272
                SC_log_error(func, "", NULL);
 
2273
                return SQL_INVALID_HANDLE;
 
2274
        }
 
2275
        conn = SC_get_conn(stmt);
 
2276
        ci = &(conn->connInfo);
 
2277
#ifdef  UNICODE_SUPPORT
 
2278
        if (conn->unicode)
 
2279
                internal_asis_type = INTERNAL_ASIS_TYPE;
 
2280
#endif /* UNICODE_SUPPORT */
 
2281
 
 
2282
        stmt->manual_result = TRUE;
 
2283
 
 
2284
        /*
 
2285
         * Create the query to find out if this is a view or not...
 
2286
         */
 
2287
        strcpy(columns_query, "select c.relhasrules, c.relkind");
 
2288
        if (PG_VERSION_GE(conn, 7.2))
 
2289
                strcat(columns_query, ", c.relhasoids");
 
2290
        if (conn->schema_support)
 
2291
                strcat(columns_query, " from pg_catalog.pg_namespace u,"
 
2292
                " pg_catalog.pg_class c where "
 
2293
                        "u.oid = c.relnamespace");
 
2294
        else
 
2295
                strcat(columns_query, " from pg_user u, pg_class c where "
 
2296
                        "u.usesysid = c.relowner");
 
2297
 
 
2298
        /* TableName cannot contain a string search pattern */
 
2299
        my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName);
 
2300
        /* SchemaName cannot contain a string search pattern */
 
2301
        if (conn->schema_support)
 
2302
                schema_strcat(columns_query, " and u.nspname = '%.*s'", szTableOwner, cbTableOwner, szTableName, cbTableName, conn);
 
2303
        else
 
2304
                my_strcat(columns_query, " and u.usename = '%.*s'", szTableOwner, cbTableOwner);
 
2305
 
 
2306
 
 
2307
        result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
 
2308
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2309
        {
 
2310
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for SQLSpecialColumns result.");
 
2311
                SC_log_error(func, "", stmt);
 
2312
                return SQL_ERROR;
 
2313
        }
 
2314
        col_stmt = (StatementClass *) hcol_stmt;
 
2315
 
 
2316
        mylog("%s: hcol_stmt = %u, col_stmt = %u\n", func, hcol_stmt, col_stmt);
 
2317
 
 
2318
        result = PGAPI_ExecDirect(hcol_stmt, columns_query,
 
2319
                                                          strlen(columns_query));
 
2320
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2321
        {
 
2322
                SC_full_error_copy(stmt, col_stmt);
 
2323
                SC_log_error(func, "", stmt);
 
2324
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2325
                return SQL_ERROR;
 
2326
        }
 
2327
 
 
2328
        result = PGAPI_BindCol(hcol_stmt, 1, internal_asis_type,
 
2329
                                        relhasrules, sizeof(relhasrules), NULL);
 
2330
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2331
        {
 
2332
                SC_error_copy(stmt, col_stmt);
 
2333
                SC_log_error(func, "", stmt);
 
2334
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2335
                return SQL_ERROR;
 
2336
        }
 
2337
 
 
2338
        result = PGAPI_BindCol(hcol_stmt, 2, internal_asis_type,
 
2339
                                        relkind, sizeof(relkind), NULL);
 
2340
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2341
        {
 
2342
                SC_error_copy(stmt, col_stmt);
 
2343
                SC_log_error(func, "", stmt);
 
2344
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2345
                return SQL_ERROR;
 
2346
        }
 
2347
        relhasoids[0] = '1';
 
2348
        if (PG_VERSION_GE(conn, 7.2))
 
2349
        {
 
2350
                result = PGAPI_BindCol(hcol_stmt, 3, internal_asis_type,
 
2351
                                        relhasoids, sizeof(relhasoids), NULL);
 
2352
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2353
                {
 
2354
                        SC_error_copy(stmt, col_stmt);
 
2355
                        SC_log_error(func, "", stmt);
 
2356
                        PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2357
                        return SQL_ERROR;
 
2358
                }
 
2359
        }
 
2360
 
 
2361
        result = PGAPI_Fetch(hcol_stmt);
 
2362
        if (PG_VERSION_GE(conn, 7.1))
 
2363
                relisaview = (relkind[0] == 'v');
 
2364
        else
 
2365
                relisaview = (relhasrules[0] == '1');
 
2366
        PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2367
 
 
2368
        res = QR_Constructor();
 
2369
        SC_set_Result(stmt, res);
 
2370
        extend_column_bindings(SC_get_ARD(stmt), 8);
 
2371
 
 
2372
        QR_set_num_fields(res, 8);
 
2373
        QR_set_field_info(res, 0, "SCOPE", PG_TYPE_INT2, 2);
 
2374
        QR_set_field_info(res, 1, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2375
        QR_set_field_info(res, 2, "DATA_TYPE", PG_TYPE_INT2, 2);
 
2376
        QR_set_field_info(res, 3, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2377
        QR_set_field_info(res, 4, "PRECISION", PG_TYPE_INT4, 4);
 
2378
        QR_set_field_info(res, 5, "LENGTH", PG_TYPE_INT4, 4);
 
2379
        QR_set_field_info(res, 6, "SCALE", PG_TYPE_INT2, 2);
 
2380
        QR_set_field_info(res, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2);
 
2381
 
 
2382
        if (relisaview)
 
2383
        {
 
2384
                /* there's no oid for views */
 
2385
                if (fColType == SQL_BEST_ROWID)
 
2386
                {
 
2387
                        return SQL_NO_DATA_FOUND;
 
2388
                }
 
2389
                else if (fColType == SQL_ROWVER)
 
2390
                {
 
2391
                        Int2            the_type = PG_TYPE_TID;
 
2392
 
 
2393
                        row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField));
 
2394
 
 
2395
                        set_tuplefield_null(&row->tuple[0]);
 
2396
                        set_tuplefield_string(&row->tuple[1], "ctid");
 
2397
                        set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, the_type));
 
2398
                        set_tuplefield_string(&row->tuple[3], pgtype_to_name(stmt, the_type));
 
2399
                        set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
 
2400
                        set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
 
2401
                        set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
 
2402
                        set_tuplefield_int2(&row->tuple[7], SQL_PC_NOT_PSEUDO);
 
2403
 
 
2404
                        QR_add_tuple(res, row);
 
2405
inolog("Add ctid\n");
 
2406
                }
 
2407
        }
 
2408
        else
 
2409
        {
 
2410
                /* use the oid value for the rowid */
 
2411
                if (fColType == SQL_BEST_ROWID)
 
2412
                {
 
2413
                        if (relhasoids[0] != '1')
 
2414
                                return SQL_NO_DATA_FOUND;
 
2415
                        row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField));
 
2416
 
 
2417
                        set_tuplefield_int2(&row->tuple[0], SQL_SCOPE_SESSION);
 
2418
                        set_tuplefield_string(&row->tuple[1], "oid");
 
2419
                        set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, PG_TYPE_OID));
 
2420
                        set_tuplefield_string(&row->tuple[3], "OID");
 
2421
                        set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
 
2422
                        set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, PG_TYPE_OID, PG_STATIC, PG_STATIC));
 
2423
                        set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, PG_TYPE_OID, PG_STATIC));
 
2424
                        set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
 
2425
 
 
2426
                        QR_add_tuple(res, row);
 
2427
 
 
2428
                }
 
2429
                else if (fColType == SQL_ROWVER)
 
2430
                {
 
2431
                        Int2            the_type = PG_TYPE_INT4;
 
2432
 
 
2433
                        if (atoi(ci->row_versioning))
 
2434
                        {
 
2435
                                row = (TupleNode *) malloc(sizeof(TupleNode) + (8 - 1) *sizeof(TupleField));
 
2436
 
 
2437
                                set_tuplefield_null(&row->tuple[0]);
 
2438
                                set_tuplefield_string(&row->tuple[1], "xmin");
 
2439
                                set_tuplefield_int2(&row->tuple[2], pgtype_to_concise_type(stmt, the_type));
 
2440
                                set_tuplefield_string(&row->tuple[3], pgtype_to_name(stmt, the_type));
 
2441
                                set_tuplefield_int4(&row->tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, PG_STATIC));
 
2442
                                set_tuplefield_int4(&row->tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, PG_STATIC));
 
2443
                                set_tuplefield_int2(&row->tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
 
2444
                                set_tuplefield_int2(&row->tuple[7], SQL_PC_PSEUDO);
 
2445
 
 
2446
                                QR_add_tuple(res, row);
 
2447
                        }
 
2448
                }
 
2449
        }
 
2450
 
 
2451
        stmt->status = STMT_FINISHED;
 
2452
        stmt->currTuple = -1;
 
2453
        stmt->rowset_start = -1;
 
2454
        stmt->current_col = -1;
 
2455
 
 
2456
        mylog("%s: EXIT,  stmt=%u\n", func, stmt);
 
2457
        return SQL_SUCCESS;
 
2458
}
 
2459
 
 
2460
 
 
2461
RETCODE         SQL_API
 
2462
PGAPI_Statistics(
 
2463
                                 HSTMT hstmt,
 
2464
                                 UCHAR FAR * szTableQualifier,
 
2465
                                 SWORD cbTableQualifier,
 
2466
                                 UCHAR FAR * szTableOwner,
 
2467
                                 SWORD cbTableOwner,
 
2468
                                 UCHAR FAR * szTableName,
 
2469
                                 SWORD cbTableName,
 
2470
                                 UWORD fUnique,
 
2471
                                 UWORD fAccuracy)
 
2472
{
 
2473
        CSTR func = "PGAPI_Statistics";
 
2474
        StatementClass *stmt = (StatementClass *) hstmt;
 
2475
        ConnectionClass *conn;
 
2476
        QResultClass    *res;
 
2477
        char            index_query[INFO_INQUIRY_LEN];
 
2478
        HSTMT           hindx_stmt;
 
2479
        RETCODE         result;
 
2480
        char       *table_name;
 
2481
        char            index_name[MAX_INFO_STRING];
 
2482
        short           fields_vector[INDEX_KEYS_STORAGE_COUNT];
 
2483
        char            isunique[10],
 
2484
                                isclustered[10],
 
2485
                                ishash[MAX_INFO_STRING];
 
2486
        SDWORD          index_name_len,
 
2487
                                fields_vector_len;
 
2488
        TupleNode  *row;
 
2489
        int                     i;
 
2490
        HSTMT           hcol_stmt;
 
2491
        StatementClass *col_stmt,
 
2492
                           *indx_stmt;
 
2493
        char            column_name[MAX_INFO_STRING],
 
2494
                        table_qualifier[MAX_INFO_STRING],
 
2495
                                relhasrules[10], relkind[8];
 
2496
        char      **column_names = 0;
 
2497
        SQLINTEGER      column_name_len;
 
2498
        int                     total_columns = 0;
 
2499
        char            error = TRUE;
 
2500
        ConnInfo   *ci;
 
2501
        char            buf[256];
 
2502
        SWORD           internal_asis_type = SQL_C_CHAR;
 
2503
 
 
2504
        mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
 
2505
 
 
2506
        if (!stmt)
 
2507
        {
 
2508
                SC_log_error(func, "", NULL);
 
2509
                return SQL_INVALID_HANDLE;
 
2510
        }
 
2511
 
 
2512
        stmt->manual_result = TRUE;
 
2513
        stmt->errormsg_created = TRUE;
 
2514
 
 
2515
        conn = SC_get_conn(stmt);
 
2516
        ci = &(conn->connInfo);
 
2517
#ifdef  UNICODE_SUPPORT
 
2518
        if (conn->unicode)
 
2519
                internal_asis_type = INTERNAL_ASIS_TYPE;
 
2520
#endif /* UNICODE_SUPPORT */
 
2521
 
 
2522
        if (res = QR_Constructor(), !res)
 
2523
        {
 
2524
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Statistics result.");
 
2525
                SC_log_error(func, "", stmt);
 
2526
                return SQL_ERROR;
 
2527
        }
 
2528
        SC_set_Result(stmt, res);
 
2529
 
 
2530
        /* the binding structure for a statement is not set up until */
 
2531
 
 
2532
        /*
 
2533
         * a statement is actually executed, so we'll have to do this
 
2534
         * ourselves.
 
2535
         */
 
2536
        extend_column_bindings(SC_get_ARD(stmt), 13);
 
2537
 
 
2538
        /* set the field names */
 
2539
        QR_set_num_fields(res, 13);
 
2540
        QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2541
        QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2542
        QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2543
        QR_set_field_info(res, 3, "NON_UNIQUE", PG_TYPE_INT2, 2);
 
2544
        QR_set_field_info(res, 4, "INDEX_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2545
        QR_set_field_info(res, 5, "INDEX_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2546
        QR_set_field_info(res, 6, "TYPE", PG_TYPE_INT2, 2);
 
2547
        QR_set_field_info(res, 7, "SEQ_IN_INDEX", PG_TYPE_INT2, 2);
 
2548
        QR_set_field_info(res, 8, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2549
        QR_set_field_info(res, 9, "COLLATION", PG_TYPE_CHAR, 1);
 
2550
        QR_set_field_info(res, 10, "CARDINALITY", PG_TYPE_INT4, 4);
 
2551
        QR_set_field_info(res, 11, "PAGES", PG_TYPE_INT4, 4);
 
2552
        QR_set_field_info(res, 12, "FILTER_CONDITION", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2553
 
 
2554
        /*
 
2555
         * only use the table name... the owner should be redundant, and we
 
2556
         * never use qualifiers.
 
2557
         */
 
2558
        table_name = make_string(szTableName, cbTableName, NULL);
 
2559
        if (!table_name)
 
2560
        {
 
2561
                SC_set_error(stmt, STMT_INTERNAL_ERROR, "No table name passed to PGAPI_Statistics.");
 
2562
                SC_log_error(func, "", stmt);
 
2563
                return SQL_ERROR;
 
2564
        }
 
2565
        table_qualifier[0] = '\0';
 
2566
        if (conn->schema_support)
 
2567
                schema_strcat(table_qualifier, "%.*s", szTableOwner, cbTableOwner, szTableName, cbTableName, conn);
 
2568
 
 
2569
        /*
 
2570
         * we need to get a list of the field names first, so we can return
 
2571
         * them later.
 
2572
         */
 
2573
        result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
 
2574
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2575
        {
 
2576
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in PGAPI_Statistics for columns.");
 
2577
                goto SEEYA;
 
2578
        }
 
2579
 
 
2580
        col_stmt = (StatementClass *) hcol_stmt;
 
2581
 
 
2582
        /*
 
2583
         * "internal" prevents SQLColumns from returning the oid if it is
 
2584
         * being shown. This would throw everything off.
 
2585
         */
 
2586
        col_stmt->internal = TRUE;
 
2587
        /* 
 
2588
         * table_name parameter cannot contain a string search pattern. 
 
2589
         */
 
2590
        result = PGAPI_Columns(hcol_stmt, "", 0, table_qualifier, SQL_NTS,
 
2591
                                                   table_name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN);
 
2592
        col_stmt->internal = FALSE;
 
2593
 
 
2594
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2595
        {
 
2596
                SC_error_copy(stmt, col_stmt);
 
2597
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2598
                goto SEEYA;
 
2599
        }
 
2600
        result = PGAPI_BindCol(hcol_stmt, 4, internal_asis_type,
 
2601
                                                 column_name, sizeof(column_name), &column_name_len);
 
2602
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2603
        {
 
2604
                SC_error_copy(stmt, col_stmt);
 
2605
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2606
                goto SEEYA;
 
2607
 
 
2608
        }
 
2609
 
 
2610
        result = PGAPI_Fetch(hcol_stmt);
 
2611
        while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO))
 
2612
        {
 
2613
                total_columns++;
 
2614
 
 
2615
                column_names =
 
2616
                        (char **) realloc(column_names,
 
2617
                                                          total_columns * sizeof(char *));
 
2618
                column_names[total_columns - 1] =
 
2619
                        (char *) malloc(strlen(column_name) + 1);
 
2620
                strcpy(column_names[total_columns - 1], column_name);
 
2621
 
 
2622
                mylog("%s: column_name = '%s'\n", func, column_name);
 
2623
 
 
2624
                result = PGAPI_Fetch(hcol_stmt);
 
2625
        }
 
2626
 
 
2627
        if (result != SQL_NO_DATA_FOUND || total_columns == 0)
 
2628
        {
 
2629
                SC_full_error_copy(stmt, col_stmt); /* "Couldn't get column
 
2630
                                                                                                                 * names in
 
2631
                                                                                                                 * SQLStatistics."; */
 
2632
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2633
                goto SEEYA;
 
2634
 
 
2635
        }
 
2636
 
 
2637
        PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2638
 
 
2639
        /* get a list of indexes on this table */
 
2640
        result = PGAPI_AllocStmt(stmt->hdbc, &hindx_stmt);
 
2641
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2642
        {
 
2643
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in SQLStatistics for indices.");
 
2644
                goto SEEYA;
 
2645
 
 
2646
        }
 
2647
        indx_stmt = (StatementClass *) hindx_stmt;
 
2648
 
 
2649
        if (conn->schema_support)
 
2650
                sprintf(index_query, "select c.relname, i.indkey, i.indisunique"
 
2651
                        ", i.indisclustered, a.amname, c.relhasrules, n.nspname"
 
2652
                        " from pg_catalog.pg_index i, pg_catalog.pg_class c,"
 
2653
                        " pg_catalog.pg_class d, pg_catalog.pg_am a,"
 
2654
                        " pg_catalog.pg_namespace n"
 
2655
                        " where d.relname = '%s'"
 
2656
                        " and n.nspname = '%s'"
 
2657
                        " and n.oid = d.relnamespace"
 
2658
                        " and d.oid = i.indrelid"
 
2659
                        " and i.indexrelid = c.oid"
 
2660
                        " and c.relam = a.oid order by"
 
2661
                        ,table_name, table_qualifier);
 
2662
        else
 
2663
                sprintf(index_query, "select c.relname, i.indkey, i.indisunique"
 
2664
                        ", i.indisclustered, a.amname, c.relhasrules"
 
2665
                        " from pg_index i, pg_class c, pg_class d, pg_am a"
 
2666
                        " where d.relname = '%s'"
 
2667
                        " and d.oid = i.indrelid"
 
2668
                        " and i.indexrelid = c.oid"
 
2669
                        " and c.relam = a.oid order by"
 
2670
                        ,table_name);
 
2671
        if (PG_VERSION_GT(SC_get_conn(stmt), 6.4))
 
2672
                strcat(index_query, " i.indisprimary desc,");
 
2673
        if (conn->schema_support)
 
2674
                strcat(index_query, " i.indisunique, n.nspname, c.relname");
 
2675
        else
 
2676
                strcat(index_query, " i.indisunique, c.relname");
 
2677
 
 
2678
        result = PGAPI_ExecDirect(hindx_stmt, index_query, strlen(index_query));
 
2679
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2680
        {
 
2681
                /*
 
2682
                 * "Couldn't execute index query (w/SQLExecDirect) in
 
2683
                 * SQLStatistics.";
 
2684
                 */
 
2685
                SC_full_error_copy(stmt, indx_stmt);
 
2686
                PGAPI_FreeStmt(hindx_stmt, SQL_DROP);
 
2687
                goto SEEYA;
 
2688
        }
 
2689
 
 
2690
        /* bind the index name column */
 
2691
        result = PGAPI_BindCol(hindx_stmt, 1, internal_asis_type,
 
2692
                                                   index_name, MAX_INFO_STRING, &index_name_len);
 
2693
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2694
        {
 
2695
                SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column 
 
2696
                                                * in SQLStatistics."; */
 
2697
                PGAPI_FreeStmt(hindx_stmt, SQL_DROP);
 
2698
                goto SEEYA;
 
2699
 
 
2700
        }
 
2701
        /* bind the vector column */
 
2702
        result = PGAPI_BindCol(hindx_stmt, 2, SQL_C_DEFAULT,
 
2703
                        fields_vector, INDEX_KEYS_STORAGE_COUNT * 2, &fields_vector_len);
 
2704
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2705
        {
 
2706
                SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column 
 
2707
                                                 * in SQLStatistics."; */
 
2708
                PGAPI_FreeStmt(hindx_stmt, SQL_DROP);
 
2709
                goto SEEYA;
 
2710
 
 
2711
        }
 
2712
        /* bind the "is unique" column */
 
2713
        result = PGAPI_BindCol(hindx_stmt, 3, internal_asis_type,
 
2714
                                                   isunique, sizeof(isunique), NULL);
 
2715
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2716
        {
 
2717
                SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column 
 
2718
                                                 * in SQLStatistics."; */
 
2719
                PGAPI_FreeStmt(hindx_stmt, SQL_DROP);
 
2720
                goto SEEYA;
 
2721
        }
 
2722
 
 
2723
        /* bind the "is clustered" column */
 
2724
        result = PGAPI_BindCol(hindx_stmt, 4, internal_asis_type,
 
2725
                                                   isclustered, sizeof(isclustered), NULL);
 
2726
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2727
        {
 
2728
                SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column *
 
2729
                                                 * in SQLStatistics."; */
 
2730
                PGAPI_FreeStmt(hindx_stmt, SQL_DROP);
 
2731
                goto SEEYA;
 
2732
 
 
2733
        }
 
2734
 
 
2735
        /* bind the "is hash" column */
 
2736
        result = PGAPI_BindCol(hindx_stmt, 5, internal_asis_type,
 
2737
                                                   ishash, sizeof(ishash), NULL);
 
2738
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2739
        {
 
2740
                SC_error_copy(stmt, indx_stmt); /* "Couldn't bind column * 
 
2741
                                                 * in SQLStatistics."; */
 
2742
                PGAPI_FreeStmt(hindx_stmt, SQL_DROP);
 
2743
                goto SEEYA;
 
2744
 
 
2745
        }
 
2746
 
 
2747
        result = PGAPI_BindCol(hindx_stmt, 6, internal_asis_type,
 
2748
                                        relhasrules, sizeof(relhasrules), NULL);
 
2749
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2750
        {
 
2751
                SC_error_copy(stmt, indx_stmt);
 
2752
                PGAPI_FreeStmt(hindx_stmt, SQL_DROP);
 
2753
                goto SEEYA;
 
2754
        }
 
2755
 
 
2756
        relhasrules[0] = '0';
 
2757
        result = PGAPI_Fetch(hindx_stmt);
 
2758
        /* fake index of OID */
 
2759
        if (relhasrules[0] != '1' && atoi(ci->show_oid_column) && atoi(ci->fake_oid_index))
 
2760
        {
 
2761
                row = (TupleNode *) malloc(sizeof(TupleNode) +
 
2762
                                                                   (13 - 1) *sizeof(TupleField));
 
2763
 
 
2764
                /* no table qualifier */
 
2765
                set_tuplefield_string(&row->tuple[0], "");
 
2766
                /* don't set the table owner, else Access tries to use it */
 
2767
                set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_qualifier));
 
2768
                set_tuplefield_string(&row->tuple[2], table_name);
 
2769
 
 
2770
                /* non-unique index? */
 
2771
                set_tuplefield_int2(&row->tuple[3], (Int2) (ci->drivers.unique_index ? FALSE : TRUE));
 
2772
 
 
2773
                /* no index qualifier */
 
2774
                set_tuplefield_string(&row->tuple[4], "");
 
2775
 
 
2776
                sprintf(buf, "%s_idx_fake_oid", table_name);
 
2777
                set_tuplefield_string(&row->tuple[5], buf);
 
2778
 
 
2779
                /*
 
2780
                 * Clustered/HASH index?
 
2781
                 */
 
2782
                set_tuplefield_int2(&row->tuple[6], (Int2) SQL_INDEX_OTHER);
 
2783
                set_tuplefield_int2(&row->tuple[7], (Int2) 1);
 
2784
 
 
2785
                set_tuplefield_string(&row->tuple[8], "oid");
 
2786
                set_tuplefield_string(&row->tuple[9], "A");
 
2787
                set_tuplefield_null(&row->tuple[10]);
 
2788
                set_tuplefield_null(&row->tuple[11]);
 
2789
                set_tuplefield_null(&row->tuple[12]);
 
2790
 
 
2791
                QR_add_tuple(res, row);
 
2792
        }
 
2793
 
 
2794
        while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO))
 
2795
        {
 
2796
                /* If only requesting unique indexs, then just return those. */
 
2797
                if (fUnique == SQL_INDEX_ALL ||
 
2798
                        (fUnique == SQL_INDEX_UNIQUE && atoi(isunique)))
 
2799
                {
 
2800
                        i = 0;
 
2801
                        /* add a row in this table for each field in the index */
 
2802
                        while (i < INDEX_KEYS_STORAGE_COUNT && fields_vector[i] != 0)
 
2803
                        {
 
2804
                                row = (TupleNode *) malloc(sizeof(TupleNode) +
 
2805
                                                                                   (13 - 1) *sizeof(TupleField));
 
2806
 
 
2807
                                /* no table qualifier */
 
2808
                                set_tuplefield_string(&row->tuple[0], "");
 
2809
                                /* don't set the table owner, else Access tries to use it */
 
2810
                                set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(table_qualifier));
 
2811
                                set_tuplefield_string(&row->tuple[2], table_name);
 
2812
 
 
2813
                                /* non-unique index? */
 
2814
                                if (ci->drivers.unique_index)
 
2815
                                        set_tuplefield_int2(&row->tuple[3], (Int2) (atoi(isunique) ? FALSE : TRUE));
 
2816
                                else
 
2817
                                        set_tuplefield_int2(&row->tuple[3], TRUE);
 
2818
 
 
2819
                                /* no index qualifier */
 
2820
                                set_tuplefield_string(&row->tuple[4], "");
 
2821
                                set_tuplefield_string(&row->tuple[5], index_name);
 
2822
 
 
2823
                                /*
 
2824
                                 * Clustered/HASH index?
 
2825
                                 */
 
2826
                                set_tuplefield_int2(&row->tuple[6], (Int2)
 
2827
                                                           (atoi(isclustered) ? SQL_INDEX_CLUSTERED :
 
2828
                                                                (!strncmp(ishash, "hash", 4)) ? SQL_INDEX_HASHED : SQL_INDEX_OTHER));
 
2829
                                set_tuplefield_int2(&row->tuple[7], (Int2) (i + 1));
 
2830
 
 
2831
                                if (fields_vector[i] == OID_ATTNUM)
 
2832
                                {
 
2833
                                        set_tuplefield_string(&row->tuple[8], "oid");
 
2834
                                        mylog("%s: column name = oid\n", func);
 
2835
                                }
 
2836
                                else if (fields_vector[i] < 0 || fields_vector[i] > total_columns)
 
2837
                                {
 
2838
                                        set_tuplefield_string(&row->tuple[8], "UNKNOWN");
 
2839
                                        mylog("%s: column name = UNKNOWN\n", func);
 
2840
                                }
 
2841
                                else
 
2842
                                {
 
2843
                                        set_tuplefield_string(&row->tuple[8], column_names[fields_vector[i] - 1]);
 
2844
                                        mylog("%s: column name = '%s'\n", func, column_names[fields_vector[i] - 1]);
 
2845
                                }
 
2846
 
 
2847
                                set_tuplefield_string(&row->tuple[9], "A");
 
2848
                                set_tuplefield_null(&row->tuple[10]);
 
2849
                                set_tuplefield_null(&row->tuple[11]);
 
2850
                                set_tuplefield_null(&row->tuple[12]);
 
2851
 
 
2852
                                QR_add_tuple(res, row);
 
2853
                                i++;
 
2854
                        }
 
2855
                }
 
2856
 
 
2857
                result = PGAPI_Fetch(hindx_stmt);
 
2858
        }
 
2859
        if (result != SQL_NO_DATA_FOUND)
 
2860
        {
 
2861
                /* "SQLFetch failed in SQLStatistics."; */
 
2862
                SC_full_error_copy(stmt, indx_stmt);
 
2863
                PGAPI_FreeStmt(hindx_stmt, SQL_DROP);
 
2864
                goto SEEYA;
 
2865
        }
 
2866
 
 
2867
        PGAPI_FreeStmt(hindx_stmt, SQL_DROP);
 
2868
 
 
2869
        /*
 
2870
         * also, things need to think that this statement is finished so the
 
2871
         * results can be retrieved.
 
2872
         */
 
2873
        stmt->status = STMT_FINISHED;
 
2874
 
 
2875
        /* set up the current tuple pointer for SQLFetch */
 
2876
        stmt->currTuple = -1;
 
2877
        stmt->rowset_start = -1;
 
2878
        stmt->current_col = -1;
 
2879
 
 
2880
        error = FALSE;
 
2881
 
 
2882
SEEYA:
 
2883
        /* These things should be freed on any error ALSO! */
 
2884
        free(table_name);
 
2885
        for (i = 0; i < total_columns; i++)
 
2886
                free(column_names[i]);
 
2887
        free(column_names);
 
2888
 
 
2889
        mylog("%s: EXIT, %s, stmt=%u\n", func, error ? "error" : "success", stmt);
 
2890
 
 
2891
        if (error)
 
2892
        {
 
2893
                SC_log_error(func, "", stmt);
 
2894
                return SQL_ERROR;
 
2895
        }
 
2896
        else
 
2897
                return SQL_SUCCESS;
 
2898
}
 
2899
 
 
2900
 
 
2901
RETCODE         SQL_API
 
2902
PGAPI_ColumnPrivileges(
 
2903
                                           HSTMT hstmt,
 
2904
                                           UCHAR FAR * szTableQualifier,
 
2905
                                           SWORD cbTableQualifier,
 
2906
                                           UCHAR FAR * szTableOwner,
 
2907
                                           SWORD cbTableOwner,
 
2908
                                           UCHAR FAR * szTableName,
 
2909
                                           SWORD cbTableName,
 
2910
                                           UCHAR FAR * szColumnName,
 
2911
                                           SWORD cbColumnName)
 
2912
{
 
2913
        CSTR func = "PGAPI_ColumnPrivileges";
 
2914
        StatementClass  *stmt = (StatementClass *) hstmt;
 
2915
 
 
2916
        mylog("%s: entering...\n", func);
 
2917
 
 
2918
        /* Neither Access or Borland care about this. */
 
2919
 
 
2920
        SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "not implemented");
 
2921
        SC_log_error(func, "Function not implemented", stmt);
 
2922
        return SQL_ERROR;
 
2923
}
 
2924
 
 
2925
 
 
2926
/*
 
2927
 *      SQLPrimaryKeys()
 
2928
 *
 
2929
 *      Retrieve the primary key columns for the specified table.
 
2930
 */
 
2931
RETCODE         SQL_API
 
2932
PGAPI_PrimaryKeys(
 
2933
                                  HSTMT hstmt,
 
2934
                                  UCHAR FAR * szTableQualifier,
 
2935
                                  SWORD cbTableQualifier,
 
2936
                                  UCHAR FAR * szTableOwner,
 
2937
                                  SWORD cbTableOwner,
 
2938
                                  UCHAR FAR * szTableName,
 
2939
                                  SWORD cbTableName)
 
2940
{
 
2941
        CSTR func = "PGAPI_PrimaryKeys";
 
2942
        StatementClass *stmt = (StatementClass *) hstmt;
 
2943
        QResultClass    *res;
 
2944
        ConnectionClass *conn;
 
2945
        TupleNode  *row;
 
2946
        RETCODE         result;
 
2947
        int                     seq = 0;
 
2948
        HSTMT           htbl_stmt;
 
2949
        StatementClass *tbl_stmt;
 
2950
        char            tables_query[INFO_INQUIRY_LEN];
 
2951
        char            attname[MAX_INFO_STRING];
 
2952
        SDWORD          attname_len;
 
2953
        char            pktab[TABLE_NAME_STORAGE_LEN + 1], pkscm[TABLE_NAME_STORAGE_LEN + 1];
 
2954
        Int2            result_cols;
 
2955
        int                     qno,
 
2956
                                qstart,
 
2957
                                qend;
 
2958
        SWORD           internal_asis_type = SQL_C_CHAR;
 
2959
 
 
2960
        mylog("%s: entering...stmt=%u scnm=%x len=%d\n", func, stmt, szTableOwner, cbTableOwner);
 
2961
 
 
2962
        if (!stmt)
 
2963
        {
 
2964
                SC_log_error(func, "", NULL);
 
2965
                return SQL_INVALID_HANDLE;
 
2966
        }
 
2967
        stmt->manual_result = TRUE;
 
2968
        stmt->errormsg_created = TRUE;
 
2969
 
 
2970
        if (res = QR_Constructor(), !res)
 
2971
        {
 
2972
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_PrimaryKeys result.");
 
2973
                SC_log_error(func, "", stmt);
 
2974
                return SQL_ERROR;
 
2975
        }
 
2976
        SC_set_Result(stmt, res);
 
2977
 
 
2978
        /* the binding structure for a statement is not set up until */
 
2979
 
 
2980
        /*
 
2981
         * a statement is actually executed, so we'll have to do this
 
2982
         * ourselves.
 
2983
         */
 
2984
        result_cols = 6;
 
2985
        extend_column_bindings(SC_get_ARD(stmt), result_cols);
 
2986
 
 
2987
        /* set the field names */
 
2988
        QR_set_num_fields(res, result_cols);
 
2989
        QR_set_field_info(res, 0, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2990
        QR_set_field_info(res, 1, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2991
        QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2992
        QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2993
        QR_set_field_info(res, 4, "KEY_SEQ", PG_TYPE_INT2, 2);
 
2994
        QR_set_field_info(res, 5, "PK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2995
 
 
2996
 
 
2997
        result = PGAPI_AllocStmt(stmt->hdbc, &htbl_stmt);
 
2998
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
2999
        {
 
3000
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for Primary Key result.");
 
3001
                SC_log_error(func, "", stmt);
 
3002
                return SQL_ERROR;
 
3003
        }
 
3004
        tbl_stmt = (StatementClass *) htbl_stmt;
 
3005
 
 
3006
        conn = SC_get_conn(stmt);
 
3007
#ifdef  UNICODE_SUPPORT
 
3008
        if (conn->unicode)
 
3009
                internal_asis_type = INTERNAL_ASIS_TYPE;
 
3010
#endif /* UNICODE_SUPPORT */
 
3011
        pktab[0] = '\0';
 
3012
        make_string(szTableName, cbTableName, pktab);
 
3013
        if (pktab[0] == '\0')
 
3014
        {
 
3015
                SC_set_error(stmt, STMT_INTERNAL_ERROR, "No Table specified to PGAPI_PrimaryKeys.");
 
3016
                SC_log_error(func, "", stmt);
 
3017
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3018
                return SQL_ERROR;
 
3019
        }
 
3020
        pkscm[0] = '\0';
 
3021
        if (conn->schema_support)
 
3022
                schema_strcat(pkscm, "%.*s", szTableOwner, cbTableOwner, szTableName, cbTableName, conn);
 
3023
 
 
3024
        result = PGAPI_BindCol(htbl_stmt, 1, internal_asis_type,
 
3025
                                                   attname, MAX_INFO_STRING, &attname_len);
 
3026
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
3027
        {
 
3028
                SC_error_copy(stmt, tbl_stmt);
 
3029
                SC_log_error(func, "", stmt);
 
3030
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3031
                return SQL_ERROR;
 
3032
        }
 
3033
 
 
3034
        if (PG_VERSION_LE(conn, 6.4))
 
3035
                qstart = 2;
 
3036
        else
 
3037
                qstart = 1;
 
3038
        qend = 2;
 
3039
        for (qno = qstart; qno <= qend; qno++)
 
3040
        {
 
3041
                switch (qno)
 
3042
                {
 
3043
                        case 1:
 
3044
 
 
3045
                                /*
 
3046
                                 * Simplified query to remove assumptions about number of
 
3047
                                 * possible index columns. Courtesy of Tom Lane - thomas
 
3048
                                 * 2000-03-21
 
3049
                                 */
 
3050
                                if (conn->schema_support)
 
3051
                                        sprintf(tables_query, "select ta.attname, ia.attnum"
 
3052
                                                " from pg_catalog.pg_attribute ta,"
 
3053
                                                " pg_catalog.pg_attribute ia, pg_catalog.pg_class c,"
 
3054
                                                " pg_catalog.pg_index i, pg_catalog.pg_namespace n"
 
3055
                                                " where c.relname = '%s'"
 
3056
                                                " AND n.nspname = '%s'"
 
3057
                                                " AND c.oid = i.indrelid"
 
3058
                                                " AND n.oid = c.relnamespace"
 
3059
                                                " AND i.indisprimary = 't'"
 
3060
                                                " AND ia.attrelid = i.indexrelid"
 
3061
                                                " AND ta.attrelid = i.indrelid"
 
3062
                                                " AND ta.attnum = i.indkey[ia.attnum-1]"
 
3063
                                                " AND (NOT ta.attisdropped)"
 
3064
                                                " AND (NOT ia.attisdropped)"
 
3065
                                                " order by ia.attnum", pktab, pkscm);
 
3066
                                else
 
3067
                                        sprintf(tables_query, "select ta.attname, ia.attnum"
 
3068
                                                " from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i"
 
3069
                                                " where c.relname = '%s'"
 
3070
                                                " AND c.oid = i.indrelid"
 
3071
                                                " AND i.indisprimary = 't'"
 
3072
                                                " AND ia.attrelid = i.indexrelid"
 
3073
                                                " AND ta.attrelid = i.indrelid"
 
3074
                                                " AND ta.attnum = i.indkey[ia.attnum-1]"
 
3075
                                                " order by ia.attnum", pktab);
 
3076
                                break;
 
3077
                        case 2:
 
3078
 
 
3079
                                /*
 
3080
                                 * Simplified query to search old fashoned primary key
 
3081
                                 */
 
3082
                                if (conn->schema_support)
 
3083
                                        sprintf(tables_query, "select ta.attname, ia.attnum"
 
3084
                                                " from pg_catalog.pg_attribute ta,"
 
3085
                                                " pg_catalog.pg_attribute ia, pg_catalog.pg_class c,"
 
3086
                                                " pg_catalog.pg_index i, pg_catalog.pg_namespace n"
 
3087
                                                " where c.relname = '%s_pkey'"
 
3088
                                                " AND n.nspname = '%s'"
 
3089
                                                " AND c.oid = i.indexrelid"
 
3090
                                                " AND n.oid = c.relnamespace"
 
3091
                                                " AND ia.attrelid = i.indexrelid"
 
3092
                                                " AND ta.attrelid = i.indrelid"
 
3093
                                                " AND ta.attnum = i.indkey[ia.attnum-1]"
 
3094
                                                " AND (NOT ta.attisdropped)"
 
3095
                                                " AND (NOT ia.attisdropped)"
 
3096
                                                " order by ia.attnum", pktab, pkscm);
 
3097
                                else
 
3098
                                        sprintf(tables_query, "select ta.attname, ia.attnum"
 
3099
                                                " from pg_attribute ta, pg_attribute ia, pg_class c, pg_index i"
 
3100
                                                " where c.relname = '%s_pkey'"
 
3101
                                                " AND c.oid = i.indexrelid"
 
3102
                                                " AND ia.attrelid = i.indexrelid"
 
3103
                                                " AND ta.attrelid = i.indrelid"
 
3104
                                                " AND ta.attnum = i.indkey[ia.attnum-1]"
 
3105
                                                " order by ia.attnum", pktab);
 
3106
                                break;
 
3107
                }
 
3108
                mylog("%s: tables_query='%s'\n", func, tables_query);
 
3109
 
 
3110
                result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query));
 
3111
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
3112
                {
 
3113
                        SC_full_error_copy(stmt, tbl_stmt);
 
3114
                        SC_log_error(func, "", stmt);
 
3115
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3116
                        return SQL_ERROR;
 
3117
                }
 
3118
 
 
3119
                result = PGAPI_Fetch(htbl_stmt);
 
3120
                if (result != SQL_NO_DATA_FOUND)
 
3121
                        break;
 
3122
        }
 
3123
 
 
3124
        while ((result == SQL_SUCCESS) || (result == SQL_SUCCESS_WITH_INFO))
 
3125
        {
 
3126
                row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
 
3127
 
 
3128
                set_tuplefield_null(&row->tuple[0]);
 
3129
 
 
3130
                /*
 
3131
                 * I have to hide the table owner from Access, otherwise it
 
3132
                 * insists on referring to the table as 'owner.table'. (this is
 
3133
                 * valid according to the ODBC SQL grammar, but Postgres won't
 
3134
                 * support it.)
 
3135
                 */
 
3136
                set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(pkscm));
 
3137
                set_tuplefield_string(&row->tuple[2], pktab);
 
3138
                set_tuplefield_string(&row->tuple[3], attname);
 
3139
                set_tuplefield_int2(&row->tuple[4], (Int2) (++seq));
 
3140
                set_tuplefield_null(&row->tuple[5]);
 
3141
 
 
3142
                QR_add_tuple(res, row);
 
3143
 
 
3144
                mylog(">> primaryKeys: pktab = '%s', attname = '%s', seq = %d\n", pktab, attname, seq);
 
3145
 
 
3146
                result = PGAPI_Fetch(htbl_stmt);
 
3147
        }
 
3148
 
 
3149
        if (result != SQL_NO_DATA_FOUND)
 
3150
        {
 
3151
                SC_full_error_copy(stmt, htbl_stmt);
 
3152
                SC_log_error(func, "", stmt);
 
3153
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3154
                return SQL_ERROR;
 
3155
        }
 
3156
 
 
3157
        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3158
 
 
3159
 
 
3160
        /*
 
3161
         * also, things need to think that this statement is finished so the
 
3162
         * results can be retrieved.
 
3163
         */
 
3164
        stmt->status = STMT_FINISHED;
 
3165
 
 
3166
        /* set up the current tuple pointer for SQLFetch */
 
3167
        stmt->currTuple = -1;
 
3168
        stmt->rowset_start = -1;
 
3169
        stmt->current_col = -1;
 
3170
 
 
3171
        mylog("%s: EXIT, stmt=%u\n", func, stmt);
 
3172
        return SQL_SUCCESS;
 
3173
}
 
3174
 
 
3175
 
 
3176
/*
 
3177
 *      Multibyte support stuff for SQLForeignKeys().
 
3178
 *      There may be much more effective way in the
 
3179
 *      future version. The way is very forcible currently.
 
3180
 */
 
3181
static BOOL
 
3182
isMultibyte(const unsigned char *str)
 
3183
{
 
3184
        for (; *str; str++)
 
3185
        {
 
3186
                if (*str >= 0x80)
 
3187
                        return TRUE;
 
3188
        }
 
3189
        return FALSE;
 
3190
}
 
3191
#ifdef NOT_USED
 
3192
static char *
 
3193
getClientTableName(ConnectionClass *conn, const char *serverSchemaName, char *serverTableName, BOOL *nameAlloced)
 
3194
{
 
3195
        char            query[1024],
 
3196
                                saveoid[24],
 
3197
                           *ret = serverTableName;
 
3198
        BOOL            continueExec = TRUE,
 
3199
                                bError = FALSE;
 
3200
        QResultClass *res;
 
3201
 
 
3202
        *nameAlloced = FALSE;
 
3203
        if (!conn->client_encoding || !isMultibyte(serverTableName))
 
3204
                return ret;
 
3205
        if (!conn->server_encoding)
 
3206
        {
 
3207
                if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, CLEAR_RESULT_ON_ABORT), res)
 
3208
                {
 
3209
                        if (QR_get_num_tuples(res) > 0)
 
3210
                                conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
 
3211
                        QR_Destructor(res);
 
3212
                }
 
3213
        }
 
3214
        if (!conn->server_encoding)
 
3215
                return ret;
 
3216
        sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
 
3217
        bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
 
3218
        if (!bError && continueExec)
 
3219
        {
 
3220
                if (conn->schema_support)
 
3221
                        sprintf(query, "select OID from pg_catalog.pg_class,"
 
3222
                        " pg_catalog.pg_namespace"
 
3223
                        " where relname = '%s' and pg_namespace.oid = relnamespace and"
 
3224
                        " pg_namespace.nspname = '%s'", serverTableName, serverSchemaName);
 
3225
                else
 
3226
                        sprintf(query, "select OID from pg_class where relname = '%s'", serverTableName);
 
3227
                if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
 
3228
                {
 
3229
                        if (QR_get_num_tuples(res) > 0)
 
3230
                                strcpy(saveoid, QR_get_value_backend_row(res, 0, 0));
 
3231
                        else
 
3232
                                continueExec = FALSE;
 
3233
                        QR_Destructor(res);
 
3234
                }
 
3235
                else
 
3236
                        bError = TRUE;
 
3237
        }
 
3238
        continueExec = (continueExec && !bError);
 
3239
        if (bError && CC_is_in_trans(conn))
 
3240
        {
 
3241
                CC_abort(conn);
 
3242
                bError = FALSE;
 
3243
        }
 
3244
        /* restore the client encoding */
 
3245
        sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding);
 
3246
        bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
 
3247
        if (bError || !continueExec)
 
3248
                return ret;
 
3249
        sprintf(query, "select relname from pg_class where OID = %s", saveoid);
 
3250
        if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
 
3251
        {
 
3252
                if (QR_get_num_tuples(res) > 0)
 
3253
                {
 
3254
                        ret = strdup(QR_get_value_backend_row(res, 0, 0));
 
3255
                        *nameAlloced = TRUE;
 
3256
                }
 
3257
                QR_Destructor(res);
 
3258
        }
 
3259
        return ret;
 
3260
}
 
3261
static char *
 
3262
getClientColumnName(ConnectionClass *conn, const char * serverSchemaName, const char *serverTableName, char *serverColumnName, BOOL *nameAlloced)
 
3263
{
 
3264
        char            query[1024],
 
3265
                                saveattrelid[24],
 
3266
                                saveattnum[16],
 
3267
                           *ret = serverColumnName;
 
3268
        BOOL            continueExec = TRUE,
 
3269
                                bError = FALSE;
 
3270
        QResultClass *res;
 
3271
 
 
3272
        *nameAlloced = FALSE;
 
3273
        if (!conn->client_encoding || !isMultibyte(serverColumnName))
 
3274
                return ret;
 
3275
        if (!conn->server_encoding)
 
3276
        {
 
3277
                if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, CLEAR_RESULT_ON_ABORT), res)
 
3278
                {
 
3279
                        if (QR_get_num_tuples(res) > 0)
 
3280
                                conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
 
3281
                        QR_Destructor(res);
 
3282
                }
 
3283
        }
 
3284
        if (!conn->server_encoding)
 
3285
                return ret;
 
3286
        sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
 
3287
        bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
 
3288
        if (!bError && continueExec)
 
3289
        {
 
3290
                if (conn->schema_support)
 
3291
                        sprintf(query, "select attrelid, attnum from pg_catalog.pg_class,"
 
3292
                        " pg_catalog.pg_attribute, pg_catalog.pg_namespace "
 
3293
                                "where relname = '%s' and attrelid = pg_class.oid "
 
3294
                                "and (not attisdropped) "
 
3295
                                "and attname = '%s' and pg_namespace.oid = relnamespace and"
 
3296
                                " pg_namespace.nspname = '%s'", serverTableName, serverColumnName, serverSchemaName);
 
3297
                else
 
3298
                        sprintf(query, "select attrelid, attnum from pg_class, pg_attribute "
 
3299
                                "where relname = '%s' and attrelid = pg_class.oid "
 
3300
                                "and attname = '%s'", serverTableName, serverColumnName);
 
3301
                if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
 
3302
                {
 
3303
                        if (QR_get_num_tuples(res) > 0)
 
3304
                        {
 
3305
                                strcpy(saveattrelid, QR_get_value_backend_row(res, 0, 0));
 
3306
                                strcpy(saveattnum, QR_get_value_backend_row(res, 0, 1));
 
3307
                        }
 
3308
                        else
 
3309
                                continueExec = FALSE;
 
3310
                        QR_Destructor(res);
 
3311
                }
 
3312
                else
 
3313
                        bError = TRUE;
 
3314
        }
 
3315
        continueExec = (continueExec && !bError);
 
3316
        if (bError && CC_is_in_trans(conn))
 
3317
        {
 
3318
                CC_abort(conn);
 
3319
                bError = FALSE;
 
3320
        }
 
3321
        /* restore the cleint encoding */
 
3322
        sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding);
 
3323
        bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
 
3324
        if (bError || !continueExec)
 
3325
                return ret;
 
3326
        sprintf(query, "select attname from pg_attribute where attrelid = %s and attnum = %s", saveattrelid, saveattnum);
 
3327
        if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
 
3328
        {
 
3329
                if (QR_get_num_tuples(res) > 0)
 
3330
                {
 
3331
                        ret = strdup(QR_get_value_backend_row(res, 0, 0));
 
3332
                        *nameAlloced = TRUE;
 
3333
                }
 
3334
                QR_Destructor(res);
 
3335
        }
 
3336
        return ret;
 
3337
}
 
3338
#endif /* NOT_USED */
 
3339
static char *
 
3340
getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName, BOOL *nameAlloced)
 
3341
{
 
3342
        char            query[1024], saveattnum[16],
 
3343
                           *ret = serverColumnName;
 
3344
        BOOL            continueExec = TRUE,
 
3345
                                bError = FALSE;
 
3346
        QResultClass *res;
 
3347
 
 
3348
        *nameAlloced = FALSE;
 
3349
        if (!conn->client_encoding || !isMultibyte(serverColumnName))
 
3350
                return ret;
 
3351
        if (!conn->server_encoding)
 
3352
        {
 
3353
                if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, CLEAR_RESULT_ON_ABORT), res)
 
3354
                {
 
3355
                        if (QR_get_num_backend_tuples(res) > 0)
 
3356
                                conn->server_encoding = strdup(QR_get_value_backend_row(res, 0, 0));
 
3357
                        QR_Destructor(res);
 
3358
                }
 
3359
        }
 
3360
        if (!conn->server_encoding)
 
3361
                return ret;
 
3362
        sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
 
3363
        bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
 
3364
        if (!bError && continueExec)
 
3365
        {
 
3366
                sprintf(query, "select attnum from pg_attribute "
 
3367
                        "where attrelid = %u and attname = '%s'",
 
3368
                        relid, serverColumnName);
 
3369
                if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
 
3370
                {
 
3371
                        if (QR_get_num_backend_tuples(res) > 0)
 
3372
                        {
 
3373
                                strcpy(saveattnum, QR_get_value_backend_row(res, 0, 0));
 
3374
                        }
 
3375
                        else
 
3376
                                continueExec = FALSE;
 
3377
                        QR_Destructor(res);
 
3378
                }
 
3379
                else
 
3380
                        bError = TRUE;
 
3381
        }
 
3382
        continueExec = (continueExec && !bError);
 
3383
        if (bError && CC_is_in_trans(conn))
 
3384
        {
 
3385
                CC_abort(conn);
 
3386
                bError = FALSE;
 
3387
        }
 
3388
        /* restore the cleint encoding */
 
3389
        sprintf(query, "SET CLIENT_ENCODING TO '%s'", conn->client_encoding);
 
3390
        bError = (CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT) == NULL);
 
3391
        if (bError || !continueExec)
 
3392
                return ret;
 
3393
        sprintf(query, "select attname from pg_attribute where attrelid = %u and attnum = %s", relid, saveattnum);
 
3394
        if (res = CC_send_query(conn, query, NULL, CLEAR_RESULT_ON_ABORT), res)
 
3395
        {
 
3396
                if (QR_get_num_backend_tuples(res) > 0)
 
3397
                {
 
3398
                        ret = strdup(QR_get_value_backend_row(res, 0, 0));
 
3399
                        *nameAlloced = TRUE;
 
3400
                }
 
3401
                QR_Destructor(res);
 
3402
        }
 
3403
        return ret;
 
3404
}
 
3405
 
 
3406
RETCODE         SQL_API
 
3407
PGAPI_ForeignKeys(
 
3408
                                  HSTMT hstmt,
 
3409
                                  UCHAR FAR * szPkTableQualifier,
 
3410
                                  SWORD cbPkTableQualifier,
 
3411
                                  UCHAR FAR * szPkTableOwner,
 
3412
                                  SWORD cbPkTableOwner,
 
3413
                                  UCHAR FAR * szPkTableName,
 
3414
                                  SWORD cbPkTableName,
 
3415
                                  UCHAR FAR * szFkTableQualifier,
 
3416
                                  SWORD cbFkTableQualifier,
 
3417
                                  UCHAR FAR * szFkTableOwner,
 
3418
                                  SWORD cbFkTableOwner,
 
3419
                                  UCHAR FAR * szFkTableName,
 
3420
                                  SWORD cbFkTableName)
 
3421
{
 
3422
        CSTR func = "PGAPI_ForeignKeys";
 
3423
        StatementClass *stmt = (StatementClass *) hstmt;
 
3424
        QResultClass    *res;
 
3425
        TupleNode  *row;
 
3426
        HSTMT           htbl_stmt,
 
3427
                                hpkey_stmt;
 
3428
        StatementClass *tbl_stmt;
 
3429
        RETCODE         result,
 
3430
                                keyresult;
 
3431
        char            tables_query[INFO_INQUIRY_LEN];
 
3432
        char            trig_deferrable[2];
 
3433
        char            trig_initdeferred[2];
 
3434
        char            trig_args[1024];
 
3435
        char            upd_rule[TABLE_NAME_STORAGE_LEN],
 
3436
                                del_rule[TABLE_NAME_STORAGE_LEN];
 
3437
        char            pk_table_needed[TABLE_NAME_STORAGE_LEN + 1];
 
3438
char            fk_table_fetched[TABLE_NAME_STORAGE_LEN + 1];
 
3439
        char            fk_table_needed[TABLE_NAME_STORAGE_LEN + 1];
 
3440
char            pk_table_fetched[TABLE_NAME_STORAGE_LEN + 1];
 
3441
        char            schema_needed[SCHEMA_NAME_STORAGE_LEN + 1];
 
3442
char            schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1];
 
3443
        char       *pkey_ptr,
 
3444
                           *pkey_text,
 
3445
                           *fkey_ptr,
 
3446
                           *fkey_text;
 
3447
 
 
3448
        ConnectionClass *conn;
 
3449
        BOOL            pkey_alloced,
 
3450
                                fkey_alloced;
 
3451
        int                     i,
 
3452
                                j,
 
3453
                                k,
 
3454
                                num_keys;
 
3455
        SWORD           trig_nargs,
 
3456
                                upd_rule_type = 0,
 
3457
                                del_rule_type = 0;
 
3458
        SWORD           internal_asis_type = SQL_C_CHAR;
 
3459
 
 
3460
#if (ODBCVER >= 0x0300)
 
3461
        SWORD           defer_type;
 
3462
#endif
 
3463
        char            pkey[MAX_INFO_STRING];
 
3464
        Int2            result_cols;
 
3465
        UInt4           relid1, relid2;
 
3466
 
 
3467
        mylog("%s: entering...stmt=%u\n", func, stmt);
 
3468
 
 
3469
        if (!stmt)
 
3470
        {
 
3471
                SC_log_error(func, "", NULL);
 
3472
                return SQL_INVALID_HANDLE;
 
3473
        }
 
3474
 
 
3475
        stmt->manual_result = TRUE;
 
3476
        stmt->errormsg_created = TRUE;
 
3477
 
 
3478
        if (res = QR_Constructor(), !res)
 
3479
        {
 
3480
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_ForeignKeys result.");
 
3481
                SC_log_error(func, "", stmt);
 
3482
                return SQL_ERROR;
 
3483
        }
 
3484
        SC_set_Result(stmt, res);
 
3485
 
 
3486
        /* the binding structure for a statement is not set up until */
 
3487
 
 
3488
        /*
 
3489
         * a statement is actually executed, so we'll have to do this
 
3490
         * ourselves.
 
3491
         */
 
3492
#if (ODBCVER >= 0x0300)
 
3493
        result_cols = 15;
 
3494
#else
 
3495
        result_cols = 14;
 
3496
#endif /* ODBCVER */
 
3497
        extend_column_bindings(SC_get_ARD(stmt), result_cols);
 
3498
 
 
3499
        /* set the field names */
 
3500
        QR_set_num_fields(res, result_cols);
 
3501
        QR_set_field_info(res, 0, "PKTABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3502
        QR_set_field_info(res, 1, "PKTABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3503
        QR_set_field_info(res, 2, "PKTABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3504
        QR_set_field_info(res, 3, "PKCOLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3505
        QR_set_field_info(res, 4, "FKTABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3506
        QR_set_field_info(res, 5, "FKTABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3507
        QR_set_field_info(res, 6, "FKTABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3508
        QR_set_field_info(res, 7, "FKCOLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3509
        QR_set_field_info(res, 8, "KEY_SEQ", PG_TYPE_INT2, 2);
 
3510
        QR_set_field_info(res, 9, "UPDATE_RULE", PG_TYPE_INT2, 2);
 
3511
        QR_set_field_info(res, 10, "DELETE_RULE", PG_TYPE_INT2, 2);
 
3512
        QR_set_field_info(res, 11, "FK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3513
        QR_set_field_info(res, 12, "PK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3514
        QR_set_field_info(res, 13, "TRIGGER_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3515
#if (ODBCVER >= 0x0300)
 
3516
        QR_set_field_info(res, 14, "DEFERRABILITY", PG_TYPE_INT2, 2);
 
3517
#endif   /* ODBCVER >= 0x0300 */
 
3518
 
 
3519
        /*
 
3520
         * also, things need to think that this statement is finished so the
 
3521
         * results can be retrieved.
 
3522
         */
 
3523
        stmt->status = STMT_FINISHED;
 
3524
 
 
3525
        /* set up the current tuple pointer for SQLFetch */
 
3526
        stmt->currTuple = -1;
 
3527
        stmt->rowset_start = -1;
 
3528
        stmt->current_col = -1;
 
3529
 
 
3530
 
 
3531
        result = PGAPI_AllocStmt(stmt->hdbc, &htbl_stmt);
 
3532
        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
3533
        {
 
3534
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys result.");
 
3535
                SC_log_error(func, "", stmt);
 
3536
                return SQL_ERROR;
 
3537
        }
 
3538
 
 
3539
        tbl_stmt = (StatementClass *) htbl_stmt;
 
3540
 
 
3541
        pk_table_needed[0] = '\0';
 
3542
        fk_table_needed[0] = '\0';
 
3543
        schema_needed[0] = '\0';
 
3544
        schema_fetched[0] = '\0';
 
3545
 
 
3546
        make_string(szPkTableName, cbPkTableName, pk_table_needed);
 
3547
        make_string(szFkTableName, cbFkTableName, fk_table_needed);
 
3548
 
 
3549
        conn = SC_get_conn(stmt);
 
3550
#ifdef  UNICODE_SUPPORT
 
3551
        if (conn->unicode)
 
3552
                internal_asis_type = INTERNAL_ASIS_TYPE;
 
3553
#endif /* UNICODE_SUPPORT */
 
3554
        pkey_text = fkey_text = NULL;
 
3555
        pkey_alloced = fkey_alloced = FALSE;
 
3556
 
 
3557
        /*
 
3558
         * Case #2 -- Get the foreign keys in the specified table (fktab) that
 
3559
         * refer to the primary keys of other table(s).
 
3560
         */
 
3561
        if (fk_table_needed[0] != '\0')
 
3562
        {
 
3563
                mylog("%s: entering Foreign Key Case #2", func);
 
3564
                if (conn->schema_support)
 
3565
                {
 
3566
                        schema_strcat(schema_needed, "%.*s", szFkTableOwner, cbFkTableOwner, szFkTableName, cbFkTableName, conn);
 
3567
                        sprintf(tables_query, "SELECT   pt.tgargs, "
 
3568
                                "               pt.tgnargs, "
 
3569
                                "               pt.tgdeferrable, "
 
3570
                                "               pt.tginitdeferred, "
 
3571
                                "               pp1.proname, "
 
3572
                                "               pp2.proname, "
 
3573
                                "               pc.oid, "
 
3574
                                "               pc1.oid, "
 
3575
                                "               pc1.relname, "
 
3576
                                "               pn.nspname "
 
3577
                                "FROM   pg_catalog.pg_class pc, "
 
3578
                                "               pg_catalog.pg_proc pp1, "
 
3579
                                "               pg_catalog.pg_proc pp2, "
 
3580
                                "               pg_catalog.pg_trigger pt1, "
 
3581
                                "               pg_catalog.pg_trigger pt2, "
 
3582
                                "               pg_catalog.pg_proc pp, "
 
3583
                                "               pg_catalog.pg_trigger pt, "
 
3584
                                "               pg_catalog.pg_class pc1, "
 
3585
                                "               pg_catalog.pg_namespace pn, "
 
3586
                                "               pg_catalog.pg_namespace pn1 "
 
3587
                                "WHERE  pt.tgrelid = pc.oid "
 
3588
                                "AND pp.oid = pt.tgfoid "
 
3589
                                "AND pt1.tgconstrrelid = pc.oid "
 
3590
                                "AND pp1.oid = pt1.tgfoid "
 
3591
                                "AND pt2.tgfoid = pp2.oid "
 
3592
                                "AND pt2.tgconstrrelid = pc.oid "
 
3593
                                "AND ((pc.relname='%s') "
 
3594
                                "AND (pn1.oid = pc.relnamespace) "
 
3595
                                "AND (pn1.nspname = '%s') "
 
3596
                                "AND (pp.proname LIKE '%%ins') "
 
3597
                                "AND (pp1.proname LIKE '%%upd') "
 
3598
                                "AND (pp2.proname LIKE '%%del') "
 
3599
                                "AND (pt1.tgrelid=pt.tgconstrrelid) "
 
3600
                                "AND (pt1.tgconstrname=pt.tgconstrname) "
 
3601
                                "AND (pt2.tgrelid=pt.tgconstrrelid) "
 
3602
                                "AND (pt2.tgconstrname=pt.tgconstrname) "
 
3603
                                "AND (pt.tgconstrrelid=pc1.oid) "
 
3604
                                "AND (pc1.relnamespace=pn.oid))",
 
3605
                                fk_table_needed, schema_needed);
 
3606
                }
 
3607
                else
 
3608
                        sprintf(tables_query, "SELECT   pt.tgargs, "
 
3609
                                "               pt.tgnargs, "
 
3610
                                "               pt.tgdeferrable, "
 
3611
                                "               pt.tginitdeferred, "
 
3612
                                "               pp1.proname, "
 
3613
                                "               pp2.proname, "
 
3614
                                "               pc.oid, "
 
3615
                                "               pc1.oid, "
 
3616
                                "               pc1.relname "
 
3617
                                "FROM   pg_class pc, "
 
3618
                                "               pg_proc pp1, "
 
3619
                                "               pg_proc pp2, "
 
3620
                                "               pg_trigger pt1, "
 
3621
                                "               pg_trigger pt2, "
 
3622
                                "               pg_proc pp, "
 
3623
                                "               pg_trigger pt, "
 
3624
                                "               pg_class pc1 "
 
3625
                                "WHERE  pt.tgrelid = pc.oid "
 
3626
                                "AND pp.oid = pt.tgfoid "
 
3627
                                "AND pt1.tgconstrrelid = pc.oid "
 
3628
                                "AND pp1.oid = pt1.tgfoid "
 
3629
                                "AND pt2.tgfoid = pp2.oid "
 
3630
                                "AND pt2.tgconstrrelid = pc.oid "
 
3631
                                "AND ((pc.relname='%s') "
 
3632
                                "AND (pp.proname LIKE '%%ins') "
 
3633
                                "AND (pp1.proname LIKE '%%upd') "
 
3634
                                "AND (pp2.proname LIKE '%%del') "
 
3635
                                "AND (pt1.tgrelid=pt.tgconstrrelid) "
 
3636
                                "AND (pt1.tgconstrname=pt.tgconstrname) "
 
3637
                                "AND (pt2.tgrelid=pt.tgconstrrelid) "
 
3638
                                "AND (pt2.tgconstrname=pt.tgconstrname) "
 
3639
                                "AND (pt.tgconstrrelid=pc1.oid)) ",
 
3640
                                fk_table_needed);
 
3641
 
 
3642
                result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query));
 
3643
 
 
3644
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
3645
                {
 
3646
                        SC_full_error_copy(stmt, tbl_stmt);
 
3647
                        SC_log_error(func, "", stmt);
 
3648
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3649
                        return SQL_ERROR;
 
3650
                }
 
3651
 
 
3652
                result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_BINARY,
 
3653
                                                           trig_args, sizeof(trig_args), NULL);
 
3654
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
3655
                {
 
3656
                        SC_error_copy(stmt, tbl_stmt);
 
3657
                        SC_log_error(func, "", stmt);
 
3658
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3659
                        return SQL_ERROR;
 
3660
                }
 
3661
 
 
3662
                result = PGAPI_BindCol(htbl_stmt, 2, SQL_C_SHORT,
 
3663
                                                           &trig_nargs, 0, NULL);
 
3664
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
3665
                {
 
3666
                        SC_error_copy(stmt, tbl_stmt);
 
3667
                        SC_log_error(func, "", stmt);
 
3668
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3669
                        return SQL_ERROR;
 
3670
                }
 
3671
 
 
3672
                result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
 
3673
                                                 trig_deferrable, sizeof(trig_deferrable), NULL);
 
3674
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
3675
                {
 
3676
                        SC_error_copy(stmt, tbl_stmt);
 
3677
                        SC_log_error(func, "", stmt);
 
3678
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3679
                        return SQL_ERROR;
 
3680
                }
 
3681
 
 
3682
                result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type,
 
3683
                                         trig_initdeferred, sizeof(trig_initdeferred), NULL);
 
3684
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
3685
                {
 
3686
                        SC_error_copy(stmt, tbl_stmt);
 
3687
                        SC_log_error(func, "", stmt);
 
3688
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3689
                        return SQL_ERROR;
 
3690
                }
 
3691
 
 
3692
                result = PGAPI_BindCol(htbl_stmt, 5, internal_asis_type,
 
3693
                                                           upd_rule, sizeof(upd_rule), NULL);
 
3694
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
3695
                {
 
3696
                        SC_error_copy(stmt, tbl_stmt);
 
3697
                        SC_log_error(func, "", stmt);
 
3698
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3699
                        return SQL_ERROR;
 
3700
                }
 
3701
 
 
3702
                result = PGAPI_BindCol(htbl_stmt, 6, internal_asis_type,
 
3703
                                                           del_rule, sizeof(del_rule), NULL);
 
3704
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
3705
                {
 
3706
                        SC_error_copy(stmt, tbl_stmt);
 
3707
                        SC_log_error(func, "", stmt);
 
3708
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3709
                        return SQL_ERROR;
 
3710
                }
 
3711
 
 
3712
                result = PGAPI_BindCol(htbl_stmt, 7, SQL_C_ULONG,
 
3713
                                                           &relid1, sizeof(relid1), NULL);
 
3714
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
3715
                {
 
3716
                        SC_error_copy(stmt, tbl_stmt);
 
3717
                        SC_log_error(func, "", stmt);
 
3718
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3719
                        return SQL_ERROR;
 
3720
                }
 
3721
                result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG,
 
3722
                                                           &relid2, sizeof(relid2), NULL);
 
3723
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
3724
                {
 
3725
                        SC_error_copy(stmt, tbl_stmt);
 
3726
                        SC_log_error(func, "", stmt);
 
3727
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3728
                        return SQL_ERROR;
 
3729
                }
 
3730
                result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type,
 
3731
                                        pk_table_fetched, TABLE_NAME_STORAGE_LEN, NULL);
 
3732
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
3733
                {
 
3734
                        SC_error_copy(stmt, tbl_stmt);
 
3735
                        SC_log_error(func, "", stmt);
 
3736
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3737
                        return SQL_ERROR;
 
3738
                }
 
3739
 
 
3740
                if (conn->schema_support)
 
3741
                {
 
3742
                        result = PGAPI_BindCol(htbl_stmt, 10, internal_asis_type,
 
3743
                                        schema_fetched, SCHEMA_NAME_STORAGE_LEN, NULL);
 
3744
                        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
3745
                        {
 
3746
                                SC_error_copy(stmt, tbl_stmt);
 
3747
                                SC_log_error(func, "", stmt);
 
3748
                                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3749
                                return SQL_ERROR;
 
3750
                        }
 
3751
                }
 
3752
 
 
3753
                result = PGAPI_Fetch(htbl_stmt);
 
3754
                if (result == SQL_NO_DATA_FOUND)
 
3755
                        return SQL_SUCCESS;
 
3756
 
 
3757
                if (result != SQL_SUCCESS)
 
3758
                {
 
3759
                        SC_full_error_copy(stmt, tbl_stmt);
 
3760
                        SC_log_error(func, "", stmt);
 
3761
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3762
                        return SQL_ERROR;
 
3763
                }
 
3764
 
 
3765
                keyresult = PGAPI_AllocStmt(stmt->hdbc, &hpkey_stmt);
 
3766
                if ((keyresult != SQL_SUCCESS) && (keyresult != SQL_SUCCESS_WITH_INFO))
 
3767
                {
 
3768
                        SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.");
 
3769
                        SC_log_error(func, "", stmt);
 
3770
                        return SQL_ERROR;
 
3771
                }
 
3772
 
 
3773
                keyresult = PGAPI_BindCol(hpkey_stmt, 4, internal_asis_type,
 
3774
                                                                  pkey, sizeof(pkey), NULL);
 
3775
                if (keyresult != SQL_SUCCESS)
 
3776
                {
 
3777
                        SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.");
 
3778
                        SC_log_error(func, "", stmt);
 
3779
                        PGAPI_FreeStmt(hpkey_stmt, SQL_DROP);
 
3780
                        return SQL_ERROR;
 
3781
                }
 
3782
 
 
3783
                while (result == SQL_SUCCESS)
 
3784
                {
 
3785
                        /* Compute the number of keyparts. */
 
3786
                        num_keys = (trig_nargs - 4) / 2;
 
3787
 
 
3788
                        mylog("Foreign Key Case#2: trig_nargs = %d, num_keys = %d\n", trig_nargs, num_keys);
 
3789
 
 
3790
                        /* If there is a pk table specified, then check it. */
 
3791
                        if (pk_table_needed[0] != '\0')
 
3792
                        {
 
3793
                                /* If it doesn't match, then continue */
 
3794
                                if (strcmp(pk_table_fetched, pk_table_needed))
 
3795
                                {
 
3796
                                        result = PGAPI_Fetch(htbl_stmt);
 
3797
                                        continue;
 
3798
                                }
 
3799
                        }
 
3800
 
 
3801
                        keyresult = PGAPI_PrimaryKeys(hpkey_stmt, NULL, 0, schema_fetched, SQL_NTS, pk_table_fetched, SQL_NTS);
 
3802
                        if (keyresult != SQL_SUCCESS)
 
3803
                        {
 
3804
                                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't get primary keys for PGAPI_ForeignKeys result.");
 
3805
                                SC_log_error(func, "", stmt);
 
3806
                                PGAPI_FreeStmt(hpkey_stmt, SQL_DROP);
 
3807
                                return SQL_ERROR;
 
3808
                        }
 
3809
 
 
3810
 
 
3811
                        /* Get to first primary key */
 
3812
                        pkey_ptr = trig_args;
 
3813
                        for (i = 0; i < 5; i++)
 
3814
                                pkey_ptr += strlen(pkey_ptr) + 1;
 
3815
 
 
3816
                        for (k = 0; k < num_keys; k++)
 
3817
                        {
 
3818
                                /* Check that the key listed is the primary key */
 
3819
                                keyresult = PGAPI_Fetch(hpkey_stmt);
 
3820
                                if (keyresult != SQL_SUCCESS)
 
3821
                                {
 
3822
                                        num_keys = 0;
 
3823
                                        break;
 
3824
                                }
 
3825
                                pkey_text = getClientColumnName(conn, relid2, pkey_ptr, &pkey_alloced);
 
3826
                                mylog("%s: pkey_ptr='%s', pkey='%s'\n", func, pkey_text, pkey);
 
3827
                                if (strcmp(pkey_text, pkey))
 
3828
                                {
 
3829
                                        num_keys = 0;
 
3830
                                        break;
 
3831
                                }
 
3832
                                if (pkey_alloced)
 
3833
                                        free(pkey_text);
 
3834
                                /* Get to next primary key */
 
3835
                                for (k = 0; k < 2; k++)
 
3836
                                        pkey_ptr += strlen(pkey_ptr) + 1;
 
3837
 
 
3838
                        }
 
3839
 
 
3840
                        /* Set to first fk column */
 
3841
                        fkey_ptr = trig_args;
 
3842
                        for (k = 0; k < 4; k++)
 
3843
                                fkey_ptr += strlen(fkey_ptr) + 1;
 
3844
 
 
3845
                        /* Set update and delete actions for foreign keys */
 
3846
                        if (!strcmp(upd_rule, "RI_FKey_cascade_upd"))
 
3847
                                upd_rule_type = SQL_CASCADE;
 
3848
                        else if (!strcmp(upd_rule, "RI_FKey_noaction_upd"))
 
3849
                                upd_rule_type = SQL_NO_ACTION;
 
3850
                        else if (!strcmp(upd_rule, "RI_FKey_restrict_upd"))
 
3851
                                upd_rule_type = SQL_NO_ACTION;
 
3852
                        else if (!strcmp(upd_rule, "RI_FKey_setdefault_upd"))
 
3853
                                upd_rule_type = SQL_SET_DEFAULT;
 
3854
                        else if (!strcmp(upd_rule, "RI_FKey_setnull_upd"))
 
3855
                                upd_rule_type = SQL_SET_NULL;
 
3856
 
 
3857
                        if (!strcmp(upd_rule, "RI_FKey_cascade_del"))
 
3858
                                del_rule_type = SQL_CASCADE;
 
3859
                        else if (!strcmp(upd_rule, "RI_FKey_noaction_del"))
 
3860
                                del_rule_type = SQL_NO_ACTION;
 
3861
                        else if (!strcmp(upd_rule, "RI_FKey_restrict_del"))
 
3862
                                del_rule_type = SQL_NO_ACTION;
 
3863
                        else if (!strcmp(upd_rule, "RI_FKey_setdefault_del"))
 
3864
                                del_rule_type = SQL_SET_DEFAULT;
 
3865
                        else if (!strcmp(upd_rule, "RI_FKey_setnull_del"))
 
3866
                                del_rule_type = SQL_SET_NULL;
 
3867
 
 
3868
#if (ODBCVER >= 0x0300)
 
3869
                        /* Set deferrability type */
 
3870
                        if (!strcmp(trig_initdeferred, "y"))
 
3871
                                defer_type = SQL_INITIALLY_DEFERRED;
 
3872
                        else if (!strcmp(trig_deferrable, "y"))
 
3873
                                defer_type = SQL_INITIALLY_IMMEDIATE;
 
3874
                        else
 
3875
                                defer_type = SQL_NOT_DEFERRABLE;
 
3876
#endif   /* ODBCVER >= 0x0300 */
 
3877
 
 
3878
                        /* Get to first primary key */
 
3879
                        pkey_ptr = trig_args;
 
3880
                        for (i = 0; i < 5; i++)
 
3881
                                pkey_ptr += strlen(pkey_ptr) + 1;
 
3882
 
 
3883
                        for (k = 0; k < num_keys; k++)
 
3884
                        {
 
3885
                                row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
 
3886
 
 
3887
                                pkey_text = getClientColumnName(conn, relid2, pkey_ptr, &pkey_alloced);
 
3888
                                fkey_text = getClientColumnName(conn, relid1, fkey_ptr, &fkey_alloced);
 
3889
 
 
3890
                                mylog("%s: pk_table = '%s', pkey_ptr = '%s'\n", func, pk_table_fetched, pkey_text);
 
3891
                                set_tuplefield_null(&row->tuple[0]);
 
3892
                                set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(schema_fetched));
 
3893
                                set_tuplefield_string(&row->tuple[2], pk_table_fetched);
 
3894
                                set_tuplefield_string(&row->tuple[3], pkey_text);
 
3895
 
 
3896
                                mylog("%s: fk_table_needed = '%s', fkey_ptr = '%s'\n", func, fk_table_needed, fkey_text);
 
3897
                                set_tuplefield_null(&row->tuple[4]);
 
3898
                                set_tuplefield_string(&row->tuple[5], GET_SCHEMA_NAME(schema_needed));
 
3899
                                set_tuplefield_string(&row->tuple[6], fk_table_needed);
 
3900
                                set_tuplefield_string(&row->tuple[7], fkey_text);
 
3901
 
 
3902
                                mylog("%s: upd_rule_type = '%i', del_rule_type = '%i'\n, trig_name = '%s'", func, upd_rule_type, del_rule_type, trig_args);
 
3903
                                set_tuplefield_int2(&row->tuple[8], (Int2) (k + 1));
 
3904
                                set_tuplefield_int2(&row->tuple[9], (Int2) upd_rule_type);
 
3905
                                set_tuplefield_int2(&row->tuple[10], (Int2) del_rule_type);
 
3906
                                set_tuplefield_null(&row->tuple[11]);
 
3907
                                set_tuplefield_null(&row->tuple[12]);
 
3908
                                set_tuplefield_string(&row->tuple[13], trig_args);
 
3909
#if (ODBCVER >= 0x0300)
 
3910
                                set_tuplefield_int2(&row->tuple[14], defer_type);
 
3911
#endif   /* ODBCVER >= 0x0300 */
 
3912
 
 
3913
                                QR_add_tuple(res, row);
 
3914
                                if (fkey_alloced)
 
3915
                                        free(fkey_text);
 
3916
                                fkey_alloced = FALSE;
 
3917
                                if (pkey_alloced)
 
3918
                                        free(pkey_text);
 
3919
                                pkey_alloced = FALSE;
 
3920
                                /* next primary/foreign key */
 
3921
                                for (i = 0; i < 2; i++)
 
3922
                                {
 
3923
                                        fkey_ptr += strlen(fkey_ptr) + 1;
 
3924
                                        pkey_ptr += strlen(pkey_ptr) + 1;
 
3925
                                }
 
3926
                        }
 
3927
 
 
3928
                        result = PGAPI_Fetch(htbl_stmt);
 
3929
                }
 
3930
                PGAPI_FreeStmt(hpkey_stmt, SQL_DROP);
 
3931
        }
 
3932
 
 
3933
        /*
 
3934
         * Case #1 -- Get the foreign keys in other tables that refer to the
 
3935
         * primary key in the specified table (pktab).  i.e., Who points to
 
3936
         * me?
 
3937
         */
 
3938
        else if (pk_table_needed[0] != '\0')
 
3939
        {
 
3940
                if (conn->schema_support)
 
3941
                {
 
3942
                        schema_strcat(schema_needed, "%.*s", szPkTableOwner, cbPkTableOwner, szPkTableName, cbPkTableName, conn);
 
3943
                        sprintf(tables_query, "SELECT   pt.tgargs, "
 
3944
                                "               pt.tgnargs, "
 
3945
                                "               pt.tgdeferrable, "
 
3946
                                "               pt.tginitdeferred, "
 
3947
                                "               pp.proname, "
 
3948
                                "               pp1.proname, "
 
3949
                                "               pc.oid, "
 
3950
                                "               pc1.oid, "
 
3951
                                "               pc1.relname, "
 
3952
                                "               pn.nspname "
 
3953
                                "FROM   pg_catalog.pg_class pc, "
 
3954
                                "               pg_catalog.pg_class pc1, "
 
3955
                                "               pg_catalog.pg_class pc2, "
 
3956
                                "               pg_catalog.pg_proc pp, "
 
3957
                                "               pg_catalog.pg_proc pp1, "
 
3958
                                "               pg_catalog.pg_trigger pt, "
 
3959
                                "               pg_catalog.pg_trigger pt1, "
 
3960
                                "               pg_catalog.pg_trigger pt2, "
 
3961
                                "               pg_catalog.pg_namespace pn, "
 
3962
                                "               pg_catalog.pg_namespace pn1 "
 
3963
                                "WHERE  pt.tgconstrrelid = pc.oid "
 
3964
                                "       AND pt.tgrelid = pc1.oid "
 
3965
                                "       AND pt1.tgfoid = pp1.oid "
 
3966
                                "       AND pt1.tgconstrrelid = pc1.oid "
 
3967
                                "       AND pt2.tgconstrrelid = pc2.oid "
 
3968
                                "       AND pt2.tgfoid = pp.oid "
 
3969
                                "       AND pc2.oid = pt.tgrelid "
 
3970
                                "       AND ("
 
3971
                                "                (pc.relname='%s') "
 
3972
                                "       AND  (pn1.oid = pc.relnamespace) "
 
3973
                                "       AND  (pn1.nspname = '%s') "
 
3974
                                "       AND  (pp.proname Like '%%upd') "
 
3975
                                "       AND  (pp1.proname Like '%%del')"
 
3976
                                "       AND      (pt1.tgrelid = pt.tgconstrrelid) "
 
3977
                                "       AND      (pt2.tgrelid = pt.tgconstrrelid) "
 
3978
                                "       AND (pn.oid = pc1.relnamespace) "
 
3979
                                "               )",
 
3980
                                pk_table_needed, schema_needed);
 
3981
                }
 
3982
                else
 
3983
                        sprintf(tables_query, "SELECT   pt.tgargs, "
 
3984
                                "               pt.tgnargs, "
 
3985
                                "               pt.tgdeferrable, "
 
3986
                                "               pt.tginitdeferred, "
 
3987
                                "               pp.proname, "
 
3988
                                "               pp1.proname, "
 
3989
                                "               pc.oid, "
 
3990
                                "               pc1.oid, "
 
3991
                                "               pc1.relname "
 
3992
                                "FROM   pg_class pc, "
 
3993
                                "               pg_class pc1, "
 
3994
                                "               pg_class pc2, "
 
3995
                                "               pg_proc pp, "
 
3996
                                "               pg_proc pp1, "
 
3997
                                "               pg_trigger pt, "
 
3998
                                "               pg_trigger pt1, "
 
3999
                                "               pg_trigger pt2 "
 
4000
                                "WHERE  pt.tgconstrrelid = pc.oid "
 
4001
                                "       AND pt.tgrelid = pc1.oid "
 
4002
                                "       AND pt1.tgfoid = pp1.oid "
 
4003
                                "       AND pt1.tgconstrrelid = pc1.oid "
 
4004
                                "       AND pt2.tgconstrrelid = pc2.oid "
 
4005
                                "       AND pt2.tgfoid = pp.oid "
 
4006
                                "       AND pc2.oid = pt.tgrelid "
 
4007
                                "       AND ("
 
4008
                                "                (pc.relname='%s') "
 
4009
                                "       AND  (pp.proname Like '%%upd') "
 
4010
                                "       AND  (pp1.proname Like '%%del')"
 
4011
                                "       AND      (pt1.tgrelid = pt.tgconstrrelid) "
 
4012
                                "       AND      (pt2.tgrelid = pt.tgconstrrelid) "
 
4013
                                "               )",
 
4014
                                pk_table_needed);
 
4015
 
 
4016
                result = PGAPI_ExecDirect(htbl_stmt, tables_query, strlen(tables_query));
 
4017
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
4018
                {
 
4019
                        SC_error_copy(stmt, tbl_stmt);
 
4020
                        SC_log_error(func, "", stmt);
 
4021
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
4022
                        return SQL_ERROR;
 
4023
                }
 
4024
 
 
4025
                result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_BINARY,
 
4026
                                                           trig_args, sizeof(trig_args), NULL);
 
4027
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
4028
                {
 
4029
                        SC_error_copy(stmt, tbl_stmt);
 
4030
                        SC_log_error(func, "", stmt);
 
4031
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
4032
                        return SQL_ERROR;
 
4033
                }
 
4034
 
 
4035
                result = PGAPI_BindCol(htbl_stmt, 2, SQL_C_SHORT,
 
4036
                                                           &trig_nargs, 0, NULL);
 
4037
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
4038
                {
 
4039
                        SC_error_copy(stmt, tbl_stmt);
 
4040
                        SC_log_error(func, "", stmt);
 
4041
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
4042
                        return SQL_ERROR;
 
4043
                }
 
4044
 
 
4045
                result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
 
4046
                                                 trig_deferrable, sizeof(trig_deferrable), NULL);
 
4047
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
4048
                {
 
4049
                        SC_error_copy(stmt, tbl_stmt);
 
4050
                        SC_log_error(func, "", stmt);
 
4051
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
4052
                        return SQL_ERROR;
 
4053
                }
 
4054
 
 
4055
                result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type,
 
4056
                                         trig_initdeferred, sizeof(trig_initdeferred), NULL);
 
4057
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
4058
                {
 
4059
                        SC_error_copy(stmt, tbl_stmt);
 
4060
                        SC_log_error(func, "", stmt);
 
4061
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
4062
                        return SQL_ERROR;
 
4063
                }
 
4064
 
 
4065
                result = PGAPI_BindCol(htbl_stmt, 5, internal_asis_type,
 
4066
                                                           upd_rule, sizeof(upd_rule), NULL);
 
4067
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
4068
                {
 
4069
                        SC_error_copy(stmt, tbl_stmt);
 
4070
                        SC_log_error(func, "", stmt);
 
4071
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
4072
                        return SQL_ERROR;
 
4073
                }
 
4074
 
 
4075
                result = PGAPI_BindCol(htbl_stmt, 6, internal_asis_type,
 
4076
                                                           del_rule, sizeof(del_rule), NULL);
 
4077
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
4078
                {
 
4079
                        SC_error_copy(stmt, tbl_stmt);
 
4080
                        SC_log_error(func, "", stmt);
 
4081
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
4082
                        return SQL_ERROR;
 
4083
                }
 
4084
 
 
4085
                result = PGAPI_BindCol(htbl_stmt, 7, SQL_C_ULONG,
 
4086
                                                &relid1, sizeof(relid1), NULL);
 
4087
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
4088
                {
 
4089
                        SC_error_copy(stmt, tbl_stmt);
 
4090
                        SC_log_error(func, "", stmt);
 
4091
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
4092
                        return SQL_ERROR;
 
4093
                }
 
4094
                result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG,
 
4095
                                                &relid2, sizeof(relid2), NULL);
 
4096
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
4097
                {
 
4098
                        SC_error_copy(stmt, tbl_stmt);
 
4099
                        SC_log_error(func, "", stmt);
 
4100
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
4101
                        return SQL_ERROR;
 
4102
                }
 
4103
                result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type,
 
4104
                                        fk_table_fetched, TABLE_NAME_STORAGE_LEN, NULL);
 
4105
                if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
4106
                {
 
4107
                        SC_error_copy(stmt, tbl_stmt);
 
4108
                        SC_log_error(func, "", stmt);
 
4109
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
4110
                        return SQL_ERROR;
 
4111
                }
 
4112
 
 
4113
                if (conn->schema_support)
 
4114
                {
 
4115
                        result = PGAPI_BindCol(htbl_stmt, 10, internal_asis_type,
 
4116
                                        schema_fetched, SCHEMA_NAME_STORAGE_LEN, NULL);
 
4117
                        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
4118
                        {
 
4119
                                SC_error_copy(stmt, tbl_stmt);
 
4120
                                SC_log_error(func, "", stmt);
 
4121
                                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
4122
                                return SQL_ERROR;
 
4123
                        }
 
4124
                }
 
4125
 
 
4126
                result = PGAPI_Fetch(htbl_stmt);
 
4127
                if (result == SQL_NO_DATA_FOUND)
 
4128
                        return SQL_SUCCESS;
 
4129
 
 
4130
                if (result != SQL_SUCCESS)
 
4131
                {
 
4132
                        SC_full_error_copy(stmt, tbl_stmt);
 
4133
                        SC_log_error(func, "", stmt);
 
4134
                        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
4135
                        return SQL_ERROR;
 
4136
                }
 
4137
 
 
4138
                while (result == SQL_SUCCESS)
 
4139
                {
 
4140
                        /* Calculate the number of key parts */
 
4141
                        num_keys = (trig_nargs - 4) / 2;;
 
4142
 
 
4143
                        /* Handle action (i.e., 'cascade', 'restrict', 'setnull') */
 
4144
                        if (!strcmp(upd_rule, "RI_FKey_cascade_upd"))
 
4145
                                upd_rule_type = SQL_CASCADE;
 
4146
                        else if (!strcmp(upd_rule, "RI_FKey_noaction_upd"))
 
4147
                                upd_rule_type = SQL_NO_ACTION;
 
4148
                        else if (!strcmp(upd_rule, "RI_FKey_restrict_upd"))
 
4149
                                upd_rule_type = SQL_NO_ACTION;
 
4150
                        else if (!strcmp(upd_rule, "RI_FKey_setdefault_upd"))
 
4151
                                upd_rule_type = SQL_SET_DEFAULT;
 
4152
                        else if (!strcmp(upd_rule, "RI_FKey_setnull_upd"))
 
4153
                                upd_rule_type = SQL_SET_NULL;
 
4154
 
 
4155
                        if (!strcmp(upd_rule, "RI_FKey_cascade_del"))
 
4156
                                del_rule_type = SQL_CASCADE;
 
4157
                        else if (!strcmp(upd_rule, "RI_FKey_noaction_del"))
 
4158
                                del_rule_type = SQL_NO_ACTION;
 
4159
                        else if (!strcmp(upd_rule, "RI_FKey_restrict_del"))
 
4160
                                del_rule_type = SQL_NO_ACTION;
 
4161
                        else if (!strcmp(upd_rule, "RI_FKey_setdefault_del"))
 
4162
                                del_rule_type = SQL_SET_DEFAULT;
 
4163
                        else if (!strcmp(upd_rule, "RI_FKey_setnull_del"))
 
4164
                                del_rule_type = SQL_SET_NULL;
 
4165
 
 
4166
#if (ODBCVER >= 0x0300)
 
4167
                        /* Set deferrability type */
 
4168
                        if (!strcmp(trig_initdeferred, "y"))
 
4169
                                defer_type = SQL_INITIALLY_DEFERRED;
 
4170
                        else if (!strcmp(trig_deferrable, "y"))
 
4171
                                defer_type = SQL_INITIALLY_IMMEDIATE;
 
4172
                        else
 
4173
                                defer_type = SQL_NOT_DEFERRABLE;
 
4174
#endif   /* ODBCVER >= 0x0300 */
 
4175
 
 
4176
                        mylog("Foreign Key Case#1: trig_nargs = %d, num_keys = %d\n", trig_nargs, num_keys);
 
4177
 
 
4178
                        /* Get to first primary key */
 
4179
                        pkey_ptr = trig_args;
 
4180
                        for (i = 0; i < 5; i++)
 
4181
                                pkey_ptr += strlen(pkey_ptr) + 1;
 
4182
 
 
4183
                        /* Get to first foreign key */
 
4184
                        fkey_ptr = trig_args;
 
4185
                        for (k = 0; k < 4; k++)
 
4186
                                fkey_ptr += strlen(fkey_ptr) + 1;
 
4187
 
 
4188
                        for (k = 0; k < num_keys; k++)
 
4189
                        {
 
4190
                                pkey_text = getClientColumnName(conn, relid1, pkey_ptr, &pkey_alloced);
 
4191
                                fkey_text = getClientColumnName(conn, relid2, fkey_ptr, &fkey_alloced);
 
4192
 
 
4193
                                mylog("pkey_ptr = '%s', fk_table = '%s', fkey_ptr = '%s'\n", pkey_text, fk_table_fetched, fkey_text);
 
4194
 
 
4195
                                row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
 
4196
 
 
4197
                                mylog("pk_table_needed = '%s', pkey_ptr = '%s'\n", pk_table_needed, pkey_text);
 
4198
                                set_tuplefield_null(&row->tuple[0]);
 
4199
                                set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(schema_needed));
 
4200
                                set_tuplefield_string(&row->tuple[2], pk_table_needed);
 
4201
                                set_tuplefield_string(&row->tuple[3], pkey_text);
 
4202
 
 
4203
                                mylog("fk_table = '%s', fkey_ptr = '%s'\n", fk_table_fetched, fkey_text);
 
4204
                                set_tuplefield_null(&row->tuple[4]);
 
4205
                                set_tuplefield_string(&row->tuple[5], GET_SCHEMA_NAME(schema_fetched));
 
4206
                                set_tuplefield_string(&row->tuple[6], fk_table_fetched);
 
4207
                                set_tuplefield_string(&row->tuple[7], fkey_text);
 
4208
 
 
4209
                                set_tuplefield_int2(&row->tuple[8], (Int2) (k + 1));
 
4210
 
 
4211
                                mylog("upd_rule = %d, del_rule= %d", upd_rule_type, del_rule_type);
 
4212
                                set_nullfield_int2(&row->tuple[9], (Int2) upd_rule_type);
 
4213
                                set_nullfield_int2(&row->tuple[10], (Int2) del_rule_type);
 
4214
 
 
4215
                                set_tuplefield_null(&row->tuple[11]);
 
4216
                                set_tuplefield_null(&row->tuple[12]);
 
4217
 
 
4218
                                set_tuplefield_string(&row->tuple[13], trig_args);
 
4219
 
 
4220
#if (ODBCVER >= 0x0300)
 
4221
                                mylog(" defer_type = %d\n", defer_type);
 
4222
                                set_tuplefield_int2(&row->tuple[14], defer_type);
 
4223
#endif   /* ODBCVER >= 0x0300 */
 
4224
 
 
4225
                                QR_add_tuple(res, row);
 
4226
                                if (pkey_alloced)
 
4227
                                        free(pkey_text);
 
4228
                                pkey_alloced = FALSE;
 
4229
                                if (fkey_alloced)
 
4230
                                        free(fkey_text);
 
4231
                                fkey_alloced = FALSE;
 
4232
 
 
4233
                                /* next primary/foreign key */
 
4234
                                for (j = 0; j < 2; j++)
 
4235
                                {
 
4236
                                        pkey_ptr += strlen(pkey_ptr) + 1;
 
4237
                                        fkey_ptr += strlen(fkey_ptr) + 1;
 
4238
                                }
 
4239
                        }
 
4240
                        result = PGAPI_Fetch(htbl_stmt);
 
4241
                }
 
4242
        }
 
4243
        else
 
4244
        {
 
4245
                SC_set_error(stmt, STMT_INTERNAL_ERROR, "No tables specified to PGAPI_ForeignKeys.");
 
4246
                SC_log_error(func, "", stmt);
 
4247
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
4248
                return SQL_ERROR;
 
4249
        }
 
4250
        if (pkey_alloced)
 
4251
                free(pkey_text);
 
4252
        if (fkey_alloced)
 
4253
                free(fkey_text);
 
4254
 
 
4255
        PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
4256
 
 
4257
        mylog("PGAPI_ForeignKeys(): EXIT, stmt=%u\n", stmt);
 
4258
        return SQL_SUCCESS;
 
4259
}
 
4260
 
 
4261
 
 
4262
RETCODE         SQL_API
 
4263
PGAPI_ProcedureColumns(
 
4264
                                           HSTMT hstmt,
 
4265
                                           UCHAR FAR * szProcQualifier,
 
4266
                                           SWORD cbProcQualifier,
 
4267
                                           UCHAR FAR * szProcOwner,
 
4268
                                           SWORD cbProcOwner,
 
4269
                                           UCHAR FAR * szProcName,
 
4270
                                           SWORD cbProcName,
 
4271
                                           UCHAR FAR * szColumnName,
 
4272
                                           SWORD cbColumnName)
 
4273
{
 
4274
        CSTR func = "PGAPI_ProcedureColumns";
 
4275
        StatementClass  *stmt = (StatementClass *) hstmt;
 
4276
        ConnectionClass *conn = SC_get_conn(stmt);
 
4277
        char            proc_query[INFO_INQUIRY_LEN];
 
4278
        Int2            result_cols;
 
4279
        TupleNode       *row;
 
4280
        char            *schema_name, *procname, *params;
 
4281
        QResultClass *res, *tres;
 
4282
        Int4            tcount, paramcount, i, j, pgtype;
 
4283
        const char *likeeq = "like";
 
4284
 
 
4285
        mylog("%s: entering...\n", func);
 
4286
 
 
4287
        if (PG_VERSION_LT(conn, 6.5))
 
4288
        {
 
4289
                SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Version is too old");
 
4290
                SC_log_error(func, "Function not implemented", stmt);
 
4291
                return SQL_ERROR;
 
4292
        }
 
4293
        if (!SC_recycle_statement(stmt))
 
4294
                return SQL_ERROR;
 
4295
        if (conn->schema_support)
 
4296
        {
 
4297
                strcpy(proc_query, "select proname, proretset, prorettype, "
 
4298
                                "pronargs, proargtypes, nspname from "
 
4299
                                "pg_catalog.pg_namespace, pg_catalog.pg_proc where "
 
4300
                                "pg_proc.pronamespace = pg_namespace.oid "
 
4301
                                "and (not proretset)");
 
4302
                schema_strcat1(proc_query, " and nspname %s '%.*s'", likeeq, szProcOwner, cbProcOwner, szProcName, cbProcName, conn);
 
4303
                my_strcat1(proc_query, " and proname %s '%.*s'", likeeq, szProcName, cbProcName);
 
4304
                strcat(proc_query, " order by nspname, proname, proretset");
 
4305
        }
 
4306
        else
 
4307
        {
 
4308
                strcpy(proc_query, "select proname, proretset, prorettype, "
 
4309
                                "pronargs, proargtypes from pg_proc where "
 
4310
                                "(not proretset)");
 
4311
                my_strcat1(proc_query, " and proname %s '%.*s'", likeeq, szProcName, cbProcName);
 
4312
                strcat(proc_query, " order by proname, proretset");
 
4313
        }
 
4314
        if (tres = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !tres)
 
4315
        {
 
4316
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_ProcedureColumns query error");
 
4317
                return SQL_ERROR;
 
4318
        }
 
4319
 
 
4320
        stmt->manual_result = TRUE;
 
4321
        stmt->errormsg_created = TRUE;
 
4322
        if (res = QR_Constructor(), !res)
 
4323
        {
 
4324
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_ProcedureColumns result.");
 
4325
                SC_log_error(func, "", stmt);
 
4326
                return SQL_ERROR;
 
4327
        }
 
4328
        SC_set_Result(stmt, res);
 
4329
 
 
4330
        /*
 
4331
         * the binding structure for a statement is not set up until
 
4332
         * a statement is actually executed, so we'll have to do this
 
4333
         * ourselves.
 
4334
         */
 
4335
#if (ODBCVER >= 0x0300)
 
4336
        result_cols = 19;
 
4337
#else
 
4338
        result_cols = 13;
 
4339
#endif /* ODBCVER */
 
4340
        extend_column_bindings(SC_get_ARD(stmt), result_cols);
 
4341
 
 
4342
        /* set the field names */
 
4343
        QR_set_num_fields(res, result_cols);
 
4344
        QR_set_field_info(res, 0, "PROCEDURE_CAT", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4345
        QR_set_field_info(res, 1, "PROCEDUR_SCHEM", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4346
        QR_set_field_info(res, 2, "PROCEDURE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4347
        QR_set_field_info(res, 3, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4348
        QR_set_field_info(res, 4, "COLUMN_TYPE", PG_TYPE_INT2, 2);
 
4349
        QR_set_field_info(res, 5, "DATA_TYPE", PG_TYPE_INT2, 2);
 
4350
        QR_set_field_info(res, 6, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4351
        QR_set_field_info(res, 7, "COLUMN_SIZE", PG_TYPE_INT4, 4);
 
4352
        QR_set_field_info(res, 8, "BUFFER_LENGTH", PG_TYPE_INT4, 4);
 
4353
        QR_set_field_info(res, 9, "DECIMAL_DIGITS", PG_TYPE_INT2, 2);
 
4354
        QR_set_field_info(res, 10, "NUM_PREC_RADIX", PG_TYPE_INT2, 2);
 
4355
        QR_set_field_info(res, 11, "NULLABLE", PG_TYPE_INT2, 2);
 
4356
        QR_set_field_info(res, 12, "REMARKS", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4357
#if (ODBCVER >= 0x0300)
 
4358
        QR_set_field_info(res, 13, "COLUMN_DEF", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4359
        QR_set_field_info(res, 14, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
 
4360
        QR_set_field_info(res, 15, "SQL_DATATIME_SUB", PG_TYPE_INT2, 2);
 
4361
        QR_set_field_info(res, 16, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
 
4362
        QR_set_field_info(res, 17, "ORIDINAL_POSITION", PG_TYPE_INT4, 4);
 
4363
        QR_set_field_info(res, 18, "IS_NULLABLE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4364
#endif   /* ODBCVER >= 0x0300 */
 
4365
 
 
4366
        if (0 == cbColumnName || !szColumnName || !szColumnName[0])
 
4367
                tcount = QR_get_num_total_tuples(tres);
 
4368
        else
 
4369
                tcount = 0;
 
4370
        for (i = 0; i < tcount; i++)
 
4371
        {
 
4372
                if (conn->schema_support)
 
4373
                        schema_name = GET_SCHEMA_NAME(QR_get_value_backend_row(tres, i, 5));
 
4374
                else
 
4375
                        schema_name = NULL;
 
4376
                procname = QR_get_value_backend_row(tres, i, 0);
 
4377
                pgtype = atoi(QR_get_value_backend_row(tres, i, 2));
 
4378
                if (pgtype != 0)
 
4379
                {
 
4380
                        row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
 
4381
                        set_tuplefield_null(&row->tuple[0]);
 
4382
                        set_nullfield_string(&row->tuple[1], schema_name);
 
4383
                        set_tuplefield_string(&row->tuple[2], procname);
 
4384
                        set_tuplefield_string(&row->tuple[3], "");
 
4385
                        set_tuplefield_int2(&row->tuple[4], SQL_RETURN_VALUE);
 
4386
                        set_tuplefield_int2(&row->tuple[5], pgtype_to_concise_type(stmt, pgtype));
 
4387
                        set_tuplefield_string(&row->tuple[6], pgtype_to_name(stmt, pgtype));
 
4388
                        set_nullfield_int4(&row->tuple[7], pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC));
 
4389
                        set_tuplefield_int4(&row->tuple[8], pgtype_buffer_length(stmt, pgtype, PG_STATIC, PG_STATIC));
 
4390
                        set_nullfield_int2(&row->tuple[9], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
 
4391
                        set_nullfield_int2(&row->tuple[10], pgtype_radix(stmt, pgtype));
 
4392
                        set_tuplefield_int2(&row->tuple[11], SQL_NULLABLE_UNKNOWN);
 
4393
                        set_tuplefield_null(&row->tuple[12]);
 
4394
#if (ODBCVER >= 0x0300)
 
4395
                        set_tuplefield_null(&row->tuple[13]);
 
4396
                        set_nullfield_int2(&row->tuple[14], pgtype_to_sqldesctype(stmt, pgtype));
 
4397
                        set_nullfield_int2(&row->tuple[15], pgtype_to_datetime_sub(stmt, pgtype));
 
4398
                        set_nullfield_int4(&row->tuple[16], pgtype_transfer_octet_length(stmt, pgtype, PG_STATIC, PG_STATIC));
 
4399
                        set_tuplefield_int4(&row->tuple[17], 0);
 
4400
                        set_tuplefield_string(&row->tuple[18], "");
 
4401
#endif   /* ODBCVER >= 0x0300 */
 
4402
                        QR_add_tuple(res, row);
 
4403
                }
 
4404
                paramcount = atoi(QR_get_value_backend_row(tres, i, 3));
 
4405
                params = QR_get_value_backend_row(tres, i, 4);
 
4406
                for (j = 0; j < paramcount; j++)
 
4407
                {
 
4408
                        while (isspace(*params))
 
4409
                                params++;
 
4410
                        sscanf(params, "%d", &pgtype);
 
4411
                        row = (TupleNode *) malloc(sizeof(TupleNode) + (result_cols - 1) *sizeof(TupleField));
 
4412
                        set_tuplefield_null(&row->tuple[0]);
 
4413
                        set_nullfield_string(&row->tuple[1], schema_name);
 
4414
                        set_tuplefield_string(&row->tuple[2], procname);
 
4415
                        set_tuplefield_string(&row->tuple[3], "");
 
4416
                        set_tuplefield_int2(&row->tuple[4], SQL_PARAM_INPUT);
 
4417
                        set_tuplefield_int2(&row->tuple[5], pgtype_to_concise_type(stmt, pgtype));
 
4418
                        set_tuplefield_string(&row->tuple[6], pgtype_to_name(stmt, pgtype));
 
4419
                        set_nullfield_int4(&row->tuple[7], pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC));
 
4420
                        set_tuplefield_int4(&row->tuple[8], pgtype_buffer_length(stmt, pgtype, PG_STATIC, PG_STATIC));
 
4421
                        set_nullfield_int2(&row->tuple[9], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
 
4422
                        set_nullfield_int2(&row->tuple[10], pgtype_radix(stmt, pgtype));
 
4423
                        set_tuplefield_int2(&row->tuple[11], SQL_NULLABLE_UNKNOWN);
 
4424
                        set_tuplefield_null(&row->tuple[12]);
 
4425
#if (ODBCVER >= 0x0300)
 
4426
                        set_tuplefield_null(&row->tuple[13]);
 
4427
                        set_nullfield_int2(&row->tuple[14], pgtype_to_sqldesctype(stmt, pgtype));
 
4428
                        set_nullfield_int2(&row->tuple[15], pgtype_to_datetime_sub(stmt, pgtype));
 
4429
                        set_nullfield_int4(&row->tuple[16], pgtype_transfer_octet_length(stmt, pgtype, PG_STATIC, PG_STATIC));
 
4430
                        set_tuplefield_int4(&row->tuple[17], j + 1);
 
4431
                        set_tuplefield_string(&row->tuple[18], "");
 
4432
#endif   /* ODBCVER >= 0x0300 */
 
4433
                        QR_add_tuple(res, row);
 
4434
                        while (isdigit(*params))
 
4435
                                params++;
 
4436
                }
 
4437
        }
 
4438
        QR_Destructor(tres);
 
4439
        /*
 
4440
         * also, things need to think that this statement is finished so the
 
4441
         * results can be retrieved.
 
4442
         */
 
4443
        stmt->status = STMT_FINISHED;
 
4444
        /* set up the current tuple pointer for SQLFetch */
 
4445
        stmt->currTuple = -1;
 
4446
        stmt->rowset_start = -1;
 
4447
        stmt->current_col = -1;
 
4448
 
 
4449
        return SQL_SUCCESS;
 
4450
}
 
4451
 
 
4452
 
 
4453
RETCODE         SQL_API
 
4454
PGAPI_Procedures(
 
4455
                                 HSTMT hstmt,
 
4456
                                 UCHAR FAR * szProcQualifier,
 
4457
                                 SWORD cbProcQualifier,
 
4458
                                 UCHAR FAR * szProcOwner,
 
4459
                                 SWORD cbProcOwner,
 
4460
                                 UCHAR FAR * szProcName,
 
4461
                                 SWORD cbProcName)
 
4462
{
 
4463
        CSTR func = "PGAPI_Procedures";
 
4464
        StatementClass *stmt = (StatementClass *) hstmt;
 
4465
        ConnectionClass *conn = SC_get_conn(stmt);
 
4466
        char            proc_query[INFO_INQUIRY_LEN];
 
4467
        QResultClass *res;
 
4468
        const char *likeeq = "like";
 
4469
 
 
4470
        mylog("%s: entering... scnm=%x len=%d\n", func, szProcOwner, cbProcOwner);
 
4471
 
 
4472
        if (PG_VERSION_LT(conn, 6.5))
 
4473
        {
 
4474
                SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Version is too old");
 
4475
                SC_log_error(func, "Function not implemented", stmt);
 
4476
                return SQL_ERROR;
 
4477
        }
 
4478
        if (!SC_recycle_statement(stmt))
 
4479
                return SQL_ERROR;
 
4480
 
 
4481
        /*
 
4482
         * The following seems the simplest implementation
 
4483
         */
 
4484
        if (conn->schema_support)
 
4485
        {
 
4486
                strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", nspname as " "PROCEDURE_SCHEM" ","
 
4487
                " proname as " "PROCEDURE_NAME" ", '' as " "NUM_INPUT_PARAMS" ","
 
4488
                   " '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
 
4489
                   " '' as " "REMARKS" ","
 
4490
                   " case when prorettype = 0 then 1::int2 else 2::int2 end"
 
4491
                   " as "                 "PROCEDURE_TYPE" " from pg_catalog.pg_namespace,"
 
4492
                   " pg_catalog.pg_proc"
 
4493
                  " where pg_proc.pronamespace = pg_namespace.oid");
 
4494
                schema_strcat1(proc_query, " and nspname %s '%.*s'", likeeq, szProcOwner, cbProcOwner, szProcName, cbProcName, conn);
 
4495
                my_strcat1(proc_query, " and proname %s '%.*s'", likeeq, szProcName, cbProcName);
 
4496
        }
 
4497
        else
 
4498
        {
 
4499
                strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", '' as " "PROCEDURE_SCHEM" ","
 
4500
                " proname as " "PROCEDURE_NAME" ", '' as " "NUM_INPUT_PARAMS" ","
 
4501
                   " '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
 
4502
                   " '' as " "REMARKS" ","
 
4503
                   " case when prorettype = 0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_proc");
 
4504
                my_strcat1(proc_query, " where proname %s '%.*s'", likeeq, szProcName, cbProcName);
 
4505
        }
 
4506
 
 
4507
        if (res = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !res)
 
4508
        {
 
4509
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_Procedures query error");
 
4510
                return SQL_ERROR;
 
4511
        }
 
4512
        SC_set_Result(stmt, res);
 
4513
 
 
4514
        /*
 
4515
         * also, things need to think that this statement is finished so the
 
4516
         * results can be retrieved.
 
4517
         */
 
4518
        stmt->status = STMT_FINISHED;
 
4519
        extend_column_bindings(SC_get_ARD(stmt), 8);
 
4520
        /* set up the current tuple pointer for SQLFetch */
 
4521
        stmt->currTuple = -1;
 
4522
        stmt->rowset_start = -1;
 
4523
        stmt->current_col = -1;
 
4524
 
 
4525
        return SQL_SUCCESS;
 
4526
}
 
4527
 
 
4528
 
 
4529
#define ACLMAX  8
 
4530
#define ALL_PRIVILIGES "arwdRxt"
 
4531
static int
 
4532
usracl_auth(char *usracl, const char *auth)
 
4533
{
 
4534
        int     i, j, addcnt = 0;
 
4535
 
 
4536
        for (i = 0; auth[i]; i++)
 
4537
        {
 
4538
                for (j = 0; j < ACLMAX; j++)
 
4539
                {
 
4540
                        if (usracl[j] == auth[i])
 
4541
                                break;
 
4542
                        else if (!usracl[j])
 
4543
                        {
 
4544
                                usracl[j]= auth[i];
 
4545
                                addcnt++;
 
4546
                                break;
 
4547
                        }
 
4548
                }
 
4549
        }
 
4550
        return addcnt;
 
4551
}
 
4552
static void
 
4553
useracl_upd(char (*useracl)[ACLMAX], QResultClass *allures, const char *user, const char *auth)
 
4554
{
 
4555
        int usercount = QR_get_num_backend_tuples(allures), i, addcnt = 0;
 
4556
 
 
4557
mylog("user=%s auth=%s\n", user, auth);
 
4558
        if (user[0])
 
4559
                for (i = 0; i < usercount; i++)
 
4560
                {
 
4561
                        if (strcmp(QR_get_value_backend_row(allures, i, 0), user) == 0)
 
4562
                        {
 
4563
                                addcnt += usracl_auth(useracl[i], auth);
 
4564
                                break;
 
4565
                        }
 
4566
                }
 
4567
        else
 
4568
                for (i = 0; i < usercount; i++)
 
4569
                {
 
4570
                        addcnt += usracl_auth(useracl[i], auth);
 
4571
                }
 
4572
        mylog("addcnt=%d\n", addcnt);
 
4573
}
 
4574
 
 
4575
RETCODE         SQL_API
 
4576
PGAPI_TablePrivileges(
 
4577
                                          HSTMT hstmt,
 
4578
                                          UCHAR FAR * szTableQualifier,
 
4579
                                          SWORD cbTableQualifier,
 
4580
                                          UCHAR FAR * szTableOwner,
 
4581
                                          SWORD cbTableOwner,
 
4582
                                          UCHAR FAR * szTableName,
 
4583
                                          SWORD cbTableName,
 
4584
                                          UWORD flag)
 
4585
{
 
4586
        StatementClass *stmt = (StatementClass *) hstmt;
 
4587
        CSTR func = "PGAPI_TablePrivileges";
 
4588
        ConnectionClass *conn = SC_get_conn(stmt);
 
4589
        Int2            result_cols;
 
4590
        char            proc_query[INFO_INQUIRY_LEN];
 
4591
        QResultClass    *res, *allures = NULL;
 
4592
        TupleNode       *row;
 
4593
        int             tablecount, usercount, i, j, k;
 
4594
        BOOL            grpauth, sys, su;
 
4595
        char            (*useracl)[ACLMAX], *acl, *user, *delim, *auth;
 
4596
        char            *reln, *owner, *priv, *schnm = NULL;
 
4597
        const char *likeeq = "like";
 
4598
 
 
4599
        mylog("%s: entering... scnm=%x len-%d\n", func, szTableOwner, cbTableOwner);
 
4600
        if (!SC_recycle_statement(stmt))
 
4601
                return SQL_ERROR;
 
4602
 
 
4603
        /*
 
4604
         * a statement is actually executed, so we'll have to do this
 
4605
         * ourselves.
 
4606
         */
 
4607
        result_cols = 7;
 
4608
        extend_column_bindings(SC_get_ARD(stmt), result_cols);
 
4609
 
 
4610
        /* set the field names */
 
4611
        stmt->manual_result = TRUE;
 
4612
        res = QR_Constructor();
 
4613
        SC_set_Result(stmt, res);
 
4614
        QR_set_num_fields(res, result_cols);
 
4615
        QR_set_field_info(res, 0, "TABLE_CAT", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4616
        QR_set_field_info(res, 1, "TABLE_SCHEM", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4617
        QR_set_field_info(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4618
        QR_set_field_info(res, 3, "GRANTOR", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4619
        QR_set_field_info(res, 4, "GRANTEE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4620
        QR_set_field_info(res, 5, "PRIVILEGE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4621
        QR_set_field_info(res, 6, "IS_GRANTABLE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4622
 
 
4623
        /*
 
4624
         * also, things need to think that this statement is finished so the
 
4625
         * results can be retrieved.
 
4626
         */
 
4627
        stmt->status = STMT_FINISHED;
 
4628
        /* set up the current tuple pointer for SQLFetch */
 
4629
        stmt->currTuple = -1;
 
4630
        stmt->rowset_start = -1;
 
4631
        stmt->current_col = -1;
 
4632
        if (conn->schema_support)
 
4633
                strncpy_null(proc_query, "select relname, usename, relacl, nspname"
 
4634
                " from pg_catalog.pg_namespace, pg_catalog.pg_class ,"
 
4635
                " pg_catalog.pg_user where", sizeof(proc_query));
 
4636
        else
 
4637
                strncpy_null(proc_query, "select relname, usename, relacl"
 
4638
                " from pg_class , pg_user where", sizeof(proc_query));
 
4639
        if ((flag & PODBC_NOT_SEARCH_PATTERN) != 0)
 
4640
        {
 
4641
                if (conn->schema_support)
 
4642
                {
 
4643
                        schema_strcat(proc_query, " nspname = '%.*s' and", szTableOwner, cbTableOwner, szTableName, cbTableName, conn);
 
4644
                }
 
4645
                my_strcat(proc_query, " relname = '%.*s' and", szTableName, cbTableName);
 
4646
        }
 
4647
        else
 
4648
        {
 
4649
                char    esc_table_name[TABLE_NAME_STORAGE_LEN * 2];
 
4650
                int     escTbnamelen;
 
4651
 
 
4652
                if (conn->schema_support)
 
4653
                {
 
4654
                        escTbnamelen = reallyEscapeCatalogEscapes(szTableOwner, cbTableOwner, esc_table_name, sizeof(esc_table_name), conn->ccsc);
 
4655
                        schema_strcat1(proc_query, " nspname %s '%.*s' and", likeeq, esc_table_name, escTbnamelen, szTableName, cbTableName, conn);
 
4656
                }
 
4657
                escTbnamelen = reallyEscapeCatalogEscapes(szTableName, cbTableName, esc_table_name, sizeof(esc_table_name), conn->ccsc);
 
4658
                my_strcat1(proc_query, " relname %s '%.*s' and", likeeq, esc_table_name, escTbnamelen);
 
4659
        }
 
4660
        if (conn->schema_support)
 
4661
                strcat(proc_query, " pg_namespace.oid = relnamespace and");
 
4662
        strcat(proc_query, " pg_user.usesysid = relowner");
 
4663
        if (res = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !res)
 
4664
        {
 
4665
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_TablePrivileges query error");
 
4666
                return SQL_ERROR;
 
4667
        }
 
4668
        strncpy_null(proc_query, "select usename, usesysid, usesuper from pg_user", sizeof(proc_query));
 
4669
        tablecount = QR_get_num_backend_tuples(res);
 
4670
        if (allures = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), !allures)
 
4671
        {
 
4672
                QR_Destructor(res);
 
4673
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_TablePrivileges query error");
 
4674
                return SQL_ERROR;
 
4675
        }
 
4676
        usercount = QR_get_num_backend_tuples(allures);
 
4677
        useracl = (char (*)[ACLMAX]) malloc(usercount * sizeof(char [ACLMAX]));
 
4678
        for (i = 0; i < tablecount; i++)
 
4679
        { 
 
4680
                memset(useracl, 0, usercount * sizeof(char[ACLMAX]));
 
4681
                acl = (char *) QR_get_value_backend_row(res, i, 2);
 
4682
                if (acl && acl[0] == '{')
 
4683
                        user = acl + 1;
 
4684
                else
 
4685
                        user = NULL;
 
4686
                for (; user && *user;)
 
4687
                {
 
4688
                        grpauth = FALSE;
 
4689
                        if (user[0] == '"' && strncmp(user + 1, "group ", 6) == 0)
 
4690
                        {
 
4691
                                user += 7;
 
4692
                                grpauth = TRUE;
 
4693
                        }
 
4694
                        if (delim = strchr(user, '='), !delim)
 
4695
                                break;
 
4696
                        *delim = '\0';
 
4697
                        auth = delim + 1;
 
4698
                        if (grpauth)
 
4699
                        {
 
4700
                                if (delim = strchr(auth, '"'), delim)
 
4701
                                {
 
4702
                                        *delim = '\0';
 
4703
                                        delim++;
 
4704
                                }
 
4705
                        }
 
4706
                        else if (delim = strchr(auth, ','), delim)
 
4707
                                *delim = '\0';
 
4708
                        else if (delim = strchr(auth, '}'), delim)
 
4709
                                *delim = '\0';
 
4710
                        if (grpauth) /* handle group privilege */
 
4711
                        {
 
4712
                                QResultClass    *gres;
 
4713
                                int             i;
 
4714
                                char    *grolist, *uid, *delm;
 
4715
 
 
4716
                                snprintf(proc_query, sizeof(proc_query) - 1, "select grolist from pg_group where groname = '%s'", user);
 
4717
                                if (gres = CC_send_query(conn, proc_query, NULL, CLEAR_RESULT_ON_ABORT), gres != NULL)
 
4718
                                {
 
4719
                                        grolist = QR_get_value_backend_row(gres, 0, 0);
 
4720
                                        if (grolist && grolist[0] == '{')
 
4721
                                        {
 
4722
                                                for (uid = grolist + 1; *uid;)
 
4723
                                                {
 
4724
                                                        if (delm = strchr(uid, ','), delm)
 
4725
                                                                *delm = '\0';
 
4726
                                                        else if (delm = strchr(uid, '}'), delm)
 
4727
                                                                *delm = '\0';
 
4728
mylog("guid=%s\n", uid);
 
4729
                                                        for (i = 0; i < usercount; i++)
 
4730
                                                        {
 
4731
                                                                if (strcmp(QR_get_value_backend_row(allures, i, 1), uid) == 0)
 
4732
                                                                        useracl_upd(useracl, allures, QR_get_value_backend_row(allures, i, 0), auth);
 
4733
                                                        }
 
4734
                                                        uid = delm + 1;
 
4735
                                                }
 
4736
                                        }
 
4737
                                        QR_Destructor(gres);
 
4738
                                }
 
4739
                        }
 
4740
                        else
 
4741
                                useracl_upd(useracl, allures, user, auth);
 
4742
                        if (!delim)
 
4743
                                break;
 
4744
                        user = delim + 1;
 
4745
                }
 
4746
                reln = QR_get_value_backend_row(res, i, 0);
 
4747
                owner = QR_get_value_backend_row(res, i, 1);
 
4748
                if (conn->schema_support)
 
4749
                        schnm = QR_get_value_backend_row(res, i, 3);
 
4750
                /* The owner has all privileges */
 
4751
                useracl_upd(useracl, allures, owner, ALL_PRIVILIGES);
 
4752
                for (j = 0; j < usercount; j++)
 
4753
                {
 
4754
                        user = QR_get_value_backend_row(allures, j, 0);
 
4755
                        su = (strcmp(QR_get_value_backend_row(allures, j, 2), "t") == 0);
 
4756
                        sys = (strcmp(user, owner) == 0);
 
4757
                        /* Super user has all privileges */
 
4758
                        if (su)
 
4759
                                useracl_upd(useracl, allures, user, ALL_PRIVILIGES);
 
4760
                        for (k = 0; k < ACLMAX; k++)
 
4761
                        {
 
4762
                                if (!useracl[j][k])
 
4763
                                        break;
 
4764
                                switch (useracl[j][k])
 
4765
                                {
 
4766
                                        case 'R': /* rule */
 
4767
                                        case 't': /* trigger */
 
4768
                                                continue;
 
4769
                                }
 
4770
                                row = (TupleNode *) malloc(sizeof(TupleNode) + (7 - 1) *sizeof(TupleField));
 
4771
                                set_tuplefield_string(&row->tuple[0], "");
 
4772
                                if (conn->schema_support)
 
4773
                                        set_tuplefield_string(&row->tuple[1], GET_SCHEMA_NAME(schnm));
 
4774
                                else
 
4775
                                        set_tuplefield_string(&row->tuple[1], "");
 
4776
                                set_tuplefield_string(&row->tuple[2], reln);
 
4777
                                if (su || sys)
 
4778
                                        set_tuplefield_string(&row->tuple[3], "_SYSTEM");
 
4779
                                else
 
4780
                                        set_tuplefield_string(&row->tuple[3], owner);
 
4781
                                mylog("user=%s\n", user);
 
4782
                                set_tuplefield_string(&row->tuple[4], user);
 
4783
                                switch (useracl[j][k])
 
4784
                                {
 
4785
                                        case 'a':
 
4786
                                                priv = "INSERT";
 
4787
                                                break;
 
4788
                                        case 'r':
 
4789
                                                priv = "SELECT";
 
4790
                                                break;
 
4791
                                        case 'w':
 
4792
                                                priv = "UPDATE";
 
4793
                                                break;
 
4794
                                        case 'd':
 
4795
                                                priv = "DELETE";
 
4796
                                                break;
 
4797
                                        case 'x':
 
4798
                                                priv = "REFERENCES";
 
4799
                                                break;
 
4800
                                        default:
 
4801
                                                priv = "";
 
4802
                                }
 
4803
                                set_tuplefield_string(&row->tuple[5], priv);
 
4804
                                /* The owner and the super user are grantable */
 
4805
                                if (sys || su)
 
4806
                                        set_tuplefield_string(&row->tuple[6], "YES");
 
4807
                                else
 
4808
                                        set_tuplefield_string(&row->tuple[6], "NO");
 
4809
                                QR_add_tuple(SC_get_Result(stmt), row);
 
4810
                        }
 
4811
                }
 
4812
        }
 
4813
        free(useracl);
 
4814
        QR_Destructor(res);
 
4815
        QR_Destructor(allures); 
 
4816
        return SQL_SUCCESS;
 
4817
}