connection.c 42.1 KB
Newer Older
1 2
/*------
 * Module:			connection.c
3
 *
4 5
 * Description:		This module contains routines related to
 *					connecting to and disconnecting from the Postgres DBMS.
6
 *
7
 * Classes:			ConnectionClass (Functions prefix: "CC_")
8
 *
9 10
 * API functions:	SQLAllocConnect, SQLConnect, SQLDisconnect, SQLFreeConnect,
 *					SQLBrowseConnect(NI)
11
 *
12
 * Comments:		See "notice.txt" for copyright and license information.
13
 *-------
14
 */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
15 16
/* Multibyte support	Eiji Tokuya 2001-03-15 */

17 18 19 20
#include <stdio.h>
#include <string.h>
#include <ctype.h>

21
#include "connection.h"
22 23 24 25 26

#include "environ.h"
#include "socket.h"
#include "statement.h"
#include "qresult.h"
27 28
#include "lobj.h"
#include "dlg_specific.h"
Hiroshi Inoue's avatar
Hiroshi Inoue committed
29 30 31 32 33

#ifdef MULTIBYTE
#include "multibyte.h"
#endif

34
#ifdef WIN32
35
#include <odbcinst.h>
Byron Nikolaidis's avatar
Byron Nikolaidis committed
36
#endif
37
#include "pgapifunc.h"
38

39 40
#define STMT_INCREMENT 16		/* how many statement holders to allocate
								 * at a time */
41

42 43
#define PRN_NULLCHECK

44
extern GLOBAL_VALUES globals;
45 46


47
RETCODE SQL_API
48
PGAPI_AllocConnect(
49 50
				HENV henv,
				HDBC FAR *phdbc)
51
{
52 53
	EnvironmentClass *env = (EnvironmentClass *) henv;
	ConnectionClass *conn;
54
	static char *func = "PGAPI_AllocConnect";
55

56
	mylog("%s: entering...\n", func);
57 58

	conn = CC_Constructor();
59
	mylog("**** %s: henv = %u, conn = %u\n", func, henv, conn);
60

61 62 63 64
	if (!conn)
	{
		env->errormsg = "Couldn't allocate memory for Connection object.";
		env->errornumber = ENV_ALLOC_ERROR;
65
		*phdbc = SQL_NULL_HDBC;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
66
		EN_log_error(func, "", env);
67 68
		return SQL_ERROR;
	}
69

70 71 72 73 74
	if (!EN_add_connection(env, conn))
	{
		env->errormsg = "Maximum number of connections exceeded.";
		env->errornumber = ENV_ALLOC_ERROR;
		CC_Destructor(conn);
75
		*phdbc = SQL_NULL_HDBC;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
76
		EN_log_error(func, "", env);
77 78
		return SQL_ERROR;
	}
79 80 81

	*phdbc = (HDBC) conn;

82
	return SQL_SUCCESS;
83 84 85
}


86
RETCODE SQL_API
87
PGAPI_Connect(
88 89 90 91 92 93 94
		   HDBC hdbc,
		   UCHAR FAR *szDSN,
		   SWORD cbDSN,
		   UCHAR FAR *szUID,
		   SWORD cbUID,
		   UCHAR FAR *szAuthStr,
		   SWORD cbAuthStr)
95
{
96 97
	ConnectionClass *conn = (ConnectionClass *) hdbc;
	ConnInfo   *ci;
98
	static char *func = "PGAPI_Connect";
99

100
	mylog("%s: entering...\n", func);
101

102 103
	if (!conn)
	{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
104
		CC_log_error(func, "", NULL);
105
		return SQL_INVALID_HANDLE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
106
	}
107

108 109 110
	ci = &conn->connInfo;

	make_string(szDSN, cbDSN, ci->dsn);
111

112
	/* get the values for the DSN from the registry */
113
	getDSNinfo(ci, CONN_OVERWRITE);
114
	logs_on_off(1, ci->drivers.debug, ci->drivers.commlog);
115 116 117 118 119 120 121
	/* initialize pg_version from connInfo.protocol    */
	CC_initialize_pg_version(conn);

	/*
	 * override values from DSN info with UID and authStr(pwd) This only
	 * occurs if the values are actually there.
	 */
122 123
	make_string(szUID, cbUID, ci->username);
	make_string(szAuthStr, cbAuthStr, ci->password);
124 125

	/* fill in any defaults */
126
	getDSNdefaults(ci);
127

128
	qlog("conn = %u, %s(DSN='%s', UID='%s', PWD='%s')\n", conn, func, ci->dsn, ci->username, ci->password);
129

130 131 132
	if (CC_connect(conn, FALSE) <= 0)
	{
		/* Error messages are filled in */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
133
		CC_log_error(func, "Error on CC_connect", conn);
134
		return SQL_ERROR;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
135
	}
136

137
	mylog("%s: returning...\n", func);
138

139 140 141 142
	return SQL_SUCCESS;
}


143
RETCODE SQL_API
144
PGAPI_BrowseConnect(
145 146 147 148 149 150
				 HDBC hdbc,
				 UCHAR FAR *szConnStrIn,
				 SWORD cbConnStrIn,
				 UCHAR FAR *szConnStrOut,
				 SWORD cbConnStrOutMax,
				 SWORD FAR *pcbConnStrOut)
151
{
152
	static char *func = "PGAPI_BrowseConnect";
153

154
	mylog("%s: entering...\n", func);
155

156 157 158 159 160
	return SQL_SUCCESS;
}


/* Drop any hstmts open on hdbc and disconnect from database */
161
RETCODE SQL_API
162
PGAPI_Disconnect(
163
			  HDBC hdbc)
164
{
165
	ConnectionClass *conn = (ConnectionClass *) hdbc;
166
	static char *func = "PGAPI_Disconnect";
167

168

169
	mylog("%s: entering...\n", func);
170

171 172
	if (!conn)
	{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
173
		CC_log_error(func, "", NULL);
174
		return SQL_INVALID_HANDLE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
175
	}
176

177
	qlog("conn=%u, %s\n", conn, func);
178

179 180
	if (conn->status == CONN_EXECUTING)
	{
181 182
		conn->errornumber = CONN_IN_USE;
		conn->errormsg = "A transaction is currently being executed";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
183
		CC_log_error(func, "", conn);
184 185
		return SQL_ERROR;
	}
186

187
	logs_on_off(-1, conn->connInfo.drivers.debug, conn->connInfo.drivers.commlog);
188
	mylog("%s: about to CC_cleanup\n", func);
189

190
	/* Close the connection and free statements */
191 192
	CC_cleanup(conn);

193 194
	mylog("%s: done CC_cleanup\n", func);
	mylog("%s: returning...\n", func);
195 196 197 198 199

	return SQL_SUCCESS;
}


200
RETCODE SQL_API
201
PGAPI_FreeConnect(
202
			   HDBC hdbc)
203
{
204
	ConnectionClass *conn = (ConnectionClass *) hdbc;
205
	static char *func = "PGAPI_FreeConnect";
206

207
	mylog("%s: entering...\n", func);
208
	mylog("**** in %s: hdbc=%u\n", func, hdbc);
209

210 211
	if (!conn)
	{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
212
		CC_log_error(func, "", NULL);
213
		return SQL_INVALID_HANDLE;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
214
	}
215

216 217 218
	/* Remove the connection from the environment */
	if (!EN_remove_connection(conn->henv, conn))
	{
219 220
		conn->errornumber = CONN_IN_USE;
		conn->errormsg = "A transaction is currently being executed";
Byron Nikolaidis's avatar
Byron Nikolaidis committed
221
		CC_log_error(func, "", conn);
222 223
		return SQL_ERROR;
	}
224 225 226

	CC_Destructor(conn);

227
	mylog("%s: returning...\n", func);
228 229 230 231 232 233

	return SQL_SUCCESS;
}


/*
234 235
 *		IMPLEMENTATION CONNECTION CLASS
 */
