~ubuntu-branches/ubuntu/trusty/psqlodbc/trusty-proposed

« back to all changes in this revision

Viewing changes to info.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2013-10-24 07:21:55 UTC
  • mfrom: (16.1.2 sid)
  • Revision ID: package-import@ubuntu.com-20131024072155-xlf5odyk3iblcd51
Tags: 1:09.02.0100-2ubuntu1
* Merge with Debian unstable. Remaining Ubuntu changes:
  - debian/tests: Disable iodbc test and dependency, as in Ubuntu iodbc and
    unixodbc are not installable in parallel, and iodbc is obsolete and
    should be removed at some point.

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, 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
 
#include "catfunc.h"
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
 
#define NULL_IF_NULL(a) ((a) ? ((const char *) a) : "(NULL)")
50
 
 
51
 
/* extern GLOBAL_VALUES globals; */
52
 
 
53
 
CSTR    pubstr = "public";
54
 
CSTR    likeop = "like";
55
 
CSTR    eqop = "=";
56
 
 
57
 
RETCODE         SQL_API
58
 
PGAPI_GetInfo(
59
 
                          HDBC hdbc,
60
 
                          SQLUSMALLINT fInfoType,
61
 
                          PTR rgbInfoValue,
62
 
                          SQLSMALLINT cbInfoValueMax,
63
 
                          SQLSMALLINT FAR * pcbInfoValue)
64
 
{
65
 
        CSTR func = "PGAPI_GetInfo";
66
 
        ConnectionClass *conn = (ConnectionClass *) hdbc;
67
 
        ConnInfo   *ci;
68
 
        const char   *p = NULL;
69
 
        char            tmp[MAX_INFO_STRING];
70
 
        SQLULEN                 len = 0,
71
 
                                value = 0;
72
 
        RETCODE         result = SQL_ERROR;
73
 
        char            odbcver[16];
74
 
        int             i_odbcver;
75
 
 
76
 
        mylog("%s: entering...fInfoType=%d\n", func, fInfoType);
77
 
 
78
 
        if (!conn)
79
 
        {
80
 
                CC_log_error(func, NULL_STRING, NULL);
81
 
                return SQL_INVALID_HANDLE;
82
 
        }
83
 
 
84
 
        ci = &(conn->connInfo);
85
 
 
86
 
        switch (fInfoType)
87
 
        {
88
 
                case SQL_ACCESSIBLE_PROCEDURES: /* ODBC 1.0 */
89
 
                        p = "N";
90
 
                        break;
91
 
 
92
 
                case SQL_ACCESSIBLE_TABLES:             /* ODBC 1.0 */
93
 
                        p = CC_accessible_only(conn) ? "Y" : "N";
94
 
                        break;
95
 
 
96
 
                case SQL_ACTIVE_CONNECTIONS:    /* ODBC 1.0 */
97
 
                        len = 2;
98
 
                        value = 0;
99
 
                        break;
100
 
 
101
 
                case SQL_ACTIVE_STATEMENTS:             /* ODBC 1.0 */
102
 
                        len = 2;
103
 
                        value = 0;
104
 
                        break;
105
 
 
106
 
                case SQL_ALTER_TABLE:   /* ODBC 2.0 */
107
 
                        len = 4;
108
 
                        value = SQL_AT_ADD_COLUMN;
109
 
                        if (PG_VERSION_GE(conn, 7.3))
110
 
                                value |= SQL_AT_DROP_COLUMN;
111
 
#if (ODBCVER >= 0x0300)
112
 
                        value |= SQL_AT_ADD_COLUMN_SINGLE;
113
 
                        if (PG_VERSION_GE(conn, 7.1))
114
 
                                value |= SQL_AT_ADD_CONSTRAINT
115
 
                                        | SQL_AT_ADD_TABLE_CONSTRAINT
116
 
                                        | SQL_AT_CONSTRAINT_INITIALLY_DEFERRED
117
 
                                        | SQL_AT_CONSTRAINT_INITIALLY_IMMEDIATE
118
 
                                        | SQL_AT_CONSTRAINT_DEFERRABLE;
119
 
                        if (PG_VERSION_GE(conn, 7.3))
120
 
                                value |= SQL_AT_DROP_TABLE_CONSTRAINT_RESTRICT
121
 
                                        | SQL_AT_DROP_TABLE_CONSTRAINT_CASCADE
122
 
                                        | SQL_AT_DROP_COLUMN_RESTRICT
123
 
                                        | SQL_AT_DROP_COLUMN_CASCADE;
124
 
#endif /* ODBCVER */
125
 
                        break;
126
 
 
127
 
                case SQL_BOOKMARK_PERSISTENCE:  /* ODBC 2.0 */
128
 
                        /* very simple bookmark support */
129
 
                        len = 4;
130
 
                        value = ci->drivers.use_declarefetch && PG_VERSION_LT(conn, 7.4) ? 0 : (SQL_BP_SCROLL | SQL_BP_DELETE | SQL_BP_UPDATE | SQL_BP_TRANSACTION);
131
 
                        break;
132
 
 
133
 
                case SQL_COLUMN_ALIAS:  /* ODBC 2.0 */
134
 
                        p = "Y";
135
 
                        break;
136
 
 
137
 
                case SQL_CONCAT_NULL_BEHAVIOR:  /* ODBC 1.0 */
138
 
                        len = 2;
139
 
                        value = SQL_CB_NON_NULL;
140
 
                        break;
141
 
 
142
 
                case SQL_CONVERT_INTEGER:
143
 
                case SQL_CONVERT_SMALLINT:
144
 
                case SQL_CONVERT_TINYINT:
145
 
                case SQL_CONVERT_BIT:
146
 
                case SQL_CONVERT_VARCHAR:               /* ODBC 1.0 */
147
 
                        len = sizeof(SQLUINTEGER);
148
 
                        value = SQL_CVT_BIT | SQL_CVT_INTEGER;
149
 
mylog("SQL_CONVERT_ mask=" FORMAT_ULEN "\n", value);
150
 
                        break;
151
 
                case SQL_CONVERT_BIGINT:
152
 
                case SQL_CONVERT_DECIMAL:
153
 
                case SQL_CONVERT_DOUBLE:
154
 
                case SQL_CONVERT_FLOAT:
155
 
                case SQL_CONVERT_NUMERIC:
156
 
                case SQL_CONVERT_REAL:
157
 
                case SQL_CONVERT_DATE:
158
 
                case SQL_CONVERT_TIME:
159
 
                case SQL_CONVERT_TIMESTAMP:
160
 
                case SQL_CONVERT_BINARY:
161
 
                case SQL_CONVERT_LONGVARBINARY:
162
 
                case SQL_CONVERT_VARBINARY:             /* ODBC 1.0 */
163
 
                case SQL_CONVERT_CHAR:
164
 
                case SQL_CONVERT_LONGVARCHAR:
165
 
#if defined(UNICODE_SUPPORT) && (ODBCVER >= 0x0300)
166
 
                case SQL_CONVERT_WCHAR:
167
 
                case SQL_CONVERT_WLONGVARCHAR:
168
 
                case SQL_CONVERT_WVARCHAR:
169
 
#endif /* UNICODE_SUPPORT */
170
 
                        len = sizeof(SQLUINTEGER);
171
 
                        value = 0;      /* CONVERT is unavailable */
172
 
                        break;
173
 
 
174
 
                case SQL_CONVERT_FUNCTIONS:             /* ODBC 1.0 */
175
 
                        len = sizeof(SQLUINTEGER);
176
 
                        value = SQL_FN_CVT_CONVERT;
177
 
mylog("CONVERT_FUNCTIONS=" FORMAT_ULEN "\n", value);
178
 
                        break;
179
 
 
180
 
                case SQL_CORRELATION_NAME:              /* ODBC 1.0 */
181
 
 
182
 
                        /*
183
 
                         * Saying no correlation name makes Query not work right.
184
 
                         * value = SQL_CN_NONE;
185
 
                         */
186
 
                        len = 2;
187
 
                        value = SQL_CN_ANY;
188
 
                        break;
189
 
 
190
 
                case SQL_CURSOR_COMMIT_BEHAVIOR:                /* ODBC 1.0 */
191
 
                        len = 2;
192
 
                        value = SQL_CB_CLOSE;
193
 
                        if (!ci->drivers.use_declarefetch || PG_VERSION_GE(conn, 7.4))
194
 
                                value = SQL_CB_PRESERVE;
195
 
                        break;
196
 
 
197
 
                case SQL_CURSOR_ROLLBACK_BEHAVIOR:              /* ODBC 1.0 */
198
 
                        len = 2;
199
 
                        value = SQL_CB_CLOSE;
200
 
                        if (!ci->drivers.use_declarefetch)
201
 
                                value = SQL_CB_PRESERVE;
202
 
                        break;
203
 
 
204
 
                case SQL_DATA_SOURCE_NAME:              /* ODBC 1.0 */
205
 
                        p = CC_get_DSN(conn);
206
 
                        break;
207
 
 
208
 
                case SQL_DATA_SOURCE_READ_ONLY: /* ODBC 1.0 */
209
 
                        p = CC_is_onlyread(conn) ? "Y" : "N";
210
 
                        break;
211
 
 
212
 
                case SQL_DATABASE_NAME: /* Support for old ODBC 1.0 Apps */
213
 
 
214
 
                        /*
215
 
                         * Returning the database name causes problems in MS Query. It
216
 
                         * generates query like: "SELECT DISTINCT a FROM byronnbad3
217
 
                         * bad3"
218
 
                         *
219
 
                         * p = CC_get_database(conn);
220
 
                         */
221
 
                        p = CurrCatString(conn);
222
 
                        break;
223
 
 
224
 
                case SQL_DBMS_NAME:             /* ODBC 1.0 */
225
 
                        if (CC_fake_mss(conn))
226
 
                                p = "Microsoft SQL Server";
227
 
                        else
228
 
                                p = "PostgreSQL";
229
 
                        break;
230
 
 
231
 
                case SQL_DBMS_VER:              /* ODBC 1.0 */
232
 
 
233
 
                        /*
234
 
                         * The ODBC spec wants ##.##.#### ...whatever... so prepend
235
 
                         * the driver
236
 
                         */
237
 
                        /* version number to the dbms version string */
238
 
                        /*
239
 
                        snprintf(tmp, sizeof(tmp) - 1, "%s %s", POSTGRESDRIVERVERSION, conn->pg_version);
240
 
                        tmp[sizeof(tmp) - 1] = '\0'; */
241
 
                        if (CC_fake_mss(conn))
242
 
                                p = "09.00.1399";
243
 
                        else
244
 
                        {
245
 
                                strncpy_null(tmp, conn->pg_version, sizeof(tmp));
246
 
                                p = tmp;
247
 
                        }
248
 
                        break;
249
 
 
250
 
                case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */
251
 
                        len = 4;
252
 
                        if (PG_VERSION_LT(conn, 6.5))
253
 
                                value = SQL_TXN_SERIALIZABLE;
254
 
                        else
255
 
                                value = SQL_TXN_READ_COMMITTED;
256
 
                        break;
257
 
 
258
 
                case SQL_DRIVER_NAME:   /* ODBC 1.0 */
259
 
                        p = DRIVER_FILE_NAME;
260
 
                        break;
261
 
 
262
 
                case SQL_DRIVER_ODBC_VER:
263
 
                        i_odbcver = conn->driver_version;
264
 
                        snprintf(odbcver, sizeof(odbcver), "%02x.%02x", i_odbcver / 256, i_odbcver % 256);
265
 
                        /* p = DRIVER_ODBC_VER; */
266
 
                        p = odbcver;
267
 
                        break;
268
 
 
269
 
                case SQL_DRIVER_VER:    /* ODBC 1.0 */
270
 
                        p = POSTGRESDRIVERVERSION;
271
 
                        break;
272
 
 
273
 
                case SQL_EXPRESSIONS_IN_ORDERBY:                /* ODBC 1.0 */
274
 
                        p = PG_VERSION_GE(conn, 6.5) ? "Y" : "N";
275
 
                        break;
276
 
 
277
 
                case SQL_FETCH_DIRECTION:               /* ODBC 1.0 */
278
 
                        len = 4;
279
 
                        value = (SQL_FD_FETCH_NEXT |
280
 
                                SQL_FD_FETCH_NEXT | 
281
 
                                SQL_FD_FETCH_FIRST |
282
 
                                SQL_FD_FETCH_LAST |
283
 
                                SQL_FD_FETCH_PRIOR |
284
 
                                SQL_FD_FETCH_ABSOLUTE |
285
 
                                SQL_FD_FETCH_RELATIVE |
286
 
                                SQL_FD_FETCH_BOOKMARK);
287
 
                        break;
288
 
 
289
 
                case SQL_FILE_USAGE:    /* ODBC 2.0 */
290
 
                        len = 2;
291
 
                        value = SQL_FILE_NOT_SUPPORTED;
292
 
                        break;
293
 
 
294
 
                case SQL_GETDATA_EXTENSIONS:    /* ODBC 2.0 */
295
 
                        len = 4;
296
 
                        value = (SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND | SQL_GD_BLOCK);
297
 
                        break;
298
 
 
299
 
                case SQL_GROUP_BY:              /* ODBC 2.0 */
300
 
                        len = 2;
301
 
                        value = SQL_GB_GROUP_BY_EQUALS_SELECT;
302
 
                        break;
303
 
 
304
 
                case SQL_IDENTIFIER_CASE:               /* ODBC 1.0 */
305
 
 
306
 
                        /*
307
 
                         * are identifiers case-sensitive (yes, but only when quoted.
308
 
                         * If not quoted, they default to lowercase)
309
 
                         */
310
 
                        len = 2;
311
 
                        value = SQL_IC_LOWER;
312
 
                        break;
313
 
 
314
 
                case SQL_IDENTIFIER_QUOTE_CHAR: /* ODBC 1.0 */
315
 
                        /* the character used to quote "identifiers" */
316
 
                        p = PG_VERSION_LE(conn, 6.2) ? " " : "\"";
317
 
                        break;
318
 
 
319
 
                case SQL_KEYWORDS:              /* ODBC 2.0 */
320
 
                        p = NULL_STRING;
321
 
                        break;
322
 
 
323
 
                case SQL_LIKE_ESCAPE_CLAUSE:    /* ODBC 2.0 */
324
 
 
325
 
                        /*
326
 
                         * is there a character that escapes '%' and '_' in a LIKE
327
 
                         * clause? not as far as I can tell
328
 
                         */
329
 
                        p = "N";
330
 
                        break;
331
 
 
332
 
                case SQL_LOCK_TYPES:    /* ODBC 2.0 */
333
 
                        len = 4;
334
 
                        value = ci->drivers.lie ? (SQL_LCK_NO_CHANGE | SQL_LCK_EXCLUSIVE | SQL_LCK_UNLOCK) : SQL_LCK_NO_CHANGE;
335
 
                        break;
336
 
 
337
 
                case SQL_MAX_BINARY_LITERAL_LEN:                /* ODBC 2.0 */
338
 
                        len = 4;
339
 
                        value = 0;
340
 
                        break;
341
 
 
342
 
                case SQL_MAX_CHAR_LITERAL_LEN:  /* ODBC 2.0 */
343
 
                        len = 4;
344
 
                        value = 0;
345
 
                        break;
346
 
 
347
 
                case SQL_MAX_COLUMN_NAME_LEN:   /* ODBC 1.0 */
348
 
                        len = 2;
349
 
                        if (PG_VERSION_GT(conn, 7.4))
350
 
                                value = CC_get_max_idlen(conn);
351
 
#ifdef  MAX_COLUMN_LEN
352
 
                        else
353
 
                                value = MAX_COLUMN_LEN;
354
 
#endif /* MAX_COLUMN_LEN */
355
 
                        if (0 == value)
356
 
                        {
357
 
                                if (PG_VERSION_GE(conn, 7.3))
358
 
                                        value = NAMEDATALEN_V73;
359
 
                                else
360
 
                                        value = NAMEDATALEN_V72;
361
 
                        }
362
 
                        break;
363
 
 
364
 
                case SQL_MAX_COLUMNS_IN_GROUP_BY:               /* ODBC 2.0 */
365
 
                        len = 2;
366
 
                        value = 0;
367
 
                        break;
368
 
 
369
 
                case SQL_MAX_COLUMNS_IN_INDEX:  /* ODBC 2.0 */
370
 
                        len = 2;
371
 
                        value = 0;
372
 
                        break;
373
 
 
374
 
                case SQL_MAX_COLUMNS_IN_ORDER_BY:               /* ODBC 2.0 */
375
 
                        len = 2;
376
 
                        value = 0;
377
 
                        break;
378
 
 
379
 
                case SQL_MAX_COLUMNS_IN_SELECT: /* ODBC 2.0 */
380
 
                        len = 2;
381
 
                        value = 0;
382
 
                        break;
383
 
 
384
 
                case SQL_MAX_COLUMNS_IN_TABLE:  /* ODBC 2.0 */
385
 
                        len = 2;
386
 
                        value = 0;
387
 
                        break;
388
 
 
389
 
                case SQL_MAX_CURSOR_NAME_LEN:   /* ODBC 1.0 */
390
 
                        len = 2;
391
 
                        value = MAX_CURSOR_LEN;
392
 
                        break;
393
 
 
394
 
                case SQL_MAX_INDEX_SIZE:                /* ODBC 2.0 */
395
 
                        len = 4;
396
 
                        value = 0;
397
 
                        break;
398
 
 
399
 
                case SQL_MAX_OWNER_NAME_LEN:    /* ODBC 1.0 */
400
 
                        len = 2;
401
 
                        value = 0;
402
 
                        if (PG_VERSION_GT(conn, 7.4))
403
 
                                value = CC_get_max_idlen(conn);
404
 
#ifdef  MAX_SCHEMA_LEN
405
 
                        else if (conn->schema_support)
406
 
                                value = MAX_SCHEMA_LEN;
407
 
#endif /* MAX_SCHEMA_LEN */
408
 
                        if (0 == value)
409
 
                        {
410
 
                                if (PG_VERSION_GE(conn, 7.3))
411
 
                                        value = NAMEDATALEN_V73;
412
 
                        }
413
 
                        break;
414
 
 
415
 
                case SQL_MAX_PROCEDURE_NAME_LEN:                /* ODBC 1.0 */
416
 
                        len = 2;
417
 
                        value = 0;
418
 
                        break;
419
 
 
420
 
                case SQL_MAX_QUALIFIER_NAME_LEN:                /* ODBC 1.0 */
421
 
                        len = 2;
422
 
                        value = 0;
423
 
                        break;
424
 
 
425
 
                case SQL_MAX_ROW_SIZE:  /* ODBC 2.0 */
426
 
                        len = 4;
427
 
                        if (PG_VERSION_GE(conn, 7.1))
428
 
                        {
429
 
                                /* Large Rowa in 7.1+ */
430
 
                                value = MAX_ROW_SIZE;
431
 
                        }
432
 
                        else
433
 
                        {
434
 
                                /* Without the Toaster we're limited to the blocksize */
435
 
                                value = BLCKSZ;
436
 
                        }
437
 
                        break;
438
 
 
439
 
                case SQL_MAX_ROW_SIZE_INCLUDES_LONG:    /* ODBC 2.0 */
440
 
 
441
 
                        /*
442
 
                         * does the preceding value include LONGVARCHAR and
443
 
                         * LONGVARBINARY fields?   Well, it does include longvarchar,
444
 
                         * but not longvarbinary.
445
 
                         */
446
 
                        p = "Y";
447
 
                        break;
448
 
 
449
 
                case SQL_MAX_STATEMENT_LEN:             /* ODBC 2.0 */
450
 
                        /* maybe this should be 0? */
451
 
                        len = 4;
452
 
                        value = CC_get_max_query_len(conn);
453
 
                        break;
454
 
 
455
 
                case SQL_MAX_TABLE_NAME_LEN:    /* ODBC 1.0 */
456
 
                        len = 2;
457
 
                        if (PG_VERSION_GT(conn, 7.4))
458
 
                                value = CC_get_max_idlen(conn);
459
 
#ifdef  MAX_TABLE_LEN
460
 
                        else
461
 
                                value = MAX_TABLE_LEN;
462
 
#endif /* MAX_TABLE_LEN */
463
 
                        if (0 == value)
464
 
                        {
465
 
                                if (PG_VERSION_GE(conn, 7.3))
466
 
                                        value = NAMEDATALEN_V73;
467
 
                                else
468
 
                                        value = NAMEDATALEN_V72;
469
 
                        }
470
 
                        break;
471
 
 
472
 
                case SQL_MAX_TABLES_IN_SELECT:  /* ODBC 2.0 */
473
 
                        len = 2;
474
 
                        value = 0;
475
 
                        break;
476
 
 
477
 
                case SQL_MAX_USER_NAME_LEN:
478
 
                        len = 2;
479
 
                        value = 0;
480
 
                        break;
481
 
 
482
 
                case SQL_MULT_RESULT_SETS:              /* ODBC 1.0 */
483
 
                        /* Don't support multiple result sets but say yes anyway? */
484
 
                        p = "Y";
485
 
                        break;
486
 
 
487
 
                case SQL_MULTIPLE_ACTIVE_TXN:   /* ODBC 1.0 */
488
 
                        p = "Y";
489
 
                        break;
490
 
 
491
 
                case SQL_NEED_LONG_DATA_LEN:    /* ODBC 2.0 */
492
 
 
493
 
                        /*
494
 
                         * Don't need the length, SQLPutData can handle any size and
495
 
                         * multiple calls
496
 
                         */
497
 
                        p = "N";
498
 
                        break;
499
 
 
500
 
                case SQL_NON_NULLABLE_COLUMNS:  /* ODBC 1.0 */
501
 
                        len = 2;
502
 
                        value = SQL_NNC_NON_NULL;
503
 
                        break;
504
 
 
505
 
                case SQL_NULL_COLLATION:                /* ODBC 2.0 */
506
 
                        /* where are nulls sorted? */
507
 
                        len = 2;
508
 
                        if (PG_VERSION_GE(conn, 7.2))
509
 
                                value = SQL_NC_HIGH;
510
 
                        else
511
 
                                value = SQL_NC_END;
512
 
                        break;
513
 
 
514
 
                case SQL_NUMERIC_FUNCTIONS:             /* ODBC 1.0 */
515
 
                        len = 4;
516
 
                        value = 0;
517
 
                        break;
518
 
 
519
 
                case SQL_ODBC_API_CONFORMANCE:  /* ODBC 1.0 */
520
 
                        len = 2;
521
 
                        value = SQL_OAC_LEVEL1;
522
 
                        break;
523
 
 
524
 
                case SQL_ODBC_SAG_CLI_CONFORMANCE:              /* ODBC 1.0 */
525
 
                        len = 2;
526
 
                        value = SQL_OSCC_NOT_COMPLIANT;
527
 
                        break;
528
 
 
529
 
                case SQL_ODBC_SQL_CONFORMANCE:  /* ODBC 1.0 */
530
 
                        len = 2;
531
 
                        value = SQL_OSC_CORE;
532
 
                        break;
533
 
 
534
 
                case SQL_ODBC_SQL_OPT_IEF:              /* ODBC 1.0 */
535
 
                        p = "N";
536
 
                        break;
537
 
 
538
 
                case SQL_OJ_CAPABILITIES:               /* ODBC 2.01 */
539
 
                        len = 4;
540
 
                        if (PG_VERSION_GE(conn, 7.1))
541
 
                        {
542
 
                                /* OJs in 7.1+ */
543
 
                                value = (SQL_OJ_LEFT |
544
 
                                                 SQL_OJ_RIGHT |
545
 
                                                 SQL_OJ_FULL |
546
 
                                                 SQL_OJ_NESTED |
547
 
                                                 SQL_OJ_NOT_ORDERED |
548
 
                                                 SQL_OJ_INNER |
549
 
                                                 SQL_OJ_ALL_COMPARISON_OPS);
550
 
                        }
551
 
                        else
552
 
                                /* OJs not in <7.1 */
553
 
                                value = 0;
554
 
                        break;
555
 
 
556
 
                case SQL_ORDER_BY_COLUMNS_IN_SELECT:    /* ODBC 2.0 */
557
 
                        p = (PG_VERSION_LE(conn, 6.3)) ? "Y" : "N";
558
 
                        break;
559
 
 
560
 
                case SQL_OUTER_JOINS:   /* ODBC 1.0 */
561
 
                        if (PG_VERSION_GE(conn, 7.1))
562
 
                                /* OJs in 7.1+ */
563
 
                                p = "Y";
564
 
                        else
565
 
                                /* OJs not in <7.1 */
566
 
                                p = "N";
567
 
                        break;
568
 
 
569
 
                case SQL_OWNER_TERM:    /* ODBC 1.0 */
570
 
                        if (conn->schema_support)
571
 
                                p = "schema";
572
 
                        else
573
 
                                p = "owner";
574
 
                        break;
575
 
 
576
 
                case SQL_OWNER_USAGE:   /* ODBC 2.0 */
577
 
                        len = 4;
578
 
                        value = 0;
579
 
                        if (conn->schema_support)
580
 
                                value = SQL_OU_DML_STATEMENTS
581
 
                                        | SQL_OU_TABLE_DEFINITION
582
 
                                        | SQL_OU_INDEX_DEFINITION
583
 
                                        | SQL_OU_PRIVILEGE_DEFINITION
584
 
                                        ;
585
 
                        break;
586
 
 
587
 
                case SQL_POS_OPERATIONS:                /* ODBC 2.0 */
588
 
                        len = 4;
589
 
                        value = (SQL_POS_POSITION | SQL_POS_REFRESH);
590
 
                        if (0 != ci->updatable_cursors)
591
 
                                value |= (SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD);
592
 
                        break;
593
 
 
594
 
                case SQL_POSITIONED_STATEMENTS: /* ODBC 2.0 */
595
 
                        len = 4;
596
 
                        value = ci->drivers.lie ? (SQL_PS_POSITIONED_DELETE |
597
 
                                                                           SQL_PS_POSITIONED_UPDATE |
598
 
                                                                           SQL_PS_SELECT_FOR_UPDATE) : 0;
599
 
                        break;
600
 
 
601
 
                case SQL_PROCEDURE_TERM:                /* ODBC 1.0 */
602
 
                        p = "procedure";
603
 
                        break;
604
 
 
605
 
                case SQL_PROCEDURES:    /* ODBC 1.0 */
606
 
                        p = "Y";
607
 
                        break;
608
 
 
609
 
                case SQL_QUALIFIER_LOCATION:    /* ODBC 2.0 */
610
 
                        len = 2;
611
 
                        if (CurrCat(conn))
612
 
                                value = SQL_QL_START;
613
 
                        else
614
 
                                value = 0;
615
 
                        break;
616
 
 
617
 
                case SQL_QUALIFIER_NAME_SEPARATOR:              /* ODBC 1.0 */
618
 
                        if (CurrCat(conn))
619
 
                                p = ".";
620
 
                        else
621
 
                                p = NULL_STRING;
622
 
                        break;
623
 
 
624
 
                case SQL_QUALIFIER_TERM:                /* ODBC 1.0 */
625
 
                        if (CurrCat(conn))
626
 
                                p = "catalog";
627
 
                        else
628
 
                                p = NULL_STRING;
629
 
                        break;
630
 
 
631
 
                case SQL_QUALIFIER_USAGE:               /* ODBC 2.0 */
632
 
                        len = 4;
633
 
#if (ODBCVER >= 0x0300)
634
 
                        if (CurrCat(conn))
635
 
                                value = SQL_CU_DML_STATEMENTS;
636
 
                        else
637
 
#endif /* ODBCVER */
638
 
                                value = 0;
639
 
                        break;
640
 
 
641
 
                case SQL_QUOTED_IDENTIFIER_CASE:                /* ODBC 2.0 */
642
 
                        /* are "quoted" identifiers case-sensitive?  YES! */
643
 
                        len = 2;
644
 
                        value = SQL_IC_SENSITIVE;
645
 
                        break;
646
 
 
647
 
                case SQL_ROW_UPDATES:   /* ODBC 1.0 */
648
 
 
649
 
                        /*
650
 
                         * Driver doesn't support keyset-driven or mixed cursors, so
651
 
                         * not much point in saying row updates are supported
652
 
                         */
653
 
                        p = (0 != ci->updatable_cursors) ? "Y" : "N";
654
 
                        break;
655
 
 
656
 
                case SQL_SCROLL_CONCURRENCY:    /* ODBC 1.0 */
657
 
                        len = 4;
658
 
                        value = SQL_SCCO_READ_ONLY;
659
 
                        if (0 != ci->updatable_cursors)
660
 
                                value |= SQL_SCCO_OPT_ROWVER;
661
 
                        if (ci->drivers.lie)
662
 
                                value |= (SQL_SCCO_LOCK | SQL_SCCO_OPT_VALUES);
663
 
                        break;
664
 
 
665
 
                case SQL_SCROLL_OPTIONS:                /* ODBC 1.0 */
666
 
                        len = 4;
667
 
                        value = SQL_SO_FORWARD_ONLY | SQL_SO_STATIC;
668
 
                        if (0 != (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
669
 
                                value |= SQL_SO_KEYSET_DRIVEN;
670
 
                        if (ci->drivers.lie)
671
 
                                value |= (SQL_SO_DYNAMIC | SQL_SO_MIXED);
672
 
                        break;
673
 
 
674
 
                case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */
675
 
                        if (PG_VERSION_GE(conn, 6.5))
676
 
                                p = "\\";
677
 
                        else
678
 
                                p = NULL_STRING;
679
 
                        break;
680
 
 
681
 
                case SQL_SERVER_NAME:   /* ODBC 1.0 */
682
 
                        p = CC_get_server(conn);
683
 
                        break;
684
 
 
685
 
                case SQL_SPECIAL_CHARACTERS:    /* ODBC 2.0 */
686
 
                        p = "_";
687
 
                        break;
688
 
 
689
 
                case SQL_STATIC_SENSITIVITY:    /* ODBC 2.0 */
690
 
                        len = 4;
691
 
                        value = 0;
692
 
                        if (0 != ci->updatable_cursors)
693
 
                                value |= (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES);
694
 
                        break;
695
 
 
696
 
                case SQL_STRING_FUNCTIONS:              /* ODBC 1.0 */
697
 
                        len = 4;
698
 
                        value = (SQL_FN_STR_CONCAT |
699
 
                                         SQL_FN_STR_LCASE |
700
 
                                         SQL_FN_STR_LENGTH |
701
 
                                         SQL_FN_STR_LOCATE |
702
 
                                         SQL_FN_STR_LTRIM |
703
 
                                         SQL_FN_STR_RTRIM |
704
 
                                         SQL_FN_STR_SUBSTRING |
705
 
                                         SQL_FN_STR_UCASE);
706
 
                        break;
707
 
 
708
 
                case SQL_SUBQUERIES:    /* ODBC 2.0 */
709
 
                        /* postgres 6.3 supports subqueries */
710
 
                        len = 4;
711
 
                        value = (SQL_SQ_QUANTIFIED |
712
 
                                         SQL_SQ_IN |
713
 
                                         SQL_SQ_EXISTS |
714
 
                                         SQL_SQ_COMPARISON);
715
 
                        break;
716
 
 
717
 
                case SQL_SYSTEM_FUNCTIONS:              /* ODBC 1.0 */
718
 
                        len = 4;
719
 
                        value = 0;
720
 
                        break;
721
 
 
722
 
                case SQL_TABLE_TERM:    /* ODBC 1.0 */
723
 
                        p = "table";
724
 
                        break;
725
 
 
726
 
                case SQL_TIMEDATE_ADD_INTERVALS:                /* ODBC 2.0 */
727
 
                        len = 4;
728
 
                        value = 0;
729
 
                        break;
730
 
 
731
 
                case SQL_TIMEDATE_DIFF_INTERVALS:               /* ODBC 2.0 */
732
 
                        len = 4;
733
 
                        value = 0;
734
 
                        break;
735
 
 
736
 
                case SQL_TIMEDATE_FUNCTIONS:    /* ODBC 1.0 */
737
 
                        len = 4;
738
 
                        value = (SQL_FN_TD_NOW);
739
 
                        break;
740
 
 
741
 
                case SQL_TXN_CAPABLE:   /* ODBC 1.0 */
742
 
 
743
 
                        /*
744
 
                         * Postgres can deal with create or drop table statements in a
745
 
                         * transaction
746
 
                         */
747
 
                        len = 2;
748
 
                        value = SQL_TC_ALL;
749
 
                        break;
750
 
 
751
 
                case SQL_TXN_ISOLATION_OPTION:  /* ODBC 1.0 */
752
 
                        len = 4;
753
 
                        if (PG_VERSION_LT(conn, 6.5))
754
 
                                value = SQL_TXN_SERIALIZABLE;
755
 
                        else if (PG_VERSION_GE(conn, 7.1))
756
 
                                value = SQL_TXN_READ_COMMITTED | SQL_TXN_SERIALIZABLE;
757
 
                        else
758
 
                                value = SQL_TXN_READ_COMMITTED;
759
 
                        break;
760
 
 
761
 
                case SQL_UNION: /* ODBC 2.0 */
762
 
                        /* unions with all supported in postgres 6.3 */
763
 
                        len = 4;
764
 
                        value = (SQL_U_UNION | SQL_U_UNION_ALL);
765
 
                        break;
766
 
 
767
 
                case SQL_USER_NAME:             /* ODBC 1.0 */
768
 
                        p = CC_get_username(conn);
769
 
                        break;
770
 
 
771
 
                default:
772
 
                        /* unrecognized key */
773
 
                        CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Unrecognized key passed to PGAPI_GetInfo.", NULL);
774
 
                        goto cleanup;
775
 
        }
776
 
 
777
 
        result = SQL_SUCCESS;
778
 
 
779
 
        mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func, p ? p : "<NULL>", len, value, cbInfoValueMax);
780
 
 
781
 
        /*
782
 
         * NOTE, that if rgbInfoValue is NULL, then no warnings or errors
783
 
         * should result and just pcbInfoValue is returned, which indicates
784
 
         * what length would be required if a real buffer had been passed in.
785
 
         */
786
 
        if (p)
787
 
        {
788
 
                /* char/binary data */
789
 
                len = strlen(p);
790
 
 
791
 
                if (rgbInfoValue)
792
 
                {
793
 
#ifdef  UNICODE_SUPPORT
794
 
                        if (CC_is_in_unicode_driver(conn))
795
 
                        {
796
 
                                len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / WCLEN);
797
 
                                len *= WCLEN;
798
 
                        }
799
 
                        else
800
 
#endif /* UNICODE_SUPPORT */
801
 
                        strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax);
802
 
 
803
 
                        if (len >= cbInfoValueMax)
804
 
                        {
805
 
                                result = SQL_SUCCESS_WITH_INFO;
806
 
                                CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the InfoValue.", func);
807
 
                        }
808
 
                }
809
 
#ifdef  UNICODE_SUPPORT
810
 
                else if (CC_is_in_unicode_driver(conn))
811
 
                        len *= WCLEN;
812
 
#endif /* UNICODE_SUPPORT */
813
 
        }
814
 
        else
815
 
        {
816
 
                /* numeric data */
817
 
                if (rgbInfoValue)
818
 
                {
819
 
                        if (len == sizeof(SQLSMALLINT))
820
 
                                *((SQLUSMALLINT *) rgbInfoValue) = (SQLUSMALLINT) value;
821
 
                        else if (len == sizeof(SQLINTEGER))
822
 
                                *((SQLUINTEGER *) rgbInfoValue) = (SQLUINTEGER) value;
823
 
                }
824
 
        }
825
 
 
826
 
        if (pcbInfoValue)
827
 
                *pcbInfoValue = (SQLSMALLINT) len;
828
 
cleanup:
829
 
 
830
 
        return result;
831
 
}
832
 
 
833
 
 
834
 
RETCODE         SQL_API
835
 
PGAPI_GetTypeInfo(
836
 
                                  HSTMT hstmt,
837
 
                                  SQLSMALLINT fSqlType)
838
 
{
839
 
        CSTR func = "PGAPI_GetTypeInfo";
840
 
        StatementClass *stmt = (StatementClass *) hstmt;
841
 
        ConnectionClass *conn;
842
 
        QResultClass    *res = NULL;
843
 
        TupleField      *tuple;
844
 
        int                     i, result_cols;
845
 
 
846
 
        /* Int4 type; */
847
 
        Int4            pgType;
848
 
        Int2            sqlType;
849
 
        RETCODE         result = SQL_SUCCESS;
850
 
 
851
 
        mylog("%s: entering...fSqlType = %d\n", func, fSqlType);
852
 
 
853
 
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
854
 
                return result;
855
 
 
856
 
        conn = SC_get_conn(stmt);
857
 
        if (res = QR_Constructor(), !res)
858
 
        {
859
 
                SC_set_error(stmt, STMT_INTERNAL_ERROR, "Error creating result.", func);
860
 
                return SQL_ERROR;
861
 
        }
862
 
        SC_set_Result(stmt, res);
863
 
 
864
 
#define return  DONT_CALL_RETURN_FROM_HERE???
865
 
#if (ODBCVER >= 0x0300)
866
 
        result_cols = 19;
867
 
#else
868
 
        result_cols = 15;
869
 
#endif /* ODBCVER */
870
 
        extend_column_bindings(SC_get_ARDF(stmt), result_cols);
871
 
 
872
 
        stmt->catalog_result = TRUE;
873
 
        QR_set_num_fields(res, result_cols);
874
 
        QR_set_field_info_v(res, 0, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
875
 
        QR_set_field_info_v(res, 1, "DATA_TYPE", PG_TYPE_INT2, 2);
876
 
        QR_set_field_info_v(res, 2, "PRECISION", PG_TYPE_INT4, 4);
877
 
        QR_set_field_info_v(res, 3, "LITERAL_PREFIX", PG_TYPE_VARCHAR, MAX_INFO_STRING);
878
 
        QR_set_field_info_v(res, 4, "LITERAL_SUFFIX", PG_TYPE_VARCHAR, MAX_INFO_STRING);
879
 
        QR_set_field_info_v(res, 5, "CREATE_PARAMS", PG_TYPE_VARCHAR, MAX_INFO_STRING);
880
 
        QR_set_field_info_v(res, 6, "NULLABLE", PG_TYPE_INT2, 2);
881
 
        QR_set_field_info_v(res, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2);
882
 
        QR_set_field_info_v(res, 8, "SEARCHABLE", PG_TYPE_INT2, 2);
883
 
        QR_set_field_info_v(res, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2);
884
 
        QR_set_field_info_v(res, 10, "MONEY", PG_TYPE_INT2, 2);
885
 
        QR_set_field_info_v(res, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2);
886
 
        QR_set_field_info_v(res, 12, "LOCAL_TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
887
 
        QR_set_field_info_v(res, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
888
 
        QR_set_field_info_v(res, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
889
 
#if (ODBCVER >=0x0300)
890
 
        QR_set_field_info_v(res, 15, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
891
 
        QR_set_field_info_v(res, 16, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
892
 
        QR_set_field_info_v(res, 17, "NUM_PREC_RADIX", PG_TYPE_INT4, 4);
893
 
        QR_set_field_info_v(res, 18, "INTERVAL_PRECISION", PG_TYPE_INT2, 2);
894
 
#endif /* ODBCVER */
895
 
 
896
 
        for (i = 0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i])
897
 
        {
898
 
                pgType = sqltype_to_pgtype(conn, sqlType);
899
 
 
900
 
if (sqlType == SQL_LONGVARBINARY)
901
 
{
902
 
ConnInfo        *ci = &(conn->connInfo);
903
 
inolog("%d sqltype=%d -> pgtype=%d\n", ci->bytea_as_longvarbinary, sqlType, pgType);
904
 
}
905
 
 
906
 
                if (fSqlType == SQL_ALL_TYPES || fSqlType == sqlType)
907
 
                {
908
 
                        int     pgtcount = 1, aunq_match = -1, cnt;
909
 
 
910
 
                        /*if (SQL_INTEGER == sqlType || SQL_TINYINT == sqlType)*/
911
 
                        if (SQL_INTEGER == sqlType)
912
 
                        {
913
 
mylog("sqlType=%d ms_jet=%d\n", sqlType, conn->ms_jet);
914
 
                                if (conn->ms_jet && PG_VERSION_GE(conn, 6.4))
915
 
                                {
916
 
                                        aunq_match = 1;
917
 
                                        pgtcount = 2;
918
 
                                }
919
 
mylog("aunq_match=%d pgtcount=%d\n", aunq_match, pgtcount);
920
 
                        }
921
 
                        for (cnt = 0; cnt < pgtcount; cnt ++)
922
 
                        {
923
 
                                if (tuple = QR_AddNew(res), NULL == tuple)
924
 
                                {
925
 
                                        result = SQL_ERROR;
926
 
                                        SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't QR_AddNew.", func);
927
 
                                        goto cleanup;
928
 
                                }
929
 
 
930
 
                                /* These values can't be NULL */
931
 
                                if (aunq_match == cnt)
932
 
                                {
933
 
                                        set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, PG_UNSPECIFIED, TRUE));
934
 
                                        set_tuplefield_int2(&tuple[6], SQL_NO_NULLS);
935
 
inolog("serial in\n");
936
 
                                }
937
 
                                else
938
 
                                {
939
 
                                        set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, PG_UNSPECIFIED, FALSE));
940
 
                                        set_tuplefield_int2(&tuple[6], pgtype_nullable(conn, pgType));
941
 
                                }
942
 
                                set_tuplefield_int2(&tuple[1], (Int2) sqlType);
943
 
                                set_tuplefield_int2(&tuple[7], pgtype_case_sensitive(conn, pgType));
944
 
                                set_tuplefield_int2(&tuple[8], pgtype_searchable(conn, pgType));
945
 
                                set_tuplefield_int2(&tuple[10], pgtype_money(conn, pgType));
946
 
 
947
 
                        /*
948
 
                         * Localized data-source dependent data type name (always
949
 
                         * NULL)
950
 
                         */
951
 
                                set_tuplefield_null(&tuple[12]);
952
 
 
953
 
                                /* These values can be NULL */
954
 
                                set_nullfield_int4(&tuple[2], pgtype_column_size(stmt, pgType, PG_STATIC, UNKNOWNS_AS_DEFAULT));
955
 
                                set_nullfield_string(&tuple[3], pgtype_literal_prefix(conn, pgType));
956
 
                                set_nullfield_string(&tuple[4], pgtype_literal_suffix(conn, pgType));
957
 
                                set_nullfield_string(&tuple[5], pgtype_create_params(conn, pgType));
958
 
                                if (1 < pgtcount)
959
 
                                        set_tuplefield_int2(&tuple[9], SQL_TRUE);
960
 
                                else
961
 
                                        set_nullfield_int2(&tuple[9], pgtype_unsigned(conn, pgType));
962
 
                                if (aunq_match == cnt)
963
 
                                        set_tuplefield_int2(&tuple[11], SQL_TRUE);
964
 
                                else
965
 
                                        set_nullfield_int2(&tuple[11], pgtype_auto_increment(conn, pgType));
966
 
                                set_nullfield_int2(&tuple[13], pgtype_min_decimal_digits(conn, pgType));
967
 
                                set_nullfield_int2(&tuple[14], pgtype_max_decimal_digits(conn, pgType));
968
 
#if (ODBCVER >=0x0300)
969
 
                                set_nullfield_int2(&tuple[15], pgtype_to_sqldesctype(stmt, pgType, PG_STATIC));
970
 
                                set_nullfield_int2(&tuple[16], pgtype_to_datetime_sub(stmt, pgType, PG_UNSPECIFIED));
971
 
                                set_nullfield_int4(&tuple[17], pgtype_radix(conn, pgType));
972
 
                                set_nullfield_int4(&tuple[18], 0);
973
 
#endif /* ODBCVER */
974
 
                        }
975
 
                }
976
 
        }
977
 
 
978
 
cleanup:
979
 
#undef  return
980
 
        /*
981
 
         * also, things need to think that this statement is finished so the
982
 
         * results can be retrieved.
983
 
         */
984
 
        stmt->status = STMT_FINISHED;
985
 
        stmt->currTuple = -1;
986
 
        if (SQL_SUCCEEDED(result))
987
 
                SC_set_rowset_start(stmt, -1, FALSE);
988
 
        else
989
 
                SC_set_Result(stmt, NULL);
990
 
        SC_set_current_col(stmt, -1);
991
 
 
992
 
        if (stmt->internal)
993
 
                result = DiscardStatementSvp(stmt, result, FALSE);
994
 
        return result;
995
 
}
996
 
 
997
 
 
998
 
RETCODE         SQL_API
999
 
PGAPI_GetFunctions(
1000
 
                                   HDBC hdbc,
1001
 
                                   SQLUSMALLINT fFunction,
1002
 
                                   SQLUSMALLINT FAR * pfExists)
1003
 
{
1004
 
        CSTR func = "PGAPI_GetFunctions";
1005
 
        ConnectionClass *conn = (ConnectionClass *) hdbc;
1006
 
        ConnInfo   *ci = &(conn->connInfo);
1007
 
 
1008
 
        mylog("%s: entering...%u\n", func, fFunction);
1009
 
 
1010
 
        if (fFunction == SQL_API_ALL_FUNCTIONS)
1011
 
        {
1012
 
#if (ODBCVER < 0x0300)
1013
 
                if (ci->drivers.lie)
1014
 
                {
1015
 
                        int                     i;
1016
 
 
1017
 
                        memset(pfExists, 0, sizeof(pfExists[0]) * 100);
1018
 
 
1019
 
                        pfExists[SQL_API_SQLALLOCENV] = TRUE;
1020
 
                        pfExists[SQL_API_SQLFREEENV] = TRUE;
1021
 
                        for (i = SQL_API_SQLALLOCCONNECT; i <= SQL_NUM_FUNCTIONS; i++)
1022
 
                                pfExists[i] = TRUE;
1023
 
                        for (i = SQL_EXT_API_START; i <= SQL_EXT_API_LAST; i++)
1024
 
                                pfExists[i] = TRUE;
1025
 
                }
1026
 
                else
1027
 
#endif
1028
 
                {
1029
 
                        memset(pfExists, 0, sizeof(pfExists[0]) * 100);
1030
 
 
1031
 
                        /* ODBC core functions */
1032
 
                        pfExists[SQL_API_SQLALLOCCONNECT] = TRUE;
1033
 
                        pfExists[SQL_API_SQLALLOCENV] = TRUE;
1034
 
                        pfExists[SQL_API_SQLALLOCSTMT] = TRUE;
1035
 
                        pfExists[SQL_API_SQLBINDCOL] = TRUE;
1036
 
                        pfExists[SQL_API_SQLCANCEL] = TRUE;
1037
 
                        pfExists[SQL_API_SQLCOLATTRIBUTES] = TRUE;
1038
 
                        pfExists[SQL_API_SQLCONNECT] = TRUE;
1039
 
                        pfExists[SQL_API_SQLDESCRIBECOL] = TRUE;        /* partial */
1040
 
                        pfExists[SQL_API_SQLDISCONNECT] = TRUE;
1041
 
                        pfExists[SQL_API_SQLERROR] = TRUE;
1042
 
                        pfExists[SQL_API_SQLEXECDIRECT] = TRUE;
1043
 
                        pfExists[SQL_API_SQLEXECUTE] = TRUE;
1044
 
                        pfExists[SQL_API_SQLFETCH] = TRUE;
1045
 
                        pfExists[SQL_API_SQLFREECONNECT] = TRUE;
1046
 
                        pfExists[SQL_API_SQLFREEENV] = TRUE;
1047
 
                        pfExists[SQL_API_SQLFREESTMT] = TRUE;
1048
 
                        pfExists[SQL_API_SQLGETCURSORNAME] = TRUE;
1049
 
                        pfExists[SQL_API_SQLNUMRESULTCOLS] = TRUE;
1050
 
                        pfExists[SQL_API_SQLPREPARE] = TRUE;            /* complete? */
1051
 
                        pfExists[SQL_API_SQLROWCOUNT] = TRUE;
1052
 
                        pfExists[SQL_API_SQLSETCURSORNAME] = TRUE;
1053
 
                        pfExists[SQL_API_SQLSETPARAM] = FALSE;          /* odbc 1.0 */
1054
 
                        pfExists[SQL_API_SQLTRANSACT] = TRUE;
1055
 
 
1056
 
                        /* ODBC level 1 functions */
1057
 
                        pfExists[SQL_API_SQLBINDPARAMETER] = TRUE;
1058
 
                        pfExists[SQL_API_SQLCOLUMNS] = TRUE;
1059
 
                        pfExists[SQL_API_SQLDRIVERCONNECT] = TRUE;
1060
 
                        pfExists[SQL_API_SQLGETCONNECTOPTION] = TRUE;           /* partial */
1061
 
                        pfExists[SQL_API_SQLGETDATA] = TRUE;
1062
 
                        pfExists[SQL_API_SQLGETFUNCTIONS] = TRUE;
1063
 
                        pfExists[SQL_API_SQLGETINFO] = TRUE;
1064
 
                        pfExists[SQL_API_SQLGETSTMTOPTION] = TRUE;      /* partial */
1065
 
                        pfExists[SQL_API_SQLGETTYPEINFO] = TRUE;
1066
 
                        pfExists[SQL_API_SQLPARAMDATA] = TRUE;
1067
 
                        pfExists[SQL_API_SQLPUTDATA] = TRUE;
1068
 
                        pfExists[SQL_API_SQLSETCONNECTOPTION] = TRUE;           /* partial */
1069
 
                        pfExists[SQL_API_SQLSETSTMTOPTION] = TRUE;
1070
 
                        pfExists[SQL_API_SQLSPECIALCOLUMNS] = TRUE;
1071
 
                        pfExists[SQL_API_SQLSTATISTICS] = TRUE;
1072
 
                        pfExists[SQL_API_SQLTABLES] = TRUE;
1073
 
 
1074
 
                        /* ODBC level 2 functions */
1075
 
                        pfExists[SQL_API_SQLBROWSECONNECT] = FALSE;
1076
 
                        if (PG_VERSION_GE(conn, 7.4))
1077
 
                                pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
1078
 
                        else
1079
 
                                pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
1080
 
                        pfExists[SQL_API_SQLDATASOURCES] = FALSE;       /* only implemented by
1081
 
                                                                                                                 * DM */
1082
 
                        if (SUPPORT_DESCRIBE_PARAM(ci))
1083
 
                                pfExists[SQL_API_SQLDESCRIBEPARAM] = TRUE;
1084
 
                        else
1085
 
                                pfExists[SQL_API_SQLDESCRIBEPARAM] = FALSE; /* not properly
1086
 
                                                                                                                 * implemented */
1087
 
                        pfExists[SQL_API_SQLDRIVERS] = FALSE;           /* only implemented by
1088
 
                                                                                                                 * DM */
1089
 
                        pfExists[SQL_API_SQLEXTENDEDFETCH] = TRUE;
1090
 
                        pfExists[SQL_API_SQLFOREIGNKEYS] = TRUE;
1091
 
                        pfExists[SQL_API_SQLMORERESULTS] = TRUE;
1092
 
                        pfExists[SQL_API_SQLNATIVESQL] = TRUE;
1093
 
                        pfExists[SQL_API_SQLNUMPARAMS] = TRUE;
1094
 
                        pfExists[SQL_API_SQLPARAMOPTIONS] = TRUE;
1095
 
                        pfExists[SQL_API_SQLPRIMARYKEYS] = TRUE;
1096
 
                        if (PG_VERSION_LT(conn, 6.5))
1097
 
                                pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE;
1098
 
                        else
1099
 
                                pfExists[SQL_API_SQLPROCEDURECOLUMNS] = TRUE;
1100
 
                        if (PG_VERSION_LT(conn, 6.5))
1101
 
                                pfExists[SQL_API_SQLPROCEDURES] = FALSE;
1102
 
                        else
1103
 
                                pfExists[SQL_API_SQLPROCEDURES] = TRUE;
1104
 
                        pfExists[SQL_API_SQLSETPOS] = TRUE;
1105
 
                        pfExists[SQL_API_SQLSETSCROLLOPTIONS] = TRUE;           /* odbc 1.0 */
1106
 
                        pfExists[SQL_API_SQLTABLEPRIVILEGES] = TRUE;
1107
 
#if (ODBCVER >= 0x0300)
1108
 
                        if (0 == ci->updatable_cursors)
1109
 
                                pfExists[SQL_API_SQLBULKOPERATIONS] = FALSE;
1110
 
                        else
1111
 
                                pfExists[SQL_API_SQLBULKOPERATIONS] = TRUE;
1112
 
#endif /* ODBCVER */
1113
 
                }
1114
 
        }
1115
 
        else
1116
 
        {
1117
 
                if (ci->drivers.lie)
1118
 
                        *pfExists = TRUE;
1119
 
                else
1120
 
                {
1121
 
                        switch (fFunction)
1122
 
                        {
1123
 
#if (ODBCVER < 0x0300)
1124
 
                                case SQL_API_SQLALLOCCONNECT:
1125
 
                                        *pfExists = TRUE;
1126
 
                                        break;
1127
 
                                case SQL_API_SQLALLOCENV:
1128
 
                                        *pfExists = TRUE;
1129
 
                                        break;
1130
 
                                case SQL_API_SQLALLOCSTMT:
1131
 
                                        *pfExists = TRUE;
1132
 
                                        break;
1133
 
#endif /* ODBCVER */
1134
 
                                case SQL_API_SQLBINDCOL:
1135
 
                                        *pfExists = TRUE;
1136
 
                                        break;
1137
 
                                case SQL_API_SQLCANCEL:
1138
 
                                        *pfExists = TRUE;
1139
 
                                        break;
1140
 
#if (ODBCVER >= 0x0300)
1141
 
                                case SQL_API_SQLCOLATTRIBUTE:
1142
 
#else
1143
 
                                case SQL_API_SQLCOLATTRIBUTES:
1144
 
#endif /* ODBCVER */
1145
 
                                        *pfExists = TRUE;
1146
 
                                        break;
1147
 
                                case SQL_API_SQLCONNECT:
1148
 
                                        *pfExists = TRUE;
1149
 
                                        break;
1150
 
                                case SQL_API_SQLDESCRIBECOL:
1151
 
                                        *pfExists = TRUE;
1152
 
                                        break;          /* partial */
1153
 
                                case SQL_API_SQLDISCONNECT:
1154
 
                                        *pfExists = TRUE;
1155
 
                                        break;
1156
 
#if (ODBCVER < 0x0300)
1157
 
                                case SQL_API_SQLERROR:
1158
 
                                        *pfExists = TRUE;
1159
 
                                        break;
1160
 
#endif /* ODBCVER */
1161
 
                                case SQL_API_SQLEXECDIRECT:
1162
 
                                        *pfExists = TRUE;
1163
 
                                        break;
1164
 
                                case SQL_API_SQLEXECUTE:
1165
 
                                        *pfExists = TRUE;
1166
 
                                        break;
1167
 
                                case SQL_API_SQLFETCH:
1168
 
                                        *pfExists = TRUE;
1169
 
                                        break;
1170
 
#if (ODBCVER < 0x0300)
1171
 
                                case SQL_API_SQLFREECONNECT:
1172
 
                                        *pfExists = TRUE;
1173
 
                                        break;
1174
 
                                case SQL_API_SQLFREEENV:
1175
 
                                        *pfExists = TRUE;
1176
 
                                        break;
1177
 
#endif /* ODBCVER */
1178
 
                                case SQL_API_SQLFREESTMT:
1179
 
                                        *pfExists = TRUE;
1180
 
                                        break;
1181
 
                                case SQL_API_SQLGETCURSORNAME:
1182
 
                                        *pfExists = TRUE;
1183
 
                                        break;
1184
 
                                case SQL_API_SQLNUMRESULTCOLS:
1185
 
                                        *pfExists = TRUE;
1186
 
                                        break;
1187
 
                                case SQL_API_SQLPREPARE:
1188
 
                                        *pfExists = TRUE;
1189
 
                                        break;
1190
 
                                case SQL_API_SQLROWCOUNT:
1191
 
                                        *pfExists = TRUE;
1192
 
                                        break;
1193
 
                                case SQL_API_SQLSETCURSORNAME:
1194
 
                                        *pfExists = TRUE;
1195
 
                                        break;
1196
 
#if (ODBCVER < 0x0300)
1197
 
                                case SQL_API_SQLSETPARAM:
1198
 
                                        *pfExists = FALSE;
1199
 
                                        break;          /* odbc 1.0 */
1200
 
                                case SQL_API_SQLTRANSACT:
1201
 
                                        *pfExists = TRUE;
1202
 
                                        break;
1203
 
#endif /* ODBCVER */
1204
 
 
1205
 
                                        /* ODBC level 1 functions */
1206
 
                                case SQL_API_SQLBINDPARAMETER:
1207
 
                                        *pfExists = TRUE;
1208
 
                                        break;
1209
 
                                case SQL_API_SQLCOLUMNS:
1210
 
                                        *pfExists = TRUE;
1211
 
                                        break;
1212
 
                                case SQL_API_SQLDRIVERCONNECT:
1213
 
                                        *pfExists = TRUE;
1214
 
                                        break;
1215
 
#if (ODBCVER < 0x0300)
1216
 
                                case SQL_API_SQLGETCONNECTOPTION:
1217
 
                                        *pfExists = TRUE;
1218
 
                                        break;          /* partial */
1219
 
#endif /* ODBCVER */
1220
 
                                case SQL_API_SQLGETDATA:
1221
 
                                        *pfExists = TRUE;
1222
 
                                        break;
1223
 
                                case SQL_API_SQLGETFUNCTIONS:
1224
 
                                        *pfExists = TRUE;
1225
 
                                        break;
1226
 
                                case SQL_API_SQLGETINFO:
1227
 
                                        *pfExists = TRUE;
1228
 
                                        break;
1229
 
#if (ODBCVER < 0x0300)
1230
 
                                case SQL_API_SQLGETSTMTOPTION:
1231
 
                                        *pfExists = TRUE;
1232
 
                                        break;          /* partial */
1233
 
#endif /* ODBCVER */
1234
 
                                case SQL_API_SQLGETTYPEINFO:
1235
 
                                        *pfExists = TRUE;
1236
 
                                        break;
1237
 
                                case SQL_API_SQLPARAMDATA:
1238
 
                                        *pfExists = TRUE;
1239
 
                                        break;
1240
 
                                case SQL_API_SQLPUTDATA:
1241
 
                                        *pfExists = TRUE;
1242
 
                                        break;
1243
 
#if (ODBCVER < 0x0300)
1244
 
                                case SQL_API_SQLSETCONNECTOPTION:
1245
 
                                        *pfExists = TRUE;
1246
 
                                        break;          /* partial */
1247
 
                                case SQL_API_SQLSETSTMTOPTION:
1248
 
                                        *pfExists = TRUE;
1249
 
                                        break;
1250
 
#endif /* ODBCVER */
1251
 
                                case SQL_API_SQLSPECIALCOLUMNS:
1252
 
                                        *pfExists = TRUE;
1253
 
                                        break;
1254
 
                                case SQL_API_SQLSTATISTICS:
1255
 
                                        *pfExists = TRUE;
1256
 
                                        break;
1257
 
                                case SQL_API_SQLTABLES:
1258
 
                                        *pfExists = TRUE;
1259
 
                                        break;
1260
 
 
1261
 
                                        /* ODBC level 2 functions */
1262
 
                                case SQL_API_SQLBROWSECONNECT:
1263
 
                                        *pfExists = FALSE;
1264
 
                                        break;
1265
 
                                case SQL_API_SQLCOLUMNPRIVILEGES:
1266
 
                                        *pfExists = FALSE;
1267
 
                                        break;
1268
 
                                case SQL_API_SQLDATASOURCES:
1269
 
                                        *pfExists = FALSE;
1270
 
                                        break;          /* only implemented by DM */
1271
 
                                case SQL_API_SQLDESCRIBEPARAM:
1272
 
                                        if (SUPPORT_DESCRIBE_PARAM(ci))
1273
 
                                                *pfExists = TRUE;
1274
 
                                        else
1275
 
                                                *pfExists = FALSE;
1276
 
                                        break;          /* not properly implemented */
1277
 
                                case SQL_API_SQLDRIVERS:
1278
 
                                        *pfExists = FALSE;
1279
 
                                        break;          /* only implemented by DM */
1280
 
                                case SQL_API_SQLEXTENDEDFETCH:
1281
 
                                        *pfExists = TRUE;
1282
 
                                        break;
1283
 
                                case SQL_API_SQLFOREIGNKEYS:
1284
 
                                        *pfExists = TRUE;
1285
 
                                        break;
1286
 
                                case SQL_API_SQLMORERESULTS:
1287
 
                                        *pfExists = TRUE;
1288
 
                                        break;
1289
 
                                case SQL_API_SQLNATIVESQL:
1290
 
                                        *pfExists = TRUE;
1291
 
                                        break;
1292
 
                                case SQL_API_SQLNUMPARAMS:
1293
 
                                        *pfExists = TRUE;
1294
 
                                        break;
1295
 
#if (ODBCVER < 0x0300)
1296
 
                                case SQL_API_SQLPARAMOPTIONS:
1297
 
                                        *pfExists = TRUE;
1298
 
                                        break;
1299
 
#endif /* ODBCVER */
1300
 
                                case SQL_API_SQLPRIMARYKEYS:
1301
 
                                        *pfExists = TRUE;
1302
 
                                        break;
1303
 
                                case SQL_API_SQLPROCEDURECOLUMNS:
1304
 
                                        if (PG_VERSION_LT(conn, 6.5))
1305
 
                                                *pfExists = FALSE;
1306
 
                                        else
1307
 
                                                *pfExists = TRUE;
1308
 
                                        break;
1309
 
                                case SQL_API_SQLPROCEDURES:
1310
 
                                        if (PG_VERSION_LT(conn, 6.5))
1311
 
                                                *pfExists = FALSE;
1312
 
                                        else
1313
 
                                                *pfExists = TRUE;
1314
 
                                        break;
1315
 
                                case SQL_API_SQLSETPOS:
1316
 
                                        *pfExists = TRUE;
1317
 
                                        break;
1318
 
#if (ODBCVER < 0x0300)
1319
 
                                case SQL_API_SQLSETSCROLLOPTIONS:
1320
 
                                        *pfExists = TRUE;
1321
 
                                        break;          /* odbc 1.0 */
1322
 
#endif /* ODBCVER */
1323
 
                                case SQL_API_SQLTABLEPRIVILEGES:
1324
 
                                        *pfExists = TRUE;
1325
 
                                        break;
1326
 
#if (ODBCVER >= 0x0300)
1327
 
                                case SQL_API_SQLBULKOPERATIONS: /* 24 */
1328
 
                                case SQL_API_SQLALLOCHANDLE:    /* 1001 */
1329
 
                                case SQL_API_SQLBINDPARAM:      /* 1002 */
1330
 
                                case SQL_API_SQLCLOSECURSOR:    /* 1003 */
1331
 
                                case SQL_API_SQLENDTRAN:        /* 1005 */
1332
 
                                case SQL_API_SQLFETCHSCROLL:    /* 1021 */
1333
 
                                case SQL_API_SQLFREEHANDLE:     /* 1006 */
1334
 
                                case SQL_API_SQLGETCONNECTATTR: /* 1007 */
1335
 
                                case SQL_API_SQLGETDESCFIELD:   /* 1008 */
1336
 
                                case SQL_API_SQLGETDIAGFIELD:   /* 1010 */
1337
 
                                case SQL_API_SQLGETDIAGREC:     /* 1011 */
1338
 
                                case SQL_API_SQLGETENVATTR:     /* 1012 */
1339
 
                                case SQL_API_SQLGETSTMTATTR:    /* 1014 */
1340
 
                                case SQL_API_SQLSETCONNECTATTR: /* 1016 */
1341
 
                                case SQL_API_SQLSETDESCFIELD:   /* 1017 */
1342
 
                                case SQL_API_SQLSETENVATTR:     /* 1019 */
1343
 
                                case SQL_API_SQLSETSTMTATTR:    /* 1020 */
1344
 
                                        *pfExists = TRUE;
1345
 
                                        break;
1346
 
                                case SQL_API_SQLGETDESCREC:     /* 1009 */
1347
 
                                case SQL_API_SQLSETDESCREC:     /* 1018 */
1348
 
                                case SQL_API_SQLCOPYDESC:       /* 1004 */
1349
 
                                        *pfExists = FALSE;
1350
 
                                        break;
1351
 
#endif /* ODBCVER */
1352
 
                                default:
1353
 
                                        *pfExists = FALSE;
1354
 
                                        break;
1355
 
                        }
1356
 
                }
1357
 
        }
1358
 
        return SQL_SUCCESS;
1359
 
}
1360
 
 
1361
 
 
1362
 
static char     *
1363
 
simpleCatalogEscape(const char *src, int srclen, int *result_len, const ConnectionClass *conn)
1364
 
{
1365
 
        int     i, outlen;
1366
 
        const char *in;
1367
 
        char    *dest = NULL, escape_ch = CC_get_escape(conn);
1368
 
        encoded_str     encstr;
1369
 
 
1370
 
        if (result_len)
1371
 
                *result_len = 0;
1372
 
        if (!src || srclen == SQL_NULL_DATA)
1373
 
                return dest;
1374
 
        else if (srclen == SQL_NTS)
1375
 
                srclen = (int) strlen(src);
1376
 
        if (srclen <= 0)
1377
 
                return dest;
1378
 
mylog("simple in=%s(%d)\n", src, srclen);
1379
 
        encoded_str_constr(&encstr, conn->ccsc, src);
1380
 
        dest = malloc(2 * srclen + 1);
1381
 
        for (i = 0, in = src, outlen = 0; i < srclen; i++, in++)
1382
 
        {
1383
 
                encoded_nextchar(&encstr);
1384
 
                if (ENCODE_STATUS(encstr) != 0)
1385
 
                {
1386
 
                        dest[outlen++] = *in;
1387
 
                        continue;
1388
 
                }
1389
 
                if (LITERAL_QUOTE == *in ||
1390
 
                    escape_ch == *in)
1391
 
                        dest[outlen++] = *in;
1392
 
                dest[outlen++] = *in;
1393
 
        }
1394
 
        dest[outlen] = '\0';
1395
 
        if (result_len)
1396
 
                *result_len = outlen;
1397
 
mylog("simple output=%s(%d)\n", dest, outlen);
1398
 
        return dest;
1399
 
}
1400
 
 
1401
 
/*
1402
 
 *      PostgreSQL needs 2 '\\' to escape '_' and '%'. 
1403
 
 */
1404
 
static char     *
1405
 
adjustLikePattern(const char *src, int srclen, char escape_ch, int *result_len, const ConnectionClass *conn)
1406
 
{
1407
 
        int     i, outlen;
1408
 
        const char *in;
1409
 
        char    *dest = NULL, escape_in_literal = CC_get_escape(conn);
1410
 
        BOOL    escape_in = FALSE;
1411
 
        encoded_str     encstr;
1412
 
 
1413
 
        if (result_len)
1414
 
                *result_len = 0;
1415
 
        if (!src || srclen == SQL_NULL_DATA)
1416
 
                return dest;
1417
 
        else if (srclen == SQL_NTS)
1418
 
                srclen = (int) strlen(src);
1419
 
        /* if (srclen <= 0) */
1420
 
        if (srclen < 0)
1421
 
                return dest;
1422
 
mylog("adjust in=%.*s(%d)\n", srclen, src, srclen);
1423
 
        encoded_str_constr(&encstr, conn->ccsc, src);
1424
 
        dest = malloc(2 * srclen + 1);
1425
 
        for (i = 0, in = src, outlen = 0; i < srclen; i++, in++)
1426
 
        {
1427
 
                encoded_nextchar(&encstr);
1428
 
                if (ENCODE_STATUS(encstr) != 0)
1429
 
                {
1430
 
                        dest[outlen++] = *in;
1431
 
                        continue;
1432
 
                }
1433
 
                if (escape_in)
1434
 
                {
1435
 
                        switch (*in)
1436
 
                        {
1437
 
                                case '%':
1438
 
                                case '_':
1439
 
                                        break;
1440
 
                                default:
1441
 
                                        if (escape_ch == escape_in_literal)
1442
 
                                                dest[outlen++] = escape_in_literal;
1443
 
                                        dest[outlen++] = escape_ch;
1444
 
                                        break;
1445
 
                        }
1446
 
                }
1447
 
                if (*in == escape_ch)
1448
 
                {
1449
 
                        escape_in = TRUE;
1450
 
                        if (escape_ch == escape_in_literal)
1451
 
                                dest[outlen++] = escape_in_literal; /* insert 1 more LEXER escape */
1452
 
                }
1453
 
                else
1454
 
                {
1455
 
                        escape_in = FALSE;
1456
 
                        if (LITERAL_QUOTE == *in)
1457
 
                                dest[outlen++] = *in;
1458
 
                }
1459
 
                dest[outlen++] = *in;
1460
 
        }
1461
 
        if (escape_in)
1462
 
        {
1463
 
                if (escape_ch == escape_in_literal)
1464
 
                        dest[outlen++] = escape_in_literal;
1465
 
                dest[outlen++] = escape_ch;
1466
 
        }
1467
 
        dest[outlen] = '\0';
1468
 
        if (result_len)
1469
 
                *result_len = outlen;
1470
 
mylog("adjust output=%s(%d)\n", dest, outlen);
1471
 
        return dest;
1472
 
}
1473
 
 
1474
 
#define CSTR_SYS_TABLE  "SYSTEM TABLE"
1475
 
#define CSTR_TABLE      "TABLE"
1476
 
#define CSTR_VIEW       "VIEW"
1477
 
 
1478
 
CSTR    like_op_sp =    "like ";
1479
 
CSTR    like_op_ext =   "like E";
1480
 
CSTR    eq_op_sp =      "= ";
1481
 
CSTR    eq_op_ext =     "= E";
1482
 
static const char *gen_opestr(const char *orig_opestr, const ConnectionClass * conn)
1483
 
{
1484
 
        BOOL    addE = (0 != CC_get_escape(conn) && PG_VERSION_GE(conn, 8.1));
1485
 
 
1486
 
        if (0 == strcmp(orig_opestr, eqop))
1487
 
                return (addE ? eq_op_ext : eq_op_sp);
1488
 
        return (addE ? like_op_ext : like_op_sp);
1489
 
}
1490
 
 
1491
 
/*
1492
 
 *      If specified schema name == user_name and the current schema is
1493
 
 *      'public', allowed to use the 'public' schema.
1494
 
 */
1495
 
static BOOL
1496
 
allow_public_schema(ConnectionClass *conn, const char *szSchemaName, SQLSMALLINT cbSchemaName)
1497
 
{
1498
 
        const char *user = CC_get_username(conn);
1499
 
        size_t  userlen = strlen(user);
1500
 
 
1501
 
        if (NULL == szSchemaName)
1502
 
                return FALSE;
1503
 
 
1504
 
        if (SQL_NTS == cbSchemaName)
1505
 
                cbSchemaName = strlen(szSchemaName);
1506
 
 
1507
 
        return (cbSchemaName == (SQLSMALLINT) userlen &&
1508
 
                strnicmp(szSchemaName, user, userlen) == 0 &&
1509
 
                stricmp(CC_get_current_schema(conn), pubstr) == 0);
1510
 
}
1511
 
 
1512
 
RETCODE         SQL_API
1513
 
PGAPI_Tables(
1514
 
                         HSTMT hstmt,
1515
 
                         const SQLCHAR FAR * szTableQualifier, /* PV X*/
1516
 
                         SQLSMALLINT cbTableQualifier,
1517
 
                         const SQLCHAR FAR * szTableOwner, /* PV E*/
1518
 
                         SQLSMALLINT cbTableOwner,
1519
 
                         const SQLCHAR FAR * szTableName, /* PV E*/
1520
 
                         SQLSMALLINT cbTableName,
1521
 
                         const SQLCHAR FAR * szTableType,
1522
 
                         SQLSMALLINT cbTableType,
1523
 
                         UWORD  flag)
1524
 
{
1525
 
        CSTR func = "PGAPI_Tables";
1526
 
        StatementClass *stmt = (StatementClass *) hstmt;
1527
 
        StatementClass *tbl_stmt;
1528
 
        QResultClass    *res;
1529
 
        TupleField      *tuple;
1530
 
        HSTMT           htbl_stmt = NULL;
1531
 
        RETCODE         ret = SQL_ERROR, result;
1532
 
        int             result_cols;
1533
 
        char            *tableType = NULL;
1534
 
        char            tables_query[INFO_INQUIRY_LEN];
1535
 
        char            table_name[MAX_INFO_STRING],
1536
 
                                table_owner[MAX_INFO_STRING],
1537
 
                                relkind_or_hasrules[MAX_INFO_STRING];
1538
 
#ifdef  HAVE_STRTOK_R
1539
 
        char            *last;
1540
 
#endif /* HAVE_STRTOK_R */
1541
 
        ConnectionClass *conn;
1542
 
        ConnInfo   *ci;
1543
 
        char    *escCatName = NULL, *escSchemaName = NULL, *escTableName = NULL;
1544
 
        char       *prefix[32],
1545
 
                                prefixes[MEDIUM_REGISTRY_LEN];
1546
 
        char       *table_type[32],
1547
 
                                table_types[MAX_INFO_STRING];
1548
 
        char            show_system_tables,
1549
 
                                show_regular_tables,
1550
 
                                show_views;
1551
 
        char            regular_table,
1552
 
                                view,
1553
 
                                systable;
1554
 
        int                     i;
1555
 
        SQLSMALLINT             internal_asis_type = SQL_C_CHAR, cbSchemaName;
1556
 
        const char      *like_or_eq, *op_string;
1557
 
        const char      *szSchemaName;
1558
 
        BOOL            search_pattern;
1559
 
        BOOL            list_cat = FALSE, list_schemas = FALSE, list_table_types = FALSE, list_some = FALSE;
1560
 
        SQLLEN          cbRelname, cbRelkind, cbSchName;
1561
 
 
1562
 
        mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func, stmt, szTableOwner, cbTableOwner);
1563
 
 
1564
 
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
1565
 
                return result;
1566
 
 
1567
 
        conn = SC_get_conn(stmt);
1568
 
        ci = &(conn->connInfo);
1569
 
 
1570
 
        result = PGAPI_AllocStmt(conn, &htbl_stmt, 0);
1571
 
        if (!SQL_SUCCEEDED(result))
1572
 
        {
1573
 
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_Tables result.", func);
1574
 
                return SQL_ERROR;
1575
 
        }
1576
 
        tbl_stmt = (StatementClass *) htbl_stmt;
1577
 
        szSchemaName = szTableOwner;
1578
 
        cbSchemaName = cbTableOwner;
1579
 
 
1580
 
#define return  DONT_CALL_RETURN_FROM_HERE???
1581
 
        search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
1582
 
        if (search_pattern) 
1583
 
        {
1584
 
                like_or_eq = likeop;
1585
 
                escCatName = adjustLikePattern(szTableQualifier, cbTableQualifier, SEARCH_PATTERN_ESCAPE, NULL, conn);
1586
 
                escTableName = adjustLikePattern(szTableName, cbTableName, SEARCH_PATTERN_ESCAPE, NULL, conn);
1587
 
        }
1588
 
        else
1589
 
        {
1590
 
                like_or_eq = eqop;
1591
 
                escCatName = simpleCatalogEscape(szTableQualifier, cbTableQualifier, NULL, conn);
1592
 
                escTableName = simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
1593
 
        }
1594
 
retry_public_schema:
1595
 
        if (escSchemaName)
1596
 
                free(escSchemaName);
1597
 
        if (search_pattern) 
1598
 
                escSchemaName = adjustLikePattern(szSchemaName, cbSchemaName, SEARCH_PATTERN_ESCAPE, NULL, conn);
1599
 
        else
1600
 
                escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn);
1601
 
        /*
1602
 
         * Create the query to find out the tables
1603
 
         */
1604
 
        /* make_string mallocs memory */
1605
 
        tableType = make_string(szTableType, cbTableType, NULL, 0);
1606
 
#if (ODBCVER >= 0x0300)
1607
 
        if (search_pattern &&
1608
 
            escTableName && '\0' == escTableName[0] &&
1609
 
            escCatName && escSchemaName)
1610
 
        {
1611
 
                if ('\0' == escSchemaName[0])
1612
 
                {
1613
 
                        if (stricmp(escCatName, SQL_ALL_CATALOGS) == 0)
1614
 
                                list_cat = TRUE;
1615
 
                        else if ('\0' == escCatName[0] &&
1616
 
                                 stricmp(tableType, SQL_ALL_TABLE_TYPES) == 0)
1617
 
                                list_table_types = TRUE;
1618
 
                }
1619
 
                else if ('\0' == escCatName[0] &&
1620
 
                         stricmp(escSchemaName, SQL_ALL_SCHEMAS) == 0)
1621
 
                        list_schemas = TRUE;
1622
 
        }
1623
 
#endif /* ODBCVER */
1624
 
        list_some = (list_cat || list_schemas || list_table_types);
1625
 
 
1626
 
        tables_query[0] = '\0';
1627
 
        if (list_cat)
1628
 
                strncpy_null(tables_query, "select NULL, NULL, NULL", sizeof(tables_query));
1629
 
        else if (list_table_types)
1630
 
                strncpy_null(tables_query, "select NULL, NULL, relkind from (select 'r' as relkind union select 'v') as a", sizeof(tables_query));
1631
 
        else if (list_schemas)
1632
 
        {
1633
 
                if (conn->schema_support)
1634
 
                        strncpy_null(tables_query, "select NULL, nspname, NULL"
1635
 
                        " from pg_catalog.pg_namespace n where true", sizeof(tables_query));
1636
 
                else
1637
 
                        strncpy_null(tables_query, "select NULL, NULL as nspname, NULL", sizeof(tables_query));
1638
 
        }
1639
 
        else if (conn->schema_support)
1640
 
        {
1641
 
                /* view is represented by its relkind since 7.1 */
1642
 
                strcpy(tables_query, "select relname, nspname, relkind"
1643
 
                        " from pg_catalog.pg_class c, pg_catalog.pg_namespace n");
1644
 
                strcat(tables_query, " where relkind in ('r', 'v')");
1645
 
        }
1646
 
        else if (PG_VERSION_GE(conn, 7.1))
1647
 
        {
1648
 
                /* view is represented by its relkind since 7.1 */
1649
 
                strcpy(tables_query, "select relname, usename, relkind"
1650
 
                " from pg_class c, pg_user u");
1651
 
                strcat(tables_query, " where relkind in ('r', 'v')");
1652
 
        }
1653
 
        else
1654
 
        {
1655
 
                strcpy(tables_query, "select relname, usename, relhasrules from pg_class c, pg_user u");
1656
 
                strcat(tables_query, " where relkind = 'r'");
1657
 
        }
1658
 
 
1659
 
        op_string = gen_opestr(like_or_eq, conn);
1660
 
        if (!list_some)
1661
 
        {
1662
 
                if (conn->schema_support)
1663
 
                {
1664
 
                        schema_strcat1(tables_query, " and nspname %s'%.*s'", op_string, escSchemaName, SQL_NTS, szTableName, cbTableName, conn);
1665
 
                        /* strcat(tables_query, " and pg_catalog.pg_table_is_visible(c.oid)"); */
1666
 
                }
1667
 
                else
1668
 
                        my_strcat1(tables_query, " and usename %s'%.*s'", op_string, escSchemaName, SQL_NTS);
1669
 
                my_strcat1(tables_query, " and relname %s'%.*s'", op_string, escTableName, SQL_NTS);
1670
 
        }
1671
 
 
1672
 
        /* Parse the extra systable prefix      */
1673
 
        strcpy(prefixes, ci->drivers.extra_systable_prefixes);
1674
 
        i = 0;
1675
 
#ifdef  HAVE_STRTOK_R
1676
 
        prefix[i] = strtok_r(prefixes, ";", &last);
1677
 
#else
1678
 
        prefix[i] = strtok(prefixes, ";");
1679
 
#endif /* HAVE_STRTOK_R */
1680
 
        while (i < sizeof(prefix) && prefix[i])
1681
 
#ifdef  HAVE_STRTOK_R
1682
 
                prefix[++i] = strtok_r(NULL, ";", &last);
1683
 
#else
1684
 
                prefix[++i] = strtok(NULL, ";");
1685
 
#endif /* HAVE_STRTOK_R */
1686
 
 
1687
 
        /* Parse the desired table types to return */
1688
 
        show_system_tables = FALSE;
1689
 
        show_regular_tables = FALSE;
1690
 
        show_views = FALSE;
1691
 
 
1692
 
        /* TABLE_TYPE */
1693
 
        if (!tableType)
1694
 
        {
1695
 
                show_regular_tables = TRUE;
1696
 
                show_views = TRUE;
1697
 
        }
1698
 
#if (ODBCVER >= 0x0300)
1699
 
        else if (list_some || stricmp(tableType, SQL_ALL_TABLE_TYPES) == 0)
1700
 
        {
1701
 
                show_regular_tables = TRUE;
1702
 
                show_views = TRUE;
1703
 
        }
1704
 
#endif /* ODBCVER */
1705
 
        else
1706
 
        {
1707
 
                strcpy(table_types, tableType);
1708
 
                i = 0;
1709
 
#ifdef  HAVE_STRTOK_R
1710
 
                table_type[i] = strtok_r(table_types, ",", &last);
1711
 
#else
1712
 
                table_type[i] = strtok(table_types, ",");
1713
 
#endif /* HAVE_STRTOK_R */
1714
 
                while (i < sizeof(table_type) && table_type[i])
1715
 
#ifdef  HAVE_STRTOK_R
1716
 
                        table_type[++i] = strtok_r(NULL, ",", &last);
1717
 
#else
1718
 
                        table_type[++i] = strtok(NULL, ",");
1719
 
#endif /* HAVE_STRTOK_R */
1720
 
 
1721
 
                /* Check for desired table types to return */
1722
 
                i = 0;
1723
 
                while (table_type[i])
1724
 
                {
1725
 
                        char *typestr = table_type[i];
1726
 
 
1727
 
                        while (isspace(*typestr))
1728
 
                                typestr++;
1729
 
                        if (*typestr == '\'')
1730
 
                                typestr++;
1731
 
                        if (strnicmp(typestr, CSTR_SYS_TABLE, strlen(CSTR_SYS_TABLE)) == 0)
1732
 
                                show_system_tables = TRUE;
1733
 
                        else if (strnicmp(typestr, CSTR_TABLE, strlen(CSTR_TABLE)) == 0)
1734
 
                                show_regular_tables = TRUE;
1735
 
                        else if (strnicmp(typestr, CSTR_VIEW, strlen(CSTR_VIEW)) == 0)
1736
 
                                show_views = TRUE;
1737
 
                        i++;
1738
 
                }
1739
 
        }
1740
 
 
1741
 
        /*
1742
 
         * If not interested in SYSTEM TABLES then filter them out to save
1743
 
         * some time on the query.      If treating system tables as regular
1744
 
         * tables, then dont filter either.
1745
 
         */
1746
 
        if ((list_schemas || !list_some) && !atoi(ci->show_system_tables) && !show_system_tables)
1747
 
        {
1748
 
                if (conn->schema_support)
1749
 
                        strcat(tables_query, " and nspname not in ('pg_catalog', 'information_schema', 'pg_toast', 'pg_temp_1')");
1750
 
                else if (!list_schemas)
1751
 
                {
1752
 
                        strcat(tables_query, " and relname !~ '^" POSTGRES_SYS_PREFIX);
1753
 
 
1754
 
                        /* Also filter out user-defined system table types */
1755
 
                        for (i = 0; prefix[i]; i++)
1756
 
                        {
1757
 
                                strcat(tables_query, "|^");
1758
 
                                strcat(tables_query, prefix[i]);
1759
 
                        }
1760
 
                        strcat(tables_query, "'");
1761
 
                }
1762
 
        }
1763
 
 
1764
 
        if (!list_some)
1765
 
        {
1766
 
                if (CC_accessible_only(conn))
1767
 
                        strcat(tables_query, " and has_table_privilege(c.oid, 'select')");
1768
 
        }
1769
 
        if (list_schemas)
1770
 
                strcat(tables_query, " order by nspname");
1771
 
        else if (list_some)
1772
 
                ;
1773
 
        else if (conn->schema_support)
1774
 
                strcat(tables_query, " and n.oid = relnamespace order by nspname, relname");
1775
 
        else
1776
 
        {
1777
 
                /* match users */
1778
 
                if (PG_VERSION_LT(conn, 7.1))
1779
 
                        /* filter out large objects in older versions */
1780
 
                        strcat(tables_query, " and relname !~ '^xinv[0-9]+'");
1781
 
                strcat(tables_query, " and usesysid = relowner order by relname");
1782
 
        }
1783
 
 
1784
 
        result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
1785
 
        if (!SQL_SUCCEEDED(result))
1786
 
        {
1787
 
                SC_full_error_copy(stmt, htbl_stmt, FALSE);
1788
 
                goto cleanup;
1789
 
        }
1790
 
 
1791
 
        /* If not found */
1792
 
        if (conn->schema_support &&
1793
 
            (res = SC_get_Result(tbl_stmt)) &&
1794
 
            0 == QR_get_num_total_tuples(res))
1795
 
        {
1796
 
                if (allow_public_schema(conn, szSchemaName, cbSchemaName))
1797
 
                {
1798
 
                        szSchemaName = pubstr;
1799
 
                        cbSchemaName = SQL_NTS;
1800
 
                        goto retry_public_schema;
1801
 
                }
1802
 
        }
1803
 
#ifdef  UNICODE_SUPPORT
1804
 
        if (CC_is_in_unicode_driver(conn))
1805
 
                internal_asis_type = INTERNAL_ASIS_TYPE;
1806
 
#endif /* UNICODE_SUPPORT */
1807
 
        result = PGAPI_BindCol(htbl_stmt, 1, internal_asis_type,
1808
 
                        table_name, MAX_INFO_STRING, &cbRelname);
1809
 
        if (!SQL_SUCCEEDED(result))
1810
 
        {
1811
 
                SC_error_copy(stmt, tbl_stmt, TRUE);
1812
 
                goto cleanup;
1813
 
        }
1814
 
 
1815
 
        result = PGAPI_BindCol(htbl_stmt, 2, internal_asis_type,
1816
 
                                                   table_owner, MAX_INFO_STRING, &cbSchName);
1817
 
        if (!SQL_SUCCEEDED(result))
1818
 
        {
1819
 
                SC_error_copy(stmt, tbl_stmt, TRUE);
1820
 
                goto cleanup;
1821
 
        }
1822
 
        result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
1823
 
                        relkind_or_hasrules, MAX_INFO_STRING, &cbRelkind);
1824
 
        if (!SQL_SUCCEEDED(result))
1825
 
        {
1826
 
                SC_error_copy(stmt, tbl_stmt, TRUE);
1827
 
                goto cleanup;
1828
 
        }
1829
 
 
1830
 
        if (res = QR_Constructor(), !res)
1831
 
        {
1832
 
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Tables result.", func);
1833
 
                goto cleanup;
1834
 
        }
1835
 
        SC_set_Result(stmt, res);
1836
 
 
1837
 
        /* the binding structure for a statement is not set up until */
1838
 
 
1839
 
        /*
1840
 
         * a statement is actually executed, so we'll have to do this
1841
 
         * ourselves.
1842
 
         */
1843
 
        result_cols = NUM_OF_TABLES_FIELDS;
1844
 
        extend_column_bindings(SC_get_ARDF(stmt), result_cols);
1845
 
 
1846
 
        stmt->catalog_result = TRUE;
1847
 
        /* set the field names */
1848
 
        QR_set_num_fields(res, result_cols);
1849
 
        QR_set_field_info_v(res, TABLES_CATALOG_NAME, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
1850
 
        QR_set_field_info_v(res, TABLES_SCHEMA_NAME, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
1851
 
        QR_set_field_info_v(res, TABLES_TABLE_NAME, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
1852
 
        QR_set_field_info_v(res, TABLES_TABLE_TYPE, "TABLE_TYPE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
1853
 
        QR_set_field_info_v(res, TABLES_REMARKS, "REMARKS", PG_TYPE_VARCHAR, INFO_VARCHAR_SIZE);
1854
 
 
1855
 
        /* add the tuples */
1856
 
        table_name[0] = '\0';
1857
 
        table_owner[0] = '\0';
1858
 
        result = PGAPI_Fetch(htbl_stmt);
1859
 
        while (SQL_SUCCEEDED(result))
1860
 
        {
1861
 
                /*
1862
 
                 * Determine if this table name is a system table. If treating
1863
 
                 * system tables as regular tables, then no need to do this test.
1864
 
                 */
1865
 
                systable = FALSE;
1866
 
                if (!atoi(ci->show_system_tables))
1867
 
                {
1868
 
                        if (conn->schema_support)
1869
 
                        {
1870
 
                                if (stricmp(table_owner, "pg_catalog") == 0 ||
1871
 
                                    stricmp(table_owner, "pg_toast") == 0 ||
1872
 
                                    strnicmp(table_owner, "pg_temp_", 8) == 0 ||
1873
 
                                    stricmp(table_owner, "information_schema") == 0)
1874
 
                                        systable = TRUE;
1875
 
                        }
1876
 
                        else if (strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0)
1877
 
                                systable = TRUE;
1878
 
 
1879
 
                        else
1880
 
                        {
1881
 
                                /* Check extra system table prefixes */
1882
 
                                i = 0;
1883
 
                                while (prefix[i])
1884
 
                                {
1885
 
                                        mylog("table_name='%s', prefix[%d]='%s'\n", table_name, i, prefix[i]);
1886
 
                                        if (strncmp(table_name, prefix[i], strlen(prefix[i])) == 0)
1887
 
                                        {
1888
 
                                                systable = TRUE;
1889
 
                                                break;
1890
 
                                        }
1891
 
                                        i++;
1892
 
                                }
1893
 
                        }
1894
 
                }
1895
 
 
1896
 
                /* Determine if the table name is a view */
1897
 
                if (PG_VERSION_GE(conn, 7.1))
1898
 
                        /* view is represented by its relkind since 7.1 */
1899
 
                        view = (relkind_or_hasrules[0] == 'v');
1900
 
                else
1901
 
                        view = (relkind_or_hasrules[0] == '1');
1902
 
 
1903
 
                /* It must be a regular table */
1904
 
                regular_table = (!systable && !view);
1905
 
 
1906
 
 
1907
 
                /* Include the row in the result set if meets all criteria */
1908
 
 
1909
 
                /*
1910
 
                 * NOTE: Unsupported table types (i.e., LOCAL TEMPORARY, ALIAS,
1911
 
                 * etc) will return nothing
1912
 
                 */
1913
 
                if ((systable && show_system_tables) ||
1914
 
                        (view && show_views) ||
1915
 
                        (regular_table && show_regular_tables))
1916
 
                {
1917
 
                        tuple = QR_AddNew(res);
1918
 
 
1919
 
                        if (list_cat || !list_some)
1920
 
                                set_tuplefield_string(&tuple[TABLES_CATALOG_NAME], CurrCat(conn));
1921
 
                        else
1922
 
                                set_tuplefield_null(&tuple[TABLES_CATALOG_NAME]);
1923
 
 
1924
 
                        /*
1925
 
                         * I have to hide the table owner from Access, otherwise it
1926
 
                         * insists on referring to the table as 'owner.table'. (this
1927
 
                         * is valid according to the ODBC SQL grammar, but Postgres
1928
 
                         * won't support it.)
1929
 
                         *
1930
 
                         * set_tuplefield_string(&tuple[TABLES_SCHEMA_NAME], table_owner);
1931
 
                         */
1932
 
 
1933
 
                        mylog("%s: table_name = '%s'\n", func, table_name);
1934
 
 
1935
 
                        if (list_schemas || (conn->schema_support && !list_some))
1936
 
                                set_tuplefield_string(&tuple[TABLES_SCHEMA_NAME], GET_SCHEMA_NAME(table_owner));
1937
 
                        else
1938
 
                                set_tuplefield_null(&tuple[TABLES_SCHEMA_NAME]);
1939
 
                        if (list_some)
1940
 
                                set_tuplefield_null(&tuple[TABLES_TABLE_NAME]);
1941
 
                        else
1942
 
                                set_tuplefield_string(&tuple[TABLES_TABLE_NAME], table_name);
1943
 
                        if (list_table_types || !list_some)
1944
 
                                set_tuplefield_string(&tuple[TABLES_TABLE_TYPE], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE"));
1945
 
                        else
1946
 
                                set_tuplefield_null(&tuple[TABLES_TABLE_TYPE]);
1947
 
                        set_tuplefield_string(&tuple[TABLES_REMARKS], NULL_STRING);
1948
 
                        /*** set_tuplefield_string(&tuple[TABLES_REMARKS], "TABLE"); ***/
1949
 
                }
1950
 
                result = PGAPI_Fetch(htbl_stmt);
1951
 
        }
1952
 
        if (result != SQL_NO_DATA_FOUND)
1953
 
        {
1954
 
                SC_full_error_copy(stmt, htbl_stmt, FALSE);
1955
 
                goto cleanup;
1956
 
        }
1957
 
        ret = SQL_SUCCESS;
1958
 
 
1959
 
cleanup:
1960
 
#undef  return
1961
 
        /*
1962
 
         * also, things need to think that this statement is finished so the
1963
 
         * results can be retrieved.
1964
 
         */
1965
 
        stmt->status = STMT_FINISHED;
1966
 
 
1967
 
        if (escCatName)
1968
 
                free(escCatName);
1969
 
        if (escSchemaName)
1970
 
                free(escSchemaName);
1971
 
        if (escTableName)
1972
 
                free(escTableName);
1973
 
        if (tableType)
1974
 
                free(tableType);
1975
 
        /* set up the current tuple pointer for SQLFetch */
1976
 
        stmt->currTuple = -1;
1977
 
        SC_set_rowset_start(stmt, -1, FALSE);
1978
 
        SC_set_current_col(stmt, -1);
1979
 
 
1980
 
        if (htbl_stmt)
1981
 
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
1982
 
 
1983
 
        if (stmt->internal)
1984
 
                ret = DiscardStatementSvp(stmt, ret, FALSE);
1985
 
        mylog("%s: EXIT, stmt=%p, ret=%d\n", func, stmt, ret);
1986
 
        return ret;
1987
 
}
1988
 
 
1989
 
RETCODE         SQL_API
1990
 
PGAPI_Columns(
1991
 
                          HSTMT hstmt,
1992
 
                          const SQLCHAR FAR * szTableQualifier, /* OA X*/
1993
 
                          SQLSMALLINT cbTableQualifier,
1994
 
                          const SQLCHAR FAR * szTableOwner, /* PV E*/
1995
 
                          SQLSMALLINT cbTableOwner,
1996
 
                          const SQLCHAR FAR * szTableName, /* PV E*/
1997
 
                          SQLSMALLINT cbTableName,
1998
 
                          const SQLCHAR FAR * szColumnName, /* PV E*/
1999
 
                          SQLSMALLINT cbColumnName,
2000
 
                          UWORD flag,
2001
 
                          OID   reloid,
2002
 
                          Int2  attnum)
2003
 
{
2004
 
        CSTR func = "PGAPI_Columns";
2005
 
        StatementClass *stmt = (StatementClass *) hstmt;
2006
 
        QResultClass    *res;
2007
 
        TupleField      *tuple;
2008
 
        HSTMT           hcol_stmt = NULL;
2009
 
        StatementClass *col_stmt;
2010
 
        char            columns_query[INFO_INQUIRY_LEN];
2011
 
        RETCODE         result;
2012
 
        char            table_owner[MAX_INFO_STRING],
2013
 
                                table_name[MAX_INFO_STRING],
2014
 
                                field_name[MAX_INFO_STRING],
2015
 
                                field_type_name[MAX_INFO_STRING];
2016
 
        Int2            field_number, sqltype, concise_type,
2017
 
                                result_cols;
2018
 
        Int4            mod_length,
2019
 
                                ordinal,
2020
 
                                typmod, relhasoids;
2021
 
        OID             field_type, the_type, greloid, basetype;
2022
 
#ifdef  USE_OLD_IMPL
2023
 
        Int2            decimal_digits;
2024
 
        Int4            field_length, column_size;
2025
 
        char            useStaticPrecision, useStaticScale;
2026
 
#endif /* USE_OLD_IMPL */
2027
 
        char            not_null[MAX_INFO_STRING],
2028
 
                                relhasrules[MAX_INFO_STRING], relkind[8];
2029
 
        char    *escSchemaName = NULL, *escTableName = NULL, *escColumnName = NULL;
2030
 
        BOOL    search_pattern = TRUE, search_by_ids, relisaview;
2031
 
        ConnInfo   *ci;
2032
 
        ConnectionClass *conn;
2033
 
        SQLSMALLINT     internal_asis_type = SQL_C_CHAR, cbSchemaName;
2034
 
        const char      *like_or_eq = likeop, *op_string;
2035
 
        const char      *szSchemaName;
2036
 
        BOOL    setIdentity = FALSE;
2037
 
 
2038
 
        mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func, stmt, szTableOwner, cbTableOwner);
2039
 
 
2040
 
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
2041
 
                return result;
2042
 
 
2043
 
        conn = SC_get_conn(stmt);
2044
 
        ci = &(conn->connInfo);
2045
 
#ifdef  UNICODE_SUPPORT
2046
 
        if (CC_is_in_unicode_driver(conn))
2047
 
                internal_asis_type = INTERNAL_ASIS_TYPE;
2048
 
#endif /* UNICODE_SUPPORT */
2049
 
 
2050
 
#define return  DONT_CALL_RETURN_FROM_HERE???
2051
 
        search_by_ids = ((flag & PODBC_SEARCH_BY_IDS) != 0);
2052
 
        if (search_by_ids)
2053
 
        {
2054
 
                szSchemaName = NULL;
2055
 
                cbSchemaName = SQL_NULL_DATA;
2056
 
        }
2057
 
        else
2058
 
        {
2059
 
                szSchemaName = szTableOwner;
2060
 
                cbSchemaName = cbTableOwner;
2061
 
                reloid = 0;
2062
 
                attnum = 0;
2063
 
                /*
2064
 
                 *      TableName or ColumnName is ordinarily an pattern value,
2065
 
                 */
2066
 
                search_pattern = ((flag & PODBC_NOT_SEARCH_PATTERN) == 0); 
2067
 
                if (search_pattern) 
2068
 
                {
2069
 
                        like_or_eq = likeop;
2070
 
                        escTableName = adjustLikePattern(szTableName, cbTableName, SEARCH_PATTERN_ESCAPE, NULL, conn);
2071
 
                        escColumnName = adjustLikePattern(szColumnName, cbColumnName, SEARCH_PATTERN_ESCAPE, NULL, conn);
2072
 
                }
2073
 
                else
2074
 
                {
2075
 
                        like_or_eq = eqop;
2076
 
                        escTableName = simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
2077
 
                        escColumnName = simpleCatalogEscape(szColumnName, cbColumnName, NULL, conn);
2078
 
                }
2079
 
        }
2080
 
retry_public_schema:
2081
 
        if (!search_by_ids)
2082
 
        {
2083
 
                if (escSchemaName)
2084
 
                        free(escSchemaName);
2085
 
                if (search_pattern) 
2086
 
                        escSchemaName = adjustLikePattern(szSchemaName, cbSchemaName, SEARCH_PATTERN_ESCAPE, NULL, conn);
2087
 
                else
2088
 
                        escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn);
2089
 
        }
2090
 
        /*
2091
 
         * Create the query to find out the columns (Note: pre 6.3 did not
2092
 
         * have the atttypmod field)
2093
 
         */
2094
 
        op_string = gen_opestr(like_or_eq, conn);
2095
 
        if (conn->schema_support)
2096
 
        {
2097
 
                snprintf(columns_query, sizeof(columns_query),
2098
 
                        "select n.nspname, c.relname, a.attname, a.atttypid"
2099
 
                        ", t.typname, a.attnum, a.attlen, a.atttypmod, a.attnotnull"
2100
 
                        ", c.relhasrules, c.relkind, c.oid, %s, %s, %s"
2101
 
                        " from (((pg_catalog.pg_class c"
2102
 
                        " inner join pg_catalog.pg_namespace n on n.oid = c.relnamespace",
2103
 
                        PG_VERSION_GE(conn, 7.4) ?
2104
 
                        "pg_get_expr(d.adbin, d.adrelid)" : "d.adsrc",
2105
 
                        PG_VERSION_GE(conn, 7.4) ?
2106
 
                        "case t.typtype when 'd' then t.typbasetype else 0 end, t.typtypmod"
2107
 
                                        : "0, -1",
2108
 
                        PG_VERSION_GE(conn, 7.2) ? "c.relhasoids" : "1"
2109
 
                                        );
2110
 
                if (search_by_ids)
2111
 
                        snprintf_add(columns_query, sizeof(columns_query), " and c.oid = %u", reloid);
2112
 
                else
2113
 
                {
2114
 
                        if (escTableName)
2115
 
                                snprintf_add(columns_query, sizeof(columns_query), " and c.relname %s'%s'", op_string, escTableName);
2116
 
                        schema_strcat1(columns_query, " and n.nspname %s'%.*s'", op_string, escSchemaName, SQL_NTS, szTableName, cbTableName, conn);
2117
 
                }
2118
 
                strcat(columns_query, ") inner join pg_catalog.pg_attribute a"
2119
 
                        " on (not a.attisdropped)");
2120
 
                if (0 == attnum && (NULL == escColumnName || like_or_eq != eqop))
2121
 
                        strcat(columns_query, " and a.attnum > 0");
2122
 
                if (search_by_ids)
2123
 
                {
2124
 
                        if (attnum != 0)
2125
 
                                snprintf_add(columns_query, sizeof(columns_query), " and a.attnum = %d", attnum);
2126
 
                }
2127
 
                else if (escColumnName)
2128
 
                        snprintf_add(columns_query, sizeof(columns_query), " and a.attname %s'%s'", op_string, escColumnName);
2129
 
                strcat(columns_query,
2130
 
                        " and a.attrelid = c.oid) inner join pg_catalog.pg_type t"
2131
 
                        " on t.oid = a.atttypid) left outer join pg_attrdef d"
2132
 
                        " on a.atthasdef and d.adrelid = a.attrelid and d.adnum = a.attnum");
2133
 
                strcat(columns_query, " order by n.nspname, c.relname, attnum");
2134
 
        }
2135
 
        else
2136
 
        {
2137
 
                snprintf(columns_query, sizeof(columns_query),
2138
 
                        "select u.usename, c.relname, a.attname, a.atttypid"
2139
 
                        ", t.typname, a.attnum, a.attlen, %s, a.attnotnull"
2140
 
                        ", c.relhasrules, c.relkind, c.oid, NULL, 0, -1 from"
2141
 
                        "  pg_user u, pg_class c, pg_attribute a, pg_type t where"
2142
 
                        "  u.usesysid = c.relowner and c.oid= a.attrelid"
2143
 
                        "  and a.atttypid = t.oid and (a.attnum > 0)",
2144
 
                        PG_VERSION_LE(conn, 6.2) ? "a.attlen" : "a.atttypmod");
2145
 
                if (escTableName)
2146
 
                        snprintf_add(columns_query, sizeof(columns_query), " and c.relname %s'%s'", op_string, escTableName);
2147
 
                my_strcat1(columns_query, " and u.usename %s'%.*s'", op_string, escSchemaName, SQL_NTS);
2148
 
                if (escColumnName)
2149
 
                        snprintf_add(columns_query, sizeof(columns_query), " and a.attname %s'%s'", op_string, escColumnName);
2150
 
                strcat(columns_query, " order by c.relname, attnum");
2151
 
        }
2152
 
 
2153
 
        result = PGAPI_AllocStmt(conn, &hcol_stmt, 0);
2154
 
        if (!SQL_SUCCEEDED(result))
2155
 
        {
2156
 
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_Columns result.", func);
2157
 
                result = SQL_ERROR;
2158
 
                goto cleanup;
2159
 
        }
2160
 
        col_stmt = (StatementClass *) hcol_stmt;
2161
 
 
2162
 
        mylog("%s: hcol_stmt = %p, col_stmt = %p\n", func, hcol_stmt, col_stmt);
2163
 
 
2164
 
        col_stmt->internal = TRUE;
2165
 
        result = PGAPI_ExecDirect(hcol_stmt, columns_query, SQL_NTS, 0);
2166
 
        if (!SQL_SUCCEEDED(result))
2167
 
        {
2168
 
                SC_full_error_copy(stmt, col_stmt, FALSE);
2169
 
                goto cleanup;
2170
 
        }
2171
 
 
2172
 
        /* If not found */
2173
 
        if (conn->schema_support &&
2174
 
            (flag & PODBC_SEARCH_PUBLIC_SCHEMA) != 0 &&
2175
 
            (res = SC_get_Result(col_stmt)) &&
2176
 
            0 == QR_get_num_total_tuples(res))
2177
 
        {
2178
 
                if (!search_by_ids &&
2179
 
                    allow_public_schema(conn, szSchemaName, cbSchemaName))
2180
 
                {
2181
 
                        PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
2182
 
                        hcol_stmt = NULL;
2183
 
                        szSchemaName = pubstr;
2184
 
                        cbSchemaName = SQL_NTS;
2185
 
                        goto retry_public_schema;
2186
 
                }
2187
 
        }
2188
 
 
2189
 
        result = PGAPI_BindCol(hcol_stmt, 1, internal_asis_type,
2190
 
                                                   table_owner, MAX_INFO_STRING, NULL);
2191
 
        if (!SQL_SUCCEEDED(result))
2192
 
        {
2193
 
                SC_error_copy(stmt, col_stmt, TRUE);
2194
 
                goto cleanup;
2195
 
        }
2196
 
 
2197
 
        result = PGAPI_BindCol(hcol_stmt, 2, internal_asis_type,
2198
 
                                                   table_name, MAX_INFO_STRING, NULL);
2199
 
        if (!SQL_SUCCEEDED(result))
2200
 
        {
2201
 
                SC_error_copy(stmt, col_stmt, TRUE);
2202
 
                goto cleanup;
2203
 
        }
2204
 
 
2205
 
        result = PGAPI_BindCol(hcol_stmt, 3, internal_asis_type,
2206
 
                                                   field_name, MAX_INFO_STRING, NULL);
2207
 
        if (!SQL_SUCCEEDED(result))
2208
 
        {
2209
 
                SC_error_copy(stmt, col_stmt, TRUE);
2210
 
                goto cleanup;
2211
 
        }
2212
 
 
2213
 
        result = PGAPI_BindCol(hcol_stmt, 4, SQL_C_ULONG,
2214
 
                                                   &field_type, 4, NULL);
2215
 
        if (!SQL_SUCCEEDED(result))
2216
 
        {
2217
 
                SC_error_copy(stmt, col_stmt, TRUE);
2218
 
                goto cleanup;
2219
 
        }
2220
 
 
2221
 
        result = PGAPI_BindCol(hcol_stmt, 5, internal_asis_type,
2222
 
                                                   field_type_name, MAX_INFO_STRING, NULL);
2223
 
        if (!SQL_SUCCEEDED(result))
2224
 
        {
2225
 
                SC_error_copy(stmt, col_stmt, TRUE);
2226
 
                goto cleanup;
2227
 
        }
2228
 
 
2229
 
        result = PGAPI_BindCol(hcol_stmt, 6, SQL_C_SHORT,
2230
 
                                                   &field_number, MAX_INFO_STRING, NULL);
2231
 
        if (!SQL_SUCCEEDED(result))
2232
 
        {
2233
 
                SC_error_copy(stmt, col_stmt, TRUE);
2234
 
                goto cleanup;
2235
 
        }
2236
 
 
2237
 
#ifdef  NOT_USED
2238
 
        result = PGAPI_BindCol(hcol_stmt, 7, SQL_C_LONG,
2239
 
                                                   &field_length, MAX_INFO_STRING, NULL);
2240
 
        if (!SQL_SUCCEEDED(result))
2241
 
        {
2242
 
                SC_error_copy(stmt, col_stmt, TRUE);
2243
 
                goto cleanup;
2244
 
        }
2245
 
#endif /* NOT_USED */
2246
 
 
2247
 
        result = PGAPI_BindCol(hcol_stmt, 8, SQL_C_LONG,
2248
 
                                                   &mod_length, MAX_INFO_STRING, NULL);
2249
 
        if (!SQL_SUCCEEDED(result))
2250
 
        {
2251
 
                SC_error_copy(stmt, col_stmt, TRUE);
2252
 
                goto cleanup;
2253
 
        }
2254
 
 
2255
 
        result = PGAPI_BindCol(hcol_stmt, 9, internal_asis_type,
2256
 
                                                   not_null, MAX_INFO_STRING, NULL);
2257
 
        if (!SQL_SUCCEEDED(result))
2258
 
        {
2259
 
                SC_error_copy(stmt, col_stmt, TRUE);
2260
 
                goto cleanup;
2261
 
        }
2262
 
 
2263
 
        result = PGAPI_BindCol(hcol_stmt, 10, internal_asis_type,
2264
 
                                                   relhasrules, MAX_INFO_STRING, NULL);
2265
 
        if (!SQL_SUCCEEDED(result))
2266
 
        {
2267
 
                SC_error_copy(stmt, col_stmt, TRUE);
2268
 
                goto cleanup;
2269
 
        }
2270
 
 
2271
 
        result = PGAPI_BindCol(hcol_stmt, 11, internal_asis_type,
2272
 
                                                   relkind, sizeof(relkind), NULL);
2273
 
        if (!SQL_SUCCEEDED(result))
2274
 
        {
2275
 
                SC_error_copy(stmt, col_stmt, TRUE);
2276
 
                goto cleanup;
2277
 
        }
2278
 
 
2279
 
        result = PGAPI_BindCol(hcol_stmt, 12, SQL_C_LONG,
2280
 
                                        &greloid, sizeof(greloid), NULL);
2281
 
        if (!SQL_SUCCEEDED(result))
2282
 
        {
2283
 
                SC_error_copy(stmt, col_stmt, TRUE);
2284
 
                goto cleanup;
2285
 
        }
2286
 
 
2287
 
        result = PGAPI_BindCol(hcol_stmt, 14, SQL_C_ULONG,
2288
 
                                        &basetype, sizeof(basetype), NULL);
2289
 
        if (!SQL_SUCCEEDED(result))
2290
 
        {
2291
 
                SC_error_copy(stmt, col_stmt, TRUE);
2292
 
                goto cleanup;
2293
 
        }
2294
 
 
2295
 
        result = PGAPI_BindCol(hcol_stmt, 15, SQL_C_LONG,
2296
 
                                        &typmod, sizeof(typmod), NULL);
2297
 
        if (!SQL_SUCCEEDED(result))
2298
 
        {
2299
 
                SC_error_copy(stmt, col_stmt, TRUE);
2300
 
                goto cleanup;
2301
 
        }
2302
 
 
2303
 
        result = PGAPI_BindCol(hcol_stmt, 16, SQL_C_LONG,
2304
 
                                        &relhasoids, sizeof(relhasoids), NULL);
2305
 
        if (!SQL_SUCCEEDED(result))
2306
 
        {
2307
 
                SC_error_copy(stmt, col_stmt, TRUE);
2308
 
                goto cleanup;
2309
 
        }
2310
 
 
2311
 
        if (res = QR_Constructor(), !res)
2312
 
        {
2313
 
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Columns result.", func);
2314
 
                goto cleanup;
2315
 
        }
2316
 
        SC_set_Result(stmt, res);
2317
 
 
2318
 
        /* the binding structure for a statement is not set up until */
2319
 
 
2320
 
        /*
2321
 
         * a statement is actually executed, so we'll have to do this
2322
 
         * ourselves.
2323
 
         */
2324
 
        result_cols = NUM_OF_COLUMNS_FIELDS;
2325
 
        extend_column_bindings(SC_get_ARDF(stmt), result_cols);
2326
 
 
2327
 
        /*
2328
 
         * Setting catalog_result here affects the behavior of
2329
 
         * pgtype_xxx() functions. So set it later.
2330
 
         * stmt->catalog_result = TRUE;
2331
 
         */
2332
 
        /* set the field names */
2333
 
        QR_set_num_fields(res, result_cols);
2334
 
        QR_set_field_info_v(res, COLUMNS_CATALOG_NAME, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
2335
 
        QR_set_field_info_v(res, COLUMNS_SCHEMA_NAME, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
2336
 
        QR_set_field_info_v(res, COLUMNS_TABLE_NAME, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
2337
 
        QR_set_field_info_v(res, COLUMNS_COLUMN_NAME, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
2338
 
        QR_set_field_info_v(res, COLUMNS_DATA_TYPE, "DATA_TYPE", PG_TYPE_INT2, 2);
2339
 
        QR_set_field_info_v(res, COLUMNS_TYPE_NAME, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
2340
 
        QR_set_field_info_v(res, COLUMNS_PRECISION, "PRECISION", PG_TYPE_INT4, 4); /* COLUMN_SIZE */
2341
 
        QR_set_field_info_v(res, COLUMNS_LENGTH, "LENGTH", PG_TYPE_INT4, 4); /* BUFFER_LENGTH */
2342
 
        QR_set_field_info_v(res, COLUMNS_SCALE, "SCALE", PG_TYPE_INT2, 2); /* DECIMAL_DIGITS ***/
2343
 
        QR_set_field_info_v(res, COLUMNS_RADIX, "RADIX", PG_TYPE_INT2, 2);
2344
 
        QR_set_field_info_v(res, COLUMNS_NULLABLE, "NULLABLE", PG_TYPE_INT2, 2);
2345
 
        QR_set_field_info_v(res, COLUMNS_REMARKS, "REMARKS", PG_TYPE_VARCHAR, INFO_VARCHAR_SIZE);
2346
 
 
2347
 
#if (ODBCVER >= 0x0300)
2348
 
        QR_set_field_info_v(res, COLUMNS_COLUMN_DEF, "COLUMN_DEF", PG_TYPE_VARCHAR, INFO_VARCHAR_SIZE);
2349
 
        QR_set_field_info_v(res, COLUMNS_SQL_DATA_TYPE, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
2350
 
        QR_set_field_info_v(res, COLUMNS_SQL_DATETIME_SUB, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
2351
 
        QR_set_field_info_v(res, COLUMNS_CHAR_OCTET_LENGTH, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
2352
 
        QR_set_field_info_v(res, COLUMNS_ORDINAL_POSITION, "ORDINAL_POSITION", PG_TYPE_INT4, 4);
2353
 
        QR_set_field_info_v(res, COLUMNS_IS_NULLABLE, "IS_NULLABLE", PG_TYPE_VARCHAR, INFO_VARCHAR_SIZE);
2354
 
#endif /* ODBCVER */
2355
 
        /* User defined fields */
2356
 
        QR_set_field_info_v(res, COLUMNS_DISPLAY_SIZE, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
2357
 
        QR_set_field_info_v(res, COLUMNS_FIELD_TYPE, "FIELD_TYPE", PG_TYPE_INT4, 4);
2358
 
        QR_set_field_info_v(res, COLUMNS_AUTO_INCREMENT, "AUTO_INCREMENT", PG_TYPE_INT4, 4);
2359
 
        QR_set_field_info_v(res, COLUMNS_PHYSICAL_NUMBER, "PHYSICAL NUMBER", PG_TYPE_INT2, 2);
2360
 
        QR_set_field_info_v(res, COLUMNS_TABLE_OID, "TABLE OID", PG_TYPE_OID, 4);
2361
 
        QR_set_field_info_v(res, COLUMNS_BASE_TYPEID, "BASE TYPEID", PG_TYPE_OID, 4);
2362
 
        QR_set_field_info_v(res, COLUMNS_ATTTYPMOD, "TYPMOD", PG_TYPE_INT4, 4);
2363
 
 
2364
 
        ordinal = 1;
2365
 
        result = PGAPI_Fetch(hcol_stmt);
2366
 
 
2367
 
        /*
2368
 
         * Only show oid if option AND there are other columns AND it's not
2369
 
         * being called by SQLStatistics . Always show OID if it's a system
2370
 
         * table
2371
 
         */
2372
 
 
2373
 
        if (PG_VERSION_GE(conn, 7.1))
2374
 
                relisaview = (relkind[0] == 'v');
2375
 
        else
2376
 
                relisaview = (relhasrules[0] == '1');
2377
 
        if (result != SQL_ERROR && !stmt->internal)
2378
 
        {
2379
 
                if (!relisaview &&
2380
 
                        relhasoids &&
2381
 
                        (atoi(ci->show_oid_column) ||
2382
 
                         strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0) &&
2383
 
                        (NULL == escColumnName ||
2384
 
                         0 == strcmp(escColumnName, OID_NAME)))
2385
 
                {
2386
 
                        /* For OID fields */
2387
 
                        the_type = PG_TYPE_OID;
2388
 
                        tuple = QR_AddNew(res);
2389
 
                        set_tuplefield_string(&tuple[COLUMNS_CATALOG_NAME], CurrCat(conn));
2390
 
                        /* see note in SQLTables() */
2391
 
                        if (conn->schema_support)
2392
 
                                set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], GET_SCHEMA_NAME(table_owner));
2393
 
                        else
2394
 
                                set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], NULL_STRING);
2395
 
                        set_tuplefield_string(&tuple[COLUMNS_TABLE_NAME], table_name);
2396
 
                        set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], OID_NAME);
2397
 
                        sqltype = pgtype_to_concise_type(stmt, the_type, PG_STATIC);
2398
 
                        set_tuplefield_int2(&tuple[COLUMNS_DATA_TYPE], sqltype);
2399
 
                        if (CC_fake_mss(conn))
2400
 
                        {
2401
 
                                set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], "OID identity");
2402
 
                                setIdentity = TRUE;
2403
 
                        }
2404
 
                        else
2405
 
                                set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], "OID");
2406
 
 
2407
 
                        set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2408
 
                        set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2409
 
                        set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
2410
 
                        set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(conn, the_type));
2411
 
                        set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], SQL_NO_NULLS);
2412
 
                        set_tuplefield_string(&tuple[COLUMNS_REMARKS], NULL_STRING);
2413
 
 
2414
 
#if (ODBCVER >= 0x0300)
2415
 
                        set_tuplefield_null(&tuple[COLUMNS_COLUMN_DEF]);
2416
 
                        set_tuplefield_int2(&tuple[COLUMNS_SQL_DATA_TYPE], sqltype);
2417
 
                        set_tuplefield_null(&tuple[COLUMNS_SQL_DATETIME_SUB]);
2418
 
                        set_tuplefield_null(&tuple[COLUMNS_CHAR_OCTET_LENGTH]);
2419
 
                        set_tuplefield_int4(&tuple[COLUMNS_ORDINAL_POSITION], ordinal);
2420
 
                        set_tuplefield_string(&tuple[COLUMNS_IS_NULLABLE], "No");
2421
 
#endif /* ODBCVER */
2422
 
                        set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_display_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2423
 
                        set_tuplefield_int4(&tuple[COLUMNS_FIELD_TYPE], the_type);
2424
 
                        set_tuplefield_int4(&tuple[COLUMNS_AUTO_INCREMENT], TRUE);
2425
 
                        set_tuplefield_int2(&tuple[COLUMNS_PHYSICAL_NUMBER], OID_ATTNUM);
2426
 
                        set_tuplefield_int4(&tuple[COLUMNS_TABLE_OID], greloid);
2427
 
                        set_tuplefield_int4(&tuple[COLUMNS_BASE_TYPEID], 0);
2428
 
                        set_tuplefield_int4(&tuple[COLUMNS_ATTTYPMOD], -1);
2429
 
                        ordinal++;
2430
 
                }
2431
 
        }
2432
 
 
2433
 
        while (SQL_SUCCEEDED(result))
2434
 
        {
2435
 
                int     auto_unique;
2436
 
                SQLLEN  len_needed;
2437
 
                char    *attdef;
2438
 
 
2439
 
                attdef = NULL;
2440
 
                PGAPI_SetPos(hcol_stmt, 1, SQL_POSITION, 0);
2441
 
                PGAPI_GetData(hcol_stmt, 13, internal_asis_type, NULL, 0, &len_needed);
2442
 
                if (len_needed > 0)
2443
 
                {
2444
 
mylog("len_needed=%d\n", len_needed);
2445
 
                        attdef = malloc(len_needed + 1);
2446
 
                        PGAPI_GetData(hcol_stmt, 13, internal_asis_type, attdef, len_needed + 1, &len_needed);
2447
 
mylog(" and the data=%s\n", attdef);
2448
 
                } 
2449
 
                tuple = QR_AddNew(res);
2450
 
 
2451
 
                sqltype = SQL_TYPE_NULL;        /* unspecified */
2452
 
                set_tuplefield_string(&tuple[COLUMNS_CATALOG_NAME], CurrCat(conn));
2453
 
                /* see note in SQLTables() */
2454
 
                if (conn->schema_support)
2455
 
                        set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], GET_SCHEMA_NAME(table_owner));
2456
 
                else
2457
 
                        set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], NULL_STRING);
2458
 
                set_tuplefield_string(&tuple[COLUMNS_TABLE_NAME], table_name);
2459
 
                set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], field_name);
2460
 
                auto_unique = SQL_FALSE;
2461
 
                if (field_type = pg_true_type(conn, field_type, basetype), field_type == basetype)
2462
 
                        mod_length = typmod;
2463
 
                switch (field_type)
2464
 
                {
2465
 
                        case PG_TYPE_OID:
2466
 
                                if (0 != atoi(ci->fake_oid_index))
2467
 
                                {
2468
 
                                        auto_unique = SQL_TRUE;
2469
 
                                        set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], "identity");
2470
 
                                        break;
2471
 
                                }
2472
 
                        case PG_TYPE_INT4:
2473
 
                        case PG_TYPE_INT8:
2474
 
                                if (attdef && strnicmp(attdef, "nextval(", 8) == 0 &&
2475
 
                                    not_null[0] != '0')
2476
 
                                {
2477
 
                                        auto_unique = SQL_TRUE;
2478
 
                                        if (!setIdentity &&
2479
 
                                            CC_fake_mss(conn))
2480
 
                                        {
2481
 
                                                char    tmp[32];
2482
 
 
2483
 
                                                snprintf(tmp, sizeof(tmp), "%s identity", field_type_name);
2484
 
                                                set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], tmp);
2485
 
                                                break;
2486
 
                                        }
2487
 
                                }
2488
 
                        default:
2489
 
                                set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], field_type_name);
2490
 
                                break;
2491
 
                }
2492
 
 
2493
 
                /*----------
2494
 
                 * Some Notes about Postgres Data Types:
2495
 
                 *
2496
 
                 * VARCHAR - the length is stored in the pg_attribute.atttypmod field
2497
 
                 * BPCHAR  - the length is also stored as varchar is
2498
 
                 *
2499
 
                 * NUMERIC - the decimal_digits is stored in atttypmod as follows:
2500
 
                 *
2501
 
                 *      column_size =((atttypmod - VARHDRSZ) >> 16) & 0xffff
2502
 
                 *      decimal_digits   = (atttypmod - VARHDRSZ) & 0xffff
2503
 
                 *
2504
 
                 *----------
2505
 
                 */
2506
 
                qlog("%s: table='%s',field_name='%s',type=%d,name='%s'\n",
2507
 
                         func, table_name, field_name, field_type, field_type_name);
2508
 
 
2509
 
#ifdef  USE_OLD_IMPL
2510
 
                useStaticPrecision = TRUE;
2511
 
                useStaticScale = TRUE;
2512
 
 
2513
 
                if (field_type == PG_TYPE_NUMERIC)
2514
 
                {
2515
 
                        if (mod_length >= 4)
2516
 
                                mod_length -= 4;        /* the length is in atttypmod - 4 */
2517
 
 
2518
 
                        if (mod_length >= 0)
2519
 
                        {
2520
 
                                useStaticPrecision = FALSE;
2521
 
                                useStaticScale = FALSE;
2522
 
 
2523
 
                                column_size = (mod_length >> 16) & 0xffff;
2524
 
                                decimal_digits = mod_length & 0xffff;
2525
 
 
2526
 
                                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);
2527
 
 
2528
 
                                set_tuplefield_int4(&tuple[COLUMNS_PRECISION], column_size);
2529
 
                                set_tuplefield_int4(&tuple[COLUMNS_LENGTH], column_size + 2);           /* sign+dec.point */
2530
 
                                set_nullfield_int2(&tuple[COLUMNS_SCALE], decimal_digits);
2531
 
#if (ODBCVER >= 0x0300)
2532
 
                                set_tuplefield_null(&tuple[COLUMNS_CHAR_OCTET_LENGTH]);
2533
 
#endif /* ODBCVER */
2534
 
                                set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], column_size + 2);     /* sign+dec.point */
2535
 
                        }
2536
 
                }
2537
 
                else if ((field_type == PG_TYPE_DATETIME) ||
2538
 
                        (field_type == PG_TYPE_TIMESTAMP_NO_TMZONE))
2539
 
                {
2540
 
                        if (PG_VERSION_GE(conn, 7.2))
2541
 
                        {
2542
 
                                useStaticScale = FALSE;
2543
 
 
2544
 
                                set_nullfield_int2(&tuple[COLUMNS_SCALE], (Int2) mod_length);
2545
 
                        }
2546
 
                }
2547
 
 
2548
 
                if ((field_type == PG_TYPE_VARCHAR) ||
2549
 
                        (field_type == PG_TYPE_BPCHAR))
2550
 
                {
2551
 
                        useStaticPrecision = FALSE;
2552
 
 
2553
 
                        if (mod_length >= 4)
2554
 
                                mod_length -= 4;        /* the length is in atttypmod - 4 */
2555
 
 
2556
 
                        /* if (mod_length > ci->drivers.max_varchar_size || mod_length <= 0) */
2557
 
                        if (mod_length <= 0)
2558
 
                                mod_length = ci->drivers.max_varchar_size;
2559
 
#ifdef  __MS_REPORTS_ANSI_CHAR__
2560
 
                        if (mod_length > ci->drivers.max_varchar_size)
2561
 
                                sqltype = SQL_LONGVARCHAR;
2562
 
                        else
2563
 
                                sqltype = (field_type == PG_TYPE_BPCHAR) ? SQL_CHAR : SQL_VARCHAR;
2564
 
#else
2565
 
                        if (mod_length > ci->drivers.max_varchar_size)
2566
 
                                sqltype = (ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR);
2567
 
                        else
2568
 
                                sqltype = (field_type == PG_TYPE_BPCHAR) ? (ALLOW_WCHAR(conn) ? SQL_WCHAR : SQL_CHAR) : (ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR);
2569
 
#endif /* __MS_LOVES_REPORTS_CHAR__ */
2570
 
 
2571
 
                        mylog("%s: field type is VARCHAR,BPCHAR: field_type = %d, mod_length = %d\n", func, field_type, mod_length);
2572
 
 
2573
 
                        set_tuplefield_int4(&tuple[COLUMNS_PRECISION], mod_length);
2574
 
                        field_length = mod_length;
2575
 
#ifdef  UNICODE_SUPPORT
2576
 
                        if (0 < field_length && ALLOW_WCHAR(conn))
2577
 
                                field_length *= WCLEN;
2578
 
#endif /* UNICODE_SUPPORT */
2579
 
                        set_tuplefield_int4(&tuple[COLUMNS_LENGTH], field_length);
2580
 
#if (ODBCVER >= 0x0300)
2581
 
                        set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(conn, field_type, mod_length));
2582
 
#endif /* ODBCVER */
2583
 
                        set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], mod_length);
2584
 
                }
2585
 
 
2586
 
                if (useStaticPrecision)
2587
 
                {
2588
 
                        mylog("%s: field type is OTHER: field_type = %d, pgtype_length = %d\n", func, field_type, pgtype_buffer_length(stmt, field_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2589
 
 
2590
 
                        set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, field_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2591
 
                        set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, field_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2592
 
#if (ODBCVER >= 0x0300)
2593
 
                        set_tuplefield_null(&tuple[COLUMNS_CHAR_OCTET_LENGTH]);
2594
 
#endif /* ODBCVER */
2595
 
                        set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_display_size(stmt, field_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2596
 
                }
2597
 
                if (useStaticScale)
2598
 
                {
2599
 
                        set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, field_type, PG_STATIC));
2600
 
                }
2601
 
 
2602
 
                if (SQL_TYPE_NULL == sqltype)
2603
 
                {
2604
 
                        sqltype = pgtype_attr_to_concise_type(conn, field_type, mod_length, -1);
2605
 
                        concise_type = pgtype_attr_to_sqldesctype(conn, field_type, mod_length);
2606
 
                }
2607
 
                else
2608
 
                        concise_type = sqltype;
2609
 
#else /* USE_OLD_IMPL */
2610
 
                /* Subtract the header length */
2611
 
                switch (field_type)
2612
 
                {
2613
 
                        case PG_TYPE_DATETIME:
2614
 
                        case PG_TYPE_TIMESTAMP_NO_TMZONE:
2615
 
                        case PG_TYPE_TIME:
2616
 
                        case PG_TYPE_TIME_WITH_TMZONE:
2617
 
                        case PG_TYPE_BIT:
2618
 
                                break;
2619
 
                        default:
2620
 
                                if (mod_length >= 4)
2621
 
                                        mod_length -= 4;
2622
 
                }
2623
 
                set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_attr_column_size(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
2624
 
                set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_attr_buffer_length(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
2625
 
                set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_attr_display_size(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
2626
 
                set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_attr_decimal_digits(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
2627
 
 
2628
 
                sqltype = pgtype_attr_to_concise_type(conn, field_type, mod_length, PG_UNSPECIFIED);
2629
 
                concise_type = pgtype_attr_to_sqldesctype(conn, field_type, mod_length);
2630
 
#endif /* USE_OLD_IMPL */
2631
 
 
2632
 
                set_tuplefield_int2(&tuple[COLUMNS_DATA_TYPE], sqltype);
2633
 
 
2634
 
                set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(conn, field_type));
2635
 
                set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], (Int2) (not_null[0] != '0' ? SQL_NO_NULLS : pgtype_nullable(conn, field_type)));
2636
 
                set_tuplefield_string(&tuple[COLUMNS_REMARKS], NULL_STRING);
2637
 
#if (ODBCVER >= 0x0300)
2638
 
                if (attdef && strlen(attdef) > INFO_VARCHAR_SIZE)
2639
 
                        set_tuplefield_string(&tuple[COLUMNS_COLUMN_DEF], "TRUNCATE");
2640
 
                else
2641
 
                        set_tuplefield_string(&tuple[COLUMNS_COLUMN_DEF], attdef);
2642
 
                set_tuplefield_int2(&tuple[COLUMNS_SQL_DATA_TYPE], concise_type);
2643
 
                set_nullfield_int2(&tuple[COLUMNS_SQL_DATETIME_SUB], pgtype_attr_to_datetime_sub(conn, field_type, mod_length));
2644
 
                set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, field_type, mod_length, UNKNOWNS_AS_DEFAULT));
2645
 
                set_tuplefield_int4(&tuple[COLUMNS_ORDINAL_POSITION], ordinal);
2646
 
                set_tuplefield_null(&tuple[COLUMNS_IS_NULLABLE]);
2647
 
#endif /* ODBCVER */
2648
 
                set_tuplefield_int4(&tuple[COLUMNS_FIELD_TYPE], field_type);
2649
 
                set_tuplefield_int4(&tuple[COLUMNS_AUTO_INCREMENT], auto_unique);
2650
 
                set_tuplefield_int2(&tuple[COLUMNS_PHYSICAL_NUMBER], field_number);
2651
 
                set_tuplefield_int4(&tuple[COLUMNS_TABLE_OID], greloid);
2652
 
                set_tuplefield_int4(&tuple[COLUMNS_BASE_TYPEID], basetype);
2653
 
                set_tuplefield_int4(&tuple[COLUMNS_ATTTYPMOD], mod_length);
2654
 
                ordinal++;
2655
 
 
2656
 
                result = PGAPI_Fetch(hcol_stmt);
2657
 
                if (attdef)
2658
 
                        free(attdef);
2659
 
        }
2660
 
        if (result != SQL_NO_DATA_FOUND)
2661
 
        {
2662
 
                SC_full_error_copy(stmt, col_stmt, FALSE);
2663
 
                goto cleanup;
2664
 
        }
2665
 
 
2666
 
        /*
2667
 
         * Put the row version column at the end so it might not be mistaken
2668
 
         * for a key field.
2669
 
         */
2670
 
        if (!relisaview && !stmt->internal && atoi(ci->row_versioning))
2671
 
        {
2672
 
                /* For Row Versioning fields */
2673
 
                the_type = PG_TYPE_INT4;
2674
 
 
2675
 
                tuple = QR_AddNew(res);
2676
 
 
2677
 
                set_tuplefield_string(&tuple[COLUMNS_CATALOG_NAME], CurrCat(conn));
2678
 
                if (conn->schema_support)
2679
 
                        set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], GET_SCHEMA_NAME(table_owner));
2680
 
                else
2681
 
                        set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], NULL_STRING);
2682
 
                set_tuplefield_string(&tuple[COLUMNS_TABLE_NAME], table_name);
2683
 
                set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], "xmin");
2684
 
                sqltype = pgtype_to_concise_type(stmt, the_type, PG_STATIC);
2685
 
                set_tuplefield_int2(&tuple[COLUMNS_DATA_TYPE], sqltype);
2686
 
                set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, FALSE));
2687
 
                set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2688
 
                set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2689
 
                set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
2690
 
                set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(conn, the_type));
2691
 
                set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], SQL_NO_NULLS);
2692
 
                set_tuplefield_string(&tuple[COLUMNS_REMARKS], NULL_STRING);
2693
 
#if (ODBCVER >= 0x0300)
2694
 
                set_tuplefield_null(&tuple[COLUMNS_COLUMN_DEF]);
2695
 
                set_tuplefield_int2(&tuple[COLUMNS_SQL_DATA_TYPE], sqltype);
2696
 
                set_tuplefield_null(&tuple[COLUMNS_SQL_DATETIME_SUB]);
2697
 
                set_tuplefield_null(&tuple[COLUMNS_CHAR_OCTET_LENGTH]);
2698
 
                set_tuplefield_int4(&tuple[COLUMNS_ORDINAL_POSITION], ordinal);
2699
 
                set_tuplefield_string(&tuple[COLUMNS_IS_NULLABLE], "No");
2700
 
#endif /* ODBCVER */
2701
 
                set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_display_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2702
 
                set_tuplefield_int4(&tuple[COLUMNS_FIELD_TYPE], the_type);
2703
 
                set_tuplefield_int4(&tuple[COLUMNS_AUTO_INCREMENT], FALSE);
2704
 
                set_tuplefield_int2(&tuple[COLUMNS_PHYSICAL_NUMBER], XMIN_ATTNUM);
2705
 
                set_tuplefield_int4(&tuple[COLUMNS_TABLE_OID], greloid);
2706
 
                set_tuplefield_int4(&tuple[COLUMNS_BASE_TYPEID], 0);
2707
 
                set_tuplefield_int4(&tuple[COLUMNS_ATTTYPMOD], -1);
2708
 
                ordinal++;
2709
 
        }
2710
 
        result = SQL_SUCCESS;
2711
 
 
2712
 
cleanup:
2713
 
#undef  return
2714
 
        /*
2715
 
         * also, things need to think that this statement is finished so the
2716
 
         * results can be retrieved.
2717
 
         */
2718
 
        stmt->status = STMT_FINISHED;
2719
 
        stmt->catalog_result = TRUE;
2720
 
 
2721
 
        /* set up the current tuple pointer for SQLFetch */
2722
 
        stmt->currTuple = -1;
2723
 
        SC_set_rowset_start(stmt, -1, FALSE);
2724
 
        SC_set_current_col(stmt, -1);
2725
 
 
2726
 
        if (escSchemaName)
2727
 
                free(escSchemaName);
2728
 
        if (escTableName)
2729
 
                free(escTableName);
2730
 
        if (escColumnName)
2731
 
                free(escColumnName);
2732
 
        if (hcol_stmt)
2733
 
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
2734
 
        if (stmt->internal)
2735
 
                result = DiscardStatementSvp(stmt, result, FALSE);
2736
 
        mylog("%s: EXIT,  stmt=%p\n", func, stmt);
2737
 
        return result;
2738
 
}
2739
 
 
2740
 
 
2741
 
RETCODE         SQL_API
2742
 
PGAPI_SpecialColumns(
2743
 
                                HSTMT hstmt,
2744
 
                                SQLUSMALLINT fColType,
2745
 
                                const SQLCHAR FAR * szTableQualifier,
2746
 
                                SQLSMALLINT cbTableQualifier,
2747
 
                                const SQLCHAR FAR * szTableOwner, /* OA E*/
2748
 
                                SQLSMALLINT cbTableOwner,
2749
 
                                const SQLCHAR FAR * szTableName, /* OA(R) E*/
2750
 
                                SQLSMALLINT cbTableName,
2751
 
                                SQLUSMALLINT fScope,
2752
 
                                SQLUSMALLINT fNullable)
2753
 
{
2754
 
        CSTR func = "PGAPI_SpecialColumns";
2755
 
        TupleField      *tuple;
2756
 
        StatementClass *stmt = (StatementClass *) hstmt;
2757
 
        ConnectionClass *conn;
2758
 
        QResultClass    *res;
2759
 
        ConnInfo   *ci;
2760
 
        HSTMT           hcol_stmt = NULL;
2761
 
        StatementClass *col_stmt;
2762
 
        char            columns_query[INFO_INQUIRY_LEN];
2763
 
        char            *escSchemaName = NULL, *escTableName = NULL;
2764
 
        RETCODE         result = SQL_SUCCESS;
2765
 
        char            relhasrules[MAX_INFO_STRING], relkind[8], relhasoids[8];
2766
 
        BOOL            relisaview;
2767
 
        SQLSMALLINT     internal_asis_type = SQL_C_CHAR, cbSchemaName;
2768
 
        const char      *szSchemaName, *eq_string;
2769
 
 
2770
 
        mylog("%s: entering...stmt=%p scnm=%p len=%d colType=%d scope=%d\n", func, stmt, szTableOwner, cbTableOwner, fColType, fScope);
2771
 
 
2772
 
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
2773
 
                return result;
2774
 
        conn = SC_get_conn(stmt);
2775
 
        ci = &(conn->connInfo);
2776
 
#ifdef  UNICODE_SUPPORT
2777
 
        if (CC_is_in_unicode_driver(conn))
2778
 
                internal_asis_type = INTERNAL_ASIS_TYPE;
2779
 
#endif /* UNICODE_SUPPORT */
2780
 
 
2781
 
        szSchemaName = szTableOwner;
2782
 
        cbSchemaName = cbTableOwner;
2783
 
 
2784
 
        escTableName = simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
2785
 
        if (!escTableName)
2786
 
        {
2787
 
                SC_set_error(stmt, STMT_INVALID_NULL_ARG, "The table name is required", func);
2788
 
                return SQL_ERROR;
2789
 
        }
2790
 
#define return  DONT_CALL_RETURN_FROM_HERE???
2791
 
 
2792
 
retry_public_schema:
2793
 
        if (escSchemaName)
2794
 
                free(escSchemaName);
2795
 
        escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn);
2796
 
        eq_string = gen_opestr(eqop, conn);
2797
 
        /*
2798
 
         * Create the query to find out if this is a view or not...
2799
 
         */
2800
 
        strcpy(columns_query, "select c.relhasrules, c.relkind");
2801
 
        if (PG_VERSION_GE(conn, 7.2))
2802
 
                strcat(columns_query, ", c.relhasoids");
2803
 
        if (conn->schema_support)
2804
 
                strcat(columns_query, " from pg_catalog.pg_namespace u,"
2805
 
                " pg_catalog.pg_class c where "
2806
 
                        "u.oid = c.relnamespace");
2807
 
        else
2808
 
                strcat(columns_query, " from pg_user u, pg_class c where "
2809
 
                        "u.usesysid = c.relowner");
2810
 
 
2811
 
        /* TableName cannot contain a string search pattern */
2812
 
        /* my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName); */
2813
 
        if (escTableName)
2814
 
                snprintf_add(columns_query, sizeof(columns_query), " and c.relname %s'%s'", eq_string, escTableName);
2815
 
        /* SchemaName cannot contain a string search pattern */
2816
 
        if (conn->schema_support)
2817
 
                schema_strcat1(columns_query, " and u.nspname %s'%.*s'", eq_string, escSchemaName, SQL_NTS, szTableName, cbTableName, conn);
2818
 
        else
2819
 
                my_strcat1(columns_query, " and u.usename %s'%.*s'", eq_string, escSchemaName, SQL_NTS);
2820
 
 
2821
 
 
2822
 
        result = PGAPI_AllocStmt(conn, &hcol_stmt, 0);
2823
 
        if (!SQL_SUCCEEDED(result))
2824
 
        {
2825
 
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for SQLSpecialColumns result.", func);
2826
 
                result = SQL_ERROR;
2827
 
                goto cleanup;
2828
 
        }
2829
 
        col_stmt = (StatementClass *) hcol_stmt;
2830
 
 
2831
 
        mylog("%s: hcol_stmt = %p, col_stmt = %p\n", func, hcol_stmt, col_stmt);
2832
 
 
2833
 
        result = PGAPI_ExecDirect(hcol_stmt, columns_query, SQL_NTS, 0);
2834
 
        if (!SQL_SUCCEEDED(result))
2835
 
        {
2836
 
                SC_full_error_copy(stmt, col_stmt, FALSE);
2837
 
                result = SQL_ERROR;
2838
 
                goto cleanup;
2839
 
        }
2840
 
 
2841
 
        /* If not found */
2842
 
        if (conn->schema_support &&
2843
 
            (res = SC_get_Result(col_stmt)) &&
2844
 
            0 == QR_get_num_total_tuples(res))
2845
 
        {
2846
 
                if (allow_public_schema(conn, szSchemaName, cbSchemaName))
2847
 
                {
2848
 
                        PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
2849
 
                        hcol_stmt = NULL;
2850
 
                        szSchemaName = pubstr;
2851
 
                        cbSchemaName = SQL_NTS;
2852
 
                        goto retry_public_schema;
2853
 
                }
2854
 
        }
2855
 
 
2856
 
        result = PGAPI_BindCol(hcol_stmt, 1, internal_asis_type,
2857
 
                                        relhasrules, sizeof(relhasrules), NULL);
2858
 
        if (!SQL_SUCCEEDED(result))
2859
 
        {
2860
 
                SC_error_copy(stmt, col_stmt, TRUE);
2861
 
                result = SQL_ERROR;
2862
 
                goto cleanup;
2863
 
        }
2864
 
 
2865
 
        result = PGAPI_BindCol(hcol_stmt, 2, internal_asis_type,
2866
 
                                        relkind, sizeof(relkind), NULL);
2867
 
        if (!SQL_SUCCEEDED(result))
2868
 
        {
2869
 
                SC_error_copy(stmt, col_stmt, TRUE);
2870
 
                result = SQL_ERROR;
2871
 
                goto cleanup;
2872
 
        }
2873
 
        relhasoids[0] = '1';
2874
 
        if (PG_VERSION_GE(conn, 7.2))
2875
 
        {
2876
 
                result = PGAPI_BindCol(hcol_stmt, 3, internal_asis_type,
2877
 
                                        relhasoids, sizeof(relhasoids), NULL);
2878
 
                if (!SQL_SUCCEEDED(result))
2879
 
                {
2880
 
                        SC_error_copy(stmt, col_stmt, TRUE);
2881
 
                        result = SQL_ERROR;
2882
 
                        goto cleanup;
2883
 
                }
2884
 
        }
2885
 
 
2886
 
        result = PGAPI_Fetch(hcol_stmt);
2887
 
        if (PG_VERSION_GE(conn, 7.1))
2888
 
                relisaview = (relkind[0] == 'v');
2889
 
        else
2890
 
                relisaview = (relhasrules[0] == '1');
2891
 
        PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
2892
 
        hcol_stmt = NULL;
2893
 
 
2894
 
        res = QR_Constructor();
2895
 
        SC_set_Result(stmt, res);
2896
 
        extend_column_bindings(SC_get_ARDF(stmt), 8);
2897
 
 
2898
 
        stmt->catalog_result = TRUE;
2899
 
        QR_set_num_fields(res, 8);
2900
 
        QR_set_field_info_v(res, 0, "SCOPE", PG_TYPE_INT2, 2);
2901
 
        QR_set_field_info_v(res, 1, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
2902
 
        QR_set_field_info_v(res, 2, "DATA_TYPE", PG_TYPE_INT2, 2);
2903
 
        QR_set_field_info_v(res, 3, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
2904
 
        QR_set_field_info_v(res, 4, "PRECISION", PG_TYPE_INT4, 4);
2905
 
        QR_set_field_info_v(res, 5, "LENGTH", PG_TYPE_INT4, 4);
2906
 
        QR_set_field_info_v(res, 6, "SCALE", PG_TYPE_INT2, 2);
2907
 
        QR_set_field_info_v(res, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2);
2908
 
 
2909
 
        if (relisaview)
2910
 
        {
2911
 
                /* there's no oid for views */
2912
 
                if (fColType == SQL_BEST_ROWID)
2913
 
                {
2914
 
                        goto cleanup;
2915
 
                }
2916
 
                else if (fColType == SQL_ROWVER)
2917
 
                {
2918
 
                        Int2            the_type = PG_TYPE_TID;
2919
 
 
2920
 
                        tuple = QR_AddNew(res);
2921
 
 
2922
 
                        set_tuplefield_null(&tuple[0]);
2923
 
                        set_tuplefield_string(&tuple[1], "ctid");
2924
 
                        set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
2925
 
                        set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, FALSE));
2926
 
                        set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2927
 
                        set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2928
 
                        set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
2929
 
                        set_tuplefield_int2(&tuple[7], SQL_PC_NOT_PSEUDO);
2930
 
inolog("Add ctid\n");
2931
 
                }
2932
 
        }
2933
 
        else
2934
 
        {
2935
 
                /* use the oid value for the rowid */
2936
 
                if (fColType == SQL_BEST_ROWID)
2937
 
                {
2938
 
                        Int2    the_type = PG_TYPE_OID;
2939
 
 
2940
 
                        if (relhasoids[0] != '1')
2941
 
                        {
2942
 
                                goto cleanup;
2943
 
                        }
2944
 
                        tuple = QR_AddNew(res);
2945
 
 
2946
 
                        set_tuplefield_int2(&tuple[0], SQL_SCOPE_SESSION);
2947
 
                        set_tuplefield_string(&tuple[1], OID_NAME);
2948
 
                        set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
2949
 
                        set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, TRUE));
2950
 
                        set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2951
 
                        set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2952
 
                        set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
2953
 
                        set_tuplefield_int2(&tuple[7], SQL_PC_PSEUDO);
2954
 
                }
2955
 
                else if (fColType == SQL_ROWVER)
2956
 
                {
2957
 
                        Int2            the_type = PG_TYPE_XID;
2958
 
 
2959
 
                        /* if (atoi(ci->row_versioning)) */
2960
 
                        {
2961
 
                                tuple = QR_AddNew(res);
2962
 
 
2963
 
                                set_tuplefield_null(&tuple[0]);
2964
 
                                set_tuplefield_string(&tuple[1], "xmin");
2965
 
                                set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
2966
 
                                set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, FALSE));
2967
 
                                set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2968
 
                                set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
2969
 
                                set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
2970
 
                                set_tuplefield_int2(&tuple[7], SQL_PC_PSEUDO);
2971
 
                        }
2972
 
                }
2973
 
        }
2974
 
 
2975
 
cleanup:
2976
 
#undef  return
2977
 
        if (escSchemaName)
2978
 
                free(escSchemaName);
2979
 
        if (escTableName)
2980
 
                free(escTableName);
2981
 
        stmt->status = STMT_FINISHED;
2982
 
        stmt->currTuple = -1;
2983
 
        SC_set_rowset_start(stmt, -1, FALSE);
2984
 
        SC_set_current_col(stmt, -1);
2985
 
        if (hcol_stmt)
2986
 
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
2987
 
        if (stmt->internal)
2988
 
                result = DiscardStatementSvp(stmt, result, FALSE);
2989
 
        mylog("%s: EXIT,  stmt=%p\n", func, stmt);
2990
 
        return result;
2991
 
}
2992
 
 
2993
 
 
2994
 
#define INDOPTION_DESC          0x0001  /* values are in reverse order */
2995
 
RETCODE         SQL_API
2996
 
PGAPI_Statistics(
2997
 
                        HSTMT hstmt,
2998
 
                        const SQLCHAR FAR * szTableQualifier, /* OA X*/
2999
 
                        SQLSMALLINT cbTableQualifier,
3000
 
                        const SQLCHAR FAR * szTableOwner, /* OA E*/
3001
 
                        SQLSMALLINT cbTableOwner,
3002
 
                        const SQLCHAR FAR * szTableName, /* OA(R) E*/
3003
 
                        SQLSMALLINT cbTableName,
3004
 
                        SQLUSMALLINT fUnique,
3005
 
                        SQLUSMALLINT fAccuracy)
3006
 
{
3007
 
        CSTR func = "PGAPI_Statistics";
3008
 
        StatementClass *stmt = (StatementClass *) hstmt;
3009
 
        ConnectionClass *conn;
3010
 
        QResultClass    *res;
3011
 
        char            index_query[INFO_INQUIRY_LEN];
3012
 
        HSTMT           hcol_stmt = NULL, hindx_stmt = NULL;
3013
 
        RETCODE         ret = SQL_ERROR, result;
3014
 
        char            *escSchemaName = NULL, *table_name = NULL, *escTableName = NULL;
3015
 
        char            index_name[MAX_INFO_STRING];
3016
 
        short           fields_vector[INDEX_KEYS_STORAGE_COUNT + 1];
3017
 
        short           indopt_vector[INDEX_KEYS_STORAGE_COUNT + 1];
3018
 
        char            isunique[10],
3019
 
                                isclustered[10],
3020
 
                                ishash[MAX_INFO_STRING];
3021
 
        SQLLEN          index_name_len, fields_vector_len;
3022
 
        TupleField      *tuple;
3023
 
        int                     i;
3024
 
        StatementClass *col_stmt,
3025
 
                           *indx_stmt;
3026
 
        char            column_name[MAX_INFO_STRING],
3027
 
                        table_schemaname[MAX_INFO_STRING],
3028
 
                                relhasrules[10];
3029
 
        struct columns_idx {
3030
 
                int     pnum;
3031
 
                char    *col_name;
3032
 
        } *column_names = NULL;
3033
 
        /* char   **column_names = NULL; */
3034
 
        SQLLEN          column_name_len;
3035
 
        int             total_columns = 0, alcount;
3036
 
        ConnInfo   *ci;
3037
 
        char            buf[256];
3038
 
        SQLSMALLINT     internal_asis_type = SQL_C_CHAR, cbSchemaName, field_number;
3039
 
        const char      *szSchemaName, *eq_string;
3040
 
        OID             ioid;
3041
 
        Int4            relhasoids;
3042
 
 
3043
 
        mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func, stmt, szTableOwner, cbTableOwner);
3044
 
 
3045
 
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
3046
 
                return result;
3047
 
 
3048
 
        table_name = make_string(szTableName, cbTableName, NULL, 0);
3049
 
        if (!table_name)
3050
 
        {
3051
 
                SC_set_error(stmt, STMT_INVALID_NULL_ARG, "The table name is required", func);
3052
 
                return result;
3053
 
        }
3054
 
        conn = SC_get_conn(stmt);
3055
 
        ci = &(conn->connInfo);
3056
 
#ifdef  UNICODE_SUPPORT
3057
 
        if (CC_is_in_unicode_driver(conn))
3058
 
                internal_asis_type = INTERNAL_ASIS_TYPE;
3059
 
#endif /* UNICODE_SUPPORT */
3060
 
 
3061
 
        if (res = QR_Constructor(), !res)
3062
 
        {
3063
 
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Statistics result.", func);
3064
 
                return SQL_ERROR;
3065
 
        }
3066
 
        SC_set_Result(stmt, res);
3067
 
 
3068
 
        /* the binding structure for a statement is not set up until */
3069
 
 
3070
 
        /*
3071
 
         * a statement is actually executed, so we'll have to do this
3072
 
         * ourselves.
3073
 
         */
3074
 
        extend_column_bindings(SC_get_ARDF(stmt), 13);
3075
 
 
3076
 
        stmt->catalog_result = TRUE;
3077
 
        /* set the field names */
3078
 
        QR_set_num_fields(res, NUM_OF_STATS_FIELDS);
3079
 
        QR_set_field_info_v(res, STATS_CATALOG_NAME, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
3080
 
        QR_set_field_info_v(res, STATS_SCHEMA_NAME, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
3081
 
        QR_set_field_info_v(res, STATS_TABLE_NAME, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
3082
 
        QR_set_field_info_v(res, STATS_NON_UNIQUE, "NON_UNIQUE", PG_TYPE_INT2, 2);
3083
 
        QR_set_field_info_v(res, STATS_INDEX_QUALIFIER, "INDEX_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
3084
 
        QR_set_field_info_v(res, STATS_INDEX_NAME, "INDEX_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
3085
 
        QR_set_field_info_v(res, STATS_TYPE, "TYPE", PG_TYPE_INT2, 2);
3086
 
        QR_set_field_info_v(res, STATS_SEQ_IN_INDEX, "SEQ_IN_INDEX", PG_TYPE_INT2, 2);
3087
 
        QR_set_field_info_v(res, STATS_COLUMN_NAME, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
3088
 
        QR_set_field_info_v(res, STATS_COLLATION, "COLLATION", PG_TYPE_CHAR, 1);
3089
 
        QR_set_field_info_v(res, STATS_CARDINALITY, "CARDINALITY", PG_TYPE_INT4, 4);
3090
 
        QR_set_field_info_v(res, STATS_PAGES, "PAGES", PG_TYPE_INT4, 4);
3091
 
        QR_set_field_info_v(res, STATS_FILTER_CONDITION, "FILTER_CONDITION", PG_TYPE_VARCHAR, MAX_INFO_STRING);
3092
 
 
3093
 
#define return  DONT_CALL_RETURN_FROM_HERE???
3094
 
        szSchemaName = szTableOwner;
3095
 
        cbSchemaName = cbTableOwner;
3096
 
 
3097
 
        table_schemaname[0] = '\0';
3098
 
        if (conn->schema_support)
3099
 
                schema_strcat(table_schemaname, "%.*s", szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
3100
 
 
3101
 
        /*
3102
 
         * we need to get a list of the field names first, so we can return
3103
 
         * them later.
3104
 
         */
3105
 
        result = PGAPI_AllocStmt(conn, &hcol_stmt, 0);
3106
 
        if (!SQL_SUCCEEDED(result))
3107
 
        {
3108
 
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in PGAPI_Statistics for columns.", func);
3109
 
                goto cleanup;
3110
 
        }
3111
 
 
3112
 
        col_stmt = (StatementClass *) hcol_stmt;
3113
 
 
3114
 
        /*
3115
 
         * "internal" prevents SQLColumns from returning the oid if it is
3116
 
         * being shown. This would throw everything off.
3117
 
         */
3118
 
        col_stmt->internal = TRUE;
3119
 
        /* 
3120
 
         * table_name parameter cannot contain a string search pattern. 
3121
 
         */
3122
 
        result = PGAPI_Columns(hcol_stmt, NULL, 0, table_schemaname, SQL_NTS,
3123
 
                                table_name, SQL_NTS, NULL, 0, PODBC_NOT_SEARCH_PATTERN | PODBC_SEARCH_PUBLIC_SCHEMA, 0, 0);
3124
 
        col_stmt->internal = FALSE;
3125
 
 
3126
 
        if (!SQL_SUCCEEDED(result))
3127
 
        {
3128
 
                SC_error_copy(stmt, col_stmt, TRUE);
3129
 
                goto cleanup;
3130
 
        }
3131
 
        result = PGAPI_BindCol(hcol_stmt, COLUMNS_COLUMN_NAME + 1, internal_asis_type,
3132
 
                                                 column_name, sizeof(column_name), &column_name_len);
3133
 
        if (!SQL_SUCCEEDED(result))
3134
 
        {
3135
 
                SC_error_copy(stmt, col_stmt, TRUE);
3136
 
                goto cleanup;
3137
 
        }
3138
 
        result = PGAPI_BindCol(hcol_stmt, COLUMNS_PHYSICAL_NUMBER + 1, SQL_C_SHORT,
3139
 
                        &field_number, sizeof(field_number), NULL);
3140
 
        if (!SQL_SUCCEEDED(result))
3141
 
        {
3142
 
                SC_error_copy(stmt, col_stmt, TRUE);
3143
 
                goto cleanup;
3144
 
        }
3145
 
 
3146
 
        alcount = 0;
3147
 
        result = PGAPI_Fetch(hcol_stmt);
3148
 
        while (SQL_SUCCEEDED(result))
3149
 
        {
3150
 
                if (0 == total_columns)
3151
 
                        PGAPI_GetData(hcol_stmt, 2, internal_asis_type, table_schemaname, sizeof(table_schemaname), NULL);
3152
 
 
3153
 
                if (total_columns >= alcount)
3154
 
                {
3155
 
                        if (0 == alcount)
3156
 
                                alcount = 4;
3157
 
                        else
3158
 
                                alcount *= 2;
3159
 
                        column_names =
3160
 
                                (struct columns_idx *) realloc(column_names,
3161
 
                                                          alcount * sizeof(struct columns_idx));
3162
 
                }
3163
 
                column_names[total_columns].col_name =
3164
 
                        (char *) malloc(strlen(column_name) + 1);
3165
 
                strcpy(column_names[total_columns].col_name, column_name);
3166
 
                column_names[total_columns].pnum = field_number;
3167
 
                total_columns++;
3168
 
 
3169
 
                mylog("%s: column_name = '%s'\n", func, column_name);
3170
 
 
3171
 
                result = PGAPI_Fetch(hcol_stmt);
3172
 
        }
3173
 
 
3174
 
        if (result != SQL_NO_DATA_FOUND)
3175
 
        {
3176
 
                SC_full_error_copy(stmt, col_stmt, FALSE);
3177
 
                goto cleanup;
3178
 
        }
3179
 
        PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
3180
 
        hcol_stmt = NULL;
3181
 
        if (total_columns == 0)
3182
 
        {
3183
 
                /* Couldn't get column names in SQLStatistics.; */
3184
 
                ret = SQL_SUCCESS;
3185
 
                goto cleanup;
3186
 
        }
3187
 
 
3188
 
        /* get a list of indexes on this table */
3189
 
        result = PGAPI_AllocStmt(conn, &hindx_stmt, 0);
3190
 
        if (!SQL_SUCCEEDED(result))
3191
 
        {
3192
 
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in SQLStatistics for indices.", func);
3193
 
                goto cleanup;
3194
 
 
3195
 
        }
3196
 
        indx_stmt = (StatementClass *) hindx_stmt;
3197
 
 
3198
 
        /* TableName cannot contain a string search pattern */
3199
 
        escTableName = simpleCatalogEscape(table_name, SQL_NTS, NULL, conn);
3200
 
        eq_string = gen_opestr(eqop, conn); 
3201
 
        if (conn->schema_support)
3202
 
        {
3203
 
                escSchemaName = simpleCatalogEscape(table_schemaname, SQL_NTS, NULL, conn); 
3204
 
                snprintf(index_query, sizeof(index_query), "select c.relname, i.indkey, i.indisunique"
3205
 
                        ", i.indisclustered, a.amname, c.relhasrules, n.nspname"
3206
 
                        ", c.oid, %s, %s"
3207
 
                        " from pg_catalog.pg_index i, pg_catalog.pg_class c,"
3208
 
                        " pg_catalog.pg_class d, pg_catalog.pg_am a,"
3209
 
                        " pg_catalog.pg_namespace n"
3210
 
                        " where d.relname %s'%s'"
3211
 
                        " and n.nspname %s'%s'"
3212
 
                        " and n.oid = d.relnamespace"
3213
 
                        " and d.oid = i.indrelid"
3214
 
                        " and i.indexrelid = c.oid"
3215
 
                        " and c.relam = a.oid order by"
3216
 
                        , PG_VERSION_GE(conn, 7.2) ? "d.relhasoids" : "1"
3217
 
                        , PG_VERSION_GE(conn, 8.3) ? "i.indoption" : "0"
3218
 
                        , eq_string, escTableName, eq_string, escSchemaName);
3219
 
        }
3220
 
        else
3221
 
                snprintf(index_query, sizeof(index_query), "select c.relname, i.indkey, i.indisunique"
3222
 
                        ", i.indisclustered, a.amname, c.relhasrules, c.oid, %s, 0"
3223
 
                        " from pg_index i, pg_class c, pg_class d, pg_am a"
3224
 
                        " where d.relname %s'%s'"
3225
 
                        " and d.oid = i.indrelid"
3226
 
                        " and i.indexrelid = c.oid"
3227
 
                        " and c.relam = a.oid order by"
3228
 
                        , PG_VERSION_GE(conn, 7.2) ? "d.relhasoids" : "1"
3229
 
                        , eq_string, escTableName);
3230
 
        if (PG_VERSION_GT(SC_get_conn(stmt), 6.4))
3231
 
                strcat(index_query, " i.indisprimary desc,");
3232
 
        if (conn->schema_support)
3233
 
                strcat(index_query, " i.indisunique, n.nspname, c.relname");
3234
 
        else
3235
 
                strcat(index_query, " i.indisunique, c.relname");
3236
 
 
3237
 
        result = PGAPI_ExecDirect(hindx_stmt, index_query, SQL_NTS, 0);
3238
 
        if (!SQL_SUCCEEDED(result))
3239
 
        {
3240
 
                /*
3241
 
                 * "Couldn't execute index query (w/SQLExecDirect) in
3242
 
                 * SQLStatistics.";
3243
 
                 */
3244
 
                SC_full_error_copy(stmt, indx_stmt, FALSE);
3245
 
                goto cleanup;
3246
 
        }
3247
 
 
3248
 
        /* bind the index name column */
3249
 
        result = PGAPI_BindCol(hindx_stmt, 1, internal_asis_type,
3250
 
                                                   index_name, MAX_INFO_STRING, &index_name_len);
3251
 
        if (!SQL_SUCCEEDED(result))
3252
 
        {
3253
 
                SC_error_copy(stmt, indx_stmt, TRUE);   /* "Couldn't bind column 
3254
 
                                                * in SQLStatistics."; */
3255
 
                goto cleanup;
3256
 
 
3257
 
        }
3258
 
        /* bind the vector column */
3259
 
        result = PGAPI_BindCol(hindx_stmt, 2, SQL_C_DEFAULT,
3260
 
                        fields_vector, sizeof(fields_vector), &fields_vector_len);
3261
 
        if (!SQL_SUCCEEDED(result))
3262
 
        {
3263
 
                SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column 
3264
 
                                                 * in SQLStatistics."; */
3265
 
                goto cleanup;
3266
 
 
3267
 
        }
3268
 
        /* bind the "is unique" column */
3269
 
        result = PGAPI_BindCol(hindx_stmt, 3, internal_asis_type,
3270
 
                                                   isunique, sizeof(isunique), NULL);
3271
 
        if (!SQL_SUCCEEDED(result))
3272
 
        {
3273
 
                SC_error_copy(stmt, indx_stmt, TRUE);   /* "Couldn't bind column 
3274
 
                                                 * in SQLStatistics."; */
3275
 
                goto cleanup;
3276
 
        }
3277
 
 
3278
 
        /* bind the "is clustered" column */
3279
 
        result = PGAPI_BindCol(hindx_stmt, 4, internal_asis_type,
3280
 
                                                   isclustered, sizeof(isclustered), NULL);
3281
 
        if (!SQL_SUCCEEDED(result))
3282
 
        {
3283
 
                SC_error_copy(stmt, indx_stmt, TRUE);   /* "Couldn't bind column *
3284
 
                                                 * in SQLStatistics."; */
3285
 
                goto cleanup;
3286
 
 
3287
 
        }
3288
 
 
3289
 
        /* bind the "is hash" column */
3290
 
        result = PGAPI_BindCol(hindx_stmt, 5, internal_asis_type,
3291
 
                                                   ishash, sizeof(ishash), NULL);
3292
 
        if (!SQL_SUCCEEDED(result))
3293
 
        {
3294
 
                SC_error_copy(stmt, indx_stmt, TRUE);   /* "Couldn't bind column * 
3295
 
                                                 * in SQLStatistics."; */
3296
 
                goto cleanup;
3297
 
 
3298
 
        }
3299
 
 
3300
 
        result = PGAPI_BindCol(hindx_stmt, 6, internal_asis_type,
3301
 
                                        relhasrules, sizeof(relhasrules), NULL);
3302
 
        if (!SQL_SUCCEEDED(result))
3303
 
        {
3304
 
                SC_error_copy(stmt, indx_stmt, TRUE);
3305
 
                goto cleanup;
3306
 
        }
3307
 
 
3308
 
        result = PGAPI_BindCol(hindx_stmt, 8, SQL_C_ULONG,
3309
 
                                        &ioid, sizeof(ioid), NULL);
3310
 
        if (!SQL_SUCCEEDED(result))
3311
 
        {
3312
 
                SC_error_copy(stmt, indx_stmt, TRUE);
3313
 
                goto cleanup;
3314
 
        }
3315
 
 
3316
 
        result = PGAPI_BindCol(hindx_stmt, 9, SQL_C_ULONG,
3317
 
                                        &relhasoids, sizeof(relhasoids), NULL);
3318
 
        if (!SQL_SUCCEEDED(result))
3319
 
        {
3320
 
                SC_error_copy(stmt, indx_stmt, TRUE);
3321
 
                goto cleanup;
3322
 
        }
3323
 
 
3324
 
        /* bind the vector column */
3325
 
        result = PGAPI_BindCol(hindx_stmt, 10, SQL_C_DEFAULT,
3326
 
                        indopt_vector, sizeof(fields_vector), &fields_vector_len);
3327
 
        if (!SQL_SUCCEEDED(result))
3328
 
        {
3329
 
                SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column 
3330
 
                                                 * in SQLStatistics."; */
3331
 
                goto cleanup;
3332
 
 
3333
 
        }
3334
 
 
3335
 
        relhasrules[0] = '0';
3336
 
        result = PGAPI_Fetch(hindx_stmt);
3337
 
        /* fake index of OID */
3338
 
        if (relhasoids && relhasrules[0] != '1' && atoi(ci->show_oid_column) && atoi(ci->fake_oid_index))
3339
 
        {
3340
 
                tuple = QR_AddNew(res);
3341
 
 
3342
 
                /* no table qualifier */
3343
 
                set_tuplefield_string(&tuple[STATS_CATALOG_NAME], CurrCat(conn));
3344
 
                /* don't set the table owner, else Access tries to use it */
3345
 
                set_tuplefield_string(&tuple[STATS_SCHEMA_NAME], GET_SCHEMA_NAME(table_schemaname));
3346
 
                set_tuplefield_string(&tuple[STATS_TABLE_NAME], table_name);
3347
 
 
3348
 
                /* non-unique index? */
3349
 
                set_tuplefield_int2(&tuple[STATS_NON_UNIQUE], (Int2) (ci->drivers.unique_index ? FALSE : TRUE));
3350
 
 
3351
 
                /* no index qualifier */
3352
 
                set_tuplefield_string(&tuple[STATS_INDEX_QUALIFIER], GET_SCHEMA_NAME(table_schemaname));
3353
 
 
3354
 
                snprintf(buf, sizeof(buf), "%s_idx_fake_oid", table_name);
3355
 
                set_tuplefield_string(&tuple[STATS_INDEX_NAME], buf);
3356
 
 
3357
 
                /*
3358
 
                 * Clustered/HASH index?
3359
 
                 */
3360
 
                set_tuplefield_int2(&tuple[STATS_TYPE], (Int2) SQL_INDEX_OTHER);
3361
 
                set_tuplefield_int2(&tuple[STATS_SEQ_IN_INDEX], (Int2) 1);
3362
 
 
3363
 
                set_tuplefield_string(&tuple[STATS_COLUMN_NAME], OID_NAME);
3364
 
                set_tuplefield_string(&tuple[STATS_COLLATION], "A");
3365
 
                set_tuplefield_null(&tuple[STATS_CARDINALITY]);
3366
 
                set_tuplefield_null(&tuple[STATS_PAGES]);
3367
 
                set_tuplefield_null(&tuple[STATS_FILTER_CONDITION]);
3368
 
        }
3369
 
 
3370
 
        while (SQL_SUCCEEDED(result))
3371
 
        {
3372
 
                /* If only requesting unique indexs, then just return those. */
3373
 
                if (fUnique == SQL_INDEX_ALL ||
3374
 
                        (fUnique == SQL_INDEX_UNIQUE && atoi(isunique)))
3375
 
                {
3376
 
                        int     colcnt, attnum;
3377
 
 
3378
 
                        /* add a row in this table for each field in the index */
3379
 
                        colcnt = fields_vector[0];
3380
 
                        for (i = 1; i <= colcnt; i++)
3381
 
                        {
3382
 
                                tuple = QR_AddNew(res);
3383
 
 
3384
 
                                /* no table qualifier */
3385
 
                                set_tuplefield_string(&tuple[STATS_CATALOG_NAME], CurrCat(conn));
3386
 
                                /* don't set the table owner, else Access tries to use it */
3387
 
                                set_tuplefield_string(&tuple[STATS_SCHEMA_NAME], GET_SCHEMA_NAME(table_schemaname));
3388
 
                                set_tuplefield_string(&tuple[STATS_TABLE_NAME], table_name);
3389
 
 
3390
 
                                /* non-unique index? */
3391
 
                                if (ci->drivers.unique_index)
3392
 
                                        set_tuplefield_int2(&tuple[STATS_NON_UNIQUE], (Int2) (atoi(isunique) ? FALSE : TRUE));
3393
 
                                else
3394
 
                                        set_tuplefield_int2(&tuple[STATS_NON_UNIQUE], TRUE);
3395
 
 
3396
 
                                /* no index qualifier */
3397
 
                                set_tuplefield_string(&tuple[STATS_INDEX_QUALIFIER], GET_SCHEMA_NAME(table_schemaname));
3398
 
                                set_tuplefield_string(&tuple[STATS_INDEX_NAME], index_name);
3399
 
 
3400
 
                                /*
3401
 
                                 * Clustered/HASH index?
3402
 
                                 */
3403
 
                                set_tuplefield_int2(&tuple[STATS_TYPE], (Int2)
3404
 
                                                           (atoi(isclustered) ? SQL_INDEX_CLUSTERED :
3405
 
                                                                (!strncmp(ishash, "hash", 4)) ? SQL_INDEX_HASHED : SQL_INDEX_OTHER));
3406
 
                                set_tuplefield_int2(&tuple[STATS_SEQ_IN_INDEX], (Int2) i);
3407
 
 
3408
 
                                attnum = fields_vector[i];
3409
 
                                if (OID_ATTNUM == attnum)
3410
 
                                {
3411
 
                                        set_tuplefield_string(&tuple[STATS_COLUMN_NAME], OID_NAME);
3412
 
                                        mylog("%s: column name = oid\n", func);
3413
 
                                }
3414
 
                                else if (0 == attnum)
3415
 
                                {
3416
 
                                        char    cmd[64];
3417
 
 
3418
 
                                        QResultClass *res;
3419
 
 
3420
 
                                        snprintf(cmd, sizeof(cmd), "select pg_get_indexdef(%u, %d, true)", ioid, i);
3421
 
                                        res = CC_send_query(conn, cmd, NULL, IGNORE_ABORT_ON_CONN, stmt);
3422
 
                                        if (QR_command_maybe_successful(res))
3423
 
                                                set_tuplefield_string(&tuple[STATS_COLUMN_NAME], QR_get_value_backend_text(res, 0, 0));
3424
 
                                        QR_Destructor(res);
3425
 
                                }
3426
 
                                else
3427
 
                                {
3428
 
                                        int j, matchidx;
3429
 
                                        BOOL    unknownf = TRUE;
3430
 
 
3431
 
                                        if (attnum > 0)
3432
 
                                        {
3433
 
                                                for (j = 0; j < total_columns; j++)
3434
 
                                                {
3435
 
                                                        if (attnum == column_names[j].pnum)
3436
 
                                                        {
3437
 
                                                                matchidx = j;
3438
 
                                                                unknownf = FALSE;
3439
 
                                                                break;
3440
 
                                                        }
3441
 
                                                }
3442
 
                                        }
3443
 
                                        if (unknownf)
3444
 
                                        {
3445
 
                                                set_tuplefield_string(&tuple[STATS_COLUMN_NAME], "UNKNOWN");
3446
 
                                                mylog("%s: column name = UNKNOWN\n", func);
3447
 
                                        }
3448
 
                                        else
3449
 
                                        {
3450
 
                                                set_tuplefield_string(&tuple[STATS_COLUMN_NAME], column_names[matchidx].col_name);
3451
 
                                                mylog("%s: column name = '%s'\n", func, column_names[matchidx].col_name);
3452
 
                                        }
3453
 
                                }
3454
 
 
3455
 
                                if (i <= indopt_vector[0] &&
3456
 
                                    (indopt_vector[i] & INDOPTION_DESC) != 0)
3457
 
                                        set_tuplefield_string(&tuple[STATS_COLLATION], "D");
3458
 
                                else
3459
 
                                        set_tuplefield_string(&tuple[STATS_COLLATION], "A");
3460
 
                                set_tuplefield_null(&tuple[STATS_CARDINALITY]);
3461
 
                                set_tuplefield_null(&tuple[STATS_PAGES]);
3462
 
                                set_tuplefield_null(&tuple[STATS_FILTER_CONDITION]);
3463
 
                        }
3464
 
                }
3465
 
 
3466
 
                result = PGAPI_Fetch(hindx_stmt);
3467
 
        }
3468
 
        if (result != SQL_NO_DATA_FOUND)
3469
 
        {
3470
 
                /* "SQLFetch failed in SQLStatistics."; */
3471
 
                SC_full_error_copy(stmt, indx_stmt, FALSE);
3472
 
                goto cleanup;
3473
 
        }
3474
 
        ret = SQL_SUCCESS;
3475
 
 
3476
 
cleanup:
3477
 
#undef  return
3478
 
        /*
3479
 
         * also, things need to think that this statement is finished so the
3480
 
         * results can be retrieved.
3481
 
         */
3482
 
        stmt->status = STMT_FINISHED;
3483
 
 
3484
 
        if (hcol_stmt)
3485
 
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
3486
 
        if (hindx_stmt)
3487
 
                PGAPI_FreeStmt(hindx_stmt, SQL_DROP);
3488
 
        /* These things should be freed on any error ALSO! */
3489
 
        if (table_name)
3490
 
                free(table_name);
3491
 
        if (escTableName)
3492
 
                free(escTableName);
3493
 
        if (escSchemaName)
3494
 
                free(escSchemaName);
3495
 
        if (column_names)
3496
 
        {
3497
 
                for (i = 0; i < total_columns; i++)
3498
 
                        free(column_names[i].col_name);
3499
 
                free(column_names);
3500
 
        }
3501
 
 
3502
 
        /* set up the current tuple pointer for SQLFetch */
3503
 
        stmt->currTuple = -1;
3504
 
        SC_set_rowset_start(stmt, -1, FALSE);
3505
 
        SC_set_current_col(stmt, -1);
3506
 
 
3507
 
        if (stmt->internal)
3508
 
                ret = DiscardStatementSvp(stmt, ret, FALSE);
3509
 
        mylog("%s: EXIT, stmt=%p, ret=%d\n", func, stmt, ret);
3510
 
 
3511
 
        return ret;
3512
 
}
3513
 
 
3514
 
 
3515
 
RETCODE         SQL_API
3516
 
PGAPI_ColumnPrivileges(
3517
 
                        HSTMT hstmt,
3518
 
                        const SQLCHAR FAR * szTableQualifier, /* OA X*/
3519
 
                        SQLSMALLINT cbTableQualifier,
3520
 
                        const SQLCHAR FAR * szTableOwner, /* OA E*/
3521
 
                        SQLSMALLINT cbTableOwner,
3522
 
                        const SQLCHAR FAR * szTableName, /* OA(R) E*/
3523
 
                        SQLSMALLINT cbTableName,
3524
 
                        const SQLCHAR FAR * szColumnName, /* PV E*/
3525
 
                        SQLSMALLINT cbColumnName,
3526
 
                        UWORD flag)
3527
 
{
3528
 
        CSTR func = "PGAPI_ColumnPrivileges";
3529
 
        StatementClass  *stmt = (StatementClass *) hstmt;
3530
 
        ConnectionClass *conn = SC_get_conn(stmt);
3531
 
        RETCODE result = SQL_ERROR;
3532
 
        char    *escSchemaName = NULL, *escTableName = NULL, *escColumnName = NULL;
3533
 
        const char      *like_or_eq, *op_string, *eq_string;
3534
 
        char    column_query[INFO_INQUIRY_LEN];
3535
 
        size_t          cq_len,cq_size;
3536
 
        char            *col_query;
3537
 
        BOOL    search_pattern;
3538
 
        QResultClass    *res = NULL;
3539
 
 
3540
 
        mylog("%s: entering...\n", func);
3541
 
 
3542
 
        /* Neither Access or Borland care about this. */
3543
 
 
3544
 
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
3545
 
                return result;
3546
 
        if (PG_VERSION_LT(conn, 7.4))
3547
 
                SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Function not implementedyet", func);
3548
 
        escSchemaName = simpleCatalogEscape(szTableOwner, cbTableOwner, NULL, conn);
3549
 
        escTableName = simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
3550
 
        search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
3551
 
        if (search_pattern) 
3552
 
        {
3553
 
                like_or_eq = likeop;
3554
 
                escColumnName = adjustLikePattern(szColumnName, cbColumnName, SEARCH_PATTERN_ESCAPE, NULL, conn);
3555
 
        }
3556
 
        else
3557
 
        {
3558
 
                like_or_eq = eqop;
3559
 
                escColumnName = simpleCatalogEscape(szColumnName, cbColumnName, NULL, conn);
3560
 
        }
3561
 
        strcpy(column_query, "select '' as TABLE_CAT, table_schema as TABLE_SCHEM,"
3562
 
                        " table_name, column_name, grantor, grantee,"
3563
 
                        " privilege_type as PRIVILEGE, is_grantable from"
3564
 
                        " information_schema.column_privileges where true");
3565
 
        cq_len = strlen(column_query);
3566
 
        cq_size = sizeof(column_query);
3567
 
        col_query = column_query;
3568
 
        op_string = gen_opestr(like_or_eq, conn);
3569
 
        eq_string = gen_opestr(eqop, conn);
3570
 
        if (escSchemaName)
3571
 
        {
3572
 
                col_query += cq_len;
3573
 
                cq_size -= cq_len;
3574
 
                cq_len = snprintf_len(col_query, cq_size,
3575
 
                        " and table_schem %s'%s'", eq_string, escSchemaName);  
3576
 
                
3577
 
        }
3578
 
        if (escTableName)
3579
 
        {
3580
 
                col_query += cq_len;
3581
 
                cq_size -= cq_len;
3582
 
                cq_len += snprintf_len(col_query, cq_size,
3583
 
                        " and table_name %s'%s'", eq_string, escTableName);  
3584
 
        }
3585
 
        if (escColumnName)
3586
 
        {
3587
 
                col_query += cq_len;
3588
 
                cq_size -= cq_len;
3589
 
                cq_len += snprintf_len(col_query, cq_size,
3590
 
                        " and column_name %s'%s'", op_string, escColumnName);
3591
 
        }
3592
 
        if (res = CC_send_query(conn, column_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(res))
3593
 
        {
3594
 
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_ColumnPrivileges query error", func);
3595
 
                goto cleanup;
3596
 
        }
3597
 
        SC_set_Result(stmt, res);
3598
 
 
3599
 
        /*
3600
 
         * also, things need to think that this statement is finished so the
3601
 
         * results can be retrieved.
3602
 
         */
3603
 
        extend_column_bindings(SC_get_ARDF(stmt), 8);
3604
 
        /* set up the current tuple pointer for SQLFetch */
3605
 
        result = SQL_SUCCESS;
3606
 
cleanup:
3607
 
        if (!SQL_SUCCEEDED(result))
3608
 
                QR_Destructor(res);
3609
 
        /* set up the current tuple pointer for SQLFetch */
3610
 
        stmt->status = STMT_FINISHED;
3611
 
        stmt->currTuple = -1;
3612
 
        SC_set_rowset_start(stmt, -1, FALSE);
3613
 
        if (escSchemaName)
3614
 
                free(escSchemaName);
3615
 
        if (escTableName)
3616
 
                free(escTableName);
3617
 
        if (escColumnName)
3618
 
                free(escColumnName);
3619
 
        return result;
3620
 
}
3621
 
 
3622
 
 
3623
 
/*
3624
 
 *      SQLPrimaryKeys()
3625
 
 *
3626
 
 *      Retrieve the primary key columns for the specified table.
3627
 
 */
3628
 
RETCODE         SQL_API
3629
 
PGAPI_PrimaryKeys(
3630
 
                        HSTMT hstmt,
3631
 
                        const SQLCHAR FAR * szTableQualifier, /* OA X*/
3632
 
                        SQLSMALLINT cbTableQualifier,
3633
 
                        const SQLCHAR FAR * szTableOwner, /* OA E*/
3634
 
                        SQLSMALLINT cbTableOwner,
3635
 
                        const SQLCHAR FAR * szTableName, /* OA(R) E*/
3636
 
                        SQLSMALLINT cbTableName,
3637
 
                        OID     reloid)
3638
 
{
3639
 
        CSTR func = "PGAPI_PrimaryKeys";
3640
 
        StatementClass *stmt = (StatementClass *) hstmt;
3641
 
        QResultClass    *res;
3642
 
        ConnectionClass *conn;
3643
 
        TupleField      *tuple;
3644
 
        RETCODE         ret = SQL_SUCCESS, result;
3645
 
        int                     seq = 0;
3646
 
        HSTMT           htbl_stmt = NULL;
3647
 
        StatementClass *tbl_stmt;
3648
 
        char            tables_query[INFO_INQUIRY_LEN];
3649
 
        char            attname[MAX_INFO_STRING];
3650
 
        SQLLEN          attname_len;
3651
 
        char            *pktab = NULL, *pktbname;
3652
 
        char            pkscm[SCHEMA_NAME_STORAGE_LEN + 1];
3653
 
        SQLLEN          pkscm_len;
3654
 
        char            tabname[TABLE_NAME_STORAGE_LEN + 1];
3655
 
        SQLLEN          tabname_len;
3656
 
        char            pkname[TABLE_NAME_STORAGE_LEN + 1];
3657
 
        Int2            result_cols;
3658
 
        int                     qno,
3659
 
                                qstart,
3660
 
                                qend;
3661
 
        SQLSMALLINT     internal_asis_type = SQL_C_CHAR, cbSchemaName;
3662
 
        const char      *szSchemaName, *eq_string;
3663
 
        char    *escSchemaName = NULL, *escTableName = NULL;
3664
 
 
3665
 
        mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func, stmt, szTableOwner, cbTableOwner);
3666
 
 
3667
 
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
3668
 
                return result;
3669
 
 
3670
 
        if (res = QR_Constructor(), !res)
3671
 
        {
3672
 
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_PrimaryKeys result.", func);
3673
 
                return SQL_ERROR;
3674
 
        }
3675
 
        SC_set_Result(stmt, res);
3676
 
 
3677
 
        /* the binding structure for a statement is not set up until 
3678
 
         *
3679
 
         * a statement is actually executed, so we'll have to do this
3680
 
         * ourselves.
3681
 
         */
3682
 
        result_cols = NUM_OF_PKS_FIELDS;
3683
 
        extend_column_bindings(SC_get_ARDF(stmt), result_cols);
3684
 
 
3685
 
        stmt->catalog_result = TRUE;
3686
 
        /* set the field names */
3687
 
        QR_set_num_fields(res, result_cols);
3688
 
        QR_set_field_info_v(res, PKS_TABLE_CAT, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
3689
 
        QR_set_field_info_v(res, PKS_TABLE_SCHEM, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
3690
 
        QR_set_field_info_v(res, PKS_TABLE_NAME, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
3691
 
        QR_set_field_info_v(res, PKS_COLUMN_NAME, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
3692
 
        QR_set_field_info_v(res, PKS_KEY_SQ, "KEY_SEQ", PG_TYPE_INT2, 2);
3693
 
        QR_set_field_info_v(res, PKS_PK_NAME, "PK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
3694
 
 
3695
 
        conn = SC_get_conn(stmt);
3696
 
        result = PGAPI_AllocStmt(conn, &htbl_stmt, 0);
3697
 
        if (!SQL_SUCCEEDED(result))
3698
 
        {
3699
 
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for Primary Key result.", func);
3700
 
                ret = SQL_ERROR;
3701
 
                goto cleanup;
3702
 
        }
3703
 
        tbl_stmt = (StatementClass *) htbl_stmt;
3704
 
 
3705
 
#ifdef  UNICODE_SUPPORT
3706
 
        if (CC_is_in_unicode_driver(conn))
3707
 
                internal_asis_type = INTERNAL_ASIS_TYPE;
3708
 
#endif /* UNICODE_SUPPORT */
3709
 
 
3710
 
#define return  DONT_CALL_RETURN_FROM_HERE???
3711
 
        if (0 != reloid)
3712
 
        {
3713
 
                szSchemaName = NULL;
3714
 
                cbSchemaName = SQL_NULL_DATA;
3715
 
        }
3716
 
        else
3717
 
        {
3718
 
                pktab = make_string(szTableName, cbTableName, NULL, 0);
3719
 
                if (!pktab || pktab[0] == '\0')
3720
 
                {
3721
 
                        SC_set_error(stmt, STMT_INTERNAL_ERROR, "No Table specified to PGAPI_PrimaryKeys.", func);
3722
 
                        ret = SQL_ERROR;
3723
 
                        goto cleanup;
3724
 
                }
3725
 
                szSchemaName = szTableOwner;
3726
 
                cbSchemaName = cbTableOwner;
3727
 
                escTableName = simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
3728
 
        }
3729
 
        eq_string = gen_opestr(eqop, conn);
3730
 
 
3731
 
retry_public_schema:
3732
 
        pkscm[0] = '\0';
3733
 
        if (0 == reloid)
3734
 
        {
3735
 
                if (escSchemaName)
3736
 
                        free(escSchemaName);
3737
 
                escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn);
3738
 
                if (conn->schema_support)
3739
 
                        schema_strcat(pkscm, "%.*s", escSchemaName, SQL_NTS, szTableName, cbTableName, conn);
3740
 
        }
3741
 
 
3742
 
        result = PGAPI_BindCol(htbl_stmt, 1, internal_asis_type,
3743
 
                                                   attname, MAX_INFO_STRING, &attname_len);
3744
 
        if (!SQL_SUCCEEDED(result))
3745
 
        {
3746
 
                SC_error_copy(stmt, tbl_stmt, TRUE);
3747
 
                ret = SQL_ERROR;
3748
 
                goto cleanup;
3749
 
        }
3750
 
        result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
3751
 
                        pkname, TABLE_NAME_STORAGE_LEN, NULL);
3752
 
        if (!SQL_SUCCEEDED(result))
3753
 
        {
3754
 
                SC_error_copy(stmt, tbl_stmt, TRUE);
3755
 
                ret = SQL_ERROR;
3756
 
                goto cleanup;
3757
 
        }
3758
 
        result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type,
3759
 
                        pkscm, SCHEMA_NAME_STORAGE_LEN, &pkscm_len);
3760
 
        if (!SQL_SUCCEEDED(result))
3761
 
        {
3762
 
                SC_error_copy(stmt, tbl_stmt, TRUE);
3763
 
                ret = SQL_ERROR;
3764
 
                goto cleanup;
3765
 
        }
3766
 
        result = PGAPI_BindCol(htbl_stmt, 5, internal_asis_type,
3767
 
                        tabname, TABLE_NAME_STORAGE_LEN, &tabname_len);
3768
 
        if (!SQL_SUCCEEDED(result))
3769
 
        {
3770
 
                SC_error_copy(stmt, tbl_stmt, TRUE);
3771
 
                ret = SQL_ERROR;
3772
 
                goto cleanup;
3773
 
        }
3774
 
 
3775
 
        if (PG_VERSION_LE(conn, 6.4))
3776
 
                qstart = 2;
3777
 
        else
3778
 
                qstart = 1;
3779
 
        if (0 == reloid)
3780
 
                qend = 2;
3781
 
        else
3782
 
                qend = 1;
3783
 
        for (qno = qstart; qno <= qend; qno++)
3784
 
        {
3785
 
                size_t  qsize, tsize;
3786
 
                char    *tbqry;
3787
 
 
3788
 
                switch (qno)
3789
 
                {
3790
 
                        case 1:
3791
 
 
3792
 
                                /*
3793
 
                                 * Simplified query to remove assumptions about number of
3794
 
                                 * possible index columns. Courtesy of Tom Lane - thomas
3795
 
                                 * 2000-03-21
3796
 
                                 */
3797
 
                                if (conn->schema_support)
3798
 
                                {
3799
 
                                        strncpy_null(tables_query,
3800
 
                                                "select ta.attname, ia.attnum, ic.relname, n.nspname, tc.relname"
3801
 
                                                " from pg_catalog.pg_attribute ta,"
3802
 
                                                " pg_catalog.pg_attribute ia, pg_catalog.pg_class tc,"
3803
 
                                                " pg_catalog.pg_index i, pg_catalog.pg_namespace n"
3804
 
                                                ", pg_catalog.pg_class ic"
3805
 
                                                , sizeof(tables_query));
3806
 
                                        qsize = strlen(tables_query);
3807
 
                                        tsize = sizeof(tables_query) - qsize;
3808
 
                                        tbqry = tables_query + qsize;
3809
 
                                        if (0 == reloid)
3810
 
                                                snprintf(tbqry, tsize,
3811
 
                                                " where tc.relname %s'%s'"
3812
 
                                                " AND n.nspname %s'%s'"
3813
 
                                                , eq_string, escTableName, eq_string, pkscm);
3814
 
                                        else
3815
 
                                                snprintf(tbqry, tsize,
3816
 
                                                " where tc.oid = " FORMAT_UINT4
3817
 
                                                , reloid);
3818
 
 
3819
 
                                        strlcat(tables_query,
3820
 
                                                " AND tc.oid = i.indrelid"
3821
 
                                                " AND n.oid = tc.relnamespace"
3822
 
                                                " AND i.indisprimary = 't'"
3823
 
                                                " AND ia.attrelid = i.indexrelid"
3824
 
                                                " AND ta.attrelid = i.indrelid"
3825
 
                                                " AND ta.attnum = i.indkey[ia.attnum-1]"
3826
 
                                                " AND (NOT ta.attisdropped)"
3827
 
                                                " AND (NOT ia.attisdropped)"
3828
 
                                                " AND ic.oid = i.indexrelid"
3829
 
                                                " order by ia.attnum"
3830
 
                                                , sizeof(tables_query));
3831
 
                                }
3832
 
                                else
3833
 
                                {
3834
 
                                        strncpy_null(tables_query, 
3835
 
                                                "select ta.attname, ia.attnum, ic.relname, NULL, tc.relname"
3836
 
                                                " from pg_attribute ta, pg_attribute ia, pg_class tc, pg_index i, pg_class ic"
3837
 
                                                , sizeof(tables_query));
3838
 
                                        qsize = strlen(tables_query);
3839
 
                                        tsize = sizeof(tables_query) - qsize;
3840
 
                                        tbqry = tables_query + qsize;
3841
 
                                        if (0 == reloid)
3842
 
                                                snprintf(tbqry, tsize,
3843
 
                                                " where tc.relname %s'%s'"
3844
 
                                                , eq_string, escTableName);
3845
 
                                        else
3846
 
                                                snprintf(tbqry, tsize,
3847
 
                                                " where tc.oid = " FORMAT_UINT4, reloid);
3848
 
                                                
3849
 
                                        strlcat(tables_query,
3850
 
                                                " AND tc.oid = i.indrelid"
3851
 
                                                " AND i.indisprimary = 't'"
3852
 
                                                " AND ia.attrelid = i.indexrelid"
3853
 
                                                " AND ta.attrelid = i.indrelid"
3854
 
                                                " AND ta.attnum = i.indkey[ia.attnum-1]"
3855
 
                                                " AND ic.oid = i.indexrelid"
3856
 
                                                " order by ia.attnum"
3857
 
                                                , sizeof(tables_query));
3858
 
                                }
3859
 
                                break;
3860
 
                        case 2:
3861
 
 
3862
 
                                /*
3863
 
                                 * Simplified query to search old fashoned primary key
3864
 
                                 */
3865
 
                                if (conn->schema_support)
3866
 
                                        snprintf(tables_query, sizeof(tables_query), "select ta.attname, ia.attnum, ic.relname, n.nspname, NULL"
3867
 
                                                " from pg_catalog.pg_attribute ta,"
3868
 
                                                " pg_catalog.pg_attribute ia, pg_catalog.pg_class ic,"
3869
 
                                                " pg_catalog.pg_index i, pg_catalog.pg_namespace n"
3870
 
                                                " where ic.relname %s'%s_pkey'"
3871
 
                                                " AND n.nspname %s'%s'"
3872
 
                                                " AND ic.oid = i.indexrelid"
3873
 
                                                " AND n.oid = ic.relnamespace"
3874
 
                                                " AND ia.attrelid = i.indexrelid"
3875
 
                                                " AND ta.attrelid = i.indrelid"
3876
 
                                                " AND ta.attnum = i.indkey[ia.attnum-1]"
3877
 
                                                " AND (NOT ta.attisdropped)"
3878
 
                                                " AND (NOT ia.attisdropped)"
3879
 
                                                " order by ia.attnum", eq_string, escTableName, eq_string, pkscm);
3880
 
                                else
3881
 
                                        snprintf(tables_query, sizeof(tables_query), "select ta.attname, ia.attnum, ic.relname, NULL, NULL"
3882
 
                                                " from pg_attribute ta, pg_attribute ia, pg_class ic, pg_index i"
3883
 
                                                " where ic.relname %s'%s_pkey'"
3884
 
                                                " AND ic.oid = i.indexrelid"
3885
 
                                                " AND ia.attrelid = i.indexrelid"
3886
 
                                                " AND ta.attrelid = i.indrelid"
3887
 
                                                " AND ta.attnum = i.indkey[ia.attnum-1]"
3888
 
                                                " order by ia.attnum", eq_string, escTableName);
3889
 
                                break;
3890
 
                }
3891
 
                mylog("%s: tables_query='%s'\n", func, tables_query);
3892
 
 
3893
 
                result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
3894
 
                if (!SQL_SUCCEEDED(result))
3895
 
                {
3896
 
                        SC_full_error_copy(stmt, tbl_stmt, FALSE);
3897
 
                        ret = SQL_ERROR;
3898
 
                        goto cleanup;
3899
 
                }
3900
 
 
3901
 
                result = PGAPI_Fetch(htbl_stmt);
3902
 
                if (result != SQL_NO_DATA_FOUND)
3903
 
                        break;
3904
 
        }
3905
 
 
3906
 
        /* If not found */
3907
 
        if (conn->schema_support &&
3908
 
            SQL_NO_DATA_FOUND == result)
3909
 
        {
3910
 
                if (0 == reloid &&
3911
 
                    allow_public_schema(conn, szSchemaName, cbSchemaName))
3912
 
                {
3913
 
                        szSchemaName = pubstr;
3914
 
                        cbSchemaName = SQL_NTS;
3915
 
                        goto retry_public_schema;
3916
 
                }
3917
 
        }
3918
 
 
3919
 
        while (SQL_SUCCEEDED(result))
3920
 
        {
3921
 
                tuple = QR_AddNew(res);
3922
 
 
3923
 
                set_tuplefield_string(&tuple[PKS_TABLE_CAT], CurrCat(conn));
3924
 
 
3925
 
                /*
3926
 
                 * I have to hide the table owner from Access, otherwise it
3927
 
                 * insists on referring to the table as 'owner.table'. (this is
3928
 
                 * valid according to the ODBC SQL grammar, but Postgres won't
3929
 
                 * support it.)
3930
 
                 */
3931
 
                if (SQL_NULL_DATA == pkscm_len)
3932
 
                        pkscm[0] = '\0';
3933
 
                set_tuplefield_string(&tuple[PKS_TABLE_SCHEM], GET_SCHEMA_NAME(pkscm));
3934
 
                if (SQL_NULL_DATA == tabname_len)
3935
 
                        tabname[0] = '\0';
3936
 
                pktbname = pktab ? pktab : tabname;
3937
 
                set_tuplefield_string(&tuple[PKS_TABLE_NAME], pktbname);
3938
 
                set_tuplefield_string(&tuple[PKS_COLUMN_NAME], attname);
3939
 
                set_tuplefield_int2(&tuple[PKS_KEY_SQ], (Int2) (++seq));
3940
 
                set_tuplefield_string(&tuple[PKS_PK_NAME], pkname);
3941
 
 
3942
 
                mylog(">> primaryKeys: schema ='%s', pktab = '%s', attname = '%s', seq = %d\n", pkscm, pktbname, attname, seq);
3943
 
 
3944
 
                result = PGAPI_Fetch(htbl_stmt);
3945
 
        }
3946
 
 
3947
 
        if (result != SQL_NO_DATA_FOUND)
3948
 
        {
3949
 
                SC_full_error_copy(stmt, htbl_stmt, FALSE);
3950
 
                ret = SQL_ERROR;
3951
 
                goto cleanup;
3952
 
        }
3953
 
        ret = SQL_SUCCESS;
3954
 
 
3955
 
cleanup:
3956
 
#undef  return
3957
 
        /*
3958
 
         * also, things need to think that this statement is finished so the
3959
 
         * results can be retrieved.
3960
 
         */
3961
 
        stmt->status = STMT_FINISHED;
3962
 
 
3963
 
        if (htbl_stmt)
3964
 
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
3965
 
 
3966
 
        if (pktab)
3967
 
                free(pktab);
3968
 
        if (escSchemaName)
3969
 
                free(escSchemaName);
3970
 
        if (escTableName)
3971
 
                free(escTableName);
3972
 
        /* set up the current tuple pointer for SQLFetch */
3973
 
        stmt->currTuple = -1;
3974
 
        SC_set_rowset_start(stmt, -1, FALSE);
3975
 
        SC_set_current_col(stmt, -1);
3976
 
 
3977
 
        if (stmt->internal)
3978
 
                ret = DiscardStatementSvp(stmt, ret, FALSE); 
3979
 
        mylog("%s: EXIT, stmt=%p, ret=%d\n", func, stmt, ret);
3980
 
        return ret;
3981
 
}
3982
 
 
3983
 
 
3984
 
/*
3985
 
 *      Multibyte support stuff for SQLForeignKeys().
3986
 
 *      There may be much more effective way in the
3987
 
 *      future version. The way is very forcible currently.
3988
 
 */
3989
 
static BOOL
3990
 
isMultibyte(const UCHAR *str)
3991
 
{
3992
 
        for (; *str; str++)
3993
 
        {
3994
 
                if (*str >= 0x80)
3995
 
                        return TRUE;
3996
 
        }
3997
 
        return FALSE;
3998
 
}
3999
 
static char *
4000
 
getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName, BOOL *nameAlloced)
4001
 
{
4002
 
        char            query[1024], saveattnum[16],
4003
 
                           *ret = serverColumnName;
4004
 
        const char *eq_string;
4005
 
        BOOL            continueExec = TRUE,
4006
 
                                bError = FALSE;
4007
 
        QResultClass *res = NULL;
4008
 
        UWORD   flag = IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR;
4009
 
 
4010
 
        *nameAlloced = FALSE;
4011
 
        if (!conn->original_client_encoding || !isMultibyte(serverColumnName))
4012
 
                return ret;
4013
 
        if (!conn->server_encoding)
4014
 
        {
4015
 
                if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, flag, NULL), QR_command_maybe_successful(res))
4016
 
                {
4017
 
                        if (QR_get_num_cached_tuples(res) > 0)
4018
 
                                conn->server_encoding = strdup(QR_get_value_backend_text(res, 0, 0));
4019
 
                }
4020
 
                QR_Destructor(res);
4021
 
                res = NULL;
4022
 
        }
4023
 
        if (!conn->server_encoding)
4024
 
                return ret;
4025
 
        snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
4026
 
        bError = (!QR_command_maybe_successful((res = CC_send_query(conn, query, NULL, flag, NULL))));
4027
 
        QR_Destructor(res);
4028
 
        eq_string = gen_opestr(eqop, conn);
4029
 
        if (!bError && continueExec)
4030
 
        {
4031
 
                snprintf(query, sizeof(query), "select attnum from pg_attribute "
4032
 
                        "where attrelid = %u and attname %s'%s'",
4033
 
                        relid, eq_string, serverColumnName);
4034
 
                if (res = CC_send_query(conn, query, NULL, flag, NULL), QR_command_maybe_successful(res))
4035
 
                {
4036
 
                        if (QR_get_num_cached_tuples(res) > 0)
4037
 
                        {
4038
 
                                strcpy(saveattnum, QR_get_value_backend_text(res, 0, 0));
4039
 
                        }
4040
 
                        else
4041
 
                                continueExec = FALSE;
4042
 
                }
4043
 
                else
4044
 
                        bError = TRUE;
4045
 
                QR_Destructor(res);
4046
 
        }
4047
 
        continueExec = (continueExec && !bError);
4048
 
        /* restore the cleint encoding */
4049
 
        snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->original_client_encoding);
4050
 
        bError = (!QR_command_maybe_successful((res = CC_send_query(conn, query, NULL, flag, NULL))));
4051
 
        QR_Destructor(res);
4052
 
        if (bError || !continueExec)
4053
 
                return ret;
4054
 
        snprintf(query, sizeof(query), "select attname from pg_attribute where attrelid = %u and attnum = %s", relid, saveattnum);
4055
 
        if (res = CC_send_query(conn, query, NULL, flag, NULL), QR_command_maybe_successful(res))
4056
 
        {
4057
 
                if (QR_get_num_cached_tuples(res) > 0)
4058
 
                {
4059
 
                        ret = strdup(QR_get_value_backend_text(res, 0, 0));
4060
 
                        *nameAlloced = TRUE;
4061
 
                }
4062
 
        }
4063
 
        QR_Destructor(res);
4064
 
        return ret;
4065
 
}
4066
 
 
4067
 
static RETCODE          SQL_API
4068
 
PGAPI_ForeignKeys_new(
4069
 
                HSTMT hstmt,
4070
 
                const SQLCHAR FAR * szPkTableQualifier, /* OA X*/
4071
 
                SQLSMALLINT cbPkTableQualifier,
4072
 
                const SQLCHAR FAR * szPkTableOwner, /* OA E*/
4073
 
                SQLSMALLINT cbPkTableOwner,
4074
 
                const SQLCHAR FAR * szPkTableName, /* OA(R) E*/
4075
 
                SQLSMALLINT cbPkTableName,
4076
 
                const SQLCHAR FAR * szFkTableQualifier, /* OA X*/
4077
 
                SQLSMALLINT cbFkTableQualifier,
4078
 
                const SQLCHAR FAR * szFkTableOwner, /* OA E*/
4079
 
                SQLSMALLINT cbFkTableOwner,
4080
 
                const SQLCHAR FAR * szFkTableName, /* OA(R) E*/
4081
 
                SQLSMALLINT cbFkTableName);
4082
 
 
4083
 
static RETCODE          SQL_API
4084
 
PGAPI_ForeignKeys_old(
4085
 
                        HSTMT hstmt,
4086
 
                        const SQLCHAR FAR * szPkTableQualifier, /* OA X*/
4087
 
                        SQLSMALLINT cbPkTableQualifier,
4088
 
                        const SQLCHAR FAR * szPkTableOwner, /* OA E*/
4089
 
                        SQLSMALLINT cbPkTableOwner,
4090
 
                        const SQLCHAR FAR * szPkTableName, /* OA(R) E*/
4091
 
                        SQLSMALLINT cbPkTableName,
4092
 
                        const SQLCHAR FAR * szFkTableQualifier, /* OA X*/
4093
 
                        SQLSMALLINT cbFkTableQualifier,
4094
 
                        const SQLCHAR FAR * szFkTableOwner, /* OA E*/
4095
 
                        SQLSMALLINT cbFkTableOwner,
4096
 
                        const SQLCHAR FAR * szFkTableName, /* OA(R) E*/
4097
 
                        SQLSMALLINT cbFkTableName)
4098
 
{
4099
 
        CSTR func = "PGAPI_ForeignKeys";
4100
 
        StatementClass *stmt = (StatementClass *) hstmt;
4101
 
        QResultClass    *res;
4102
 
        TupleField      *tuple;
4103
 
        HSTMT           htbl_stmt = NULL, hpkey_stmt = NULL;
4104
 
        StatementClass *tbl_stmt;
4105
 
        RETCODE         ret = SQL_ERROR, result, keyresult;
4106
 
        char            tables_query[INFO_INQUIRY_LEN];
4107
 
        char            trig_deferrable[2];
4108
 
        char            trig_initdeferred[2];
4109
 
        char            trig_args[1024];
4110
 
        char            upd_rule[TABLE_NAME_STORAGE_LEN],
4111
 
                                del_rule[TABLE_NAME_STORAGE_LEN];
4112
 
        char            *pk_table_needed = NULL, *escPkTableName = NULL;
4113
 
        char            fk_table_fetched[TABLE_NAME_STORAGE_LEN + 1];
4114
 
        char            *fk_table_needed = NULL, *escFkTableName = NULL;
4115
 
        char            pk_table_fetched[TABLE_NAME_STORAGE_LEN + 1];
4116
 
        char            schema_needed[SCHEMA_NAME_STORAGE_LEN + 1];
4117
 
        char            schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1];
4118
 
        char            constrname[NAMESTORAGELEN + 1], pkname[TABLE_NAME_STORAGE_LEN + 1];
4119
 
        char       *pkey_ptr,
4120
 
                           *pkey_text = NULL,
4121
 
                           *fkey_ptr,
4122
 
                           *fkey_text = NULL;
4123
 
 
4124
 
        ConnectionClass *conn;
4125
 
        BOOL            pkey_alloced,
4126
 
                        fkey_alloced, got_pkname;
4127
 
        int                     i,
4128
 
                                j,
4129
 
                                k,
4130
 
                                num_keys;
4131
 
        SQLSMALLINT             trig_nargs,
4132
 
                                upd_rule_type = 0,
4133
 
                                del_rule_type = 0;
4134
 
        SQLSMALLINT     internal_asis_type = SQL_C_CHAR;
4135
 
 
4136
 
#if (ODBCVER >= 0x0300)
4137
 
        SQLSMALLINT     defer_type;
4138
 
#endif
4139
 
        char            pkey[MAX_INFO_STRING];
4140
 
        Int2            result_cols;
4141
 
        UInt4           relid1, relid2;
4142
 
        const char *eq_string;
4143
 
 
4144
 
        mylog("%s: entering...stmt=%p\n", func, stmt);
4145
 
 
4146
 
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
4147
 
                return result;
4148
 
 
4149
 
        if (res = QR_Constructor(), !res)
4150
 
        {
4151
 
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_ForeignKeys result.", func);
4152
 
                return SQL_ERROR;
4153
 
        }
4154
 
        SC_set_Result(stmt, res);
4155
 
 
4156
 
        /* the binding structure for a statement is not set up until */
4157
 
 
4158
 
        /*
4159
 
         * a statement is actually executed, so we'll have to do this
4160
 
         * ourselves.
4161
 
         */
4162
 
        result_cols = NUM_OF_FKS_FIELDS;
4163
 
        extend_column_bindings(SC_get_ARDF(stmt), result_cols);
4164
 
 
4165
 
        stmt->catalog_result = TRUE;
4166
 
        /* set the field names */
4167
 
        QR_set_num_fields(res, result_cols);
4168
 
        QR_set_field_info_v(res, FKS_PKTABLE_CAT, "PKTABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
4169
 
        QR_set_field_info_v(res, FKS_PKTABLE_SCHEM, "PKTABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
4170
 
        QR_set_field_info_v(res, FKS_PKTABLE_NAME, "PKTABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
4171
 
        QR_set_field_info_v(res, FKS_PKCOLUMN_NAME, "PKCOLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
4172
 
        QR_set_field_info_v(res, FKS_FKTABLE_CAT, "FKTABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
4173
 
        QR_set_field_info_v(res, FKS_FKTABLE_SCHEM, "FKTABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
4174
 
        QR_set_field_info_v(res, FKS_FKTABLE_NAME, "FKTABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
4175
 
        QR_set_field_info_v(res, FKS_FKCOLUMN_NAME, "FKCOLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
4176
 
        QR_set_field_info_v(res, FKS_KEY_SEQ, "KEY_SEQ", PG_TYPE_INT2, 2);
4177
 
        QR_set_field_info_v(res, FKS_UPDATE_RULE, "UPDATE_RULE", PG_TYPE_INT2, 2);
4178
 
        QR_set_field_info_v(res, FKS_DELETE_RULE, "DELETE_RULE", PG_TYPE_INT2, 2);
4179
 
        QR_set_field_info_v(res, FKS_FK_NAME, "FK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
4180
 
        QR_set_field_info_v(res, FKS_PK_NAME, "PK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
4181
 
#if (ODBCVER >= 0x0300)
4182
 
        QR_set_field_info_v(res, FKS_DEFERRABILITY, "DEFERRABILITY", PG_TYPE_INT2, 2);
4183
 
#endif   /* ODBCVER >= 0x0300 */
4184
 
        QR_set_field_info_v(res, FKS_TRIGGER_NAME, "TRIGGER_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
4185
 
 
4186
 
        /*
4187
 
         * also, things need to think that this statement is finished so the
4188
 
         * results can be retrieved.
4189
 
         */
4190
 
        stmt->status = STMT_FINISHED;
4191
 
 
4192
 
        /* set up the current tuple pointer for SQLFetch */
4193
 
        stmt->currTuple = -1;
4194
 
        SC_set_rowset_start(stmt, -1, FALSE);
4195
 
        SC_set_current_col(stmt, -1);
4196
 
 
4197
 
        conn = SC_get_conn(stmt);
4198
 
        result = PGAPI_AllocStmt(conn, &htbl_stmt, 0);
4199
 
        if (!SQL_SUCCEEDED(result))
4200
 
        {
4201
 
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys result.", func);
4202
 
                return SQL_ERROR;
4203
 
        }
4204
 
 
4205
 
#define return  DONT_CALL_RETURN_FROM_HERE???
4206
 
 
4207
 
        tbl_stmt = (StatementClass *) htbl_stmt;
4208
 
        schema_needed[0] = '\0';
4209
 
        schema_fetched[0] = '\0';
4210
 
 
4211
 
        pk_table_needed = make_string(szPkTableName, cbPkTableName, NULL, 0);
4212
 
        fk_table_needed = make_string(szFkTableName, cbFkTableName, NULL, 0);
4213
 
 
4214
 
#ifdef  UNICODE_SUPPORT
4215
 
        if (CC_is_in_unicode_driver(conn))
4216
 
                internal_asis_type = INTERNAL_ASIS_TYPE;
4217
 
#endif /* UNICODE_SUPPORT */
4218
 
        pkey_alloced = fkey_alloced = FALSE;
4219
 
 
4220
 
        eq_string = gen_opestr(eqop, conn);
4221
 
        /*
4222
 
         * Case #2 -- Get the foreign keys in the specified table (fktab) that
4223
 
         * refer to the primary keys of other table(s).
4224
 
         */
4225
 
        if (fk_table_needed && fk_table_needed[0] != '\0')
4226
 
        {
4227
 
                mylog("%s: entering Foreign Key Case #2", func);
4228
 
                escFkTableName = simpleCatalogEscape(fk_table_needed, SQL_NTS, NULL, conn);
4229
 
                if (conn->schema_support)
4230
 
                {
4231
 
                        char    *escSchemaName;
4232
 
 
4233
 
                        schema_strcat(schema_needed, "%.*s", szFkTableOwner, cbFkTableOwner, szFkTableName, cbFkTableName, conn);
4234
 
                        escSchemaName = simpleCatalogEscape(schema_needed, SQL_NTS, NULL, conn);
4235
 
                        snprintf(tables_query, sizeof(tables_query), "SELECT    pt.tgargs, "
4236
 
                                "               pt.tgnargs, "
4237
 
                                "               pt.tgdeferrable, "
4238
 
                                "               pt.tginitdeferred, "
4239
 
                                "               pp1.proname, "
4240
 
                                "               pp2.proname, "
4241
 
                                "               pc.oid, "
4242
 
                                "               pc1.oid, "
4243
 
                                "               pc1.relname, "
4244
 
                                "               pt.tgconstrname, pn.nspname "
4245
 
                                "FROM   pg_catalog.pg_class pc, "
4246
 
                                "               pg_catalog.pg_proc pp1, "
4247
 
                                "               pg_catalog.pg_proc pp2, "
4248
 
                                "               pg_catalog.pg_trigger pt1, "
4249
 
                                "               pg_catalog.pg_trigger pt2, "
4250
 
                                "               pg_catalog.pg_proc pp, "
4251
 
                                "               pg_catalog.pg_trigger pt, "
4252
 
                                "               pg_catalog.pg_class pc1, "
4253
 
                                "               pg_catalog.pg_namespace pn, "
4254
 
                                "               pg_catalog.pg_namespace pn1 "
4255
 
                                "WHERE  pt.tgrelid = pc.oid "
4256
 
                                "AND pp.oid = pt.tgfoid "
4257
 
                                "AND pt1.tgconstrrelid = pc.oid "
4258
 
                                "AND pp1.oid = pt1.tgfoid "
4259
 
                                "AND pt2.tgfoid = pp2.oid "
4260
 
                                "AND pt2.tgconstrrelid = pc.oid "
4261
 
                                "AND ((pc.relname %s'%s') "
4262
 
                                "AND (pn1.oid = pc.relnamespace) "
4263
 
                                "AND (pn1.nspname %s'%s') "
4264
 
                                "AND (pp.proname LIKE '%%ins') "
4265
 
                                "AND (pp1.proname LIKE '%%upd') "
4266
 
                                "AND (pp1.proname not LIKE '%%check%%') "
4267
 
                                "AND (pp2.proname LIKE '%%del') "
4268
 
                                "AND (pt1.tgrelid=pt.tgconstrrelid) "
4269
 
                                "AND (pt1.tgconstrname=pt.tgconstrname) "
4270
 
                                "AND (pt2.tgrelid=pt.tgconstrrelid) "
4271
 
                                "AND (pt2.tgconstrname=pt.tgconstrname) "
4272
 
                                "AND (pt.tgconstrrelid=pc1.oid) "
4273
 
                                "AND (pc1.relnamespace=pn.oid))"
4274
 
                                " order by pt.tgconstrname",
4275
 
                                eq_string, escFkTableName, eq_string, escSchemaName);
4276
 
                        free(escSchemaName);
4277
 
                }
4278
 
                else
4279
 
                        snprintf(tables_query, sizeof(tables_query), "SELECT    pt.tgargs, "
4280
 
                                "               pt.tgnargs, "
4281
 
                                "               pt.tgdeferrable, "
4282
 
                                "               pt.tginitdeferred, "
4283
 
                                "               pp1.proname, "
4284
 
                                "               pp2.proname, "
4285
 
                                "               pc.oid, "
4286
 
                                "               pc1.oid, "
4287
 
                                "               pc1.relname, pt.tgconstrname "
4288
 
                                "FROM   pg_class pc, "
4289
 
                                "               pg_proc pp1, "
4290
 
                                "               pg_proc pp2, "
4291
 
                                "               pg_trigger pt1, "
4292
 
                                "               pg_trigger pt2, "
4293
 
                                "               pg_proc pp, "
4294
 
                                "               pg_trigger pt, "
4295
 
                                "               pg_class pc1 "
4296
 
                                "WHERE  pt.tgrelid = pc.oid "
4297
 
                                "AND pp.oid = pt.tgfoid "
4298
 
                                "AND pt1.tgconstrrelid = pc.oid "
4299
 
                                "AND pp1.oid = pt1.tgfoid "
4300
 
                                "AND pt2.tgfoid = pp2.oid "
4301
 
                                "AND pt2.tgconstrrelid = pc.oid "
4302
 
                                "AND ((pc.relname %s'%s') "
4303
 
                                "AND (pp.proname LIKE '%%ins') "
4304
 
                                "AND (pp1.proname LIKE '%%upd') "
4305
 
                                "AND (pp1.proname not LIKE '%%check%%') "
4306
 
                                "AND (pp2.proname LIKE '%%del') "
4307
 
                                "AND (pt1.tgrelid=pt.tgconstrrelid) "
4308
 
                                "AND (pt1.tgconstrname=pt.tgconstrname) "
4309
 
                                "AND (pt2.tgrelid=pt.tgconstrrelid) "
4310
 
                                "AND (pt2.tgconstrname=pt.tgconstrname) "
4311
 
                                "AND (pt.tgconstrrelid=pc1.oid)) "
4312
 
                                "order by pt.tgconstrname",
4313
 
                                eq_string, escFkTableName);
4314
 
 
4315
 
                result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
4316
 
 
4317
 
                if (!SQL_SUCCEEDED(result))
4318
 
                {
4319
 
                        SC_full_error_copy(stmt, tbl_stmt, FALSE);
4320
 
                        goto cleanup;
4321
 
                }
4322
 
 
4323
 
                result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_BINARY,
4324
 
                                                           trig_args, sizeof(trig_args), NULL);
4325
 
                if (!SQL_SUCCEEDED(result))
4326
 
                {
4327
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4328
 
                        goto cleanup;
4329
 
                }
4330
 
 
4331
 
                result = PGAPI_BindCol(htbl_stmt, 2, SQL_C_SHORT,
4332
 
                                                           &trig_nargs, 0, NULL);
4333
 
                if (!SQL_SUCCEEDED(result))
4334
 
                {
4335
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4336
 
                        goto cleanup;
4337
 
                }
4338
 
 
4339
 
                result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
4340
 
                                                 trig_deferrable, sizeof(trig_deferrable), NULL);
4341
 
                if (!SQL_SUCCEEDED(result))
4342
 
                {
4343
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4344
 
                        goto cleanup;
4345
 
                }
4346
 
 
4347
 
                result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type,
4348
 
                                         trig_initdeferred, sizeof(trig_initdeferred), NULL);
4349
 
                if (!SQL_SUCCEEDED(result))
4350
 
                {
4351
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4352
 
                        goto cleanup;
4353
 
                }
4354
 
 
4355
 
                result = PGAPI_BindCol(htbl_stmt, 5, internal_asis_type,
4356
 
                                                           upd_rule, sizeof(upd_rule), NULL);
4357
 
                if (!SQL_SUCCEEDED(result))
4358
 
                {
4359
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4360
 
                        goto cleanup;
4361
 
                }
4362
 
 
4363
 
                result = PGAPI_BindCol(htbl_stmt, 6, internal_asis_type,
4364
 
                                                           del_rule, sizeof(del_rule), NULL);
4365
 
                if (!SQL_SUCCEEDED(result))
4366
 
                {
4367
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4368
 
                        goto cleanup;
4369
 
                }
4370
 
 
4371
 
                result = PGAPI_BindCol(htbl_stmt, 7, SQL_C_ULONG,
4372
 
                                                           &relid1, sizeof(relid1), NULL);
4373
 
                if (!SQL_SUCCEEDED(result))
4374
 
                {
4375
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4376
 
                        goto cleanup;
4377
 
                }
4378
 
                result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG,
4379
 
                                                           &relid2, sizeof(relid2), NULL);
4380
 
                if (!SQL_SUCCEEDED(result))
4381
 
                {
4382
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4383
 
                        goto cleanup;
4384
 
                }
4385
 
                result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type,
4386
 
                                        pk_table_fetched, TABLE_NAME_STORAGE_LEN, NULL);
4387
 
                if (!SQL_SUCCEEDED(result))
4388
 
                {
4389
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4390
 
                        goto cleanup;
4391
 
                }
4392
 
                result = PGAPI_BindCol(htbl_stmt, 10, internal_asis_type,
4393
 
                                        constrname, NAMESTORAGELEN, NULL);
4394
 
                if (!SQL_SUCCEEDED(result))
4395
 
                {
4396
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4397
 
                        goto cleanup;
4398
 
                }
4399
 
 
4400
 
                if (conn->schema_support)
4401
 
                {
4402
 
                        result = PGAPI_BindCol(htbl_stmt, 11, internal_asis_type,
4403
 
                                        schema_fetched, SCHEMA_NAME_STORAGE_LEN, NULL);
4404
 
                        if (!SQL_SUCCEEDED(result))
4405
 
                        {
4406
 
                                SC_error_copy(stmt, tbl_stmt, TRUE);
4407
 
                                goto cleanup;
4408
 
                        }
4409
 
                }
4410
 
 
4411
 
                result = PGAPI_Fetch(htbl_stmt);
4412
 
                if (result == SQL_NO_DATA_FOUND)
4413
 
                {
4414
 
                        ret = SQL_SUCCESS;
4415
 
                        goto cleanup;
4416
 
                }
4417
 
 
4418
 
                if (result != SQL_SUCCESS)
4419
 
                {
4420
 
                        SC_full_error_copy(stmt, tbl_stmt, FALSE);
4421
 
                        goto cleanup;
4422
 
                }
4423
 
 
4424
 
                keyresult = PGAPI_AllocStmt(conn, &hpkey_stmt, 0);
4425
 
                if (!SQL_SUCCEEDED(keyresult))
4426
 
                {
4427
 
                        SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.", func);
4428
 
                        goto cleanup;
4429
 
                }
4430
 
 
4431
 
                keyresult = PGAPI_BindCol(hpkey_stmt, 4, internal_asis_type,
4432
 
                                                                  pkey, sizeof(pkey), NULL);
4433
 
                if (keyresult != SQL_SUCCESS)
4434
 
                {
4435
 
                        SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.", func);
4436
 
                        goto cleanup;
4437
 
                }
4438
 
 
4439
 
                while (result == SQL_SUCCESS)
4440
 
                {
4441
 
                        /* Compute the number of keyparts. */
4442
 
                        num_keys = (trig_nargs - 4) / 2;
4443
 
 
4444
 
                        mylog("Foreign Key Case#2: trig_nargs = %d, num_keys = %d\n", trig_nargs, num_keys);
4445
 
 
4446
 
                        /* If there is a pk table specified, then check it. */
4447
 
                        if (pk_table_needed && pk_table_needed[0] != '\0')
4448
 
                        {
4449
 
                                /* If it doesn't match, then continue */
4450
 
                                if (strcmp(pk_table_fetched, pk_table_needed))
4451
 
                                {
4452
 
                                        result = PGAPI_Fetch(htbl_stmt);
4453
 
                                        continue;
4454
 
                                }
4455
 
                        }
4456
 
 
4457
 
                        got_pkname = FALSE;
4458
 
                        keyresult = PGAPI_PrimaryKeys(hpkey_stmt, NULL, 0, schema_fetched, SQL_NTS, pk_table_fetched, SQL_NTS, 0);
4459
 
                        if (keyresult != SQL_SUCCESS)
4460
 
                        {
4461
 
                                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't get primary keys for PGAPI_ForeignKeys result.", func);
4462
 
                                goto cleanup;
4463
 
                        }
4464
 
 
4465
 
                        /* Get to first primary key */
4466
 
                        pkey_ptr = trig_args;
4467
 
                        for (i = 0; i < 5; i++)
4468
 
                                pkey_ptr += strlen(pkey_ptr) + 1;
4469
 
 
4470
 
                        for (k = 0; k < num_keys; k++)
4471
 
                        {
4472
 
                                /* Check that the key listed is the primary key */
4473
 
                                keyresult = PGAPI_Fetch(hpkey_stmt);
4474
 
                                if (keyresult != SQL_SUCCESS)
4475
 
                                {
4476
 
                                        num_keys = 0;
4477
 
                                        break;
4478
 
                                }
4479
 
                                if (!got_pkname)
4480
 
                                {
4481
 
                                        PGAPI_GetData(hpkey_stmt, 6, internal_asis_type, pkname, sizeof(pkname), NULL);
4482
 
                                        got_pkname = TRUE;
4483
 
                                }
4484
 
                                pkey_text = getClientColumnName(conn, relid2, pkey_ptr, &pkey_alloced);
4485
 
                                mylog("%s: pkey_ptr='%s', pkey='%s'\n", func, pkey_text, pkey);
4486
 
                                if (strcmp(pkey_text, pkey))
4487
 
                                {
4488
 
                                        num_keys = 0;
4489
 
                                        break;
4490
 
                                }
4491
 
                                if (pkey_alloced)
4492
 
                                        free(pkey_text);
4493
 
                                /* Get to next primary key */
4494
 
                                for (k = 0; k < 2; k++)
4495
 
                                        pkey_ptr += strlen(pkey_ptr) + 1;
4496
 
 
4497
 
                        }
4498
 
                        PGAPI_FreeStmt(hpkey_stmt, SQL_CLOSE);
4499
 
 
4500
 
                        /* Set to first fk column */
4501
 
                        fkey_ptr = trig_args;
4502
 
                        for (k = 0; k < 4; k++)
4503
 
                                fkey_ptr += strlen(fkey_ptr) + 1;
4504
 
 
4505
 
                        /* Set update and delete actions for foreign keys */
4506
 
                        if (!strcmp(upd_rule, "RI_FKey_cascade_upd"))
4507
 
                                upd_rule_type = SQL_CASCADE;
4508
 
                        else if (!strcmp(upd_rule, "RI_FKey_noaction_upd"))
4509
 
                                upd_rule_type = SQL_NO_ACTION;
4510
 
                        else if (!strcmp(upd_rule, "RI_FKey_restrict_upd"))
4511
 
                                upd_rule_type = SQL_NO_ACTION;
4512
 
                        else if (!strcmp(upd_rule, "RI_FKey_setdefault_upd"))
4513
 
                                upd_rule_type = SQL_SET_DEFAULT;
4514
 
                        else if (!strcmp(upd_rule, "RI_FKey_setnull_upd"))
4515
 
                                upd_rule_type = SQL_SET_NULL;
4516
 
 
4517
 
                        if (!strcmp(del_rule, "RI_FKey_cascade_del"))
4518
 
                                del_rule_type = SQL_CASCADE;
4519
 
                        else if (!strcmp(del_rule, "RI_FKey_noaction_del"))
4520
 
                                del_rule_type = SQL_NO_ACTION;
4521
 
                        else if (!strcmp(del_rule, "RI_FKey_restrict_del"))
4522
 
                                del_rule_type = SQL_NO_ACTION;
4523
 
                        else if (!strcmp(del_rule, "RI_FKey_setdefault_del"))
4524
 
                                del_rule_type = SQL_SET_DEFAULT;
4525
 
                        else if (!strcmp(del_rule, "RI_FKey_setnull_del"))
4526
 
                                del_rule_type = SQL_SET_NULL;
4527
 
 
4528
 
#if (ODBCVER >= 0x0300)
4529
 
                        /* Set deferrability type */
4530
 
                        if (!strcmp(trig_initdeferred, "y"))
4531
 
                                defer_type = SQL_INITIALLY_DEFERRED;
4532
 
                        else if (!strcmp(trig_deferrable, "y"))
4533
 
                                defer_type = SQL_INITIALLY_IMMEDIATE;
4534
 
                        else
4535
 
                                defer_type = SQL_NOT_DEFERRABLE;
4536
 
#endif   /* ODBCVER >= 0x0300 */
4537
 
 
4538
 
                        /* Get to first primary key */
4539
 
                        pkey_ptr = trig_args;
4540
 
                        for (i = 0; i < 5; i++)
4541
 
                                pkey_ptr += strlen(pkey_ptr) + 1;
4542
 
 
4543
 
                        for (k = 0; k < num_keys; k++)
4544
 
                        {
4545
 
                                tuple = QR_AddNew(res);
4546
 
 
4547
 
                                pkey_text = getClientColumnName(conn, relid2, pkey_ptr, &pkey_alloced);
4548
 
                                fkey_text = getClientColumnName(conn, relid1, fkey_ptr, &fkey_alloced);
4549
 
 
4550
 
                                mylog("%s: pk_table = '%s', pkey_ptr = '%s'\n", func, pk_table_fetched, pkey_text);
4551
 
                                set_tuplefield_string(&tuple[FKS_PKTABLE_CAT], CurrCat(conn));
4552
 
                                set_tuplefield_string(&tuple[FKS_PKTABLE_SCHEM], GET_SCHEMA_NAME(schema_fetched));
4553
 
                                set_tuplefield_string(&tuple[FKS_PKTABLE_NAME], pk_table_fetched);
4554
 
                                set_tuplefield_string(&tuple[FKS_PKCOLUMN_NAME], pkey_text);
4555
 
 
4556
 
                                mylog("%s: fk_table_needed = '%s', fkey_ptr = '%s'\n", func, fk_table_needed, fkey_text);
4557
 
                                set_tuplefield_string(&tuple[FKS_FKTABLE_CAT], CurrCat(conn));
4558
 
                                set_tuplefield_string(&tuple[FKS_FKTABLE_SCHEM], GET_SCHEMA_NAME(schema_needed));
4559
 
                                set_tuplefield_string(&tuple[FKS_FKTABLE_NAME], fk_table_needed);
4560
 
                                set_tuplefield_string(&tuple[FKS_FKCOLUMN_NAME], fkey_text);
4561
 
 
4562
 
                                mylog("%s: upd_rule_type = '%i', del_rule_type = '%i'\n, trig_name = '%s'", func, upd_rule_type, del_rule_type, trig_args);
4563
 
                                set_tuplefield_int2(&tuple[FKS_KEY_SEQ], (Int2) (k + 1));
4564
 
                                set_tuplefield_int2(&tuple[FKS_UPDATE_RULE], upd_rule_type);
4565
 
                                set_tuplefield_int2(&tuple[FKS_DELETE_RULE], del_rule_type);
4566
 
                                set_tuplefield_string(&tuple[FKS_FK_NAME], constrname);
4567
 
                                set_tuplefield_string(&tuple[FKS_PK_NAME], pkname);
4568
 
#if (ODBCVER >= 0x0300)
4569
 
                                set_tuplefield_int2(&tuple[FKS_DEFERRABILITY], defer_type);
4570
 
#endif   /* ODBCVER >= 0x0300 */
4571
 
                                set_tuplefield_string(&tuple[FKS_TRIGGER_NAME], trig_args);
4572
 
 
4573
 
                                if (fkey_alloced)
4574
 
                                        free(fkey_text);
4575
 
                                fkey_alloced = FALSE;
4576
 
                                if (pkey_alloced)
4577
 
                                        free(pkey_text);
4578
 
                                pkey_alloced = FALSE;
4579
 
                                /* next primary/foreign key */
4580
 
                                for (i = 0; i < 2; i++)
4581
 
                                {
4582
 
                                        fkey_ptr += strlen(fkey_ptr) + 1;
4583
 
                                        pkey_ptr += strlen(pkey_ptr) + 1;
4584
 
                                }
4585
 
                        }
4586
 
 
4587
 
                        result = PGAPI_Fetch(htbl_stmt);
4588
 
                }
4589
 
        }
4590
 
 
4591
 
        /*
4592
 
         * Case #1 -- Get the foreign keys in other tables that refer to the
4593
 
         * primary key in the specified table (pktab).  i.e., Who points to
4594
 
         * me?
4595
 
         */
4596
 
        else if (pk_table_needed[0] != '\0')
4597
 
        {
4598
 
                escPkTableName = simpleCatalogEscape(pk_table_needed, SQL_NTS, NULL, conn);
4599
 
                if (conn->schema_support)
4600
 
                {
4601
 
                        char    *escSchemaName;
4602
 
 
4603
 
                        schema_strcat(schema_needed, "%.*s", szPkTableOwner, cbPkTableOwner, szPkTableName, cbPkTableName, conn);
4604
 
                        escSchemaName = simpleCatalogEscape(schema_needed, SQL_NTS, NULL, conn);
4605
 
                        snprintf(tables_query, sizeof(tables_query), "SELECT    pt.tgargs, "
4606
 
                                "       pt.tgnargs, "
4607
 
                                "       pt.tgdeferrable, "
4608
 
                                "       pt.tginitdeferred, "
4609
 
                                "       pp1.proname, "
4610
 
                                "       pp2.proname, "
4611
 
                                "       pc.oid, "
4612
 
                                "       pc1.oid, "
4613
 
                                "       pc1.relname, "
4614
 
                                "       pt.tgconstrname, pn1.nspname "
4615
 
                                "FROM   pg_catalog.pg_class pc, "
4616
 
                                "       pg_catalog.pg_class pc1, "
4617
 
                                "       pg_catalog.pg_proc pp, "
4618
 
                                "       pg_catalog.pg_proc pp1, "
4619
 
                                "       pg_catalog.pg_proc pp2, "
4620
 
                                "       pg_catalog.pg_trigger pt, "
4621
 
                                "       pg_catalog.pg_trigger pt1, "
4622
 
                                "       pg_catalog.pg_trigger pt2, "
4623
 
                                "       pg_catalog.pg_namespace pn, "
4624
 
                                "       pg_catalog.pg_namespace pn1 "
4625
 
                                "WHERE  pc.relname %s'%s' "
4626
 
                                "       AND pn.nspname %s'%s' "
4627
 
                                "       AND pc.relnamespace = pn.oid "
4628
 
                                "       AND pt.tgconstrrelid = pc.oid "
4629
 
                                "       AND pp.oid = pt.tgfoid "
4630
 
                                "       AND pp.proname Like '%%ins' "
4631
 
                                "       AND pt1.tgconstrname = pt.tgconstrname "
4632
 
                                "       AND pt1.tgconstrrelid = pt.tgrelid "
4633
 
                                "       AND pt1.tgrelid = pc.oid "
4634
 
                                "       AND pc1.oid = pt.tgrelid "
4635
 
                                "       AND pp1.oid = pt1.tgfoid "
4636
 
                                "       AND pp1.proname like '%%upd' "
4637
 
                                "       AND (pp1.proname not like '%%check%%') "
4638
 
                                "       AND pt2.tgconstrname = pt.tgconstrname "
4639
 
                                "       AND pt2.tgconstrrelid = pt.tgrelid "
4640
 
                                "       AND pt2.tgrelid = pc.oid "
4641
 
                                "       AND pp2.oid = pt2.tgfoid "
4642
 
                                "       AND pp2.proname Like '%%del' "
4643
 
                                "       AND pn1.oid = pc1.relnamespace "
4644
 
                                " order by pt.tgconstrname",
4645
 
                                eq_string, escPkTableName, eq_string, escSchemaName);
4646
 
                        free(escSchemaName);
4647
 
                }
4648
 
                else
4649
 
                        snprintf(tables_query, sizeof(tables_query), "SELECT    pt.tgargs, "
4650
 
                                "       pt.tgnargs, "
4651
 
                                "       pt.tgdeferrable, "
4652
 
                                "       pt.tginitdeferred, "
4653
 
                                "       pp1.proname, "
4654
 
                                "       pp2.proname, "
4655
 
                                "       pc.oid, "
4656
 
                                "       pc1.oid, "
4657
 
                                "       pc1.relname, pt.tgconstrname "
4658
 
                                "FROM   pg_class pc, "
4659
 
                                "       pg_class pc1, "
4660
 
                                "       pg_proc pp, "
4661
 
                                "       pg_proc pp1, "
4662
 
                                "       pg_proc pp2, "
4663
 
                                "       pg_trigger pt, "
4664
 
                                "       pg_trigger pt1, "
4665
 
                                "       pg_trigger pt2 "
4666
 
                                "WHERE  pc.relname %s'%s' "
4667
 
                                "       AND pt.tgconstrrelid = pc.oid "
4668
 
                                "       AND pp.oid = pt.tgfoid "
4669
 
                                "       AND pp.proname Like '%%ins' "
4670
 
                                "       AND pt1.tgconstrname = pt.tgconstrname "
4671
 
                                "       AND pt1.tgconstrrelid = pt.tgrelid "
4672
 
                                "       AND pt1.tgrelid = pc.oid "
4673
 
                                "       AND pc1.oid = pt.tgrelid "
4674
 
                                "       AND pp1.oid = pt1.tgfoid "
4675
 
                                "       AND pp1.proname like '%%upd' "
4676
 
                                "       AND pp1.(proname not like '%%check%%') "
4677
 
                                "       AND pt2.tgconstrname = pt.tgconstrname "
4678
 
                                "       AND pt2.tgconstrrelid = pt.tgrelid "
4679
 
                                "       AND pt2.tgrelid = pc.oid "
4680
 
                                "       AND pp2.oid = pt2.tgfoid "
4681
 
                                "       AND pp2.proname Like '%%del'"
4682
 
                                " order by pt.tgconstrname",
4683
 
                                eq_string, escPkTableName);
4684
 
 
4685
 
                result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
4686
 
                if (!SQL_SUCCEEDED(result))
4687
 
                {
4688
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4689
 
                        goto cleanup;
4690
 
                }
4691
 
 
4692
 
                result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_BINARY,
4693
 
                                                           trig_args, sizeof(trig_args), NULL);
4694
 
                if (!SQL_SUCCEEDED(result))
4695
 
                {
4696
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4697
 
                        goto cleanup;
4698
 
                }
4699
 
 
4700
 
                result = PGAPI_BindCol(htbl_stmt, 2, SQL_C_SHORT,
4701
 
                                                           &trig_nargs, 0, NULL);
4702
 
                if (!SQL_SUCCEEDED(result))
4703
 
                {
4704
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4705
 
                        goto cleanup;
4706
 
                }
4707
 
 
4708
 
                result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
4709
 
                                                 trig_deferrable, sizeof(trig_deferrable), NULL);
4710
 
                if (!SQL_SUCCEEDED(result))
4711
 
                {
4712
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4713
 
                        goto cleanup;
4714
 
                }
4715
 
 
4716
 
                result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type,
4717
 
                                         trig_initdeferred, sizeof(trig_initdeferred), NULL);
4718
 
                if (!SQL_SUCCEEDED(result))
4719
 
                {
4720
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4721
 
                        goto cleanup;
4722
 
                }
4723
 
 
4724
 
                result = PGAPI_BindCol(htbl_stmt, 5, internal_asis_type,
4725
 
                                                           upd_rule, sizeof(upd_rule), NULL);
4726
 
                if (!SQL_SUCCEEDED(result))
4727
 
                {
4728
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4729
 
                        goto cleanup;
4730
 
                }
4731
 
 
4732
 
                result = PGAPI_BindCol(htbl_stmt, 6, internal_asis_type,
4733
 
                                                           del_rule, sizeof(del_rule), NULL);
4734
 
                if (!SQL_SUCCEEDED(result))
4735
 
                {
4736
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4737
 
                        goto cleanup;
4738
 
                }
4739
 
 
4740
 
                result = PGAPI_BindCol(htbl_stmt, 7, SQL_C_ULONG,
4741
 
                                                &relid1, sizeof(relid1), NULL);
4742
 
                if (!SQL_SUCCEEDED(result))
4743
 
                {
4744
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4745
 
                        goto cleanup;
4746
 
                }
4747
 
                result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG,
4748
 
                                                &relid2, sizeof(relid2), NULL);
4749
 
                if (!SQL_SUCCEEDED(result))
4750
 
                {
4751
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4752
 
                        goto cleanup;
4753
 
                }
4754
 
                result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type,
4755
 
                                        fk_table_fetched, TABLE_NAME_STORAGE_LEN, NULL);
4756
 
                if (!SQL_SUCCEEDED(result))
4757
 
                {
4758
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4759
 
                        goto cleanup;
4760
 
                }
4761
 
                result = PGAPI_BindCol(htbl_stmt, 10, internal_asis_type,
4762
 
                                        constrname, NAMESTORAGELEN, NULL);
4763
 
                if (!SQL_SUCCEEDED(result))
4764
 
                {
4765
 
                        SC_error_copy(stmt, tbl_stmt, TRUE);
4766
 
                        goto cleanup;
4767
 
                }
4768
 
 
4769
 
                if (conn->schema_support)
4770
 
                {
4771
 
                        result = PGAPI_BindCol(htbl_stmt, 11, internal_asis_type,
4772
 
                                        schema_fetched, SCHEMA_NAME_STORAGE_LEN, NULL);
4773
 
                        if (!SQL_SUCCEEDED(result))
4774
 
                        {
4775
 
                                SC_error_copy(stmt, tbl_stmt, TRUE);
4776
 
                                goto cleanup;
4777
 
                        }
4778
 
                }
4779
 
 
4780
 
                result = PGAPI_Fetch(htbl_stmt);
4781
 
                if (result == SQL_NO_DATA_FOUND)
4782
 
                {
4783
 
                        ret = SQL_SUCCESS;
4784
 
                        goto cleanup;
4785
 
                }
4786
 
 
4787
 
                if (result != SQL_SUCCESS)
4788
 
                {
4789
 
                        SC_full_error_copy(stmt, tbl_stmt, FALSE);
4790
 
                        goto cleanup;
4791
 
                }
4792
 
 
4793
 
                /*
4794
 
                 *      get pk_name here
4795
 
                 */
4796
 
                keyresult = PGAPI_AllocStmt(conn, &hpkey_stmt, 0);
4797
 
                if (!SQL_SUCCEEDED(keyresult))
4798
 
                {
4799
 
                        SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.", func);
4800
 
                        goto cleanup;
4801
 
                }
4802
 
                keyresult = PGAPI_BindCol(hpkey_stmt, 6, internal_asis_type,
4803
 
                                pkname, sizeof(pkname), NULL);
4804
 
                if (keyresult != SQL_SUCCESS)
4805
 
                {
4806
 
                        SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.", func);
4807
 
                        goto cleanup;
4808
 
                }
4809
 
                keyresult = PGAPI_PrimaryKeys(hpkey_stmt, NULL, 0, schema_needed, SQL_NTS, pk_table_needed, SQL_NTS, 0);
4810
 
                if (keyresult != SQL_SUCCESS)
4811
 
                {
4812
 
                        SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't get primary keys for PGAPI_ForeignKeys result.", func);
4813
 
                        goto cleanup;
4814
 
                }
4815
 
                pkname[0] = '\0';
4816
 
                keyresult = PGAPI_Fetch(hpkey_stmt);
4817
 
                PGAPI_FreeStmt(hpkey_stmt, SQL_CLOSE);
4818
 
                while (result == SQL_SUCCESS)
4819
 
                {
4820
 
                        /* Calculate the number of key parts */
4821
 
                        num_keys = (trig_nargs - 4) / 2;;
4822
 
 
4823
 
                        /* Handle action (i.e., 'cascade', 'restrict', 'setnull') */
4824
 
                        if (!strcmp(upd_rule, "RI_FKey_cascade_upd"))
4825
 
                                upd_rule_type = SQL_CASCADE;
4826
 
                        else if (!strcmp(upd_rule, "RI_FKey_noaction_upd"))
4827
 
                                upd_rule_type = SQL_NO_ACTION;
4828
 
                        else if (!strcmp(upd_rule, "RI_FKey_restrict_upd"))
4829
 
                                upd_rule_type = SQL_NO_ACTION;
4830
 
                        else if (!strcmp(upd_rule, "RI_FKey_setdefault_upd"))
4831
 
                                upd_rule_type = SQL_SET_DEFAULT;
4832
 
                        else if (!strcmp(upd_rule, "RI_FKey_setnull_upd"))
4833
 
                                upd_rule_type = SQL_SET_NULL;
4834
 
 
4835
 
                        if (!strcmp(del_rule, "RI_FKey_cascade_del"))
4836
 
                                del_rule_type = SQL_CASCADE;
4837
 
                        else if (!strcmp(del_rule, "RI_FKey_noaction_del"))
4838
 
                                del_rule_type = SQL_NO_ACTION;
4839
 
                        else if (!strcmp(del_rule, "RI_FKey_restrict_del"))
4840
 
                                del_rule_type = SQL_NO_ACTION;
4841
 
                        else if (!strcmp(del_rule, "RI_FKey_setdefault_del"))
4842
 
                                del_rule_type = SQL_SET_DEFAULT;
4843
 
                        else if (!strcmp(del_rule, "RI_FKey_setnull_del"))
4844
 
                                del_rule_type = SQL_SET_NULL;
4845
 
 
4846
 
#if (ODBCVER >= 0x0300)
4847
 
                        /* Set deferrability type */
4848
 
                        if (!strcmp(trig_initdeferred, "y"))
4849
 
                                defer_type = SQL_INITIALLY_DEFERRED;
4850
 
                        else if (!strcmp(trig_deferrable, "y"))
4851
 
                                defer_type = SQL_INITIALLY_IMMEDIATE;
4852
 
                        else
4853
 
                                defer_type = SQL_NOT_DEFERRABLE;
4854
 
#endif   /* ODBCVER >= 0x0300 */
4855
 
 
4856
 
                        mylog("Foreign Key Case#1: trig_nargs = %d, num_keys = %d\n", trig_nargs, num_keys);
4857
 
 
4858
 
                        /* Get to first primary key */
4859
 
                        pkey_ptr = trig_args;
4860
 
                        for (i = 0; i < 5; i++)
4861
 
                                pkey_ptr += strlen(pkey_ptr) + 1;
4862
 
 
4863
 
                        /* Get to first foreign key */
4864
 
                        fkey_ptr = trig_args;
4865
 
                        for (k = 0; k < 4; k++)
4866
 
                                fkey_ptr += strlen(fkey_ptr) + 1;
4867
 
 
4868
 
                        for (k = 0; k < num_keys; k++)
4869
 
                        {
4870
 
                                pkey_text = getClientColumnName(conn, relid1, pkey_ptr, &pkey_alloced);
4871
 
                                fkey_text = getClientColumnName(conn, relid2, fkey_ptr, &fkey_alloced);
4872
 
 
4873
 
                                mylog("pkey_ptr = '%s', fk_table = '%s', fkey_ptr = '%s'\n", pkey_text, fk_table_fetched, fkey_text);
4874
 
 
4875
 
                                tuple = QR_AddNew(res);
4876
 
 
4877
 
                                mylog("pk_table_needed = '%s', pkey_ptr = '%s'\n", pk_table_needed, pkey_text);
4878
 
                                set_tuplefield_string(&tuple[FKS_PKTABLE_CAT], CurrCat(conn));
4879
 
                                set_tuplefield_string(&tuple[FKS_PKTABLE_SCHEM], GET_SCHEMA_NAME(schema_needed));
4880
 
                                set_tuplefield_string(&tuple[FKS_PKTABLE_NAME], pk_table_needed);
4881
 
                                set_tuplefield_string(&tuple[FKS_PKCOLUMN_NAME], pkey_text);
4882
 
 
4883
 
                                mylog("fk_table = '%s', fkey_ptr = '%s'\n", fk_table_fetched, fkey_text);
4884
 
                                set_tuplefield_string(&tuple[FKS_FKTABLE_CAT], CurrCat(conn));
4885
 
                                set_tuplefield_string(&tuple[FKS_FKTABLE_SCHEM], GET_SCHEMA_NAME(schema_fetched));
4886
 
                                set_tuplefield_string(&tuple[FKS_FKTABLE_NAME], fk_table_fetched);
4887
 
                                set_tuplefield_string(&tuple[FKS_FKCOLUMN_NAME], fkey_text);
4888
 
 
4889
 
                                set_tuplefield_int2(&tuple[FKS_KEY_SEQ], (Int2) (k + 1));
4890
 
 
4891
 
                                mylog("upd_rule = %d, del_rule= %d", upd_rule_type, del_rule_type);
4892
 
                                set_nullfield_int2(&tuple[FKS_UPDATE_RULE], upd_rule_type);
4893
 
                                set_nullfield_int2(&tuple[FKS_DELETE_RULE], del_rule_type);
4894
 
 
4895
 
                                set_tuplefield_string(&tuple[FKS_FK_NAME], constrname);
4896
 
                                set_tuplefield_string(&tuple[FKS_PK_NAME], pkname);
4897
 
 
4898
 
                                set_tuplefield_string(&tuple[FKS_TRIGGER_NAME], trig_args);
4899
 
 
4900
 
#if (ODBCVER >= 0x0300)
4901
 
                                mylog(" defer_type = %d\n", defer_type);
4902
 
                                set_tuplefield_int2(&tuple[FKS_DEFERRABILITY], defer_type);
4903
 
#endif   /* ODBCVER >= 0x0300 */
4904
 
 
4905
 
                                if (pkey_alloced)
4906
 
                                        free(pkey_text);
4907
 
                                pkey_alloced = FALSE;
4908
 
                                if (fkey_alloced)
4909
 
                                        free(fkey_text);
4910
 
                                fkey_alloced = FALSE;
4911
 
 
4912
 
                                /* next primary/foreign key */
4913
 
                                for (j = 0; j < 2; j++)
4914
 
                                {
4915
 
                                        pkey_ptr += strlen(pkey_ptr) + 1;
4916
 
                                        fkey_ptr += strlen(fkey_ptr) + 1;
4917
 
                                }
4918
 
                        }
4919
 
                        result = PGAPI_Fetch(htbl_stmt);
4920
 
                }
4921
 
        }
4922
 
        else
4923
 
        {
4924
 
                SC_set_error(stmt, STMT_INTERNAL_ERROR, "No tables specified to PGAPI_ForeignKeys.", func);
4925
 
                goto cleanup;
4926
 
        }
4927
 
        ret = SQL_SUCCESS;
4928
 
 
4929
 
cleanup:
4930
 
#undef  return
4931
 
        /*
4932
 
         * also, things need to think that this statement is finished so the
4933
 
         * results can be retrieved.
4934
 
         */
4935
 
        stmt->status = STMT_FINISHED;
4936
 
 
4937
 
        if (pkey_alloced)
4938
 
                free(pkey_text);
4939
 
        if (fkey_alloced)
4940
 
                free(fkey_text);
4941
 
        if (pk_table_needed)
4942
 
                free(pk_table_needed);
4943
 
        if (escPkTableName)
4944
 
                free(escPkTableName);
4945
 
        if (fk_table_needed)
4946
 
                free(fk_table_needed);
4947
 
        if (escFkTableName)
4948
 
                free(escFkTableName);
4949
 
 
4950
 
        if (htbl_stmt)
4951
 
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
4952
 
        if (hpkey_stmt)
4953
 
                PGAPI_FreeStmt(hpkey_stmt, SQL_DROP);
4954
 
 
4955
 
        /* set up the current tuple pointer for SQLFetch */
4956
 
        stmt->currTuple = -1;
4957
 
        SC_set_rowset_start(stmt, -1, FALSE);
4958
 
        SC_set_current_col(stmt, -1);
4959
 
 
4960
 
        if (stmt->internal)
4961
 
                ret = DiscardStatementSvp(stmt, ret, FALSE);
4962
 
        mylog("%s(): EXIT, stmt=%p, ret=%d\n", func, stmt, ret);
4963
 
        return ret;
4964
 
}
4965
 
 
4966
 
RETCODE         SQL_API
4967
 
PGAPI_ForeignKeys(
4968
 
                        HSTMT hstmt,
4969
 
                        const SQLCHAR FAR * szPkTableQualifier, /* OA X*/
4970
 
                        SQLSMALLINT cbPkTableQualifier,
4971
 
                        const SQLCHAR FAR * szPkTableOwner, /* OA E*/
4972
 
                        SQLSMALLINT cbPkTableOwner,
4973
 
                        const SQLCHAR FAR * szPkTableName, /* OA(R) E*/
4974
 
                        SQLSMALLINT cbPkTableName,
4975
 
                        const SQLCHAR FAR * szFkTableQualifier, /* OA X*/
4976
 
                        SQLSMALLINT cbFkTableQualifier,
4977
 
                        const SQLCHAR FAR * szFkTableOwner, /* OA E*/
4978
 
                        SQLSMALLINT cbFkTableOwner,
4979
 
                        const SQLCHAR FAR * szFkTableName, /* OA(R) E*/
4980
 
                        SQLSMALLINT cbFkTableName)
4981
 
{
4982
 
        ConnectionClass *conn = SC_get_conn(((StatementClass *) hstmt));
4983
 
        if (PG_VERSION_GE(conn, 8.1))
4984
 
                return PGAPI_ForeignKeys_new(hstmt,
4985
 
                                szPkTableQualifier, cbPkTableQualifier,
4986
 
                                szPkTableOwner, cbPkTableOwner,
4987
 
                                szPkTableName, cbPkTableName,
4988
 
                                szFkTableQualifier, cbFkTableQualifier,
4989
 
                                szFkTableOwner, cbFkTableOwner,
4990
 
                                szFkTableName, cbFkTableName);
4991
 
        else
4992
 
                return PGAPI_ForeignKeys_old(hstmt,
4993
 
                                szPkTableQualifier, cbPkTableQualifier,
4994
 
                                szPkTableOwner, cbPkTableOwner,
4995
 
                                szPkTableName, cbPkTableName,
4996
 
                                szFkTableQualifier, cbFkTableQualifier,
4997
 
                                szFkTableOwner, cbFkTableOwner,
4998
 
                                szFkTableName, cbFkTableName);
4999
 
}
5000
 
 
5001
 
 
5002
 
#define PRORET_COUNT
5003
 
#define DISPLAY_ARGNAME
5004
 
RETCODE         SQL_API
5005
 
PGAPI_ProcedureColumns(
5006
 
                                HSTMT hstmt,
5007
 
                                const SQLCHAR FAR * szProcQualifier, /* OA X*/
5008
 
                                SQLSMALLINT cbProcQualifier,
5009
 
                                const SQLCHAR FAR * szProcOwner, /* PV E*/
5010
 
                                SQLSMALLINT cbProcOwner,
5011
 
                                const SQLCHAR FAR * szProcName, /* PV E*/
5012
 
                                SQLSMALLINT cbProcName,
5013
 
                                const SQLCHAR FAR * szColumnName, /* PV X*/
5014
 
                                SQLSMALLINT cbColumnName,
5015
 
                                UWORD flag)
5016
 
{
5017
 
        CSTR func = "PGAPI_ProcedureColumns";
5018
 
        StatementClass  *stmt = (StatementClass *) hstmt;
5019
 
        ConnectionClass *conn = SC_get_conn(stmt);
5020
 
        char            proc_query[INFO_INQUIRY_LEN];
5021
 
        Int2            result_cols;
5022
 
        TupleField      *tuple;
5023
 
        char            *schema_name, *procname;
5024
 
        char            *escSchemaName = NULL, *escProcName = NULL;
5025
 
        char            *params, *proargnames, *proargmodes, *delim = NULL;
5026
 
        char            *atttypid, *attname, *column_name;
5027
 
        QResultClass *res, *tres;
5028
 
        SQLLEN          tcount;
5029
 
        OID             pgtype;
5030
 
        Int4            paramcount, column_size, i, j;
5031
 
        RETCODE         result;
5032
 
        BOOL            search_pattern, bRetset;
5033
 
        const char      *like_or_eq, *op_string, *retset;
5034
 
        int             ret_col = -1, ext_pos = -1, poid_pos = -1, attid_pos = -1, attname_pos = -1;
5035
 
        UInt4           poid = 0, newpoid;
5036
 
 
5037
 
        mylog("%s: entering...\n", func);
5038
 
 
5039
 
        if (PG_VERSION_LT(conn, 6.5))
5040
 
        {
5041
 
                SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Version is too old", func);
5042
 
                return SQL_ERROR;
5043
 
        }
5044
 
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
5045
 
                return result;
5046
 
        search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
5047
 
        if (search_pattern) 
5048
 
        {
5049
 
                like_or_eq = likeop;
5050
 
                escSchemaName = adjustLikePattern(szProcOwner, cbProcOwner, SEARCH_PATTERN_ESCAPE, NULL, conn);
5051
 
                escProcName = adjustLikePattern(szProcName, cbProcName, SEARCH_PATTERN_ESCAPE, NULL, conn);
5052
 
        }
5053
 
        else
5054
 
        {
5055
 
                like_or_eq = eqop;
5056
 
                escSchemaName = simpleCatalogEscape(szProcOwner, cbProcOwner, NULL, conn);
5057
 
                escProcName = simpleCatalogEscape(szProcName, cbProcName, NULL, conn);
5058
 
        }
5059
 
        op_string = gen_opestr(like_or_eq, conn);
5060
 
        if (conn->schema_support)
5061
 
        {
5062
 
                strcpy(proc_query, "select proname, proretset, prorettype, "
5063
 
                                "pronargs, proargtypes, nspname, p.oid");
5064
 
                ret_col = ext_pos = 7;
5065
 
                poid_pos = 6;
5066
 
#ifdef  PRORET_COUNT
5067
 
                strcat(proc_query, ", atttypid, attname");
5068
 
                attid_pos = ext_pos;
5069
 
                attname_pos = ext_pos + 1;
5070
 
                ret_col += 2;
5071
 
                ext_pos = ret_col;
5072
 
#endif /* PRORET_COUNT */
5073
 
                if (PG_VERSION_GE(conn, 8.0))
5074
 
                {
5075
 
                        strcat(proc_query, ", proargnames");
5076
 
                        ret_col++;
5077
 
                }
5078
 
                if (PG_VERSION_GE(conn, 8.1))
5079
 
                {
5080
 
                        strcat(proc_query, ", proargmodes, proallargtypes");
5081
 
                        ret_col += 2;
5082
 
                }
5083
 
#ifdef  PRORET_COUNT
5084
 
                strcat(proc_query, " from ((pg_catalog.pg_namespace n inner join"
5085
 
                                   " pg_catalog.pg_proc p on p.pronamespace = n.oid)"
5086
 
                        " inner join pg_type t on t.oid = p.prorettype)"
5087
 
                        " left outer join pg_attribute a on a.attrelid = t.typrelid "
5088
 
                        " and attnum > 0 and not attisdropped where");
5089
 
#else
5090
 
                strcat(proc_query, " from pg_catalog.pg_namespace n,"
5091
 
                                   " pg_catalog.pg_proc p where");
5092
 
                                   " p.pronamespace = n.oid  and"
5093
 
                                   " (not proretset) and");
5094
 
#endif /* PRORET_COUNT */
5095
 
                strcat(proc_query, " has_function_privilege(p.oid, 'EXECUTE')");
5096
 
                my_strcat1(proc_query, " and nspname %s'%.*s'", op_string, escSchemaName, SQL_NTS);
5097
 
                if (escProcName)
5098
 
                        snprintf_add(proc_query, sizeof(proc_query), " and proname %s'%s'", op_string, escProcName);
5099
 
                strcat(proc_query, " order by nspname, proname, p.oid, attnum");
5100
 
        }
5101
 
        else
5102
 
        {
5103
 
                strcpy(proc_query, "select proname, proretset, prorettype, "
5104
 
                                "pronargs, proargtypes from pg_proc where "
5105
 
                                "(not proretset)");
5106
 
                ret_col = 5;
5107
 
                if (escProcName)
5108
 
                        snprintf_add(proc_query, sizeof(proc_query), " and proname %s'%s'", op_string, escProcName);
5109
 
                strcat(proc_query, " order by proname, proretset");
5110
 
        }
5111
 
        if (tres = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(tres))
5112
 
        {
5113
 
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_ProcedureColumns query error", func);
5114
 
                QR_Destructor(tres);
5115
 
                return SQL_ERROR;
5116
 
        }
5117
 
 
5118
 
        if (res = QR_Constructor(), !res)
5119
 
        {
5120
 
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_ProcedureColumns result.", func);
5121
 
                return SQL_ERROR;
5122
 
        }
5123
 
        SC_set_Result(stmt, res);
5124
 
 
5125
 
        /*
5126
 
         * the binding structure for a statement is not set up until
5127
 
         * a statement is actually executed, so we'll have to do this
5128
 
         * ourselves.
5129
 
         */
5130
 
        result_cols = NUM_OF_PROCOLS_FIELDS;
5131
 
        extend_column_bindings(SC_get_ARDF(stmt), result_cols);
5132
 
 
5133
 
        stmt->catalog_result = TRUE;
5134
 
        /* set the field names */
5135
 
        QR_set_num_fields(res, result_cols);
5136
 
        QR_set_field_info_v(res, PROCOLS_PROCEDURE_CAT, "PROCEDURE_CAT", PG_TYPE_VARCHAR, MAX_INFO_STRING);
5137
 
        QR_set_field_info_v(res, PROCOLS_PROCEDURE_SCHEM, "PROCEDUR_SCHEM", PG_TYPE_VARCHAR, MAX_INFO_STRING);
5138
 
        QR_set_field_info_v(res, PROCOLS_PROCEDURE_NAME, "PROCEDURE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
5139
 
        QR_set_field_info_v(res, PROCOLS_COLUMN_NAME, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
5140
 
        QR_set_field_info_v(res, PROCOLS_COLUMN_TYPE, "COLUMN_TYPE", PG_TYPE_INT2, 2);
5141
 
        QR_set_field_info_v(res, PROCOLS_DATA_TYPE, "DATA_TYPE", PG_TYPE_INT2, 2);
5142
 
        QR_set_field_info_v(res, PROCOLS_TYPE_NAME, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
5143
 
        QR_set_field_info_v(res, PROCOLS_COLUMN_SIZE, "COLUMN_SIZE", PG_TYPE_INT4, 4);
5144
 
        QR_set_field_info_v(res, PROCOLS_BUFFER_LENGTH, "BUFFER_LENGTH", PG_TYPE_INT4, 4);
5145
 
        QR_set_field_info_v(res, PROCOLS_DECIMAL_DIGITS, "DECIMAL_DIGITS", PG_TYPE_INT2, 2);
5146
 
        QR_set_field_info_v(res, PROCOLS_NUM_PREC_RADIX, "NUM_PREC_RADIX", PG_TYPE_INT2, 2);
5147
 
        QR_set_field_info_v(res, PROCOLS_NULLABLE, "NULLABLE", PG_TYPE_INT2, 2);
5148
 
        QR_set_field_info_v(res, PROCOLS_REMARKS, "REMARKS", PG_TYPE_VARCHAR, MAX_INFO_STRING);
5149
 
#if (ODBCVER >= 0x0300)
5150
 
        QR_set_field_info_v(res, PROCOLS_COLUMN_DEF, "COLUMN_DEF", PG_TYPE_VARCHAR, MAX_INFO_STRING);
5151
 
        QR_set_field_info_v(res, PROCOLS_SQL_DATA_TYPE, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
5152
 
        QR_set_field_info_v(res, PROCOLS_SQL_DATETIME_SUB, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
5153
 
        QR_set_field_info_v(res, PROCOLS_CHAR_OCTET_LENGTH, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
5154
 
        QR_set_field_info_v(res, PROCOLS_ORDINAL_POSITION, "ORDINAL_POSITION", PG_TYPE_INT4, 4);
5155
 
        QR_set_field_info_v(res, PROCOLS_IS_NULLABLE, "IS_NULLABLE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
5156
 
#endif   /* ODBCVER >= 0x0300 */
5157
 
 
5158
 
        column_name = make_string(szColumnName, cbColumnName, NULL, 0);
5159
 
        if (column_name) /* column_name is unavailable now */
5160
 
        {
5161
 
                tcount = 0;
5162
 
                free(column_name);
5163
 
        }
5164
 
        else
5165
 
                tcount = QR_get_num_total_tuples(tres);
5166
 
        for (i = 0, poid = 0; i < tcount; i++)
5167
 
        {
5168
 
                if (conn->schema_support)
5169
 
                        schema_name = GET_SCHEMA_NAME(QR_get_value_backend_text(tres, i, 5));
5170
 
                else
5171
 
                        schema_name = NULL;
5172
 
                procname = QR_get_value_backend_text(tres, i, 0);
5173
 
                retset = QR_get_value_backend_text(tres, i, 1);
5174
 
                pgtype = QR_get_value_backend_int(tres, i, 2, NULL);
5175
 
                bRetset = retset && (retset[0] == 't' || retset[0] == 'y');
5176
 
                newpoid = 0;
5177
 
                if (poid_pos >= 0)
5178
 
                        newpoid = QR_get_value_backend_int(tres, i, poid_pos, NULL);
5179
 
mylog("newpoid=%d\n", newpoid);
5180
 
                atttypid = NULL;
5181
 
                if (attid_pos >= 0)
5182
 
                {
5183
 
                        atttypid = QR_get_value_backend_text(tres, i, attid_pos);
5184
 
mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
5185
 
                }
5186
 
                if (poid == 0 || newpoid != poid)
5187
 
                {
5188
 
                        poid = newpoid;
5189
 
                        proargmodes = NULL;
5190
 
                        proargnames = NULL;
5191
 
                        if (ext_pos >=0)
5192
 
                        {
5193
 
#ifdef  DISPLAY_ARGNAME /* !! named parameter is unavailable !! */
5194
 
                                if (PG_VERSION_GE(conn, 8.0))
5195
 
                                        proargnames = QR_get_value_backend_text(tres, i, ext_pos);
5196
 
#endif /* DISPLAY_ARGNAME */
5197
 
                                if (PG_VERSION_GE(conn, 8.1))
5198
 
                                        proargmodes = QR_get_value_backend_text(tres, i, ext_pos + 1);
5199
 
                        }
5200
 
                        /* RETURN_VALUE info */ 
5201
 
                        if (0 != pgtype && PG_TYPE_VOID != pgtype && !bRetset && !atttypid && !proargmodes)
5202
 
                        {
5203
 
                                tuple = QR_AddNew(res);
5204
 
                                set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_CAT], CurrCat(conn));
5205
 
                                set_nullfield_string(&tuple[PROCOLS_PROCEDURE_SCHEM], schema_name);
5206
 
                                set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_NAME], procname);
5207
 
                                set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME], NULL_STRING);
5208
 
                                set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE], SQL_RETURN_VALUE);
5209
 
                                set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
5210
 
                                set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, pgtype, PG_UNSPECIFIED, FALSE));
5211
 
                                column_size = pgtype_column_size(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT);
5212
 
                                set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE], column_size);
5213
 
                                set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH], pgtype_buffer_length(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT));
5214
 
                                set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
5215
 
                                set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(conn, pgtype));
5216
 
                                set_tuplefield_int2(&tuple[PROCOLS_NULLABLE], SQL_NULLABLE_UNKNOWN);
5217
 
                                set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
5218
 
#if (ODBCVER >= 0x0300)
5219
 
                                set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
5220
 
                                set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
5221
 
                                set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, pgtype, PG_UNSPECIFIED));
5222
 
                                set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, pgtype, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
5223
 
                                set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION], 0);
5224
 
                                set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE], NULL_STRING);
5225
 
#endif   /* ODBCVER >= 0x0300 */
5226
 
                        }
5227
 
                        if (proargmodes)
5228
 
                        {
5229
 
                                const char *p;
5230
 
 
5231
 
                                paramcount = 0;
5232
 
                                for (p = proargmodes; *p; p++)
5233
 
                                {
5234
 
                                        if (',' == (*p))
5235
 
                                                paramcount++;
5236
 
                                }
5237
 
                                paramcount++;
5238
 
                                params = QR_get_value_backend_text(tres, i, ext_pos + 2);
5239
 
                                if ('{' == *proargmodes)
5240
 
                                        proargmodes++;
5241
 
                                if ('{' == *params)
5242
 
                                        params++;
5243
 
                        }
5244
 
                        else
5245
 
                        {
5246
 
                                paramcount = QR_get_value_backend_int(tres, i, 3, NULL);
5247
 
                                params = QR_get_value_backend_text(tres, i, 4);
5248
 
                        }
5249
 
                        if (proargnames)
5250
 
                        {
5251
 
                                if ('{' == *proargnames)
5252
 
                                        proargnames++;
5253
 
                        }
5254
 
                        /* PARAMETERS info */
5255
 
                        for (j = 0; j < paramcount; j++)
5256
 
                        {
5257
 
                                /* PG type of parameters */
5258
 
                                pgtype = 0;
5259
 
                                if (params)
5260
 
                                {
5261
 
                                        while (isspace(*params) || ',' == *params)
5262
 
                                                params++;
5263
 
                                        if ('\0' == *params || '}' == *params)
5264
 
                                                params = NULL;
5265
 
                                        else
5266
 
                                        {
5267
 
                                                sscanf(params, "%u", &pgtype);
5268
 
                                                while (isdigit(*params))
5269
 
                                                        params++;
5270
 
                                        }
5271
 
                                }
5272
 
                                /* input/output type of parameters */
5273
 
                                if (proargmodes)
5274
 
                                {
5275
 
                                        while (isspace(*proargmodes) || ',' == *proargmodes)
5276
 
                                                proargmodes++;
5277
 
                                        if ('\0' == *proargmodes || '}' == *proargmodes)
5278
 
                                                proargmodes = NULL;
5279
 
                                }
5280
 
                                /* name of parameters */
5281
 
                                if (proargnames)
5282
 
                                {
5283
 
                                        while (isspace(*proargnames) || ',' == *proargnames)
5284
 
                                                proargnames++;
5285
 
                                        if ('\0' == *proargnames || '}' == *proargnames)
5286
 
                                                proargnames = NULL;
5287
 
                                        else if ('"' == *proargnames)
5288
 
                                        {
5289
 
                                                proargnames++;
5290
 
                                                for (delim = proargnames; *delim && *delim != '"'; delim++)
5291
 
                                                        ;
5292
 
                                        }
5293
 
                                        else
5294
 
                                        {
5295
 
                                                for (delim = proargnames; *delim && !isspace(*delim) && ',' != *delim && '}' != *delim; delim++)
5296
 
                                                        ;
5297
 
                                        }
5298
 
                                        if (proargnames && '\0' == *delim) /* discard the incomplete name */
5299
 
                                                proargnames = NULL;
5300
 
                                }
5301
 
 
5302
 
                                tuple = QR_AddNew(res);
5303
 
                                set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_CAT], CurrCat(conn));
5304
 
                                set_nullfield_string(&tuple[PROCOLS_PROCEDURE_SCHEM], schema_name);
5305
 
                                set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_NAME], procname);
5306
 
                                if (proargnames)
5307
 
                                {
5308
 
                                        *delim = '\0';
5309
 
                                        set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME], proargnames);
5310
 
                                        proargnames = delim + 1;
5311
 
                                }
5312
 
                                else
5313
 
                                        set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME], NULL_STRING);
5314
 
                                if (proargmodes)
5315
 
                                {
5316
 
                                        int     ptype;
5317
 
 
5318
 
                                        switch (*proargmodes)
5319
 
                                        {
5320
 
                                                case 'o':
5321
 
                                                        ptype = SQL_PARAM_OUTPUT;
5322
 
                                                        break;
5323
 
                                                case 'b':
5324
 
                                                        ptype = SQL_PARAM_INPUT_OUTPUT;
5325
 
                                                        break;
5326
 
                                                default:
5327
 
                                                        ptype = SQL_PARAM_INPUT;
5328
 
                                                        break;
5329
 
                                        }
5330
 
                                        set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE], ptype);
5331
 
                                        proargmodes++;
5332
 
                                }
5333
 
                                else
5334
 
                                        set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE], SQL_PARAM_INPUT);
5335
 
                                set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
5336
 
                                set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, pgtype, PG_UNSPECIFIED, FALSE));
5337
 
                                column_size = pgtype_column_size(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT);
5338
 
                                set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE], column_size);
5339
 
                                set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH], pgtype_buffer_length(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT));
5340
 
                                set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
5341
 
                                set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(conn, pgtype));
5342
 
                                set_tuplefield_int2(&tuple[PROCOLS_NULLABLE], SQL_NULLABLE_UNKNOWN);
5343
 
                                set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
5344
 
#if (ODBCVER >= 0x0300)
5345
 
                                set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
5346
 
                                set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
5347
 
                                set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, pgtype, PG_UNSPECIFIED));
5348
 
                                set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, pgtype, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
5349
 
                                set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION], j + 1);
5350
 
                                set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE], NULL_STRING);
5351
 
#endif   /* ODBCVER >= 0x0300 */
5352
 
                        }
5353
 
                }
5354
 
                /* RESULT Columns info */
5355
 
                if (NULL != atttypid || bRetset)
5356
 
                {
5357
 
                        int     typid;
5358
 
 
5359
 
                        if (bRetset)
5360
 
                        {
5361
 
                                typid = pgtype;
5362
 
                                attname = NULL;
5363
 
                        }
5364
 
                        else
5365
 
                        {
5366
 
                                typid = atoi(atttypid);
5367
 
                                attname = QR_get_value_backend_text(tres, i, attname_pos);
5368
 
                        }
5369
 
                        tuple = QR_AddNew(res);
5370
 
                        set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_CAT], CurrCat(conn));
5371
 
                        set_nullfield_string(&tuple[PROCOLS_PROCEDURE_SCHEM], schema_name);
5372
 
                        set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_NAME], procname);
5373
 
                        set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME], attname);
5374
 
                        set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE], SQL_RESULT_COL);
5375
 
                        set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE], pgtype_to_concise_type(stmt, typid, PG_STATIC));
5376
 
                        set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, typid, PG_UNSPECIFIED, FALSE));
5377
 
                        column_size = pgtype_column_size(stmt, typid, PG_STATIC, UNKNOWNS_AS_DEFAULT);
5378
 
                        set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE], column_size);
5379
 
                        set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH], pgtype_buffer_length(stmt, typid, PG_STATIC, UNKNOWNS_AS_DEFAULT));
5380
 
                        set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS], pgtype_decimal_digits(stmt, typid, PG_STATIC));
5381
 
                        set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(conn, typid));
5382
 
                        set_tuplefield_int2(&tuple[PROCOLS_NULLABLE], SQL_NULLABLE_UNKNOWN);
5383
 
                        set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
5384
 
#if (ODBCVER >= 0x0300)
5385
 
                        set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
5386
 
                        set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE], pgtype_to_sqldesctype(stmt, typid, PG_STATIC));
5387
 
                        set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, typid, PG_UNSPECIFIED));
5388
 
                        set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, typid, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
5389
 
                        set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION], 0);
5390
 
                        set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE], NULL_STRING);
5391
 
#endif   /* ODBCVER >= 0x0300 */
5392
 
                }
5393
 
        }
5394
 
        QR_Destructor(tres);
5395
 
        /*
5396
 
         * also, things need to think that this statement is finished so the
5397
 
         * results can be retrieved.
5398
 
         */
5399
 
        if (escSchemaName)
5400
 
                free(escSchemaName);
5401
 
        if (escProcName)
5402
 
                free(escProcName);
5403
 
        stmt->status = STMT_FINISHED;
5404
 
        /* set up the current tuple pointer for SQLFetch */
5405
 
        stmt->currTuple = -1;
5406
 
        SC_set_rowset_start(stmt, -1, FALSE);
5407
 
        SC_set_current_col(stmt, -1);
5408
 
 
5409
 
        return SQL_SUCCESS;
5410
 
}
5411
 
 
5412
 
 
5413
 
RETCODE         SQL_API
5414
 
PGAPI_Procedures(
5415
 
                                 HSTMT hstmt,
5416
 
                                 const SQLCHAR FAR * szProcQualifier, /* OA X*/
5417
 
                                 SQLSMALLINT cbProcQualifier,
5418
 
                                 const SQLCHAR FAR * szProcOwner, /* PV E*/
5419
 
                                 SQLSMALLINT cbProcOwner,
5420
 
                                 const SQLCHAR FAR * szProcName, /* PV E*/
5421
 
                                 SQLSMALLINT cbProcName,
5422
 
                                 UWORD flag)
5423
 
{
5424
 
        CSTR func = "PGAPI_Procedures";
5425
 
        StatementClass *stmt = (StatementClass *) hstmt;
5426
 
        ConnectionClass *conn = SC_get_conn(stmt);
5427
 
        char            proc_query[INFO_INQUIRY_LEN];
5428
 
        char    *escSchemaName = NULL, *escProcName = NULL;
5429
 
        QResultClass *res;
5430
 
        RETCODE         result;
5431
 
        const char      *like_or_eq, *op_string;
5432
 
        BOOL    search_pattern;
5433
 
 
5434
 
        mylog("%s: entering... scnm=%p len=%d\n", func, szProcOwner, cbProcOwner);
5435
 
 
5436
 
        if (PG_VERSION_LT(conn, 6.5))
5437
 
        {
5438
 
                SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Version is too old", func);
5439
 
                return SQL_ERROR;
5440
 
        }
5441
 
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
5442
 
                return result;
5443
 
 
5444
 
        search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
5445
 
        if (search_pattern) 
5446
 
        {
5447
 
                like_or_eq = likeop;
5448
 
                escSchemaName = adjustLikePattern(szProcOwner, cbProcOwner, SEARCH_PATTERN_ESCAPE, NULL, conn);
5449
 
                escProcName = adjustLikePattern(szProcName, cbProcName, SEARCH_PATTERN_ESCAPE, NULL, conn);
5450
 
        }
5451
 
        else
5452
 
        {
5453
 
                like_or_eq = eqop;
5454
 
                escSchemaName = simpleCatalogEscape(szProcOwner, cbProcOwner, NULL, conn);
5455
 
                escProcName = simpleCatalogEscape(szProcName, cbProcName, NULL, conn);
5456
 
        }
5457
 
        /*
5458
 
         * The following seems the simplest implementation
5459
 
         */
5460
 
        op_string = gen_opestr(like_or_eq, conn);
5461
 
        if (conn->schema_support)
5462
 
        {
5463
 
                strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", nspname as " "PROCEDURE_SCHEM" ","
5464
 
                " proname as " "PROCEDURE_NAME" ", '' as " "NUM_INPUT_PARAMS" ","
5465
 
                   " '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
5466
 
                   " '' as " "REMARKS" ","
5467
 
                   " case when prorettype = 0 then 1::int2 else 2::int2 end"
5468
 
                   " as "                 "PROCEDURE_TYPE" " from pg_catalog.pg_namespace,"
5469
 
                   " pg_catalog.pg_proc"
5470
 
                  " where pg_proc.pronamespace = pg_namespace.oid");
5471
 
                schema_strcat1(proc_query, " and nspname %s'%.*s'", op_string, escSchemaName, SQL_NTS, szProcName, cbProcName, conn);
5472
 
                my_strcat1(proc_query, " and proname %s'%.*s'", op_string, escProcName, SQL_NTS);
5473
 
        }
5474
 
        else
5475
 
        {
5476
 
                strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", '' as " "PROCEDURE_SCHEM" ","
5477
 
                " proname as " "PROCEDURE_NAME" ", '' as " "NUM_INPUT_PARAMS" ","
5478
 
                   " '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
5479
 
                   " '' as " "REMARKS" ","
5480
 
                   " case when prorettype = 0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_proc");
5481
 
                my_strcat1(proc_query, " where proname %s'%.*s'", op_string, escSchemaName, SQL_NTS);
5482
 
        }
5483
 
 
5484
 
        if (res = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(res))
5485
 
        {
5486
 
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_Procedures query error", func);
5487
 
                QR_Destructor(res);
5488
 
                return SQL_ERROR;
5489
 
        }
5490
 
        SC_set_Result(stmt, res);
5491
 
 
5492
 
        /*
5493
 
         * also, things need to think that this statement is finished so the
5494
 
         * results can be retrieved.
5495
 
         */
5496
 
        stmt->status = STMT_FINISHED;
5497
 
        extend_column_bindings(SC_get_ARDF(stmt), 8);
5498
 
        if (escSchemaName)
5499
 
                free(escSchemaName);
5500
 
        if (escProcName)
5501
 
                free(escProcName);
5502
 
        /* set up the current tuple pointer for SQLFetch */
5503
 
        stmt->currTuple = -1;
5504
 
        SC_set_rowset_start(stmt, -1, FALSE);
5505
 
        SC_set_current_col(stmt, -1);
5506
 
 
5507
 
        return SQL_SUCCESS;
5508
 
}
5509
 
 
5510
 
 
5511
 
#define ACLMAX  8
5512
 
#define ALL_PRIVILIGES "arwdRxt"
5513
 
static int
5514
 
usracl_auth(char *usracl, const char *auth)
5515
 
{
5516
 
        int     i, j, addcnt = 0;
5517
 
 
5518
 
        for (i = 0; auth[i]; i++)
5519
 
        {
5520
 
                for (j = 0; j < ACLMAX; j++)
5521
 
                {
5522
 
                        if (usracl[j] == auth[i])
5523
 
                                break;
5524
 
                        else if (!usracl[j])
5525
 
                        {
5526
 
                                usracl[j]= auth[i];
5527
 
                                addcnt++;
5528
 
                                break;
5529
 
                        }
5530
 
                }
5531
 
        }
5532
 
        return addcnt;
5533
 
}
5534
 
static void
5535
 
useracl_upd(char (*useracl)[ACLMAX], QResultClass *allures, const char *user, const char *auth)
5536
 
{
5537
 
        int usercount = (int) QR_get_num_cached_tuples(allures), i, addcnt = 0;
5538
 
 
5539
 
mylog("user=%s auth=%s\n", user, auth);
5540
 
        if (user[0])
5541
 
                for (i = 0; i < usercount; i++)
5542
 
                {
5543
 
                        if (strcmp(QR_get_value_backend_text(allures, i, 0), user) == 0)
5544
 
                        {
5545
 
                                addcnt += usracl_auth(useracl[i], auth);
5546
 
                                break;
5547
 
                        }
5548
 
                }
5549
 
        else
5550
 
                for (i = 0; i < usercount; i++)
5551
 
                {
5552
 
                        addcnt += usracl_auth(useracl[i], auth);
5553
 
                }
5554
 
        mylog("addcnt=%d\n", addcnt);
5555
 
}
5556
 
 
5557
 
RETCODE         SQL_API
5558
 
PGAPI_TablePrivileges(
5559
 
                                HSTMT hstmt,
5560
 
                                const SQLCHAR FAR * szTableQualifier, /* OA X*/
5561
 
                                SQLSMALLINT cbTableQualifier,
5562
 
                                const SQLCHAR FAR * szTableOwner, /* PV E*/
5563
 
                                SQLSMALLINT cbTableOwner,
5564
 
                                const SQLCHAR FAR * szTableName, /* PV E*/
5565
 
                                SQLSMALLINT cbTableName,
5566
 
                                UWORD flag)
5567
 
{
5568
 
        StatementClass *stmt = (StatementClass *) hstmt;
5569
 
        CSTR func = "PGAPI_TablePrivileges";
5570
 
        ConnectionClass *conn = SC_get_conn(stmt);
5571
 
        Int2            result_cols;
5572
 
        char            proc_query[INFO_INQUIRY_LEN];
5573
 
        QResultClass    *res, *wres = NULL, *allures = NULL;
5574
 
        TupleField      *tuple;
5575
 
        Int4            tablecount, usercount, i, j, k;
5576
 
        BOOL            grpauth, sys, su;
5577
 
        char            (*useracl)[ACLMAX] = NULL, *acl, *user, *delim, *auth;
5578
 
        const char      *reln, *owner, *priv, *schnm = NULL;
5579
 
        RETCODE         result, ret = SQL_SUCCESS;
5580
 
        const char      *like_or_eq, *op_string;
5581
 
        const char      *szSchemaName;
5582
 
        SQLSMALLINT     cbSchemaName;
5583
 
        char            *escSchemaName = NULL, *escTableName = NULL;
5584
 
        BOOL            search_pattern;
5585
 
 
5586
 
        mylog("%s: entering... scnm=%p len-%d\n", func, szTableOwner, cbTableOwner);
5587
 
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
5588
 
                return result;
5589
 
 
5590
 
        /*
5591
 
         * a statement is actually executed, so we'll have to do this
5592
 
         * ourselves.
5593
 
         */
5594
 
        result_cols = 7;
5595
 
        extend_column_bindings(SC_get_ARDF(stmt), result_cols);
5596
 
 
5597
 
        stmt->catalog_result = TRUE;
5598
 
        /* set the field names */
5599
 
        res = QR_Constructor();
5600
 
        SC_set_Result(stmt, res);
5601
 
        QR_set_num_fields(res, result_cols);
5602
 
        QR_set_field_info_v(res, 0, "TABLE_CAT", PG_TYPE_VARCHAR, MAX_INFO_STRING);
5603
 
        QR_set_field_info_v(res, 1, "TABLE_SCHEM", PG_TYPE_VARCHAR, MAX_INFO_STRING);
5604
 
        QR_set_field_info_v(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
5605
 
        QR_set_field_info_v(res, 3, "GRANTOR", PG_TYPE_VARCHAR, MAX_INFO_STRING);
5606
 
        QR_set_field_info_v(res, 4, "GRANTEE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
5607
 
        QR_set_field_info_v(res, 5, "PRIVILEGE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
5608
 
        QR_set_field_info_v(res, 6, "IS_GRANTABLE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
5609
 
 
5610
 
        /*
5611
 
         * also, things need to think that this statement is finished so the
5612
 
         * results can be retrieved.
5613
 
         */
5614
 
        stmt->status = STMT_FINISHED;
5615
 
        /* set up the current tuple pointer for SQLFetch */
5616
 
        stmt->currTuple = -1;
5617
 
        SC_set_rowset_start(stmt, -1, FALSE);
5618
 
        SC_set_current_col(stmt, -1);
5619
 
        szSchemaName = szTableOwner;
5620
 
        cbSchemaName = cbTableOwner;
5621
 
 
5622
 
#define return  DONT_CALL_RETURN_FROM_HERE???
5623
 
        search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
5624
 
        if (search_pattern) 
5625
 
        {
5626
 
                like_or_eq = likeop;
5627
 
                escTableName = adjustLikePattern(szTableName, cbTableName, SEARCH_PATTERN_ESCAPE, NULL, conn);
5628
 
        }
5629
 
        else
5630
 
        {
5631
 
                like_or_eq = eqop;
5632
 
                escTableName = simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
5633
 
        }
5634
 
 
5635
 
retry_public_schema:
5636
 
        if (escSchemaName)
5637
 
                free(escSchemaName);
5638
 
        if (search_pattern) 
5639
 
                escSchemaName = adjustLikePattern(szSchemaName, cbSchemaName, SEARCH_PATTERN_ESCAPE, NULL, conn);
5640
 
        else
5641
 
                escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn);
5642
 
 
5643
 
        op_string = gen_opestr(like_or_eq, conn);
5644
 
        if (conn->schema_support)
5645
 
                strncpy_null(proc_query, "select relname, usename, relacl, nspname"
5646
 
                " from pg_catalog.pg_namespace, pg_catalog.pg_class ,"
5647
 
                " pg_catalog.pg_user where", sizeof(proc_query));
5648
 
        else
5649
 
                strncpy_null(proc_query, "select relname, usename, relacl"
5650
 
                " from pg_class , pg_user where", sizeof(proc_query));
5651
 
        if (conn->schema_support)
5652
 
        {
5653
 
                if (escSchemaName)
5654
 
                        schema_strcat1(proc_query, " nspname %s'%.*s' and", op_string, escSchemaName, SQL_NTS, szTableName, cbTableName, conn);
5655
 
        }
5656
 
        if (escTableName)
5657
 
                snprintf_add(proc_query, sizeof(proc_query), " relname %s'%s' and", op_string, escTableName);
5658
 
        if (conn->schema_support)
5659
 
        {
5660
 
                strcat(proc_query, " pg_namespace.oid = relnamespace and relkind in ('r', 'v') and");
5661
 
                if ((!escTableName) && (!escSchemaName))
5662
 
                        strcat(proc_query, " nspname not in ('pg_catalog', 'information_schema') and");
5663
 
        }
5664
 
        strcat(proc_query, " pg_user.usesysid = relowner");
5665
 
        if (wres = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(wres))
5666
 
        {
5667
 
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_TablePrivileges query error", func);
5668
 
                ret = SQL_ERROR;
5669
 
                goto cleanup;
5670
 
        }
5671
 
        tablecount = (Int4) QR_get_num_cached_tuples(wres);
5672
 
        /* If not found */
5673
 
        if (conn->schema_support &&
5674
 
            (flag & PODBC_SEARCH_PUBLIC_SCHEMA) != 0 &&
5675
 
            0 == tablecount)
5676
 
        {
5677
 
                if (allow_public_schema(conn, szSchemaName, cbSchemaName))
5678
 
                {
5679
 
                        QR_Destructor(wres);
5680
 
                        wres = NULL;
5681
 
                        szSchemaName = pubstr;
5682
 
                        cbSchemaName = SQL_NTS;
5683
 
                        goto retry_public_schema;
5684
 
                }
5685
 
        }
5686
 
 
5687
 
        strncpy_null(proc_query, "select usename, usesysid, usesuper from pg_user", sizeof(proc_query));
5688
 
        if (allures = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(allures))
5689
 
        {
5690
 
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_TablePrivileges query error", func);
5691
 
                ret = SQL_ERROR;
5692
 
                goto cleanup;
5693
 
        }
5694
 
        usercount = (Int4) QR_get_num_cached_tuples(allures);
5695
 
        useracl = (char (*)[ACLMAX]) malloc(usercount * sizeof(char [ACLMAX]));
5696
 
        for (i = 0; i < tablecount; i++)
5697
 
        { 
5698
 
                memset(useracl, 0, usercount * sizeof(char[ACLMAX]));
5699
 
                acl = (char *) QR_get_value_backend_text(wres, i, 2);
5700
 
                if (acl && acl[0] == '{')
5701
 
                        user = acl + 1;
5702
 
                else
5703
 
                        user = NULL;
5704
 
                for (; user && *user;)
5705
 
                {
5706
 
                        grpauth = FALSE;
5707
 
                        if (user[0] == '"' && strncmp(user + 1, "group ", 6) == 0)
5708
 
                        {
5709
 
                                user += 7;
5710
 
                                grpauth = TRUE;
5711
 
                        }
5712
 
                        if (delim = strchr(user, '='), !delim)
5713
 
                                break;
5714
 
                        *delim = '\0';
5715
 
                        auth = delim + 1;
5716
 
                        if (grpauth)
5717
 
                        {
5718
 
                                if (delim = strchr(auth, '"'), delim)
5719
 
                                {
5720
 
                                        *delim = '\0';
5721
 
                                        delim++;
5722
 
                                }
5723
 
                        }
5724
 
                        else if (delim = strchr(auth, ','), delim)
5725
 
                                *delim = '\0';
5726
 
                        else if (delim = strchr(auth, '}'), delim)
5727
 
                                *delim = '\0';
5728
 
                        if (grpauth) /* handle group privilege */
5729
 
                        {
5730
 
                                QResultClass    *gres;
5731
 
                                int             i;
5732
 
                                char    *grolist, *uid, *delm;
5733
 
 
5734
 
                                snprintf(proc_query, sizeof(proc_query) - 1, "select grolist from pg_group where groname = '%s'", user);
5735
 
                                if (gres = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(gres))
5736
 
                                {
5737
 
                                        grolist = QR_get_value_backend_text(gres, 0, 0);
5738
 
                                        if (grolist && grolist[0] == '{')
5739
 
                                        {
5740
 
                                                for (uid = grolist + 1; *uid;)
5741
 
                                                {
5742
 
                                                        if (delm = strchr(uid, ','), delm)
5743
 
                                                                *delm = '\0';
5744
 
                                                        else if (delm = strchr(uid, '}'), delm)
5745
 
                                                                *delm = '\0';
5746
 
mylog("guid=%s\n", uid);
5747
 
                                                        for (i = 0; i < usercount; i++)
5748
 
                                                        {
5749
 
                                                                if (strcmp(QR_get_value_backend_text(allures, i, 1), uid) == 0)
5750
 
                                                                        useracl_upd(useracl, allures, QR_get_value_backend_text(allures, i, 0), auth);
5751
 
                                                        }
5752
 
                                                        uid = delm + 1;
5753
 
                                                }
5754
 
                                        }
5755
 
                                }
5756
 
                                QR_Destructor(gres);
5757
 
                        }
5758
 
                        else
5759
 
                                useracl_upd(useracl, allures, user, auth);
5760
 
                        if (!delim)
5761
 
                                break;
5762
 
                        user = delim + 1;
5763
 
                }
5764
 
                reln = QR_get_value_backend_text(wres, i, 0);
5765
 
                owner = QR_get_value_backend_text(wres, i, 1);
5766
 
                if (conn->schema_support)
5767
 
                        schnm = QR_get_value_backend_text(wres, i, 3);
5768
 
                /* The owner has all privileges */
5769
 
                useracl_upd(useracl, allures, owner, ALL_PRIVILIGES);
5770
 
                for (j = 0; j < usercount; j++)
5771
 
                {
5772
 
                        user = QR_get_value_backend_text(allures, j, 0);
5773
 
                        su = (strcmp(QR_get_value_backend_text(allures, j, 2), "t") == 0);
5774
 
                        sys = (strcmp(user, owner) == 0);
5775
 
                        /* Super user has all privileges */
5776
 
                        if (su)
5777
 
                                useracl_upd(useracl, allures, user, ALL_PRIVILIGES);
5778
 
                        for (k = 0; k < ACLMAX; k++)
5779
 
                        {
5780
 
                                if (!useracl[j][k])
5781
 
                                        break;
5782
 
                                switch (useracl[j][k])
5783
 
                                {
5784
 
                                        case 'R': /* rule */
5785
 
                                        case 't': /* trigger */
5786
 
                                                continue;
5787
 
                                }
5788
 
                                tuple = QR_AddNew(res);
5789
 
                                set_tuplefield_string(&tuple[0], CurrCat(conn));
5790
 
                                if (conn->schema_support)
5791
 
                                        set_tuplefield_string(&tuple[1], GET_SCHEMA_NAME(schnm));
5792
 
                                else
5793
 
                                        set_tuplefield_string(&tuple[1], NULL_STRING);
5794
 
                                set_tuplefield_string(&tuple[2], reln);
5795
 
                                if (su || sys)
5796
 
                                        set_tuplefield_string(&tuple[3], "_SYSTEM");
5797
 
                                else
5798
 
                                        set_tuplefield_string(&tuple[3], owner);
5799
 
                                mylog("user=%s\n", user);
5800
 
                                set_tuplefield_string(&tuple[4], user);
5801
 
                                switch (useracl[j][k])
5802
 
                                {
5803
 
                                        case 'a':
5804
 
                                                priv = "INSERT";
5805
 
                                                break;
5806
 
                                        case 'r':
5807
 
                                                priv = "SELECT";
5808
 
                                                break;
5809
 
                                        case 'w':
5810
 
                                                priv = "UPDATE";
5811
 
                                                break;
5812
 
                                        case 'd':
5813
 
                                                priv = "DELETE";
5814
 
                                                break;
5815
 
                                        case 'x':
5816
 
                                                priv = "REFERENCES";
5817
 
                                                break;
5818
 
                                        default:
5819
 
                                                priv = NULL_STRING;
5820
 
                                }
5821
 
                                set_tuplefield_string(&tuple[5], priv);
5822
 
                                /* The owner and the super user are grantable */
5823
 
                                if (sys || su)
5824
 
                                        set_tuplefield_string(&tuple[6], "YES");
5825
 
                                else
5826
 
                                        set_tuplefield_string(&tuple[6], "NO");
5827
 
                        }
5828
 
                }
5829
 
        }
5830
 
cleanup:
5831
 
#undef  return
5832
 
        if (escSchemaName)
5833
 
                free(escSchemaName);
5834
 
        if (escTableName)
5835
 
                free(escTableName);
5836
 
        if (useracl)
5837
 
                free(useracl);
5838
 
        if (wres)
5839
 
                QR_Destructor(wres);
5840
 
        if (allures)
5841
 
                QR_Destructor(allures);
5842
 
        if (stmt->internal) 
5843
 
                ret = DiscardStatementSvp(stmt, ret, FALSE);
5844
 
        return ret;
5845
 
}
5846
 
 
5847
 
 
5848
 
static RETCODE          SQL_API
5849
 
PGAPI_ForeignKeys_new(
5850
 
                HSTMT hstmt,
5851
 
                const SQLCHAR FAR * szPkTableQualifier, /* OA X*/
5852
 
                SQLSMALLINT cbPkTableQualifier,
5853
 
                const SQLCHAR FAR * szPkTableOwner, /* OA E*/
5854
 
                SQLSMALLINT cbPkTableOwner,
5855
 
                const SQLCHAR FAR * szPkTableName, /* OA(R) E*/
5856
 
                SQLSMALLINT cbPkTableName,
5857
 
                const SQLCHAR FAR * szFkTableQualifier, /* OA X*/
5858
 
                SQLSMALLINT cbFkTableQualifier,
5859
 
                const SQLCHAR FAR * szFkTableOwner, /* OA E*/
5860
 
                SQLSMALLINT cbFkTableOwner,
5861
 
                const SQLCHAR FAR * szFkTableName, /* OA(R) E*/
5862
 
                SQLSMALLINT cbFkTableName)
5863
 
{
5864
 
        CSTR func = "PGAPI_ForeignKeys";
5865
 
        StatementClass  *stmt = (StatementClass *) hstmt;
5866
 
        QResultClass    *res = NULL;
5867
 
        RETCODE         ret = SQL_ERROR, result;
5868
 
        char            tables_query[INFO_INQUIRY_LEN];
5869
 
        char            *pk_table_needed = NULL, *escTableName = NULL;
5870
 
        char            *fk_table_needed = NULL;
5871
 
        char            schema_needed[SCHEMA_NAME_STORAGE_LEN + 1];
5872
 
        char            catName[SCHEMA_NAME_STORAGE_LEN],
5873
 
                        scmName1[SCHEMA_NAME_STORAGE_LEN],
5874
 
                        scmName2[SCHEMA_NAME_STORAGE_LEN];
5875
 
        const char      *relqual;
5876
 
        ConnectionClass *conn = SC_get_conn(stmt);
5877
 
 
5878
 
        const char *eq_string;
5879
 
 
5880
 
        mylog("%s: entering...stmt=%p\n", func, stmt);
5881
 
 
5882
 
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
5883
 
                return result;
5884
 
 
5885
 
        schema_needed[0] = '\0';
5886
 
#define return  DONT_CALL_RETURN_FROM_HERE???
5887
 
 
5888
 
        pk_table_needed = make_string(szPkTableName, cbPkTableName, NULL, 0);
5889
 
        fk_table_needed = make_string(szFkTableName, cbFkTableName, NULL, 0);
5890
 
 
5891
 
        eq_string = gen_opestr(eqop, conn);
5892
 
 
5893
 
        /*
5894
 
         * Case #2 -- Get the foreign keys in the specified table (fktab) that
5895
 
         * refer to the primary keys of other table(s).
5896
 
         */
5897
 
        if (NULL != fk_table_needed)
5898
 
        {
5899
 
                mylog("%s: entering Foreign Key Case #2", func);
5900
 
                escTableName = simpleCatalogEscape(fk_table_needed, SQL_NTS, NULL, conn);
5901
 
                schema_strcat(schema_needed, "%.*s", szFkTableOwner, cbFkTableOwner, szFkTableName, cbFkTableName, conn);
5902
 
                relqual = "\n   and  conrelid = c.oid";
5903
 
        }
5904
 
        /*
5905
 
         * Case #1 -- Get the foreign keys in other tables that refer to the
5906
 
         * primary key in the specified table (pktab).  i.e., Who points to
5907
 
         * me?
5908
 
         */
5909
 
        else if (NULL != pk_table_needed)
5910
 
        {
5911
 
                escTableName = simpleCatalogEscape(pk_table_needed, SQL_NTS, NULL, conn);
5912
 
                schema_strcat(schema_needed, "%.*s", szPkTableOwner, cbPkTableOwner, szPkTableName, cbPkTableName, conn);
5913
 
                relqual = "\n   and  confrelid = c.oid";
5914
 
        }
5915
 
        else
5916
 
        {
5917
 
                SC_set_error(stmt, STMT_INTERNAL_ERROR, "No tables specified to PGAPI_ForeignKeys.", func);
5918
 
                goto cleanup;
5919
 
        }
5920
 
 
5921
 
        if (conn->schema_support)
5922
 
        {
5923
 
                char    *escSchemaName;
5924
 
 
5925
 
                if (NULL != CurrCat(conn))
5926
 
                        snprintf(catName, sizeof(catName), "'%s'::name", CurrCat(conn));
5927
 
                else
5928
 
                        strcpy(catName, "NULL::name");
5929
 
                strcpy(scmName1, "n2.nspname");
5930
 
                strcpy(scmName2, "n1.nspname");
5931
 
                escSchemaName = simpleCatalogEscape(schema_needed, SQL_NTS, NULL, conn);
5932
 
 
5933
 
                snprintf(tables_query, sizeof(tables_query),
5934
 
                "select"
5935
 
                "       %s as PKTABLE_CAT"
5936
 
                ",\n    %s as PKTABLE_SCHEM"
5937
 
                ",\n    c2.relname as PKTABLE_NAME"
5938
 
                ",\n    a2.attname as PKCOLUMN_NAME"
5939
 
                ",\n    %s as FKTABLE_CAT"
5940
 
                ",\n    %s as FKTABLE_SCHEM"
5941
 
                ",\n    c1.relname as FKTABLE_NAME"
5942
 
                ",\n    a1.attname as FKCOLUMN_NAME"
5943
 
                ",\n    i::int2 as KEY_SEQ"
5944
 
                ",\n    case ref.confupdtype"
5945
 
                "\n             when 'c' then %d::int2"
5946
 
                "\n             when 'n' then %d::int2"
5947
 
                "\n             when 'd' then %d::int2"
5948
 
                "\n             when 'r' then %d::int2"
5949
 
                "\n             else %d::int2"
5950
 
                "\n     end as UPDATE_RULE"
5951
 
                ",\n    case ref.confdeltype"
5952
 
                "\n             when 'c' then %d::int2"
5953
 
                "\n             when 'n' then %d::int2"
5954
 
                "\n             when 'd' then %d::int2"
5955
 
                "\n             when 'r' then %d::int2"
5956
 
                "\n             else %d::int2"
5957
 
                "\n     end as DELETE_RULE"
5958
 
                ",\n    ref.conname as FK_NAME"
5959
 
                ",\n    cn.conname as PK_NAME"
5960
 
#if (ODBCVER >= 0x0300)
5961
 
                ",\n    case"
5962
 
                "\n             when ref.condeferrable then"
5963
 
                "\n                     case"
5964
 
                "\n                     when ref.condeferred then %d::int2"
5965
 
                "\n                     else %d::int2"
5966
 
                "\n                     end"
5967
 
                "\n             else %d::int2"
5968
 
                "\n     end as DEFERRABLITY"
5969
 
#endif /* ODBCVER */
5970
 
                "\n from"
5971
 
                "\n ((((((("
5972
 
                " (select cn.oid, conrelid, conkey, confrelid, confkey"
5973
 
                ",\n     generate_series(array_lower(conkey, 1), array_upper(conkey, 1)) as i"
5974
 
                ",\n     confupdtype, confdeltype, conname"
5975
 
                ",\n     condeferrable, condeferred"
5976
 
                "\n  from pg_catalog.pg_constraint cn"
5977
 
                ",\n    pg_catalog.pg_class c"
5978
 
                ",\n    pg_catalog.pg_namespace n"
5979
 
                "\n  where contype = 'f' %s"
5980
 
                "\n   and  relname %s'%s'"
5981
 
                "\n   and  n.oid = c.relnamespace"
5982
 
                "\n   and  n.nspname %s'%s'"
5983
 
                "\n ) ref"
5984
 
                "\n inner join pg_catalog.pg_class c1"
5985
 
                "\n  on c1.oid = ref.conrelid)"
5986
 
                "\n inner join pg_catalog.pg_namespace n1"
5987
 
                "\n  on  n1.oid = c1.relnamespace)"
5988
 
                "\n inner join pg_catalog.pg_attribute a1"
5989
 
                "\n  on  a1.attrelid = c1.oid"
5990
 
                "\n  and  a1.attnum = conkey[i])"
5991
 
                "\n inner join pg_catalog.pg_class c2"
5992
 
                "\n  on  c2.oid = ref.confrelid)"
5993
 
                "\n inner join pg_catalog.pg_namespace n2"
5994
 
                "\n  on  n2.oid = c2.relnamespace)"
5995
 
                "\n inner join pg_catalog.pg_attribute a2"
5996
 
                "\n  on  a2.attrelid = c2.oid"
5997
 
                "\n  and  a2.attnum = confkey[i])"
5998
 
                "\n left outer join pg_catalog.pg_constraint cn"
5999
 
                "\n  on cn.conrelid = ref.confrelid"
6000
 
                "\n  and cn.contype = 'p')"
6001
 
                , catName
6002
 
                , scmName1
6003
 
                , catName
6004
 
                , scmName2
6005
 
                , SQL_CASCADE
6006
 
                , SQL_SET_NULL
6007
 
                , SQL_SET_DEFAULT
6008
 
                , SQL_RESTRICT
6009
 
                , SQL_NO_ACTION
6010
 
                , SQL_CASCADE
6011
 
                , SQL_SET_NULL
6012
 
                , SQL_SET_DEFAULT
6013
 
                , SQL_RESTRICT
6014
 
                , SQL_NO_ACTION
6015
 
#if (ODBCVER >= 0x0300)
6016
 
                , SQL_INITIALLY_DEFERRED
6017
 
                , SQL_INITIALLY_IMMEDIATE
6018
 
                , SQL_NOT_DEFERRABLE
6019
 
#endif /* ODBCVER */
6020
 
                , relqual
6021
 
                , eq_string, escTableName
6022
 
                , eq_string, escSchemaName);
6023
 
 
6024
 
                free(escSchemaName);
6025
 
                if (NULL != pk_table_needed &&
6026
 
                    NULL != fk_table_needed)
6027
 
                {
6028
 
                        free(escTableName);
6029
 
                        escTableName = simpleCatalogEscape(pk_table_needed, SQL_NTS, NULL, conn);
6030
 
                        snprintf_add(tables_query, sizeof(tables_query),
6031
 
                                        "\n where c2.relname %s'%s'",
6032
 
                                        eq_string, escTableName);
6033
 
                }
6034
 
                strcat(tables_query, "\n  order by ref.oid, ref.i");
6035
 
        }
6036
 
        else
6037
 
        {
6038
 
                strcpy(catName, "NULL::name");
6039
 
                strcpy(scmName1, "NULL::name");
6040
 
                strcpy(scmName2, "NULL::name");
6041
 
 
6042
 
                snprintf(tables_query, sizeof(tables_query),
6043
 
                "select %s as PKTABLE_CAT"
6044
 
                ",\n    %s as PKTABLE_SCHEM"
6045
 
                ",\n    c2.relname as PKTABLE_NAME"
6046
 
                ",\n    a2.attname as PKCOLUMN_NAME"
6047
 
                ",\n    %s as FKTABLE_CAT"
6048
 
                ",\n    %s as FKTABLE_SCHEM"
6049
 
                ",\n    c1.relname as FKTABLE_NAME"
6050
 
                ",\n    a1.attname as FKCOLUMN_NAME"
6051
 
                ",\n    i::int2 as KEY_SEQ"
6052
 
                ",\n    case confupdtype"
6053
 
                "\n             when 'c' then %d::int2"
6054
 
                "\n             when 'n' then %d::int2"
6055
 
                "\n             when 'd' then %d::int2"
6056
 
                "\n             when 'r' then %d::int2"
6057
 
                "\n             else %d::int2"
6058
 
                "\n     end as UPDATE_RULE"
6059
 
                ",\n    case confdeltype"
6060
 
                "\n             when 'c' then %d::int2"
6061
 
                "\n             when 'n' then %d::int2"
6062
 
                "\n             when 'd' then %d::int2"
6063
 
                "\n             when 'r' then %d::int2"
6064
 
                "\n             else %d::int2"
6065
 
                "\n     end as DELETE_RULE"
6066
 
                ",\n    conname as FK_NAME"
6067
 
                ",\n    NULL::name as PK_NAME"
6068
 
#if (ODBCVER >= 0x0300)
6069
 
                ",\n    case"
6070
 
                "\n             when condeferrable then"
6071
 
                "\n                     case"
6072
 
                "\n                     when condeferred then %d::int2"
6073
 
                "\n                     else %d::int2"
6074
 
                "\n                     end"
6075
 
                "\n             else %d::int2"
6076
 
                "\n     end as DEFERRABLITY"
6077
 
#endif /* ODBCVER */
6078
 
                "\n from"
6079
 
                "\n (select conrelid, conkey, confrelid, confkey"
6080
 
                ",\n     generate_series(array_lower(conkey, 1), array_upper(conkey, 1)) as i"
6081
 
                ",\n     confupdtype, confdeltype, conname"
6082
 
                ",\n     condeferrable, condeferred"
6083
 
                "\n  from pg_catalog.pg_constraint cn"
6084
 
                ",\n    pg_catalog.pg_class c"
6085
 
                "\n  where contype = 'f' %s"
6086
 
                "\n   and  relname %s'%s'"
6087
 
                "\n ) ref"
6088
 
                ",\n pg_catalog.pg_class c1"
6089
 
                ",\n pg_catalog.pg_attribute a1"
6090
 
                ",\n pg_catalog.pg_class c2"
6091
 
                ",\n pg_catalog.pg_attribute a2"
6092
 
                "\n where c1.oid = ref.conrelid"
6093
 
                "\n  and  c2.oid = ref.confrelid"
6094
 
                "\n  and  a1.attrelid = c1.oid"
6095
 
                "\n  and  a1.attnum = conkey[i]"
6096
 
                "\n  and  a2.attrelid = c2.oid"
6097
 
                "\n  and  a2.attnum = confkey[i]"
6098
 
                "\n  order by ref.oid, ref.i"
6099
 
                , catName
6100
 
                , scmName1
6101
 
                , catName
6102
 
                , scmName2
6103
 
                , SQL_CASCADE
6104
 
                , SQL_SET_NULL
6105
 
                , SQL_SET_DEFAULT
6106
 
                , SQL_RESTRICT
6107
 
                , SQL_NO_ACTION
6108
 
                , SQL_CASCADE
6109
 
                , SQL_SET_NULL
6110
 
                , SQL_SET_DEFAULT
6111
 
                , SQL_RESTRICT
6112
 
                , SQL_NO_ACTION
6113
 
#if (ODBCVER >= 0x0300)
6114
 
                , SQL_INITIALLY_DEFERRED
6115
 
                , SQL_INITIALLY_IMMEDIATE
6116
 
                , SQL_NOT_DEFERRABLE
6117
 
#endif /* ODBCVER */
6118
 
                , relqual, eq_string, escTableName);
6119
 
        }
6120
 
 
6121
 
        if (res = CC_send_query(conn, tables_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(res))
6122
 
        {
6123
 
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_ForeignKeys query error", func);
6124
 
                QR_Destructor(res);
6125
 
                goto cleanup;
6126
 
        }
6127
 
        SC_set_Result(stmt, res);
6128
 
        ret = SQL_SUCCESS;
6129
 
 
6130
 
cleanup:
6131
 
#undef  return
6132
 
 
6133
 
        /*
6134
 
         * also, things need to think that this statement is finished so the
6135
 
         * results can be retrieved.
6136
 
         */
6137
 
        if (SQL_SUCCEEDED(ret))
6138
 
        {
6139
 
                stmt->status = STMT_FINISHED;
6140
 
                extend_column_bindings(SC_get_ARDF(stmt), QR_NumResultCols(res));
6141
 
        }
6142
 
        if (pk_table_needed)
6143
 
                free(pk_table_needed);
6144
 
        if (escTableName)
6145
 
                free(escTableName);
6146
 
        if (fk_table_needed)
6147
 
                free(fk_table_needed);
6148
 
        /* set up the current tuple pointer for SQLFetch */
6149
 
        stmt->currTuple = -1;
6150
 
        SC_set_rowset_start(stmt, -1, FALSE);
6151
 
        SC_set_current_col(stmt, -1);
6152
 
 
6153
 
        if (stmt->internal)
6154
 
                ret = DiscardStatementSvp(stmt, ret, FALSE);
6155
 
        mylog("%s(): EXIT, stmt=%p, ret=%d\n", func, stmt, ret);
6156
 
        return ret;
6157
 
}
 
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, SQLProcedures,
 
13
 *                                      SQLTablePrivileges, SQLColumnPrivileges(NI)
 
14
 *
 
15
 * Comments:            See "readme.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
#include "catfunc.h"
 
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
#define NULL_IF_NULL(a) ((a) ? ((const char *) a) : "(NULL)")
 
50
 
 
51
/* extern GLOBAL_VALUES globals; */
 
52
 
 
53
CSTR    pubstr = "public";
 
54
CSTR    likeop = "like";
 
55
CSTR    eqop = "=";
 
56
 
 
57
RETCODE         SQL_API
 
58
PGAPI_GetInfo(
 
59
                          HDBC hdbc,
 
60
                          SQLUSMALLINT fInfoType,
 
61
                          PTR rgbInfoValue,
 
62
                          SQLSMALLINT cbInfoValueMax,
 
63
                          SQLSMALLINT FAR * pcbInfoValue)
 
64
{
 
65
        CSTR func = "PGAPI_GetInfo";
 
66
        ConnectionClass *conn = (ConnectionClass *) hdbc;
 
67
        ConnInfo   *ci;
 
68
        const char   *p = NULL;
 
69
        char            tmp[MAX_INFO_STRING];
 
70
        SQLULEN                 len = 0,
 
71
                                value = 0;
 
72
        RETCODE         result = SQL_ERROR;
 
73
        char            odbcver[16];
 
74
        int             i_odbcver;
 
75
 
 
76
        mylog("%s: entering...fInfoType=%d\n", func, fInfoType);
 
77
 
 
78
        if (!conn)
 
79
        {
 
80
                CC_log_error(func, NULL_STRING, NULL);
 
81
                return SQL_INVALID_HANDLE;
 
82
        }
 
83
 
 
84
        ci = &(conn->connInfo);
 
85
 
 
86
        switch (fInfoType)
 
87
        {
 
88
                case SQL_ACCESSIBLE_PROCEDURES: /* ODBC 1.0 */
 
89
                        p = "N";
 
90
                        break;
 
91
 
 
92
                case SQL_ACCESSIBLE_TABLES:             /* ODBC 1.0 */
 
93
                        p = CC_accessible_only(conn) ? "Y" : "N";
 
94
                        break;
 
95
 
 
96
                case SQL_ACTIVE_CONNECTIONS:    /* ODBC 1.0 */
 
97
                        len = 2;
 
98
                        value = 0;
 
99
                        break;
 
100
 
 
101
                case SQL_ACTIVE_STATEMENTS:             /* ODBC 1.0 */
 
102
                        len = 2;
 
103
                        value = 0;
 
104
                        break;
 
105
 
 
106
                case SQL_ALTER_TABLE:   /* ODBC 2.0 */
 
107
                        len = 4;
 
108
                        value = SQL_AT_ADD_COLUMN;
 
109
                        if (PG_VERSION_GE(conn, 7.3))
 
110
                                value |= SQL_AT_DROP_COLUMN;
 
111
#if (ODBCVER >= 0x0300)
 
112
                        value |= SQL_AT_ADD_COLUMN_SINGLE;
 
113
                        if (PG_VERSION_GE(conn, 7.1))
 
114
                                value |= SQL_AT_ADD_CONSTRAINT
 
115
                                        | SQL_AT_ADD_TABLE_CONSTRAINT
 
116
                                        | SQL_AT_CONSTRAINT_INITIALLY_DEFERRED
 
117
                                        | SQL_AT_CONSTRAINT_INITIALLY_IMMEDIATE
 
118
                                        | SQL_AT_CONSTRAINT_DEFERRABLE;
 
119
                        if (PG_VERSION_GE(conn, 7.3))
 
120
                                value |= SQL_AT_DROP_TABLE_CONSTRAINT_RESTRICT
 
121
                                        | SQL_AT_DROP_TABLE_CONSTRAINT_CASCADE
 
122
                                        | SQL_AT_DROP_COLUMN_RESTRICT
 
123
                                        | SQL_AT_DROP_COLUMN_CASCADE;
 
124
#endif /* ODBCVER */
 
125
                        break;
 
126
 
 
127
                case SQL_BOOKMARK_PERSISTENCE:  /* ODBC 2.0 */
 
128
                        /* very simple bookmark support */
 
129
                        len = 4;
 
130
                        value = ci->drivers.use_declarefetch && PG_VERSION_LT(conn, 7.4) ? 0 : (SQL_BP_SCROLL | SQL_BP_DELETE | SQL_BP_UPDATE | SQL_BP_TRANSACTION);
 
131
                        break;
 
132
 
 
133
                case SQL_COLUMN_ALIAS:  /* ODBC 2.0 */
 
134
                        p = "Y";
 
135
                        break;
 
136
 
 
137
                case SQL_CONCAT_NULL_BEHAVIOR:  /* ODBC 1.0 */
 
138
                        len = 2;
 
139
                        value = SQL_CB_NON_NULL;
 
140
                        break;
 
141
 
 
142
                case SQL_CONVERT_INTEGER:
 
143
                case SQL_CONVERT_SMALLINT:
 
144
                case SQL_CONVERT_TINYINT:
 
145
                case SQL_CONVERT_BIT:
 
146
                case SQL_CONVERT_VARCHAR:               /* ODBC 1.0 */
 
147
                        len = sizeof(SQLUINTEGER);
 
148
                        value = SQL_CVT_BIT | SQL_CVT_INTEGER;
 
149
mylog("SQL_CONVERT_ mask=" FORMAT_ULEN "\n", value);
 
150
                        break;
 
151
                case SQL_CONVERT_BIGINT:
 
152
                case SQL_CONVERT_DECIMAL:
 
153
                case SQL_CONVERT_DOUBLE:
 
154
                case SQL_CONVERT_FLOAT:
 
155
                case SQL_CONVERT_NUMERIC:
 
156
                case SQL_CONVERT_REAL:
 
157
                case SQL_CONVERT_DATE:
 
158
                case SQL_CONVERT_TIME:
 
159
                case SQL_CONVERT_TIMESTAMP:
 
160
                case SQL_CONVERT_BINARY:
 
161
                case SQL_CONVERT_LONGVARBINARY:
 
162
                case SQL_CONVERT_VARBINARY:             /* ODBC 1.0 */
 
163
                case SQL_CONVERT_CHAR:
 
164
                case SQL_CONVERT_LONGVARCHAR:
 
165
#if defined(UNICODE_SUPPORT) && (ODBCVER >= 0x0300)
 
166
                case SQL_CONVERT_WCHAR:
 
167
                case SQL_CONVERT_WLONGVARCHAR:
 
168
                case SQL_CONVERT_WVARCHAR:
 
169
#endif /* UNICODE_SUPPORT */
 
170
                        len = sizeof(SQLUINTEGER);
 
171
                        value = 0;      /* CONVERT is unavailable */
 
172
                        break;
 
173
 
 
174
                case SQL_CONVERT_FUNCTIONS:             /* ODBC 1.0 */
 
175
                        len = sizeof(SQLUINTEGER);
 
176
                        value = SQL_FN_CVT_CONVERT;
 
177
mylog("CONVERT_FUNCTIONS=" FORMAT_ULEN "\n", value);
 
178
                        break;
 
179
 
 
180
                case SQL_CORRELATION_NAME:              /* ODBC 1.0 */
 
181
 
 
182
                        /*
 
183
                         * Saying no correlation name makes Query not work right.
 
184
                         * value = SQL_CN_NONE;
 
185
                         */
 
186
                        len = 2;
 
187
                        value = SQL_CN_ANY;
 
188
                        break;
 
189
 
 
190
                case SQL_CURSOR_COMMIT_BEHAVIOR:                /* ODBC 1.0 */
 
191
                        len = 2;
 
192
                        value = SQL_CB_CLOSE;
 
193
                        if (!ci->drivers.use_declarefetch || PG_VERSION_GE(conn, 7.4))
 
194
                                value = SQL_CB_PRESERVE;
 
195
                        break;
 
196
 
 
197
                case SQL_CURSOR_ROLLBACK_BEHAVIOR:              /* ODBC 1.0 */
 
198
                        len = 2;
 
199
                        value = SQL_CB_CLOSE;
 
200
                        if (!ci->drivers.use_declarefetch)
 
201
                                value = SQL_CB_PRESERVE;
 
202
                        break;
 
203
 
 
204
                case SQL_DATA_SOURCE_NAME:              /* ODBC 1.0 */
 
205
                        p = CC_get_DSN(conn);
 
206
                        break;
 
207
 
 
208
                case SQL_DATA_SOURCE_READ_ONLY: /* ODBC 1.0 */
 
209
                        p = CC_is_onlyread(conn) ? "Y" : "N";
 
210
                        break;
 
211
 
 
212
                case SQL_DATABASE_NAME: /* Support for old ODBC 1.0 Apps */
 
213
 
 
214
                        /*
 
215
                         * Returning the database name causes problems in MS Query. It
 
216
                         * generates query like: "SELECT DISTINCT a FROM byronnbad3
 
217
                         * bad3"
 
218
                         *
 
219
                         * p = CC_get_database(conn);
 
220
                         */
 
221
                        p = CurrCatString(conn);
 
222
                        break;
 
223
 
 
224
                case SQL_DBMS_NAME:             /* ODBC 1.0 */
 
225
                        if (CC_fake_mss(conn))
 
226
                                p = "Microsoft SQL Server";
 
227
                        else
 
228
                                p = "PostgreSQL";
 
229
                        break;
 
230
 
 
231
                case SQL_DBMS_VER:              /* ODBC 1.0 */
 
232
 
 
233
                        /*
 
234
                         * The ODBC spec wants ##.##.#### ...whatever... so prepend
 
235
                         * the driver
 
236
                         */
 
237
                        /* version number to the dbms version string */
 
238
                        /*
 
239
                        snprintf(tmp, sizeof(tmp) - 1, "%s %s", POSTGRESDRIVERVERSION, conn->pg_version);
 
240
                        tmp[sizeof(tmp) - 1] = '\0'; */
 
241
                        if (CC_fake_mss(conn))
 
242
                                p = "09.00.1399";
 
243
                        else
 
244
                        {
 
245
                                strncpy_null(tmp, conn->pg_version, sizeof(tmp));
 
246
                                p = tmp;
 
247
                        }
 
248
                        break;
 
249
 
 
250
                case SQL_DEFAULT_TXN_ISOLATION: /* ODBC 1.0 */
 
251
                        len = 4;
 
252
                        if (PG_VERSION_LT(conn, 6.5))
 
253
                                value = SQL_TXN_SERIALIZABLE;
 
254
                        else
 
255
                                value = SQL_TXN_READ_COMMITTED;
 
256
                        break;
 
257
 
 
258
                case SQL_DRIVER_NAME:   /* ODBC 1.0 */
 
259
                        p = DRIVER_FILE_NAME;
 
260
                        break;
 
261
 
 
262
                case SQL_DRIVER_ODBC_VER:
 
263
                        i_odbcver = conn->driver_version;
 
264
                        snprintf(odbcver, sizeof(odbcver), "%02x.%02x", i_odbcver / 256, i_odbcver % 256);
 
265
                        /* p = DRIVER_ODBC_VER; */
 
266
                        p = odbcver;
 
267
                        break;
 
268
 
 
269
                case SQL_DRIVER_VER:    /* ODBC 1.0 */
 
270
                        p = POSTGRESDRIVERVERSION;
 
271
                        break;
 
272
 
 
273
                case SQL_EXPRESSIONS_IN_ORDERBY:                /* ODBC 1.0 */
 
274
                        p = PG_VERSION_GE(conn, 6.5) ? "Y" : "N";
 
275
                        break;
 
276
 
 
277
                case SQL_FETCH_DIRECTION:               /* ODBC 1.0 */
 
278
                        len = 4;
 
279
                        value = (SQL_FD_FETCH_NEXT |
 
280
                                SQL_FD_FETCH_NEXT | 
 
281
                                SQL_FD_FETCH_FIRST |
 
282
                                SQL_FD_FETCH_LAST |
 
283
                                SQL_FD_FETCH_PRIOR |
 
284
                                SQL_FD_FETCH_ABSOLUTE |
 
285
                                SQL_FD_FETCH_RELATIVE |
 
286
                                SQL_FD_FETCH_BOOKMARK);
 
287
                        break;
 
288
 
 
289
                case SQL_FILE_USAGE:    /* ODBC 2.0 */
 
290
                        len = 2;
 
291
                        value = SQL_FILE_NOT_SUPPORTED;
 
292
                        break;
 
293
 
 
294
                case SQL_GETDATA_EXTENSIONS:    /* ODBC 2.0 */
 
295
                        len = 4;
 
296
                        value = (SQL_GD_ANY_COLUMN | SQL_GD_ANY_ORDER | SQL_GD_BOUND | SQL_GD_BLOCK);
 
297
                        break;
 
298
 
 
299
                case SQL_GROUP_BY:              /* ODBC 2.0 */
 
300
                        len = 2;
 
301
                        value = SQL_GB_GROUP_BY_EQUALS_SELECT;
 
302
                        break;
 
303
 
 
304
                case SQL_IDENTIFIER_CASE:               /* ODBC 1.0 */
 
305
 
 
306
                        /*
 
307
                         * are identifiers case-sensitive (yes, but only when quoted.
 
308
                         * If not quoted, they default to lowercase)
 
309
                         */
 
310
                        len = 2;
 
311
                        value = SQL_IC_LOWER;
 
312
                        break;
 
313
 
 
314
                case SQL_IDENTIFIER_QUOTE_CHAR: /* ODBC 1.0 */
 
315
                        /* the character used to quote "identifiers" */
 
316
                        p = PG_VERSION_LE(conn, 6.2) ? " " : "\"";
 
317
                        break;
 
318
 
 
319
                case SQL_KEYWORDS:              /* ODBC 2.0 */
 
320
                        p = NULL_STRING;
 
321
                        break;
 
322
 
 
323
                case SQL_LIKE_ESCAPE_CLAUSE:    /* ODBC 2.0 */
 
324
 
 
325
                        /*
 
326
                         * is there a character that escapes '%' and '_' in a LIKE
 
327
                         * clause? not as far as I can tell
 
328
                         */
 
329
                        p = "N";
 
330
                        break;
 
331
 
 
332
                case SQL_LOCK_TYPES:    /* ODBC 2.0 */
 
333
                        len = 4;
 
334
                        value = ci->drivers.lie ? (SQL_LCK_NO_CHANGE | SQL_LCK_EXCLUSIVE | SQL_LCK_UNLOCK) : SQL_LCK_NO_CHANGE;
 
335
                        break;
 
336
 
 
337
                case SQL_MAX_BINARY_LITERAL_LEN:                /* ODBC 2.0 */
 
338
                        len = 4;
 
339
                        value = 0;
 
340
                        break;
 
341
 
 
342
                case SQL_MAX_CHAR_LITERAL_LEN:  /* ODBC 2.0 */
 
343
                        len = 4;
 
344
                        value = 0;
 
345
                        break;
 
346
 
 
347
                case SQL_MAX_COLUMN_NAME_LEN:   /* ODBC 1.0 */
 
348
                        len = 2;
 
349
                        if (PG_VERSION_GT(conn, 7.4))
 
350
                                value = CC_get_max_idlen(conn);
 
351
#ifdef  MAX_COLUMN_LEN
 
352
                        else
 
353
                                value = MAX_COLUMN_LEN;
 
354
#endif /* MAX_COLUMN_LEN */
 
355
                        if (0 == value)
 
356
                        {
 
357
                                if (PG_VERSION_GE(conn, 7.3))
 
358
                                        value = NAMEDATALEN_V73;
 
359
                                else
 
360
                                        value = NAMEDATALEN_V72;
 
361
                        }
 
362
                        break;
 
363
 
 
364
                case SQL_MAX_COLUMNS_IN_GROUP_BY:               /* ODBC 2.0 */
 
365
                        len = 2;
 
366
                        value = 0;
 
367
                        break;
 
368
 
 
369
                case SQL_MAX_COLUMNS_IN_INDEX:  /* ODBC 2.0 */
 
370
                        len = 2;
 
371
                        value = 0;
 
372
                        break;
 
373
 
 
374
                case SQL_MAX_COLUMNS_IN_ORDER_BY:               /* ODBC 2.0 */
 
375
                        len = 2;
 
376
                        value = 0;
 
377
                        break;
 
378
 
 
379
                case SQL_MAX_COLUMNS_IN_SELECT: /* ODBC 2.0 */
 
380
                        len = 2;
 
381
                        value = 0;
 
382
                        break;
 
383
 
 
384
                case SQL_MAX_COLUMNS_IN_TABLE:  /* ODBC 2.0 */
 
385
                        len = 2;
 
386
                        value = 0;
 
387
                        break;
 
388
 
 
389
                case SQL_MAX_CURSOR_NAME_LEN:   /* ODBC 1.0 */
 
390
                        len = 2;
 
391
                        value = MAX_CURSOR_LEN;
 
392
                        break;
 
393
 
 
394
                case SQL_MAX_INDEX_SIZE:                /* ODBC 2.0 */
 
395
                        len = 4;
 
396
                        value = 0;
 
397
                        break;
 
398
 
 
399
                case SQL_MAX_OWNER_NAME_LEN:    /* ODBC 1.0 */
 
400
                        len = 2;
 
401
                        value = 0;
 
402
                        if (PG_VERSION_GT(conn, 7.4))
 
403
                                value = CC_get_max_idlen(conn);
 
404
#ifdef  MAX_SCHEMA_LEN
 
405
                        else if (conn->schema_support)
 
406
                                value = MAX_SCHEMA_LEN;
 
407
#endif /* MAX_SCHEMA_LEN */
 
408
                        if (0 == value)
 
409
                        {
 
410
                                if (PG_VERSION_GE(conn, 7.3))
 
411
                                        value = NAMEDATALEN_V73;
 
412
                        }
 
413
                        break;
 
414
 
 
415
                case SQL_MAX_PROCEDURE_NAME_LEN:                /* ODBC 1.0 */
 
416
                        len = 2;
 
417
                        value = 0;
 
418
                        break;
 
419
 
 
420
                case SQL_MAX_QUALIFIER_NAME_LEN:                /* ODBC 1.0 */
 
421
                        len = 2;
 
422
                        value = 0;
 
423
                        break;
 
424
 
 
425
                case SQL_MAX_ROW_SIZE:  /* ODBC 2.0 */
 
426
                        len = 4;
 
427
                        if (PG_VERSION_GE(conn, 7.1))
 
428
                        {
 
429
                                /* Large Rowa in 7.1+ */
 
430
                                value = MAX_ROW_SIZE;
 
431
                        }
 
432
                        else
 
433
                        {
 
434
                                /* Without the Toaster we're limited to the blocksize */
 
435
                                value = BLCKSZ;
 
436
                        }
 
437
                        break;
 
438
 
 
439
                case SQL_MAX_ROW_SIZE_INCLUDES_LONG:    /* ODBC 2.0 */
 
440
 
 
441
                        /*
 
442
                         * does the preceding value include LONGVARCHAR and
 
443
                         * LONGVARBINARY fields?   Well, it does include longvarchar,
 
444
                         * but not longvarbinary.
 
445
                         */
 
446
                        p = "Y";
 
447
                        break;
 
448
 
 
449
                case SQL_MAX_STATEMENT_LEN:             /* ODBC 2.0 */
 
450
                        /* maybe this should be 0? */
 
451
                        len = 4;
 
452
                        value = CC_get_max_query_len(conn);
 
453
                        break;
 
454
 
 
455
                case SQL_MAX_TABLE_NAME_LEN:    /* ODBC 1.0 */
 
456
                        len = 2;
 
457
                        if (PG_VERSION_GT(conn, 7.4))
 
458
                                value = CC_get_max_idlen(conn);
 
459
#ifdef  MAX_TABLE_LEN
 
460
                        else
 
461
                                value = MAX_TABLE_LEN;
 
462
#endif /* MAX_TABLE_LEN */
 
463
                        if (0 == value)
 
464
                        {
 
465
                                if (PG_VERSION_GE(conn, 7.3))
 
466
                                        value = NAMEDATALEN_V73;
 
467
                                else
 
468
                                        value = NAMEDATALEN_V72;
 
469
                        }
 
470
                        break;
 
471
 
 
472
                case SQL_MAX_TABLES_IN_SELECT:  /* ODBC 2.0 */
 
473
                        len = 2;
 
474
                        value = 0;
 
475
                        break;
 
476
 
 
477
                case SQL_MAX_USER_NAME_LEN:
 
478
                        len = 2;
 
479
                        value = 0;
 
480
                        break;
 
481
 
 
482
                case SQL_MULT_RESULT_SETS:              /* ODBC 1.0 */
 
483
                        /* Don't support multiple result sets but say yes anyway? */
 
484
                        p = "Y";
 
485
                        break;
 
486
 
 
487
                case SQL_MULTIPLE_ACTIVE_TXN:   /* ODBC 1.0 */
 
488
                        p = "Y";
 
489
                        break;
 
490
 
 
491
                case SQL_NEED_LONG_DATA_LEN:    /* ODBC 2.0 */
 
492
 
 
493
                        /*
 
494
                         * Don't need the length, SQLPutData can handle any size and
 
495
                         * multiple calls
 
496
                         */
 
497
                        p = "N";
 
498
                        break;
 
499
 
 
500
                case SQL_NON_NULLABLE_COLUMNS:  /* ODBC 1.0 */
 
501
                        len = 2;
 
502
                        value = SQL_NNC_NON_NULL;
 
503
                        break;
 
504
 
 
505
                case SQL_NULL_COLLATION:                /* ODBC 2.0 */
 
506
                        /* where are nulls sorted? */
 
507
                        len = 2;
 
508
                        if (PG_VERSION_GE(conn, 7.2))
 
509
                                value = SQL_NC_HIGH;
 
510
                        else
 
511
                                value = SQL_NC_END;
 
512
                        break;
 
513
 
 
514
                case SQL_NUMERIC_FUNCTIONS:             /* ODBC 1.0 */
 
515
                        len = 4;
 
516
                        value = 0;
 
517
                        break;
 
518
 
 
519
                case SQL_ODBC_API_CONFORMANCE:  /* ODBC 1.0 */
 
520
                        len = 2;
 
521
                        value = SQL_OAC_LEVEL1;
 
522
                        break;
 
523
 
 
524
                case SQL_ODBC_SAG_CLI_CONFORMANCE:              /* ODBC 1.0 */
 
525
                        len = 2;
 
526
                        value = SQL_OSCC_NOT_COMPLIANT;
 
527
                        break;
 
528
 
 
529
                case SQL_ODBC_SQL_CONFORMANCE:  /* ODBC 1.0 */
 
530
                        len = 2;
 
531
                        value = SQL_OSC_CORE;
 
532
                        break;
 
533
 
 
534
                case SQL_ODBC_SQL_OPT_IEF:              /* ODBC 1.0 */
 
535
                        p = "N";
 
536
                        break;
 
537
 
 
538
                case SQL_OJ_CAPABILITIES:               /* ODBC 2.01 */
 
539
                        len = 4;
 
540
                        if (PG_VERSION_GE(conn, 7.1))
 
541
                        {
 
542
                                /* OJs in 7.1+ */
 
543
                                value = (SQL_OJ_LEFT |
 
544
                                                 SQL_OJ_RIGHT |
 
545
                                                 SQL_OJ_FULL |
 
546
                                                 SQL_OJ_NESTED |
 
547
                                                 SQL_OJ_NOT_ORDERED |
 
548
                                                 SQL_OJ_INNER |
 
549
                                                 SQL_OJ_ALL_COMPARISON_OPS);
 
550
                        }
 
551
                        else
 
552
                                /* OJs not in <7.1 */
 
553
                                value = 0;
 
554
                        break;
 
555
 
 
556
                case SQL_ORDER_BY_COLUMNS_IN_SELECT:    /* ODBC 2.0 */
 
557
                        p = (PG_VERSION_LE(conn, 6.3)) ? "Y" : "N";
 
558
                        break;
 
559
 
 
560
                case SQL_OUTER_JOINS:   /* ODBC 1.0 */
 
561
                        if (PG_VERSION_GE(conn, 7.1))
 
562
                                /* OJs in 7.1+ */
 
563
                                p = "Y";
 
564
                        else
 
565
                                /* OJs not in <7.1 */
 
566
                                p = "N";
 
567
                        break;
 
568
 
 
569
                case SQL_OWNER_TERM:    /* ODBC 1.0 */
 
570
                        if (conn->schema_support)
 
571
                                p = "schema";
 
572
                        else
 
573
                                p = "owner";
 
574
                        break;
 
575
 
 
576
                case SQL_OWNER_USAGE:   /* ODBC 2.0 */
 
577
                        len = 4;
 
578
                        value = 0;
 
579
                        if (conn->schema_support)
 
580
                                value = SQL_OU_DML_STATEMENTS
 
581
                                        | SQL_OU_TABLE_DEFINITION
 
582
                                        | SQL_OU_INDEX_DEFINITION
 
583
                                        | SQL_OU_PRIVILEGE_DEFINITION
 
584
                                        ;
 
585
                        break;
 
586
 
 
587
                case SQL_POS_OPERATIONS:                /* ODBC 2.0 */
 
588
                        len = 4;
 
589
                        value = (SQL_POS_POSITION | SQL_POS_REFRESH);
 
590
                        if (0 != ci->updatable_cursors)
 
591
                                value |= (SQL_POS_UPDATE | SQL_POS_DELETE | SQL_POS_ADD);
 
592
                        break;
 
593
 
 
594
                case SQL_POSITIONED_STATEMENTS: /* ODBC 2.0 */
 
595
                        len = 4;
 
596
                        value = ci->drivers.lie ? (SQL_PS_POSITIONED_DELETE |
 
597
                                                                           SQL_PS_POSITIONED_UPDATE |
 
598
                                                                           SQL_PS_SELECT_FOR_UPDATE) : 0;
 
599
                        break;
 
600
 
 
601
                case SQL_PROCEDURE_TERM:                /* ODBC 1.0 */
 
602
                        p = "procedure";
 
603
                        break;
 
604
 
 
605
                case SQL_PROCEDURES:    /* ODBC 1.0 */
 
606
                        p = "Y";
 
607
                        break;
 
608
 
 
609
                case SQL_QUALIFIER_LOCATION:    /* ODBC 2.0 */
 
610
                        len = 2;
 
611
                        if (CurrCat(conn))
 
612
                                value = SQL_QL_START;
 
613
                        else
 
614
                                value = 0;
 
615
                        break;
 
616
 
 
617
                case SQL_QUALIFIER_NAME_SEPARATOR:              /* ODBC 1.0 */
 
618
                        if (CurrCat(conn))
 
619
                                p = ".";
 
620
                        else
 
621
                                p = NULL_STRING;
 
622
                        break;
 
623
 
 
624
                case SQL_QUALIFIER_TERM:                /* ODBC 1.0 */
 
625
                        if (CurrCat(conn))
 
626
                                p = "catalog";
 
627
                        else
 
628
                                p = NULL_STRING;
 
629
                        break;
 
630
 
 
631
                case SQL_QUALIFIER_USAGE:               /* ODBC 2.0 */
 
632
                        len = 4;
 
633
#if (ODBCVER >= 0x0300)
 
634
                        if (CurrCat(conn))
 
635
                                value = SQL_CU_DML_STATEMENTS;
 
636
                        else
 
637
#endif /* ODBCVER */
 
638
                                value = 0;
 
639
                        break;
 
640
 
 
641
                case SQL_QUOTED_IDENTIFIER_CASE:                /* ODBC 2.0 */
 
642
                        /* are "quoted" identifiers case-sensitive?  YES! */
 
643
                        len = 2;
 
644
                        value = SQL_IC_SENSITIVE;
 
645
                        break;
 
646
 
 
647
                case SQL_ROW_UPDATES:   /* ODBC 1.0 */
 
648
 
 
649
                        /*
 
650
                         * Driver doesn't support keyset-driven or mixed cursors, so
 
651
                         * not much point in saying row updates are supported
 
652
                         */
 
653
                        p = (0 != ci->updatable_cursors) ? "Y" : "N";
 
654
                        break;
 
655
 
 
656
                case SQL_SCROLL_CONCURRENCY:    /* ODBC 1.0 */
 
657
                        len = 4;
 
658
                        value = SQL_SCCO_READ_ONLY;
 
659
                        if (0 != ci->updatable_cursors)
 
660
                                value |= SQL_SCCO_OPT_ROWVER;
 
661
                        if (ci->drivers.lie)
 
662
                                value |= (SQL_SCCO_LOCK | SQL_SCCO_OPT_VALUES);
 
663
                        break;
 
664
 
 
665
                case SQL_SCROLL_OPTIONS:                /* ODBC 1.0 */
 
666
                        len = 4;
 
667
                        value = SQL_SO_FORWARD_ONLY | SQL_SO_STATIC;
 
668
                        if (0 != (ci->updatable_cursors & ALLOW_KEYSET_DRIVEN_CURSORS))
 
669
                                value |= SQL_SO_KEYSET_DRIVEN;
 
670
                        if (ci->drivers.lie)
 
671
                                value |= (SQL_SO_DYNAMIC | SQL_SO_MIXED);
 
672
                        break;
 
673
 
 
674
                case SQL_SEARCH_PATTERN_ESCAPE: /* ODBC 1.0 */
 
675
                        if (PG_VERSION_GE(conn, 6.5))
 
676
                                p = "\\";
 
677
                        else
 
678
                                p = NULL_STRING;
 
679
                        break;
 
680
 
 
681
                case SQL_SERVER_NAME:   /* ODBC 1.0 */
 
682
                        p = CC_get_server(conn);
 
683
                        break;
 
684
 
 
685
                case SQL_SPECIAL_CHARACTERS:    /* ODBC 2.0 */
 
686
                        p = "_";
 
687
                        break;
 
688
 
 
689
                case SQL_STATIC_SENSITIVITY:    /* ODBC 2.0 */
 
690
                        len = 4;
 
691
                        value = 0;
 
692
                        if (0 != ci->updatable_cursors)
 
693
                                value |= (SQL_SS_ADDITIONS | SQL_SS_DELETIONS | SQL_SS_UPDATES);
 
694
                        break;
 
695
 
 
696
                case SQL_STRING_FUNCTIONS:              /* ODBC 1.0 */
 
697
                        len = 4;
 
698
                        value = (SQL_FN_STR_CONCAT |
 
699
                                         SQL_FN_STR_LCASE |
 
700
                                         SQL_FN_STR_LENGTH |
 
701
                                         SQL_FN_STR_LOCATE |
 
702
                                         SQL_FN_STR_LTRIM |
 
703
                                         SQL_FN_STR_RTRIM |
 
704
                                         SQL_FN_STR_SUBSTRING |
 
705
                                         SQL_FN_STR_UCASE);
 
706
                        break;
 
707
 
 
708
                case SQL_SUBQUERIES:    /* ODBC 2.0 */
 
709
                        /* postgres 6.3 supports subqueries */
 
710
                        len = 4;
 
711
                        value = (SQL_SQ_QUANTIFIED |
 
712
                                         SQL_SQ_IN |
 
713
                                         SQL_SQ_EXISTS |
 
714
                                         SQL_SQ_COMPARISON);
 
715
                        break;
 
716
 
 
717
                case SQL_SYSTEM_FUNCTIONS:              /* ODBC 1.0 */
 
718
                        len = 4;
 
719
                        value = 0;
 
720
                        break;
 
721
 
 
722
                case SQL_TABLE_TERM:    /* ODBC 1.0 */
 
723
                        p = "table";
 
724
                        break;
 
725
 
 
726
                case SQL_TIMEDATE_ADD_INTERVALS:                /* ODBC 2.0 */
 
727
                        len = 4;
 
728
                        value = 0;
 
729
                        break;
 
730
 
 
731
                case SQL_TIMEDATE_DIFF_INTERVALS:               /* ODBC 2.0 */
 
732
                        len = 4;
 
733
                        value = 0;
 
734
                        break;
 
735
 
 
736
                case SQL_TIMEDATE_FUNCTIONS:    /* ODBC 1.0 */
 
737
                        len = 4;
 
738
                        value = (SQL_FN_TD_NOW);
 
739
                        break;
 
740
 
 
741
                case SQL_TXN_CAPABLE:   /* ODBC 1.0 */
 
742
 
 
743
                        /*
 
744
                         * Postgres can deal with create or drop table statements in a
 
745
                         * transaction
 
746
                         */
 
747
                        len = 2;
 
748
                        value = SQL_TC_ALL;
 
749
                        break;
 
750
 
 
751
                case SQL_TXN_ISOLATION_OPTION:  /* ODBC 1.0 */
 
752
                        len = 4;
 
753
                        if (PG_VERSION_LT(conn, 6.5))
 
754
                                value = SQL_TXN_SERIALIZABLE;
 
755
                        else if (PG_VERSION_GE(conn, 7.1))
 
756
                                value = SQL_TXN_READ_COMMITTED | SQL_TXN_SERIALIZABLE;
 
757
                        else
 
758
                                value = SQL_TXN_READ_COMMITTED;
 
759
                        break;
 
760
 
 
761
                case SQL_UNION: /* ODBC 2.0 */
 
762
                        /* unions with all supported in postgres 6.3 */
 
763
                        len = 4;
 
764
                        value = (SQL_U_UNION | SQL_U_UNION_ALL);
 
765
                        break;
 
766
 
 
767
                case SQL_USER_NAME:             /* ODBC 1.0 */
 
768
                        p = CC_get_username(conn);
 
769
                        break;
 
770
 
 
771
                default:
 
772
                        /* unrecognized key */
 
773
                        CC_set_error(conn, CONN_NOT_IMPLEMENTED_ERROR, "Unrecognized key passed to PGAPI_GetInfo.", NULL);
 
774
                        goto cleanup;
 
775
        }
 
776
 
 
777
        result = SQL_SUCCESS;
 
778
 
 
779
        mylog("%s: p='%s', len=%d, value=%d, cbMax=%d\n", func, p ? p : "<NULL>", len, value, cbInfoValueMax);
 
780
 
 
781
        /*
 
782
         * NOTE, that if rgbInfoValue is NULL, then no warnings or errors
 
783
         * should result and just pcbInfoValue is returned, which indicates
 
784
         * what length would be required if a real buffer had been passed in.
 
785
         */
 
786
        if (p)
 
787
        {
 
788
                /* char/binary data */
 
789
                len = strlen(p);
 
790
 
 
791
                if (rgbInfoValue)
 
792
                {
 
793
#ifdef  UNICODE_SUPPORT
 
794
                        if (CC_is_in_unicode_driver(conn))
 
795
                        {
 
796
                                len = utf8_to_ucs2(p, len, (SQLWCHAR *) rgbInfoValue, cbInfoValueMax / WCLEN);
 
797
                                len *= WCLEN;
 
798
                        }
 
799
                        else
 
800
#endif /* UNICODE_SUPPORT */
 
801
                        strncpy_null((char *) rgbInfoValue, p, (size_t) cbInfoValueMax);
 
802
 
 
803
                        if (len >= cbInfoValueMax)
 
804
                        {
 
805
                                result = SQL_SUCCESS_WITH_INFO;
 
806
                                CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the InfoValue.", func);
 
807
                        }
 
808
                }
 
809
#ifdef  UNICODE_SUPPORT
 
810
                else if (CC_is_in_unicode_driver(conn))
 
811
                        len *= WCLEN;
 
812
#endif /* UNICODE_SUPPORT */
 
813
        }
 
814
        else
 
815
        {
 
816
                /* numeric data */
 
817
                if (rgbInfoValue)
 
818
                {
 
819
                        if (len == sizeof(SQLSMALLINT))
 
820
                                *((SQLUSMALLINT *) rgbInfoValue) = (SQLUSMALLINT) value;
 
821
                        else if (len == sizeof(SQLINTEGER))
 
822
                                *((SQLUINTEGER *) rgbInfoValue) = (SQLUINTEGER) value;
 
823
                }
 
824
        }
 
825
 
 
826
        if (pcbInfoValue)
 
827
                *pcbInfoValue = (SQLSMALLINT) len;
 
828
cleanup:
 
829
 
 
830
        return result;
 
831
}
 
832
 
 
833
 
 
834
RETCODE         SQL_API
 
835
PGAPI_GetTypeInfo(
 
836
                                  HSTMT hstmt,
 
837
                                  SQLSMALLINT fSqlType)
 
838
{
 
839
        CSTR func = "PGAPI_GetTypeInfo";
 
840
        StatementClass *stmt = (StatementClass *) hstmt;
 
841
        ConnectionClass *conn;
 
842
        QResultClass    *res = NULL;
 
843
        TupleField      *tuple;
 
844
        int                     i, result_cols;
 
845
 
 
846
        /* Int4 type; */
 
847
        Int4            pgType;
 
848
        Int2            sqlType;
 
849
        RETCODE         result = SQL_SUCCESS;
 
850
 
 
851
        mylog("%s: entering...fSqlType = %d\n", func, fSqlType);
 
852
 
 
853
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
 
854
                return result;
 
855
 
 
856
        conn = SC_get_conn(stmt);
 
857
        if (res = QR_Constructor(), !res)
 
858
        {
 
859
                SC_set_error(stmt, STMT_INTERNAL_ERROR, "Error creating result.", func);
 
860
                return SQL_ERROR;
 
861
        }
 
862
        SC_set_Result(stmt, res);
 
863
 
 
864
#define return  DONT_CALL_RETURN_FROM_HERE???
 
865
#if (ODBCVER >= 0x0300)
 
866
        result_cols = 19;
 
867
#else
 
868
        result_cols = 15;
 
869
#endif /* ODBCVER */
 
870
        extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
871
 
 
872
        stmt->catalog_result = TRUE;
 
873
        QR_set_num_fields(res, result_cols);
 
874
        QR_set_field_info_v(res, 0, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
875
        QR_set_field_info_v(res, 1, "DATA_TYPE", PG_TYPE_INT2, 2);
 
876
        QR_set_field_info_v(res, 2, "PRECISION", PG_TYPE_INT4, 4);
 
877
        QR_set_field_info_v(res, 3, "LITERAL_PREFIX", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
878
        QR_set_field_info_v(res, 4, "LITERAL_SUFFIX", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
879
        QR_set_field_info_v(res, 5, "CREATE_PARAMS", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
880
        QR_set_field_info_v(res, 6, "NULLABLE", PG_TYPE_INT2, 2);
 
881
        QR_set_field_info_v(res, 7, "CASE_SENSITIVE", PG_TYPE_INT2, 2);
 
882
        QR_set_field_info_v(res, 8, "SEARCHABLE", PG_TYPE_INT2, 2);
 
883
        QR_set_field_info_v(res, 9, "UNSIGNED_ATTRIBUTE", PG_TYPE_INT2, 2);
 
884
        QR_set_field_info_v(res, 10, "MONEY", PG_TYPE_INT2, 2);
 
885
        QR_set_field_info_v(res, 11, "AUTO_INCREMENT", PG_TYPE_INT2, 2);
 
886
        QR_set_field_info_v(res, 12, "LOCAL_TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
887
        QR_set_field_info_v(res, 13, "MINIMUM_SCALE", PG_TYPE_INT2, 2);
 
888
        QR_set_field_info_v(res, 14, "MAXIMUM_SCALE", PG_TYPE_INT2, 2);
 
889
#if (ODBCVER >=0x0300)
 
890
        QR_set_field_info_v(res, 15, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
 
891
        QR_set_field_info_v(res, 16, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
 
892
        QR_set_field_info_v(res, 17, "NUM_PREC_RADIX", PG_TYPE_INT4, 4);
 
893
        QR_set_field_info_v(res, 18, "INTERVAL_PRECISION", PG_TYPE_INT2, 2);
 
894
#endif /* ODBCVER */
 
895
 
 
896
        for (i = 0, sqlType = sqlTypes[0]; sqlType; sqlType = sqlTypes[++i])
 
897
        {
 
898
                pgType = sqltype_to_pgtype(conn, sqlType);
 
899
 
 
900
if (sqlType == SQL_LONGVARBINARY)
 
901
{
 
902
ConnInfo        *ci = &(conn->connInfo);
 
903
inolog("%d sqltype=%d -> pgtype=%d\n", ci->bytea_as_longvarbinary, sqlType, pgType);
 
904
}
 
905
 
 
906
                if (fSqlType == SQL_ALL_TYPES || fSqlType == sqlType)
 
907
                {
 
908
                        int     pgtcount = 1, aunq_match = -1, cnt;
 
909
 
 
910
                        /*if (SQL_INTEGER == sqlType || SQL_TINYINT == sqlType)*/
 
911
                        if (SQL_INTEGER == sqlType)
 
912
                        {
 
913
mylog("sqlType=%d ms_jet=%d\n", sqlType, conn->ms_jet);
 
914
                                if (conn->ms_jet && PG_VERSION_GE(conn, 6.4))
 
915
                                {
 
916
                                        aunq_match = 1;
 
917
                                        pgtcount = 2;
 
918
                                }
 
919
mylog("aunq_match=%d pgtcount=%d\n", aunq_match, pgtcount);
 
920
                        }
 
921
                        for (cnt = 0; cnt < pgtcount; cnt ++)
 
922
                        {
 
923
                                if (tuple = QR_AddNew(res), NULL == tuple)
 
924
                                {
 
925
                                        result = SQL_ERROR;
 
926
                                        SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't QR_AddNew.", func);
 
927
                                        goto cleanup;
 
928
                                }
 
929
 
 
930
                                /* These values can't be NULL */
 
931
                                if (aunq_match == cnt)
 
932
                                {
 
933
                                        set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, PG_UNSPECIFIED, TRUE));
 
934
                                        set_tuplefield_int2(&tuple[6], SQL_NO_NULLS);
 
935
inolog("serial in\n");
 
936
                                }
 
937
                                else
 
938
                                {
 
939
                                        set_tuplefield_string(&tuple[0], pgtype_to_name(stmt, pgType, PG_UNSPECIFIED, FALSE));
 
940
                                        set_tuplefield_int2(&tuple[6], pgtype_nullable(conn, pgType));
 
941
                                }
 
942
                                set_tuplefield_int2(&tuple[1], (Int2) sqlType);
 
943
                                set_tuplefield_int2(&tuple[7], pgtype_case_sensitive(conn, pgType));
 
944
                                set_tuplefield_int2(&tuple[8], pgtype_searchable(conn, pgType));
 
945
                                set_tuplefield_int2(&tuple[10], pgtype_money(conn, pgType));
 
946
 
 
947
                        /*
 
948
                         * Localized data-source dependent data type name (always
 
949
                         * NULL)
 
950
                         */
 
951
                                set_tuplefield_null(&tuple[12]);
 
952
 
 
953
                                /* These values can be NULL */
 
954
                                set_nullfield_int4(&tuple[2], pgtype_column_size(stmt, pgType, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
955
                                set_nullfield_string(&tuple[3], pgtype_literal_prefix(conn, pgType));
 
956
                                set_nullfield_string(&tuple[4], pgtype_literal_suffix(conn, pgType));
 
957
                                set_nullfield_string(&tuple[5], pgtype_create_params(conn, pgType));
 
958
                                if (1 < pgtcount)
 
959
                                        set_tuplefield_int2(&tuple[9], SQL_TRUE);
 
960
                                else
 
961
                                        set_nullfield_int2(&tuple[9], pgtype_unsigned(conn, pgType));
 
962
                                if (aunq_match == cnt)
 
963
                                        set_tuplefield_int2(&tuple[11], SQL_TRUE);
 
964
                                else
 
965
                                        set_nullfield_int2(&tuple[11], pgtype_auto_increment(conn, pgType));
 
966
                                set_nullfield_int2(&tuple[13], pgtype_min_decimal_digits(conn, pgType));
 
967
                                set_nullfield_int2(&tuple[14], pgtype_max_decimal_digits(conn, pgType));
 
968
#if (ODBCVER >=0x0300)
 
969
                                set_nullfield_int2(&tuple[15], pgtype_to_sqldesctype(stmt, pgType, PG_STATIC));
 
970
                                set_nullfield_int2(&tuple[16], pgtype_to_datetime_sub(stmt, pgType, PG_UNSPECIFIED));
 
971
                                set_nullfield_int4(&tuple[17], pgtype_radix(conn, pgType));
 
972
                                set_nullfield_int4(&tuple[18], 0);
 
973
#endif /* ODBCVER */
 
974
                        }
 
975
                }
 
976
        }
 
977
 
 
978
cleanup:
 
979
#undef  return
 
980
        /*
 
981
         * also, things need to think that this statement is finished so the
 
982
         * results can be retrieved.
 
983
         */
 
984
        stmt->status = STMT_FINISHED;
 
985
        stmt->currTuple = -1;
 
986
        if (SQL_SUCCEEDED(result))
 
987
                SC_set_rowset_start(stmt, -1, FALSE);
 
988
        else
 
989
                SC_set_Result(stmt, NULL);
 
990
        SC_set_current_col(stmt, -1);
 
991
 
 
992
        if (stmt->internal)
 
993
                result = DiscardStatementSvp(stmt, result, FALSE);
 
994
        return result;
 
995
}
 
996
 
 
997
 
 
998
RETCODE         SQL_API
 
999
PGAPI_GetFunctions(
 
1000
                                   HDBC hdbc,
 
1001
                                   SQLUSMALLINT fFunction,
 
1002
                                   SQLUSMALLINT FAR * pfExists)
 
1003
{
 
1004
        CSTR func = "PGAPI_GetFunctions";
 
1005
        ConnectionClass *conn = (ConnectionClass *) hdbc;
 
1006
        ConnInfo   *ci = &(conn->connInfo);
 
1007
 
 
1008
        mylog("%s: entering...%u\n", func, fFunction);
 
1009
 
 
1010
        if (fFunction == SQL_API_ALL_FUNCTIONS)
 
1011
        {
 
1012
#if (ODBCVER < 0x0300)
 
1013
                if (ci->drivers.lie)
 
1014
                {
 
1015
                        int                     i;
 
1016
 
 
1017
                        memset(pfExists, 0, sizeof(pfExists[0]) * 100);
 
1018
 
 
1019
                        pfExists[SQL_API_SQLALLOCENV] = TRUE;
 
1020
                        pfExists[SQL_API_SQLFREEENV] = TRUE;
 
1021
                        for (i = SQL_API_SQLALLOCCONNECT; i <= SQL_NUM_FUNCTIONS; i++)
 
1022
                                pfExists[i] = TRUE;
 
1023
                        for (i = SQL_EXT_API_START; i <= SQL_EXT_API_LAST; i++)
 
1024
                                pfExists[i] = TRUE;
 
1025
                }
 
1026
                else
 
1027
#endif
 
1028
                {
 
1029
                        memset(pfExists, 0, sizeof(pfExists[0]) * 100);
 
1030
 
 
1031
                        /* ODBC core functions */
 
1032
                        pfExists[SQL_API_SQLALLOCCONNECT] = TRUE;
 
1033
                        pfExists[SQL_API_SQLALLOCENV] = TRUE;
 
1034
                        pfExists[SQL_API_SQLALLOCSTMT] = TRUE;
 
1035
                        pfExists[SQL_API_SQLBINDCOL] = TRUE;
 
1036
                        pfExists[SQL_API_SQLCANCEL] = TRUE;
 
1037
                        pfExists[SQL_API_SQLCOLATTRIBUTES] = TRUE;
 
1038
                        pfExists[SQL_API_SQLCONNECT] = TRUE;
 
1039
                        pfExists[SQL_API_SQLDESCRIBECOL] = TRUE;        /* partial */
 
1040
                        pfExists[SQL_API_SQLDISCONNECT] = TRUE;
 
1041
                        pfExists[SQL_API_SQLERROR] = TRUE;
 
1042
                        pfExists[SQL_API_SQLEXECDIRECT] = TRUE;
 
1043
                        pfExists[SQL_API_SQLEXECUTE] = TRUE;
 
1044
                        pfExists[SQL_API_SQLFETCH] = TRUE;
 
1045
                        pfExists[SQL_API_SQLFREECONNECT] = TRUE;
 
1046
                        pfExists[SQL_API_SQLFREEENV] = TRUE;
 
1047
                        pfExists[SQL_API_SQLFREESTMT] = TRUE;
 
1048
                        pfExists[SQL_API_SQLGETCURSORNAME] = TRUE;
 
1049
                        pfExists[SQL_API_SQLNUMRESULTCOLS] = TRUE;
 
1050
                        pfExists[SQL_API_SQLPREPARE] = TRUE;            /* complete? */
 
1051
                        pfExists[SQL_API_SQLROWCOUNT] = TRUE;
 
1052
                        pfExists[SQL_API_SQLSETCURSORNAME] = TRUE;
 
1053
                        pfExists[SQL_API_SQLSETPARAM] = FALSE;          /* odbc 1.0 */
 
1054
                        pfExists[SQL_API_SQLTRANSACT] = TRUE;
 
1055
 
 
1056
                        /* ODBC level 1 functions */
 
1057
                        pfExists[SQL_API_SQLBINDPARAMETER] = TRUE;
 
1058
                        pfExists[SQL_API_SQLCOLUMNS] = TRUE;
 
1059
                        pfExists[SQL_API_SQLDRIVERCONNECT] = TRUE;
 
1060
                        pfExists[SQL_API_SQLGETCONNECTOPTION] = TRUE;           /* partial */
 
1061
                        pfExists[SQL_API_SQLGETDATA] = TRUE;
 
1062
                        pfExists[SQL_API_SQLGETFUNCTIONS] = TRUE;
 
1063
                        pfExists[SQL_API_SQLGETINFO] = TRUE;
 
1064
                        pfExists[SQL_API_SQLGETSTMTOPTION] = TRUE;      /* partial */
 
1065
                        pfExists[SQL_API_SQLGETTYPEINFO] = TRUE;
 
1066
                        pfExists[SQL_API_SQLPARAMDATA] = TRUE;
 
1067
                        pfExists[SQL_API_SQLPUTDATA] = TRUE;
 
1068
                        pfExists[SQL_API_SQLSETCONNECTOPTION] = TRUE;           /* partial */
 
1069
                        pfExists[SQL_API_SQLSETSTMTOPTION] = TRUE;
 
1070
                        pfExists[SQL_API_SQLSPECIALCOLUMNS] = TRUE;
 
1071
                        pfExists[SQL_API_SQLSTATISTICS] = TRUE;
 
1072
                        pfExists[SQL_API_SQLTABLES] = TRUE;
 
1073
 
 
1074
                        /* ODBC level 2 functions */
 
1075
                        pfExists[SQL_API_SQLBROWSECONNECT] = FALSE;
 
1076
                        if (PG_VERSION_GE(conn, 7.4))
 
1077
                                pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
 
1078
                        else
 
1079
                                pfExists[SQL_API_SQLCOLUMNPRIVILEGES] = FALSE;
 
1080
                        pfExists[SQL_API_SQLDATASOURCES] = FALSE;       /* only implemented by
 
1081
                                                                                                                 * DM */
 
1082
                        if (SUPPORT_DESCRIBE_PARAM(ci))
 
1083
                                pfExists[SQL_API_SQLDESCRIBEPARAM] = TRUE;
 
1084
                        else
 
1085
                                pfExists[SQL_API_SQLDESCRIBEPARAM] = FALSE; /* not properly
 
1086
                                                                                                                 * implemented */
 
1087
                        pfExists[SQL_API_SQLDRIVERS] = FALSE;           /* only implemented by
 
1088
                                                                                                                 * DM */
 
1089
                        pfExists[SQL_API_SQLEXTENDEDFETCH] = TRUE;
 
1090
                        pfExists[SQL_API_SQLFOREIGNKEYS] = TRUE;
 
1091
                        pfExists[SQL_API_SQLMORERESULTS] = TRUE;
 
1092
                        pfExists[SQL_API_SQLNATIVESQL] = TRUE;
 
1093
                        pfExists[SQL_API_SQLNUMPARAMS] = TRUE;
 
1094
                        pfExists[SQL_API_SQLPARAMOPTIONS] = TRUE;
 
1095
                        pfExists[SQL_API_SQLPRIMARYKEYS] = TRUE;
 
1096
                        if (PG_VERSION_LT(conn, 6.5))
 
1097
                                pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE;
 
1098
                        else
 
1099
                                pfExists[SQL_API_SQLPROCEDURECOLUMNS] = TRUE;
 
1100
                        if (PG_VERSION_LT(conn, 6.5))
 
1101
                                pfExists[SQL_API_SQLPROCEDURES] = FALSE;
 
1102
                        else
 
1103
                                pfExists[SQL_API_SQLPROCEDURES] = TRUE;
 
1104
                        pfExists[SQL_API_SQLSETPOS] = TRUE;
 
1105
                        pfExists[SQL_API_SQLSETSCROLLOPTIONS] = TRUE;           /* odbc 1.0 */
 
1106
                        pfExists[SQL_API_SQLTABLEPRIVILEGES] = TRUE;
 
1107
#if (ODBCVER >= 0x0300)
 
1108
                        if (0 == ci->updatable_cursors)
 
1109
                                pfExists[SQL_API_SQLBULKOPERATIONS] = FALSE;
 
1110
                        else
 
1111
                                pfExists[SQL_API_SQLBULKOPERATIONS] = TRUE;
 
1112
#endif /* ODBCVER */
 
1113
                }
 
1114
        }
 
1115
        else
 
1116
        {
 
1117
                if (ci->drivers.lie)
 
1118
                        *pfExists = TRUE;
 
1119
                else
 
1120
                {
 
1121
                        switch (fFunction)
 
1122
                        {
 
1123
#if (ODBCVER < 0x0300)
 
1124
                                case SQL_API_SQLALLOCCONNECT:
 
1125
                                        *pfExists = TRUE;
 
1126
                                        break;
 
1127
                                case SQL_API_SQLALLOCENV:
 
1128
                                        *pfExists = TRUE;
 
1129
                                        break;
 
1130
                                case SQL_API_SQLALLOCSTMT:
 
1131
                                        *pfExists = TRUE;
 
1132
                                        break;
 
1133
#endif /* ODBCVER */
 
1134
                                case SQL_API_SQLBINDCOL:
 
1135
                                        *pfExists = TRUE;
 
1136
                                        break;
 
1137
                                case SQL_API_SQLCANCEL:
 
1138
                                        *pfExists = TRUE;
 
1139
                                        break;
 
1140
#if (ODBCVER >= 0x0300)
 
1141
                                case SQL_API_SQLCOLATTRIBUTE:
 
1142
#else
 
1143
                                case SQL_API_SQLCOLATTRIBUTES:
 
1144
#endif /* ODBCVER */
 
1145
                                        *pfExists = TRUE;
 
1146
                                        break;
 
1147
                                case SQL_API_SQLCONNECT:
 
1148
                                        *pfExists = TRUE;
 
1149
                                        break;
 
1150
                                case SQL_API_SQLDESCRIBECOL:
 
1151
                                        *pfExists = TRUE;
 
1152
                                        break;          /* partial */
 
1153
                                case SQL_API_SQLDISCONNECT:
 
1154
                                        *pfExists = TRUE;
 
1155
                                        break;
 
1156
#if (ODBCVER < 0x0300)
 
1157
                                case SQL_API_SQLERROR:
 
1158
                                        *pfExists = TRUE;
 
1159
                                        break;
 
1160
#endif /* ODBCVER */
 
1161
                                case SQL_API_SQLEXECDIRECT:
 
1162
                                        *pfExists = TRUE;
 
1163
                                        break;
 
1164
                                case SQL_API_SQLEXECUTE:
 
1165
                                        *pfExists = TRUE;
 
1166
                                        break;
 
1167
                                case SQL_API_SQLFETCH:
 
1168
                                        *pfExists = TRUE;
 
1169
                                        break;
 
1170
#if (ODBCVER < 0x0300)
 
1171
                                case SQL_API_SQLFREECONNECT:
 
1172
                                        *pfExists = TRUE;
 
1173
                                        break;
 
1174
                                case SQL_API_SQLFREEENV:
 
1175
                                        *pfExists = TRUE;
 
1176
                                        break;
 
1177
#endif /* ODBCVER */
 
1178
                                case SQL_API_SQLFREESTMT:
 
1179
                                        *pfExists = TRUE;
 
1180
                                        break;
 
1181
                                case SQL_API_SQLGETCURSORNAME:
 
1182
                                        *pfExists = TRUE;
 
1183
                                        break;
 
1184
                                case SQL_API_SQLNUMRESULTCOLS:
 
1185
                                        *pfExists = TRUE;
 
1186
                                        break;
 
1187
                                case SQL_API_SQLPREPARE:
 
1188
                                        *pfExists = TRUE;
 
1189
                                        break;
 
1190
                                case SQL_API_SQLROWCOUNT:
 
1191
                                        *pfExists = TRUE;
 
1192
                                        break;
 
1193
                                case SQL_API_SQLSETCURSORNAME:
 
1194
                                        *pfExists = TRUE;
 
1195
                                        break;
 
1196
#if (ODBCVER < 0x0300)
 
1197
                                case SQL_API_SQLSETPARAM:
 
1198
                                        *pfExists = FALSE;
 
1199
                                        break;          /* odbc 1.0 */
 
1200
                                case SQL_API_SQLTRANSACT:
 
1201
                                        *pfExists = TRUE;
 
1202
                                        break;
 
1203
#endif /* ODBCVER */
 
1204
 
 
1205
                                        /* ODBC level 1 functions */
 
1206
                                case SQL_API_SQLBINDPARAMETER:
 
1207
                                        *pfExists = TRUE;
 
1208
                                        break;
 
1209
                                case SQL_API_SQLCOLUMNS:
 
1210
                                        *pfExists = TRUE;
 
1211
                                        break;
 
1212
                                case SQL_API_SQLDRIVERCONNECT:
 
1213
                                        *pfExists = TRUE;
 
1214
                                        break;
 
1215
#if (ODBCVER < 0x0300)
 
1216
                                case SQL_API_SQLGETCONNECTOPTION:
 
1217
                                        *pfExists = TRUE;
 
1218
                                        break;          /* partial */
 
1219
#endif /* ODBCVER */
 
1220
                                case SQL_API_SQLGETDATA:
 
1221
                                        *pfExists = TRUE;
 
1222
                                        break;
 
1223
                                case SQL_API_SQLGETFUNCTIONS:
 
1224
                                        *pfExists = TRUE;
 
1225
                                        break;
 
1226
                                case SQL_API_SQLGETINFO:
 
1227
                                        *pfExists = TRUE;
 
1228
                                        break;
 
1229
#if (ODBCVER < 0x0300)
 
1230
                                case SQL_API_SQLGETSTMTOPTION:
 
1231
                                        *pfExists = TRUE;
 
1232
                                        break;          /* partial */
 
1233
#endif /* ODBCVER */
 
1234
                                case SQL_API_SQLGETTYPEINFO:
 
1235
                                        *pfExists = TRUE;
 
1236
                                        break;
 
1237
                                case SQL_API_SQLPARAMDATA:
 
1238
                                        *pfExists = TRUE;
 
1239
                                        break;
 
1240
                                case SQL_API_SQLPUTDATA:
 
1241
                                        *pfExists = TRUE;
 
1242
                                        break;
 
1243
#if (ODBCVER < 0x0300)
 
1244
                                case SQL_API_SQLSETCONNECTOPTION:
 
1245
                                        *pfExists = TRUE;
 
1246
                                        break;          /* partial */
 
1247
                                case SQL_API_SQLSETSTMTOPTION:
 
1248
                                        *pfExists = TRUE;
 
1249
                                        break;
 
1250
#endif /* ODBCVER */
 
1251
                                case SQL_API_SQLSPECIALCOLUMNS:
 
1252
                                        *pfExists = TRUE;
 
1253
                                        break;
 
1254
                                case SQL_API_SQLSTATISTICS:
 
1255
                                        *pfExists = TRUE;
 
1256
                                        break;
 
1257
                                case SQL_API_SQLTABLES:
 
1258
                                        *pfExists = TRUE;
 
1259
                                        break;
 
1260
 
 
1261
                                        /* ODBC level 2 functions */
 
1262
                                case SQL_API_SQLBROWSECONNECT:
 
1263
                                        *pfExists = FALSE;
 
1264
                                        break;
 
1265
                                case SQL_API_SQLCOLUMNPRIVILEGES:
 
1266
                                        *pfExists = FALSE;
 
1267
                                        break;
 
1268
                                case SQL_API_SQLDATASOURCES:
 
1269
                                        *pfExists = FALSE;
 
1270
                                        break;          /* only implemented by DM */
 
1271
                                case SQL_API_SQLDESCRIBEPARAM:
 
1272
                                        if (SUPPORT_DESCRIBE_PARAM(ci))
 
1273
                                                *pfExists = TRUE;
 
1274
                                        else
 
1275
                                                *pfExists = FALSE;
 
1276
                                        break;          /* not properly implemented */
 
1277
                                case SQL_API_SQLDRIVERS:
 
1278
                                        *pfExists = FALSE;
 
1279
                                        break;          /* only implemented by DM */
 
1280
                                case SQL_API_SQLEXTENDEDFETCH:
 
1281
                                        *pfExists = TRUE;
 
1282
                                        break;
 
1283
                                case SQL_API_SQLFOREIGNKEYS:
 
1284
                                        *pfExists = TRUE;
 
1285
                                        break;
 
1286
                                case SQL_API_SQLMORERESULTS:
 
1287
                                        *pfExists = TRUE;
 
1288
                                        break;
 
1289
                                case SQL_API_SQLNATIVESQL:
 
1290
                                        *pfExists = TRUE;
 
1291
                                        break;
 
1292
                                case SQL_API_SQLNUMPARAMS:
 
1293
                                        *pfExists = TRUE;
 
1294
                                        break;
 
1295
#if (ODBCVER < 0x0300)
 
1296
                                case SQL_API_SQLPARAMOPTIONS:
 
1297
                                        *pfExists = TRUE;
 
1298
                                        break;
 
1299
#endif /* ODBCVER */
 
1300
                                case SQL_API_SQLPRIMARYKEYS:
 
1301
                                        *pfExists = TRUE;
 
1302
                                        break;
 
1303
                                case SQL_API_SQLPROCEDURECOLUMNS:
 
1304
                                        if (PG_VERSION_LT(conn, 6.5))
 
1305
                                                *pfExists = FALSE;
 
1306
                                        else
 
1307
                                                *pfExists = TRUE;
 
1308
                                        break;
 
1309
                                case SQL_API_SQLPROCEDURES:
 
1310
                                        if (PG_VERSION_LT(conn, 6.5))
 
1311
                                                *pfExists = FALSE;
 
1312
                                        else
 
1313
                                                *pfExists = TRUE;
 
1314
                                        break;
 
1315
                                case SQL_API_SQLSETPOS:
 
1316
                                        *pfExists = TRUE;
 
1317
                                        break;
 
1318
#if (ODBCVER < 0x0300)
 
1319
                                case SQL_API_SQLSETSCROLLOPTIONS:
 
1320
                                        *pfExists = TRUE;
 
1321
                                        break;          /* odbc 1.0 */
 
1322
#endif /* ODBCVER */
 
1323
                                case SQL_API_SQLTABLEPRIVILEGES:
 
1324
                                        *pfExists = TRUE;
 
1325
                                        break;
 
1326
#if (ODBCVER >= 0x0300)
 
1327
                                case SQL_API_SQLBULKOPERATIONS: /* 24 */
 
1328
                                case SQL_API_SQLALLOCHANDLE:    /* 1001 */
 
1329
                                case SQL_API_SQLBINDPARAM:      /* 1002 */
 
1330
                                case SQL_API_SQLCLOSECURSOR:    /* 1003 */
 
1331
                                case SQL_API_SQLENDTRAN:        /* 1005 */
 
1332
                                case SQL_API_SQLFETCHSCROLL:    /* 1021 */
 
1333
                                case SQL_API_SQLFREEHANDLE:     /* 1006 */
 
1334
                                case SQL_API_SQLGETCONNECTATTR: /* 1007 */
 
1335
                                case SQL_API_SQLGETDESCFIELD:   /* 1008 */
 
1336
                                case SQL_API_SQLGETDIAGFIELD:   /* 1010 */
 
1337
                                case SQL_API_SQLGETDIAGREC:     /* 1011 */
 
1338
                                case SQL_API_SQLGETENVATTR:     /* 1012 */
 
1339
                                case SQL_API_SQLGETSTMTATTR:    /* 1014 */
 
1340
                                case SQL_API_SQLSETCONNECTATTR: /* 1016 */
 
1341
                                case SQL_API_SQLSETDESCFIELD:   /* 1017 */
 
1342
                                case SQL_API_SQLSETENVATTR:     /* 1019 */
 
1343
                                case SQL_API_SQLSETSTMTATTR:    /* 1020 */
 
1344
                                        *pfExists = TRUE;
 
1345
                                        break;
 
1346
                                case SQL_API_SQLGETDESCREC:     /* 1009 */
 
1347
                                case SQL_API_SQLSETDESCREC:     /* 1018 */
 
1348
                                case SQL_API_SQLCOPYDESC:       /* 1004 */
 
1349
                                        *pfExists = FALSE;
 
1350
                                        break;
 
1351
#endif /* ODBCVER */
 
1352
                                default:
 
1353
                                        *pfExists = FALSE;
 
1354
                                        break;
 
1355
                        }
 
1356
                }
 
1357
        }
 
1358
        return SQL_SUCCESS;
 
1359
}
 
1360
 
 
1361
 
 
1362
static char     *
 
1363
simpleCatalogEscape(const char *src, int srclen, int *result_len, const ConnectionClass *conn)
 
1364
{
 
1365
        int     i, outlen;
 
1366
        const char *in;
 
1367
        char    *dest = NULL, escape_ch = CC_get_escape(conn);
 
1368
        encoded_str     encstr;
 
1369
 
 
1370
        if (result_len)
 
1371
                *result_len = 0;
 
1372
        if (!src || srclen == SQL_NULL_DATA)
 
1373
                return dest;
 
1374
        else if (srclen == SQL_NTS)
 
1375
                srclen = (int) strlen(src);
 
1376
        if (srclen <= 0)
 
1377
                return dest;
 
1378
mylog("simple in=%s(%d)\n", src, srclen);
 
1379
        encoded_str_constr(&encstr, conn->ccsc, src);
 
1380
        dest = malloc(2 * srclen + 1);
 
1381
        for (i = 0, in = src, outlen = 0; i < srclen; i++, in++)
 
1382
        {
 
1383
                encoded_nextchar(&encstr);
 
1384
                if (ENCODE_STATUS(encstr) != 0)
 
1385
                {
 
1386
                        dest[outlen++] = *in;
 
1387
                        continue;
 
1388
                }
 
1389
                if (LITERAL_QUOTE == *in ||
 
1390
                    escape_ch == *in)
 
1391
                        dest[outlen++] = *in;
 
1392
                dest[outlen++] = *in;
 
1393
        }
 
1394
        dest[outlen] = '\0';
 
1395
        if (result_len)
 
1396
                *result_len = outlen;
 
1397
mylog("simple output=%s(%d)\n", dest, outlen);
 
1398
        return dest;
 
1399
}
 
1400
 
 
1401
/*
 
1402
 *      PostgreSQL needs 2 '\\' to escape '_' and '%'. 
 
1403
 */
 
1404
static char     *
 
1405
adjustLikePattern(const char *src, int srclen, char escape_ch, int *result_len, const ConnectionClass *conn)
 
1406
{
 
1407
        int     i, outlen;
 
1408
        const char *in;
 
1409
        char    *dest = NULL, escape_in_literal = CC_get_escape(conn);
 
1410
        BOOL    escape_in = FALSE;
 
1411
        encoded_str     encstr;
 
1412
 
 
1413
        if (result_len)
 
1414
                *result_len = 0;
 
1415
        if (!src || srclen == SQL_NULL_DATA)
 
1416
                return dest;
 
1417
        else if (srclen == SQL_NTS)
 
1418
                srclen = (int) strlen(src);
 
1419
        /* if (srclen <= 0) */
 
1420
        if (srclen < 0)
 
1421
                return dest;
 
1422
mylog("adjust in=%.*s(%d)\n", srclen, src, srclen);
 
1423
        encoded_str_constr(&encstr, conn->ccsc, src);
 
1424
        dest = malloc(2 * srclen + 1);
 
1425
        for (i = 0, in = src, outlen = 0; i < srclen; i++, in++)
 
1426
        {
 
1427
                encoded_nextchar(&encstr);
 
1428
                if (ENCODE_STATUS(encstr) != 0)
 
1429
                {
 
1430
                        dest[outlen++] = *in;
 
1431
                        continue;
 
1432
                }
 
1433
                if (escape_in)
 
1434
                {
 
1435
                        switch (*in)
 
1436
                        {
 
1437
                                case '%':
 
1438
                                case '_':
 
1439
                                        break;
 
1440
                                default:
 
1441
                                        if (escape_ch == escape_in_literal)
 
1442
                                                dest[outlen++] = escape_in_literal;
 
1443
                                        dest[outlen++] = escape_ch;
 
1444
                                        break;
 
1445
                        }
 
1446
                }
 
1447
                if (*in == escape_ch)
 
1448
                {
 
1449
                        escape_in = TRUE;
 
1450
                        if (escape_ch == escape_in_literal)
 
1451
                                dest[outlen++] = escape_in_literal; /* insert 1 more LEXER escape */
 
1452
                }
 
1453
                else
 
1454
                {
 
1455
                        escape_in = FALSE;
 
1456
                        if (LITERAL_QUOTE == *in)
 
1457
                                dest[outlen++] = *in;
 
1458
                }
 
1459
                dest[outlen++] = *in;
 
1460
        }
 
1461
        if (escape_in)
 
1462
        {
 
1463
                if (escape_ch == escape_in_literal)
 
1464
                        dest[outlen++] = escape_in_literal;
 
1465
                dest[outlen++] = escape_ch;
 
1466
        }
 
1467
        dest[outlen] = '\0';
 
1468
        if (result_len)
 
1469
                *result_len = outlen;
 
1470
mylog("adjust output=%s(%d)\n", dest, outlen);
 
1471
        return dest;
 
1472
}
 
1473
 
 
1474
#define CSTR_SYS_TABLE  "SYSTEM TABLE"
 
1475
#define CSTR_TABLE      "TABLE"
 
1476
#define CSTR_VIEW       "VIEW"
 
1477
 
 
1478
CSTR    like_op_sp =    "like ";
 
1479
CSTR    like_op_ext =   "like E";
 
1480
CSTR    eq_op_sp =      "= ";
 
1481
CSTR    eq_op_ext =     "= E";
 
1482
static const char *gen_opestr(const char *orig_opestr, const ConnectionClass * conn)
 
1483
{
 
1484
        BOOL    addE = (0 != CC_get_escape(conn) && PG_VERSION_GE(conn, 8.1));
 
1485
 
 
1486
        if (0 == strcmp(orig_opestr, eqop))
 
1487
                return (addE ? eq_op_ext : eq_op_sp);
 
1488
        return (addE ? like_op_ext : like_op_sp);
 
1489
}
 
1490
 
 
1491
/*
 
1492
 *      If specified schema name == user_name and the current schema is
 
1493
 *      'public', allowed to use the 'public' schema.
 
1494
 */
 
1495
static BOOL
 
1496
allow_public_schema(ConnectionClass *conn, const char *szSchemaName, SQLSMALLINT cbSchemaName)
 
1497
{
 
1498
        const char *user = CC_get_username(conn);
 
1499
        size_t  userlen = strlen(user);
 
1500
 
 
1501
        if (NULL == szSchemaName)
 
1502
                return FALSE;
 
1503
 
 
1504
        if (SQL_NTS == cbSchemaName)
 
1505
                cbSchemaName = strlen(szSchemaName);
 
1506
 
 
1507
        return (cbSchemaName == (SQLSMALLINT) userlen &&
 
1508
                strnicmp(szSchemaName, user, userlen) == 0 &&
 
1509
                stricmp(CC_get_current_schema(conn), pubstr) == 0);
 
1510
}
 
1511
 
 
1512
RETCODE         SQL_API
 
1513
PGAPI_Tables(
 
1514
                         HSTMT hstmt,
 
1515
                         const SQLCHAR FAR * szTableQualifier, /* PV X*/
 
1516
                         SQLSMALLINT cbTableQualifier,
 
1517
                         const SQLCHAR FAR * szTableOwner, /* PV E*/
 
1518
                         SQLSMALLINT cbTableOwner,
 
1519
                         const SQLCHAR FAR * szTableName, /* PV E*/
 
1520
                         SQLSMALLINT cbTableName,
 
1521
                         const SQLCHAR FAR * szTableType,
 
1522
                         SQLSMALLINT cbTableType,
 
1523
                         UWORD  flag)
 
1524
{
 
1525
        CSTR func = "PGAPI_Tables";
 
1526
        StatementClass *stmt = (StatementClass *) hstmt;
 
1527
        StatementClass *tbl_stmt;
 
1528
        QResultClass    *res;
 
1529
        TupleField      *tuple;
 
1530
        HSTMT           htbl_stmt = NULL;
 
1531
        RETCODE         ret = SQL_ERROR, result;
 
1532
        int             result_cols;
 
1533
        char            *tableType = NULL;
 
1534
        char            tables_query[INFO_INQUIRY_LEN];
 
1535
        char            table_name[MAX_INFO_STRING],
 
1536
                                table_owner[MAX_INFO_STRING],
 
1537
                                relkind_or_hasrules[MAX_INFO_STRING];
 
1538
#ifdef  HAVE_STRTOK_R
 
1539
        char            *last;
 
1540
#endif /* HAVE_STRTOK_R */
 
1541
        ConnectionClass *conn;
 
1542
        ConnInfo   *ci;
 
1543
        char    *escCatName = NULL, *escSchemaName = NULL, *escTableName = NULL;
 
1544
        char       *prefix[32],
 
1545
                                prefixes[MEDIUM_REGISTRY_LEN];
 
1546
        char       *table_type[32],
 
1547
                                table_types[MAX_INFO_STRING];
 
1548
        char            show_system_tables,
 
1549
                                show_regular_tables,
 
1550
                                show_views;
 
1551
        char            regular_table,
 
1552
                                view,
 
1553
                                systable;
 
1554
        int                     i;
 
1555
        SQLSMALLINT             internal_asis_type = SQL_C_CHAR, cbSchemaName;
 
1556
        const char      *like_or_eq, *op_string;
 
1557
        const char      *szSchemaName;
 
1558
        BOOL            search_pattern;
 
1559
        BOOL            list_cat = FALSE, list_schemas = FALSE, list_table_types = FALSE, list_some = FALSE;
 
1560
        SQLLEN          cbRelname, cbRelkind, cbSchName;
 
1561
 
 
1562
        mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func, stmt, szTableOwner, cbTableOwner);
 
1563
 
 
1564
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
 
1565
                return result;
 
1566
 
 
1567
        conn = SC_get_conn(stmt);
 
1568
        ci = &(conn->connInfo);
 
1569
 
 
1570
        result = PGAPI_AllocStmt(conn, &htbl_stmt, 0);
 
1571
        if (!SQL_SUCCEEDED(result))
 
1572
        {
 
1573
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_Tables result.", func);
 
1574
                return SQL_ERROR;
 
1575
        }
 
1576
        tbl_stmt = (StatementClass *) htbl_stmt;
 
1577
        szSchemaName = szTableOwner;
 
1578
        cbSchemaName = cbTableOwner;
 
1579
 
 
1580
#define return  DONT_CALL_RETURN_FROM_HERE???
 
1581
        search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
 
1582
        if (search_pattern) 
 
1583
        {
 
1584
                like_or_eq = likeop;
 
1585
                escCatName = adjustLikePattern(szTableQualifier, cbTableQualifier, SEARCH_PATTERN_ESCAPE, NULL, conn);
 
1586
                escTableName = adjustLikePattern(szTableName, cbTableName, SEARCH_PATTERN_ESCAPE, NULL, conn);
 
1587
        }
 
1588
        else
 
1589
        {
 
1590
                like_or_eq = eqop;
 
1591
                escCatName = simpleCatalogEscape(szTableQualifier, cbTableQualifier, NULL, conn);
 
1592
                escTableName = simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
 
1593
        }
 
1594
retry_public_schema:
 
1595
        if (escSchemaName)
 
1596
                free(escSchemaName);
 
1597
        if (search_pattern) 
 
1598
                escSchemaName = adjustLikePattern(szSchemaName, cbSchemaName, SEARCH_PATTERN_ESCAPE, NULL, conn);
 
1599
        else
 
1600
                escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn);
 
1601
        /*
 
1602
         * Create the query to find out the tables
 
1603
         */
 
1604
        /* make_string mallocs memory */
 
1605
        tableType = make_string(szTableType, cbTableType, NULL, 0);
 
1606
#if (ODBCVER >= 0x0300)
 
1607
        if (search_pattern &&
 
1608
            escTableName && '\0' == escTableName[0] &&
 
1609
            escCatName && escSchemaName)
 
1610
        {
 
1611
                if ('\0' == escSchemaName[0])
 
1612
                {
 
1613
                        if (stricmp(escCatName, SQL_ALL_CATALOGS) == 0)
 
1614
                                list_cat = TRUE;
 
1615
                        else if ('\0' == escCatName[0] &&
 
1616
                                 stricmp(tableType, SQL_ALL_TABLE_TYPES) == 0)
 
1617
                                list_table_types = TRUE;
 
1618
                }
 
1619
                else if ('\0' == escCatName[0] &&
 
1620
                         stricmp(escSchemaName, SQL_ALL_SCHEMAS) == 0)
 
1621
                        list_schemas = TRUE;
 
1622
        }
 
1623
#endif /* ODBCVER */
 
1624
        list_some = (list_cat || list_schemas || list_table_types);
 
1625
 
 
1626
        tables_query[0] = '\0';
 
1627
        if (list_cat)
 
1628
                strncpy_null(tables_query, "select NULL, NULL, NULL", sizeof(tables_query));
 
1629
        else if (list_table_types)
 
1630
                strncpy_null(tables_query, "select NULL, NULL, relkind from (select 'r' as relkind union select 'v') as a", sizeof(tables_query));
 
1631
        else if (list_schemas)
 
1632
        {
 
1633
                if (conn->schema_support)
 
1634
                        strncpy_null(tables_query, "select NULL, nspname, NULL"
 
1635
                        " from pg_catalog.pg_namespace n where true", sizeof(tables_query));
 
1636
                else
 
1637
                        strncpy_null(tables_query, "select NULL, NULL as nspname, NULL", sizeof(tables_query));
 
1638
        }
 
1639
        else if (conn->schema_support)
 
1640
        {
 
1641
                /* view is represented by its relkind since 7.1 */
 
1642
                strcpy(tables_query, "select relname, nspname, relkind"
 
1643
                        " from pg_catalog.pg_class c, pg_catalog.pg_namespace n");
 
1644
                strcat(tables_query, " where relkind in ('r', 'v')");
 
1645
        }
 
1646
        else if (PG_VERSION_GE(conn, 7.1))
 
1647
        {
 
1648
                /* view is represented by its relkind since 7.1 */
 
1649
                strcpy(tables_query, "select relname, usename, relkind"
 
1650
                " from pg_class c, pg_user u");
 
1651
                strcat(tables_query, " where relkind in ('r', 'v')");
 
1652
        }
 
1653
        else
 
1654
        {
 
1655
                strcpy(tables_query, "select relname, usename, relhasrules from pg_class c, pg_user u");
 
1656
                strcat(tables_query, " where relkind = 'r'");
 
1657
        }
 
1658
 
 
1659
        op_string = gen_opestr(like_or_eq, conn);
 
1660
        if (!list_some)
 
1661
        {
 
1662
                if (conn->schema_support)
 
1663
                {
 
1664
                        schema_strcat1(tables_query, " and nspname %s'%.*s'", op_string, escSchemaName, SQL_NTS, szTableName, cbTableName, conn);
 
1665
                        /* strcat(tables_query, " and pg_catalog.pg_table_is_visible(c.oid)"); */
 
1666
                }
 
1667
                else
 
1668
                        my_strcat1(tables_query, " and usename %s'%.*s'", op_string, escSchemaName, SQL_NTS);
 
1669
                my_strcat1(tables_query, " and relname %s'%.*s'", op_string, escTableName, SQL_NTS);
 
1670
        }
 
1671
 
 
1672
        /* Parse the extra systable prefix      */
 
1673
        strcpy(prefixes, ci->drivers.extra_systable_prefixes);
 
1674
        i = 0;
 
1675
#ifdef  HAVE_STRTOK_R
 
1676
        prefix[i] = strtok_r(prefixes, ";", &last);
 
1677
#else
 
1678
        prefix[i] = strtok(prefixes, ";");
 
1679
#endif /* HAVE_STRTOK_R */
 
1680
        while (i < sizeof(prefix) && prefix[i])
 
1681
#ifdef  HAVE_STRTOK_R
 
1682
                prefix[++i] = strtok_r(NULL, ";", &last);
 
1683
#else
 
1684
                prefix[++i] = strtok(NULL, ";");
 
1685
#endif /* HAVE_STRTOK_R */
 
1686
 
 
1687
        /* Parse the desired table types to return */
 
1688
        show_system_tables = FALSE;
 
1689
        show_regular_tables = FALSE;
 
1690
        show_views = FALSE;
 
1691
 
 
1692
        /* TABLE_TYPE */
 
1693
        if (!tableType)
 
1694
        {
 
1695
                show_regular_tables = TRUE;
 
1696
                show_views = TRUE;
 
1697
        }
 
1698
#if (ODBCVER >= 0x0300)
 
1699
        else if (list_some || stricmp(tableType, SQL_ALL_TABLE_TYPES) == 0)
 
1700
        {
 
1701
                show_regular_tables = TRUE;
 
1702
                show_views = TRUE;
 
1703
        }
 
1704
#endif /* ODBCVER */
 
1705
        else
 
1706
        {
 
1707
                strcpy(table_types, tableType);
 
1708
                i = 0;
 
1709
#ifdef  HAVE_STRTOK_R
 
1710
                table_type[i] = strtok_r(table_types, ",", &last);
 
1711
#else
 
1712
                table_type[i] = strtok(table_types, ",");
 
1713
#endif /* HAVE_STRTOK_R */
 
1714
                while (i < sizeof(table_type) && table_type[i])
 
1715
#ifdef  HAVE_STRTOK_R
 
1716
                        table_type[++i] = strtok_r(NULL, ",", &last);
 
1717
#else
 
1718
                        table_type[++i] = strtok(NULL, ",");
 
1719
#endif /* HAVE_STRTOK_R */
 
1720
 
 
1721
                /* Check for desired table types to return */
 
1722
                i = 0;
 
1723
                while (table_type[i])
 
1724
                {
 
1725
                        char *typestr = table_type[i];
 
1726
 
 
1727
                        while (isspace(*typestr))
 
1728
                                typestr++;
 
1729
                        if (*typestr == '\'')
 
1730
                                typestr++;
 
1731
                        if (strnicmp(typestr, CSTR_SYS_TABLE, strlen(CSTR_SYS_TABLE)) == 0)
 
1732
                                show_system_tables = TRUE;
 
1733
                        else if (strnicmp(typestr, CSTR_TABLE, strlen(CSTR_TABLE)) == 0)
 
1734
                                show_regular_tables = TRUE;
 
1735
                        else if (strnicmp(typestr, CSTR_VIEW, strlen(CSTR_VIEW)) == 0)
 
1736
                                show_views = TRUE;
 
1737
                        i++;
 
1738
                }
 
1739
        }
 
1740
 
 
1741
        /*
 
1742
         * If not interested in SYSTEM TABLES then filter them out to save
 
1743
         * some time on the query.      If treating system tables as regular
 
1744
         * tables, then dont filter either.
 
1745
         */
 
1746
        if ((list_schemas || !list_some) && !atoi(ci->show_system_tables) && !show_system_tables)
 
1747
        {
 
1748
                if (conn->schema_support)
 
1749
                        strcat(tables_query, " and nspname not in ('pg_catalog', 'information_schema', 'pg_toast', 'pg_temp_1')");
 
1750
                else if (!list_schemas)
 
1751
                {
 
1752
                        strcat(tables_query, " and relname !~ '^" POSTGRES_SYS_PREFIX);
 
1753
 
 
1754
                        /* Also filter out user-defined system table types */
 
1755
                        for (i = 0; prefix[i]; i++)
 
1756
                        {
 
1757
                                strcat(tables_query, "|^");
 
1758
                                strcat(tables_query, prefix[i]);
 
1759
                        }
 
1760
                        strcat(tables_query, "'");
 
1761
                }
 
1762
        }
 
1763
 
 
1764
        if (!list_some)
 
1765
        {
 
1766
                if (CC_accessible_only(conn))
 
1767
                        strcat(tables_query, " and has_table_privilege(c.oid, 'select')");
 
1768
        }
 
1769
        if (list_schemas)
 
1770
                strcat(tables_query, " order by nspname");
 
1771
        else if (list_some)
 
1772
                ;
 
1773
        else if (conn->schema_support)
 
1774
                strcat(tables_query, " and n.oid = relnamespace order by nspname, relname");
 
1775
        else
 
1776
        {
 
1777
                /* match users */
 
1778
                if (PG_VERSION_LT(conn, 7.1))
 
1779
                        /* filter out large objects in older versions */
 
1780
                        strcat(tables_query, " and relname !~ '^xinv[0-9]+'");
 
1781
                strcat(tables_query, " and usesysid = relowner order by relname");
 
1782
        }
 
1783
 
 
1784
        result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
 
1785
        if (!SQL_SUCCEEDED(result))
 
1786
        {
 
1787
                SC_full_error_copy(stmt, htbl_stmt, FALSE);
 
1788
                goto cleanup;
 
1789
        }
 
1790
 
 
1791
        /* If not found */
 
1792
        if (conn->schema_support &&
 
1793
            (res = SC_get_Result(tbl_stmt)) &&
 
1794
            0 == QR_get_num_total_tuples(res))
 
1795
        {
 
1796
                if (allow_public_schema(conn, szSchemaName, cbSchemaName))
 
1797
                {
 
1798
                        szSchemaName = pubstr;
 
1799
                        cbSchemaName = SQL_NTS;
 
1800
                        goto retry_public_schema;
 
1801
                }
 
1802
        }
 
1803
#ifdef  UNICODE_SUPPORT
 
1804
        if (CC_is_in_unicode_driver(conn))
 
1805
                internal_asis_type = INTERNAL_ASIS_TYPE;
 
1806
#endif /* UNICODE_SUPPORT */
 
1807
        result = PGAPI_BindCol(htbl_stmt, 1, internal_asis_type,
 
1808
                        table_name, MAX_INFO_STRING, &cbRelname);
 
1809
        if (!SQL_SUCCEEDED(result))
 
1810
        {
 
1811
                SC_error_copy(stmt, tbl_stmt, TRUE);
 
1812
                goto cleanup;
 
1813
        }
 
1814
 
 
1815
        result = PGAPI_BindCol(htbl_stmt, 2, internal_asis_type,
 
1816
                                                   table_owner, MAX_INFO_STRING, &cbSchName);
 
1817
        if (!SQL_SUCCEEDED(result))
 
1818
        {
 
1819
                SC_error_copy(stmt, tbl_stmt, TRUE);
 
1820
                goto cleanup;
 
1821
        }
 
1822
        result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
 
1823
                        relkind_or_hasrules, MAX_INFO_STRING, &cbRelkind);
 
1824
        if (!SQL_SUCCEEDED(result))
 
1825
        {
 
1826
                SC_error_copy(stmt, tbl_stmt, TRUE);
 
1827
                goto cleanup;
 
1828
        }
 
1829
 
 
1830
        if (res = QR_Constructor(), !res)
 
1831
        {
 
1832
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Tables result.", func);
 
1833
                goto cleanup;
 
1834
        }
 
1835
        SC_set_Result(stmt, res);
 
1836
 
 
1837
        /* the binding structure for a statement is not set up until */
 
1838
 
 
1839
        /*
 
1840
         * a statement is actually executed, so we'll have to do this
 
1841
         * ourselves.
 
1842
         */
 
1843
        result_cols = NUM_OF_TABLES_FIELDS;
 
1844
        extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
1845
 
 
1846
        stmt->catalog_result = TRUE;
 
1847
        /* set the field names */
 
1848
        QR_set_num_fields(res, result_cols);
 
1849
        QR_set_field_info_v(res, TABLES_CATALOG_NAME, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
1850
        QR_set_field_info_v(res, TABLES_SCHEMA_NAME, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
1851
        QR_set_field_info_v(res, TABLES_TABLE_NAME, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
1852
        QR_set_field_info_v(res, TABLES_TABLE_TYPE, "TABLE_TYPE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
1853
        QR_set_field_info_v(res, TABLES_REMARKS, "REMARKS", PG_TYPE_VARCHAR, INFO_VARCHAR_SIZE);
 
1854
 
 
1855
        /* add the tuples */
 
1856
        table_name[0] = '\0';
 
1857
        table_owner[0] = '\0';
 
1858
        result = PGAPI_Fetch(htbl_stmt);
 
1859
        while (SQL_SUCCEEDED(result))
 
1860
        {
 
1861
                /*
 
1862
                 * Determine if this table name is a system table. If treating
 
1863
                 * system tables as regular tables, then no need to do this test.
 
1864
                 */
 
1865
                systable = FALSE;
 
1866
                if (!atoi(ci->show_system_tables))
 
1867
                {
 
1868
                        if (conn->schema_support)
 
1869
                        {
 
1870
                                if (stricmp(table_owner, "pg_catalog") == 0 ||
 
1871
                                    stricmp(table_owner, "pg_toast") == 0 ||
 
1872
                                    strnicmp(table_owner, "pg_temp_", 8) == 0 ||
 
1873
                                    stricmp(table_owner, "information_schema") == 0)
 
1874
                                        systable = TRUE;
 
1875
                        }
 
1876
                        else if (strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0)
 
1877
                                systable = TRUE;
 
1878
 
 
1879
                        else
 
1880
                        {
 
1881
                                /* Check extra system table prefixes */
 
1882
                                i = 0;
 
1883
                                while (prefix[i])
 
1884
                                {
 
1885
                                        mylog("table_name='%s', prefix[%d]='%s'\n", table_name, i, prefix[i]);
 
1886
                                        if (strncmp(table_name, prefix[i], strlen(prefix[i])) == 0)
 
1887
                                        {
 
1888
                                                systable = TRUE;
 
1889
                                                break;
 
1890
                                        }
 
1891
                                        i++;
 
1892
                                }
 
1893
                        }
 
1894
                }
 
1895
 
 
1896
                /* Determine if the table name is a view */
 
1897
                if (PG_VERSION_GE(conn, 7.1))
 
1898
                        /* view is represented by its relkind since 7.1 */
 
1899
                        view = (relkind_or_hasrules[0] == 'v');
 
1900
                else
 
1901
                        view = (relkind_or_hasrules[0] == '1');
 
1902
 
 
1903
                /* It must be a regular table */
 
1904
                regular_table = (!systable && !view);
 
1905
 
 
1906
 
 
1907
                /* Include the row in the result set if meets all criteria */
 
1908
 
 
1909
                /*
 
1910
                 * NOTE: Unsupported table types (i.e., LOCAL TEMPORARY, ALIAS,
 
1911
                 * etc) will return nothing
 
1912
                 */
 
1913
                if ((systable && show_system_tables) ||
 
1914
                        (view && show_views) ||
 
1915
                        (regular_table && show_regular_tables))
 
1916
                {
 
1917
                        tuple = QR_AddNew(res);
 
1918
 
 
1919
                        if (list_cat || !list_some)
 
1920
                                set_tuplefield_string(&tuple[TABLES_CATALOG_NAME], CurrCat(conn));
 
1921
                        else
 
1922
                                set_tuplefield_null(&tuple[TABLES_CATALOG_NAME]);
 
1923
 
 
1924
                        /*
 
1925
                         * I have to hide the table owner from Access, otherwise it
 
1926
                         * insists on referring to the table as 'owner.table'. (this
 
1927
                         * is valid according to the ODBC SQL grammar, but Postgres
 
1928
                         * won't support it.)
 
1929
                         *
 
1930
                         * set_tuplefield_string(&tuple[TABLES_SCHEMA_NAME], table_owner);
 
1931
                         */
 
1932
 
 
1933
                        mylog("%s: table_name = '%s'\n", func, table_name);
 
1934
 
 
1935
                        if (list_schemas || (conn->schema_support && !list_some))
 
1936
                                set_tuplefield_string(&tuple[TABLES_SCHEMA_NAME], GET_SCHEMA_NAME(table_owner));
 
1937
                        else
 
1938
                                set_tuplefield_null(&tuple[TABLES_SCHEMA_NAME]);
 
1939
                        if (list_some)
 
1940
                                set_tuplefield_null(&tuple[TABLES_TABLE_NAME]);
 
1941
                        else
 
1942
                                set_tuplefield_string(&tuple[TABLES_TABLE_NAME], table_name);
 
1943
                        if (list_table_types || !list_some)
 
1944
                                set_tuplefield_string(&tuple[TABLES_TABLE_TYPE], systable ? "SYSTEM TABLE" : (view ? "VIEW" : "TABLE"));
 
1945
                        else
 
1946
                                set_tuplefield_null(&tuple[TABLES_TABLE_TYPE]);
 
1947
                        set_tuplefield_string(&tuple[TABLES_REMARKS], NULL_STRING);
 
1948
                        /*** set_tuplefield_string(&tuple[TABLES_REMARKS], "TABLE"); ***/
 
1949
                }
 
1950
                result = PGAPI_Fetch(htbl_stmt);
 
1951
        }
 
1952
        if (result != SQL_NO_DATA_FOUND)
 
1953
        {
 
1954
                SC_full_error_copy(stmt, htbl_stmt, FALSE);
 
1955
                goto cleanup;
 
1956
        }
 
1957
        ret = SQL_SUCCESS;
 
1958
 
 
1959
cleanup:
 
1960
#undef  return
 
1961
        /*
 
1962
         * also, things need to think that this statement is finished so the
 
1963
         * results can be retrieved.
 
1964
         */
 
1965
        stmt->status = STMT_FINISHED;
 
1966
 
 
1967
        if (escCatName)
 
1968
                free(escCatName);
 
1969
        if (escSchemaName)
 
1970
                free(escSchemaName);
 
1971
        if (escTableName)
 
1972
                free(escTableName);
 
1973
        if (tableType)
 
1974
                free(tableType);
 
1975
        /* set up the current tuple pointer for SQLFetch */
 
1976
        stmt->currTuple = -1;
 
1977
        SC_set_rowset_start(stmt, -1, FALSE);
 
1978
        SC_set_current_col(stmt, -1);
 
1979
 
 
1980
        if (htbl_stmt)
 
1981
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
1982
 
 
1983
        if (stmt->internal)
 
1984
                ret = DiscardStatementSvp(stmt, ret, FALSE);
 
1985
        mylog("%s: EXIT, stmt=%p, ret=%d\n", func, stmt, ret);
 
1986
        return ret;
 
1987
}
 
1988
 
 
1989
RETCODE         SQL_API
 
1990
PGAPI_Columns(
 
1991
                          HSTMT hstmt,
 
1992
                          const SQLCHAR FAR * szTableQualifier, /* OA X*/
 
1993
                          SQLSMALLINT cbTableQualifier,
 
1994
                          const SQLCHAR FAR * szTableOwner, /* PV E*/
 
1995
                          SQLSMALLINT cbTableOwner,
 
1996
                          const SQLCHAR FAR * szTableName, /* PV E*/
 
1997
                          SQLSMALLINT cbTableName,
 
1998
                          const SQLCHAR FAR * szColumnName, /* PV E*/
 
1999
                          SQLSMALLINT cbColumnName,
 
2000
                          UWORD flag,
 
2001
                          OID   reloid,
 
2002
                          Int2  attnum)
 
2003
{
 
2004
        CSTR func = "PGAPI_Columns";
 
2005
        StatementClass *stmt = (StatementClass *) hstmt;
 
2006
        QResultClass    *res;
 
2007
        TupleField      *tuple;
 
2008
        HSTMT           hcol_stmt = NULL;
 
2009
        StatementClass *col_stmt;
 
2010
        char            columns_query[INFO_INQUIRY_LEN];
 
2011
        RETCODE         result;
 
2012
        char            table_owner[MAX_INFO_STRING],
 
2013
                                table_name[MAX_INFO_STRING],
 
2014
                                field_name[MAX_INFO_STRING],
 
2015
                                field_type_name[MAX_INFO_STRING];
 
2016
        Int2            field_number, sqltype, concise_type,
 
2017
                                result_cols;
 
2018
        Int4            mod_length,
 
2019
                                ordinal,
 
2020
                                typmod, relhasoids;
 
2021
        OID             field_type, the_type, greloid, basetype;
 
2022
#ifdef  USE_OLD_IMPL
 
2023
        Int2            decimal_digits;
 
2024
        Int4            field_length, column_size;
 
2025
        char            useStaticPrecision, useStaticScale;
 
2026
#endif /* USE_OLD_IMPL */
 
2027
        char            not_null[MAX_INFO_STRING],
 
2028
                                relhasrules[MAX_INFO_STRING], relkind[8];
 
2029
        char    *escSchemaName = NULL, *escTableName = NULL, *escColumnName = NULL;
 
2030
        BOOL    search_pattern = TRUE, search_by_ids, relisaview;
 
2031
        ConnInfo   *ci;
 
2032
        ConnectionClass *conn;
 
2033
        SQLSMALLINT     internal_asis_type = SQL_C_CHAR, cbSchemaName;
 
2034
        const char      *like_or_eq = likeop, *op_string;
 
2035
        const char      *szSchemaName;
 
2036
        BOOL    setIdentity = FALSE;
 
2037
 
 
2038
        mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func, stmt, szTableOwner, cbTableOwner);
 
2039
 
 
2040
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
 
2041
                return result;
 
2042
 
 
2043
        conn = SC_get_conn(stmt);
 
2044
        ci = &(conn->connInfo);
 
2045
#ifdef  UNICODE_SUPPORT
 
2046
        if (CC_is_in_unicode_driver(conn))
 
2047
                internal_asis_type = INTERNAL_ASIS_TYPE;
 
2048
#endif /* UNICODE_SUPPORT */
 
2049
 
 
2050
#define return  DONT_CALL_RETURN_FROM_HERE???
 
2051
        search_by_ids = ((flag & PODBC_SEARCH_BY_IDS) != 0);
 
2052
        if (search_by_ids)
 
2053
        {
 
2054
                szSchemaName = NULL;
 
2055
                cbSchemaName = SQL_NULL_DATA;
 
2056
        }
 
2057
        else
 
2058
        {
 
2059
                szSchemaName = szTableOwner;
 
2060
                cbSchemaName = cbTableOwner;
 
2061
                reloid = 0;
 
2062
                attnum = 0;
 
2063
                /*
 
2064
                 *      TableName or ColumnName is ordinarily an pattern value,
 
2065
                 */
 
2066
                search_pattern = ((flag & PODBC_NOT_SEARCH_PATTERN) == 0); 
 
2067
                if (search_pattern) 
 
2068
                {
 
2069
                        like_or_eq = likeop;
 
2070
                        escTableName = adjustLikePattern(szTableName, cbTableName, SEARCH_PATTERN_ESCAPE, NULL, conn);
 
2071
                        escColumnName = adjustLikePattern(szColumnName, cbColumnName, SEARCH_PATTERN_ESCAPE, NULL, conn);
 
2072
                }
 
2073
                else
 
2074
                {
 
2075
                        like_or_eq = eqop;
 
2076
                        escTableName = simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
 
2077
                        escColumnName = simpleCatalogEscape(szColumnName, cbColumnName, NULL, conn);
 
2078
                }
 
2079
        }
 
2080
retry_public_schema:
 
2081
        if (!search_by_ids)
 
2082
        {
 
2083
                if (escSchemaName)
 
2084
                        free(escSchemaName);
 
2085
                if (search_pattern) 
 
2086
                        escSchemaName = adjustLikePattern(szSchemaName, cbSchemaName, SEARCH_PATTERN_ESCAPE, NULL, conn);
 
2087
                else
 
2088
                        escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn);
 
2089
        }
 
2090
        /*
 
2091
         * Create the query to find out the columns (Note: pre 6.3 did not
 
2092
         * have the atttypmod field)
 
2093
         */
 
2094
        op_string = gen_opestr(like_or_eq, conn);
 
2095
        if (conn->schema_support)
 
2096
        {
 
2097
                snprintf(columns_query, sizeof(columns_query),
 
2098
                        "select n.nspname, c.relname, a.attname, a.atttypid"
 
2099
                        ", t.typname, a.attnum, a.attlen, a.atttypmod, a.attnotnull"
 
2100
                        ", c.relhasrules, c.relkind, c.oid, %s, %s, %s"
 
2101
                        " from (((pg_catalog.pg_class c"
 
2102
                        " inner join pg_catalog.pg_namespace n on n.oid = c.relnamespace",
 
2103
                        PG_VERSION_GE(conn, 7.4) ?
 
2104
                        "pg_get_expr(d.adbin, d.adrelid)" : "d.adsrc",
 
2105
                        PG_VERSION_GE(conn, 7.4) ?
 
2106
                        "case t.typtype when 'd' then t.typbasetype else 0 end, t.typtypmod"
 
2107
                                        : "0, -1",
 
2108
                        PG_VERSION_GE(conn, 7.2) ? "c.relhasoids" : "1"
 
2109
                                        );
 
2110
                if (search_by_ids)
 
2111
                        snprintf_add(columns_query, sizeof(columns_query), " and c.oid = %u", reloid);
 
2112
                else
 
2113
                {
 
2114
                        if (escTableName)
 
2115
                                snprintf_add(columns_query, sizeof(columns_query), " and c.relname %s'%s'", op_string, escTableName);
 
2116
                        schema_strcat1(columns_query, " and n.nspname %s'%.*s'", op_string, escSchemaName, SQL_NTS, szTableName, cbTableName, conn);
 
2117
                }
 
2118
                strcat(columns_query, ") inner join pg_catalog.pg_attribute a"
 
2119
                        " on (not a.attisdropped)");
 
2120
                if (0 == attnum && (NULL == escColumnName || like_or_eq != eqop))
 
2121
                        strcat(columns_query, " and a.attnum > 0");
 
2122
                if (search_by_ids)
 
2123
                {
 
2124
                        if (attnum != 0)
 
2125
                                snprintf_add(columns_query, sizeof(columns_query), " and a.attnum = %d", attnum);
 
2126
                }
 
2127
                else if (escColumnName)
 
2128
                        snprintf_add(columns_query, sizeof(columns_query), " and a.attname %s'%s'", op_string, escColumnName);
 
2129
                strcat(columns_query,
 
2130
                        " and a.attrelid = c.oid) inner join pg_catalog.pg_type t"
 
2131
                        " on t.oid = a.atttypid) left outer join pg_attrdef d"
 
2132
                        " on a.atthasdef and d.adrelid = a.attrelid and d.adnum = a.attnum");
 
2133
                strcat(columns_query, " order by n.nspname, c.relname, attnum");
 
2134
        }
 
2135
        else
 
2136
        {
 
2137
                snprintf(columns_query, sizeof(columns_query),
 
2138
                        "select u.usename, c.relname, a.attname, a.atttypid"
 
2139
                        ", t.typname, a.attnum, a.attlen, %s, a.attnotnull"
 
2140
                        ", c.relhasrules, c.relkind, c.oid, NULL, 0, -1 from"
 
2141
                        "  pg_user u, pg_class c, pg_attribute a, pg_type t where"
 
2142
                        "  u.usesysid = c.relowner and c.oid= a.attrelid"
 
2143
                        "  and a.atttypid = t.oid and (a.attnum > 0)",
 
2144
                        PG_VERSION_LE(conn, 6.2) ? "a.attlen" : "a.atttypmod");
 
2145
                if (escTableName)
 
2146
                        snprintf_add(columns_query, sizeof(columns_query), " and c.relname %s'%s'", op_string, escTableName);
 
2147
                my_strcat1(columns_query, " and u.usename %s'%.*s'", op_string, escSchemaName, SQL_NTS);
 
2148
                if (escColumnName)
 
2149
                        snprintf_add(columns_query, sizeof(columns_query), " and a.attname %s'%s'", op_string, escColumnName);
 
2150
                strcat(columns_query, " order by c.relname, attnum");
 
2151
        }
 
2152
 
 
2153
        result = PGAPI_AllocStmt(conn, &hcol_stmt, 0);
 
2154
        if (!SQL_SUCCEEDED(result))
 
2155
        {
 
2156
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_Columns result.", func);
 
2157
                result = SQL_ERROR;
 
2158
                goto cleanup;
 
2159
        }
 
2160
        col_stmt = (StatementClass *) hcol_stmt;
 
2161
 
 
2162
        mylog("%s: hcol_stmt = %p, col_stmt = %p\n", func, hcol_stmt, col_stmt);
 
2163
 
 
2164
        col_stmt->internal = TRUE;
 
2165
        result = PGAPI_ExecDirect(hcol_stmt, columns_query, SQL_NTS, 0);
 
2166
        if (!SQL_SUCCEEDED(result))
 
2167
        {
 
2168
                SC_full_error_copy(stmt, col_stmt, FALSE);
 
2169
                goto cleanup;
 
2170
        }
 
2171
 
 
2172
        /* If not found */
 
2173
        if (conn->schema_support &&
 
2174
            (flag & PODBC_SEARCH_PUBLIC_SCHEMA) != 0 &&
 
2175
            (res = SC_get_Result(col_stmt)) &&
 
2176
            0 == QR_get_num_total_tuples(res))
 
2177
        {
 
2178
                if (!search_by_ids &&
 
2179
                    allow_public_schema(conn, szSchemaName, cbSchemaName))
 
2180
                {
 
2181
                        PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2182
                        hcol_stmt = NULL;
 
2183
                        szSchemaName = pubstr;
 
2184
                        cbSchemaName = SQL_NTS;
 
2185
                        goto retry_public_schema;
 
2186
                }
 
2187
        }
 
2188
 
 
2189
        result = PGAPI_BindCol(hcol_stmt, 1, internal_asis_type,
 
2190
                                                   table_owner, MAX_INFO_STRING, NULL);
 
2191
        if (!SQL_SUCCEEDED(result))
 
2192
        {
 
2193
                SC_error_copy(stmt, col_stmt, TRUE);
 
2194
                goto cleanup;
 
2195
        }
 
2196
 
 
2197
        result = PGAPI_BindCol(hcol_stmt, 2, internal_asis_type,
 
2198
                                                   table_name, MAX_INFO_STRING, NULL);
 
2199
        if (!SQL_SUCCEEDED(result))
 
2200
        {
 
2201
                SC_error_copy(stmt, col_stmt, TRUE);
 
2202
                goto cleanup;
 
2203
        }
 
2204
 
 
2205
        result = PGAPI_BindCol(hcol_stmt, 3, internal_asis_type,
 
2206
                                                   field_name, MAX_INFO_STRING, NULL);
 
2207
        if (!SQL_SUCCEEDED(result))
 
2208
        {
 
2209
                SC_error_copy(stmt, col_stmt, TRUE);
 
2210
                goto cleanup;
 
2211
        }
 
2212
 
 
2213
        result = PGAPI_BindCol(hcol_stmt, 4, SQL_C_ULONG,
 
2214
                                                   &field_type, 4, NULL);
 
2215
        if (!SQL_SUCCEEDED(result))
 
2216
        {
 
2217
                SC_error_copy(stmt, col_stmt, TRUE);
 
2218
                goto cleanup;
 
2219
        }
 
2220
 
 
2221
        result = PGAPI_BindCol(hcol_stmt, 5, internal_asis_type,
 
2222
                                                   field_type_name, MAX_INFO_STRING, NULL);
 
2223
        if (!SQL_SUCCEEDED(result))
 
2224
        {
 
2225
                SC_error_copy(stmt, col_stmt, TRUE);
 
2226
                goto cleanup;
 
2227
        }
 
2228
 
 
2229
        result = PGAPI_BindCol(hcol_stmt, 6, SQL_C_SHORT,
 
2230
                                                   &field_number, MAX_INFO_STRING, NULL);
 
2231
        if (!SQL_SUCCEEDED(result))
 
2232
        {
 
2233
                SC_error_copy(stmt, col_stmt, TRUE);
 
2234
                goto cleanup;
 
2235
        }
 
2236
 
 
2237
#ifdef  NOT_USED
 
2238
        result = PGAPI_BindCol(hcol_stmt, 7, SQL_C_LONG,
 
2239
                                                   &field_length, MAX_INFO_STRING, NULL);
 
2240
        if (!SQL_SUCCEEDED(result))
 
2241
        {
 
2242
                SC_error_copy(stmt, col_stmt, TRUE);
 
2243
                goto cleanup;
 
2244
        }
 
2245
#endif /* NOT_USED */
 
2246
 
 
2247
        result = PGAPI_BindCol(hcol_stmt, 8, SQL_C_LONG,
 
2248
                                                   &mod_length, MAX_INFO_STRING, NULL);
 
2249
        if (!SQL_SUCCEEDED(result))
 
2250
        {
 
2251
                SC_error_copy(stmt, col_stmt, TRUE);
 
2252
                goto cleanup;
 
2253
        }
 
2254
 
 
2255
        result = PGAPI_BindCol(hcol_stmt, 9, internal_asis_type,
 
2256
                                                   not_null, MAX_INFO_STRING, NULL);
 
2257
        if (!SQL_SUCCEEDED(result))
 
2258
        {
 
2259
                SC_error_copy(stmt, col_stmt, TRUE);
 
2260
                goto cleanup;
 
2261
        }
 
2262
 
 
2263
        result = PGAPI_BindCol(hcol_stmt, 10, internal_asis_type,
 
2264
                                                   relhasrules, MAX_INFO_STRING, NULL);
 
2265
        if (!SQL_SUCCEEDED(result))
 
2266
        {
 
2267
                SC_error_copy(stmt, col_stmt, TRUE);
 
2268
                goto cleanup;
 
2269
        }
 
2270
 
 
2271
        result = PGAPI_BindCol(hcol_stmt, 11, internal_asis_type,
 
2272
                                                   relkind, sizeof(relkind), NULL);
 
2273
        if (!SQL_SUCCEEDED(result))
 
2274
        {
 
2275
                SC_error_copy(stmt, col_stmt, TRUE);
 
2276
                goto cleanup;
 
2277
        }
 
2278
 
 
2279
        result = PGAPI_BindCol(hcol_stmt, 12, SQL_C_LONG,
 
2280
                                        &greloid, sizeof(greloid), NULL);
 
2281
        if (!SQL_SUCCEEDED(result))
 
2282
        {
 
2283
                SC_error_copy(stmt, col_stmt, TRUE);
 
2284
                goto cleanup;
 
2285
        }
 
2286
 
 
2287
        result = PGAPI_BindCol(hcol_stmt, 14, SQL_C_ULONG,
 
2288
                                        &basetype, sizeof(basetype), NULL);
 
2289
        if (!SQL_SUCCEEDED(result))
 
2290
        {
 
2291
                SC_error_copy(stmt, col_stmt, TRUE);
 
2292
                goto cleanup;
 
2293
        }
 
2294
 
 
2295
        result = PGAPI_BindCol(hcol_stmt, 15, SQL_C_LONG,
 
2296
                                        &typmod, sizeof(typmod), NULL);
 
2297
        if (!SQL_SUCCEEDED(result))
 
2298
        {
 
2299
                SC_error_copy(stmt, col_stmt, TRUE);
 
2300
                goto cleanup;
 
2301
        }
 
2302
 
 
2303
        result = PGAPI_BindCol(hcol_stmt, 16, SQL_C_LONG,
 
2304
                                        &relhasoids, sizeof(relhasoids), NULL);
 
2305
        if (!SQL_SUCCEEDED(result))
 
2306
        {
 
2307
                SC_error_copy(stmt, col_stmt, TRUE);
 
2308
                goto cleanup;
 
2309
        }
 
2310
 
 
2311
        if (res = QR_Constructor(), !res)
 
2312
        {
 
2313
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Columns result.", func);
 
2314
                goto cleanup;
 
2315
        }
 
2316
        SC_set_Result(stmt, res);
 
2317
 
 
2318
        /* the binding structure for a statement is not set up until */
 
2319
 
 
2320
        /*
 
2321
         * a statement is actually executed, so we'll have to do this
 
2322
         * ourselves.
 
2323
         */
 
2324
        result_cols = NUM_OF_COLUMNS_FIELDS;
 
2325
        extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
2326
 
 
2327
        /*
 
2328
         * Setting catalog_result here affects the behavior of
 
2329
         * pgtype_xxx() functions. So set it later.
 
2330
         * stmt->catalog_result = TRUE;
 
2331
         */
 
2332
        /* set the field names */
 
2333
        QR_set_num_fields(res, result_cols);
 
2334
        QR_set_field_info_v(res, COLUMNS_CATALOG_NAME, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2335
        QR_set_field_info_v(res, COLUMNS_SCHEMA_NAME, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2336
        QR_set_field_info_v(res, COLUMNS_TABLE_NAME, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2337
        QR_set_field_info_v(res, COLUMNS_COLUMN_NAME, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2338
        QR_set_field_info_v(res, COLUMNS_DATA_TYPE, "DATA_TYPE", PG_TYPE_INT2, 2);
 
2339
        QR_set_field_info_v(res, COLUMNS_TYPE_NAME, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2340
        QR_set_field_info_v(res, COLUMNS_PRECISION, "PRECISION", PG_TYPE_INT4, 4); /* COLUMN_SIZE */
 
2341
        QR_set_field_info_v(res, COLUMNS_LENGTH, "LENGTH", PG_TYPE_INT4, 4); /* BUFFER_LENGTH */
 
2342
        QR_set_field_info_v(res, COLUMNS_SCALE, "SCALE", PG_TYPE_INT2, 2); /* DECIMAL_DIGITS ***/
 
2343
        QR_set_field_info_v(res, COLUMNS_RADIX, "RADIX", PG_TYPE_INT2, 2);
 
2344
        QR_set_field_info_v(res, COLUMNS_NULLABLE, "NULLABLE", PG_TYPE_INT2, 2);
 
2345
        QR_set_field_info_v(res, COLUMNS_REMARKS, "REMARKS", PG_TYPE_VARCHAR, INFO_VARCHAR_SIZE);
 
2346
 
 
2347
#if (ODBCVER >= 0x0300)
 
2348
        QR_set_field_info_v(res, COLUMNS_COLUMN_DEF, "COLUMN_DEF", PG_TYPE_VARCHAR, INFO_VARCHAR_SIZE);
 
2349
        QR_set_field_info_v(res, COLUMNS_SQL_DATA_TYPE, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
 
2350
        QR_set_field_info_v(res, COLUMNS_SQL_DATETIME_SUB, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
 
2351
        QR_set_field_info_v(res, COLUMNS_CHAR_OCTET_LENGTH, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
 
2352
        QR_set_field_info_v(res, COLUMNS_ORDINAL_POSITION, "ORDINAL_POSITION", PG_TYPE_INT4, 4);
 
2353
        QR_set_field_info_v(res, COLUMNS_IS_NULLABLE, "IS_NULLABLE", PG_TYPE_VARCHAR, INFO_VARCHAR_SIZE);
 
2354
#endif /* ODBCVER */
 
2355
        /* User defined fields */
 
2356
        QR_set_field_info_v(res, COLUMNS_DISPLAY_SIZE, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
 
2357
        QR_set_field_info_v(res, COLUMNS_FIELD_TYPE, "FIELD_TYPE", PG_TYPE_INT4, 4);
 
2358
        QR_set_field_info_v(res, COLUMNS_AUTO_INCREMENT, "AUTO_INCREMENT", PG_TYPE_INT4, 4);
 
2359
        QR_set_field_info_v(res, COLUMNS_PHYSICAL_NUMBER, "PHYSICAL NUMBER", PG_TYPE_INT2, 2);
 
2360
        QR_set_field_info_v(res, COLUMNS_TABLE_OID, "TABLE OID", PG_TYPE_OID, 4);
 
2361
        QR_set_field_info_v(res, COLUMNS_BASE_TYPEID, "BASE TYPEID", PG_TYPE_OID, 4);
 
2362
        QR_set_field_info_v(res, COLUMNS_ATTTYPMOD, "TYPMOD", PG_TYPE_INT4, 4);
 
2363
 
 
2364
        ordinal = 1;
 
2365
        result = PGAPI_Fetch(hcol_stmt);
 
2366
 
 
2367
        /*
 
2368
         * Only show oid if option AND there are other columns AND it's not
 
2369
         * being called by SQLStatistics . Always show OID if it's a system
 
2370
         * table
 
2371
         */
 
2372
 
 
2373
        if (PG_VERSION_GE(conn, 7.1))
 
2374
                relisaview = (relkind[0] == 'v');
 
2375
        else
 
2376
                relisaview = (relhasrules[0] == '1');
 
2377
        if (result != SQL_ERROR && !stmt->internal)
 
2378
        {
 
2379
                if (!relisaview &&
 
2380
                        relhasoids &&
 
2381
                        (atoi(ci->show_oid_column) ||
 
2382
                         strncmp(table_name, POSTGRES_SYS_PREFIX, strlen(POSTGRES_SYS_PREFIX)) == 0) &&
 
2383
                        (NULL == escColumnName ||
 
2384
                         0 == strcmp(escColumnName, OID_NAME)))
 
2385
                {
 
2386
                        /* For OID fields */
 
2387
                        the_type = PG_TYPE_OID;
 
2388
                        tuple = QR_AddNew(res);
 
2389
                        set_tuplefield_string(&tuple[COLUMNS_CATALOG_NAME], CurrCat(conn));
 
2390
                        /* see note in SQLTables() */
 
2391
                        if (conn->schema_support)
 
2392
                                set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], GET_SCHEMA_NAME(table_owner));
 
2393
                        else
 
2394
                                set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], NULL_STRING);
 
2395
                        set_tuplefield_string(&tuple[COLUMNS_TABLE_NAME], table_name);
 
2396
                        set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], OID_NAME);
 
2397
                        sqltype = pgtype_to_concise_type(stmt, the_type, PG_STATIC);
 
2398
                        set_tuplefield_int2(&tuple[COLUMNS_DATA_TYPE], sqltype);
 
2399
                        if (CC_fake_mss(conn))
 
2400
                        {
 
2401
                                set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], "OID identity");
 
2402
                                setIdentity = TRUE;
 
2403
                        }
 
2404
                        else
 
2405
                                set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], "OID");
 
2406
 
 
2407
                        set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2408
                        set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2409
                        set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
 
2410
                        set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(conn, the_type));
 
2411
                        set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], SQL_NO_NULLS);
 
2412
                        set_tuplefield_string(&tuple[COLUMNS_REMARKS], NULL_STRING);
 
2413
 
 
2414
#if (ODBCVER >= 0x0300)
 
2415
                        set_tuplefield_null(&tuple[COLUMNS_COLUMN_DEF]);
 
2416
                        set_tuplefield_int2(&tuple[COLUMNS_SQL_DATA_TYPE], sqltype);
 
2417
                        set_tuplefield_null(&tuple[COLUMNS_SQL_DATETIME_SUB]);
 
2418
                        set_tuplefield_null(&tuple[COLUMNS_CHAR_OCTET_LENGTH]);
 
2419
                        set_tuplefield_int4(&tuple[COLUMNS_ORDINAL_POSITION], ordinal);
 
2420
                        set_tuplefield_string(&tuple[COLUMNS_IS_NULLABLE], "No");
 
2421
#endif /* ODBCVER */
 
2422
                        set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_display_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2423
                        set_tuplefield_int4(&tuple[COLUMNS_FIELD_TYPE], the_type);
 
2424
                        set_tuplefield_int4(&tuple[COLUMNS_AUTO_INCREMENT], TRUE);
 
2425
                        set_tuplefield_int2(&tuple[COLUMNS_PHYSICAL_NUMBER], OID_ATTNUM);
 
2426
                        set_tuplefield_int4(&tuple[COLUMNS_TABLE_OID], greloid);
 
2427
                        set_tuplefield_int4(&tuple[COLUMNS_BASE_TYPEID], 0);
 
2428
                        set_tuplefield_int4(&tuple[COLUMNS_ATTTYPMOD], -1);
 
2429
                        ordinal++;
 
2430
                }
 
2431
        }
 
2432
 
 
2433
        while (SQL_SUCCEEDED(result))
 
2434
        {
 
2435
                int     auto_unique;
 
2436
                SQLLEN  len_needed;
 
2437
                char    *attdef;
 
2438
 
 
2439
                attdef = NULL;
 
2440
                PGAPI_SetPos(hcol_stmt, 1, SQL_POSITION, 0);
 
2441
                PGAPI_GetData(hcol_stmt, 13, internal_asis_type, NULL, 0, &len_needed);
 
2442
                if (len_needed > 0)
 
2443
                {
 
2444
mylog("len_needed=%d\n", len_needed);
 
2445
                        attdef = malloc(len_needed + 1);
 
2446
                        PGAPI_GetData(hcol_stmt, 13, internal_asis_type, attdef, len_needed + 1, &len_needed);
 
2447
mylog(" and the data=%s\n", attdef);
 
2448
                } 
 
2449
                tuple = QR_AddNew(res);
 
2450
 
 
2451
                sqltype = SQL_TYPE_NULL;        /* unspecified */
 
2452
                set_tuplefield_string(&tuple[COLUMNS_CATALOG_NAME], CurrCat(conn));
 
2453
                /* see note in SQLTables() */
 
2454
                if (conn->schema_support)
 
2455
                        set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], GET_SCHEMA_NAME(table_owner));
 
2456
                else
 
2457
                        set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], NULL_STRING);
 
2458
                set_tuplefield_string(&tuple[COLUMNS_TABLE_NAME], table_name);
 
2459
                set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], field_name);
 
2460
                auto_unique = SQL_FALSE;
 
2461
                if (field_type = pg_true_type(conn, field_type, basetype), field_type == basetype)
 
2462
                        mod_length = typmod;
 
2463
                switch (field_type)
 
2464
                {
 
2465
                        case PG_TYPE_OID:
 
2466
                                if (0 != atoi(ci->fake_oid_index))
 
2467
                                {
 
2468
                                        auto_unique = SQL_TRUE;
 
2469
                                        set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], "identity");
 
2470
                                        break;
 
2471
                                }
 
2472
                        case PG_TYPE_INT4:
 
2473
                        case PG_TYPE_INT8:
 
2474
                                if (attdef && strnicmp(attdef, "nextval(", 8) == 0 &&
 
2475
                                    not_null[0] != '0')
 
2476
                                {
 
2477
                                        auto_unique = SQL_TRUE;
 
2478
                                        if (!setIdentity &&
 
2479
                                            CC_fake_mss(conn))
 
2480
                                        {
 
2481
                                                char    tmp[32];
 
2482
 
 
2483
                                                snprintf(tmp, sizeof(tmp), "%s identity", field_type_name);
 
2484
                                                set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], tmp);
 
2485
                                                break;
 
2486
                                        }
 
2487
                                }
 
2488
                        default:
 
2489
                                set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], field_type_name);
 
2490
                                break;
 
2491
                }
 
2492
 
 
2493
                /*----------
 
2494
                 * Some Notes about Postgres Data Types:
 
2495
                 *
 
2496
                 * VARCHAR - the length is stored in the pg_attribute.atttypmod field
 
2497
                 * BPCHAR  - the length is also stored as varchar is
 
2498
                 *
 
2499
                 * NUMERIC - the decimal_digits is stored in atttypmod as follows:
 
2500
                 *
 
2501
                 *      column_size =((atttypmod - VARHDRSZ) >> 16) & 0xffff
 
2502
                 *      decimal_digits   = (atttypmod - VARHDRSZ) & 0xffff
 
2503
                 *
 
2504
                 *----------
 
2505
                 */
 
2506
                qlog("%s: table='%s',field_name='%s',type=%d,name='%s'\n",
 
2507
                         func, table_name, field_name, field_type, field_type_name);
 
2508
 
 
2509
#ifdef  USE_OLD_IMPL
 
2510
                useStaticPrecision = TRUE;
 
2511
                useStaticScale = TRUE;
 
2512
 
 
2513
                if (field_type == PG_TYPE_NUMERIC)
 
2514
                {
 
2515
                        if (mod_length >= 4)
 
2516
                                mod_length -= 4;        /* the length is in atttypmod - 4 */
 
2517
 
 
2518
                        if (mod_length >= 0)
 
2519
                        {
 
2520
                                useStaticPrecision = FALSE;
 
2521
                                useStaticScale = FALSE;
 
2522
 
 
2523
                                column_size = (mod_length >> 16) & 0xffff;
 
2524
                                decimal_digits = mod_length & 0xffff;
 
2525
 
 
2526
                                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);
 
2527
 
 
2528
                                set_tuplefield_int4(&tuple[COLUMNS_PRECISION], column_size);
 
2529
                                set_tuplefield_int4(&tuple[COLUMNS_LENGTH], column_size + 2);           /* sign+dec.point */
 
2530
                                set_nullfield_int2(&tuple[COLUMNS_SCALE], decimal_digits);
 
2531
#if (ODBCVER >= 0x0300)
 
2532
                                set_tuplefield_null(&tuple[COLUMNS_CHAR_OCTET_LENGTH]);
 
2533
#endif /* ODBCVER */
 
2534
                                set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], column_size + 2);     /* sign+dec.point */
 
2535
                        }
 
2536
                }
 
2537
                else if ((field_type == PG_TYPE_DATETIME) ||
 
2538
                        (field_type == PG_TYPE_TIMESTAMP_NO_TMZONE))
 
2539
                {
 
2540
                        if (PG_VERSION_GE(conn, 7.2))
 
2541
                        {
 
2542
                                useStaticScale = FALSE;
 
2543
 
 
2544
                                set_nullfield_int2(&tuple[COLUMNS_SCALE], (Int2) mod_length);
 
2545
                        }
 
2546
                }
 
2547
 
 
2548
                if ((field_type == PG_TYPE_VARCHAR) ||
 
2549
                        (field_type == PG_TYPE_BPCHAR))
 
2550
                {
 
2551
                        useStaticPrecision = FALSE;
 
2552
 
 
2553
                        if (mod_length >= 4)
 
2554
                                mod_length -= 4;        /* the length is in atttypmod - 4 */
 
2555
 
 
2556
                        /* if (mod_length > ci->drivers.max_varchar_size || mod_length <= 0) */
 
2557
                        if (mod_length <= 0)
 
2558
                                mod_length = ci->drivers.max_varchar_size;
 
2559
#ifdef  __MS_REPORTS_ANSI_CHAR__
 
2560
                        if (mod_length > ci->drivers.max_varchar_size)
 
2561
                                sqltype = SQL_LONGVARCHAR;
 
2562
                        else
 
2563
                                sqltype = (field_type == PG_TYPE_BPCHAR) ? SQL_CHAR : SQL_VARCHAR;
 
2564
#else
 
2565
                        if (mod_length > ci->drivers.max_varchar_size)
 
2566
                                sqltype = (ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR);
 
2567
                        else
 
2568
                                sqltype = (field_type == PG_TYPE_BPCHAR) ? (ALLOW_WCHAR(conn) ? SQL_WCHAR : SQL_CHAR) : (ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR);
 
2569
#endif /* __MS_LOVES_REPORTS_CHAR__ */
 
2570
 
 
2571
                        mylog("%s: field type is VARCHAR,BPCHAR: field_type = %d, mod_length = %d\n", func, field_type, mod_length);
 
2572
 
 
2573
                        set_tuplefield_int4(&tuple[COLUMNS_PRECISION], mod_length);
 
2574
                        field_length = mod_length;
 
2575
#ifdef  UNICODE_SUPPORT
 
2576
                        if (0 < field_length && ALLOW_WCHAR(conn))
 
2577
                                field_length *= WCLEN;
 
2578
#endif /* UNICODE_SUPPORT */
 
2579
                        set_tuplefield_int4(&tuple[COLUMNS_LENGTH], field_length);
 
2580
#if (ODBCVER >= 0x0300)
 
2581
                        set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_transfer_octet_length(conn, field_type, mod_length));
 
2582
#endif /* ODBCVER */
 
2583
                        set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], mod_length);
 
2584
                }
 
2585
 
 
2586
                if (useStaticPrecision)
 
2587
                {
 
2588
                        mylog("%s: field type is OTHER: field_type = %d, pgtype_length = %d\n", func, field_type, pgtype_buffer_length(stmt, field_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2589
 
 
2590
                        set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, field_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2591
                        set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, field_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2592
#if (ODBCVER >= 0x0300)
 
2593
                        set_tuplefield_null(&tuple[COLUMNS_CHAR_OCTET_LENGTH]);
 
2594
#endif /* ODBCVER */
 
2595
                        set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_display_size(stmt, field_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2596
                }
 
2597
                if (useStaticScale)
 
2598
                {
 
2599
                        set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, field_type, PG_STATIC));
 
2600
                }
 
2601
 
 
2602
                if (SQL_TYPE_NULL == sqltype)
 
2603
                {
 
2604
                        sqltype = pgtype_attr_to_concise_type(conn, field_type, mod_length, -1);
 
2605
                        concise_type = pgtype_attr_to_sqldesctype(conn, field_type, mod_length);
 
2606
                }
 
2607
                else
 
2608
                        concise_type = sqltype;
 
2609
#else /* USE_OLD_IMPL */
 
2610
                /* Subtract the header length */
 
2611
                switch (field_type)
 
2612
                {
 
2613
                        case PG_TYPE_DATETIME:
 
2614
                        case PG_TYPE_TIMESTAMP_NO_TMZONE:
 
2615
                        case PG_TYPE_TIME:
 
2616
                        case PG_TYPE_TIME_WITH_TMZONE:
 
2617
                        case PG_TYPE_BIT:
 
2618
                                break;
 
2619
                        default:
 
2620
                                if (mod_length >= 4)
 
2621
                                        mod_length -= 4;
 
2622
                }
 
2623
                set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_attr_column_size(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
 
2624
                set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_attr_buffer_length(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
 
2625
                set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_attr_display_size(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
 
2626
                set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_attr_decimal_digits(conn, field_type, mod_length, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
 
2627
 
 
2628
                sqltype = pgtype_attr_to_concise_type(conn, field_type, mod_length, PG_UNSPECIFIED);
 
2629
                concise_type = pgtype_attr_to_sqldesctype(conn, field_type, mod_length);
 
2630
#endif /* USE_OLD_IMPL */
 
2631
 
 
2632
                set_tuplefield_int2(&tuple[COLUMNS_DATA_TYPE], sqltype);
 
2633
 
 
2634
                set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(conn, field_type));
 
2635
                set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], (Int2) (not_null[0] != '0' ? SQL_NO_NULLS : pgtype_nullable(conn, field_type)));
 
2636
                set_tuplefield_string(&tuple[COLUMNS_REMARKS], NULL_STRING);
 
2637
#if (ODBCVER >= 0x0300)
 
2638
                if (attdef && strlen(attdef) > INFO_VARCHAR_SIZE)
 
2639
                        set_tuplefield_string(&tuple[COLUMNS_COLUMN_DEF], "TRUNCATE");
 
2640
                else
 
2641
                        set_tuplefield_string(&tuple[COLUMNS_COLUMN_DEF], attdef);
 
2642
                set_tuplefield_int2(&tuple[COLUMNS_SQL_DATA_TYPE], concise_type);
 
2643
                set_nullfield_int2(&tuple[COLUMNS_SQL_DATETIME_SUB], pgtype_attr_to_datetime_sub(conn, field_type, mod_length));
 
2644
                set_tuplefield_int4(&tuple[COLUMNS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, field_type, mod_length, UNKNOWNS_AS_DEFAULT));
 
2645
                set_tuplefield_int4(&tuple[COLUMNS_ORDINAL_POSITION], ordinal);
 
2646
                set_tuplefield_null(&tuple[COLUMNS_IS_NULLABLE]);
 
2647
#endif /* ODBCVER */
 
2648
                set_tuplefield_int4(&tuple[COLUMNS_FIELD_TYPE], field_type);
 
2649
                set_tuplefield_int4(&tuple[COLUMNS_AUTO_INCREMENT], auto_unique);
 
2650
                set_tuplefield_int2(&tuple[COLUMNS_PHYSICAL_NUMBER], field_number);
 
2651
                set_tuplefield_int4(&tuple[COLUMNS_TABLE_OID], greloid);
 
2652
                set_tuplefield_int4(&tuple[COLUMNS_BASE_TYPEID], basetype);
 
2653
                set_tuplefield_int4(&tuple[COLUMNS_ATTTYPMOD], mod_length);
 
2654
                ordinal++;
 
2655
 
 
2656
                result = PGAPI_Fetch(hcol_stmt);
 
2657
                if (attdef)
 
2658
                        free(attdef);
 
2659
        }
 
2660
        if (result != SQL_NO_DATA_FOUND)
 
2661
        {
 
2662
                SC_full_error_copy(stmt, col_stmt, FALSE);
 
2663
                goto cleanup;
 
2664
        }
 
2665
 
 
2666
        /*
 
2667
         * Put the row version column at the end so it might not be mistaken
 
2668
         * for a key field.
 
2669
         */
 
2670
        if (!relisaview && !stmt->internal && atoi(ci->row_versioning))
 
2671
        {
 
2672
                /* For Row Versioning fields */
 
2673
                the_type = PG_TYPE_INT4;
 
2674
 
 
2675
                tuple = QR_AddNew(res);
 
2676
 
 
2677
                set_tuplefield_string(&tuple[COLUMNS_CATALOG_NAME], CurrCat(conn));
 
2678
                if (conn->schema_support)
 
2679
                        set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], GET_SCHEMA_NAME(table_owner));
 
2680
                else
 
2681
                        set_tuplefield_string(&tuple[COLUMNS_SCHEMA_NAME], NULL_STRING);
 
2682
                set_tuplefield_string(&tuple[COLUMNS_TABLE_NAME], table_name);
 
2683
                set_tuplefield_string(&tuple[COLUMNS_COLUMN_NAME], "xmin");
 
2684
                sqltype = pgtype_to_concise_type(stmt, the_type, PG_STATIC);
 
2685
                set_tuplefield_int2(&tuple[COLUMNS_DATA_TYPE], sqltype);
 
2686
                set_tuplefield_string(&tuple[COLUMNS_TYPE_NAME], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, FALSE));
 
2687
                set_tuplefield_int4(&tuple[COLUMNS_PRECISION], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2688
                set_tuplefield_int4(&tuple[COLUMNS_LENGTH], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2689
                set_nullfield_int2(&tuple[COLUMNS_SCALE], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
 
2690
                set_nullfield_int2(&tuple[COLUMNS_RADIX], pgtype_radix(conn, the_type));
 
2691
                set_tuplefield_int2(&tuple[COLUMNS_NULLABLE], SQL_NO_NULLS);
 
2692
                set_tuplefield_string(&tuple[COLUMNS_REMARKS], NULL_STRING);
 
2693
#if (ODBCVER >= 0x0300)
 
2694
                set_tuplefield_null(&tuple[COLUMNS_COLUMN_DEF]);
 
2695
                set_tuplefield_int2(&tuple[COLUMNS_SQL_DATA_TYPE], sqltype);
 
2696
                set_tuplefield_null(&tuple[COLUMNS_SQL_DATETIME_SUB]);
 
2697
                set_tuplefield_null(&tuple[COLUMNS_CHAR_OCTET_LENGTH]);
 
2698
                set_tuplefield_int4(&tuple[COLUMNS_ORDINAL_POSITION], ordinal);
 
2699
                set_tuplefield_string(&tuple[COLUMNS_IS_NULLABLE], "No");
 
2700
#endif /* ODBCVER */
 
2701
                set_tuplefield_int4(&tuple[COLUMNS_DISPLAY_SIZE], pgtype_display_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2702
                set_tuplefield_int4(&tuple[COLUMNS_FIELD_TYPE], the_type);
 
2703
                set_tuplefield_int4(&tuple[COLUMNS_AUTO_INCREMENT], FALSE);
 
2704
                set_tuplefield_int2(&tuple[COLUMNS_PHYSICAL_NUMBER], XMIN_ATTNUM);
 
2705
                set_tuplefield_int4(&tuple[COLUMNS_TABLE_OID], greloid);
 
2706
                set_tuplefield_int4(&tuple[COLUMNS_BASE_TYPEID], 0);
 
2707
                set_tuplefield_int4(&tuple[COLUMNS_ATTTYPMOD], -1);
 
2708
                ordinal++;
 
2709
        }
 
2710
        result = SQL_SUCCESS;
 
2711
 
 
2712
cleanup:
 
2713
#undef  return
 
2714
        /*
 
2715
         * also, things need to think that this statement is finished so the
 
2716
         * results can be retrieved.
 
2717
         */
 
2718
        stmt->status = STMT_FINISHED;
 
2719
        stmt->catalog_result = TRUE;
 
2720
 
 
2721
        /* set up the current tuple pointer for SQLFetch */
 
2722
        stmt->currTuple = -1;
 
2723
        SC_set_rowset_start(stmt, -1, FALSE);
 
2724
        SC_set_current_col(stmt, -1);
 
2725
 
 
2726
        if (escSchemaName)
 
2727
                free(escSchemaName);
 
2728
        if (escTableName)
 
2729
                free(escTableName);
 
2730
        if (escColumnName)
 
2731
                free(escColumnName);
 
2732
        if (hcol_stmt)
 
2733
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2734
        if (stmt->internal)
 
2735
                result = DiscardStatementSvp(stmt, result, FALSE);
 
2736
        mylog("%s: EXIT,  stmt=%p\n", func, stmt);
 
2737
        return result;
 
2738
}
 
2739
 
 
2740
 
 
2741
RETCODE         SQL_API
 
2742
PGAPI_SpecialColumns(
 
2743
                                HSTMT hstmt,
 
2744
                                SQLUSMALLINT fColType,
 
2745
                                const SQLCHAR FAR * szTableQualifier,
 
2746
                                SQLSMALLINT cbTableQualifier,
 
2747
                                const SQLCHAR FAR * szTableOwner, /* OA E*/
 
2748
                                SQLSMALLINT cbTableOwner,
 
2749
                                const SQLCHAR FAR * szTableName, /* OA(R) E*/
 
2750
                                SQLSMALLINT cbTableName,
 
2751
                                SQLUSMALLINT fScope,
 
2752
                                SQLUSMALLINT fNullable)
 
2753
{
 
2754
        CSTR func = "PGAPI_SpecialColumns";
 
2755
        TupleField      *tuple;
 
2756
        StatementClass *stmt = (StatementClass *) hstmt;
 
2757
        ConnectionClass *conn;
 
2758
        QResultClass    *res;
 
2759
        HSTMT           hcol_stmt = NULL;
 
2760
        StatementClass *col_stmt;
 
2761
        char            columns_query[INFO_INQUIRY_LEN];
 
2762
        char            *escSchemaName = NULL, *escTableName = NULL;
 
2763
        RETCODE         result = SQL_SUCCESS;
 
2764
        char            relhasrules[MAX_INFO_STRING], relkind[8], relhasoids[8];
 
2765
        BOOL            relisaview;
 
2766
        SQLSMALLINT     internal_asis_type = SQL_C_CHAR, cbSchemaName;
 
2767
        const char      *szSchemaName, *eq_string;
 
2768
 
 
2769
        mylog("%s: entering...stmt=%p scnm=%p len=%d colType=%d scope=%d\n", func, stmt, szTableOwner, cbTableOwner, fColType, fScope);
 
2770
 
 
2771
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
 
2772
                return result;
 
2773
        conn = SC_get_conn(stmt);
 
2774
#ifdef  UNICODE_SUPPORT
 
2775
        if (CC_is_in_unicode_driver(conn))
 
2776
                internal_asis_type = INTERNAL_ASIS_TYPE;
 
2777
#endif /* UNICODE_SUPPORT */
 
2778
 
 
2779
        szSchemaName = szTableOwner;
 
2780
        cbSchemaName = cbTableOwner;
 
2781
 
 
2782
        escTableName = simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
 
2783
        if (!escTableName)
 
2784
        {
 
2785
                SC_set_error(stmt, STMT_INVALID_NULL_ARG, "The table name is required", func);
 
2786
                return SQL_ERROR;
 
2787
        }
 
2788
#define return  DONT_CALL_RETURN_FROM_HERE???
 
2789
 
 
2790
retry_public_schema:
 
2791
        if (escSchemaName)
 
2792
                free(escSchemaName);
 
2793
        escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn);
 
2794
        eq_string = gen_opestr(eqop, conn);
 
2795
        /*
 
2796
         * Create the query to find out if this is a view or not...
 
2797
         */
 
2798
        strcpy(columns_query, "select c.relhasrules, c.relkind");
 
2799
        if (PG_VERSION_GE(conn, 7.2))
 
2800
                strcat(columns_query, ", c.relhasoids");
 
2801
        if (conn->schema_support)
 
2802
                strcat(columns_query, " from pg_catalog.pg_namespace u,"
 
2803
                " pg_catalog.pg_class c where "
 
2804
                        "u.oid = c.relnamespace");
 
2805
        else
 
2806
                strcat(columns_query, " from pg_user u, pg_class c where "
 
2807
                        "u.usesysid = c.relowner");
 
2808
 
 
2809
        /* TableName cannot contain a string search pattern */
 
2810
        /* my_strcat(columns_query, " and c.relname = '%.*s'", szTableName, cbTableName); */
 
2811
        if (escTableName)
 
2812
                snprintf_add(columns_query, sizeof(columns_query), " and c.relname %s'%s'", eq_string, escTableName);
 
2813
        /* SchemaName cannot contain a string search pattern */
 
2814
        if (conn->schema_support)
 
2815
                schema_strcat1(columns_query, " and u.nspname %s'%.*s'", eq_string, escSchemaName, SQL_NTS, szTableName, cbTableName, conn);
 
2816
        else
 
2817
                my_strcat1(columns_query, " and u.usename %s'%.*s'", eq_string, escSchemaName, SQL_NTS);
 
2818
 
 
2819
 
 
2820
        result = PGAPI_AllocStmt(conn, &hcol_stmt, 0);
 
2821
        if (!SQL_SUCCEEDED(result))
 
2822
        {
 
2823
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for SQLSpecialColumns result.", func);
 
2824
                result = SQL_ERROR;
 
2825
                goto cleanup;
 
2826
        }
 
2827
        col_stmt = (StatementClass *) hcol_stmt;
 
2828
 
 
2829
        mylog("%s: hcol_stmt = %p, col_stmt = %p\n", func, hcol_stmt, col_stmt);
 
2830
 
 
2831
        result = PGAPI_ExecDirect(hcol_stmt, columns_query, SQL_NTS, 0);
 
2832
        if (!SQL_SUCCEEDED(result))
 
2833
        {
 
2834
                SC_full_error_copy(stmt, col_stmt, FALSE);
 
2835
                result = SQL_ERROR;
 
2836
                goto cleanup;
 
2837
        }
 
2838
 
 
2839
        /* If not found */
 
2840
        if (conn->schema_support &&
 
2841
            (res = SC_get_Result(col_stmt)) &&
 
2842
            0 == QR_get_num_total_tuples(res))
 
2843
        {
 
2844
                if (allow_public_schema(conn, szSchemaName, cbSchemaName))
 
2845
                {
 
2846
                        PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2847
                        hcol_stmt = NULL;
 
2848
                        szSchemaName = pubstr;
 
2849
                        cbSchemaName = SQL_NTS;
 
2850
                        goto retry_public_schema;
 
2851
                }
 
2852
        }
 
2853
 
 
2854
        result = PGAPI_BindCol(hcol_stmt, 1, internal_asis_type,
 
2855
                                        relhasrules, sizeof(relhasrules), NULL);
 
2856
        if (!SQL_SUCCEEDED(result))
 
2857
        {
 
2858
                SC_error_copy(stmt, col_stmt, TRUE);
 
2859
                result = SQL_ERROR;
 
2860
                goto cleanup;
 
2861
        }
 
2862
 
 
2863
        result = PGAPI_BindCol(hcol_stmt, 2, internal_asis_type,
 
2864
                                        relkind, sizeof(relkind), NULL);
 
2865
        if (!SQL_SUCCEEDED(result))
 
2866
        {
 
2867
                SC_error_copy(stmt, col_stmt, TRUE);
 
2868
                result = SQL_ERROR;
 
2869
                goto cleanup;
 
2870
        }
 
2871
        relhasoids[0] = '1';
 
2872
        if (PG_VERSION_GE(conn, 7.2))
 
2873
        {
 
2874
                result = PGAPI_BindCol(hcol_stmt, 3, internal_asis_type,
 
2875
                                        relhasoids, sizeof(relhasoids), NULL);
 
2876
                if (!SQL_SUCCEEDED(result))
 
2877
                {
 
2878
                        SC_error_copy(stmt, col_stmt, TRUE);
 
2879
                        result = SQL_ERROR;
 
2880
                        goto cleanup;
 
2881
                }
 
2882
        }
 
2883
 
 
2884
        result = PGAPI_Fetch(hcol_stmt);
 
2885
        if (PG_VERSION_GE(conn, 7.1))
 
2886
                relisaview = (relkind[0] == 'v');
 
2887
        else
 
2888
                relisaview = (relhasrules[0] == '1');
 
2889
        PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2890
        hcol_stmt = NULL;
 
2891
 
 
2892
        res = QR_Constructor();
 
2893
        SC_set_Result(stmt, res);
 
2894
        extend_column_bindings(SC_get_ARDF(stmt), 8);
 
2895
 
 
2896
        stmt->catalog_result = TRUE;
 
2897
        QR_set_num_fields(res, 8);
 
2898
        QR_set_field_info_v(res, 0, "SCOPE", PG_TYPE_INT2, 2);
 
2899
        QR_set_field_info_v(res, 1, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2900
        QR_set_field_info_v(res, 2, "DATA_TYPE", PG_TYPE_INT2, 2);
 
2901
        QR_set_field_info_v(res, 3, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
2902
        QR_set_field_info_v(res, 4, "PRECISION", PG_TYPE_INT4, 4);
 
2903
        QR_set_field_info_v(res, 5, "LENGTH", PG_TYPE_INT4, 4);
 
2904
        QR_set_field_info_v(res, 6, "SCALE", PG_TYPE_INT2, 2);
 
2905
        QR_set_field_info_v(res, 7, "PSEUDO_COLUMN", PG_TYPE_INT2, 2);
 
2906
 
 
2907
        if (relisaview)
 
2908
        {
 
2909
                /* there's no oid for views */
 
2910
                if (fColType == SQL_BEST_ROWID)
 
2911
                {
 
2912
                        goto cleanup;
 
2913
                }
 
2914
                else if (fColType == SQL_ROWVER)
 
2915
                {
 
2916
                        Int2            the_type = PG_TYPE_TID;
 
2917
 
 
2918
                        tuple = QR_AddNew(res);
 
2919
 
 
2920
                        set_tuplefield_null(&tuple[0]);
 
2921
                        set_tuplefield_string(&tuple[1], "ctid");
 
2922
                        set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
 
2923
                        set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, FALSE));
 
2924
                        set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2925
                        set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2926
                        set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
 
2927
                        set_tuplefield_int2(&tuple[7], SQL_PC_NOT_PSEUDO);
 
2928
inolog("Add ctid\n");
 
2929
                }
 
2930
        }
 
2931
        else
 
2932
        {
 
2933
                /* use the oid value for the rowid */
 
2934
                if (fColType == SQL_BEST_ROWID)
 
2935
                {
 
2936
                        Int2    the_type = PG_TYPE_OID;
 
2937
 
 
2938
                        if (relhasoids[0] != '1')
 
2939
                        {
 
2940
                                goto cleanup;
 
2941
                        }
 
2942
                        tuple = QR_AddNew(res);
 
2943
 
 
2944
                        set_tuplefield_int2(&tuple[0], SQL_SCOPE_SESSION);
 
2945
                        set_tuplefield_string(&tuple[1], OID_NAME);
 
2946
                        set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
 
2947
                        set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, TRUE));
 
2948
                        set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2949
                        set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2950
                        set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
 
2951
                        set_tuplefield_int2(&tuple[7], SQL_PC_PSEUDO);
 
2952
                }
 
2953
                else if (fColType == SQL_ROWVER)
 
2954
                {
 
2955
                        Int2            the_type = PG_TYPE_XID;
 
2956
 
 
2957
                        tuple = QR_AddNew(res);
 
2958
 
 
2959
                        set_tuplefield_null(&tuple[0]);
 
2960
                        set_tuplefield_string(&tuple[1], "xmin");
 
2961
                        set_tuplefield_int2(&tuple[2], pgtype_to_concise_type(stmt, the_type, PG_STATIC));
 
2962
                        set_tuplefield_string(&tuple[3], pgtype_to_name(stmt, the_type, PG_UNSPECIFIED, FALSE));
 
2963
                        set_tuplefield_int4(&tuple[4], pgtype_column_size(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2964
                        set_tuplefield_int4(&tuple[5], pgtype_buffer_length(stmt, the_type, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
2965
                        set_tuplefield_int2(&tuple[6], pgtype_decimal_digits(stmt, the_type, PG_STATIC));
 
2966
                        set_tuplefield_int2(&tuple[7], SQL_PC_PSEUDO);
 
2967
                }
 
2968
        }
 
2969
 
 
2970
cleanup:
 
2971
#undef  return
 
2972
        if (escSchemaName)
 
2973
                free(escSchemaName);
 
2974
        if (escTableName)
 
2975
                free(escTableName);
 
2976
        stmt->status = STMT_FINISHED;
 
2977
        stmt->currTuple = -1;
 
2978
        SC_set_rowset_start(stmt, -1, FALSE);
 
2979
        SC_set_current_col(stmt, -1);
 
2980
        if (hcol_stmt)
 
2981
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
2982
        if (stmt->internal)
 
2983
                result = DiscardStatementSvp(stmt, result, FALSE);
 
2984
        mylog("%s: EXIT,  stmt=%p\n", func, stmt);
 
2985
        return result;
 
2986
}
 
2987
 
 
2988
 
 
2989
#define INDOPTION_DESC          0x0001  /* values are in reverse order */
 
2990
RETCODE         SQL_API
 
2991
PGAPI_Statistics(
 
2992
                        HSTMT hstmt,
 
2993
                        const SQLCHAR FAR * szTableQualifier, /* OA X*/
 
2994
                        SQLSMALLINT cbTableQualifier,
 
2995
                        const SQLCHAR FAR * szTableOwner, /* OA E*/
 
2996
                        SQLSMALLINT cbTableOwner,
 
2997
                        const SQLCHAR FAR * szTableName, /* OA(R) E*/
 
2998
                        SQLSMALLINT cbTableName,
 
2999
                        SQLUSMALLINT fUnique,
 
3000
                        SQLUSMALLINT fAccuracy)
 
3001
{
 
3002
        CSTR func = "PGAPI_Statistics";
 
3003
        StatementClass *stmt = (StatementClass *) hstmt;
 
3004
        ConnectionClass *conn;
 
3005
        QResultClass    *res;
 
3006
        char            index_query[INFO_INQUIRY_LEN];
 
3007
        HSTMT           hcol_stmt = NULL, hindx_stmt = NULL;
 
3008
        RETCODE         ret = SQL_ERROR, result;
 
3009
        char            *escSchemaName = NULL, *table_name = NULL, *escTableName = NULL;
 
3010
        char            index_name[MAX_INFO_STRING];
 
3011
        short           fields_vector[INDEX_KEYS_STORAGE_COUNT + 1];
 
3012
        short           indopt_vector[INDEX_KEYS_STORAGE_COUNT + 1];
 
3013
        char            isunique[10],
 
3014
                                isclustered[10],
 
3015
                                ishash[MAX_INFO_STRING];
 
3016
        SQLLEN          index_name_len, fields_vector_len;
 
3017
        TupleField      *tuple;
 
3018
        int                     i;
 
3019
        StatementClass *col_stmt,
 
3020
                           *indx_stmt;
 
3021
        char            column_name[MAX_INFO_STRING],
 
3022
                        table_schemaname[MAX_INFO_STRING],
 
3023
                                relhasrules[10];
 
3024
        struct columns_idx {
 
3025
                int     pnum;
 
3026
                char    *col_name;
 
3027
        } *column_names = NULL;
 
3028
        /* char   **column_names = NULL; */
 
3029
        SQLLEN          column_name_len;
 
3030
        int             total_columns = 0, alcount;
 
3031
        ConnInfo   *ci;
 
3032
        char            buf[256];
 
3033
        SQLSMALLINT     internal_asis_type = SQL_C_CHAR, cbSchemaName, field_number;
 
3034
        const char      *szSchemaName, *eq_string;
 
3035
        OID             ioid;
 
3036
        Int4            relhasoids;
 
3037
 
 
3038
        mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func, stmt, szTableOwner, cbTableOwner);
 
3039
 
 
3040
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
 
3041
                return result;
 
3042
 
 
3043
        table_name = make_string(szTableName, cbTableName, NULL, 0);
 
3044
        if (!table_name)
 
3045
        {
 
3046
                SC_set_error(stmt, STMT_INVALID_NULL_ARG, "The table name is required", func);
 
3047
                return result;
 
3048
        }
 
3049
        conn = SC_get_conn(stmt);
 
3050
        ci = &(conn->connInfo);
 
3051
#ifdef  UNICODE_SUPPORT
 
3052
        if (CC_is_in_unicode_driver(conn))
 
3053
                internal_asis_type = INTERNAL_ASIS_TYPE;
 
3054
#endif /* UNICODE_SUPPORT */
 
3055
 
 
3056
        if (res = QR_Constructor(), !res)
 
3057
        {
 
3058
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_Statistics result.", func);
 
3059
                return SQL_ERROR;
 
3060
        }
 
3061
        SC_set_Result(stmt, res);
 
3062
 
 
3063
        /* the binding structure for a statement is not set up until */
 
3064
 
 
3065
        /*
 
3066
         * a statement is actually executed, so we'll have to do this
 
3067
         * ourselves.
 
3068
         */
 
3069
        extend_column_bindings(SC_get_ARDF(stmt), 13);
 
3070
 
 
3071
        stmt->catalog_result = TRUE;
 
3072
        /* set the field names */
 
3073
        QR_set_num_fields(res, NUM_OF_STATS_FIELDS);
 
3074
        QR_set_field_info_v(res, STATS_CATALOG_NAME, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3075
        QR_set_field_info_v(res, STATS_SCHEMA_NAME, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3076
        QR_set_field_info_v(res, STATS_TABLE_NAME, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3077
        QR_set_field_info_v(res, STATS_NON_UNIQUE, "NON_UNIQUE", PG_TYPE_INT2, 2);
 
3078
        QR_set_field_info_v(res, STATS_INDEX_QUALIFIER, "INDEX_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3079
        QR_set_field_info_v(res, STATS_INDEX_NAME, "INDEX_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3080
        QR_set_field_info_v(res, STATS_TYPE, "TYPE", PG_TYPE_INT2, 2);
 
3081
        QR_set_field_info_v(res, STATS_SEQ_IN_INDEX, "SEQ_IN_INDEX", PG_TYPE_INT2, 2);
 
3082
        QR_set_field_info_v(res, STATS_COLUMN_NAME, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3083
        QR_set_field_info_v(res, STATS_COLLATION, "COLLATION", PG_TYPE_CHAR, 1);
 
3084
        QR_set_field_info_v(res, STATS_CARDINALITY, "CARDINALITY", PG_TYPE_INT4, 4);
 
3085
        QR_set_field_info_v(res, STATS_PAGES, "PAGES", PG_TYPE_INT4, 4);
 
3086
        QR_set_field_info_v(res, STATS_FILTER_CONDITION, "FILTER_CONDITION", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3087
 
 
3088
#define return  DONT_CALL_RETURN_FROM_HERE???
 
3089
        szSchemaName = szTableOwner;
 
3090
        cbSchemaName = cbTableOwner;
 
3091
 
 
3092
        table_schemaname[0] = '\0';
 
3093
        if (conn->schema_support)
 
3094
                schema_strcat(table_schemaname, "%.*s", szSchemaName, cbSchemaName, szTableName, cbTableName, conn);
 
3095
 
 
3096
        /*
 
3097
         * we need to get a list of the field names first, so we can return
 
3098
         * them later.
 
3099
         */
 
3100
        result = PGAPI_AllocStmt(conn, &hcol_stmt, 0);
 
3101
        if (!SQL_SUCCEEDED(result))
 
3102
        {
 
3103
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in PGAPI_Statistics for columns.", func);
 
3104
                goto cleanup;
 
3105
        }
 
3106
 
 
3107
        col_stmt = (StatementClass *) hcol_stmt;
 
3108
 
 
3109
        /*
 
3110
         * "internal" prevents SQLColumns from returning the oid if it is
 
3111
         * being shown. This would throw everything off.
 
3112
         */
 
3113
        col_stmt->internal = TRUE;
 
3114
        /* 
 
3115
         * table_name parameter cannot contain a string search pattern. 
 
3116
         */
 
3117
        result = PGAPI_Columns(hcol_stmt, NULL, 0, table_schemaname, SQL_NTS,
 
3118
                                table_name, SQL_NTS, NULL, 0, PODBC_NOT_SEARCH_PATTERN | PODBC_SEARCH_PUBLIC_SCHEMA, 0, 0);
 
3119
        col_stmt->internal = FALSE;
 
3120
 
 
3121
        if (!SQL_SUCCEEDED(result))
 
3122
        {
 
3123
                SC_error_copy(stmt, col_stmt, TRUE);
 
3124
                goto cleanup;
 
3125
        }
 
3126
        result = PGAPI_BindCol(hcol_stmt, COLUMNS_COLUMN_NAME + 1, internal_asis_type,
 
3127
                                                 column_name, sizeof(column_name), &column_name_len);
 
3128
        if (!SQL_SUCCEEDED(result))
 
3129
        {
 
3130
                SC_error_copy(stmt, col_stmt, TRUE);
 
3131
                goto cleanup;
 
3132
        }
 
3133
        result = PGAPI_BindCol(hcol_stmt, COLUMNS_PHYSICAL_NUMBER + 1, SQL_C_SHORT,
 
3134
                        &field_number, sizeof(field_number), NULL);
 
3135
        if (!SQL_SUCCEEDED(result))
 
3136
        {
 
3137
                SC_error_copy(stmt, col_stmt, TRUE);
 
3138
                goto cleanup;
 
3139
        }
 
3140
 
 
3141
        alcount = 0;
 
3142
        result = PGAPI_Fetch(hcol_stmt);
 
3143
        while (SQL_SUCCEEDED(result))
 
3144
        {
 
3145
                if (0 == total_columns)
 
3146
                        PGAPI_GetData(hcol_stmt, 2, internal_asis_type, table_schemaname, sizeof(table_schemaname), NULL);
 
3147
 
 
3148
                if (total_columns >= alcount)
 
3149
                {
 
3150
                        if (0 == alcount)
 
3151
                                alcount = 4;
 
3152
                        else
 
3153
                                alcount *= 2;
 
3154
                        column_names =
 
3155
                                (struct columns_idx *) realloc(column_names,
 
3156
                                                          alcount * sizeof(struct columns_idx));
 
3157
                }
 
3158
                column_names[total_columns].col_name =
 
3159
                        (char *) malloc(strlen(column_name) + 1);
 
3160
                strcpy(column_names[total_columns].col_name, column_name);
 
3161
                column_names[total_columns].pnum = field_number;
 
3162
                total_columns++;
 
3163
 
 
3164
                mylog("%s: column_name = '%s'\n", func, column_name);
 
3165
 
 
3166
                result = PGAPI_Fetch(hcol_stmt);
 
3167
        }
 
3168
 
 
3169
        if (result != SQL_NO_DATA_FOUND)
 
3170
        {
 
3171
                SC_full_error_copy(stmt, col_stmt, FALSE);
 
3172
                goto cleanup;
 
3173
        }
 
3174
        PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
3175
        hcol_stmt = NULL;
 
3176
        if (total_columns == 0)
 
3177
        {
 
3178
                /* Couldn't get column names in SQLStatistics.; */
 
3179
                ret = SQL_SUCCESS;
 
3180
                goto cleanup;
 
3181
        }
 
3182
 
 
3183
        /* get a list of indexes on this table */
 
3184
        result = PGAPI_AllocStmt(conn, &hindx_stmt, 0);
 
3185
        if (!SQL_SUCCEEDED(result))
 
3186
        {
 
3187
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in SQLStatistics for indices.", func);
 
3188
                goto cleanup;
 
3189
 
 
3190
        }
 
3191
        indx_stmt = (StatementClass *) hindx_stmt;
 
3192
 
 
3193
        /* TableName cannot contain a string search pattern */
 
3194
        escTableName = simpleCatalogEscape(table_name, SQL_NTS, NULL, conn);
 
3195
        eq_string = gen_opestr(eqop, conn); 
 
3196
        if (conn->schema_support)
 
3197
        {
 
3198
                escSchemaName = simpleCatalogEscape(table_schemaname, SQL_NTS, NULL, conn); 
 
3199
                snprintf(index_query, sizeof(index_query), "select c.relname, i.indkey, i.indisunique"
 
3200
                        ", i.indisclustered, a.amname, c.relhasrules, n.nspname"
 
3201
                        ", c.oid, %s, %s"
 
3202
                        " from pg_catalog.pg_index i, pg_catalog.pg_class c,"
 
3203
                        " pg_catalog.pg_class d, pg_catalog.pg_am a,"
 
3204
                        " pg_catalog.pg_namespace n"
 
3205
                        " where d.relname %s'%s'"
 
3206
                        " and n.nspname %s'%s'"
 
3207
                        " and n.oid = d.relnamespace"
 
3208
                        " and d.oid = i.indrelid"
 
3209
                        " and i.indexrelid = c.oid"
 
3210
                        " and c.relam = a.oid order by"
 
3211
                        , PG_VERSION_GE(conn, 7.2) ? "d.relhasoids" : "1"
 
3212
                        , PG_VERSION_GE(conn, 8.3) ? "i.indoption" : "0"
 
3213
                        , eq_string, escTableName, eq_string, escSchemaName);
 
3214
        }
 
3215
        else
 
3216
                snprintf(index_query, sizeof(index_query), "select c.relname, i.indkey, i.indisunique"
 
3217
                        ", i.indisclustered, a.amname, c.relhasrules, c.oid, %s, 0"
 
3218
                        " from pg_index i, pg_class c, pg_class d, pg_am a"
 
3219
                        " where d.relname %s'%s'"
 
3220
                        " and d.oid = i.indrelid"
 
3221
                        " and i.indexrelid = c.oid"
 
3222
                        " and c.relam = a.oid order by"
 
3223
                        , PG_VERSION_GE(conn, 7.2) ? "d.relhasoids" : "1"
 
3224
                        , eq_string, escTableName);
 
3225
        if (PG_VERSION_GT(SC_get_conn(stmt), 6.4))
 
3226
                strcat(index_query, " i.indisprimary desc,");
 
3227
        if (conn->schema_support)
 
3228
                strcat(index_query, " i.indisunique, n.nspname, c.relname");
 
3229
        else
 
3230
                strcat(index_query, " i.indisunique, c.relname");
 
3231
 
 
3232
        result = PGAPI_ExecDirect(hindx_stmt, index_query, SQL_NTS, 0);
 
3233
        if (!SQL_SUCCEEDED(result))
 
3234
        {
 
3235
                /*
 
3236
                 * "Couldn't execute index query (w/SQLExecDirect) in
 
3237
                 * SQLStatistics.";
 
3238
                 */
 
3239
                SC_full_error_copy(stmt, indx_stmt, FALSE);
 
3240
                goto cleanup;
 
3241
        }
 
3242
 
 
3243
        /* bind the index name column */
 
3244
        result = PGAPI_BindCol(hindx_stmt, 1, internal_asis_type,
 
3245
                                                   index_name, MAX_INFO_STRING, &index_name_len);
 
3246
        if (!SQL_SUCCEEDED(result))
 
3247
        {
 
3248
                SC_error_copy(stmt, indx_stmt, TRUE);   /* "Couldn't bind column 
 
3249
                                                * in SQLStatistics."; */
 
3250
                goto cleanup;
 
3251
 
 
3252
        }
 
3253
        /* bind the vector column */
 
3254
        result = PGAPI_BindCol(hindx_stmt, 2, SQL_C_DEFAULT,
 
3255
                        fields_vector, sizeof(fields_vector), &fields_vector_len);
 
3256
        if (!SQL_SUCCEEDED(result))
 
3257
        {
 
3258
                SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column 
 
3259
                                                 * in SQLStatistics."; */
 
3260
                goto cleanup;
 
3261
 
 
3262
        }
 
3263
        /* bind the "is unique" column */
 
3264
        result = PGAPI_BindCol(hindx_stmt, 3, internal_asis_type,
 
3265
                                                   isunique, sizeof(isunique), NULL);
 
3266
        if (!SQL_SUCCEEDED(result))
 
3267
        {
 
3268
                SC_error_copy(stmt, indx_stmt, TRUE);   /* "Couldn't bind column 
 
3269
                                                 * in SQLStatistics."; */
 
3270
                goto cleanup;
 
3271
        }
 
3272
 
 
3273
        /* bind the "is clustered" column */
 
3274
        result = PGAPI_BindCol(hindx_stmt, 4, internal_asis_type,
 
3275
                                                   isclustered, sizeof(isclustered), NULL);
 
3276
        if (!SQL_SUCCEEDED(result))
 
3277
        {
 
3278
                SC_error_copy(stmt, indx_stmt, TRUE);   /* "Couldn't bind column *
 
3279
                                                 * in SQLStatistics."; */
 
3280
                goto cleanup;
 
3281
 
 
3282
        }
 
3283
 
 
3284
        /* bind the "is hash" column */
 
3285
        result = PGAPI_BindCol(hindx_stmt, 5, internal_asis_type,
 
3286
                                                   ishash, sizeof(ishash), NULL);
 
3287
        if (!SQL_SUCCEEDED(result))
 
3288
        {
 
3289
                SC_error_copy(stmt, indx_stmt, TRUE);   /* "Couldn't bind column * 
 
3290
                                                 * in SQLStatistics."; */
 
3291
                goto cleanup;
 
3292
 
 
3293
        }
 
3294
 
 
3295
        result = PGAPI_BindCol(hindx_stmt, 6, internal_asis_type,
 
3296
                                        relhasrules, sizeof(relhasrules), NULL);
 
3297
        if (!SQL_SUCCEEDED(result))
 
3298
        {
 
3299
                SC_error_copy(stmt, indx_stmt, TRUE);
 
3300
                goto cleanup;
 
3301
        }
 
3302
 
 
3303
        result = PGAPI_BindCol(hindx_stmt, 8, SQL_C_ULONG,
 
3304
                                        &ioid, sizeof(ioid), NULL);
 
3305
        if (!SQL_SUCCEEDED(result))
 
3306
        {
 
3307
                SC_error_copy(stmt, indx_stmt, TRUE);
 
3308
                goto cleanup;
 
3309
        }
 
3310
 
 
3311
        result = PGAPI_BindCol(hindx_stmt, 9, SQL_C_ULONG,
 
3312
                                        &relhasoids, sizeof(relhasoids), NULL);
 
3313
        if (!SQL_SUCCEEDED(result))
 
3314
        {
 
3315
                SC_error_copy(stmt, indx_stmt, TRUE);
 
3316
                goto cleanup;
 
3317
        }
 
3318
 
 
3319
        /* bind the vector column */
 
3320
        result = PGAPI_BindCol(hindx_stmt, 10, SQL_C_DEFAULT,
 
3321
                        indopt_vector, sizeof(fields_vector), &fields_vector_len);
 
3322
        if (!SQL_SUCCEEDED(result))
 
3323
        {
 
3324
                SC_error_copy(stmt, indx_stmt, TRUE); /* "Couldn't bind column 
 
3325
                                                 * in SQLStatistics."; */
 
3326
                goto cleanup;
 
3327
 
 
3328
        }
 
3329
 
 
3330
        relhasrules[0] = '0';
 
3331
        result = PGAPI_Fetch(hindx_stmt);
 
3332
        /* fake index of OID */
 
3333
        if (relhasoids && relhasrules[0] != '1' && atoi(ci->show_oid_column) && atoi(ci->fake_oid_index))
 
3334
        {
 
3335
                tuple = QR_AddNew(res);
 
3336
 
 
3337
                /* no table qualifier */
 
3338
                set_tuplefield_string(&tuple[STATS_CATALOG_NAME], CurrCat(conn));
 
3339
                /* don't set the table owner, else Access tries to use it */
 
3340
                set_tuplefield_string(&tuple[STATS_SCHEMA_NAME], GET_SCHEMA_NAME(table_schemaname));
 
3341
                set_tuplefield_string(&tuple[STATS_TABLE_NAME], table_name);
 
3342
 
 
3343
                /* non-unique index? */
 
3344
                set_tuplefield_int2(&tuple[STATS_NON_UNIQUE], (Int2) (ci->drivers.unique_index ? FALSE : TRUE));
 
3345
 
 
3346
                /* no index qualifier */
 
3347
                set_tuplefield_string(&tuple[STATS_INDEX_QUALIFIER], GET_SCHEMA_NAME(table_schemaname));
 
3348
 
 
3349
                snprintf(buf, sizeof(buf), "%s_idx_fake_oid", table_name);
 
3350
                set_tuplefield_string(&tuple[STATS_INDEX_NAME], buf);
 
3351
 
 
3352
                /*
 
3353
                 * Clustered/HASH index?
 
3354
                 */
 
3355
                set_tuplefield_int2(&tuple[STATS_TYPE], (Int2) SQL_INDEX_OTHER);
 
3356
                set_tuplefield_int2(&tuple[STATS_SEQ_IN_INDEX], (Int2) 1);
 
3357
 
 
3358
                set_tuplefield_string(&tuple[STATS_COLUMN_NAME], OID_NAME);
 
3359
                set_tuplefield_string(&tuple[STATS_COLLATION], "A");
 
3360
                set_tuplefield_null(&tuple[STATS_CARDINALITY]);
 
3361
                set_tuplefield_null(&tuple[STATS_PAGES]);
 
3362
                set_tuplefield_null(&tuple[STATS_FILTER_CONDITION]);
 
3363
        }
 
3364
 
 
3365
        while (SQL_SUCCEEDED(result))
 
3366
        {
 
3367
                /* If only requesting unique indexs, then just return those. */
 
3368
                if (fUnique == SQL_INDEX_ALL ||
 
3369
                        (fUnique == SQL_INDEX_UNIQUE && atoi(isunique)))
 
3370
                {
 
3371
                        int     colcnt, attnum;
 
3372
 
 
3373
                        /* add a row in this table for each field in the index */
 
3374
                        colcnt = fields_vector[0];
 
3375
                        for (i = 1; i <= colcnt; i++)
 
3376
                        {
 
3377
                                tuple = QR_AddNew(res);
 
3378
 
 
3379
                                /* no table qualifier */
 
3380
                                set_tuplefield_string(&tuple[STATS_CATALOG_NAME], CurrCat(conn));
 
3381
                                /* don't set the table owner, else Access tries to use it */
 
3382
                                set_tuplefield_string(&tuple[STATS_SCHEMA_NAME], GET_SCHEMA_NAME(table_schemaname));
 
3383
                                set_tuplefield_string(&tuple[STATS_TABLE_NAME], table_name);
 
3384
 
 
3385
                                /* non-unique index? */
 
3386
                                if (ci->drivers.unique_index)
 
3387
                                        set_tuplefield_int2(&tuple[STATS_NON_UNIQUE], (Int2) (atoi(isunique) ? FALSE : TRUE));
 
3388
                                else
 
3389
                                        set_tuplefield_int2(&tuple[STATS_NON_UNIQUE], TRUE);
 
3390
 
 
3391
                                /* no index qualifier */
 
3392
                                set_tuplefield_string(&tuple[STATS_INDEX_QUALIFIER], GET_SCHEMA_NAME(table_schemaname));
 
3393
                                set_tuplefield_string(&tuple[STATS_INDEX_NAME], index_name);
 
3394
 
 
3395
                                /*
 
3396
                                 * Clustered/HASH index?
 
3397
                                 */
 
3398
                                set_tuplefield_int2(&tuple[STATS_TYPE], (Int2)
 
3399
                                                           (atoi(isclustered) ? SQL_INDEX_CLUSTERED :
 
3400
                                                                (!strncmp(ishash, "hash", 4)) ? SQL_INDEX_HASHED : SQL_INDEX_OTHER));
 
3401
                                set_tuplefield_int2(&tuple[STATS_SEQ_IN_INDEX], (Int2) i);
 
3402
 
 
3403
                                attnum = fields_vector[i];
 
3404
                                if (OID_ATTNUM == attnum)
 
3405
                                {
 
3406
                                        set_tuplefield_string(&tuple[STATS_COLUMN_NAME], OID_NAME);
 
3407
                                        mylog("%s: column name = oid\n", func);
 
3408
                                }
 
3409
                                else if (0 == attnum)
 
3410
                                {
 
3411
                                        char    cmd[64];
 
3412
 
 
3413
                                        QResultClass *res;
 
3414
 
 
3415
                                        snprintf(cmd, sizeof(cmd), "select pg_get_indexdef(%u, %d, true)", ioid, i);
 
3416
                                        res = CC_send_query(conn, cmd, NULL, IGNORE_ABORT_ON_CONN, stmt);
 
3417
                                        if (QR_command_maybe_successful(res))
 
3418
                                                set_tuplefield_string(&tuple[STATS_COLUMN_NAME], QR_get_value_backend_text(res, 0, 0));
 
3419
                                        QR_Destructor(res);
 
3420
                                }
 
3421
                                else
 
3422
                                {
 
3423
                                        int j, matchidx;
 
3424
                                        BOOL    unknownf = TRUE;
 
3425
 
 
3426
                                        if (attnum > 0)
 
3427
                                        {
 
3428
                                                for (j = 0; j < total_columns; j++)
 
3429
                                                {
 
3430
                                                        if (attnum == column_names[j].pnum)
 
3431
                                                        {
 
3432
                                                                matchidx = j;
 
3433
                                                                unknownf = FALSE;
 
3434
                                                                break;
 
3435
                                                        }
 
3436
                                                }
 
3437
                                        }
 
3438
                                        if (unknownf)
 
3439
                                        {
 
3440
                                                set_tuplefield_string(&tuple[STATS_COLUMN_NAME], "UNKNOWN");
 
3441
                                                mylog("%s: column name = UNKNOWN\n", func);
 
3442
                                        }
 
3443
                                        else
 
3444
                                        {
 
3445
                                                set_tuplefield_string(&tuple[STATS_COLUMN_NAME], column_names[matchidx].col_name);
 
3446
                                                mylog("%s: column name = '%s'\n", func, column_names[matchidx].col_name);
 
3447
                                        }
 
3448
                                }
 
3449
 
 
3450
                                if (i <= indopt_vector[0] &&
 
3451
                                    (indopt_vector[i] & INDOPTION_DESC) != 0)
 
3452
                                        set_tuplefield_string(&tuple[STATS_COLLATION], "D");
 
3453
                                else
 
3454
                                        set_tuplefield_string(&tuple[STATS_COLLATION], "A");
 
3455
                                set_tuplefield_null(&tuple[STATS_CARDINALITY]);
 
3456
                                set_tuplefield_null(&tuple[STATS_PAGES]);
 
3457
                                set_tuplefield_null(&tuple[STATS_FILTER_CONDITION]);
 
3458
                        }
 
3459
                }
 
3460
 
 
3461
                result = PGAPI_Fetch(hindx_stmt);
 
3462
        }
 
3463
        if (result != SQL_NO_DATA_FOUND)
 
3464
        {
 
3465
                /* "SQLFetch failed in SQLStatistics."; */
 
3466
                SC_full_error_copy(stmt, indx_stmt, FALSE);
 
3467
                goto cleanup;
 
3468
        }
 
3469
        ret = SQL_SUCCESS;
 
3470
 
 
3471
cleanup:
 
3472
#undef  return
 
3473
        /*
 
3474
         * also, things need to think that this statement is finished so the
 
3475
         * results can be retrieved.
 
3476
         */
 
3477
        stmt->status = STMT_FINISHED;
 
3478
 
 
3479
        if (hcol_stmt)
 
3480
                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
3481
        if (hindx_stmt)
 
3482
                PGAPI_FreeStmt(hindx_stmt, SQL_DROP);
 
3483
        /* These things should be freed on any error ALSO! */
 
3484
        if (table_name)
 
3485
                free(table_name);
 
3486
        if (escTableName)
 
3487
                free(escTableName);
 
3488
        if (escSchemaName)
 
3489
                free(escSchemaName);
 
3490
        if (column_names)
 
3491
        {
 
3492
                for (i = 0; i < total_columns; i++)
 
3493
                        free(column_names[i].col_name);
 
3494
                free(column_names);
 
3495
        }
 
3496
 
 
3497
        /* set up the current tuple pointer for SQLFetch */
 
3498
        stmt->currTuple = -1;
 
3499
        SC_set_rowset_start(stmt, -1, FALSE);
 
3500
        SC_set_current_col(stmt, -1);
 
3501
 
 
3502
        if (stmt->internal)
 
3503
                ret = DiscardStatementSvp(stmt, ret, FALSE);
 
3504
        mylog("%s: EXIT, stmt=%p, ret=%d\n", func, stmt, ret);
 
3505
 
 
3506
        return ret;
 
3507
}
 
3508
 
 
3509
 
 
3510
RETCODE         SQL_API
 
3511
PGAPI_ColumnPrivileges(
 
3512
                        HSTMT hstmt,
 
3513
                        const SQLCHAR FAR * szTableQualifier, /* OA X*/
 
3514
                        SQLSMALLINT cbTableQualifier,
 
3515
                        const SQLCHAR FAR * szTableOwner, /* OA E*/
 
3516
                        SQLSMALLINT cbTableOwner,
 
3517
                        const SQLCHAR FAR * szTableName, /* OA(R) E*/
 
3518
                        SQLSMALLINT cbTableName,
 
3519
                        const SQLCHAR FAR * szColumnName, /* PV E*/
 
3520
                        SQLSMALLINT cbColumnName,
 
3521
                        UWORD flag)
 
3522
{
 
3523
        CSTR func = "PGAPI_ColumnPrivileges";
 
3524
        StatementClass  *stmt = (StatementClass *) hstmt;
 
3525
        ConnectionClass *conn = SC_get_conn(stmt);
 
3526
        RETCODE result = SQL_ERROR;
 
3527
        char    *escSchemaName = NULL, *escTableName = NULL, *escColumnName = NULL;
 
3528
        const char      *like_or_eq, *op_string, *eq_string;
 
3529
        char    column_query[INFO_INQUIRY_LEN];
 
3530
        size_t          cq_len,cq_size;
 
3531
        char            *col_query;
 
3532
        BOOL    search_pattern;
 
3533
        QResultClass    *res = NULL;
 
3534
 
 
3535
        mylog("%s: entering...\n", func);
 
3536
 
 
3537
        /* Neither Access or Borland care about this. */
 
3538
 
 
3539
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
 
3540
                return result;
 
3541
        if (PG_VERSION_LT(conn, 7.4))
 
3542
                SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Function not implementedyet", func);
 
3543
        escSchemaName = simpleCatalogEscape(szTableOwner, cbTableOwner, NULL, conn);
 
3544
        escTableName = simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
 
3545
        search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
 
3546
        if (search_pattern) 
 
3547
        {
 
3548
                like_or_eq = likeop;
 
3549
                escColumnName = adjustLikePattern(szColumnName, cbColumnName, SEARCH_PATTERN_ESCAPE, NULL, conn);
 
3550
        }
 
3551
        else
 
3552
        {
 
3553
                like_or_eq = eqop;
 
3554
                escColumnName = simpleCatalogEscape(szColumnName, cbColumnName, NULL, conn);
 
3555
        }
 
3556
        strcpy(column_query, "select '' as TABLE_CAT, table_schema as TABLE_SCHEM,"
 
3557
                        " table_name, column_name, grantor, grantee,"
 
3558
                        " privilege_type as PRIVILEGE, is_grantable from"
 
3559
                        " information_schema.column_privileges where true");
 
3560
        cq_len = strlen(column_query);
 
3561
        cq_size = sizeof(column_query);
 
3562
        col_query = column_query;
 
3563
        op_string = gen_opestr(like_or_eq, conn);
 
3564
        eq_string = gen_opestr(eqop, conn);
 
3565
        if (escSchemaName)
 
3566
        {
 
3567
                col_query += cq_len;
 
3568
                cq_size -= cq_len;
 
3569
                cq_len = snprintf_len(col_query, cq_size,
 
3570
                        " and table_schem %s'%s'", eq_string, escSchemaName);  
 
3571
                
 
3572
        }
 
3573
        if (escTableName)
 
3574
        {
 
3575
                col_query += cq_len;
 
3576
                cq_size -= cq_len;
 
3577
                cq_len += snprintf_len(col_query, cq_size,
 
3578
                        " and table_name %s'%s'", eq_string, escTableName);  
 
3579
        }
 
3580
        if (escColumnName)
 
3581
        {
 
3582
                col_query += cq_len;
 
3583
                cq_size -= cq_len;
 
3584
                cq_len += snprintf_len(col_query, cq_size,
 
3585
                        " and column_name %s'%s'", op_string, escColumnName);
 
3586
        }
 
3587
        if (res = CC_send_query(conn, column_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(res))
 
3588
        {
 
3589
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_ColumnPrivileges query error", func);
 
3590
                goto cleanup;
 
3591
        }
 
3592
        SC_set_Result(stmt, res);
 
3593
 
 
3594
        /*
 
3595
         * also, things need to think that this statement is finished so the
 
3596
         * results can be retrieved.
 
3597
         */
 
3598
        extend_column_bindings(SC_get_ARDF(stmt), 8);
 
3599
        /* set up the current tuple pointer for SQLFetch */
 
3600
        result = SQL_SUCCESS;
 
3601
cleanup:
 
3602
        if (!SQL_SUCCEEDED(result))
 
3603
                QR_Destructor(res);
 
3604
        /* set up the current tuple pointer for SQLFetch */
 
3605
        stmt->status = STMT_FINISHED;
 
3606
        stmt->currTuple = -1;
 
3607
        SC_set_rowset_start(stmt, -1, FALSE);
 
3608
        if (escSchemaName)
 
3609
                free(escSchemaName);
 
3610
        if (escTableName)
 
3611
                free(escTableName);
 
3612
        if (escColumnName)
 
3613
                free(escColumnName);
 
3614
        return result;
 
3615
}
 
3616
 
 
3617
 
 
3618
/*
 
3619
 *      SQLPrimaryKeys()
 
3620
 *
 
3621
 *      Retrieve the primary key columns for the specified table.
 
3622
 */
 
3623
RETCODE         SQL_API
 
3624
PGAPI_PrimaryKeys(
 
3625
                        HSTMT hstmt,
 
3626
                        const SQLCHAR FAR * szTableQualifier, /* OA X*/
 
3627
                        SQLSMALLINT cbTableQualifier,
 
3628
                        const SQLCHAR FAR * szTableOwner, /* OA E*/
 
3629
                        SQLSMALLINT cbTableOwner,
 
3630
                        const SQLCHAR FAR * szTableName, /* OA(R) E*/
 
3631
                        SQLSMALLINT cbTableName,
 
3632
                        OID     reloid)
 
3633
{
 
3634
        CSTR func = "PGAPI_PrimaryKeys";
 
3635
        StatementClass *stmt = (StatementClass *) hstmt;
 
3636
        QResultClass    *res;
 
3637
        ConnectionClass *conn;
 
3638
        TupleField      *tuple;
 
3639
        RETCODE         ret = SQL_SUCCESS, result;
 
3640
        int                     seq = 0;
 
3641
        HSTMT           htbl_stmt = NULL;
 
3642
        StatementClass *tbl_stmt;
 
3643
        char            tables_query[INFO_INQUIRY_LEN];
 
3644
        char            attname[MAX_INFO_STRING];
 
3645
        SQLLEN          attname_len;
 
3646
        char            *pktab = NULL, *pktbname;
 
3647
        char            pkscm[SCHEMA_NAME_STORAGE_LEN + 1];
 
3648
        SQLLEN          pkscm_len;
 
3649
        char            tabname[TABLE_NAME_STORAGE_LEN + 1];
 
3650
        SQLLEN          tabname_len;
 
3651
        char            pkname[TABLE_NAME_STORAGE_LEN + 1];
 
3652
        Int2            result_cols;
 
3653
        int                     qno,
 
3654
                                qstart,
 
3655
                                qend;
 
3656
        SQLSMALLINT     internal_asis_type = SQL_C_CHAR, cbSchemaName;
 
3657
        const char      *szSchemaName, *eq_string;
 
3658
        char    *escSchemaName = NULL, *escTableName = NULL;
 
3659
 
 
3660
        mylog("%s: entering...stmt=%p scnm=%p len=%d\n", func, stmt, szTableOwner, cbTableOwner);
 
3661
 
 
3662
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
 
3663
                return result;
 
3664
 
 
3665
        if (res = QR_Constructor(), !res)
 
3666
        {
 
3667
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_PrimaryKeys result.", func);
 
3668
                return SQL_ERROR;
 
3669
        }
 
3670
        SC_set_Result(stmt, res);
 
3671
 
 
3672
        /* the binding structure for a statement is not set up until 
 
3673
         *
 
3674
         * a statement is actually executed, so we'll have to do this
 
3675
         * ourselves.
 
3676
         */
 
3677
        result_cols = NUM_OF_PKS_FIELDS;
 
3678
        extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
3679
 
 
3680
        stmt->catalog_result = TRUE;
 
3681
        /* set the field names */
 
3682
        QR_set_num_fields(res, result_cols);
 
3683
        QR_set_field_info_v(res, PKS_TABLE_CAT, "TABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3684
        QR_set_field_info_v(res, PKS_TABLE_SCHEM, "TABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3685
        QR_set_field_info_v(res, PKS_TABLE_NAME, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3686
        QR_set_field_info_v(res, PKS_COLUMN_NAME, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3687
        QR_set_field_info_v(res, PKS_KEY_SQ, "KEY_SEQ", PG_TYPE_INT2, 2);
 
3688
        QR_set_field_info_v(res, PKS_PK_NAME, "PK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
3689
 
 
3690
        conn = SC_get_conn(stmt);
 
3691
        result = PGAPI_AllocStmt(conn, &htbl_stmt, 0);
 
3692
        if (!SQL_SUCCEEDED(result))
 
3693
        {
 
3694
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for Primary Key result.", func);
 
3695
                ret = SQL_ERROR;
 
3696
                goto cleanup;
 
3697
        }
 
3698
        tbl_stmt = (StatementClass *) htbl_stmt;
 
3699
 
 
3700
#ifdef  UNICODE_SUPPORT
 
3701
        if (CC_is_in_unicode_driver(conn))
 
3702
                internal_asis_type = INTERNAL_ASIS_TYPE;
 
3703
#endif /* UNICODE_SUPPORT */
 
3704
 
 
3705
#define return  DONT_CALL_RETURN_FROM_HERE???
 
3706
        if (0 != reloid)
 
3707
        {
 
3708
                szSchemaName = NULL;
 
3709
                cbSchemaName = SQL_NULL_DATA;
 
3710
        }
 
3711
        else
 
3712
        {
 
3713
                pktab = make_string(szTableName, cbTableName, NULL, 0);
 
3714
                if (!pktab || pktab[0] == '\0')
 
3715
                {
 
3716
                        SC_set_error(stmt, STMT_INTERNAL_ERROR, "No Table specified to PGAPI_PrimaryKeys.", func);
 
3717
                        ret = SQL_ERROR;
 
3718
                        goto cleanup;
 
3719
                }
 
3720
                szSchemaName = szTableOwner;
 
3721
                cbSchemaName = cbTableOwner;
 
3722
                escTableName = simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
 
3723
        }
 
3724
        eq_string = gen_opestr(eqop, conn);
 
3725
 
 
3726
retry_public_schema:
 
3727
        pkscm[0] = '\0';
 
3728
        if (0 == reloid)
 
3729
        {
 
3730
                if (escSchemaName)
 
3731
                        free(escSchemaName);
 
3732
                escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn);
 
3733
                if (conn->schema_support)
 
3734
                        schema_strcat(pkscm, "%.*s", escSchemaName, SQL_NTS, szTableName, cbTableName, conn);
 
3735
        }
 
3736
 
 
3737
        result = PGAPI_BindCol(htbl_stmt, 1, internal_asis_type,
 
3738
                                                   attname, MAX_INFO_STRING, &attname_len);
 
3739
        if (!SQL_SUCCEEDED(result))
 
3740
        {
 
3741
                SC_error_copy(stmt, tbl_stmt, TRUE);
 
3742
                ret = SQL_ERROR;
 
3743
                goto cleanup;
 
3744
        }
 
3745
        result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
 
3746
                        pkname, TABLE_NAME_STORAGE_LEN, NULL);
 
3747
        if (!SQL_SUCCEEDED(result))
 
3748
        {
 
3749
                SC_error_copy(stmt, tbl_stmt, TRUE);
 
3750
                ret = SQL_ERROR;
 
3751
                goto cleanup;
 
3752
        }
 
3753
        result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type,
 
3754
                        pkscm, SCHEMA_NAME_STORAGE_LEN, &pkscm_len);
 
3755
        if (!SQL_SUCCEEDED(result))
 
3756
        {
 
3757
                SC_error_copy(stmt, tbl_stmt, TRUE);
 
3758
                ret = SQL_ERROR;
 
3759
                goto cleanup;
 
3760
        }
 
3761
        result = PGAPI_BindCol(htbl_stmt, 5, internal_asis_type,
 
3762
                        tabname, TABLE_NAME_STORAGE_LEN, &tabname_len);
 
3763
        if (!SQL_SUCCEEDED(result))
 
3764
        {
 
3765
                SC_error_copy(stmt, tbl_stmt, TRUE);
 
3766
                ret = SQL_ERROR;
 
3767
                goto cleanup;
 
3768
        }
 
3769
 
 
3770
        if (PG_VERSION_LE(conn, 6.4))
 
3771
                qstart = 2;
 
3772
        else
 
3773
                qstart = 1;
 
3774
        if (0 == reloid)
 
3775
                qend = 2;
 
3776
        else
 
3777
                qend = 1;
 
3778
        for (qno = qstart; qno <= qend; qno++)
 
3779
        {
 
3780
                size_t  qsize, tsize;
 
3781
                char    *tbqry;
 
3782
 
 
3783
                switch (qno)
 
3784
                {
 
3785
                        case 1:
 
3786
 
 
3787
                                /*
 
3788
                                 * Simplified query to remove assumptions about number of
 
3789
                                 * possible index columns. Courtesy of Tom Lane - thomas
 
3790
                                 * 2000-03-21
 
3791
                                 */
 
3792
                                if (conn->schema_support)
 
3793
                                {
 
3794
                                        strncpy_null(tables_query,
 
3795
                                                "select ta.attname, ia.attnum, ic.relname, n.nspname, tc.relname"
 
3796
                                                " from pg_catalog.pg_attribute ta,"
 
3797
                                                " pg_catalog.pg_attribute ia, pg_catalog.pg_class tc,"
 
3798
                                                " pg_catalog.pg_index i, pg_catalog.pg_namespace n"
 
3799
                                                ", pg_catalog.pg_class ic"
 
3800
                                                , sizeof(tables_query));
 
3801
                                        qsize = strlen(tables_query);
 
3802
                                        tsize = sizeof(tables_query) - qsize;
 
3803
                                        tbqry = tables_query + qsize;
 
3804
                                        if (0 == reloid)
 
3805
                                                snprintf(tbqry, tsize,
 
3806
                                                " where tc.relname %s'%s'"
 
3807
                                                " AND n.nspname %s'%s'"
 
3808
                                                , eq_string, escTableName, eq_string, pkscm);
 
3809
                                        else
 
3810
                                                snprintf(tbqry, tsize,
 
3811
                                                " where tc.oid = " FORMAT_UINT4
 
3812
                                                , reloid);
 
3813
 
 
3814
                                        strlcat(tables_query,
 
3815
                                                " AND tc.oid = i.indrelid"
 
3816
                                                " AND n.oid = tc.relnamespace"
 
3817
                                                " AND i.indisprimary = 't'"
 
3818
                                                " AND ia.attrelid = i.indexrelid"
 
3819
                                                " AND ta.attrelid = i.indrelid"
 
3820
                                                " AND ta.attnum = i.indkey[ia.attnum-1]"
 
3821
                                                " AND (NOT ta.attisdropped)"
 
3822
                                                " AND (NOT ia.attisdropped)"
 
3823
                                                " AND ic.oid = i.indexrelid"
 
3824
                                                " order by ia.attnum"
 
3825
                                                , sizeof(tables_query));
 
3826
                                }
 
3827
                                else
 
3828
                                {
 
3829
                                        strncpy_null(tables_query, 
 
3830
                                                "select ta.attname, ia.attnum, ic.relname, NULL, tc.relname"
 
3831
                                                " from pg_attribute ta, pg_attribute ia, pg_class tc, pg_index i, pg_class ic"
 
3832
                                                , sizeof(tables_query));
 
3833
                                        qsize = strlen(tables_query);
 
3834
                                        tsize = sizeof(tables_query) - qsize;
 
3835
                                        tbqry = tables_query + qsize;
 
3836
                                        if (0 == reloid)
 
3837
                                                snprintf(tbqry, tsize,
 
3838
                                                " where tc.relname %s'%s'"
 
3839
                                                , eq_string, escTableName);
 
3840
                                        else
 
3841
                                                snprintf(tbqry, tsize,
 
3842
                                                " where tc.oid = " FORMAT_UINT4, reloid);
 
3843
                                                
 
3844
                                        strlcat(tables_query,
 
3845
                                                " AND tc.oid = i.indrelid"
 
3846
                                                " AND i.indisprimary = 't'"
 
3847
                                                " AND ia.attrelid = i.indexrelid"
 
3848
                                                " AND ta.attrelid = i.indrelid"
 
3849
                                                " AND ta.attnum = i.indkey[ia.attnum-1]"
 
3850
                                                " AND ic.oid = i.indexrelid"
 
3851
                                                " order by ia.attnum"
 
3852
                                                , sizeof(tables_query));
 
3853
                                }
 
3854
                                break;
 
3855
                        case 2:
 
3856
 
 
3857
                                /*
 
3858
                                 * Simplified query to search old fashoned primary key
 
3859
                                 */
 
3860
                                if (conn->schema_support)
 
3861
                                        snprintf(tables_query, sizeof(tables_query), "select ta.attname, ia.attnum, ic.relname, n.nspname, NULL"
 
3862
                                                " from pg_catalog.pg_attribute ta,"
 
3863
                                                " pg_catalog.pg_attribute ia, pg_catalog.pg_class ic,"
 
3864
                                                " pg_catalog.pg_index i, pg_catalog.pg_namespace n"
 
3865
                                                " where ic.relname %s'%s_pkey'"
 
3866
                                                " AND n.nspname %s'%s'"
 
3867
                                                " AND ic.oid = i.indexrelid"
 
3868
                                                " AND n.oid = ic.relnamespace"
 
3869
                                                " AND ia.attrelid = i.indexrelid"
 
3870
                                                " AND ta.attrelid = i.indrelid"
 
3871
                                                " AND ta.attnum = i.indkey[ia.attnum-1]"
 
3872
                                                " AND (NOT ta.attisdropped)"
 
3873
                                                " AND (NOT ia.attisdropped)"
 
3874
                                                " order by ia.attnum", eq_string, escTableName, eq_string, pkscm);
 
3875
                                else
 
3876
                                        snprintf(tables_query, sizeof(tables_query), "select ta.attname, ia.attnum, ic.relname, NULL, NULL"
 
3877
                                                " from pg_attribute ta, pg_attribute ia, pg_class ic, pg_index i"
 
3878
                                                " where ic.relname %s'%s_pkey'"
 
3879
                                                " AND ic.oid = i.indexrelid"
 
3880
                                                " AND ia.attrelid = i.indexrelid"
 
3881
                                                " AND ta.attrelid = i.indrelid"
 
3882
                                                " AND ta.attnum = i.indkey[ia.attnum-1]"
 
3883
                                                " order by ia.attnum", eq_string, escTableName);
 
3884
                                break;
 
3885
                }
 
3886
                mylog("%s: tables_query='%s'\n", func, tables_query);
 
3887
 
 
3888
                result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
 
3889
                if (!SQL_SUCCEEDED(result))
 
3890
                {
 
3891
                        SC_full_error_copy(stmt, tbl_stmt, FALSE);
 
3892
                        ret = SQL_ERROR;
 
3893
                        goto cleanup;
 
3894
                }
 
3895
 
 
3896
                result = PGAPI_Fetch(htbl_stmt);
 
3897
                if (result != SQL_NO_DATA_FOUND)
 
3898
                        break;
 
3899
        }
 
3900
 
 
3901
        /* If not found */
 
3902
        if (conn->schema_support &&
 
3903
            SQL_NO_DATA_FOUND == result)
 
3904
        {
 
3905
                if (0 == reloid &&
 
3906
                    allow_public_schema(conn, szSchemaName, cbSchemaName))
 
3907
                {
 
3908
                        szSchemaName = pubstr;
 
3909
                        cbSchemaName = SQL_NTS;
 
3910
                        goto retry_public_schema;
 
3911
                }
 
3912
        }
 
3913
 
 
3914
        while (SQL_SUCCEEDED(result))
 
3915
        {
 
3916
                tuple = QR_AddNew(res);
 
3917
 
 
3918
                set_tuplefield_string(&tuple[PKS_TABLE_CAT], CurrCat(conn));
 
3919
 
 
3920
                /*
 
3921
                 * I have to hide the table owner from Access, otherwise it
 
3922
                 * insists on referring to the table as 'owner.table'. (this is
 
3923
                 * valid according to the ODBC SQL grammar, but Postgres won't
 
3924
                 * support it.)
 
3925
                 */
 
3926
                if (SQL_NULL_DATA == pkscm_len)
 
3927
                        pkscm[0] = '\0';
 
3928
                set_tuplefield_string(&tuple[PKS_TABLE_SCHEM], GET_SCHEMA_NAME(pkscm));
 
3929
                if (SQL_NULL_DATA == tabname_len)
 
3930
                        tabname[0] = '\0';
 
3931
                pktbname = pktab ? pktab : tabname;
 
3932
                set_tuplefield_string(&tuple[PKS_TABLE_NAME], pktbname);
 
3933
                set_tuplefield_string(&tuple[PKS_COLUMN_NAME], attname);
 
3934
                set_tuplefield_int2(&tuple[PKS_KEY_SQ], (Int2) (++seq));
 
3935
                set_tuplefield_string(&tuple[PKS_PK_NAME], pkname);
 
3936
 
 
3937
                mylog(">> primaryKeys: schema ='%s', pktab = '%s', attname = '%s', seq = %d\n", pkscm, pktbname, attname, seq);
 
3938
 
 
3939
                result = PGAPI_Fetch(htbl_stmt);
 
3940
        }
 
3941
 
 
3942
        if (result != SQL_NO_DATA_FOUND)
 
3943
        {
 
3944
                SC_full_error_copy(stmt, htbl_stmt, FALSE);
 
3945
                ret = SQL_ERROR;
 
3946
                goto cleanup;
 
3947
        }
 
3948
        ret = SQL_SUCCESS;
 
3949
 
 
3950
cleanup:
 
3951
#undef  return
 
3952
        /*
 
3953
         * also, things need to think that this statement is finished so the
 
3954
         * results can be retrieved.
 
3955
         */
 
3956
        stmt->status = STMT_FINISHED;
 
3957
 
 
3958
        if (htbl_stmt)
 
3959
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
3960
 
 
3961
        if (pktab)
 
3962
                free(pktab);
 
3963
        if (escSchemaName)
 
3964
                free(escSchemaName);
 
3965
        if (escTableName)
 
3966
                free(escTableName);
 
3967
        /* set up the current tuple pointer for SQLFetch */
 
3968
        stmt->currTuple = -1;
 
3969
        SC_set_rowset_start(stmt, -1, FALSE);
 
3970
        SC_set_current_col(stmt, -1);
 
3971
 
 
3972
        if (stmt->internal)
 
3973
                ret = DiscardStatementSvp(stmt, ret, FALSE); 
 
3974
        mylog("%s: EXIT, stmt=%p, ret=%d\n", func, stmt, ret);
 
3975
        return ret;
 
3976
}
 
3977
 
 
3978
 
 
3979
/*
 
3980
 *      Multibyte support stuff for SQLForeignKeys().
 
3981
 *      There may be much more effective way in the
 
3982
 *      future version. The way is very forcible currently.
 
3983
 */
 
3984
static BOOL
 
3985
isMultibyte(const UCHAR *str)
 
3986
{
 
3987
        for (; *str; str++)
 
3988
        {
 
3989
                if (*str >= 0x80)
 
3990
                        return TRUE;
 
3991
        }
 
3992
        return FALSE;
 
3993
}
 
3994
static char *
 
3995
getClientColumnName(ConnectionClass *conn, UInt4 relid, char *serverColumnName, BOOL *nameAlloced)
 
3996
{
 
3997
        char            query[1024], saveattnum[16],
 
3998
                           *ret = serverColumnName;
 
3999
        const char *eq_string;
 
4000
        BOOL            continueExec = TRUE,
 
4001
                                bError = FALSE;
 
4002
        QResultClass *res = NULL;
 
4003
        UWORD   flag = IGNORE_ABORT_ON_CONN | ROLLBACK_ON_ERROR;
 
4004
 
 
4005
        *nameAlloced = FALSE;
 
4006
        if (!conn->original_client_encoding || !isMultibyte(serverColumnName))
 
4007
                return ret;
 
4008
        if (!conn->server_encoding)
 
4009
        {
 
4010
                if (res = CC_send_query(conn, "select getdatabaseencoding()", NULL, flag, NULL), QR_command_maybe_successful(res))
 
4011
                {
 
4012
                        if (QR_get_num_cached_tuples(res) > 0)
 
4013
                                conn->server_encoding = strdup(QR_get_value_backend_text(res, 0, 0));
 
4014
                }
 
4015
                QR_Destructor(res);
 
4016
                res = NULL;
 
4017
        }
 
4018
        if (!conn->server_encoding)
 
4019
                return ret;
 
4020
        snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->server_encoding);
 
4021
        bError = (!QR_command_maybe_successful((res = CC_send_query(conn, query, NULL, flag, NULL))));
 
4022
        QR_Destructor(res);
 
4023
        eq_string = gen_opestr(eqop, conn);
 
4024
        if (!bError && continueExec)
 
4025
        {
 
4026
                snprintf(query, sizeof(query), "select attnum from pg_attribute "
 
4027
                        "where attrelid = %u and attname %s'%s'",
 
4028
                        relid, eq_string, serverColumnName);
 
4029
                if (res = CC_send_query(conn, query, NULL, flag, NULL), QR_command_maybe_successful(res))
 
4030
                {
 
4031
                        if (QR_get_num_cached_tuples(res) > 0)
 
4032
                        {
 
4033
                                strcpy(saveattnum, QR_get_value_backend_text(res, 0, 0));
 
4034
                        }
 
4035
                        else
 
4036
                                continueExec = FALSE;
 
4037
                }
 
4038
                else
 
4039
                        bError = TRUE;
 
4040
                QR_Destructor(res);
 
4041
        }
 
4042
        continueExec = (continueExec && !bError);
 
4043
        /* restore the cleint encoding */
 
4044
        snprintf(query, sizeof(query), "SET CLIENT_ENCODING TO '%s'", conn->original_client_encoding);
 
4045
        bError = (!QR_command_maybe_successful((res = CC_send_query(conn, query, NULL, flag, NULL))));
 
4046
        QR_Destructor(res);
 
4047
        if (bError || !continueExec)
 
4048
                return ret;
 
4049
        snprintf(query, sizeof(query), "select attname from pg_attribute where attrelid = %u and attnum = %s", relid, saveattnum);
 
4050
        if (res = CC_send_query(conn, query, NULL, flag, NULL), QR_command_maybe_successful(res))
 
4051
        {
 
4052
                if (QR_get_num_cached_tuples(res) > 0)
 
4053
                {
 
4054
                        ret = strdup(QR_get_value_backend_text(res, 0, 0));
 
4055
                        *nameAlloced = TRUE;
 
4056
                }
 
4057
        }
 
4058
        QR_Destructor(res);
 
4059
        return ret;
 
4060
}
 
4061
 
 
4062
static RETCODE          SQL_API
 
4063
PGAPI_ForeignKeys_new(
 
4064
                HSTMT hstmt,
 
4065
                const SQLCHAR FAR * szPkTableQualifier, /* OA X*/
 
4066
                SQLSMALLINT cbPkTableQualifier,
 
4067
                const SQLCHAR FAR * szPkTableOwner, /* OA E*/
 
4068
                SQLSMALLINT cbPkTableOwner,
 
4069
                const SQLCHAR FAR * szPkTableName, /* OA(R) E*/
 
4070
                SQLSMALLINT cbPkTableName,
 
4071
                const SQLCHAR FAR * szFkTableQualifier, /* OA X*/
 
4072
                SQLSMALLINT cbFkTableQualifier,
 
4073
                const SQLCHAR FAR * szFkTableOwner, /* OA E*/
 
4074
                SQLSMALLINT cbFkTableOwner,
 
4075
                const SQLCHAR FAR * szFkTableName, /* OA(R) E*/
 
4076
                SQLSMALLINT cbFkTableName);
 
4077
 
 
4078
static RETCODE          SQL_API
 
4079
PGAPI_ForeignKeys_old(
 
4080
                        HSTMT hstmt,
 
4081
                        const SQLCHAR FAR * szPkTableQualifier, /* OA X*/
 
4082
                        SQLSMALLINT cbPkTableQualifier,
 
4083
                        const SQLCHAR FAR * szPkTableOwner, /* OA E*/
 
4084
                        SQLSMALLINT cbPkTableOwner,
 
4085
                        const SQLCHAR FAR * szPkTableName, /* OA(R) E*/
 
4086
                        SQLSMALLINT cbPkTableName,
 
4087
                        const SQLCHAR FAR * szFkTableQualifier, /* OA X*/
 
4088
                        SQLSMALLINT cbFkTableQualifier,
 
4089
                        const SQLCHAR FAR * szFkTableOwner, /* OA E*/
 
4090
                        SQLSMALLINT cbFkTableOwner,
 
4091
                        const SQLCHAR FAR * szFkTableName, /* OA(R) E*/
 
4092
                        SQLSMALLINT cbFkTableName)
 
4093
{
 
4094
        CSTR func = "PGAPI_ForeignKeys";
 
4095
        StatementClass *stmt = (StatementClass *) hstmt;
 
4096
        QResultClass    *res;
 
4097
        TupleField      *tuple;
 
4098
        HSTMT           htbl_stmt = NULL, hpkey_stmt = NULL;
 
4099
        StatementClass *tbl_stmt;
 
4100
        RETCODE         ret = SQL_ERROR, result, keyresult;
 
4101
        char            tables_query[INFO_INQUIRY_LEN];
 
4102
        char            trig_deferrable[2];
 
4103
        char            trig_initdeferred[2];
 
4104
        char            trig_args[1024];
 
4105
        char            upd_rule[TABLE_NAME_STORAGE_LEN],
 
4106
                                del_rule[TABLE_NAME_STORAGE_LEN];
 
4107
        char            *pk_table_needed = NULL, *escPkTableName = NULL;
 
4108
        char            fk_table_fetched[TABLE_NAME_STORAGE_LEN + 1];
 
4109
        char            *fk_table_needed = NULL, *escFkTableName = NULL;
 
4110
        char            pk_table_fetched[TABLE_NAME_STORAGE_LEN + 1];
 
4111
        char            schema_needed[SCHEMA_NAME_STORAGE_LEN + 1];
 
4112
        char            schema_fetched[SCHEMA_NAME_STORAGE_LEN + 1];
 
4113
        char            constrname[NAMESTORAGELEN + 1], pkname[TABLE_NAME_STORAGE_LEN + 1];
 
4114
        char       *pkey_ptr,
 
4115
                           *pkey_text = NULL,
 
4116
                           *fkey_ptr,
 
4117
                           *fkey_text = NULL;
 
4118
 
 
4119
        ConnectionClass *conn;
 
4120
        BOOL            pkey_alloced,
 
4121
                        fkey_alloced, got_pkname;
 
4122
        int                     i,
 
4123
                                j,
 
4124
                                k,
 
4125
                                num_keys;
 
4126
        SQLSMALLINT             trig_nargs,
 
4127
                                upd_rule_type = 0,
 
4128
                                del_rule_type = 0;
 
4129
        SQLSMALLINT     internal_asis_type = SQL_C_CHAR;
 
4130
 
 
4131
#if (ODBCVER >= 0x0300)
 
4132
        SQLSMALLINT     defer_type;
 
4133
#endif
 
4134
        char            pkey[MAX_INFO_STRING];
 
4135
        Int2            result_cols;
 
4136
        UInt4           relid1, relid2;
 
4137
        const char *eq_string;
 
4138
 
 
4139
        mylog("%s: entering...stmt=%p\n", func, stmt);
 
4140
 
 
4141
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
 
4142
                return result;
 
4143
 
 
4144
        if (res = QR_Constructor(), !res)
 
4145
        {
 
4146
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_ForeignKeys result.", func);
 
4147
                return SQL_ERROR;
 
4148
        }
 
4149
        SC_set_Result(stmt, res);
 
4150
 
 
4151
        /* the binding structure for a statement is not set up until */
 
4152
 
 
4153
        /*
 
4154
         * a statement is actually executed, so we'll have to do this
 
4155
         * ourselves.
 
4156
         */
 
4157
        result_cols = NUM_OF_FKS_FIELDS;
 
4158
        extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
4159
 
 
4160
        stmt->catalog_result = TRUE;
 
4161
        /* set the field names */
 
4162
        QR_set_num_fields(res, result_cols);
 
4163
        QR_set_field_info_v(res, FKS_PKTABLE_CAT, "PKTABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4164
        QR_set_field_info_v(res, FKS_PKTABLE_SCHEM, "PKTABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4165
        QR_set_field_info_v(res, FKS_PKTABLE_NAME, "PKTABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4166
        QR_set_field_info_v(res, FKS_PKCOLUMN_NAME, "PKCOLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4167
        QR_set_field_info_v(res, FKS_FKTABLE_CAT, "FKTABLE_QUALIFIER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4168
        QR_set_field_info_v(res, FKS_FKTABLE_SCHEM, "FKTABLE_OWNER", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4169
        QR_set_field_info_v(res, FKS_FKTABLE_NAME, "FKTABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4170
        QR_set_field_info_v(res, FKS_FKCOLUMN_NAME, "FKCOLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4171
        QR_set_field_info_v(res, FKS_KEY_SEQ, "KEY_SEQ", PG_TYPE_INT2, 2);
 
4172
        QR_set_field_info_v(res, FKS_UPDATE_RULE, "UPDATE_RULE", PG_TYPE_INT2, 2);
 
4173
        QR_set_field_info_v(res, FKS_DELETE_RULE, "DELETE_RULE", PG_TYPE_INT2, 2);
 
4174
        QR_set_field_info_v(res, FKS_FK_NAME, "FK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4175
        QR_set_field_info_v(res, FKS_PK_NAME, "PK_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4176
#if (ODBCVER >= 0x0300)
 
4177
        QR_set_field_info_v(res, FKS_DEFERRABILITY, "DEFERRABILITY", PG_TYPE_INT2, 2);
 
4178
#endif   /* ODBCVER >= 0x0300 */
 
4179
        QR_set_field_info_v(res, FKS_TRIGGER_NAME, "TRIGGER_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
4180
 
 
4181
        /*
 
4182
         * also, things need to think that this statement is finished so the
 
4183
         * results can be retrieved.
 
4184
         */
 
4185
        stmt->status = STMT_FINISHED;
 
4186
 
 
4187
        /* set up the current tuple pointer for SQLFetch */
 
4188
        stmt->currTuple = -1;
 
4189
        SC_set_rowset_start(stmt, -1, FALSE);
 
4190
        SC_set_current_col(stmt, -1);
 
4191
 
 
4192
        conn = SC_get_conn(stmt);
 
4193
        result = PGAPI_AllocStmt(conn, &htbl_stmt, 0);
 
4194
        if (!SQL_SUCCEEDED(result))
 
4195
        {
 
4196
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys result.", func);
 
4197
                return SQL_ERROR;
 
4198
        }
 
4199
 
 
4200
#define return  DONT_CALL_RETURN_FROM_HERE???
 
4201
 
 
4202
        tbl_stmt = (StatementClass *) htbl_stmt;
 
4203
        schema_needed[0] = '\0';
 
4204
        schema_fetched[0] = '\0';
 
4205
 
 
4206
        pk_table_needed = make_string(szPkTableName, cbPkTableName, NULL, 0);
 
4207
        fk_table_needed = make_string(szFkTableName, cbFkTableName, NULL, 0);
 
4208
 
 
4209
#ifdef  UNICODE_SUPPORT
 
4210
        if (CC_is_in_unicode_driver(conn))
 
4211
                internal_asis_type = INTERNAL_ASIS_TYPE;
 
4212
#endif /* UNICODE_SUPPORT */
 
4213
        pkey_alloced = fkey_alloced = FALSE;
 
4214
 
 
4215
        eq_string = gen_opestr(eqop, conn);
 
4216
        /*
 
4217
         * Case #2 -- Get the foreign keys in the specified table (fktab) that
 
4218
         * refer to the primary keys of other table(s).
 
4219
         */
 
4220
        if (fk_table_needed && fk_table_needed[0] != '\0')
 
4221
        {
 
4222
                mylog("%s: entering Foreign Key Case #2", func);
 
4223
                escFkTableName = simpleCatalogEscape(fk_table_needed, SQL_NTS, NULL, conn);
 
4224
                if (conn->schema_support)
 
4225
                {
 
4226
                        char    *escSchemaName;
 
4227
 
 
4228
                        schema_strcat(schema_needed, "%.*s", szFkTableOwner, cbFkTableOwner, szFkTableName, cbFkTableName, conn);
 
4229
                        escSchemaName = simpleCatalogEscape(schema_needed, SQL_NTS, NULL, conn);
 
4230
                        snprintf(tables_query, sizeof(tables_query), "SELECT    pt.tgargs, "
 
4231
                                "               pt.tgnargs, "
 
4232
                                "               pt.tgdeferrable, "
 
4233
                                "               pt.tginitdeferred, "
 
4234
                                "               pp1.proname, "
 
4235
                                "               pp2.proname, "
 
4236
                                "               pc.oid, "
 
4237
                                "               pc1.oid, "
 
4238
                                "               pc1.relname, "
 
4239
                                "               pt.tgconstrname, pn.nspname "
 
4240
                                "FROM   pg_catalog.pg_class pc, "
 
4241
                                "               pg_catalog.pg_proc pp1, "
 
4242
                                "               pg_catalog.pg_proc pp2, "
 
4243
                                "               pg_catalog.pg_trigger pt1, "
 
4244
                                "               pg_catalog.pg_trigger pt2, "
 
4245
                                "               pg_catalog.pg_proc pp, "
 
4246
                                "               pg_catalog.pg_trigger pt, "
 
4247
                                "               pg_catalog.pg_class pc1, "
 
4248
                                "               pg_catalog.pg_namespace pn, "
 
4249
                                "               pg_catalog.pg_namespace pn1 "
 
4250
                                "WHERE  pt.tgrelid = pc.oid "
 
4251
                                "AND pp.oid = pt.tgfoid "
 
4252
                                "AND pt1.tgconstrrelid = pc.oid "
 
4253
                                "AND pp1.oid = pt1.tgfoid "
 
4254
                                "AND pt2.tgfoid = pp2.oid "
 
4255
                                "AND pt2.tgconstrrelid = pc.oid "
 
4256
                                "AND ((pc.relname %s'%s') "
 
4257
                                "AND (pn1.oid = pc.relnamespace) "
 
4258
                                "AND (pn1.nspname %s'%s') "
 
4259
                                "AND (pp.proname LIKE '%%ins') "
 
4260
                                "AND (pp1.proname LIKE '%%upd') "
 
4261
                                "AND (pp1.proname not LIKE '%%check%%') "
 
4262
                                "AND (pp2.proname LIKE '%%del') "
 
4263
                                "AND (pt1.tgrelid=pt.tgconstrrelid) "
 
4264
                                "AND (pt1.tgconstrname=pt.tgconstrname) "
 
4265
                                "AND (pt2.tgrelid=pt.tgconstrrelid) "
 
4266
                                "AND (pt2.tgconstrname=pt.tgconstrname) "
 
4267
                                "AND (pt.tgconstrrelid=pc1.oid) "
 
4268
                                "AND (pc1.relnamespace=pn.oid))"
 
4269
                                " order by pt.tgconstrname",
 
4270
                                eq_string, escFkTableName, eq_string, escSchemaName);
 
4271
                        free(escSchemaName);
 
4272
                }
 
4273
                else
 
4274
                        snprintf(tables_query, sizeof(tables_query), "SELECT    pt.tgargs, "
 
4275
                                "               pt.tgnargs, "
 
4276
                                "               pt.tgdeferrable, "
 
4277
                                "               pt.tginitdeferred, "
 
4278
                                "               pp1.proname, "
 
4279
                                "               pp2.proname, "
 
4280
                                "               pc.oid, "
 
4281
                                "               pc1.oid, "
 
4282
                                "               pc1.relname, pt.tgconstrname "
 
4283
                                "FROM   pg_class pc, "
 
4284
                                "               pg_proc pp1, "
 
4285
                                "               pg_proc pp2, "
 
4286
                                "               pg_trigger pt1, "
 
4287
                                "               pg_trigger pt2, "
 
4288
                                "               pg_proc pp, "
 
4289
                                "               pg_trigger pt, "
 
4290
                                "               pg_class pc1 "
 
4291
                                "WHERE  pt.tgrelid = pc.oid "
 
4292
                                "AND pp.oid = pt.tgfoid "
 
4293
                                "AND pt1.tgconstrrelid = pc.oid "
 
4294
                                "AND pp1.oid = pt1.tgfoid "
 
4295
                                "AND pt2.tgfoid = pp2.oid "
 
4296
                                "AND pt2.tgconstrrelid = pc.oid "
 
4297
                                "AND ((pc.relname %s'%s') "
 
4298
                                "AND (pp.proname LIKE '%%ins') "
 
4299
                                "AND (pp1.proname LIKE '%%upd') "
 
4300
                                "AND (pp1.proname not LIKE '%%check%%') "
 
4301
                                "AND (pp2.proname LIKE '%%del') "
 
4302
                                "AND (pt1.tgrelid=pt.tgconstrrelid) "
 
4303
                                "AND (pt1.tgconstrname=pt.tgconstrname) "
 
4304
                                "AND (pt2.tgrelid=pt.tgconstrrelid) "
 
4305
                                "AND (pt2.tgconstrname=pt.tgconstrname) "
 
4306
                                "AND (pt.tgconstrrelid=pc1.oid)) "
 
4307
                                "order by pt.tgconstrname",
 
4308
                                eq_string, escFkTableName);
 
4309
 
 
4310
                result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
 
4311
 
 
4312
                if (!SQL_SUCCEEDED(result))
 
4313
                {
 
4314
                        SC_full_error_copy(stmt, tbl_stmt, FALSE);
 
4315
                        goto cleanup;
 
4316
                }
 
4317
 
 
4318
                result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_BINARY,
 
4319
                                                           trig_args, sizeof(trig_args), NULL);
 
4320
                if (!SQL_SUCCEEDED(result))
 
4321
                {
 
4322
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4323
                        goto cleanup;
 
4324
                }
 
4325
 
 
4326
                result = PGAPI_BindCol(htbl_stmt, 2, SQL_C_SHORT,
 
4327
                                                           &trig_nargs, 0, NULL);
 
4328
                if (!SQL_SUCCEEDED(result))
 
4329
                {
 
4330
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4331
                        goto cleanup;
 
4332
                }
 
4333
 
 
4334
                result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
 
4335
                                                 trig_deferrable, sizeof(trig_deferrable), NULL);
 
4336
                if (!SQL_SUCCEEDED(result))
 
4337
                {
 
4338
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4339
                        goto cleanup;
 
4340
                }
 
4341
 
 
4342
                result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type,
 
4343
                                         trig_initdeferred, sizeof(trig_initdeferred), NULL);
 
4344
                if (!SQL_SUCCEEDED(result))
 
4345
                {
 
4346
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4347
                        goto cleanup;
 
4348
                }
 
4349
 
 
4350
                result = PGAPI_BindCol(htbl_stmt, 5, internal_asis_type,
 
4351
                                                           upd_rule, sizeof(upd_rule), NULL);
 
4352
                if (!SQL_SUCCEEDED(result))
 
4353
                {
 
4354
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4355
                        goto cleanup;
 
4356
                }
 
4357
 
 
4358
                result = PGAPI_BindCol(htbl_stmt, 6, internal_asis_type,
 
4359
                                                           del_rule, sizeof(del_rule), NULL);
 
4360
                if (!SQL_SUCCEEDED(result))
 
4361
                {
 
4362
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4363
                        goto cleanup;
 
4364
                }
 
4365
 
 
4366
                result = PGAPI_BindCol(htbl_stmt, 7, SQL_C_ULONG,
 
4367
                                                           &relid1, sizeof(relid1), NULL);
 
4368
                if (!SQL_SUCCEEDED(result))
 
4369
                {
 
4370
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4371
                        goto cleanup;
 
4372
                }
 
4373
                result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG,
 
4374
                                                           &relid2, sizeof(relid2), NULL);
 
4375
                if (!SQL_SUCCEEDED(result))
 
4376
                {
 
4377
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4378
                        goto cleanup;
 
4379
                }
 
4380
                result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type,
 
4381
                                        pk_table_fetched, TABLE_NAME_STORAGE_LEN, NULL);
 
4382
                if (!SQL_SUCCEEDED(result))
 
4383
                {
 
4384
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4385
                        goto cleanup;
 
4386
                }
 
4387
                result = PGAPI_BindCol(htbl_stmt, 10, internal_asis_type,
 
4388
                                        constrname, NAMESTORAGELEN, NULL);
 
4389
                if (!SQL_SUCCEEDED(result))
 
4390
                {
 
4391
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4392
                        goto cleanup;
 
4393
                }
 
4394
 
 
4395
                if (conn->schema_support)
 
4396
                {
 
4397
                        result = PGAPI_BindCol(htbl_stmt, 11, internal_asis_type,
 
4398
                                        schema_fetched, SCHEMA_NAME_STORAGE_LEN, NULL);
 
4399
                        if (!SQL_SUCCEEDED(result))
 
4400
                        {
 
4401
                                SC_error_copy(stmt, tbl_stmt, TRUE);
 
4402
                                goto cleanup;
 
4403
                        }
 
4404
                }
 
4405
 
 
4406
                result = PGAPI_Fetch(htbl_stmt);
 
4407
                if (result == SQL_NO_DATA_FOUND)
 
4408
                {
 
4409
                        ret = SQL_SUCCESS;
 
4410
                        goto cleanup;
 
4411
                }
 
4412
 
 
4413
                if (result != SQL_SUCCESS)
 
4414
                {
 
4415
                        SC_full_error_copy(stmt, tbl_stmt, FALSE);
 
4416
                        goto cleanup;
 
4417
                }
 
4418
 
 
4419
                keyresult = PGAPI_AllocStmt(conn, &hpkey_stmt, 0);
 
4420
                if (!SQL_SUCCEEDED(keyresult))
 
4421
                {
 
4422
                        SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.", func);
 
4423
                        goto cleanup;
 
4424
                }
 
4425
 
 
4426
                keyresult = PGAPI_BindCol(hpkey_stmt, 4, internal_asis_type,
 
4427
                                                                  pkey, sizeof(pkey), NULL);
 
4428
                if (keyresult != SQL_SUCCESS)
 
4429
                {
 
4430
                        SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.", func);
 
4431
                        goto cleanup;
 
4432
                }
 
4433
 
 
4434
                while (result == SQL_SUCCESS)
 
4435
                {
 
4436
                        /* Compute the number of keyparts. */
 
4437
                        num_keys = (trig_nargs - 4) / 2;
 
4438
 
 
4439
                        mylog("Foreign Key Case#2: trig_nargs = %d, num_keys = %d\n", trig_nargs, num_keys);
 
4440
 
 
4441
                        /* If there is a pk table specified, then check it. */
 
4442
                        if (pk_table_needed && pk_table_needed[0] != '\0')
 
4443
                        {
 
4444
                                /* If it doesn't match, then continue */
 
4445
                                if (strcmp(pk_table_fetched, pk_table_needed))
 
4446
                                {
 
4447
                                        result = PGAPI_Fetch(htbl_stmt);
 
4448
                                        continue;
 
4449
                                }
 
4450
                        }
 
4451
 
 
4452
                        got_pkname = FALSE;
 
4453
                        keyresult = PGAPI_PrimaryKeys(hpkey_stmt, NULL, 0, schema_fetched, SQL_NTS, pk_table_fetched, SQL_NTS, 0);
 
4454
                        if (keyresult != SQL_SUCCESS)
 
4455
                        {
 
4456
                                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't get primary keys for PGAPI_ForeignKeys result.", func);
 
4457
                                goto cleanup;
 
4458
                        }
 
4459
 
 
4460
                        /* Get to first primary key */
 
4461
                        pkey_ptr = trig_args;
 
4462
                        for (i = 0; i < 5; i++)
 
4463
                                pkey_ptr += strlen(pkey_ptr) + 1;
 
4464
 
 
4465
                        for (k = 0; k < num_keys; k++)
 
4466
                        {
 
4467
                                /* Check that the key listed is the primary key */
 
4468
                                keyresult = PGAPI_Fetch(hpkey_stmt);
 
4469
                                if (keyresult != SQL_SUCCESS)
 
4470
                                {
 
4471
                                        num_keys = 0;
 
4472
                                        break;
 
4473
                                }
 
4474
                                if (!got_pkname)
 
4475
                                {
 
4476
                                        PGAPI_GetData(hpkey_stmt, 6, internal_asis_type, pkname, sizeof(pkname), NULL);
 
4477
                                        got_pkname = TRUE;
 
4478
                                }
 
4479
                                pkey_text = getClientColumnName(conn, relid2, pkey_ptr, &pkey_alloced);
 
4480
                                mylog("%s: pkey_ptr='%s', pkey='%s'\n", func, pkey_text, pkey);
 
4481
                                if (strcmp(pkey_text, pkey))
 
4482
                                {
 
4483
                                        num_keys = 0;
 
4484
                                        break;
 
4485
                                }
 
4486
                                if (pkey_alloced)
 
4487
                                        free(pkey_text);
 
4488
                                /* Get to next primary key */
 
4489
                                for (k = 0; k < 2; k++)
 
4490
                                        pkey_ptr += strlen(pkey_ptr) + 1;
 
4491
 
 
4492
                        }
 
4493
                        PGAPI_FreeStmt(hpkey_stmt, SQL_CLOSE);
 
4494
 
 
4495
                        /* Set to first fk column */
 
4496
                        fkey_ptr = trig_args;
 
4497
                        for (k = 0; k < 4; k++)
 
4498
                                fkey_ptr += strlen(fkey_ptr) + 1;
 
4499
 
 
4500
                        /* Set update and delete actions for foreign keys */
 
4501
                        if (!strcmp(upd_rule, "RI_FKey_cascade_upd"))
 
4502
                                upd_rule_type = SQL_CASCADE;
 
4503
                        else if (!strcmp(upd_rule, "RI_FKey_noaction_upd"))
 
4504
                                upd_rule_type = SQL_NO_ACTION;
 
4505
                        else if (!strcmp(upd_rule, "RI_FKey_restrict_upd"))
 
4506
                                upd_rule_type = SQL_NO_ACTION;
 
4507
                        else if (!strcmp(upd_rule, "RI_FKey_setdefault_upd"))
 
4508
                                upd_rule_type = SQL_SET_DEFAULT;
 
4509
                        else if (!strcmp(upd_rule, "RI_FKey_setnull_upd"))
 
4510
                                upd_rule_type = SQL_SET_NULL;
 
4511
 
 
4512
                        if (!strcmp(del_rule, "RI_FKey_cascade_del"))
 
4513
                                del_rule_type = SQL_CASCADE;
 
4514
                        else if (!strcmp(del_rule, "RI_FKey_noaction_del"))
 
4515
                                del_rule_type = SQL_NO_ACTION;
 
4516
                        else if (!strcmp(del_rule, "RI_FKey_restrict_del"))
 
4517
                                del_rule_type = SQL_NO_ACTION;
 
4518
                        else if (!strcmp(del_rule, "RI_FKey_setdefault_del"))
 
4519
                                del_rule_type = SQL_SET_DEFAULT;
 
4520
                        else if (!strcmp(del_rule, "RI_FKey_setnull_del"))
 
4521
                                del_rule_type = SQL_SET_NULL;
 
4522
 
 
4523
#if (ODBCVER >= 0x0300)
 
4524
                        /* Set deferrability type */
 
4525
                        if (!strcmp(trig_initdeferred, "y"))
 
4526
                                defer_type = SQL_INITIALLY_DEFERRED;
 
4527
                        else if (!strcmp(trig_deferrable, "y"))
 
4528
                                defer_type = SQL_INITIALLY_IMMEDIATE;
 
4529
                        else
 
4530
                                defer_type = SQL_NOT_DEFERRABLE;
 
4531
#endif   /* ODBCVER >= 0x0300 */
 
4532
 
 
4533
                        /* Get to first primary key */
 
4534
                        pkey_ptr = trig_args;
 
4535
                        for (i = 0; i < 5; i++)
 
4536
                                pkey_ptr += strlen(pkey_ptr) + 1;
 
4537
 
 
4538
                        for (k = 0; k < num_keys; k++)
 
4539
                        {
 
4540
                                tuple = QR_AddNew(res);
 
4541
 
 
4542
                                pkey_text = getClientColumnName(conn, relid2, pkey_ptr, &pkey_alloced);
 
4543
                                fkey_text = getClientColumnName(conn, relid1, fkey_ptr, &fkey_alloced);
 
4544
 
 
4545
                                mylog("%s: pk_table = '%s', pkey_ptr = '%s'\n", func, pk_table_fetched, pkey_text);
 
4546
                                set_tuplefield_string(&tuple[FKS_PKTABLE_CAT], CurrCat(conn));
 
4547
                                set_tuplefield_string(&tuple[FKS_PKTABLE_SCHEM], GET_SCHEMA_NAME(schema_fetched));
 
4548
                                set_tuplefield_string(&tuple[FKS_PKTABLE_NAME], pk_table_fetched);
 
4549
                                set_tuplefield_string(&tuple[FKS_PKCOLUMN_NAME], pkey_text);
 
4550
 
 
4551
                                mylog("%s: fk_table_needed = '%s', fkey_ptr = '%s'\n", func, fk_table_needed, fkey_text);
 
4552
                                set_tuplefield_string(&tuple[FKS_FKTABLE_CAT], CurrCat(conn));
 
4553
                                set_tuplefield_string(&tuple[FKS_FKTABLE_SCHEM], GET_SCHEMA_NAME(schema_needed));
 
4554
                                set_tuplefield_string(&tuple[FKS_FKTABLE_NAME], fk_table_needed);
 
4555
                                set_tuplefield_string(&tuple[FKS_FKCOLUMN_NAME], fkey_text);
 
4556
 
 
4557
                                mylog("%s: upd_rule_type = '%i', del_rule_type = '%i'\n, trig_name = '%s'", func, upd_rule_type, del_rule_type, trig_args);
 
4558
                                set_tuplefield_int2(&tuple[FKS_KEY_SEQ], (Int2) (k + 1));
 
4559
                                set_tuplefield_int2(&tuple[FKS_UPDATE_RULE], upd_rule_type);
 
4560
                                set_tuplefield_int2(&tuple[FKS_DELETE_RULE], del_rule_type);
 
4561
                                set_tuplefield_string(&tuple[FKS_FK_NAME], constrname);
 
4562
                                set_tuplefield_string(&tuple[FKS_PK_NAME], pkname);
 
4563
#if (ODBCVER >= 0x0300)
 
4564
                                set_tuplefield_int2(&tuple[FKS_DEFERRABILITY], defer_type);
 
4565
#endif   /* ODBCVER >= 0x0300 */
 
4566
                                set_tuplefield_string(&tuple[FKS_TRIGGER_NAME], trig_args);
 
4567
 
 
4568
                                if (fkey_alloced)
 
4569
                                        free(fkey_text);
 
4570
                                fkey_alloced = FALSE;
 
4571
                                if (pkey_alloced)
 
4572
                                        free(pkey_text);
 
4573
                                pkey_alloced = FALSE;
 
4574
                                /* next primary/foreign key */
 
4575
                                for (i = 0; i < 2; i++)
 
4576
                                {
 
4577
                                        fkey_ptr += strlen(fkey_ptr) + 1;
 
4578
                                        pkey_ptr += strlen(pkey_ptr) + 1;
 
4579
                                }
 
4580
                        }
 
4581
 
 
4582
                        result = PGAPI_Fetch(htbl_stmt);
 
4583
                }
 
4584
        }
 
4585
 
 
4586
        /*
 
4587
         * Case #1 -- Get the foreign keys in other tables that refer to the
 
4588
         * primary key in the specified table (pktab).  i.e., Who points to
 
4589
         * me?
 
4590
         */
 
4591
        else if (pk_table_needed[0] != '\0')
 
4592
        {
 
4593
                escPkTableName = simpleCatalogEscape(pk_table_needed, SQL_NTS, NULL, conn);
 
4594
                if (conn->schema_support)
 
4595
                {
 
4596
                        char    *escSchemaName;
 
4597
 
 
4598
                        schema_strcat(schema_needed, "%.*s", szPkTableOwner, cbPkTableOwner, szPkTableName, cbPkTableName, conn);
 
4599
                        escSchemaName = simpleCatalogEscape(schema_needed, SQL_NTS, NULL, conn);
 
4600
                        snprintf(tables_query, sizeof(tables_query), "SELECT    pt.tgargs, "
 
4601
                                "       pt.tgnargs, "
 
4602
                                "       pt.tgdeferrable, "
 
4603
                                "       pt.tginitdeferred, "
 
4604
                                "       pp1.proname, "
 
4605
                                "       pp2.proname, "
 
4606
                                "       pc.oid, "
 
4607
                                "       pc1.oid, "
 
4608
                                "       pc1.relname, "
 
4609
                                "       pt.tgconstrname, pn1.nspname "
 
4610
                                "FROM   pg_catalog.pg_class pc, "
 
4611
                                "       pg_catalog.pg_class pc1, "
 
4612
                                "       pg_catalog.pg_proc pp, "
 
4613
                                "       pg_catalog.pg_proc pp1, "
 
4614
                                "       pg_catalog.pg_proc pp2, "
 
4615
                                "       pg_catalog.pg_trigger pt, "
 
4616
                                "       pg_catalog.pg_trigger pt1, "
 
4617
                                "       pg_catalog.pg_trigger pt2, "
 
4618
                                "       pg_catalog.pg_namespace pn, "
 
4619
                                "       pg_catalog.pg_namespace pn1 "
 
4620
                                "WHERE  pc.relname %s'%s' "
 
4621
                                "       AND pn.nspname %s'%s' "
 
4622
                                "       AND pc.relnamespace = pn.oid "
 
4623
                                "       AND pt.tgconstrrelid = pc.oid "
 
4624
                                "       AND pp.oid = pt.tgfoid "
 
4625
                                "       AND pp.proname Like '%%ins' "
 
4626
                                "       AND pt1.tgconstrname = pt.tgconstrname "
 
4627
                                "       AND pt1.tgconstrrelid = pt.tgrelid "
 
4628
                                "       AND pt1.tgrelid = pc.oid "
 
4629
                                "       AND pc1.oid = pt.tgrelid "
 
4630
                                "       AND pp1.oid = pt1.tgfoid "
 
4631
                                "       AND pp1.proname like '%%upd' "
 
4632
                                "       AND (pp1.proname not like '%%check%%') "
 
4633
                                "       AND pt2.tgconstrname = pt.tgconstrname "
 
4634
                                "       AND pt2.tgconstrrelid = pt.tgrelid "
 
4635
                                "       AND pt2.tgrelid = pc.oid "
 
4636
                                "       AND pp2.oid = pt2.tgfoid "
 
4637
                                "       AND pp2.proname Like '%%del' "
 
4638
                                "       AND pn1.oid = pc1.relnamespace "
 
4639
                                " order by pt.tgconstrname",
 
4640
                                eq_string, escPkTableName, eq_string, escSchemaName);
 
4641
                        free(escSchemaName);
 
4642
                }
 
4643
                else
 
4644
                        snprintf(tables_query, sizeof(tables_query), "SELECT    pt.tgargs, "
 
4645
                                "       pt.tgnargs, "
 
4646
                                "       pt.tgdeferrable, "
 
4647
                                "       pt.tginitdeferred, "
 
4648
                                "       pp1.proname, "
 
4649
                                "       pp2.proname, "
 
4650
                                "       pc.oid, "
 
4651
                                "       pc1.oid, "
 
4652
                                "       pc1.relname, pt.tgconstrname "
 
4653
                                "FROM   pg_class pc, "
 
4654
                                "       pg_class pc1, "
 
4655
                                "       pg_proc pp, "
 
4656
                                "       pg_proc pp1, "
 
4657
                                "       pg_proc pp2, "
 
4658
                                "       pg_trigger pt, "
 
4659
                                "       pg_trigger pt1, "
 
4660
                                "       pg_trigger pt2 "
 
4661
                                "WHERE  pc.relname %s'%s' "
 
4662
                                "       AND pt.tgconstrrelid = pc.oid "
 
4663
                                "       AND pp.oid = pt.tgfoid "
 
4664
                                "       AND pp.proname Like '%%ins' "
 
4665
                                "       AND pt1.tgconstrname = pt.tgconstrname "
 
4666
                                "       AND pt1.tgconstrrelid = pt.tgrelid "
 
4667
                                "       AND pt1.tgrelid = pc.oid "
 
4668
                                "       AND pc1.oid = pt.tgrelid "
 
4669
                                "       AND pp1.oid = pt1.tgfoid "
 
4670
                                "       AND pp1.proname like '%%upd' "
 
4671
                                "       AND pp1.(proname not like '%%check%%') "
 
4672
                                "       AND pt2.tgconstrname = pt.tgconstrname "
 
4673
                                "       AND pt2.tgconstrrelid = pt.tgrelid "
 
4674
                                "       AND pt2.tgrelid = pc.oid "
 
4675
                                "       AND pp2.oid = pt2.tgfoid "
 
4676
                                "       AND pp2.proname Like '%%del'"
 
4677
                                " order by pt.tgconstrname",
 
4678
                                eq_string, escPkTableName);
 
4679
 
 
4680
                result = PGAPI_ExecDirect(htbl_stmt, tables_query, SQL_NTS, 0);
 
4681
                if (!SQL_SUCCEEDED(result))
 
4682
                {
 
4683
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4684
                        goto cleanup;
 
4685
                }
 
4686
 
 
4687
                result = PGAPI_BindCol(htbl_stmt, 1, SQL_C_BINARY,
 
4688
                                                           trig_args, sizeof(trig_args), NULL);
 
4689
                if (!SQL_SUCCEEDED(result))
 
4690
                {
 
4691
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4692
                        goto cleanup;
 
4693
                }
 
4694
 
 
4695
                result = PGAPI_BindCol(htbl_stmt, 2, SQL_C_SHORT,
 
4696
                                                           &trig_nargs, 0, NULL);
 
4697
                if (!SQL_SUCCEEDED(result))
 
4698
                {
 
4699
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4700
                        goto cleanup;
 
4701
                }
 
4702
 
 
4703
                result = PGAPI_BindCol(htbl_stmt, 3, internal_asis_type,
 
4704
                                                 trig_deferrable, sizeof(trig_deferrable), NULL);
 
4705
                if (!SQL_SUCCEEDED(result))
 
4706
                {
 
4707
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4708
                        goto cleanup;
 
4709
                }
 
4710
 
 
4711
                result = PGAPI_BindCol(htbl_stmt, 4, internal_asis_type,
 
4712
                                         trig_initdeferred, sizeof(trig_initdeferred), NULL);
 
4713
                if (!SQL_SUCCEEDED(result))
 
4714
                {
 
4715
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4716
                        goto cleanup;
 
4717
                }
 
4718
 
 
4719
                result = PGAPI_BindCol(htbl_stmt, 5, internal_asis_type,
 
4720
                                                           upd_rule, sizeof(upd_rule), NULL);
 
4721
                if (!SQL_SUCCEEDED(result))
 
4722
                {
 
4723
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4724
                        goto cleanup;
 
4725
                }
 
4726
 
 
4727
                result = PGAPI_BindCol(htbl_stmt, 6, internal_asis_type,
 
4728
                                                           del_rule, sizeof(del_rule), NULL);
 
4729
                if (!SQL_SUCCEEDED(result))
 
4730
                {
 
4731
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4732
                        goto cleanup;
 
4733
                }
 
4734
 
 
4735
                result = PGAPI_BindCol(htbl_stmt, 7, SQL_C_ULONG,
 
4736
                                                &relid1, sizeof(relid1), NULL);
 
4737
                if (!SQL_SUCCEEDED(result))
 
4738
                {
 
4739
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4740
                        goto cleanup;
 
4741
                }
 
4742
                result = PGAPI_BindCol(htbl_stmt, 8, SQL_C_ULONG,
 
4743
                                                &relid2, sizeof(relid2), NULL);
 
4744
                if (!SQL_SUCCEEDED(result))
 
4745
                {
 
4746
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4747
                        goto cleanup;
 
4748
                }
 
4749
                result = PGAPI_BindCol(htbl_stmt, 9, internal_asis_type,
 
4750
                                        fk_table_fetched, TABLE_NAME_STORAGE_LEN, NULL);
 
4751
                if (!SQL_SUCCEEDED(result))
 
4752
                {
 
4753
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4754
                        goto cleanup;
 
4755
                }
 
4756
                result = PGAPI_BindCol(htbl_stmt, 10, internal_asis_type,
 
4757
                                        constrname, NAMESTORAGELEN, NULL);
 
4758
                if (!SQL_SUCCEEDED(result))
 
4759
                {
 
4760
                        SC_error_copy(stmt, tbl_stmt, TRUE);
 
4761
                        goto cleanup;
 
4762
                }
 
4763
 
 
4764
                if (conn->schema_support)
 
4765
                {
 
4766
                        result = PGAPI_BindCol(htbl_stmt, 11, internal_asis_type,
 
4767
                                        schema_fetched, SCHEMA_NAME_STORAGE_LEN, NULL);
 
4768
                        if (!SQL_SUCCEEDED(result))
 
4769
                        {
 
4770
                                SC_error_copy(stmt, tbl_stmt, TRUE);
 
4771
                                goto cleanup;
 
4772
                        }
 
4773
                }
 
4774
 
 
4775
                result = PGAPI_Fetch(htbl_stmt);
 
4776
                if (result == SQL_NO_DATA_FOUND)
 
4777
                {
 
4778
                        ret = SQL_SUCCESS;
 
4779
                        goto cleanup;
 
4780
                }
 
4781
 
 
4782
                if (result != SQL_SUCCESS)
 
4783
                {
 
4784
                        SC_full_error_copy(stmt, tbl_stmt, FALSE);
 
4785
                        goto cleanup;
 
4786
                }
 
4787
 
 
4788
                /*
 
4789
                 *      get pk_name here
 
4790
                 */
 
4791
                keyresult = PGAPI_AllocStmt(conn, &hpkey_stmt, 0);
 
4792
                if (!SQL_SUCCEEDED(keyresult))
 
4793
                {
 
4794
                        SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate statement for PGAPI_ForeignKeys (pkeys) result.", func);
 
4795
                        goto cleanup;
 
4796
                }
 
4797
                keyresult = PGAPI_BindCol(hpkey_stmt, 6, internal_asis_type,
 
4798
                                pkname, sizeof(pkname), NULL);
 
4799
                if (keyresult != SQL_SUCCESS)
 
4800
                {
 
4801
                        SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't bindcol for primary keys for PGAPI_ForeignKeys result.", func);
 
4802
                        goto cleanup;
 
4803
                }
 
4804
                keyresult = PGAPI_PrimaryKeys(hpkey_stmt, NULL, 0, schema_needed, SQL_NTS, pk_table_needed, SQL_NTS, 0);
 
4805
                if (keyresult != SQL_SUCCESS)
 
4806
                {
 
4807
                        SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't get primary keys for PGAPI_ForeignKeys result.", func);
 
4808
                        goto cleanup;
 
4809
                }
 
4810
                pkname[0] = '\0';
 
4811
                keyresult = PGAPI_Fetch(hpkey_stmt);
 
4812
                PGAPI_FreeStmt(hpkey_stmt, SQL_CLOSE);
 
4813
                while (result == SQL_SUCCESS)
 
4814
                {
 
4815
                        /* Calculate the number of key parts */
 
4816
                        num_keys = (trig_nargs - 4) / 2;;
 
4817
 
 
4818
                        /* Handle action (i.e., 'cascade', 'restrict', 'setnull') */
 
4819
                        if (!strcmp(upd_rule, "RI_FKey_cascade_upd"))
 
4820
                                upd_rule_type = SQL_CASCADE;
 
4821
                        else if (!strcmp(upd_rule, "RI_FKey_noaction_upd"))
 
4822
                                upd_rule_type = SQL_NO_ACTION;
 
4823
                        else if (!strcmp(upd_rule, "RI_FKey_restrict_upd"))
 
4824
                                upd_rule_type = SQL_NO_ACTION;
 
4825
                        else if (!strcmp(upd_rule, "RI_FKey_setdefault_upd"))
 
4826
                                upd_rule_type = SQL_SET_DEFAULT;
 
4827
                        else if (!strcmp(upd_rule, "RI_FKey_setnull_upd"))
 
4828
                                upd_rule_type = SQL_SET_NULL;
 
4829
 
 
4830
                        if (!strcmp(del_rule, "RI_FKey_cascade_del"))
 
4831
                                del_rule_type = SQL_CASCADE;
 
4832
                        else if (!strcmp(del_rule, "RI_FKey_noaction_del"))
 
4833
                                del_rule_type = SQL_NO_ACTION;
 
4834
                        else if (!strcmp(del_rule, "RI_FKey_restrict_del"))
 
4835
                                del_rule_type = SQL_NO_ACTION;
 
4836
                        else if (!strcmp(del_rule, "RI_FKey_setdefault_del"))
 
4837
                                del_rule_type = SQL_SET_DEFAULT;
 
4838
                        else if (!strcmp(del_rule, "RI_FKey_setnull_del"))
 
4839
                                del_rule_type = SQL_SET_NULL;
 
4840
 
 
4841
#if (ODBCVER >= 0x0300)
 
4842
                        /* Set deferrability type */
 
4843
                        if (!strcmp(trig_initdeferred, "y"))
 
4844
                                defer_type = SQL_INITIALLY_DEFERRED;
 
4845
                        else if (!strcmp(trig_deferrable, "y"))
 
4846
                                defer_type = SQL_INITIALLY_IMMEDIATE;
 
4847
                        else
 
4848
                                defer_type = SQL_NOT_DEFERRABLE;
 
4849
#endif   /* ODBCVER >= 0x0300 */
 
4850
 
 
4851
                        mylog("Foreign Key Case#1: trig_nargs = %d, num_keys = %d\n", trig_nargs, num_keys);
 
4852
 
 
4853
                        /* Get to first primary key */
 
4854
                        pkey_ptr = trig_args;
 
4855
                        for (i = 0; i < 5; i++)
 
4856
                                pkey_ptr += strlen(pkey_ptr) + 1;
 
4857
 
 
4858
                        /* Get to first foreign key */
 
4859
                        fkey_ptr = trig_args;
 
4860
                        for (k = 0; k < 4; k++)
 
4861
                                fkey_ptr += strlen(fkey_ptr) + 1;
 
4862
 
 
4863
                        for (k = 0; k < num_keys; k++)
 
4864
                        {
 
4865
                                pkey_text = getClientColumnName(conn, relid1, pkey_ptr, &pkey_alloced);
 
4866
                                fkey_text = getClientColumnName(conn, relid2, fkey_ptr, &fkey_alloced);
 
4867
 
 
4868
                                mylog("pkey_ptr = '%s', fk_table = '%s', fkey_ptr = '%s'\n", pkey_text, fk_table_fetched, fkey_text);
 
4869
 
 
4870
                                tuple = QR_AddNew(res);
 
4871
 
 
4872
                                mylog("pk_table_needed = '%s', pkey_ptr = '%s'\n", pk_table_needed, pkey_text);
 
4873
                                set_tuplefield_string(&tuple[FKS_PKTABLE_CAT], CurrCat(conn));
 
4874
                                set_tuplefield_string(&tuple[FKS_PKTABLE_SCHEM], GET_SCHEMA_NAME(schema_needed));
 
4875
                                set_tuplefield_string(&tuple[FKS_PKTABLE_NAME], pk_table_needed);
 
4876
                                set_tuplefield_string(&tuple[FKS_PKCOLUMN_NAME], pkey_text);
 
4877
 
 
4878
                                mylog("fk_table = '%s', fkey_ptr = '%s'\n", fk_table_fetched, fkey_text);
 
4879
                                set_tuplefield_string(&tuple[FKS_FKTABLE_CAT], CurrCat(conn));
 
4880
                                set_tuplefield_string(&tuple[FKS_FKTABLE_SCHEM], GET_SCHEMA_NAME(schema_fetched));
 
4881
                                set_tuplefield_string(&tuple[FKS_FKTABLE_NAME], fk_table_fetched);
 
4882
                                set_tuplefield_string(&tuple[FKS_FKCOLUMN_NAME], fkey_text);
 
4883
 
 
4884
                                set_tuplefield_int2(&tuple[FKS_KEY_SEQ], (Int2) (k + 1));
 
4885
 
 
4886
                                mylog("upd_rule = %d, del_rule= %d", upd_rule_type, del_rule_type);
 
4887
                                set_nullfield_int2(&tuple[FKS_UPDATE_RULE], upd_rule_type);
 
4888
                                set_nullfield_int2(&tuple[FKS_DELETE_RULE], del_rule_type);
 
4889
 
 
4890
                                set_tuplefield_string(&tuple[FKS_FK_NAME], constrname);
 
4891
                                set_tuplefield_string(&tuple[FKS_PK_NAME], pkname);
 
4892
 
 
4893
                                set_tuplefield_string(&tuple[FKS_TRIGGER_NAME], trig_args);
 
4894
 
 
4895
#if (ODBCVER >= 0x0300)
 
4896
                                mylog(" defer_type = %d\n", defer_type);
 
4897
                                set_tuplefield_int2(&tuple[FKS_DEFERRABILITY], defer_type);
 
4898
#endif   /* ODBCVER >= 0x0300 */
 
4899
 
 
4900
                                if (pkey_alloced)
 
4901
                                        free(pkey_text);
 
4902
                                pkey_alloced = FALSE;
 
4903
                                if (fkey_alloced)
 
4904
                                        free(fkey_text);
 
4905
                                fkey_alloced = FALSE;
 
4906
 
 
4907
                                /* next primary/foreign key */
 
4908
                                for (j = 0; j < 2; j++)
 
4909
                                {
 
4910
                                        pkey_ptr += strlen(pkey_ptr) + 1;
 
4911
                                        fkey_ptr += strlen(fkey_ptr) + 1;
 
4912
                                }
 
4913
                        }
 
4914
                        result = PGAPI_Fetch(htbl_stmt);
 
4915
                }
 
4916
        }
 
4917
        else
 
4918
        {
 
4919
                SC_set_error(stmt, STMT_INTERNAL_ERROR, "No tables specified to PGAPI_ForeignKeys.", func);
 
4920
                goto cleanup;
 
4921
        }
 
4922
        ret = SQL_SUCCESS;
 
4923
 
 
4924
cleanup:
 
4925
#undef  return
 
4926
        /*
 
4927
         * also, things need to think that this statement is finished so the
 
4928
         * results can be retrieved.
 
4929
         */
 
4930
        stmt->status = STMT_FINISHED;
 
4931
 
 
4932
        if (pkey_alloced)
 
4933
                free(pkey_text);
 
4934
        if (fkey_alloced)
 
4935
                free(fkey_text);
 
4936
        if (pk_table_needed)
 
4937
                free(pk_table_needed);
 
4938
        if (escPkTableName)
 
4939
                free(escPkTableName);
 
4940
        if (fk_table_needed)
 
4941
                free(fk_table_needed);
 
4942
        if (escFkTableName)
 
4943
                free(escFkTableName);
 
4944
 
 
4945
        if (htbl_stmt)
 
4946
                PGAPI_FreeStmt(htbl_stmt, SQL_DROP);
 
4947
        if (hpkey_stmt)
 
4948
                PGAPI_FreeStmt(hpkey_stmt, SQL_DROP);
 
4949
 
 
4950
        /* set up the current tuple pointer for SQLFetch */
 
4951
        stmt->currTuple = -1;
 
4952
        SC_set_rowset_start(stmt, -1, FALSE);
 
4953
        SC_set_current_col(stmt, -1);
 
4954
 
 
4955
        if (stmt->internal)
 
4956
                ret = DiscardStatementSvp(stmt, ret, FALSE);
 
4957
        mylog("%s(): EXIT, stmt=%p, ret=%d\n", func, stmt, ret);
 
4958
        return ret;
 
4959
}
 
4960
 
 
4961
RETCODE         SQL_API
 
4962
PGAPI_ForeignKeys(
 
4963
                        HSTMT hstmt,
 
4964
                        const SQLCHAR FAR * szPkTableQualifier, /* OA X*/
 
4965
                        SQLSMALLINT cbPkTableQualifier,
 
4966
                        const SQLCHAR FAR * szPkTableOwner, /* OA E*/
 
4967
                        SQLSMALLINT cbPkTableOwner,
 
4968
                        const SQLCHAR FAR * szPkTableName, /* OA(R) E*/
 
4969
                        SQLSMALLINT cbPkTableName,
 
4970
                        const SQLCHAR FAR * szFkTableQualifier, /* OA X*/
 
4971
                        SQLSMALLINT cbFkTableQualifier,
 
4972
                        const SQLCHAR FAR * szFkTableOwner, /* OA E*/
 
4973
                        SQLSMALLINT cbFkTableOwner,
 
4974
                        const SQLCHAR FAR * szFkTableName, /* OA(R) E*/
 
4975
                        SQLSMALLINT cbFkTableName)
 
4976
{
 
4977
        ConnectionClass *conn = SC_get_conn(((StatementClass *) hstmt));
 
4978
        if (PG_VERSION_GE(conn, 8.1))
 
4979
                return PGAPI_ForeignKeys_new(hstmt,
 
4980
                                szPkTableQualifier, cbPkTableQualifier,
 
4981
                                szPkTableOwner, cbPkTableOwner,
 
4982
                                szPkTableName, cbPkTableName,
 
4983
                                szFkTableQualifier, cbFkTableQualifier,
 
4984
                                szFkTableOwner, cbFkTableOwner,
 
4985
                                szFkTableName, cbFkTableName);
 
4986
        else
 
4987
                return PGAPI_ForeignKeys_old(hstmt,
 
4988
                                szPkTableQualifier, cbPkTableQualifier,
 
4989
                                szPkTableOwner, cbPkTableOwner,
 
4990
                                szPkTableName, cbPkTableName,
 
4991
                                szFkTableQualifier, cbFkTableQualifier,
 
4992
                                szFkTableOwner, cbFkTableOwner,
 
4993
                                szFkTableName, cbFkTableName);
 
4994
}
 
4995
 
 
4996
 
 
4997
#define PRORET_COUNT
 
4998
#define DISPLAY_ARGNAME
 
4999
RETCODE         SQL_API
 
5000
PGAPI_ProcedureColumns(
 
5001
                                HSTMT hstmt,
 
5002
                                const SQLCHAR FAR * szProcQualifier, /* OA X*/
 
5003
                                SQLSMALLINT cbProcQualifier,
 
5004
                                const SQLCHAR FAR * szProcOwner, /* PV E*/
 
5005
                                SQLSMALLINT cbProcOwner,
 
5006
                                const SQLCHAR FAR * szProcName, /* PV E*/
 
5007
                                SQLSMALLINT cbProcName,
 
5008
                                const SQLCHAR FAR * szColumnName, /* PV X*/
 
5009
                                SQLSMALLINT cbColumnName,
 
5010
                                UWORD flag)
 
5011
{
 
5012
        CSTR func = "PGAPI_ProcedureColumns";
 
5013
        StatementClass  *stmt = (StatementClass *) hstmt;
 
5014
        ConnectionClass *conn = SC_get_conn(stmt);
 
5015
        char            proc_query[INFO_INQUIRY_LEN];
 
5016
        Int2            result_cols;
 
5017
        TupleField      *tuple;
 
5018
        char            *schema_name, *procname;
 
5019
        char            *escSchemaName = NULL, *escProcName = NULL;
 
5020
        char            *params, *proargnames, *proargmodes, *delim = NULL;
 
5021
        char            *atttypid, *attname, *column_name;
 
5022
        QResultClass *res, *tres;
 
5023
        SQLLEN          tcount;
 
5024
        OID             pgtype;
 
5025
        Int4            paramcount, column_size, i, j;
 
5026
        RETCODE         result;
 
5027
        BOOL            search_pattern, bRetset;
 
5028
        const char      *like_or_eq, *op_string, *retset;
 
5029
        int             ret_col = -1, ext_pos = -1, poid_pos = -1, attid_pos = -1, attname_pos = -1;
 
5030
        UInt4           poid = 0, newpoid;
 
5031
 
 
5032
        mylog("%s: entering...\n", func);
 
5033
 
 
5034
        if (PG_VERSION_LT(conn, 6.5))
 
5035
        {
 
5036
                SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Version is too old", func);
 
5037
                return SQL_ERROR;
 
5038
        }
 
5039
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
 
5040
                return result;
 
5041
        search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
 
5042
        if (search_pattern) 
 
5043
        {
 
5044
                like_or_eq = likeop;
 
5045
                escSchemaName = adjustLikePattern(szProcOwner, cbProcOwner, SEARCH_PATTERN_ESCAPE, NULL, conn);
 
5046
                escProcName = adjustLikePattern(szProcName, cbProcName, SEARCH_PATTERN_ESCAPE, NULL, conn);
 
5047
        }
 
5048
        else
 
5049
        {
 
5050
                like_or_eq = eqop;
 
5051
                escSchemaName = simpleCatalogEscape(szProcOwner, cbProcOwner, NULL, conn);
 
5052
                escProcName = simpleCatalogEscape(szProcName, cbProcName, NULL, conn);
 
5053
        }
 
5054
        op_string = gen_opestr(like_or_eq, conn);
 
5055
        if (conn->schema_support)
 
5056
        {
 
5057
                strcpy(proc_query, "select proname, proretset, prorettype, "
 
5058
                                "pronargs, proargtypes, nspname, p.oid");
 
5059
                ret_col = ext_pos = 7;
 
5060
                poid_pos = 6;
 
5061
#ifdef  PRORET_COUNT
 
5062
                strcat(proc_query, ", atttypid, attname");
 
5063
                attid_pos = ext_pos;
 
5064
                attname_pos = ext_pos + 1;
 
5065
                ret_col += 2;
 
5066
                ext_pos = ret_col;
 
5067
#endif /* PRORET_COUNT */
 
5068
                if (PG_VERSION_GE(conn, 8.0))
 
5069
                {
 
5070
                        strcat(proc_query, ", proargnames");
 
5071
                        ret_col++;
 
5072
                }
 
5073
                if (PG_VERSION_GE(conn, 8.1))
 
5074
                {
 
5075
                        strcat(proc_query, ", proargmodes, proallargtypes");
 
5076
                        ret_col += 2;
 
5077
                }
 
5078
#ifdef  PRORET_COUNT
 
5079
                strcat(proc_query, " from ((pg_catalog.pg_namespace n inner join"
 
5080
                                   " pg_catalog.pg_proc p on p.pronamespace = n.oid)"
 
5081
                        " inner join pg_type t on t.oid = p.prorettype)"
 
5082
                        " left outer join pg_attribute a on a.attrelid = t.typrelid "
 
5083
                        " and attnum > 0 and not attisdropped where");
 
5084
#else
 
5085
                strcat(proc_query, " from pg_catalog.pg_namespace n,"
 
5086
                                   " pg_catalog.pg_proc p where");
 
5087
                                   " p.pronamespace = n.oid  and"
 
5088
                                   " (not proretset) and");
 
5089
#endif /* PRORET_COUNT */
 
5090
                strcat(proc_query, " has_function_privilege(p.oid, 'EXECUTE')");
 
5091
                my_strcat1(proc_query, " and nspname %s'%.*s'", op_string, escSchemaName, SQL_NTS);
 
5092
                if (escProcName)
 
5093
                        snprintf_add(proc_query, sizeof(proc_query), " and proname %s'%s'", op_string, escProcName);
 
5094
                strcat(proc_query, " order by nspname, proname, p.oid, attnum");
 
5095
        }
 
5096
        else
 
5097
        {
 
5098
                strcpy(proc_query, "select proname, proretset, prorettype, "
 
5099
                                "pronargs, proargtypes from pg_proc where "
 
5100
                                "(not proretset)");
 
5101
                ret_col = 5;
 
5102
                if (escProcName)
 
5103
                        snprintf_add(proc_query, sizeof(proc_query), " and proname %s'%s'", op_string, escProcName);
 
5104
                strcat(proc_query, " order by proname, proretset");
 
5105
        }
 
5106
        if (tres = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(tres))
 
5107
        {
 
5108
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_ProcedureColumns query error", func);
 
5109
                QR_Destructor(tres);
 
5110
                return SQL_ERROR;
 
5111
        }
 
5112
 
 
5113
        if (res = QR_Constructor(), !res)
 
5114
        {
 
5115
                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for PGAPI_ProcedureColumns result.", func);
 
5116
                return SQL_ERROR;
 
5117
        }
 
5118
        SC_set_Result(stmt, res);
 
5119
 
 
5120
        /*
 
5121
         * the binding structure for a statement is not set up until
 
5122
         * a statement is actually executed, so we'll have to do this
 
5123
         * ourselves.
 
5124
         */
 
5125
        result_cols = NUM_OF_PROCOLS_FIELDS;
 
5126
        extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
5127
 
 
5128
        stmt->catalog_result = TRUE;
 
5129
        /* set the field names */
 
5130
        QR_set_num_fields(res, result_cols);
 
5131
        QR_set_field_info_v(res, PROCOLS_PROCEDURE_CAT, "PROCEDURE_CAT", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
5132
        QR_set_field_info_v(res, PROCOLS_PROCEDURE_SCHEM, "PROCEDUR_SCHEM", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
5133
        QR_set_field_info_v(res, PROCOLS_PROCEDURE_NAME, "PROCEDURE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
5134
        QR_set_field_info_v(res, PROCOLS_COLUMN_NAME, "COLUMN_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
5135
        QR_set_field_info_v(res, PROCOLS_COLUMN_TYPE, "COLUMN_TYPE", PG_TYPE_INT2, 2);
 
5136
        QR_set_field_info_v(res, PROCOLS_DATA_TYPE, "DATA_TYPE", PG_TYPE_INT2, 2);
 
5137
        QR_set_field_info_v(res, PROCOLS_TYPE_NAME, "TYPE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
5138
        QR_set_field_info_v(res, PROCOLS_COLUMN_SIZE, "COLUMN_SIZE", PG_TYPE_INT4, 4);
 
5139
        QR_set_field_info_v(res, PROCOLS_BUFFER_LENGTH, "BUFFER_LENGTH", PG_TYPE_INT4, 4);
 
5140
        QR_set_field_info_v(res, PROCOLS_DECIMAL_DIGITS, "DECIMAL_DIGITS", PG_TYPE_INT2, 2);
 
5141
        QR_set_field_info_v(res, PROCOLS_NUM_PREC_RADIX, "NUM_PREC_RADIX", PG_TYPE_INT2, 2);
 
5142
        QR_set_field_info_v(res, PROCOLS_NULLABLE, "NULLABLE", PG_TYPE_INT2, 2);
 
5143
        QR_set_field_info_v(res, PROCOLS_REMARKS, "REMARKS", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
5144
#if (ODBCVER >= 0x0300)
 
5145
        QR_set_field_info_v(res, PROCOLS_COLUMN_DEF, "COLUMN_DEF", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
5146
        QR_set_field_info_v(res, PROCOLS_SQL_DATA_TYPE, "SQL_DATA_TYPE", PG_TYPE_INT2, 2);
 
5147
        QR_set_field_info_v(res, PROCOLS_SQL_DATETIME_SUB, "SQL_DATETIME_SUB", PG_TYPE_INT2, 2);
 
5148
        QR_set_field_info_v(res, PROCOLS_CHAR_OCTET_LENGTH, "CHAR_OCTET_LENGTH", PG_TYPE_INT4, 4);
 
5149
        QR_set_field_info_v(res, PROCOLS_ORDINAL_POSITION, "ORDINAL_POSITION", PG_TYPE_INT4, 4);
 
5150
        QR_set_field_info_v(res, PROCOLS_IS_NULLABLE, "IS_NULLABLE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
5151
#endif   /* ODBCVER >= 0x0300 */
 
5152
 
 
5153
        column_name = make_string(szColumnName, cbColumnName, NULL, 0);
 
5154
        if (column_name) /* column_name is unavailable now */
 
5155
        {
 
5156
                tcount = 0;
 
5157
                free(column_name);
 
5158
        }
 
5159
        else
 
5160
                tcount = QR_get_num_total_tuples(tres);
 
5161
        for (i = 0, poid = 0; i < tcount; i++)
 
5162
        {
 
5163
                if (conn->schema_support)
 
5164
                        schema_name = GET_SCHEMA_NAME(QR_get_value_backend_text(tres, i, 5));
 
5165
                else
 
5166
                        schema_name = NULL;
 
5167
                procname = QR_get_value_backend_text(tres, i, 0);
 
5168
                retset = QR_get_value_backend_text(tres, i, 1);
 
5169
                pgtype = QR_get_value_backend_int(tres, i, 2, NULL);
 
5170
                bRetset = retset && (retset[0] == 't' || retset[0] == 'y');
 
5171
                newpoid = 0;
 
5172
                if (poid_pos >= 0)
 
5173
                        newpoid = QR_get_value_backend_int(tres, i, poid_pos, NULL);
 
5174
mylog("newpoid=%d\n", newpoid);
 
5175
                atttypid = NULL;
 
5176
                if (attid_pos >= 0)
 
5177
                {
 
5178
                        atttypid = QR_get_value_backend_text(tres, i, attid_pos);
 
5179
mylog("atttypid=%s\n", atttypid ? atttypid : "(null)");
 
5180
                }
 
5181
                if (poid == 0 || newpoid != poid)
 
5182
                {
 
5183
                        poid = newpoid;
 
5184
                        proargmodes = NULL;
 
5185
                        proargnames = NULL;
 
5186
                        if (ext_pos >=0)
 
5187
                        {
 
5188
#ifdef  DISPLAY_ARGNAME /* !! named parameter is unavailable !! */
 
5189
                                if (PG_VERSION_GE(conn, 8.0))
 
5190
                                        proargnames = QR_get_value_backend_text(tres, i, ext_pos);
 
5191
#endif /* DISPLAY_ARGNAME */
 
5192
                                if (PG_VERSION_GE(conn, 8.1))
 
5193
                                        proargmodes = QR_get_value_backend_text(tres, i, ext_pos + 1);
 
5194
                        }
 
5195
                        /* RETURN_VALUE info */ 
 
5196
                        if (0 != pgtype && PG_TYPE_VOID != pgtype && !bRetset && !atttypid && !proargmodes)
 
5197
                        {
 
5198
                                tuple = QR_AddNew(res);
 
5199
                                set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_CAT], CurrCat(conn));
 
5200
                                set_nullfield_string(&tuple[PROCOLS_PROCEDURE_SCHEM], schema_name);
 
5201
                                set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_NAME], procname);
 
5202
                                set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME], NULL_STRING);
 
5203
                                set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE], SQL_RETURN_VALUE);
 
5204
                                set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
 
5205
                                set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, pgtype, PG_UNSPECIFIED, FALSE));
 
5206
                                column_size = pgtype_column_size(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT);
 
5207
                                set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE], column_size);
 
5208
                                set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH], pgtype_buffer_length(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
5209
                                set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
 
5210
                                set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(conn, pgtype));
 
5211
                                set_tuplefield_int2(&tuple[PROCOLS_NULLABLE], SQL_NULLABLE_UNKNOWN);
 
5212
                                set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
 
5213
#if (ODBCVER >= 0x0300)
 
5214
                                set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
 
5215
                                set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
 
5216
                                set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, pgtype, PG_UNSPECIFIED));
 
5217
                                set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, pgtype, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
 
5218
                                set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION], 0);
 
5219
                                set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE], NULL_STRING);
 
5220
#endif   /* ODBCVER >= 0x0300 */
 
5221
                        }
 
5222
                        if (proargmodes)
 
5223
                        {
 
5224
                                const char *p;
 
5225
 
 
5226
                                paramcount = 0;
 
5227
                                for (p = proargmodes; *p; p++)
 
5228
                                {
 
5229
                                        if (',' == (*p))
 
5230
                                                paramcount++;
 
5231
                                }
 
5232
                                paramcount++;
 
5233
                                params = QR_get_value_backend_text(tres, i, ext_pos + 2);
 
5234
                                if ('{' == *proargmodes)
 
5235
                                        proargmodes++;
 
5236
                                if ('{' == *params)
 
5237
                                        params++;
 
5238
                        }
 
5239
                        else
 
5240
                        {
 
5241
                                paramcount = QR_get_value_backend_int(tres, i, 3, NULL);
 
5242
                                params = QR_get_value_backend_text(tres, i, 4);
 
5243
                        }
 
5244
                        if (proargnames)
 
5245
                        {
 
5246
                                if ('{' == *proargnames)
 
5247
                                        proargnames++;
 
5248
                        }
 
5249
                        /* PARAMETERS info */
 
5250
                        for (j = 0; j < paramcount; j++)
 
5251
                        {
 
5252
                                /* PG type of parameters */
 
5253
                                pgtype = 0;
 
5254
                                if (params)
 
5255
                                {
 
5256
                                        while (isspace(*params) || ',' == *params)
 
5257
                                                params++;
 
5258
                                        if ('\0' == *params || '}' == *params)
 
5259
                                                params = NULL;
 
5260
                                        else
 
5261
                                        {
 
5262
                                                sscanf(params, "%u", &pgtype);
 
5263
                                                while (isdigit(*params))
 
5264
                                                        params++;
 
5265
                                        }
 
5266
                                }
 
5267
                                /* input/output type of parameters */
 
5268
                                if (proargmodes)
 
5269
                                {
 
5270
                                        while (isspace(*proargmodes) || ',' == *proargmodes)
 
5271
                                                proargmodes++;
 
5272
                                        if ('\0' == *proargmodes || '}' == *proargmodes)
 
5273
                                                proargmodes = NULL;
 
5274
                                }
 
5275
                                /* name of parameters */
 
5276
                                if (proargnames)
 
5277
                                {
 
5278
                                        while (isspace(*proargnames) || ',' == *proargnames)
 
5279
                                                proargnames++;
 
5280
                                        if ('\0' == *proargnames || '}' == *proargnames)
 
5281
                                                proargnames = NULL;
 
5282
                                        else if ('"' == *proargnames)
 
5283
                                        {
 
5284
                                                proargnames++;
 
5285
                                                for (delim = proargnames; *delim && *delim != '"'; delim++)
 
5286
                                                        ;
 
5287
                                        }
 
5288
                                        else
 
5289
                                        {
 
5290
                                                for (delim = proargnames; *delim && !isspace(*delim) && ',' != *delim && '}' != *delim; delim++)
 
5291
                                                        ;
 
5292
                                        }
 
5293
                                        if (proargnames && '\0' == *delim) /* discard the incomplete name */
 
5294
                                                proargnames = NULL;
 
5295
                                }
 
5296
 
 
5297
                                tuple = QR_AddNew(res);
 
5298
                                set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_CAT], CurrCat(conn));
 
5299
                                set_nullfield_string(&tuple[PROCOLS_PROCEDURE_SCHEM], schema_name);
 
5300
                                set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_NAME], procname);
 
5301
                                if (proargnames)
 
5302
                                {
 
5303
                                        *delim = '\0';
 
5304
                                        set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME], proargnames);
 
5305
                                        proargnames = delim + 1;
 
5306
                                }
 
5307
                                else
 
5308
                                        set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME], NULL_STRING);
 
5309
                                if (proargmodes)
 
5310
                                {
 
5311
                                        int     ptype;
 
5312
 
 
5313
                                        switch (*proargmodes)
 
5314
                                        {
 
5315
                                                case 'o':
 
5316
                                                        ptype = SQL_PARAM_OUTPUT;
 
5317
                                                        break;
 
5318
                                                case 'b':
 
5319
                                                        ptype = SQL_PARAM_INPUT_OUTPUT;
 
5320
                                                        break;
 
5321
                                                default:
 
5322
                                                        ptype = SQL_PARAM_INPUT;
 
5323
                                                        break;
 
5324
                                        }
 
5325
                                        set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE], ptype);
 
5326
                                        proargmodes++;
 
5327
                                }
 
5328
                                else
 
5329
                                        set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE], SQL_PARAM_INPUT);
 
5330
                                set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE], pgtype_to_concise_type(stmt, pgtype, PG_STATIC));
 
5331
                                set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, pgtype, PG_UNSPECIFIED, FALSE));
 
5332
                                column_size = pgtype_column_size(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT);
 
5333
                                set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE], column_size);
 
5334
                                set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH], pgtype_buffer_length(stmt, pgtype, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
5335
                                set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS], pgtype_decimal_digits(stmt, pgtype, PG_STATIC));
 
5336
                                set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(conn, pgtype));
 
5337
                                set_tuplefield_int2(&tuple[PROCOLS_NULLABLE], SQL_NULLABLE_UNKNOWN);
 
5338
                                set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
 
5339
#if (ODBCVER >= 0x0300)
 
5340
                                set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
 
5341
                                set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE], pgtype_to_sqldesctype(stmt, pgtype, PG_STATIC));
 
5342
                                set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, pgtype, PG_UNSPECIFIED));
 
5343
                                set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, pgtype, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
 
5344
                                set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION], j + 1);
 
5345
                                set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE], NULL_STRING);
 
5346
#endif   /* ODBCVER >= 0x0300 */
 
5347
                        }
 
5348
                }
 
5349
                /* RESULT Columns info */
 
5350
                if (NULL != atttypid || bRetset)
 
5351
                {
 
5352
                        int     typid;
 
5353
 
 
5354
                        if (bRetset)
 
5355
                        {
 
5356
                                typid = pgtype;
 
5357
                                attname = NULL;
 
5358
                        }
 
5359
                        else
 
5360
                        {
 
5361
                                typid = atoi(atttypid);
 
5362
                                attname = QR_get_value_backend_text(tres, i, attname_pos);
 
5363
                        }
 
5364
                        tuple = QR_AddNew(res);
 
5365
                        set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_CAT], CurrCat(conn));
 
5366
                        set_nullfield_string(&tuple[PROCOLS_PROCEDURE_SCHEM], schema_name);
 
5367
                        set_tuplefield_string(&tuple[PROCOLS_PROCEDURE_NAME], procname);
 
5368
                        set_tuplefield_string(&tuple[PROCOLS_COLUMN_NAME], attname);
 
5369
                        set_tuplefield_int2(&tuple[PROCOLS_COLUMN_TYPE], SQL_RESULT_COL);
 
5370
                        set_tuplefield_int2(&tuple[PROCOLS_DATA_TYPE], pgtype_to_concise_type(stmt, typid, PG_STATIC));
 
5371
                        set_tuplefield_string(&tuple[PROCOLS_TYPE_NAME], pgtype_to_name(stmt, typid, PG_UNSPECIFIED, FALSE));
 
5372
                        column_size = pgtype_column_size(stmt, typid, PG_STATIC, UNKNOWNS_AS_DEFAULT);
 
5373
                        set_nullfield_int4(&tuple[PROCOLS_COLUMN_SIZE], column_size);
 
5374
                        set_tuplefield_int4(&tuple[PROCOLS_BUFFER_LENGTH], pgtype_buffer_length(stmt, typid, PG_STATIC, UNKNOWNS_AS_DEFAULT));
 
5375
                        set_nullfield_int2(&tuple[PROCOLS_DECIMAL_DIGITS], pgtype_decimal_digits(stmt, typid, PG_STATIC));
 
5376
                        set_nullfield_int2(&tuple[PROCOLS_NUM_PREC_RADIX], pgtype_radix(conn, typid));
 
5377
                        set_tuplefield_int2(&tuple[PROCOLS_NULLABLE], SQL_NULLABLE_UNKNOWN);
 
5378
                        set_tuplefield_null(&tuple[PROCOLS_REMARKS]);
 
5379
#if (ODBCVER >= 0x0300)
 
5380
                        set_tuplefield_null(&tuple[PROCOLS_COLUMN_DEF]);
 
5381
                        set_nullfield_int2(&tuple[PROCOLS_SQL_DATA_TYPE], pgtype_to_sqldesctype(stmt, typid, PG_STATIC));
 
5382
                        set_nullfield_int2(&tuple[PROCOLS_SQL_DATETIME_SUB], pgtype_to_datetime_sub(stmt, typid, PG_UNSPECIFIED));
 
5383
                        set_nullfield_int4(&tuple[PROCOLS_CHAR_OCTET_LENGTH], pgtype_attr_transfer_octet_length(conn, typid, PG_UNSPECIFIED, UNKNOWNS_AS_DEFAULT));
 
5384
                        set_tuplefield_int4(&tuple[PROCOLS_ORDINAL_POSITION], 0);
 
5385
                        set_tuplefield_string(&tuple[PROCOLS_IS_NULLABLE], NULL_STRING);
 
5386
#endif   /* ODBCVER >= 0x0300 */
 
5387
                }
 
5388
        }
 
5389
        QR_Destructor(tres);
 
5390
        /*
 
5391
         * also, things need to think that this statement is finished so the
 
5392
         * results can be retrieved.
 
5393
         */
 
5394
        if (escSchemaName)
 
5395
                free(escSchemaName);
 
5396
        if (escProcName)
 
5397
                free(escProcName);
 
5398
        stmt->status = STMT_FINISHED;
 
5399
        /* set up the current tuple pointer for SQLFetch */
 
5400
        stmt->currTuple = -1;
 
5401
        SC_set_rowset_start(stmt, -1, FALSE);
 
5402
        SC_set_current_col(stmt, -1);
 
5403
 
 
5404
        return SQL_SUCCESS;
 
5405
}
 
5406
 
 
5407
 
 
5408
RETCODE         SQL_API
 
5409
PGAPI_Procedures(
 
5410
                                 HSTMT hstmt,
 
5411
                                 const SQLCHAR FAR * szProcQualifier, /* OA X*/
 
5412
                                 SQLSMALLINT cbProcQualifier,
 
5413
                                 const SQLCHAR FAR * szProcOwner, /* PV E*/
 
5414
                                 SQLSMALLINT cbProcOwner,
 
5415
                                 const SQLCHAR FAR * szProcName, /* PV E*/
 
5416
                                 SQLSMALLINT cbProcName,
 
5417
                                 UWORD flag)
 
5418
{
 
5419
        CSTR func = "PGAPI_Procedures";
 
5420
        StatementClass *stmt = (StatementClass *) hstmt;
 
5421
        ConnectionClass *conn = SC_get_conn(stmt);
 
5422
        char            proc_query[INFO_INQUIRY_LEN];
 
5423
        char    *escSchemaName = NULL, *escProcName = NULL;
 
5424
        QResultClass *res;
 
5425
        RETCODE         result;
 
5426
        const char      *like_or_eq, *op_string;
 
5427
        BOOL    search_pattern;
 
5428
 
 
5429
        mylog("%s: entering... scnm=%p len=%d\n", func, szProcOwner, cbProcOwner);
 
5430
 
 
5431
        if (PG_VERSION_LT(conn, 6.5))
 
5432
        {
 
5433
                SC_set_error(stmt, STMT_NOT_IMPLEMENTED_ERROR, "Version is too old", func);
 
5434
                return SQL_ERROR;
 
5435
        }
 
5436
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
 
5437
                return result;
 
5438
 
 
5439
        search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
 
5440
        if (search_pattern) 
 
5441
        {
 
5442
                like_or_eq = likeop;
 
5443
                escSchemaName = adjustLikePattern(szProcOwner, cbProcOwner, SEARCH_PATTERN_ESCAPE, NULL, conn);
 
5444
                escProcName = adjustLikePattern(szProcName, cbProcName, SEARCH_PATTERN_ESCAPE, NULL, conn);
 
5445
        }
 
5446
        else
 
5447
        {
 
5448
                like_or_eq = eqop;
 
5449
                escSchemaName = simpleCatalogEscape(szProcOwner, cbProcOwner, NULL, conn);
 
5450
                escProcName = simpleCatalogEscape(szProcName, cbProcName, NULL, conn);
 
5451
        }
 
5452
        /*
 
5453
         * The following seems the simplest implementation
 
5454
         */
 
5455
        op_string = gen_opestr(like_or_eq, conn);
 
5456
        if (conn->schema_support)
 
5457
        {
 
5458
                strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", nspname as " "PROCEDURE_SCHEM" ","
 
5459
                " proname as " "PROCEDURE_NAME" ", '' as " "NUM_INPUT_PARAMS" ","
 
5460
                   " '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
 
5461
                   " '' as " "REMARKS" ","
 
5462
                   " case when prorettype = 0 then 1::int2 else 2::int2 end"
 
5463
                   " as "                 "PROCEDURE_TYPE" " from pg_catalog.pg_namespace,"
 
5464
                   " pg_catalog.pg_proc"
 
5465
                  " where pg_proc.pronamespace = pg_namespace.oid");
 
5466
                schema_strcat1(proc_query, " and nspname %s'%.*s'", op_string, escSchemaName, SQL_NTS, szProcName, cbProcName, conn);
 
5467
                my_strcat1(proc_query, " and proname %s'%.*s'", op_string, escProcName, SQL_NTS);
 
5468
        }
 
5469
        else
 
5470
        {
 
5471
                strcpy(proc_query, "select '' as " "PROCEDURE_CAT" ", '' as " "PROCEDURE_SCHEM" ","
 
5472
                " proname as " "PROCEDURE_NAME" ", '' as " "NUM_INPUT_PARAMS" ","
 
5473
                   " '' as " "NUM_OUTPUT_PARAMS" ", '' as " "NUM_RESULT_SETS" ","
 
5474
                   " '' as " "REMARKS" ","
 
5475
                   " case when prorettype = 0 then 1::int2 else 2::int2 end as " "PROCEDURE_TYPE" " from pg_proc");
 
5476
                my_strcat1(proc_query, " where proname %s'%.*s'", op_string, escSchemaName, SQL_NTS);
 
5477
        }
 
5478
 
 
5479
        if (res = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(res))
 
5480
        {
 
5481
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_Procedures query error", func);
 
5482
                QR_Destructor(res);
 
5483
                return SQL_ERROR;
 
5484
        }
 
5485
        SC_set_Result(stmt, res);
 
5486
 
 
5487
        /*
 
5488
         * also, things need to think that this statement is finished so the
 
5489
         * results can be retrieved.
 
5490
         */
 
5491
        stmt->status = STMT_FINISHED;
 
5492
        extend_column_bindings(SC_get_ARDF(stmt), 8);
 
5493
        if (escSchemaName)
 
5494
                free(escSchemaName);
 
5495
        if (escProcName)
 
5496
                free(escProcName);
 
5497
        /* set up the current tuple pointer for SQLFetch */
 
5498
        stmt->currTuple = -1;
 
5499
        SC_set_rowset_start(stmt, -1, FALSE);
 
5500
        SC_set_current_col(stmt, -1);
 
5501
 
 
5502
        return SQL_SUCCESS;
 
5503
}
 
5504
 
 
5505
 
 
5506
#define ACLMAX  8
 
5507
#define ALL_PRIVILIGES "arwdRxt"
 
5508
static int
 
5509
usracl_auth(char *usracl, const char *auth)
 
5510
{
 
5511
        int     i, j, addcnt = 0;
 
5512
 
 
5513
        for (i = 0; auth[i]; i++)
 
5514
        {
 
5515
                for (j = 0; j < ACLMAX; j++)
 
5516
                {
 
5517
                        if (usracl[j] == auth[i])
 
5518
                                break;
 
5519
                        else if (!usracl[j])
 
5520
                        {
 
5521
                                usracl[j]= auth[i];
 
5522
                                addcnt++;
 
5523
                                break;
 
5524
                        }
 
5525
                }
 
5526
        }
 
5527
        return addcnt;
 
5528
}
 
5529
static void
 
5530
useracl_upd(char (*useracl)[ACLMAX], QResultClass *allures, const char *user, const char *auth)
 
5531
{
 
5532
        int usercount = (int) QR_get_num_cached_tuples(allures), i, addcnt = 0;
 
5533
 
 
5534
mylog("user=%s auth=%s\n", user, auth);
 
5535
        if (user[0])
 
5536
                for (i = 0; i < usercount; i++)
 
5537
                {
 
5538
                        if (strcmp(QR_get_value_backend_text(allures, i, 0), user) == 0)
 
5539
                        {
 
5540
                                addcnt += usracl_auth(useracl[i], auth);
 
5541
                                break;
 
5542
                        }
 
5543
                }
 
5544
        else
 
5545
                for (i = 0; i < usercount; i++)
 
5546
                {
 
5547
                        addcnt += usracl_auth(useracl[i], auth);
 
5548
                }
 
5549
        mylog("addcnt=%d\n", addcnt);
 
5550
}
 
5551
 
 
5552
RETCODE         SQL_API
 
5553
PGAPI_TablePrivileges(
 
5554
                                HSTMT hstmt,
 
5555
                                const SQLCHAR FAR * szTableQualifier, /* OA X*/
 
5556
                                SQLSMALLINT cbTableQualifier,
 
5557
                                const SQLCHAR FAR * szTableOwner, /* PV E*/
 
5558
                                SQLSMALLINT cbTableOwner,
 
5559
                                const SQLCHAR FAR * szTableName, /* PV E*/
 
5560
                                SQLSMALLINT cbTableName,
 
5561
                                UWORD flag)
 
5562
{
 
5563
        StatementClass *stmt = (StatementClass *) hstmt;
 
5564
        CSTR func = "PGAPI_TablePrivileges";
 
5565
        ConnectionClass *conn = SC_get_conn(stmt);
 
5566
        Int2            result_cols;
 
5567
        char            proc_query[INFO_INQUIRY_LEN];
 
5568
        QResultClass    *res, *wres = NULL, *allures = NULL;
 
5569
        TupleField      *tuple;
 
5570
        Int4            tablecount, usercount, i, j, k;
 
5571
        BOOL            grpauth, sys, su;
 
5572
        char            (*useracl)[ACLMAX] = NULL, *acl, *user, *delim, *auth;
 
5573
        const char      *reln, *owner, *priv, *schnm = NULL;
 
5574
        RETCODE         result, ret = SQL_SUCCESS;
 
5575
        const char      *like_or_eq, *op_string;
 
5576
        const char      *szSchemaName;
 
5577
        SQLSMALLINT     cbSchemaName;
 
5578
        char            *escSchemaName = NULL, *escTableName = NULL;
 
5579
        BOOL            search_pattern;
 
5580
 
 
5581
        mylog("%s: entering... scnm=%p len-%d\n", func, szTableOwner, cbTableOwner);
 
5582
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
 
5583
                return result;
 
5584
 
 
5585
        /*
 
5586
         * a statement is actually executed, so we'll have to do this
 
5587
         * ourselves.
 
5588
         */
 
5589
        result_cols = 7;
 
5590
        extend_column_bindings(SC_get_ARDF(stmt), result_cols);
 
5591
 
 
5592
        stmt->catalog_result = TRUE;
 
5593
        /* set the field names */
 
5594
        res = QR_Constructor();
 
5595
        SC_set_Result(stmt, res);
 
5596
        QR_set_num_fields(res, result_cols);
 
5597
        QR_set_field_info_v(res, 0, "TABLE_CAT", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
5598
        QR_set_field_info_v(res, 1, "TABLE_SCHEM", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
5599
        QR_set_field_info_v(res, 2, "TABLE_NAME", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
5600
        QR_set_field_info_v(res, 3, "GRANTOR", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
5601
        QR_set_field_info_v(res, 4, "GRANTEE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
5602
        QR_set_field_info_v(res, 5, "PRIVILEGE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
5603
        QR_set_field_info_v(res, 6, "IS_GRANTABLE", PG_TYPE_VARCHAR, MAX_INFO_STRING);
 
5604
 
 
5605
        /*
 
5606
         * also, things need to think that this statement is finished so the
 
5607
         * results can be retrieved.
 
5608
         */
 
5609
        stmt->status = STMT_FINISHED;
 
5610
        /* set up the current tuple pointer for SQLFetch */
 
5611
        stmt->currTuple = -1;
 
5612
        SC_set_rowset_start(stmt, -1, FALSE);
 
5613
        SC_set_current_col(stmt, -1);
 
5614
        szSchemaName = szTableOwner;
 
5615
        cbSchemaName = cbTableOwner;
 
5616
 
 
5617
#define return  DONT_CALL_RETURN_FROM_HERE???
 
5618
        search_pattern = (0 == (flag & PODBC_NOT_SEARCH_PATTERN));
 
5619
        if (search_pattern) 
 
5620
        {
 
5621
                like_or_eq = likeop;
 
5622
                escTableName = adjustLikePattern(szTableName, cbTableName, SEARCH_PATTERN_ESCAPE, NULL, conn);
 
5623
        }
 
5624
        else
 
5625
        {
 
5626
                like_or_eq = eqop;
 
5627
                escTableName = simpleCatalogEscape(szTableName, cbTableName, NULL, conn);
 
5628
        }
 
5629
 
 
5630
retry_public_schema:
 
5631
        if (escSchemaName)
 
5632
                free(escSchemaName);
 
5633
        if (search_pattern) 
 
5634
                escSchemaName = adjustLikePattern(szSchemaName, cbSchemaName, SEARCH_PATTERN_ESCAPE, NULL, conn);
 
5635
        else
 
5636
                escSchemaName = simpleCatalogEscape(szSchemaName, cbSchemaName, NULL, conn);
 
5637
 
 
5638
        op_string = gen_opestr(like_or_eq, conn);
 
5639
        if (conn->schema_support)
 
5640
                strncpy_null(proc_query, "select relname, usename, relacl, nspname"
 
5641
                " from pg_catalog.pg_namespace, pg_catalog.pg_class ,"
 
5642
                " pg_catalog.pg_user where", sizeof(proc_query));
 
5643
        else
 
5644
                strncpy_null(proc_query, "select relname, usename, relacl"
 
5645
                " from pg_class , pg_user where", sizeof(proc_query));
 
5646
        if (conn->schema_support)
 
5647
        {
 
5648
                if (escSchemaName)
 
5649
                        schema_strcat1(proc_query, " nspname %s'%.*s' and", op_string, escSchemaName, SQL_NTS, szTableName, cbTableName, conn);
 
5650
        }
 
5651
        if (escTableName)
 
5652
                snprintf_add(proc_query, sizeof(proc_query), " relname %s'%s' and", op_string, escTableName);
 
5653
        if (conn->schema_support)
 
5654
        {
 
5655
                strcat(proc_query, " pg_namespace.oid = relnamespace and relkind in ('r', 'v') and");
 
5656
                if ((!escTableName) && (!escSchemaName))
 
5657
                        strcat(proc_query, " nspname not in ('pg_catalog', 'information_schema') and");
 
5658
        }
 
5659
        strcat(proc_query, " pg_user.usesysid = relowner");
 
5660
        if (wres = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(wres))
 
5661
        {
 
5662
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_TablePrivileges query error", func);
 
5663
                ret = SQL_ERROR;
 
5664
                goto cleanup;
 
5665
        }
 
5666
        tablecount = (Int4) QR_get_num_cached_tuples(wres);
 
5667
        /* If not found */
 
5668
        if (conn->schema_support &&
 
5669
            (flag & PODBC_SEARCH_PUBLIC_SCHEMA) != 0 &&
 
5670
            0 == tablecount)
 
5671
        {
 
5672
                if (allow_public_schema(conn, szSchemaName, cbSchemaName))
 
5673
                {
 
5674
                        QR_Destructor(wres);
 
5675
                        wres = NULL;
 
5676
                        szSchemaName = pubstr;
 
5677
                        cbSchemaName = SQL_NTS;
 
5678
                        goto retry_public_schema;
 
5679
                }
 
5680
        }
 
5681
 
 
5682
        strncpy_null(proc_query, "select usename, usesysid, usesuper from pg_user", sizeof(proc_query));
 
5683
        if (allures = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(allures))
 
5684
        {
 
5685
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_TablePrivileges query error", func);
 
5686
                ret = SQL_ERROR;
 
5687
                goto cleanup;
 
5688
        }
 
5689
        usercount = (Int4) QR_get_num_cached_tuples(allures);
 
5690
        useracl = (char (*)[ACLMAX]) malloc(usercount * sizeof(char [ACLMAX]));
 
5691
        for (i = 0; i < tablecount; i++)
 
5692
        { 
 
5693
                memset(useracl, 0, usercount * sizeof(char[ACLMAX]));
 
5694
                acl = (char *) QR_get_value_backend_text(wres, i, 2);
 
5695
                if (acl && acl[0] == '{')
 
5696
                        user = acl + 1;
 
5697
                else
 
5698
                        user = NULL;
 
5699
                for (; user && *user;)
 
5700
                {
 
5701
                        grpauth = FALSE;
 
5702
                        if (user[0] == '"' && strncmp(user + 1, "group ", 6) == 0)
 
5703
                        {
 
5704
                                user += 7;
 
5705
                                grpauth = TRUE;
 
5706
                        }
 
5707
                        if (delim = strchr(user, '='), !delim)
 
5708
                                break;
 
5709
                        *delim = '\0';
 
5710
                        auth = delim + 1;
 
5711
                        if (grpauth)
 
5712
                        {
 
5713
                                if (delim = strchr(auth, '"'), delim)
 
5714
                                {
 
5715
                                        *delim = '\0';
 
5716
                                        delim++;
 
5717
                                }
 
5718
                        }
 
5719
                        else if (delim = strchr(auth, ','), delim)
 
5720
                                *delim = '\0';
 
5721
                        else if (delim = strchr(auth, '}'), delim)
 
5722
                                *delim = '\0';
 
5723
                        if (grpauth) /* handle group privilege */
 
5724
                        {
 
5725
                                QResultClass    *gres;
 
5726
                                int             i;
 
5727
                                char    *grolist, *uid, *delm;
 
5728
 
 
5729
                                snprintf(proc_query, sizeof(proc_query) - 1, "select grolist from pg_group where groname = '%s'", user);
 
5730
                                if (gres = CC_send_query(conn, proc_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(gres))
 
5731
                                {
 
5732
                                        grolist = QR_get_value_backend_text(gres, 0, 0);
 
5733
                                        if (grolist && grolist[0] == '{')
 
5734
                                        {
 
5735
                                                for (uid = grolist + 1; *uid;)
 
5736
                                                {
 
5737
                                                        if (delm = strchr(uid, ','), delm)
 
5738
                                                                *delm = '\0';
 
5739
                                                        else if (delm = strchr(uid, '}'), delm)
 
5740
                                                                *delm = '\0';
 
5741
mylog("guid=%s\n", uid);
 
5742
                                                        for (i = 0; i < usercount; i++)
 
5743
                                                        {
 
5744
                                                                if (strcmp(QR_get_value_backend_text(allures, i, 1), uid) == 0)
 
5745
                                                                        useracl_upd(useracl, allures, QR_get_value_backend_text(allures, i, 0), auth);
 
5746
                                                        }
 
5747
                                                        uid = delm + 1;
 
5748
                                                }
 
5749
                                        }
 
5750
                                }
 
5751
                                QR_Destructor(gres);
 
5752
                        }
 
5753
                        else
 
5754
                                useracl_upd(useracl, allures, user, auth);
 
5755
                        if (!delim)
 
5756
                                break;
 
5757
                        user = delim + 1;
 
5758
                }
 
5759
                reln = QR_get_value_backend_text(wres, i, 0);
 
5760
                owner = QR_get_value_backend_text(wres, i, 1);
 
5761
                if (conn->schema_support)
 
5762
                        schnm = QR_get_value_backend_text(wres, i, 3);
 
5763
                /* The owner has all privileges */
 
5764
                useracl_upd(useracl, allures, owner, ALL_PRIVILIGES);
 
5765
                for (j = 0; j < usercount; j++)
 
5766
                {
 
5767
                        user = QR_get_value_backend_text(allures, j, 0);
 
5768
                        su = (strcmp(QR_get_value_backend_text(allures, j, 2), "t") == 0);
 
5769
                        sys = (strcmp(user, owner) == 0);
 
5770
                        /* Super user has all privileges */
 
5771
                        if (su)
 
5772
                                useracl_upd(useracl, allures, user, ALL_PRIVILIGES);
 
5773
                        for (k = 0; k < ACLMAX; k++)
 
5774
                        {
 
5775
                                if (!useracl[j][k])
 
5776
                                        break;
 
5777
                                switch (useracl[j][k])
 
5778
                                {
 
5779
                                        case 'R': /* rule */
 
5780
                                        case 't': /* trigger */
 
5781
                                                continue;
 
5782
                                }
 
5783
                                tuple = QR_AddNew(res);
 
5784
                                set_tuplefield_string(&tuple[0], CurrCat(conn));
 
5785
                                if (conn->schema_support)
 
5786
                                        set_tuplefield_string(&tuple[1], GET_SCHEMA_NAME(schnm));
 
5787
                                else
 
5788
                                        set_tuplefield_string(&tuple[1], NULL_STRING);
 
5789
                                set_tuplefield_string(&tuple[2], reln);
 
5790
                                if (su || sys)
 
5791
                                        set_tuplefield_string(&tuple[3], "_SYSTEM");
 
5792
                                else
 
5793
                                        set_tuplefield_string(&tuple[3], owner);
 
5794
                                mylog("user=%s\n", user);
 
5795
                                set_tuplefield_string(&tuple[4], user);
 
5796
                                switch (useracl[j][k])
 
5797
                                {
 
5798
                                        case 'a':
 
5799
                                                priv = "INSERT";
 
5800
                                                break;
 
5801
                                        case 'r':
 
5802
                                                priv = "SELECT";
 
5803
                                                break;
 
5804
                                        case 'w':
 
5805
                                                priv = "UPDATE";
 
5806
                                                break;
 
5807
                                        case 'd':
 
5808
                                                priv = "DELETE";
 
5809
                                                break;
 
5810
                                        case 'x':
 
5811
                                                priv = "REFERENCES";
 
5812
                                                break;
 
5813
                                        default:
 
5814
                                                priv = NULL_STRING;
 
5815
                                }
 
5816
                                set_tuplefield_string(&tuple[5], priv);
 
5817
                                /* The owner and the super user are grantable */
 
5818
                                if (sys || su)
 
5819
                                        set_tuplefield_string(&tuple[6], "YES");
 
5820
                                else
 
5821
                                        set_tuplefield_string(&tuple[6], "NO");
 
5822
                        }
 
5823
                }
 
5824
        }
 
5825
cleanup:
 
5826
#undef  return
 
5827
        if (escSchemaName)
 
5828
                free(escSchemaName);
 
5829
        if (escTableName)
 
5830
                free(escTableName);
 
5831
        if (useracl)
 
5832
                free(useracl);
 
5833
        if (wres)
 
5834
                QR_Destructor(wres);
 
5835
        if (allures)
 
5836
                QR_Destructor(allures);
 
5837
        if (stmt->internal) 
 
5838
                ret = DiscardStatementSvp(stmt, ret, FALSE);
 
5839
        return ret;
 
5840
}
 
5841
 
 
5842
 
 
5843
static RETCODE          SQL_API
 
5844
PGAPI_ForeignKeys_new(
 
5845
                HSTMT hstmt,
 
5846
                const SQLCHAR FAR * szPkTableQualifier, /* OA X*/
 
5847
                SQLSMALLINT cbPkTableQualifier,
 
5848
                const SQLCHAR FAR * szPkTableOwner, /* OA E*/
 
5849
                SQLSMALLINT cbPkTableOwner,
 
5850
                const SQLCHAR FAR * szPkTableName, /* OA(R) E*/
 
5851
                SQLSMALLINT cbPkTableName,
 
5852
                const SQLCHAR FAR * szFkTableQualifier, /* OA X*/
 
5853
                SQLSMALLINT cbFkTableQualifier,
 
5854
                const SQLCHAR FAR * szFkTableOwner, /* OA E*/
 
5855
                SQLSMALLINT cbFkTableOwner,
 
5856
                const SQLCHAR FAR * szFkTableName, /* OA(R) E*/
 
5857
                SQLSMALLINT cbFkTableName)
 
5858
{
 
5859
        CSTR func = "PGAPI_ForeignKeys";
 
5860
        StatementClass  *stmt = (StatementClass *) hstmt;
 
5861
        QResultClass    *res = NULL;
 
5862
        RETCODE         ret = SQL_ERROR, result;
 
5863
        char            tables_query[INFO_INQUIRY_LEN];
 
5864
        char            *pk_table_needed = NULL, *escTableName = NULL;
 
5865
        char            *fk_table_needed = NULL;
 
5866
        char            schema_needed[SCHEMA_NAME_STORAGE_LEN + 1];
 
5867
        char            catName[SCHEMA_NAME_STORAGE_LEN],
 
5868
                        scmName1[SCHEMA_NAME_STORAGE_LEN],
 
5869
                        scmName2[SCHEMA_NAME_STORAGE_LEN];
 
5870
        const char      *relqual;
 
5871
        ConnectionClass *conn = SC_get_conn(stmt);
 
5872
 
 
5873
        const char *eq_string;
 
5874
 
 
5875
        mylog("%s: entering...stmt=%p\n", func, stmt);
 
5876
 
 
5877
        if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result)
 
5878
                return result;
 
5879
 
 
5880
        schema_needed[0] = '\0';
 
5881
#define return  DONT_CALL_RETURN_FROM_HERE???
 
5882
 
 
5883
        pk_table_needed = make_string(szPkTableName, cbPkTableName, NULL, 0);
 
5884
        fk_table_needed = make_string(szFkTableName, cbFkTableName, NULL, 0);
 
5885
 
 
5886
        eq_string = gen_opestr(eqop, conn);
 
5887
 
 
5888
        /*
 
5889
         * Case #2 -- Get the foreign keys in the specified table (fktab) that
 
5890
         * refer to the primary keys of other table(s).
 
5891
         */
 
5892
        if (NULL != fk_table_needed)
 
5893
        {
 
5894
                mylog("%s: entering Foreign Key Case #2", func);
 
5895
                escTableName = simpleCatalogEscape(fk_table_needed, SQL_NTS, NULL, conn);
 
5896
                schema_strcat(schema_needed, "%.*s", szFkTableOwner, cbFkTableOwner, szFkTableName, cbFkTableName, conn);
 
5897
                relqual = "\n   and  conrelid = c.oid";
 
5898
        }
 
5899
        /*
 
5900
         * Case #1 -- Get the foreign keys in other tables that refer to the
 
5901
         * primary key in the specified table (pktab).  i.e., Who points to
 
5902
         * me?
 
5903
         */
 
5904
        else if (NULL != pk_table_needed)
 
5905
        {
 
5906
                escTableName = simpleCatalogEscape(pk_table_needed, SQL_NTS, NULL, conn);
 
5907
                schema_strcat(schema_needed, "%.*s", szPkTableOwner, cbPkTableOwner, szPkTableName, cbPkTableName, conn);
 
5908
                relqual = "\n   and  confrelid = c.oid";
 
5909
        }
 
5910
        else
 
5911
        {
 
5912
                SC_set_error(stmt, STMT_INTERNAL_ERROR, "No tables specified to PGAPI_ForeignKeys.", func);
 
5913
                goto cleanup;
 
5914
        }
 
5915
 
 
5916
        if (conn->schema_support)
 
5917
        {
 
5918
                char    *escSchemaName;
 
5919
 
 
5920
                if (NULL != CurrCat(conn))
 
5921
                        snprintf(catName, sizeof(catName), "'%s'::name", CurrCat(conn));
 
5922
                else
 
5923
                        strcpy(catName, "NULL::name");
 
5924
                strcpy(scmName1, "n2.nspname");
 
5925
                strcpy(scmName2, "n1.nspname");
 
5926
                escSchemaName = simpleCatalogEscape(schema_needed, SQL_NTS, NULL, conn);
 
5927
 
 
5928
                snprintf(tables_query, sizeof(tables_query),
 
5929
                "select"
 
5930
                "       %s as PKTABLE_CAT"
 
5931
                ",\n    %s as PKTABLE_SCHEM"
 
5932
                ",\n    c2.relname as PKTABLE_NAME"
 
5933
                ",\n    a2.attname as PKCOLUMN_NAME"
 
5934
                ",\n    %s as FKTABLE_CAT"
 
5935
                ",\n    %s as FKTABLE_SCHEM"
 
5936
                ",\n    c1.relname as FKTABLE_NAME"
 
5937
                ",\n    a1.attname as FKCOLUMN_NAME"
 
5938
                ",\n    i::int2 as KEY_SEQ"
 
5939
                ",\n    case ref.confupdtype"
 
5940
                "\n             when 'c' then %d::int2"
 
5941
                "\n             when 'n' then %d::int2"
 
5942
                "\n             when 'd' then %d::int2"
 
5943
                "\n             when 'r' then %d::int2"
 
5944
                "\n             else %d::int2"
 
5945
                "\n     end as UPDATE_RULE"
 
5946
                ",\n    case ref.confdeltype"
 
5947
                "\n             when 'c' then %d::int2"
 
5948
                "\n             when 'n' then %d::int2"
 
5949
                "\n             when 'd' then %d::int2"
 
5950
                "\n             when 'r' then %d::int2"
 
5951
                "\n             else %d::int2"
 
5952
                "\n     end as DELETE_RULE"
 
5953
                ",\n    ref.conname as FK_NAME"
 
5954
                ",\n    cn.conname as PK_NAME"
 
5955
#if (ODBCVER >= 0x0300)
 
5956
                ",\n    case"
 
5957
                "\n             when ref.condeferrable then"
 
5958
                "\n                     case"
 
5959
                "\n                     when ref.condeferred then %d::int2"
 
5960
                "\n                     else %d::int2"
 
5961
                "\n                     end"
 
5962
                "\n             else %d::int2"
 
5963
                "\n     end as DEFERRABLITY"
 
5964
#endif /* ODBCVER */
 
5965
                "\n from"
 
5966
                "\n ((((((("
 
5967
                " (select cn.oid, conrelid, conkey, confrelid, confkey"
 
5968
                ",\n     generate_series(array_lower(conkey, 1), array_upper(conkey, 1)) as i"
 
5969
                ",\n     confupdtype, confdeltype, conname"
 
5970
                ",\n     condeferrable, condeferred"
 
5971
                "\n  from pg_catalog.pg_constraint cn"
 
5972
                ",\n    pg_catalog.pg_class c"
 
5973
                ",\n    pg_catalog.pg_namespace n"
 
5974
                "\n  where contype = 'f' %s"
 
5975
                "\n   and  relname %s'%s'"
 
5976
                "\n   and  n.oid = c.relnamespace"
 
5977
                "\n   and  n.nspname %s'%s'"
 
5978
                "\n ) ref"
 
5979
                "\n inner join pg_catalog.pg_class c1"
 
5980
                "\n  on c1.oid = ref.conrelid)"
 
5981
                "\n inner join pg_catalog.pg_namespace n1"
 
5982
                "\n  on  n1.oid = c1.relnamespace)"
 
5983
                "\n inner join pg_catalog.pg_attribute a1"
 
5984
                "\n  on  a1.attrelid = c1.oid"
 
5985
                "\n  and  a1.attnum = conkey[i])"
 
5986
                "\n inner join pg_catalog.pg_class c2"
 
5987
                "\n  on  c2.oid = ref.confrelid)"
 
5988
                "\n inner join pg_catalog.pg_namespace n2"
 
5989
                "\n  on  n2.oid = c2.relnamespace)"
 
5990
                "\n inner join pg_catalog.pg_attribute a2"
 
5991
                "\n  on  a2.attrelid = c2.oid"
 
5992
                "\n  and  a2.attnum = confkey[i])"
 
5993
                "\n left outer join pg_catalog.pg_constraint cn"
 
5994
                "\n  on cn.conrelid = ref.confrelid"
 
5995
                "\n  and cn.contype = 'p')"
 
5996
                , catName
 
5997
                , scmName1
 
5998
                , catName
 
5999
                , scmName2
 
6000
                , SQL_CASCADE
 
6001
                , SQL_SET_NULL
 
6002
                , SQL_SET_DEFAULT
 
6003
                , SQL_RESTRICT
 
6004
                , SQL_NO_ACTION
 
6005
                , SQL_CASCADE
 
6006
                , SQL_SET_NULL
 
6007
                , SQL_SET_DEFAULT
 
6008
                , SQL_RESTRICT
 
6009
                , SQL_NO_ACTION
 
6010
#if (ODBCVER >= 0x0300)
 
6011
                , SQL_INITIALLY_DEFERRED
 
6012
                , SQL_INITIALLY_IMMEDIATE
 
6013
                , SQL_NOT_DEFERRABLE
 
6014
#endif /* ODBCVER */
 
6015
                , relqual
 
6016
                , eq_string, escTableName
 
6017
                , eq_string, escSchemaName);
 
6018
 
 
6019
                free(escSchemaName);
 
6020
                if (NULL != pk_table_needed &&
 
6021
                    NULL != fk_table_needed)
 
6022
                {
 
6023
                        free(escTableName);
 
6024
                        escTableName = simpleCatalogEscape(pk_table_needed, SQL_NTS, NULL, conn);
 
6025
                        snprintf_add(tables_query, sizeof(tables_query),
 
6026
                                        "\n where c2.relname %s'%s'",
 
6027
                                        eq_string, escTableName);
 
6028
                }
 
6029
                strcat(tables_query, "\n  order by ref.oid, ref.i");
 
6030
        }
 
6031
        else
 
6032
        {
 
6033
                strcpy(catName, "NULL::name");
 
6034
                strcpy(scmName1, "NULL::name");
 
6035
                strcpy(scmName2, "NULL::name");
 
6036
 
 
6037
                snprintf(tables_query, sizeof(tables_query),
 
6038
                "select %s as PKTABLE_CAT"
 
6039
                ",\n    %s as PKTABLE_SCHEM"
 
6040
                ",\n    c2.relname as PKTABLE_NAME"
 
6041
                ",\n    a2.attname as PKCOLUMN_NAME"
 
6042
                ",\n    %s as FKTABLE_CAT"
 
6043
                ",\n    %s as FKTABLE_SCHEM"
 
6044
                ",\n    c1.relname as FKTABLE_NAME"
 
6045
                ",\n    a1.attname as FKCOLUMN_NAME"
 
6046
                ",\n    i::int2 as KEY_SEQ"
 
6047
                ",\n    case confupdtype"
 
6048
                "\n             when 'c' then %d::int2"
 
6049
                "\n             when 'n' then %d::int2"
 
6050
                "\n             when 'd' then %d::int2"
 
6051
                "\n             when 'r' then %d::int2"
 
6052
                "\n             else %d::int2"
 
6053
                "\n     end as UPDATE_RULE"
 
6054
                ",\n    case confdeltype"
 
6055
                "\n             when 'c' then %d::int2"
 
6056
                "\n             when 'n' then %d::int2"
 
6057
                "\n             when 'd' then %d::int2"
 
6058
                "\n             when 'r' then %d::int2"
 
6059
                "\n             else %d::int2"
 
6060
                "\n     end as DELETE_RULE"
 
6061
                ",\n    conname as FK_NAME"
 
6062
                ",\n    NULL::name as PK_NAME"
 
6063
#if (ODBCVER >= 0x0300)
 
6064
                ",\n    case"
 
6065
                "\n             when condeferrable then"
 
6066
                "\n                     case"
 
6067
                "\n                     when condeferred then %d::int2"
 
6068
                "\n                     else %d::int2"
 
6069
                "\n                     end"
 
6070
                "\n             else %d::int2"
 
6071
                "\n     end as DEFERRABLITY"
 
6072
#endif /* ODBCVER */
 
6073
                "\n from"
 
6074
                "\n (select conrelid, conkey, confrelid, confkey"
 
6075
                ",\n     generate_series(array_lower(conkey, 1), array_upper(conkey, 1)) as i"
 
6076
                ",\n     confupdtype, confdeltype, conname"
 
6077
                ",\n     condeferrable, condeferred"
 
6078
                "\n  from pg_catalog.pg_constraint cn"
 
6079
                ",\n    pg_catalog.pg_class c"
 
6080
                "\n  where contype = 'f' %s"
 
6081
                "\n   and  relname %s'%s'"
 
6082
                "\n ) ref"
 
6083
                ",\n pg_catalog.pg_class c1"
 
6084
                ",\n pg_catalog.pg_attribute a1"
 
6085
                ",\n pg_catalog.pg_class c2"
 
6086
                ",\n pg_catalog.pg_attribute a2"
 
6087
                "\n where c1.oid = ref.conrelid"
 
6088
                "\n  and  c2.oid = ref.confrelid"
 
6089
                "\n  and  a1.attrelid = c1.oid"
 
6090
                "\n  and  a1.attnum = conkey[i]"
 
6091
                "\n  and  a2.attrelid = c2.oid"
 
6092
                "\n  and  a2.attnum = confkey[i]"
 
6093
                "\n  order by ref.oid, ref.i"
 
6094
                , catName
 
6095
                , scmName1
 
6096
                , catName
 
6097
                , scmName2
 
6098
                , SQL_CASCADE
 
6099
                , SQL_SET_NULL
 
6100
                , SQL_SET_DEFAULT
 
6101
                , SQL_RESTRICT
 
6102
                , SQL_NO_ACTION
 
6103
                , SQL_CASCADE
 
6104
                , SQL_SET_NULL
 
6105
                , SQL_SET_DEFAULT
 
6106
                , SQL_RESTRICT
 
6107
                , SQL_NO_ACTION
 
6108
#if (ODBCVER >= 0x0300)
 
6109
                , SQL_INITIALLY_DEFERRED
 
6110
                , SQL_INITIALLY_IMMEDIATE
 
6111
                , SQL_NOT_DEFERRABLE
 
6112
#endif /* ODBCVER */
 
6113
                , relqual, eq_string, escTableName);
 
6114
        }
 
6115
 
 
6116
        if (res = CC_send_query(conn, tables_query, NULL, IGNORE_ABORT_ON_CONN, stmt), !QR_command_maybe_successful(res))
 
6117
        {
 
6118
                SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_ForeignKeys query error", func);
 
6119
                QR_Destructor(res);
 
6120
                goto cleanup;
 
6121
        }
 
6122
        SC_set_Result(stmt, res);
 
6123
        ret = SQL_SUCCESS;
 
6124
 
 
6125
cleanup:
 
6126
#undef  return
 
6127
 
 
6128
        /*
 
6129
         * also, things need to think that this statement is finished so the
 
6130
         * results can be retrieved.
 
6131
         */
 
6132
        if (SQL_SUCCEEDED(ret))
 
6133
        {
 
6134
                stmt->status = STMT_FINISHED;
 
6135
                extend_column_bindings(SC_get_ARDF(stmt), QR_NumResultCols(res));
 
6136
        }
 
6137
        if (pk_table_needed)
 
6138
                free(pk_table_needed);
 
6139
        if (escTableName)
 
6140
                free(escTableName);
 
6141
        if (fk_table_needed)
 
6142
                free(fk_table_needed);
 
6143
        /* set up the current tuple pointer for SQLFetch */
 
6144
        stmt->currTuple = -1;
 
6145
        SC_set_rowset_start(stmt, -1, FALSE);
 
6146
        SC_set_current_col(stmt, -1);
 
6147
 
 
6148
        if (stmt->internal)
 
6149
                ret = DiscardStatementSvp(stmt, ret, FALSE);
 
6150
        mylog("%s(): EXIT, stmt=%p, ret=%d\n", func, stmt, ret);
 
6151
        return ret;
 
6152
}