diff --git a/src/interfaces/odbc/connection.c b/src/interfaces/odbc/connection.c
index 9916042d4b410b8d0f763dc3692ed81eb3fff36d..c853cdb79baccbed89e78ccb27b02f725bbf8b41 100644
--- a/src/interfaces/odbc/connection.c
+++ b/src/interfaces/odbc/connection.c
@@ -915,6 +915,7 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
 	char		swallow;
 	int			id;
 	SocketClass *sock = self->sock;
+	int		maxlen;
 
 	/* ERROR_MSG_LENGTH is suffcient */
 	static char msgbuffer[ERROR_MSG_LENGTH + 1];
@@ -926,7 +927,8 @@ CC_send_query(ConnectionClass *self, char *query, QueryInfo *qi)
 	qlog("conn=%u, query='%s'\n", self, query);
 
 	/* Indicate that we are sending a query to the backend */
-	if (strlen(query) > MAX_MESSAGE_LEN - 2)
+	maxlen = CC_get_max_query_len(self);
+	if (maxlen > 0 && maxlen < (int) strlen(query) + 1)
 	{
 		self->errornumber = CONNECTION_MSG_TOO_LONG;
 		self->errormsg = "Query string is too long";
@@ -1643,3 +1645,18 @@ CC_log_error(char *func, char *desc, ConnectionClass *self)
 		qlog("INVALID CONNECTION HANDLE ERROR: func=%s, desc='%s'\n", func, desc);
 #undef PRN_NULLCHECK
 }
+
+int     CC_get_max_query_len(const ConnectionClass *conn)
+{
+        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;
+}
diff --git a/src/interfaces/odbc/connection.h b/src/interfaces/odbc/connection.h
index 91047caeb1d182be692f4b82e2a8af3db5dc1391..034ef137d187cd8420067264629856977644d48f 100644
--- a/src/interfaces/odbc/connection.h
+++ b/src/interfaces/odbc/connection.h
@@ -307,6 +307,6 @@ void		CC_lookup_lo(ConnectionClass *conn);
 void		CC_lookup_pg_version(ConnectionClass *conn);
 void		CC_initialize_pg_version(ConnectionClass *conn);
 void		CC_log_error(char *func, char *desc, ConnectionClass *self);
-
+int		CC_get_max_query_len(const  ConnectionClass *self);
 
 #endif
diff --git a/src/interfaces/odbc/convert.c b/src/interfaces/odbc/convert.c
index 9147db3d2aa5700efb5310fec630e091367dd1ff..62fb91bb1b970e3611d4b5cdb3a71c8f0de6dfff 100644
--- a/src/interfaces/odbc/convert.c
+++ b/src/interfaces/odbc/convert.c
@@ -1,5 +1,5 @@
 /*-------
- * Module:		   convert.c
+ * Module:               convert.c
  *
  * Description:    This module contains routines related to
  *				   converting parameters and columns into requested data types.
@@ -190,8 +190,12 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
 	int			bind_row = stmt->bind_row;
 	int			bind_size = stmt->options.bind_size;
 	int			result = COPY_OK;
-	char		tempBuf[TEXT_FIELD_SIZE + 5];
+	BOOL		changed;
+	static		char *tempBuf= NULL;
+	static		unsigned int tempBuflen = 0;
 
+	if (!tempBuf)
+		tempBuflen = 0;
 	/*---------
 	 *	rgbValueOffset is *ONLY* for character and binary data.
 	 *	pcbValueOffset is for computing any pcbValue location
@@ -437,23 +441,62 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
 				break;
 
 			default:
-				/* convert linefeeds to carriage-return/linefeed */
-				len = convert_linefeeds(value, tempBuf, sizeof(tempBuf));
-				ptr = tempBuf;
+				if (stmt->current_col >= 0 && stmt->bindings[stmt->current_col].data_left == -2)
+					stmt->bindings[stmt->current_col].data_left = (cbValueMax > 0) ? 0 : -1; /* This seems to be needed for ADO ? */
+				if (stmt->current_col < 0 || stmt->bindings[stmt->current_col].data_left < 0)
+				{
+					/* convert linefeeds to carriage-return/linefeed */
+					len = convert_linefeeds(value, NULL, 0, &changed);
+					if (cbValueMax == 0) /* just returns length info */
+					{
+						result = COPY_RESULT_TRUNCATED;
+						break;
+					}
+					if (changed || len >= cbValueMax)
+					{
+						if (len >= (int) tempBuflen)
+						{
+							tempBuf = realloc(tempBuf, len + 1);
+							tempBuflen = len + 1;
+						}
+						convert_linefeeds(value, tempBuf, tempBuflen, &changed);
+						ptr = tempBuf;
+					}
+					else
+					{
+						if (tempBuf)
+						{
+							free(tempBuf);
+							tempBuf = NULL;
+						}
+						ptr = value;
+					}
+				}
+				else
+					ptr = tempBuf;
 
 				mylog("DEFAULT: len = %d, ptr = '%s'\n", len, ptr);
 
 				if (stmt->current_col >= 0)
 				{
 					if (stmt->bindings[stmt->current_col].data_left == 0)
+					{
+						if (tempBuf)
+						{
+							free(tempBuf);
+							tempBuf = NULL;
+						}
+						/* The following seems to be needed for ADO ? */
+						stmt->bindings[stmt->current_col].data_left = -2;
 						return COPY_NO_DATA_FOUND;
+					}
 					else if (stmt->bindings[stmt->current_col].data_left > 0)
 					{
-						ptr += len - stmt->bindings[stmt->current_col].data_left;
+						ptr += strlen(ptr) - stmt->bindings[stmt->current_col].data_left;
 						len = stmt->bindings[stmt->current_col].data_left;
 					}
 					else
-						stmt->bindings[stmt->current_col].data_left = strlen(ptr);
+						stmt->bindings[stmt->current_col].data_left = len;
 				}
 
 				if (cbValueMax > 0)