236 237
ConnectionClass *
CC_Constructor()
238
{
239
	ConnectionClass *rv;
240

241
	rv = (ConnectionClass *) malloc(sizeof(ConnectionClass));
242

243 244 245
	if (rv != NULL)
	{
		rv->henv = NULL;		/* not yet associated with an environment */
246

247 248
		rv->errormsg = NULL;
		rv->errornumber = 0;
249 250
		rv->errormsg_created = FALSE;

251 252
		rv->status = CONN_NOT_CONNECTED;
		rv->transact_status = CONN_IN_AUTOCOMMIT;		/* autocommit by default */
253 254

		memset(&rv->connInfo, 0, sizeof(ConnInfo));
255 256
memcpy(&(rv->connInfo.drivers), &globals, sizeof(globals));
		rv->sock = SOCK_Constructor(rv);
257
		if (!rv->sock)
258 259
			return NULL;

260 261
		rv->stmts = (StatementClass **) malloc(sizeof(StatementClass *) * STMT_INCREMENT);
		if (!rv->stmts)
262 263 264 265 266
			return NULL;
		memset(rv->stmts, 0, sizeof(StatementClass *) * STMT_INCREMENT);

		rv->num_stmts = STMT_INCREMENT;

267
		rv->lobj_type = PG_TYPE_LO;
Byron Nikolaidis's avatar
Byron Nikolaidis committed
268 269 270 271 272 273 274 275

		rv->ntables = 0;
		rv->col_info = NULL;

		rv->translation_option = 0;
		rv->translation_handle = NULL;
		rv->DataSourceToDriver = NULL;
		rv->DriverToDataSource = NULL;
276
		rv->driver_version = ODBCVER;
277 278 279 280
		memset(rv->pg_version, 0, sizeof(rv->pg_version));
		rv->pg_version_number = .0;
		rv->pg_version_major = 0;
		rv->pg_version_minor = 0;
281 282 283 284
#ifdef	MULTIBYTE
		rv->client_encoding = NULL;
		rv->server_encoding = NULL;
#endif	/* MULTIBYTE */
285

286

287 288
		/* Initialize statement options to defaults */
		/* Statements under this conn will inherit these options */
289 290

		InitializeStatementOptions(&rv->stmtOptions);
291 292


293 294
	}
	return rv;
295 296 297 298
}


char
Bruce Momjian's avatar
Bruce Momjian committed
299
CC_Destructor(ConnectionClass *self)
300 301 302 303 304 305
{
	mylog("enter CC_Destructor, self=%u\n", self);

	if (self->status == CONN_EXECUTING)
		return 0;

306
	CC_cleanup(self);			/* cleanup socket and statements */
307 308 309

	mylog("after CC_Cleanup\n");

310 311 312 313 314 315
#ifdef	MULTIBYTE
	if (self->client_encoding)
		free(self->client_encoding);
	if (self->server_encoding)
		free(self->server_encoding);
#endif	/* MULTIBYTE */
316 317 318
	/* Free up statement holders */
	if (self->stmts)
	{
319 320 321 322 323
		free(self->stmts);
		self->stmts = NULL;
	}
	mylog("after free statement holders\n");

324 325 326 327 328 329 330 331 332
	/* Free cached table info */
	if (self->col_info)
	{
		int			i;

		for (i = 0; i < self->ntables; i++)
		{
			if (self->col_info[i]->result)		/* Free the SQLColumns
												 * result structure */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
333 334 335 336 337 338 339
				QR_Destructor(self->col_info[i]->result);

			free(self->col_info[i]);
		}
		free(self->col_info);
	}

340

341 342 343 344 345 346 347
	free(self);

	mylog("exit CC_Destructor\n");

	return 1;
}

348

349 350
/*	Return how many cursors are opened on this connection */
int
Bruce Momjian's avatar
Bruce Momjian committed
351
CC_cursor_count(ConnectionClass *self)
352
{
353 354 355
	StatementClass *stmt;
	int			i,
				count = 0;
356 357 358

	mylog("CC_cursor_count: self=%u, num_stmts=%d\n", self, self->num_stmts);

359 360
	for (i = 0; i < self->num_stmts; i++)
	{
361 362 363 364 365 366 367 368 369 370
		stmt = self->stmts[i];
		if (stmt && stmt->result && stmt->result->cursor)
			count++;
	}

	mylog("CC_cursor_count: returning %d\n", count);

	return count;
}

371

372
void
Bruce Momjian's avatar
Bruce Momjian committed
373
CC_clear_error(ConnectionClass *self)
374
{
375 376
	self->errornumber = 0;
	self->errormsg = NULL;
377 378 379
	self->errormsg_created = FALSE;
}

380 381 382 383 384

/*
 *	Used to cancel a transaction.
 *	We are almost always in the middle of a transaction.
 */
385
char
Bruce Momjian's avatar
Bruce Momjian committed
386
CC_abort(ConnectionClass *self)
387
{
388
	QResultClass *res;
389

390 391
	if (CC_is_in_trans(self))
	{
392 393 394 395
		res = NULL;

		mylog("CC_abort:  sending ABORT!\n");

396
		res = CC_send_query(self, "ABORT", NULL);
397 398 399 400 401 402
		CC_set_no_trans(self);

		if (res != NULL)
			QR_Destructor(res);
		else
			return FALSE;
403

404 405 406 407 408
	}

	return TRUE;
}

409

410 411
/* This is called by SQLDisconnect also */
char
Bruce Momjian's avatar
Bruce Momjian committed
412
CC_cleanup(ConnectionClass *self)
413
{
414 415
	int			i;
	StatementClass *stmt;
416 417 418 419 420 421

	if (self->status == CONN_EXECUTING)
		return FALSE;

	mylog("in CC_Cleanup, self=%u\n", self);

422 423 424
	/* Cancel an ongoing transaction */
	/* We are always in the middle of a transaction, */
	/* even if we are in auto commit. */
425 426 427 428 429
	if (self->sock)
		CC_abort(self);

	mylog("after CC_abort\n");

430 431 432 433
	/* This actually closes the connection to the dbase */
	if (self->sock)
	{
		SOCK_Destructor(self->sock);
434 435 436 437 438
		self->sock = NULL;
	}

	mylog("after SOCK destructor\n");

439 440 441
	/* Free all the stmts on this connection */
	for (i = 0; i < self->num_stmts; i++)
	{
442
		stmt = self->stmts[i];
443 444
		if (stmt)
		{
445
			stmt->hdbc = NULL;	/* prevent any more dbase interactions */
446

447
			SC_Destructor(stmt);
448

449 450 451
			self->stmts[i] = NULL;
		}
	}
Byron Nikolaidis's avatar
Byron Nikolaidis committed
452

453
	/* Check for translation dll */
454
#ifdef WIN32
455 456 457
	if (self->translation_handle)
	{
		FreeLibrary(self->translation_handle);
Byron Nikolaidis's avatar
Byron Nikolaidis committed
458 459
		self->translation_handle = NULL;
	}
460
#endif
Byron Nikolaidis's avatar
Byron Nikolaidis committed
461

462 463 464 465
	mylog("exit CC_Cleanup\n");
	return TRUE;
}

466

