1 /*********************************************************************
2  *
3  * This is based on code created by Peter Harvey,
4  * (pharvey@codebydesign.com).
5  *
6  * Modified and extended by Nick Gorham
7  * (nick@lurcher.org).
8  *
9  * Any bugs or problems should be considered the fault of Nick and not
10  * Peter.
11  *
12  * copyright (c) 1999 Nick Gorham
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Lesser General Public
16  * License as published by the Free Software Foundation; either
17  * version 2 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  *
28  **********************************************************************
29  *
30  * $Id: SQLForeignKeys.c,v 1.7 2009/02/18 17:59:08 lurcher Exp $
31  *
32  * $Log: SQLForeignKeys.c,v $
33  * Revision 1.7  2009/02/18 17:59:08  lurcher
34  * Shift to using config.h, the compile lines were making it hard to spot warnings
35  *
36  * Revision 1.6  2004/01/12 09:54:39  lurcher
37  *
38  * Fix problem where STATE_S5 stops metadata calls
39  *
40  * Revision 1.5  2003/10/30 18:20:45  lurcher
41  *
42  * Fix broken thread protection
43  * Remove SQLNumResultCols after execute, lease S4/S% to driver
44  * Fix string overrun in SQLDriverConnect
45  * Add initial support for Interix
46  *
47  * Revision 1.4  2003/02/27 12:19:39  lurcher
48  *
49  * Add the A functions as well as the W
50  *
51  * Revision 1.3  2002/12/05 17:44:30  lurcher
52  *
53  * Display unknown return values in return logging
54  *
55  * Revision 1.2  2002/07/24 08:49:52  lurcher
56  *
57  * Alter UNICODE support to use iconv for UNICODE-ANSI conversion
58  *
59  * Revision 1.1.1.1  2001/10/17 16:40:05  lurcher
60  *
61  * First upload to SourceForge
62  *
63  * Revision 1.4  2001/07/03 09:30:41  nick
64  *
65  * Add ability to alter size of displayed message in the log
66  *
67  * Revision 1.3  2001/04/12 17:43:36  nick
68  *
69  * Change logging and added autotest to odbctest
70  *
71  * Revision 1.2  2000/12/31 20:30:54  nick
72  *
73  * Add UNICODE support
74  *
75  * Revision 1.1.1.1  2000/09/04 16:42:52  nick
76  * Imported Sources
77  *
78  * Revision 1.9  2000/06/20 12:44:00  ngorham
79  *
80  * Fix bug that caused a success with info message from SQLExecute or
81  * SQLExecDirect to be lost if used with a ODBC 3 driver and the application
82  * called SQLGetDiagRec
83  *
84  * Revision 1.8  2000/06/16 16:52:18  ngorham
85  *
86  * Stop info messages being lost when calling SQLExecute etc on ODBC 3
87  * drivers, the SQLNumResultCols were clearing the error before
88  * function return had a chance to get to them
89  *
90  * Revision 1.7  1999/11/13 23:40:59  ngorham
91  *
92  * Alter the way DM logging works
93  * Upgrade the Postgres driver to 6.4.6
94  *
95  * Revision 1.6  1999/10/24 23:54:18  ngorham
96  *
97  * First part of the changes to the error reporting
98  *
99  * Revision 1.5  1999/09/21 22:34:24  ngorham
100  *
101  * Improve performance by removing unneeded logging calls when logging is
102  * disabled
103  *
104  * Revision 1.4  1999/07/10 21:10:16  ngorham
105  *
106  * Adjust error sqlstate from driver manager, depending on requested
107  * version (ODBC2/3)
108  *
109  * Revision 1.3  1999/07/04 21:05:07  ngorham
110  *
111  * Add LGPL Headers to code
112  *
113  * Revision 1.2  1999/06/30 23:56:54  ngorham
114  *
115  * Add initial thread safety code
116  *
117  * Revision 1.1.1.1  1999/05/29 13:41:07  sShandyb
118  * first go at it
119  *
120  * Revision 1.1.1.1  1999/05/27 18:23:17  pharvey
121  * Imported sources
122  *
123  * Revision 1.3  1999/05/03 19:50:43  nick
124  * Another check point
125  *
126  * Revision 1.2  1999/04/30 16:22:47  nick
127  * Another checkpoint
128  *
129  * Revision 1.1  1999/04/25 23:06:11  nick
130  * Initial revision
131  *
132  *
133  **********************************************************************/
134 
135 #include <config.h>
136 #include "drivermanager.h"
137 
138 static char const rcsid[]= "$RCSfile: SQLForeignKeys.c,v $ $Revision: 1.7 $";
139 
SQLForeignKeysA(SQLHSTMT statement_handle,SQLCHAR * szpk_catalog_name,SQLSMALLINT cbpk_catalog_name,SQLCHAR * szpk_schema_name,SQLSMALLINT cbpk_schema_name,SQLCHAR * szpk_table_name,SQLSMALLINT cbpk_table_name,SQLCHAR * szfk_catalog_name,SQLSMALLINT cbfk_catalog_name,SQLCHAR * szfk_schema_name,SQLSMALLINT cbfk_schema_name,SQLCHAR * szfk_table_name,SQLSMALLINT cbfk_table_name)140 SQLRETURN SQLForeignKeysA(
141     SQLHSTMT           statement_handle,
142     SQLCHAR            *szpk_catalog_name,
143     SQLSMALLINT        cbpk_catalog_name,
144     SQLCHAR            *szpk_schema_name,
145     SQLSMALLINT        cbpk_schema_name,
146     SQLCHAR            *szpk_table_name,
147     SQLSMALLINT        cbpk_table_name,
148     SQLCHAR            *szfk_catalog_name,
149     SQLSMALLINT        cbfk_catalog_name,
150     SQLCHAR            *szfk_schema_name,
151     SQLSMALLINT        cbfk_schema_name,
152     SQLCHAR            *szfk_table_name,
153     SQLSMALLINT        cbfk_table_name )
154 {
155     return SQLForeignKeys( statement_handle,
156                             szpk_catalog_name,
157                             cbpk_catalog_name,
158                             szpk_schema_name,
159                             cbpk_schema_name,
160                             szpk_table_name,
161                             cbpk_table_name,
162                             szfk_catalog_name,
163                             cbfk_catalog_name,
164                             szfk_schema_name,
165                             cbfk_schema_name,
166                             szfk_table_name,
167                             cbfk_table_name );
168 }
169 
SQLForeignKeys(SQLHSTMT statement_handle,SQLCHAR * szpk_catalog_name,SQLSMALLINT cbpk_catalog_name,SQLCHAR * szpk_schema_name,SQLSMALLINT cbpk_schema_name,SQLCHAR * szpk_table_name,SQLSMALLINT cbpk_table_name,SQLCHAR * szfk_catalog_name,SQLSMALLINT cbfk_catalog_name,SQLCHAR * szfk_schema_name,SQLSMALLINT cbfk_schema_name,SQLCHAR * szfk_table_name,SQLSMALLINT cbfk_table_name)170 SQLRETURN SQLForeignKeys(
171     SQLHSTMT           statement_handle,
172     SQLCHAR            *szpk_catalog_name,
173     SQLSMALLINT        cbpk_catalog_name,
174     SQLCHAR            *szpk_schema_name,
175     SQLSMALLINT        cbpk_schema_name,
176     SQLCHAR            *szpk_table_name,
177     SQLSMALLINT        cbpk_table_name,
178     SQLCHAR            *szfk_catalog_name,
179     SQLSMALLINT        cbfk_catalog_name,
180     SQLCHAR            *szfk_schema_name,
181     SQLSMALLINT        cbfk_schema_name,
182     SQLCHAR            *szfk_table_name,
183     SQLSMALLINT        cbfk_table_name )
184 {
185     DMHSTMT statement = (DMHSTMT) statement_handle;
186     SQLRETURN ret;
187     SQLCHAR s1[ 100 + LOG_MESSAGE_LEN ], s2[ 100 + LOG_MESSAGE_LEN ], s3[ 100 + LOG_MESSAGE_LEN ], s4[ 100 + LOG_MESSAGE_LEN ];
188     SQLCHAR s5[ 100 + LOG_MESSAGE_LEN ], s6[ 100 + LOG_MESSAGE_LEN ];
189 
190     /*
191      * check statement
192      */
193 
194     if ( !__validate_stmt( statement ))
195     {
196         dm_log_write( __FILE__,
197                     __LINE__,
198                     LOG_INFO,
199                     LOG_INFO,
200                     "Error: SQL_INVALID_HANDLE" );
201 
202         return SQL_INVALID_HANDLE;
203     }
204 
205     function_entry( statement );
206 
207     if ( log_info.log_flag )
208     {
209         sprintf( statement -> msg, "\n\t\tEntry:\
210 \n\t\t\tStatement = %p\
211 \n\t\t\tPK Catalog Name = %s\
212 \n\t\t\tPK Schema Name = %s\
213 \n\t\t\tPK Table Name = %s\
214 \n\t\t\tFK Catalog Name = %s\
215 \n\t\t\tFK Schema Name = %s\
216 \n\t\t\tFK Table Name = %s",
217                 statement,
218                 __string_with_length( s1, szpk_catalog_name, cbpk_catalog_name ),
219                 __string_with_length( s2, szpk_schema_name, cbpk_schema_name ),
220                 __string_with_length( s3, szpk_table_name, cbpk_table_name ),
221                 __string_with_length( s4, szfk_catalog_name, cbfk_catalog_name ),
222                 __string_with_length( s5, szfk_schema_name, cbfk_schema_name ),
223                 __string_with_length( s6, szfk_table_name, cbfk_table_name ));
224 
225         dm_log_write( __FILE__,
226                 __LINE__,
227                 LOG_INFO,
228                 LOG_INFO,
229                 statement -> msg );
230     }
231 
232     thread_protect( SQL_HANDLE_STMT, statement );
233 
234     if ( !szpk_table_name && !szfk_table_name )
235     {
236         __post_internal_error( &statement -> error,
237                 ERROR_HY009, NULL,
238                 statement -> connection -> environment -> requested_version );
239 
240         return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
241     }
242 
243     if (( cbpk_catalog_name < 0 && cbpk_catalog_name != SQL_NTS ) ||
244             ( cbpk_schema_name < 0 && cbpk_schema_name != SQL_NTS ) ||
245             ( cbpk_table_name < 0 && cbpk_table_name != SQL_NTS ) ||
246             ( cbfk_catalog_name < 0 && cbfk_catalog_name != SQL_NTS ) ||
247             ( cbfk_schema_name < 0 && cbfk_schema_name != SQL_NTS ) ||
248             ( cbfk_table_name < 0 && cbfk_table_name != SQL_NTS ))
249     {
250         __post_internal_error( &statement -> error,
251                 ERROR_HY090, NULL,
252                 statement -> connection -> environment -> requested_version );
253 
254         return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
255     }
256 
257     /*
258      * check states
259      */
260 
261 #ifdef NR_PROBE
262     if ( statement -> state == STATE_S5 ||
263             statement -> state == STATE_S6 ||
264             statement -> state == STATE_S7 )
265 #else
266     if (( statement -> state == STATE_S6 && statement -> eod == 0 ) ||
267             statement -> state == STATE_S7 )
268 #endif
269     {
270         dm_log_write( __FILE__,
271                 __LINE__,
272                 LOG_INFO,
273                 LOG_INFO,
274                 "Error: 24000" );
275 
276         __post_internal_error( &statement -> error,
277                 ERROR_24000, NULL,
278                 statement -> connection -> environment -> requested_version );
279 
280         return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
281     }
282     else if ( statement -> state == STATE_S8 ||
283             statement -> state == STATE_S9 ||
284             statement -> state == STATE_S10 ||
285             statement -> state == STATE_S13 ||
286             statement -> state == STATE_S14 ||
287             statement -> state == STATE_S15 )
288     {
289         dm_log_write( __FILE__,
290                 __LINE__,
291                 LOG_INFO,
292                 LOG_INFO,
293                 "Error: HY010" );
294 
295         __post_internal_error( &statement -> error,
296                 ERROR_HY010, NULL,
297                 statement -> connection -> environment -> requested_version );
298 
299         return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
300     }
301 
302     if ( statement -> state == STATE_S11 ||
303             statement -> state == STATE_S12 )
304     {
305         if ( statement -> interupted_func != SQL_API_SQLFOREIGNKEYS )
306         {
307             dm_log_write( __FILE__,
308                     __LINE__,
309                     LOG_INFO,
310                     LOG_INFO,
311                     "Error: HY010" );
312 
313             __post_internal_error( &statement -> error,
314                     ERROR_HY010, NULL,
315                     statement -> connection -> environment -> requested_version );
316 
317             return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
318         }
319     }
320 
321     /*
322      * TO_DO Check the SQL_ATTR_METADATA_ID settings
323      */
324 
325     if ( statement -> connection -> unicode_driver )
326     {
327         SQLWCHAR *s1, *s2, *s3, *s4, *s5, *s6;
328         int wlen;
329 
330         if ( !CHECK_SQLFOREIGNKEYSW( statement -> connection ))
331         {
332             dm_log_write( __FILE__,
333                     __LINE__,
334                     LOG_INFO,
335                     LOG_INFO,
336                     "Error: IM001" );
337 
338             __post_internal_error( &statement -> error,
339                     ERROR_IM001, NULL,
340                     statement -> connection -> environment -> requested_version );
341 
342             return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
343         }
344 
345         s1 = ansi_to_unicode_alloc( szpk_catalog_name, cbpk_catalog_name, statement -> connection, &wlen );
346         cbpk_catalog_name = wlen;
347         s2 = ansi_to_unicode_alloc( szpk_schema_name, cbpk_schema_name, statement -> connection, &wlen );
348         cbpk_schema_name = wlen;
349         s3 = ansi_to_unicode_alloc( szpk_table_name, cbpk_table_name, statement -> connection, &wlen );
350         cbpk_table_name = wlen;
351         s4 = ansi_to_unicode_alloc( szfk_catalog_name, cbfk_catalog_name, statement -> connection, &wlen );
352         cbfk_catalog_name = wlen;
353         s5 = ansi_to_unicode_alloc( szfk_schema_name, cbfk_schema_name, statement -> connection, &wlen );
354         cbfk_schema_name = wlen;
355         s6 = ansi_to_unicode_alloc( szfk_table_name, cbfk_table_name, statement -> connection, &wlen );
356         cbfk_table_name = wlen;
357 
358         ret = SQLFOREIGNKEYSW( statement -> connection ,
359                 statement -> driver_stmt,
360                 s1,
361                 cbpk_catalog_name,
362                 s2,
363                 cbpk_schema_name,
364                 s3,
365                 cbpk_table_name,
366                 s4,
367                 cbfk_catalog_name,
368                 s5,
369                 cbfk_schema_name,
370                 s6,
371                 cbfk_table_name );
372 
373         if ( s1 )
374             free( s1 );
375         if ( s2 )
376             free( s2 );
377         if ( s3 )
378             free( s3 );
379         if ( s4 )
380             free( s4 );
381         if ( s5 )
382             free( s5 );
383         if ( s6 )
384             free( s6 );
385     }
386     else
387     {
388         if ( !CHECK_SQLFOREIGNKEYS( statement -> connection ))
389         {
390             dm_log_write( __FILE__,
391                     __LINE__,
392                     LOG_INFO,
393                     LOG_INFO,
394                     "Error: IM001" );
395 
396             __post_internal_error( &statement -> error,
397                     ERROR_IM001, NULL,
398                     statement -> connection -> environment -> requested_version );
399 
400             return function_return_nodrv( SQL_HANDLE_STMT, statement, SQL_ERROR );
401         }
402 
403         ret = SQLFOREIGNKEYS( statement -> connection ,
404                 statement -> driver_stmt,
405                 szpk_catalog_name,
406                 cbpk_catalog_name,
407                 szpk_schema_name,
408                 cbpk_schema_name,
409                 szpk_table_name,
410                 cbpk_table_name,
411                 szfk_catalog_name,
412                 cbfk_catalog_name,
413                 szfk_schema_name,
414                 cbfk_schema_name,
415                 szfk_table_name,
416                 cbfk_table_name );
417     }
418 
419     if ( SQL_SUCCEEDED( ret ))
420     {
421 #ifdef NR_PROBE
422 		/********
423 		 * Added this to get num cols from drivers which can only tell
424 		 * us after execute - PAH
425 		 */
426 
427         /*
428          * grab any errors
429          */
430 
431         if ( ret == SQL_SUCCESS_WITH_INFO )
432         {
433             function_return_ex( IGNORE_THREAD, statement, ret, TRUE, DEFER_R1 );
434         }
435 
436         SQLNUMRESULTCOLS( statement -> connection,
437                 statement -> driver_stmt, &statement -> numcols );
438 		/******/
439 #endif
440         statement -> hascols = 1;
441         statement -> state = STATE_S5;
442         statement -> prepared = 0;
443     }
444     else if ( ret == SQL_STILL_EXECUTING )
445     {
446         statement -> interupted_func = SQL_API_SQLFOREIGNKEYS;
447         if ( statement -> state != STATE_S11 &&
448                 statement -> state != STATE_S12 )
449             statement -> state = STATE_S11;
450     }
451     else
452     {
453         statement -> state = STATE_S1;
454     }
455 
456     if ( log_info.log_flag )
457     {
458         sprintf( statement -> msg,
459                 "\n\t\tExit:[%s]",
460                     __get_return_status( ret, s1 ));
461 
462         dm_log_write( __FILE__,
463                 __LINE__,
464                 LOG_INFO,
465                 LOG_INFO,
466                 statement -> msg );
467     }
468 
469     return function_return( SQL_HANDLE_STMT, statement, ret, DEFER_R1 );
470 }
471