@@ -461,7 +504,8 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
 					copy_len = (len >= cbValueMax) ? cbValueMax - 1 : len;
 
 					/* Copy the data */
-					strncpy_null(rgbValueBindRow, ptr, copy_len + 1);
+					memcpy(rgbValueBindRow, ptr, copy_len);
+					rgbValueBindRow[copy_len] = '\0';
 
 					/* Adjust data_left for next time */
 					if (stmt->current_col >= 0)
@@ -472,8 +516,16 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
 				 * Finally, check for truncation so that proper status can
 				 * be returned
 				 */
-				if (len >= cbValueMax)
+				if (cbValueMax > 0 && len >= cbValueMax)
 					result = COPY_RESULT_TRUNCATED;
+				else
+				{
+					if (tempBuf)
+					{
+						free(tempBuf);
+						tempBuf = NULL;
+					}
+				}
 
 
 				mylog("    SQL_C_CHAR, default: len = %d, cbValueMax = %d, rgbValueBindRow = '%s'\n", len, cbValueMax, rgbValueBindRow);
@@ -629,14 +681,23 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
 				/* truncate if necessary */
 				/* convert octal escapes to bytes */
 
-				len = convert_from_pgbinary(value, tempBuf, sizeof(tempBuf));
+				if (len = strlen(value), len >= (int) tempBuflen)
+				{
+					tempBuf = realloc(tempBuf, len + 1);
+					tempBuflen = len + 1;
+				}
+				len = convert_from_pgbinary(value, tempBuf, tempBuflen);
 				ptr = tempBuf;
 
 				if (stmt->current_col >= 0)
 				{
 					/* No more data left for this column */
 					if (stmt->bindings[stmt->current_col].data_left == 0)
+					{
+						free(tempBuf);
+						tempBuf = NULL;
 						return COPY_NO_DATA_FOUND;
+					}
 
 					/*
 					 * Second (or more) call to SQLGetData so move the
@@ -673,6 +734,11 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
 				if (len > cbValueMax)
 					result = COPY_RESULT_TRUNCATED;
 
+				if (tempBuf)
+				{
+					free(tempBuf);
+					tempBuf = NULL;
+				}
 				mylog("SQL_C_BINARY: len = %d, copy_len = %d\n", len, copy_len);
 				break;
 
@@ -690,10 +756,181 @@ copy_and_convert_field(StatementClass *stmt, Int4 field_type, void *value, Int2
 }
 
 
+/*--------------------------------------------------------------------
+ *	Functions/Macros to get rid of query size limit.
+ *
+ *	I always used the follwoing macros to convert from
+ *	old_statement to new_statement.	 Please improve it
+ *	if you have a better way.	Hiroshi 2001/05/22
+ *--------------------------------------------------------------------
+ */
+#define	INIT_MIN_ALLOC	4096
+static int enlarge_statement(StatementClass *stmt, unsigned int newsize)
+{
+	unsigned int	newalsize = INIT_MIN_ALLOC;
+	static char *func = "enlarge_statement";
+
+	if (stmt->stmt_size_limit > 0 && stmt->stmt_size_limit < (int) newsize)
+	{
+		stmt->errormsg = "Query buffer overflow in copy_statement_with_parameters";
+		stmt->errornumber = STMT_EXEC_ERROR;
+		SC_log_error(func, "", stmt);
+		return -1;
+	}
+	while (newalsize <= newsize)
+		newalsize *= 2;
+	if (!(stmt->stmt_with_params = realloc(stmt->stmt_with_params, newalsize)))
+	{
+		stmt->errormsg = "Query buffer allocate error in copy_statement_with_parameters";
+		stmt->errornumber = STMT_EXEC_ERROR;
+		SC_log_error(func, "", stmt);
+		return 0;
+	}
+	return newalsize;
+}
+
+/*----------
+ *	Enlarge stmt_with_params if necessary.
+ *----------
+ */
+#define	ENLARGE_NEWSTATEMENT(newpos) \
+	if (newpos >= new_stsize) \
+	{ \
+		if ((new_stsize = enlarge_statement(stmt, newpos)) <= 0) \
+			return SQL_ERROR; \
+		new_statement = stmt->stmt_with_params; \
+	}
+/*----------
+ *	Initialize stmt_with_params, new_statement etc.
+ *----------
+ */
+#define	CVT_INIT(size) \
+{ \
+	if (stmt->stmt_with_params) \
+		free(stmt->stmt_with_params); \
+	if (stmt->stmt_size_limit > 0) \
+		new_stsize = stmt->stmt_size_limit; \
+	else \
+	{ \
+		new_stsize = INIT_MIN_ALLOC; \
+		while (new_stsize <= size) \
+			new_stsize *= 2; \
+	} \
+	new_statement = malloc(new_stsize); \
+	stmt->stmt_with_params = new_statement; \
+	npos = 0; \
+	new_statement[0] = '\0'; \
+}
+/*----------
+ *	Terminate the stmt_with_params string with NULL.
+ *----------
+ */
+#define	CVT_TERMINATE { new_statement[npos] = '\0'; }
+
+/*----------
+ *	Append a data.
+ *----------
+ */
+#define	CVT_APPEND_DATA(s, len) \
+{ \
+	unsigned int	newpos = npos + len; \
+	ENLARGE_NEWSTATEMENT(newpos) \
+	memcpy(&new_statement[npos], s, len); \
+	npos = newpos; \
+	new_statement[npos] = '\0'; \
+}
+/*----------
+ *	Append a string.
+ *----------
+ */
+#define	CVT_APPEND_STR(s) \
+{ \
+	unsigned int len = strlen(s); \
+	CVT_APPEND_DATA(s, len); \
+}
+/*----------
+ *	Append a char.	
+ *----------
+ */
+#define	CVT_APPEND_CHAR(c) \
+{ \
+	ENLARGE_NEWSTATEMENT(npos + 1); \
+	new_statement[npos++] = c; \
+}
+/*----------
+ *	Append a binary data.
+ *	Newly reqeuired size may be overestimated currently. 
+ *----------
+ */
+#define	CVT_APPEND_BINARY(buf, used) \
+{ \
+	unsigned int	newlimit = npos + 5 * used; \
+	ENLARGE_NEWSTATEMENT(newlimit); \
+	npos += convert_to_pgbinary(buf, &new_statement[npos], used); \
+}
+/*----------
+ *
+ *----------
+ */
+#define	CVT_SPECIAL_CHARS(buf, used) \
+{ \
+	int	cnvlen = convert_special_chars(buf, NULL, used); \
+	unsigned int	newlimit = npos + cnvlen; \
+\
+	ENLARGE_NEWSTATEMENT(newlimit); \
+	convert_special_chars(buf, &new_statement[npos], used); \
+	npos += cnvlen; \
+}
+
+/*----------
+ *	Check if the statement is	
+ *	SELECT ... INTO table FROM .....
+ *	This isn't really a strict check but ...
+ *---------- 
+ */
+static BOOL
+into_table_from(const char *stmt)
+{
+	if (strnicmp(stmt, "into", 4))
+		return FALSE;
+	stmt += 4;
+	if (!isspace((unsigned char) *stmt))
+		return FALSE;
+	while (isspace((unsigned char) *(++stmt)));
+	switch (*stmt)
+	{
+		case '\0':
+		case ',':
+		case '\'':
+			return FALSE;
+		case '\"': /* double quoted table name ? */
+			do
+			{
+				do
+				{
+					 while (*(++stmt) != '\"' && *stmt);
+				}
+				while (*stmt && *(++stmt) == '\"');
+				while (*stmt && !isspace((unsigned char) *stmt) && *stmt != '\"') stmt++;
+			}
+			while (*stmt == '\"');
+			break;
+		default:
+			while (!isspace((unsigned char) *(++stmt)));
+			break;
+	}
+	if (! *stmt)
+		return FALSE;
+	while (isspace((unsigned char) *(++stmt)));
+	if (strnicmp(stmt, "from", 4))
+		return FALSE;
+	return isspace((unsigned char) stmt[4]);
+}
+
 /*
  *	This function inserts parameters into an SQL statements.
  *	It will also modify a SELECT statement for use with declare/fetch cursors.
- *	This function no longer does any dynamic memory allocation!
+ *	This function does a dynamic memory allocation to get rid of query siz elimit!
  */
 int
 copy_statement_with_parameters(StatementClass *stmt)
@@ -704,22 +941,25 @@ copy_statement_with_parameters(StatementClass *stmt)
 				oldstmtlen;
 	char		param_string[128],
 				tmp[256],
-				cbuf[TEXT_FIELD_SIZE + 5];
+				cbuf[PG_NUMERIC_MAX_PRECISION * 2]; /* seems big enough to handle the data in this function */
 	int			param_number;
 	Int2		param_ctype,
 				param_sqltype;
 	char	   *old_statement = stmt->statement;
 	char	   *new_statement = stmt->stmt_with_params;
+	unsigned int	new_stsize = 0;
 	SIMPLE_TIME st;
 	time_t		t = time(NULL);
 	struct tm  *tim;
 	SDWORD		used;
 	char	   *buffer,
 			   *buf;
-	char		in_quote = FALSE;
+	BOOL		in_quote = FALSE, in_dquote = FALSE, in_escape = FALSE;
 	Oid			lobj_oid;
 	int			lobj_fd,
 				retval;
+	BOOL	check_select_into = FALSE; /* select into check */
+	unsigned int	declare_pos;
 
 
 	if (!old_statement)
@@ -740,43 +980,66 @@ copy_statement_with_parameters(StatementClass *stmt)
 	if (stmt->cursor_name[0] == '\0')
 		sprintf(stmt->cursor_name, "SQL_CUR%p", stmt);
 
+	oldstmtlen = strlen(old_statement);
+	CVT_INIT(oldstmtlen);
 	/* For selects, prepend a declare cursor to the statement */
 	if (stmt->statement_type == STMT_TYPE_SELECT && globals.use_declarefetch)
 	{
 		sprintf(new_statement, "declare %s cursor for ", stmt->cursor_name);
 		npos = strlen(new_statement);
-	}
-	else
-	{
-		new_statement[0] = '0';
-		npos = 0;
+		check_select_into = TRUE;
+		declare_pos = npos;
 	}
 
 	param_number = -1;
 
-	oldstmtlen = strlen(old_statement);
 #ifdef MULTIBYTE
 	multibyte_init();
 #endif
 
 	for (opos = 0; opos < oldstmtlen; opos++)
 	{
+#ifdef MULTIBYTE
+		if (multibyte_char_check(old_statement[opos]) != 0)
+		{
+			CVT_APPEND_CHAR(old_statement[opos]);
+			continue;
+		}
+		/*
+		 *	From here we are guaranteed to handle a
+		 *	1-byte character.
+		 */
+#endif
 		/* Squeeze carriage-return/linefeed pairs to linefeed only */
 		if (old_statement[opos] == '\r' && opos + 1 < oldstmtlen &&
 			old_statement[opos + 1] == '\n')
 			continue;
 
+		else if (in_escape) /* escape check */
+		{
+			in_escape = FALSE;
+			CVT_APPEND_CHAR(old_statement[opos]);
+			continue;
+		}	
+		else if (in_quote || in_dquote) /* quote/double quote check */
+		{
+			if (old_statement[opos] == '\'' && in_quote)
+				in_quote = FALSE;
+			else if (old_statement[opos] == '\"' && in_dquote)
+				in_dquote = FALSE;
+			CVT_APPEND_CHAR(old_statement[opos]);
+			continue;	
+		}
+		/*
+		 *	From here we are guranteed to be in neither
+		 *	an escape nor a quote nor a double quote.
+		 */
 		/*
 		 * Handle literals (date, time, timestamp) and ODBC scalar
 		 * functions
 		 */
-#ifdef MULTIBYTE
-		else if (multibyte_char_check(old_statement[opos]) == 0 && old_statement[opos] == '{')
-		{
-#else
 		else if (old_statement[opos] == '{')
 		{
-#endif
 			char	   *esc;
 			char	   *begin = &old_statement[opos + 1];
 
@@ -796,13 +1059,12 @@ copy_statement_with_parameters(StatementClass *stmt)
 			esc = convert_escape(begin);
 			if (esc)
 			{
-				memcpy(&new_statement[npos], esc, strlen(esc));
-				npos += strlen(esc);
+				CVT_APPEND_STR(esc);
 			}
 			else
 			{					/* it's not a valid literal so just copy */
 				*end = '}';
-				new_statement[npos++] = old_statement[opos];
+				CVT_APPEND_CHAR(old_statement[opos]);
 				continue;
 			}
 
@@ -816,14 +1078,26 @@ copy_statement_with_parameters(StatementClass *stmt)
 		 * so. All the queries I've seen expect the driver to put quotes
 		 * if needed.
 		 */
-		else if (old_statement[opos] == '?' && !in_quote)
+		else if (old_statement[opos] == '?')
 			;					/* ok */
 		else
 		{
 			if (old_statement[opos] == '\'')
-				in_quote = (in_quote ? FALSE : TRUE);
-
-			new_statement[npos++] = old_statement[opos];
+				in_quote = TRUE;
+			else if (old_statement[opos] == '\\')
+				in_escape = TRUE;
+			else if (old_statement[opos] == '\"')
+				in_dquote = TRUE;
+			else if (check_select_into && /* select into check */
+    				 opos > 0 &&
+    				 isspace((unsigned char) old_statement[opos - 1]) &&
+    				 into_table_from(&old_statement[opos]))
+			{
+				stmt->statement_type = STMT_TYPE_CREATE;
+				memmove(new_statement, new_statement + declare_pos, npos - declare_pos);
+				npos -= declare_pos;
+			}
+			CVT_APPEND_CHAR(old_statement[opos]);
 			continue;
 		}
 
@@ -836,14 +1110,13 @@ copy_statement_with_parameters(StatementClass *stmt)
 		{
 			if (stmt->pre_executing)
 			{
-				strcpy(&new_statement[npos], "NULL");
-				npos += 4;
+				CVT_APPEND_STR("NULL");
 				stmt->inaccurate_result = TRUE;
 				continue;
 			}
 			else
 			{
-				new_statement[npos++] = '?';
+				CVT_APPEND_CHAR('?');
 				continue;
 			}
 		}
@@ -863,8 +1136,7 @@ copy_statement_with_parameters(StatementClass *stmt)
 		/* Handle NULL parameter data */
 		if (used == SQL_NULL_DATA)
 		{
-			strcpy(&new_statement[npos], "NULL");
-			npos += 4;
+			CVT_APPEND_STR("NULL");
 			continue;
 		}
 
@@ -876,14 +1148,13 @@ copy_statement_with_parameters(StatementClass *stmt)
 		{
 			if (stmt->pre_executing)
 			{
-				strcpy(&new_statement[npos], "NULL");
-				npos += 4;
+				CVT_APPEND_STR("NULL");
 				stmt->inaccurate_result = TRUE;
 				continue;
 			}
 			else
 			{
-				new_statement[npos++] = '?';
+				CVT_APPEND_CHAR('?');
 				continue;
 			}
 		}
@@ -1002,7 +1273,7 @@ copy_statement_with_parameters(StatementClass *stmt)
 				/* error */
 				stmt->errormsg = "Unrecognized C_parameter type in copy_statement_with_parameters";
 				stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR;
-				new_statement[npos] = '\0';		/* just in case */
+				CVT_TERMINATE	/* just in case */
 				SC_log_error(func, "", stmt);
 				return SQL_ERROR;
 		}
@@ -1018,20 +1289,18 @@ copy_statement_with_parameters(StatementClass *stmt)
 			case SQL_VARCHAR:
 			case SQL_LONGVARCHAR:
 
-				new_statement[npos++] = '\'';	/* Open Quote */
+				CVT_APPEND_CHAR('\'');	/* Open Quote */
 
 				/* it was a SQL_C_CHAR */
 				if (buf)
 				{
-					convert_special_chars(buf, &new_statement[npos], used);
-					npos += strlen(&new_statement[npos]);
+					CVT_SPECIAL_CHARS(buf, used);
 				}
 
 				/* it was a numeric type */
 				else if (param_string[0] != '\0')
 				{
-					strcpy(&new_statement[npos], param_string);
-					npos += strlen(param_string);
+					CVT_APPEND_STR(param_string);
 				}
 
 				/* it was date,time,timestamp -- use m,d,y,hh,mm,ss */
@@ -1040,11 +1309,10 @@ copy_statement_with_parameters(StatementClass *stmt)
 					sprintf(tmp, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d",
 							st.y, st.m, st.d, st.hh, st.mm, st.ss);
 
-					strcpy(&new_statement[npos], tmp);
-					npos += strlen(tmp);
+					CVT_APPEND_STR(tmp);
 				}
 
-				new_statement[npos++] = '\'';	/* Close Quote */
+				CVT_APPEND_CHAR('\'');	/* Close Quote */
 
 				break;
 
@@ -1057,8 +1325,7 @@ copy_statement_with_parameters(StatementClass *stmt)
 
 				sprintf(tmp, "'%.4d-%.2d-%.2d'", st.y, st.m, st.d);
 
-				strcpy(&new_statement[npos], tmp);
-				npos += strlen(tmp);
+				CVT_APPEND_STR(tmp);
 				break;
 
 			case SQL_TIME:
@@ -1070,8 +1337,7 @@ copy_statement_with_parameters(StatementClass *stmt)
 
 				sprintf(tmp, "'%.2d:%.2d:%.2d'", st.hh, st.mm, st.ss);
 
-				strcpy(&new_statement[npos], tmp);
-				npos += strlen(tmp);
+				CVT_APPEND_STR(tmp);
 				break;
 
 			case SQL_TIMESTAMP:
@@ -1085,21 +1351,20 @@ copy_statement_with_parameters(StatementClass *stmt)
 				sprintf(tmp, "'%.4d-%.2d-%.2d %.2d:%.2d:%.2d'",
 						st.y, st.m, st.d, st.hh, st.mm, st.ss);
 
-				strcpy(&new_statement[npos], tmp);
-				npos += strlen(tmp);
+				CVT_APPEND_STR(tmp);
 
 				break;
 
 			case SQL_BINARY:
 			case SQL_VARBINARY:/* non-ascii characters should be
 								 * converted to octal */
-				new_statement[npos++] = '\'';	/* Open Quote */
+				CVT_APPEND_CHAR('\'');	/* Open Quote */
 
 				mylog("SQL_VARBINARY: about to call convert_to_pgbinary, used = %d\n", used);
 
-				npos += convert_to_pgbinary(buf, &new_statement[npos], used);
+				CVT_APPEND_BINARY(buf, used);
 
-				new_statement[npos++] = '\'';	/* Close Quote */
+				CVT_APPEND_CHAR('\'');	/* Close Quote */
 
 				break;
 
@@ -1194,8 +1459,7 @@ copy_statement_with_parameters(StatementClass *stmt)
 				 * the large object
 				 */
 				sprintf(param_string, "'%d'", lobj_oid);
-				strcpy(&new_statement[npos], param_string);
-				npos += strlen(param_string);
+				CVT_APPEND_STR(param_string);
 
 				break;
 
@@ -1209,16 +1473,14 @@ copy_statement_with_parameters(StatementClass *stmt)
 				if (buf)
 					my_strcpy(param_string, sizeof(param_string), buf, used);
 				sprintf(tmp, "'%s'::float4", param_string);
-				strcpy(&new_statement[npos], tmp);
-				npos += strlen(tmp);
+				CVT_APPEND_STR(tmp);
 				break;
 			case SQL_FLOAT:
 			case SQL_DOUBLE:
 				if (buf)
 					my_strcpy(param_string, sizeof(param_string), buf, used);
 				sprintf(tmp, "'%s'::float8", param_string);
-				strcpy(&new_statement[npos], tmp);
-				npos += strlen(tmp);
+				CVT_APPEND_STR(tmp);
 				break;
 			case SQL_NUMERIC:
 				if (buf)
@@ -1231,33 +1493,30 @@ copy_statement_with_parameters(StatementClass *stmt)
 				}
 				else
 					sprintf(cbuf, "'%s'::numeric", param_string);
-				my_strcpy(&new_statement[npos], sizeof(stmt->stmt_with_params) - npos - 1, cbuf, strlen(cbuf));
-				npos += strlen(&new_statement[npos]);
+				CVT_APPEND_STR(cbuf);
 				break;
 			default:			/* a numeric type or SQL_BIT */
 				if (param_sqltype == SQL_BIT)
-					new_statement[npos++] = '\'';		/* Open Quote */
+					CVT_APPEND_CHAR('\'');		/* Open Quote */
 
 				if (buf)
 				{
-					my_strcpy(&new_statement[npos], sizeof(stmt->stmt_with_params) - npos, buf, used);
-					npos += strlen(&new_statement[npos]);
+					CVT_APPEND_DATA(buf, used);
 				}
 				else
 				{
-					strcpy(&new_statement[npos], param_string);
-					npos += strlen(param_string);
+					CVT_APPEND_STR(param_string);
 				}
 
 				if (param_sqltype == SQL_BIT)
-					new_statement[npos++] = '\'';		/* Close Quote */
+					CVT_APPEND_CHAR('\'');		/* Close Quote */
 
 				break;
 		}
 	}							/* end, for */
 
 	/* make sure new_statement is always null-terminated */