Byron Nikolaidis's avatar
Byron Nikolaidis committed
467
int
468
CC_set_translation(ConnectionClass *self)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
469 470
{

471 472
#ifdef WIN32

473 474 475
	if (self->translation_handle != NULL)
	{
		FreeLibrary(self->translation_handle);
Byron Nikolaidis's avatar
Byron Nikolaidis committed
476 477
		self->translation_handle = NULL;
	}
478

Byron Nikolaidis's avatar
Byron Nikolaidis committed
479 480 481
	if (self->connInfo.translation_dll[0] == 0)
		return TRUE;

482 483
	self->translation_option = atoi(self->connInfo.translation_option);
	self->translation_handle = LoadLibrary(self->connInfo.translation_dll);
Byron Nikolaidis's avatar
Byron Nikolaidis committed
484

485 486
	if (self->translation_handle == NULL)
	{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
487 488 489 490 491 492
		self->errornumber = CONN_UNABLE_TO_LOAD_DLL;
		self->errormsg = "Could not load the translation DLL.";
		return FALSE;
	}

	self->DataSourceToDriver
493
		= (DataSourceToDriverProc) GetProcAddress(self->translation_handle,
Byron Nikolaidis's avatar
Byron Nikolaidis committed
494 495 496
												"SQLDataSourceToDriver");

	self->DriverToDataSource
497
		= (DriverToDataSourceProc) GetProcAddress(self->translation_handle,
Byron Nikolaidis's avatar
Byron Nikolaidis committed
498 499
												"SQLDriverToDataSource");

500 501
	if (self->DataSourceToDriver == NULL || self->DriverToDataSource == NULL)
	{
Byron Nikolaidis's avatar
Byron Nikolaidis committed
502 503 504 505
		self->errornumber = CONN_UNABLE_TO_LOAD_DLL;
		self->errormsg = "Could not find translation DLL functions.";
		return FALSE;
	}
506
#endif
Byron Nikolaidis's avatar
Byron Nikolaidis committed
507 508
	return TRUE;
}
509

510

511
char
Bruce Momjian's avatar
Bruce Momjian committed
512
CC_connect(ConnectionClass *self, char do_password)
513
{
514 515 516 517 518 519 520 521
	StartupPacket sp;
	StartupPacket6_2 sp62;
	QResultClass *res;
	SocketClass *sock;
	ConnInfo   *ci = &(self->connInfo);
	int			areq = -1;
	int			beresp;
	char		msgbuffer[ERROR_MSG_LENGTH];
Bruce Momjian's avatar
Bruce Momjian committed
522
	char		salt[5];
523
	static char *func = "CC_connect";
524 525 526
#ifdef	MULTIBYTE
	char	*encoding;
#endif /* MULTIBYTE */
527 528

	mylog("%s: entering...\n", func);
529

530
	if (do_password)
531

532 533
		sock = self->sock;		/* already connected, just authenticate */

534 535
	else
	{
536
		qlog("Global Options: Version='%s', fetch=%d, socket=%d, unknown_sizes=%d, max_varchar_size=%d, max_longvarchar_size=%d\n",
537
			 POSTGRESDRIVERVERSION,
538 539 540 541 542
			 ci->drivers.fetch_max,
			 ci->drivers.socket_buffersize,
			 ci->drivers.unknown_sizes,
			 ci->drivers.max_varchar_size,
			 ci->drivers.max_longvarchar_size);
543
		qlog("                disable_optimizer=%d, ksqo=%d, unique_index=%d, use_declarefetch=%d\n",
544 545 546 547
			 ci->drivers.disable_optimizer,
			 ci->drivers.ksqo,
			 ci->drivers.unique_index,
			 ci->drivers.use_declarefetch);
548
		qlog("                text_as_longvarchar=%d, unknowns_as_longvarchar=%d, bools_as_char=%d\n",
549 550 551
			 ci->drivers.text_as_longvarchar,
			 ci->drivers.unknowns_as_longvarchar,
			 ci->drivers.bools_as_char);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
552 553

#ifdef MULTIBYTE
554
		encoding = check_client_encoding(ci->conn_settings);
555 556
		if (encoding && strcmp(encoding, "OTHER"))
			self->client_encoding = strdup(encoding);
557 558 559 560 561 562
		else
		{ 
			encoding = check_client_encoding(ci->drivers.conn_settings);
			if (encoding && strcmp(encoding, "OTHER"))
				self->client_encoding = strdup(encoding);
		}
Hiroshi Inoue's avatar
Hiroshi Inoue committed
563
		qlog("                extra_systable_prefixes='%s', conn_settings='%s' conn_encoding='%s'\n",
564 565
			 ci->drivers.extra_systable_prefixes,
			 ci->drivers.conn_settings,
566
			 encoding ? encoding : "");
Hiroshi Inoue's avatar
Hiroshi Inoue committed
567
#else
568
		qlog("                extra_systable_prefixes='%s', conn_settings='%s'\n",
569 570
			 ci->drivers.extra_systable_prefixes,
			 ci->drivers.conn_settings);
Hiroshi Inoue's avatar
Hiroshi Inoue committed
571
#endif
572

573 574
		if (self->status != CONN_NOT_CONNECTED)
		{
575 576 577 578 579
			self->errormsg = "Already connected.";
			self->errornumber = CONN_OPENDB_ERROR;
			return 0;
		}

580 581
		if (ci->server[0] == '\0' || ci->port[0] == '\0' || ci->database[0] == '\0')
		{
582 583 584 585 586
			self->errornumber = CONN_INIREAD_ERROR;
			self->errormsg = "Missing server name, port, or database name in call to CC_connect.";
			return 0;
		}

587
		mylog("CC_connect(): DSN = '%s', server = '%s', port = '%s', database = '%s', username = '%s', password='%s'\n", ci->dsn, ci->server, ci->port, ci->database, ci->username, ci->password);
588

589 590 591 592 593 594
		/*
		 * If the socket was closed for some reason (like a SQLDisconnect,
		 * but no SQLFreeConnect then create a socket now.
		 */
		if (!self->sock)
		{
595
			self->sock = SOCK_Constructor(self);
596 597 598 599 600
			if (!self->sock)
			{
				self->errornumber = CONNECTION_SERVER_NOT_REACHED;
				self->errormsg = "Could not open a socket to the server";
				return 0;
601 602 603 604 605 606 607 608
			}
		}

		sock = self->sock;

		mylog("connecting to the server socket...\n");

		SOCK_connect_to(sock, (short) atoi(ci->port), ci->server);
609 610
		if (SOCK_get_errcode(sock) != 0)
		{
611 612 613 614 615 616
			mylog("connection to the server socket failed.\n");
			self->errornumber = CONNECTION_SERVER_NOT_REACHED;
			self->errormsg = "Could not connect to the server";
			return 0;
		}
		mylog("connection to the server socket succeeded.\n");
617

618 619 620 621
		if (PROTOCOL_62(ci))
		{
			sock->reverse = TRUE;		/* make put_int and get_int work
										 * for 6.2 */
622 623

			memset(&sp62, 0, sizeof(StartupPacket6_2));
624
			SOCK_put_int(sock, htonl(4 + sizeof(StartupPacket6_2)), 4);
625 626 627 628 629 630
			sp62.authtype = htonl(NO_AUTHENTICATION);
			strncpy(sp62.database, ci->database, PATH_SIZE);
			strncpy(sp62.user, ci->username, NAMEDATALEN);
			SOCK_put_n_char(sock, (char *) &sp62, sizeof(StartupPacket6_2));
			SOCK_flush_output(sock);
		}
631 632
		else
		{
633
			memset(&sp, 0, sizeof(StartupPacket));
634

635
			mylog("sizeof startup packet = %d\n", sizeof(StartupPacket));
636

637
			/* Send length of Authentication Block */
638
			SOCK_put_int(sock, 4 + sizeof(StartupPacket), 4);
639

640
			if (PROTOCOL_63(ci))
641 642 643
				sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_63);
			else
				sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_LATEST);
644

645 646
			strncpy(sp.database, ci->database, SM_DATABASE);
			strncpy(sp.user, ci->username, SM_USER);
647

648 649 650
			SOCK_put_n_char(sock, (char *) &sp, sizeof(StartupPacket));
			SOCK_flush_output(sock);
		}
651 652 653

		mylog("sent the authentication block.\n");

654 655
		if (sock->errornumber != 0)
		{
656 657 658 659 660 661 662 663
			mylog("couldn't send the authentication block properly.\n");
			self->errornumber = CONN_INVALID_AUTHENTICATION;
			self->errormsg = "Sending the authentication packet failed";
			return 0;
		}
		mylog("sent the authentication block successfully.\n");
	}

