File: esqlc_v6.ec

package info (click to toggle)
libdbd-informix-perl 2003.04-3
  • links: PTS
  • area: contrib
  • in suites: etch, etch-m68k, sarge
  • size: 1,232 kB
  • ctags: 467
  • sloc: perl: 7,349; ansic: 5,340; sh: 184; makefile: 58
file content (217 lines) | stat: -rw-r--r-- 6,390 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*
 * @(#)$Id: esqlc_v6.ec,v 100.6 2002/12/06 22:18:24 jleffler Exp $
 *
 * IBM Informix Database Driver for Perl (DBD::Informix)
 * Connection Management for ESQL/C Version 6.0x and later
 *
 * Copyright 1996-98 Jonathan Leffler
 * Copyright 2000    Informix Software Inc
 * Copyright 2002    IBM
 *
 * You may distribute under the terms of either the GNU General Public
 * License or the Artistic License, as specified in the Perl README file.
 */

/*TABSTOP=4*/

#include <string.h>
#include <stdlib.h>
#include "esqlperl.h"

#ifndef lint
static const char rcs[] = "@(#)$Id: esqlc_v6.ec,v 100.6 2002/12/06 22:18:24 jleffler Exp $";
#endif

/* ================================================================= */
/* =================== Database Level Operations =================== */
/* ================================================================= */

static char *get_server_name(void)
{
	char *srvr = 0;
	char *ix_srvr = getenv("INFORMIXSERVER");

	if (ix_srvr == 0 || *ix_srvr == '\0' || (srvr = (char *)malloc(strlen(ix_srvr) + 2)) == 0)
	{
		sqlca.sqlcode = -952;
	}
	{
		srvr[0] = '@';
		strcpy(&srvr[1], ix_srvr);
	}
	return(srvr);
}

static void rel_server_name(char *srvr)
{
	free(srvr);
}

/* Execute a full CONNECT statement - no error checking */
static void full_connect(char *connection, char *dbase, char *user, char *pass)
{
	EXEC SQL BEGIN DECLARE SECTION;
	char           *dbconn = connection;
	char           *dbname = dbase;
	char           *dbpass = pass;
	char           *dbuser = user;
	EXEC SQL END DECLARE SECTION;

	EXEC SQL CONNECT TO :dbname AS :dbconn
		USER :dbuser USING :dbpass
		WITH CONCURRENT TRANSACTION;
}

/*
** Use CONNECT to initiate database connection
**
** If both user and password are provided, then the USER clause is used.
** If no database is specified, a default connection will be made.
**
** Note that CONNECT statements (and DISCONNECT and SET CONNECTION)
** cannot be prepared.
*/

Boolean dbd_ix_connect(char *connection, char *dbase, char *user, char *pass)
{
	EXEC SQL BEGIN DECLARE SECTION;
	char           *dbconn;
	char           *dbname;
	EXEC SQL END DECLARE SECTION;
	Boolean         conn_ok = False;

	if (user != (char *)0 && pass != (char *)0)
	{
		/* User name and password provided */
		if (dbase == (char *)0 || *dbase == '\0')
		{
			/* No database name; connect to '@server' */
			dbname = get_server_name();
			if (dbname != 0)
			{
				dbd_ix_debug(1, "CONNECT TO '%s' {DEFAULT with user info}\n", dbname);
				full_connect(connection, dbname, user, pass);
				rel_server_name(dbname);
			}
		}
		else
		{
			dbd_ix_debug(1, "CONNECT TO '%s' with user info\n", dbase);
			full_connect(connection, dbase, user, pass);
		}
	}
	else if (dbase == (char *)0 || *dbase == '\0')
	{
		/* Not frequently used, but valid */
		/* Reset connection name to empty string, and connect to default */
		/* Typically used to create database on default server */
		/* Only works when no username/password needed to connect */
		/* Nasty interface, overwriting connection name! */
		*connection = '\0';
		dbd_ix_debug(1, "CONNECT TO DEFAULT %s\n", "- no user info");
		EXEC SQL CONNECT TO DEFAULT
			WITH CONCURRENT TRANSACTION;
	}
	else
	{
		dbconn = connection;
		dbname = dbase;
		dbd_ix_debug(1, "CONNECT TO '%s' - no user info\n", dbname);
		EXEC SQL CONNECT TO :dbname AS :dbconn
			WITH CONCURRENT TRANSACTION;
	}
	if (sqlca.sqlcode == 0)
		conn_ok = True;
	return(conn_ok);
}

/* Basic interface to DISCONNECT */
static void do_disconnect(char *connection)
{
	EXEC SQL BEGIN DECLARE SECTION;
	char           *dbconn = connection;
	EXEC SQL END DECLARE SECTION;

	if (*connection != '\0')
	{
		dbd_ix_debug(1, "DISCONNECT (%s)\n", connection);
		EXEC SQL DISCONNECT :dbconn;
	}
	else
	{
		dbd_ix_debug(1, "DISCONNECT DEFAULT%s\n", connection);
		EXEC SQL DISCONNECT DEFAULT;
	}
}

/* External interface to disconnect which handles various oddities */
void dbd_ix_disconnect(char *connection)
{
	do_disconnect(connection);
	if (sqlca.sqlcode == -1800)
	{
		/*
		** -1800: Invalid transaction state
		** One problem was discovered by Nathan Neulinger (nneul@umr.edu).
		** This can occur if the application is talking to a 5.0x engine.
		** The solution seems to be to do CLOSE DATABASE, which also closes
		** the connection (you get error -1803 if you try to DISCONNECT
		** after doing CLOSE DATABASE).  Ensure that the correct connection
		** is current before closing the database.  Bugs B64926 and B42204
		** are the source of the trouble.
		**
		** A second version of the problem found with 7.x databases where a
		** transaction has been started and not completed.  Trying CLOSE
		** DATABASE fails with -759 (Cannot use database commands in an
		** explicit database connection).  It requires a ROLLBACK WORK
		** instead, followed by a DISCONNECT.  If you are connected to a
		** 5.0x engine, then the ROLLBACK WORK succeeds, but the DISCONNECT
		** fails a second time, but the CLOSE DATABASE ruse then works.
		**
		** If both these attempts fail, then the disconnect operation gives
		** up, letting the database engine clean up.  The engine will do a
		** rollback when it notes the absence of the application.
		*/
		dbd_ix_debug(1, "DISCONNECT **FAILED: -1800 ** <<%s>>\n", connection);
		dbd_ix_setconnection(connection);
		dbd_ix_debug(1, "Try ROLLBACK WORK <<%s>>\n", connection);
		EXEC SQL ROLLBACK WORK;
		if (sqlca.sqlcode == 0)
		{
			dbd_ix_debug(1, "ROLLBACK WORK worked <<%s>>\n", connection);
			do_disconnect(connection);
		}
		if (sqlca.sqlcode < 0)
		{
			dbd_ix_debug_l(1, "DISCONNECT ** FAILED AGAIN (%ld) **\n",
						   sqlca.sqlcode);
			dbd_ix_debug(1, "Try CLOSE DATABASE <<%s>>\n", connection);
			EXEC SQL CLOSE DATABASE;
			if (*connection == '\0')
			{
				dbd_ix_debug(1, "Retry DISCONNECT DEFAULT%s\n", connection);
				EXEC SQL DISCONNECT DEFAULT;
			}
		}
	}
	dbd_ix_debug_l(1, "DISCONNECT -- STATUS %ld\n", sqlca.sqlcode);
}

/* Ensure that the correct connection is current -- a no-op in version 5.0x */
void dbd_ix_setconnection(char *conn)
{
	EXEC SQL BEGIN DECLARE SECTION;
	char           *nm_connection = conn;
	EXEC SQL END DECLARE SECTION;

	if (nm_connection)
	{
		dbd_ix_debug(1, "SET CONNECTION %s\n", nm_connection);
		EXEC SQL SET CONNECTION :nm_connection;
	}
	else
	{
		dbd_ix_debug(1, "SET CONNECTION DEFAULT%s\n", "");
		EXEC SQL SET CONNECTION DEFAULT;
	}
}