-	new_statement[npos] = '\0';
+	CVT_TERMINATE
 
 	if (stmt->hdbc->DriverToDataSource != NULL)
 	{
@@ -1458,29 +1717,47 @@ parse_datetime(char *buf, SIMPLE_TIME *st)
 
 /*	Change linefeed to carriage-return/linefeed */
 int
-convert_linefeeds(char *si, char *dst, size_t max)
+convert_linefeeds(const char *si, char *dst, size_t max, BOOL *changed)
 {
 	size_t		i = 0,
 				out = 0;
 
-	for (i = 0; i < strlen(si) && out < max - 1; i++)
+	if (max == 0)
+		max = 0xffffffff;
+	*changed = FALSE;
+	for (i = 0; si[i] && out < max - 1; i++)
 	{
 		if (si[i] == '\n')
 		{
 			/* Only add the carriage-return if needed */
 			if (i > 0 && si[i - 1] == '\r')
 			{
-				dst[out++] = si[i];
+				if (dst)
+					dst[out++] = si[i];
+				else
+					out++;
 				continue;
 			}
+			*changed = TRUE;
 
-			dst[out++] = '\r';
-			dst[out++] = '\n';
+			if (dst)
+			{
+				dst[out++] = '\r';
+				dst[out++] = '\n';
+			}
+			else
+				out += 2;
 		}
 		else
-			dst[out++] = si[i];
+		{
+			if (dst)
+				dst[out++] = si[i];
+			else
+				out++;
+		}
 	}
-	dst[out] = '\0';
+	if (dst)
+		dst[out] = '\0';
 	return out;
 }
 
@@ -1489,45 +1766,51 @@ convert_linefeeds(char *si, char *dst, size_t max)
  *	Change carriage-return/linefeed to just linefeed
  *	Plus, escape any special characters.
  */
-char *
+int
 convert_special_chars(char *si, char *dst, int used)
 {
 	size_t		i = 0,
 				out = 0,
 				max;
-	static char sout[TEXT_FIELD_SIZE + 5];
-	char	   *p;
-
-	if (dst)
-		p = dst;
-	else
-		p = sout;
+	char	   *p = NULL;
 
-	p[0] = '\0';
 
 	if (used == SQL_NTS)
 		max = strlen(si);
 	else
 		max = used;
+	if (dst)
+	{
+		p = dst;
+		p[0] = '\0';
+	}
 #ifdef MULTIBYTE
 	multibyte_init();
 #endif
 
 	for (i = 0; i < max; i++)
 	{
-		if (si[i] == '\r' && i + 1 < strlen(si) && si[i + 1] == '\n')
+		if (si[i] == '\r' && si[i + 1] == '\n')
 			continue;
 #ifdef MULTIBYTE
 		else if (multibyte_char_check(si[i]) == 0 && (si[i] == '\'' || si[i] == '\\'))
 #else
 		else if (si[i] == '\'' || si[i] == '\\')
 #endif
-			p[out++] = '\\';
-
-		p[out++] = si[i];
+		{
+			if (p)
+				p[out++] = '\\';
+			else
+				out++;
+		}
+		if (p)
+			p[out++] = si[i];
+		else
+			out++;
 	}
-	p[out] = '\0';
-	return p;
+	if (p)
+		p[out] = '\0';
+	return out;
 }
 
 
@@ -1583,11 +1866,11 @@ conv_from_hex(unsigned char *s)
 int
 convert_from_pgbinary(unsigned char *value, unsigned char *rgbValue, int cbValueMax)
 {
-	size_t		i;
+	size_t		i, ilen = strlen(value);
 	int			o = 0;
 
 
-	for (i = 0; i < strlen(value);)
+	for (i = 0; i < ilen;)
 	{
 		if (value[i] == '\\')
 		{
@@ -1654,10 +1937,10 @@ convert_to_pgbinary(unsigned char *in, char *out, int len)
 void
 encode(char *in, char *out)
 {
-	unsigned int i,
+	unsigned int i, ilen = strlen(in),
 				o = 0;
 
-	for (i = 0; i < strlen(in); i++)
+	for (i = 0; i < ilen; i++)
 	{
 		if (in[i] == '+')
 		{
@@ -1681,10 +1964,10 @@ encode(char *in, char *out)
 void
 decode(char *in, char *out)
 {
-	unsigned int i,
+	unsigned int i, ilen = strlen(in),
 				o = 0;
 
-	for (i = 0; i < strlen(in); i++)
+	for (i = 0; i < ilen; i++)
 	{
 		if (in[i] == '+')
 			out[o++] = ' ';
diff --git a/src/interfaces/odbc/convert.h b/src/interfaces/odbc/convert.h
index 893bf0ceebdefa1566b7b61c9c4f565b2e4ec166..fed2239e3b14b14056a6493d5742022b57532158 100644
--- a/src/interfaces/odbc/convert.h
+++ b/src/interfaces/odbc/convert.h
@@ -37,8 +37,8 @@ int			copy_statement_with_parameters(StatementClass *stmt);
 char	   *convert_escape(char *value);
 char	   *convert_money(char *s);
 char		parse_datetime(char *buf, SIMPLE_TIME *st);
-int			convert_linefeeds(char *s, char *dst, size_t max);
-char	   *convert_special_chars(char *si, char *dst, int used);
+int		convert_linefeeds(const char *s, char *dst, size_t max, BOOL *changed);
+int	   convert_special_chars(char *si, char *dst, int used);
 
 int			convert_pgbinary_to_char(char *value, char *rgbValue, int cbValueMax);
 int			convert_from_pgbinary(unsigned char *value, unsigned char *rgbValue, int cbValueMax);
diff --git a/src/interfaces/odbc/info.c b/src/interfaces/odbc/info.c
index 5e3e980d9f0149c878377cee2cf166be852c7f3c..173a1591bcdc1fba8252704696ad1ecd8b0e04fe 100644
--- a/src/interfaces/odbc/info.c
+++ b/src/interfaces/odbc/info.c
@@ -379,16 +379,7 @@ SQLGetInfo(
 		case SQL_MAX_STATEMENT_LEN:		/* ODBC 2.0 */
 			/* maybe this should be 0? */
 			len = 4;
-			/* Long Queries in 7.0+ */
-			if (PG_VERSION_GE(conn, 7.0))
-				value = 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;
-
+			value = CC_get_max_query_len(conn);
 			break;
 
 		case SQL_MAX_TABLE_NAME_LEN:	/* ODBC 1.0 */
diff --git a/src/interfaces/odbc/pgtypes.c b/src/interfaces/odbc/pgtypes.c
index 7e2b2ef36ce73eb702b6211832c0cf5eb9dc7da2..ca6b7a2387ff0c68d033a45047c2917aa7705398 100644
--- a/src/interfaces/odbc/pgtypes.c
+++ b/src/interfaces/odbc/pgtypes.c
@@ -503,6 +503,13 @@ getCharPrecision(StatementClass *stmt, Int4 type, int col, int handle_unknown_si
 	 * Static Precision (i.e., the Maximum Precision of the datatype) This
 	 * has nothing to do with a result set.
 	 */
+	if (maxsize == TEXT_FIELD_SIZE + 1) /* magic length for testing */
+	{
+		if (PG_VERSION_GE(SC_get_conn(stmt), 7.1))
+			maxsize = 0;
+		else 
+			maxsize = TEXT_FIELD_SIZE;
+	}
 	if (col < 0)
 		return maxsize;
 
diff --git a/src/interfaces/odbc/statement.c b/src/interfaces/odbc/statement.c
index 5c1ce699aad9c12854fb5ee48b9a2dbc982d721d..83dd58ba8f269a70b169fa0fb34a03f2a12ee88b 100644
--- a/src/interfaces/odbc/statement.c
+++ b/src/interfaces/odbc/statement.c
@@ -131,6 +131,7 @@ SQLAllocStmt(HDBC hdbc,
 	/* Copy default statement options based from Connection options */
 	stmt->options = conn->stmtOptions;
 
+	stmt->stmt_size_limit = CC_get_max_query_len(conn);
 	/* Save the handle for later */
 	stmt->phstmt = phstmt;
 
@@ -249,7 +250,8 @@ SC_Constructor(void)
 		rv->errormsg_created = FALSE;
 
 		rv->statement = NULL;
-		rv->stmt_with_params[0] = '\0';
+		rv->stmt_with_params = NULL;
+		rv->stmt_size_limit = -1;
 		rv->statement_type = STMT_TYPE_UNKNOWN;
 
 		rv->bindings = NULL;
@@ -313,6 +315,11 @@ SC_Destructor(StatementClass *self)
 
 	if (self->statement)
 		free(self->statement);
+	if (self->stmt_with_params)
+	{
+		free(self->stmt_with_params);
+		self->stmt_with_params = NULL;
+	}
 
 	SC_free_params(self, STMT_FREE_PARAMS_ALL);
 
diff --git a/src/interfaces/odbc/statement.h b/src/interfaces/odbc/statement.h
index 98e545795e04def837143c7948fedd7eec1acfc1..fe0b4a0b720eb34cb4c5bce349599a0481f4fd33 100644
--- a/src/interfaces/odbc/statement.h
+++ b/src/interfaces/odbc/statement.h
@@ -210,9 +210,10 @@ struct StatementClass_
 
 	char		cursor_name[MAX_CURSOR_LEN + 1];
 
-	char		stmt_with_params[STD_STATEMENT_LEN];	/* statement after
+	char		*stmt_with_params;	/* statement after
 														 * parameter
 														 * substitution */
+	int		stmt_size_limit;	
 
 	char		pre_executing;	/* This statement is prematurely executing */
 	char		inaccurate_result;		/* Current status is PREMATURE but