664

665 666 667
	mylog("gonna do authentication\n");


668 669 670
	/*
	 * Now get the authentication request from backend
	 */
671

672
	if (!PROTOCOL_62(ci))
673 674
	{
		BOOL before_64 = PG_VERSION_LT(self, 6.4), ReadyForQuery = FALSE;
675 676 677 678 679
		do
		{
			if (do_password)
				beresp = 'R';
			else
680
			{
681
				beresp = SOCK_get_char(sock);
682 683
				mylog("auth got '%c'\n", beresp);
			}
684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703

			switch (beresp)
			{
				case 'E':

					SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
					self->errornumber = CONN_INVALID_AUTHENTICATION;
					self->errormsg = msgbuffer;
					qlog("ERROR from backend during authentication: '%s'\n", self->errormsg);
					return 0;
				case 'R':

					if (do_password)
					{
						mylog("in 'R' do_password\n");
						areq = AUTH_REQ_PASSWORD;
						do_password = FALSE;
					}
					else
					{
704

705
						areq = SOCK_get_int(sock, 4);
Bruce Momjian's avatar
Bruce Momjian committed
706 707 708
						if (areq == AUTH_REQ_MD5)
							SOCK_get_n_char(sock, salt, 4);
						if (areq == AUTH_REQ_CRYPT)
709
							SOCK_get_n_char(sock, salt, 2);
710

711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
						mylog("areq = %d\n", areq);
					}
					switch (areq)
					{
						case AUTH_REQ_OK:
							break;

						case AUTH_REQ_KRB4:
							self->errormsg = "Kerberos 4 authentication not supported";
							self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED;
							return 0;

						case AUTH_REQ_KRB5:
							self->errormsg = "Kerberos 5 authentication not supported";
							self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED;
							return 0;

						case AUTH_REQ_PASSWORD:
							mylog("in AUTH_REQ_PASSWORD\n");

							if (ci->password[0] == '\0')
							{
								self->errornumber = CONNECTION_NEED_PASSWORD;
								self->errormsg = "A password is required for this connection.";
								return -1;		/* need password */
							}

							mylog("past need password\n");

							SOCK_put_int(sock, 4 + strlen(ci->password) + 1, 4);
							SOCK_put_n_char(sock, ci->password, strlen(ci->password) + 1);
							SOCK_flush_output(sock);

							mylog("past flush\n");
							break;

						case AUTH_REQ_CRYPT:
748
						case AUTH_REQ_MD5:
749 750 751 752
							self->errormsg = "Password crypt authentication not supported";
							self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED;
							return 0;

753 754 755 756 757
						case AUTH_REQ_SCM_CREDS:
							self->errormsg = "Unix socket credential authentication not supported";
							self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED;
							return 0;

758 759 760 761 762 763
						default:
							self->errormsg = "Unknown authentication type";
							self->errornumber = CONN_AUTH_TYPE_UNSUPPORTED;
							return 0;
					}
					break;
764 765 766 767 768 769 770 771
				case 'K':			/* Secret key (6.4 protocol) */
					(void) SOCK_get_int(sock, 4);	/* pid */
					(void) SOCK_get_int(sock, 4);	/* key */

					break;
				case 'Z':			/* Backend is ready for new query (6.4) */
					ReadyForQuery = TRUE;
					break;
772 773 774 775
				default:
					self->errormsg = "Unexpected protocol character during authentication";
					self->errornumber = CONN_INVALID_AUTHENTICATION;
					return 0;
776
			}
777

778 779 780 781 782 783 784 785
			/* 
			 *	There were no ReadyForQuery responce
			 *	before 6.4.
			 */
			if (before_64 && areq == AUTH_REQ_OK)
				ReadyForQuery = TRUE;
		} while (!ReadyForQuery);
	}
786 787


788
	CC_clear_error(self);		/* clear any password error */
789

790 791 792 793
	/*
	 * send an empty query in order to find out whether the specified
	 * database really exists on the server machine
	 */
794 795
	mylog("sending an empty query...\n");

796
	res = CC_send_query(self, " ", NULL);
797 798
	if (res == NULL || QR_get_status(res) != PGRES_EMPTY_QUERY)
	{
799 800 801 802 803 804 805 806 807 808 809 810
		mylog("got no result from the empty query.  (probably database does not exist)\n");
		self->errornumber = CONNECTION_NO_SUCH_DATABASE;
		self->errormsg = "The database does not exist on the server\nor user authentication failed.";
		if (res != NULL)
			QR_Destructor(res);
		return 0;
	}
	if (res)
		QR_Destructor(res);

	mylog("empty query seems to be OK.\n");

811
	CC_set_translation(self);
812

813
	/*
814
	 * Send any initial settings
815
	 */
816

817 818 819 820 821 822
	/*
	 * Since these functions allocate statements, and since the connection
	 * is not established yet, it would violate odbc state transition
	 * rules.  Therefore, these functions call the corresponding local
	 * function instead.
	 */
Byron Nikolaidis's avatar
Byron Nikolaidis committed
823
	CC_send_settings(self);
824 825 826 827
	CC_lookup_lo(self);			/* a hack to get the oid of our large
								 * object oid type */
	CC_lookup_pg_version(self); /* Get PostgreSQL version for SQLGetInfo
								 * use */
828

829
	CC_clear_error(self);		/* clear any initial command errors */
830 831
	self->status = CONN_CONNECTED;

832 833
	mylog("%s: returning...\n", func);

834
	return 1;
835

836 837
}

838

839
char
Bruce Momjian's avatar
Bruce Momjian committed
840
CC_add_statement(ConnectionClass *self, StatementClass *stmt)
841
{
842
	int			i;
843 844 845

	mylog("CC_add_statement: self=%u, stmt=%u\n", self, stmt);

846 847 848 849
	for (i = 0; i < self->num_stmts; i++)
	{
		if (!self->stmts[i])
		{
850 851 852 853 854 855 856
			stmt->hdbc = self;
			self->stmts[i] = stmt;
			return TRUE;
		}
	}

	/* no more room -- allocate more memory */
857 858
	self->stmts = (StatementClass **) realloc(self->stmts, sizeof(StatementClass *) * (STMT_INCREMENT + self->num_stmts));
	if (!self->stmts)
859 860 861 862 863 864 865 866 867 868 869 870
		return FALSE;

	memset(&self->stmts[self->num_stmts], 0, sizeof(StatementClass *) * STMT_INCREMENT);

	stmt->hdbc = self;
	self->stmts[self->num_stmts] = stmt;

	self->num_stmts += STMT_INCREMENT;

	return TRUE;
}

871

872
char
Bruce Momjian's avatar
Bruce Momjian committed
873
CC_remove_statement(ConnectionClass *self, StatementClass *stmt)
874
{
875
	int			i;
876

877 878 879 880
	for (i = 0; i < self->num_stmts; i++)
	{
		if (self->stmts[i] == stmt && stmt->status != STMT_EXECUTING)
		{
881 882 883 884 885 886 887 888
			self->stmts[i] = NULL;
			return TRUE;
		}
	}

	return FALSE;
}

889 890 891 892 893

/*
 *	Create a more informative error message by concatenating the connection
 *	error message with its socket error message.
 */
894
char *
Bruce Momjian's avatar
Bruce Momjian committed
895
CC_create_errormsg(ConnectionClass *self)
896
{
897 898 899
	SocketClass *sock = self->sock;
	int			pos;
	static char msg[4096];
900 901 902 903 904 905 906 907 908 909

	mylog("enter CC_create_errormsg\n");

	msg[0] = '\0';

	if (self->errormsg)
		strcpy(msg, self->errormsg);

	mylog("msg = '%s'\n", msg);

910 911
	if (sock && sock->errormsg && sock->errormsg[0] != '\0')
	{
912 913 914 915 916 917 918 919 920
		pos = strlen(msg);
		sprintf(&msg[pos], ";\n%s", sock->errormsg);
	}

	mylog("exit CC_create_errormsg\n");
	return msg;
}


921
char
Bruce Momjian's avatar
Bruce Momjian committed
922
CC_get_error(ConnectionClass *self, int *number, char **message)
923
{
924
	int			rv;
925 926 927

	mylog("enter CC_get_error\n");

928 929 930
	/* Create a very informative errormsg if it hasn't been done yet. */
	if (!self->errormsg_created)
	{
931 932 933 934
		self->errormsg = CC_create_errormsg(self);
		self->errormsg_created = TRUE;
	}

935 936
	if (self->errornumber)
	{
937 938 939 940 941
		*number = self->errornumber;
		*message = self->errormsg;
	}
	rv = (self->errornumber != 0);

942
	self->errornumber = 0;		/* clear the error */
943 944 945 946 947 948

	mylog("exit CC_get_error\n");

	return rv;
}

949

950 951 952 953 954 955 956 957 958
/*
 *	The "result_in" is only used by QR_next_tuple() to fetch another group of rows into
 *	the same existing QResultClass (this occurs when the tuple cache is depleted and
 *	needs to be re-filled).
 *
 *	The "cursor" is used by SQLExecute to associate a statement handle as the cursor name
 *	(i.e., C3326857) for SQL select statements.  This cursor is then used in future
 *	'declare cursor C3326857 for ...' and 'fetch 100 in C3326857' statements.
 */
959
QResultClass *
Bruce Momjian's avatar
Bruce Momjian committed
960
CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
961
{
962
	QResultClass *result_in = NULL, *res = NULL, *retres = NULL;
963
	char		swallow, *wq;
964 965
	int			id;
	SocketClass *sock = self->sock;
966 967 968 969
	int		maxlen, empty_reqs;
	BOOL		msg_truncated, ReadyToReturn,
			tuples_return = FALSE, query_completed = FALSE,
			before_64 = PG_VERSION_LT(self, 6.4);
970

971 972
	/* ERROR_MSG_LENGTH is suffcient */
	static char msgbuffer[ERROR_MSG_LENGTH + 1];
973

974 975
	/* QR_set_command() dups this string so doesn't need static */
	char		cmdbuffer[ERROR_MSG_LENGTH + 1];
976 977 978 979

	mylog("send_query(): conn=%u, query='%s'\n", self, query);
	qlog("conn=%u, query='%s'\n", self, query);

980
	/* Indicate that we are sending a query to the backend */
981 982
	maxlen = CC_get_max_query_len(self);
	if (maxlen > 0 && maxlen < (int) strlen(query) + 1)
983
	{
984 985 986 987 988 989 990 991
		self->errornumber = CONNECTION_MSG_TOO_LONG;
		self->errormsg = "Query string is too long";
		return NULL;
	}

	if ((NULL == query) || (query[0] == '\0'))
		return NULL;

992 993
	if (SOCK_get_errcode(sock) != 0)
	{
994 995 996 997 998 999 1000
		self->errornumber = CONNECTION_COULD_NOT_SEND;
		self->errormsg = "Could not send Query to backend";
		CC_set_no_trans(self);
		return NULL;
	}

	SOCK_put_char(sock, 'Q');
1001 1002
	if (SOCK_get_errcode(sock) != 0)
	{
1003 1004 1005 1006 1007 1008 1009 1010 1011
		self->errornumber = CONNECTION_COULD_NOT_SEND;
		self->errormsg = "Could not send Query to backend";
		CC_set_no_trans(self);
		return NULL;
	}

	SOCK_put_string(sock, query);
	SOCK_flush_output(sock);

1012 1013
	if (SOCK_get_errcode(sock) != 0)
	{
1014 1015 1016 1017 1018 1019 1020 1021
		self->errornumber = CONNECTION_COULD_NOT_SEND;
		self->errormsg = "Could not send Query to backend";
		CC_set_no_trans(self);
		return NULL;
	}

	mylog("send_query: done sending query\n");

1022 1023
	ReadyToReturn = FALSE;
	empty_reqs = 0;
1024 1025 1026
	for (wq = query; isspace(*wq); wq++)
		;
	if (*wq == '\0')
1027 1028
		empty_reqs = 1;
	while (!ReadyToReturn)
1029
	{
1030
		/* what type of message is coming now ? */
1031 1032
		id = SOCK_get_char(sock);

1033 1034
		if ((SOCK_get_errcode(sock) != 0) || (id == EOF))
		{
1035 1036 1037 1038 1039
			self->errornumber = CONNECTION_NO_RESPONSE;
			self->errormsg = "No response from the backend";

			mylog("send_query: 'id' - %s\n", self->errormsg);
			CC_set_no_trans(self);
1040 1041 1042
			ReadyToReturn = TRUE;
			retres = NULL;
			break;
1043 1044 1045 1046
		}

		mylog("send_query: got id = '%c'\n", id);

1047 1048 1049 1050
		switch (id)
		{
			case 'A':			/* Asynchronous Messages are ignored */
				(void) SOCK_get_int(sock, 4);	/* id of notification */
1051
				SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
1052 1053 1054 1055 1056
				/* name of the relation the message comes from */
				break;
			case 'C':			/* portal query command, no tuples
								 * returned */
				/* read in the return message from the backend */
1057
				SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
1058 1059 1060 1061 1062 1063
				if (SOCK_get_errcode(sock) != 0)
				{
					self->errornumber = CONNECTION_NO_RESPONSE;
					self->errormsg = "No response from backend while receiving a portal query command";
					mylog("send_query: 'C' - %s\n", self->errormsg);
					CC_set_no_trans(self);
1064 1065
					ReadyToReturn = TRUE;
					retres = NULL;
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076
				}
				else
				{
					mylog("send_query: ok - 'C' - %s\n", cmdbuffer);

					if (res == NULL)	/* allow for "show" style notices */
						res = QR_Constructor();

					mylog("send_query: setting cmdbuffer = '%s'\n", cmdbuffer);

					/* Only save the first command */
1077 1078
					if (QR_command_successful(res))
						QR_set_status(res, PGRES_COMMAND_OK);
1079
					QR_set_command(res, cmdbuffer);
1080
					query_completed = TRUE;
1081
					mylog("send_query: returning res = %u\n", res);
1082 1083
					if (!before_64)
						break;
1084 1085 1086 1087 1088 1089 1090 1091
					/*
					 * (Quotation from the original comments) since
					 * backend may produce more than one result for some
					 * commands we need to poll until clear so we send an
					 * empty query, and keep reading out of the pipe until
					 * an 'I' is received
					 */

1092 1093 1094 1095 1096 1097
					if (empty_reqs == 0)
					{
						SOCK_put_string(sock, "Q ");
						SOCK_flush_output(sock);
						empty_reqs++;
					}
1098
				}
1099
				break;
1100
			case 'Z':			/* Backend is ready for new query (6.4) */
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
				if (empty_reqs == 0)
				{
					ReadyToReturn = TRUE;
					if (res && QR_get_aborted(res))
						retres = res;
					else if (tuples_return)
						retres = result_in;
					else if (query_completed)
						retres = res;
					else
						ReadyToReturn = FALSE;
				}
1113 1114
				break;
			case 'N':			/* NOTICE: */
1115 1116 1117 1118 1119
				msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
				if (!res)
					res = QR_Constructor();
				if (QR_command_successful(res))
					QR_set_status(res, PGRES_NONFATAL_ERROR);
1120
				QR_set_notice(res, cmdbuffer);	/* will dup this string */
1121

1122 1123
				mylog("~~~ NOTICE: '%s'\n", cmdbuffer);
				qlog("NOTICE from backend during send_query: '%s'\n", cmdbuffer);
1124 1125
				while (msg_truncated)
					msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
1126

1127 1128
				continue;		/* dont return a result -- continue
								 * reading */
1129

1130
			case 'I':			/* The server sends an empty query */
1131
				/* There is a closing '\0' following the 'I', so we eat it */
1132
				swallow = SOCK_get_char(sock);
1133 1134
				if (!res)
					res = QR_Constructor();
1135 1136 1137 1138 1139
				if ((swallow != '\0') || SOCK_get_errcode(sock) != 0)
				{
					self->errornumber = CONNECTION_BACKEND_CRAZY;
					self->errormsg = "Unexpected protocol character from backend (send_query - I)";
					QR_set_status(res, PGRES_FATAL_ERROR);
1140 1141 1142
					ReadyToReturn = TRUE;
					retres = res;
					break;
1143 1144 1145 1146 1147
				}
				else
				{
					/* We return the empty query */
					QR_set_status(res, PGRES_EMPTY_QUERY);
1148 1149 1150 1151 1152
				}
				if (empty_reqs > 0)
				{
					if (--empty_reqs == 0)
						query_completed = TRUE;
1153 1154 1155
				}
				break;
			case 'E':
1156
				msg_truncated = SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
1157

1158 1159 1160
				/* Remove a newline */
				if (msgbuffer[0] != '\0' && msgbuffer[strlen(msgbuffer) - 1] == '\n')
					msgbuffer[strlen(msgbuffer) - 1] = '\0';
1161

1162
				self->errormsg = msgbuffer;
1163

1164 1165
				mylog("send_query: 'E' - %s\n", self->errormsg);
				qlog("ERROR from backend during send_query: '%s'\n", self->errormsg);
1166

1167
				/* We should report that an error occured. Zoltan */
1168 1169
				if (!res)
					res = QR_Constructor();
1170

1171 1172 1173 1174
				if (!strncmp(self->errormsg, "FATAL", 5))
				{
					self->errornumber = CONNECTION_SERVER_REPORTED_ERROR;
					CC_set_no_trans(self);
1175
				}
1176 1177 1178 1179
				else
				{
					self->errornumber = CONNECTION_SERVER_REPORTED_WARNING;
				}
1180
				QR_set_status(res, PGRES_FATAL_ERROR);
1181
				QR_set_aborted(res, TRUE);
1182 1183
				while (msg_truncated)
					msg_truncated = SOCK_get_string(sock, cmdbuffer, ERROR_MSG_LENGTH);
1184

1185 1186
				query_completed = TRUE;
				break;
1187

1188
			case 'P':			/* get the Portal name */
1189
				SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
				break;
			case 'T':			/* Tuple results start here */
				result_in = qi ? qi->result_in : NULL;

				if (result_in == NULL)
				{
					result_in = QR_Constructor();
					mylog("send_query: 'T' no result_in: res = %u\n", result_in);
					if (!result_in)
					{
						self->errornumber = CONNECTION_COULD_NOT_RECEIVE;
						self->errormsg = "Could not create result info in send_query.";
1202 1203 1204
						ReadyToReturn = TRUE;
						retres = NULL;
						break;
1205 1206 1207 1208 1209 1210 1211 1212 1213
					}

					if (qi)
						QR_set_cache_size(result_in, qi->row_size);

					if (!QR_fetch_tuples(result_in, self, qi ? qi->cursor : NULL))
					{
						self->errornumber = CONNECTION_COULD_NOT_RECEIVE;
						self->errormsg = QR_get_message(result_in);
1214 1215 1216
						ReadyToReturn = TRUE;
						retres = NULL;
						break;
1217
					}
1218
				}
1219 1220
				else
				{				/* next fetch, so reuse an existing result */
1221 1222 1223 1224 1225
					/*
					 *	called from QR_next_tuple
					 *	and must return immediately.
					 */
					ReadyToReturn = TRUE;
1226 1227 1228 1229
					if (!QR_fetch_tuples(result_in, NULL, NULL))
					{
						self->errornumber = CONNECTION_COULD_NOT_RECEIVE;
						self->errormsg = QR_get_message(result_in);
1230 1231
						retres = NULL;
						break;
1232
					}
1233
					retres = result_in;
1234 1235
				}

1236 1237
				tuples_return = TRUE;
				break;
1238
			case 'D':			/* Copy in command began successfully */
1239 1240 1241 1242
				if (!res)
					res = QR_Constructor();
				if (QR_command_successful(res))
					QR_set_status(res, PGRES_COPY_IN);
1243 1244 1245
				ReadyToReturn = TRUE;
				retres = res;
				break;
1246
			case 'B':			/* Copy out command began successfully */
1247 1248 1249 1250
				if (!res)
					res = QR_Constructor();
				if (QR_command_successful(res))
					QR_set_status(res, PGRES_COPY_OUT);
1251 1252 1253
				ReadyToReturn = TRUE;
				retres = res;
				break;
1254 1255 1256 1257
			default:
				self->errornumber = CONNECTION_BACKEND_CRAZY;
				self->errormsg = "Unexpected protocol character from backend (send_query)";
				CC_set_no_trans(self);
1258

1259
				mylog("send_query: error - %s\n", self->errormsg);
1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
				ReadyToReturn = TRUE;
				retres = NULL;
				break;
		}
		/*
		 *	There were no ReadyForQuery response before 6.4.
		 */
		if (before_64)
		{
			if (empty_reqs == 0 && (query_completed || tuples_return))
				break;
1271 1272
		}
	}
1273
	/*	
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1274
	 *	Break before being ready to return.
1275
	 */
Hiroshi Inoue's avatar
Hiroshi Inoue committed
1276
	if (!ReadyToReturn)
1277 1278 1279 1280 1281 1282 1283 1284
	{
		if (res && QR_get_aborted(res))
			retres = res;
		else if (tuples_return)
			retres = result_in;
		else
			retres = res;
	}
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306
	/*
	 *	set notice message to result_in.
	 */
	if (result_in && res && retres == result_in)
	{
		if (QR_command_successful(result_in))
			QR_set_status(result_in, QR_get_status(res));
		QR_set_notice(result_in, QR_get_notice(res));
	}
	/*
	 *	Cleanup garbage results before returning.
	 */
	if (res && retres != res)
		QR_Destructor(res);
	if (result_in && retres != result_in)
	{
		if (qi && qi->result_in)
			;
		else
			QR_Destructor(result_in);
	}
	return retres;
1307
}
1308

1309

1310
int
Bruce Momjian's avatar
Bruce Momjian committed
1311
CC_send_function(ConnectionClass *self, int fnid, void *result_buf, int *actual_result_len, int result_is_int, LO_ARG *args, int nargs)
1312
{
1313 1314 1315 1316
	char		id,
				c,
				done;
	SocketClass *sock = self->sock;
1317

1318 1319
	/* ERROR_MSG_LENGTH is sufficient */
	static char msgbuffer[ERROR_MSG_LENGTH + 1];
1320
	int			i;
1321 1322 1323

	mylog("send_function(): conn=%u, fnid=%d, result_is_int=%d, nargs=%d\n", self, fnid, result_is_int, nargs);

1324 1325
	if (SOCK_get_errcode(sock) != 0)
	{
1326 1327 1328 1329 1330 1331 1332
		self->errornumber = CONNECTION_COULD_NOT_SEND;
		self->errormsg = "Could not send function to backend";
		CC_set_no_trans(self);
		return FALSE;
	}

	SOCK_put_string(sock, "F ");
1333 1334
	if (SOCK_get_errcode(sock) != 0)
	{
1335 1336 1337 1338 1339 1340
		self->errornumber = CONNECTION_COULD_NOT_SEND;
		self->errormsg = "Could not send function to backend";
		CC_set_no_trans(self);
		return FALSE;
	}

1341 1342
	SOCK_put_int(sock, fnid, 4);
	SOCK_put_int(sock, nargs, 4);
1343

1344 1345 1346

	mylog("send_function: done sending function\n");

1347 1348
	for (i = 0; i < nargs; ++i)
	{
1349
		mylog("  arg[%d]: len = %d, isint = %d, integer = %d, ptr = %u\n", i, args[i].len, args[i].isint, args[i].u.integer, args[i].u.ptr);
1350 1351

		SOCK_put_int(sock, args[i].len, 4);
1352
		if (args[i].isint)
1353 1354 1355
			SOCK_put_int(sock, args[i].u.integer, 4);
		else
			SOCK_put_n_char(sock, (char *) args[i].u.ptr, args[i].len);
1356 1357


1358 1359 1360 1361 1362 1363 1364 1365
	}

	mylog("    done sending args\n");

	SOCK_flush_output(sock);
	mylog("  after flush output\n");

	done = FALSE;
1366 1367
	while (!done)
	{
1368 1369 1370
		id = SOCK_get_char(sock);
		mylog("   got id = %c\n", id);

1371 1372 1373 1374 1375
		switch (id)
		{
			case 'V':
				done = TRUE;
				break;			/* ok */
1376

1377 1378 1379 1380 1381
			case 'N':
				SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
				mylog("send_function(V): 'N' - %s\n", msgbuffer);
				/* continue reading */
				break;
1382

1383 1384 1385
			case 'E':
				SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
				self->errormsg = msgbuffer;
1386

1387 1388
				mylog("send_function(V): 'E' - %s\n", self->errormsg);
				qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
1389

1390
				return FALSE;
1391

1392 1393
			case 'Z':
				break;
1394

1395 1396 1397 1398
			default:
				self->errornumber = CONNECTION_BACKEND_CRAZY;
				self->errormsg = "Unexpected protocol character from backend (send_function, args)";
				CC_set_no_trans(self);
1399

1400 1401
				mylog("send_function: error - %s\n", self->errormsg);
				return FALSE;
1402 1403 1404 1405
		}
	}

	id = SOCK_get_char(sock);
1406 1407 1408 1409 1410 1411
	for (;;)
	{
		switch (id)
		{
			case 'G':			/* function returned properly */
				mylog("  got G!\n");
1412

1413 1414
				*actual_result_len = SOCK_get_int(sock, 4);
				mylog("  actual_result_len = %d\n", *actual_result_len);
1415

1416 1417 1418 1419
				if (result_is_int)
					*((int *) result_buf) = SOCK_get_int(sock, 4);
				else
					SOCK_get_n_char(sock, (char *) result_buf, *actual_result_len);
1420

1421
				mylog("  after get result\n");
1422

1423
				c = SOCK_get_char(sock);		/* get the last '0' */
1424

1425
				mylog("   after get 0\n");
1426

1427
				return TRUE;
1428

1429 1430 1431
			case 'E':
				SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
				self->errormsg = msgbuffer;
1432

1433 1434
				mylog("send_function(G): 'E' - %s\n", self->errormsg);
				qlog("ERROR from backend during send_function: '%s'\n", self->errormsg);
1435

1436
				return FALSE;
1437

1438 1439
			case 'N':
				SOCK_get_string(sock, msgbuffer, ERROR_MSG_LENGTH);
1440

1441 1442
				mylog("send_function(G): 'N' - %s\n", msgbuffer);
				qlog("NOTICE from backend during send_function: '%s'\n", msgbuffer);
1443

1444 1445
				continue;		/* dont return a result -- continue
								 * reading */
1446

1447 1448
			case '0':			/* empty result */
				return TRUE;
1449

1450 1451 1452 1453
			default:
				self->errornumber = CONNECTION_BACKEND_CRAZY;
				self->errormsg = "Unexpected protocol character from backend (send_function, result)";
				CC_set_no_trans(self);
1454

1455 1456
				mylog("send_function: error - %s\n", self->errormsg);
				return FALSE;
1457 1458 1459 1460
		}
	}
}

Byron Nikolaidis's avatar
Byron Nikolaidis committed
1461

1462
char
Bruce Momjian's avatar
Bruce Momjian committed
1463
CC_send_settings(ConnectionClass *self)
1464
{
1465 1466 1467
	/* char ini_query[MAX_MESSAGE_LEN]; */
	ConnInfo   *ci = &(self->connInfo);

1468
/* QResultClass *res; */
1469 1470 1471 1472 1473 1474 1475
	HSTMT		hstmt;
	StatementClass *stmt;
	RETCODE		result;
	char		status = TRUE;
	char	   *cs,
			   *ptr;
	static char *func = "CC_send_settings";
1476 1477 1478


	mylog("%s: entering...\n", func);
1479

1480 1481 1482 1483
/*
 *	This function must use the local odbc API functions since the odbc state
 *	has not transitioned to "connected" yet.
 */
1484

1485
	result = PGAPI_AllocStmt(self, &hstmt);
1486
	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
1487 1488 1489
		return FALSE;
	stmt = (StatementClass *) hstmt;

1490
	stmt->internal = TRUE;		/* ensure no BEGIN/COMMIT/ABORT stuff */
1491

1492
	/* Set the Datestyle to the format the driver expects it to be in */
1493
	result = PGAPI_ExecDirect(hstmt, "set DateStyle to 'ISO'", SQL_NTS);
1494
	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
1495 1496 1497
		status = FALSE;

	mylog("%s: result %d, status %d from set DateStyle\n", func, result, status);
1498

1499
	/* Disable genetic optimizer based on global flag */
1500
	if (ci->drivers.disable_optimizer)
1501
	{
1502
		result = PGAPI_ExecDirect(hstmt, "set geqo to 'OFF'", SQL_NTS);
1503
		if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
1504 1505 1506
			status = FALSE;

		mylog("%s: result %d, status %d from set geqo\n", func, result, status);
1507

1508
	}
1509

1510
	/* KSQO */
1511
	if (ci->drivers.ksqo)
1512
	{
1513
		result = PGAPI_ExecDirect(hstmt, "set ksqo to 'ON'", SQL_NTS);
1514
		if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
1515 1516 1517
			status = FALSE;

		mylog("%s: result %d, status %d from set ksqo\n", func, result, status);
1518

1519 1520
	}

1521
	/* Global settings */
1522
	if (ci->drivers.conn_settings[0] != '\0')
1523
	{
1524
		cs = strdup(ci->drivers.conn_settings);
1525
		ptr = strtok(cs, ";");
1526 1527
		while (ptr)
		{
1528
			result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS);
1529
			if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
1530 1531 1532 1533 1534 1535
				status = FALSE;

			mylog("%s: result %d, status %d from '%s'\n", func, result, status, ptr);

			ptr = strtok(NULL, ";");
		}
1536

1537 1538
		free(cs);
	}
1539 1540 1541 1542

	/* Per Datasource settings */
	if (ci->conn_settings[0] != '\0')
	{
1543 1544
		cs = strdup(ci->conn_settings);
		ptr = strtok(cs, ";");
1545 1546
		while (ptr)
		{
1547
			result = PGAPI_ExecDirect(hstmt, ptr, SQL_NTS);
1548
			if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
1549
				status = FALSE;
1550

1551
			mylog("%s: result %d, status %d from '%s'\n", func, result, status, ptr);
1552

1553
			ptr = strtok(NULL, ";");
1554 1555
		}

1556
		free(cs);
1557
	}
1558 1559


1560
	PGAPI_FreeStmt(hstmt, SQL_DROP);
1561 1562

	return status;
1563 1564
}

1565 1566 1567 1568 1569 1570

/*
 *	This function is just a hack to get the oid of our Large Object oid type.
 *	If a real Large Object oid type is made part of Postgres, this function
 *	will go away and the define 'PG_TYPE_LO' will be updated.
 */
1571
void
1572
CC_lookup_lo(ConnectionClass *self)
1573
{
1574 1575 1576 1577
	HSTMT		hstmt;
	StatementClass *stmt;
	RETCODE		result;
	static char *func = "CC_lookup_lo";
1578

1579
	mylog("%s: entering...\n", func);
1580

1581 1582 1583 1584
/*
 *	This function must use the local odbc API functions since the odbc state
 *	has not transitioned to "connected" yet.
 */
1585
	result = PGAPI_AllocStmt(self, &hstmt);
1586
	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
1587 1588 1589
		return;
	stmt = (StatementClass *) hstmt;

1590
	result = PGAPI_ExecDirect(hstmt, "select oid from pg_type where typname='" PG_TYPE_LO_NAME "'", SQL_NTS);
1591 1592
	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
	{
1593
		PGAPI_FreeStmt(hstmt, SQL_DROP);
1594 1595 1596
		return;
	}

1597
	result = PGAPI_Fetch(hstmt);
1598 1599
	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
	{
1600
		PGAPI_FreeStmt(hstmt, SQL_DROP);
1601 1602 1603
		return;
	}

1604
	result = PGAPI_GetData(hstmt, 1, SQL_C_SLONG, &self->lobj_type, sizeof(self->lobj_type), NULL);
1605 1606
	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
	{
1607
		PGAPI_FreeStmt(hstmt, SQL_DROP);
1608 1609 1610 1611 1612 1613
		return;
	}

	mylog("Got the large object oid: %d\n", self->lobj_type);
	qlog("    [ Large Object oid = %d ]\n", self->lobj_type);

1614
	result = PGAPI_FreeStmt(hstmt, SQL_DROP);
1615 1616
}

1617 1618 1619 1620 1621 1622

/*
 *	This function initializes the version of PostgreSQL from
 *	connInfo.protocol that we're connected to.
 *	h-inoue 01-2-2001
 */
1623
void
1624
CC_initialize_pg_version(ConnectionClass *self)
1625
{
1626 1627 1628
	strcpy(self->pg_version, self->connInfo.protocol);
	if (PROTOCOL_62(&self->connInfo))
	{
1629 1630 1631
		self->pg_version_number = (float) 6.2;
		self->pg_version_major = 6;
		self->pg_version_minor = 2;
1632 1633 1634
	}
	else if (PROTOCOL_63(&self->connInfo))
	{
1635 1636 1637
		self->pg_version_number = (float) 6.3;
		self->pg_version_major = 6;
		self->pg_version_minor = 3;
1638 1639 1640
	}
	else
	{
1641 1642 1643 1644
		self->pg_version_number = (float) 6.4;
		self->pg_version_major = 6;
		self->pg_version_minor = 4;
	}
1645
}
1646

1647 1648 1649 1650 1651 1652

/*
 *	This function gets the version of PostgreSQL that we're connected to.
 *	This is used to return the correct info in SQLGetInfo
 *	DJP - 25-1-2001
 */
1653
void
1654
CC_lookup_pg_version(ConnectionClass *self)
1655
{
1656 1657 1658 1659 1660 1661 1662
	HSTMT		hstmt;
	StatementClass *stmt;
	RETCODE		result;
	char		szVersion[32];
	int			major,
				minor;
	static char *func = "CC_lookup_pg_version";
1663

1664
	mylog("%s: entering...\n", func);
1665

1666 1667 1668 1669
/*
 *	This function must use the local odbc API functions since the odbc state
 *	has not transitioned to "connected" yet.
 */
1670
	result = PGAPI_AllocStmt(self, &hstmt);
1671
	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
1672 1673 1674
		return;
	stmt = (StatementClass *) hstmt;

1675
	/* get the server's version if possible	 */
1676
	result = PGAPI_ExecDirect(hstmt, "select version()", SQL_NTS);
1677 1678
	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
	{
1679
		PGAPI_FreeStmt(hstmt, SQL_DROP);
1680 1681 1682
		return;
	}

1683
	result = PGAPI_Fetch(hstmt);
1684 1685
	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
	{
1686
		PGAPI_FreeStmt(hstmt, SQL_DROP);
1687 1688 1689
		return;
	}

1690
	result = PGAPI_GetData(hstmt, 1, SQL_C_CHAR, self->pg_version, MAX_INFO_STRING, NULL);
1691 1692
	if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
	{
1693
		PGAPI_FreeStmt(hstmt, SQL_DROP);
1694 1695 1696
		return;
	}

1697
	/*
1698 1699
	 * Extract the Major and Minor numbers from the string. This assumes
	 * the string starts 'Postgresql X.X'
1700
	 */
1701
	strcpy(szVersion, "0.0");
1702 1703
	if (sscanf(self->pg_version, "%*s %d.%d", &major, &minor) >= 2)
	{
1704 1705 1706 1707
		sprintf(szVersion, "%d.%d", major, minor);
		self->pg_version_major = major;
		self->pg_version_minor = minor;
	}
1708 1709 1710 1711 1712 1713 1714
	self->pg_version_number = (float) atof(szVersion);

	mylog("Got the PostgreSQL version string: '%s'\n", self->pg_version);
	mylog("Extracted PostgreSQL version number: '%1.1f'\n", self->pg_version_number);
	qlog("    [ PostgreSQL version string = '%s' ]\n", self->pg_version);
	qlog("    [ PostgreSQL version number = '%1.1f' ]\n", self->pg_version_number);

1715
	result = PGAPI_FreeStmt(hstmt, SQL_DROP);
1716 1717
}

1718

Byron Nikolaidis's avatar
Byron Nikolaidis committed
1719
void
Bruce Momjian's avatar
Bruce Momjian committed
1720
CC_log_error(char *func, char *desc, ConnectionClass *self)
Byron Nikolaidis's avatar
Byron Nikolaidis committed
1721
{
1722 1723 1724 1725
#ifdef PRN_NULLCHECK
#define nullcheck(a) (a ? a : "(NULL)")
#endif

1726 1727 1728 1729
	if (self)
	{
		qlog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg));
		mylog("CONN ERROR: func=%s, desc='%s', errnum=%d, errmsg='%s'\n", func, desc, self->errornumber, nullcheck(self->errormsg));
Byron Nikolaidis's avatar
Byron Nikolaidis committed
1730 1731 1732 1733 1734
		qlog("            ------------------------------------------------------------\n");
		qlog("            henv=%u, conn=%u, status=%u, num_stmts=%d\n", self->henv, self, self->status, self->num_stmts);
		qlog("            sock=%u, stmts=%u, lobj_type=%d\n", self->sock, self->stmts, self->lobj_type);

		qlog("            ---------------- Socket Info -------------------------------\n");
1735 1736 1737 1738 1739 1740 1741
		if (self->sock)
		{
			SocketClass *sock = self->sock;

			qlog("            socket=%d, reverse=%d, errornumber=%d, errormsg='%s'\n", sock->socket, sock->reverse, sock->errornumber, nullcheck(sock->errormsg));
			qlog("            buffer_in=%u, buffer_out=%u\n", sock->buffer_in, sock->buffer_out);
			qlog("            buffer_filled_in=%d, buffer_filled_out=%d, buffer_read_in=%d\n", sock->buffer_filled_in, sock->buffer_filled_out, sock->buffer_read_in);
Byron Nikolaidis's avatar
Byron Nikolaidis committed
1742 1743 1744 1745
		}
	}
	else
		qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
1746
#undef PRN_NULLCHECK
Byron Nikolaidis's avatar
Byron Nikolaidis committed
1747
}
1748 1749 1750

int     CC_get_max_query_len(const ConnectionClass *conn)
{
1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761
		int     value;
		/* Long Queries in 7.0+ */
		if (PG_VERSION_GE(conn, 7.0))
				value = 0 /* MAX_STATEMENT_LEN */;
		/* Prior to 7.0 we used 2*BLCKSZ */
		else if (PG_VERSION_GE(conn, 6.5))
				value = (2 * BLCKSZ);
		else
				/* Prior to 6.5 we used BLCKSZ */
				value = BLCKSZ;
		return value;
1762
}