[patches] odbc

Nirgal <[email protected]> Sun, 4 Sep 2011 01:27:23 +0000
Newsgroups gmane.comp.db.mdb-tools.devel
Message-ID <[email protected]>
--Boundary-00=_HQtYO66l4N6T74z
Content-Type: text/plain;
  charset="utf-8"
Content-Transfer-Encoding: 7bit

04_odbcgetcol.diff fixes fill of pcbColName even when szColName is null. This was crashing my pyodbc tests.

05_odbctypes.diff is based on a patch by Mark Williams:
https://github.com/markrwilliams/mdbtools/commit/4c847948fcd035f3ebafcc0cab3be4de6a90771b so that odbc returns the correct types.
short dates support (without time).
I did not get the opportunity to tests long string reading, despite mangling the original patch. Sorry.

Full patch series against brian git master is at http://www.nirgal.com/mdbtools/debian.squeeze/debian/patches/series
test binaries available at http://www.nirgal.com/mdbtools/debian.squeeze/

--Boundary-00=_HQtYO66l4N6T74z
Content-Type: text/x-patch;
  charset="UTF-8";
  name="04_odbcgetcol.diff"
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment;
	filename="04_odbcgetcol.diff"

Author: Jean-Michel Vourgère <[email protected]>
Date: 20110904
Description: SQLDescribeCol: fill pcbColName even when szColName is null.
Index: mdbtools-0.6~pre1/src/odbc/odbc.c
===================================================================
--- mdbtools-0.6~pre1.orig/src/odbc/odbc.c
+++ mdbtools-0.6~pre1/src/odbc/odbc.c
@@ -732,12 +732,20 @@
 			break;
 		}
 	}
+	if (i==table->num_cols) {
+		fprintf(stderr, "Column %s lost\n", (char*)sqlcol->name);
+		return SQL_ERROR;
+	}
 
 	if (szColName) {
 		namelen = MIN(cbColNameMax,strlen(sqlcol->name));
 		strncpy((char*)szColName, sqlcol->name, namelen);
 		szColName[namelen]='\0';
-		*pcbColName=namelen;
+		if (pcbColName)
+			*pcbColName=namelen;
+	} else {
+		if (pcbColName)
+			*pcbColName = strlen(sqlcol->name);
 	}
 	if (pfSqlType) { //Currently libmdbodbc.so returns values as string in SQLGetData() even though it is a number.
 		*pfSqlType = SQL_VARCHAR;//_odbc_get_client_type(col->col_type);

--Boundary-00=_HQtYO66l4N6T74z
Content-Type: text/x-patch;
  charset="UTF-8";
  name="05_odbctypes.diff"
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment;
	filename="05_odbctypes.diff"

Author: Jean-Michel Vourgère <[email protected]>
Date: 20110904
Description: https://github.com/markrwilliams/mdbtools/commit/4c847948fcd035f3ebafcc0cab3be4de6a90771b + short dates
Index: mdbtools-0.6~pre1/src/odbc/odbc.c
===================================================================
--- mdbtools-0.6~pre1.orig/src/odbc/odbc.c
+++ mdbtools-0.6~pre1/src/odbc/odbc.c
@@ -35,7 +35,7 @@
 static iconv_t iconv_in,iconv_out;
 #endif //ENABLE_ODBC_W
 
-static SQLSMALLINT _odbc_get_client_type(int srv_type);
+static SQLSMALLINT _odbc_get_client_type(MdbColumn *col);
 static int _odbc_fix_literals(struct _hstmt *stmt);
 //static int _odbc_get_server_type(int clt_type);
 static int _odbc_get_string_size(int size, SQLCHAR FAR *str);
@@ -747,8 +747,8 @@
 		if (pcbColName)
 			*pcbColName = strlen(sqlcol->name);
 	}
-	if (pfSqlType) { //Currently libmdbodbc.so returns values as string in SQLGetData() even though it is a number.
-		*pfSqlType = SQL_VARCHAR;//_odbc_get_client_type(col->col_type);
+	if (pfSqlType) {
+		*pfSqlType = _odbc_get_client_type(col);
 	}
 	if (pcbColDef) {
 		*pcbColDef = col->col_size;
@@ -1310,8 +1310,8 @@
 			ts3 = mdb_ascii2unicode(mdb, col->name, 0, (char*)t3, MDB_BIND_SIZE);
 			ts5 = mdb_ascii2unicode(mdb, "FIX ME", 0,  (char*)t5, MDB_BIND_SIZE);
 			nullable = SQL_NO_NULLS;
-			datatype = _odbc_get_client_type(col->col_type);
-			sqldatatype = _odbc_get_client_type(col->col_type);
+			datatype = _odbc_get_client_type(col);
+			sqldatatype = _odbc_get_client_type(col);
 			ordinal = j+1;
 
 			/* Set all fields to NULL */
@@ -1411,42 +1411,124 @@
 		}
 	}
 
-	if(icol!=stmt->icol){stmt->icol=icol;stmt->pos=0;}
+	if (icol!=stmt->icol) {
+		stmt->icol=icol;
+		stmt->pos=0;
+	}
+
+	if (!rgbValue) {
+		strcpy(sqlState, "HY009");
+	 	return SQL_ERROR;
+	}
+	if (pcbValue && *pcbValue<0) {
+		strcpy(sqlState, "HY090");
+	 	return SQL_ERROR;
+	}
+
 	if (col->col_type == MDB_BOOL) {
-	    if(cbValueMax==0){if(pcbValue)*pcbValue=1;return SQL_SUCCESS_WITH_INFO;}
-		if(stmt->pos>=1)return SQL_NO_DATA;
-		if(!rgbValue){
-		  strcpy(sqlState,"HY009");
-		  return SQL_ERROR;
-		}
-		strcpy(rgbValue, (col->cur_value_len)?"0":"1");
+		// bool cannot be null
+		*(BOOL*)rgbValue = col->cur_value_len ? 0 : 1;
 		if (pcbValue)
 			*pcbValue = 1;
-		stmt->pos=1;
-	} else if (col->cur_value_len) {
-		char *str = mdb_col_to_string(mdb,mdb->pg_buf,
-			col->cur_value_start,col->col_type,col->cur_value_len);
-		if(cbValueMax==0){if(pcbValue)*pcbValue=strlen(str);g_free(str);return SQL_SUCCESS_WITH_INFO;}
-		if(stmt->pos>=strlen(str))return SQL_NO_DATA;
-		if(!rgbValue){
-		  strcpy(sqlState,"HY009");
-		  return SQL_ERROR;
-		}
-		i=cbValueMax<=strlen(str+stmt->pos)?cbValueMax-1:strlen(str+stmt->pos);
-		memcpy(rgbValue,str+stmt->pos,i);
-		*((char*)(rgbValue)+i)=0;
-		stmt->pos+=i;
-		g_free(str);
-		if (pcbValue)
-			*pcbValue = i;
-	} else {
-		/* When NULL data is retrieved, non-null pcbValue is required */
-		if (pcbValue) {
-			*pcbValue = SQL_NULL_DATA;
-		} else {
+		return SQL_SUCCESS;
+	}
+	if (col->cur_value_len == 0) {
+		/* When NULL data is retrieved, non-null pcbValue is
+		   required */
+		if (!pcbValue) {
 			strcpy(sqlState, "22002");
 			return SQL_ERROR;
-		}		
+		}
+		*pcbValue = SQL_NULL_DATA;
+		return SQL_SUCCESS;
+	}
+
+	switch(col->col_type) {
+		case MDB_BYTE:
+			*(SQLSMALLINT*)rgbValue = mdb_get_byte(mdb->pg_buf, col->cur_value_start);
+			if (pcbValue)
+				*pcbValue = sizeof(SQLSMALLINT);
+			break;
+		case MDB_INT:
+			*(SQLSMALLINT*)rgbValue = (SQLSMALLINT)mdb_get_int16(mdb->pg_buf, col->cur_value_start);
+			if (pcbValue)
+				*pcbValue = sizeof(SQLSMALLINT);
+			break;
+		case MDB_LONGINT:
+			*(SQLINTEGER*)rgbValue = mdb_get_int32(mdb->pg_buf, col->cur_value_start);
+			if (pcbValue)
+				*pcbValue = sizeof(SQLINTEGER);
+			break;
+		// case MDB_MONEY: TODO
+		case MDB_FLOAT:
+			*(float*)rgbValue = mdb_get_single(mdb->pg_buf, col->cur_value_start);
+			if (pcbValue)
+				*pcbValue = sizeof(float);
+			break;
+		case MDB_DOUBLE:
+			*(double*)rgbValue = mdb_get_double(mdb->pg_buf, col->cur_value_start);
+			if (pcbValue)
+			  *pcbValue = sizeof(double);
+			break;
+		case MDB_DATETIME: ;
+#if ODBCVER >= 0x0300
+			struct tm tmp_t;
+			mdb_date_to_tm(mdb_get_double(mdb->pg_buf, col->cur_value_start), &tmp_t);
+
+			const char *format = mdb_col_get_prop(col, "Format");
+			if (format && !strcmp(format, "Short Date")) {
+				DATE_STRUCT sql_dt;
+				sql_dt.year     = tmp_t.tm_year + 1900;
+				sql_dt.month    = tmp_t.tm_mon + 1;
+				sql_dt.day      = tmp_t.tm_mday;
+				*(DATE_STRUCT*)rgbValue = sql_dt;
+				if (pcbValue)
+					*pcbValue = sizeof(DATE_STRUCT);
+			} else {
+				TIMESTAMP_STRUCT sql_ts;
+				sql_ts.year     = tmp_t.tm_year + 1900;
+				sql_ts.month    = tmp_t.tm_mon + 1;
+				sql_ts.day      = tmp_t.tm_mday;
+				sql_ts.hour     = tmp_t.tm_hour;
+				sql_ts.minute   = tmp_t.tm_min;
+				sql_ts.second   = tmp_t.tm_sec;
+				sql_ts.fraction = 0;
+
+				*(TIMESTAMP_STRUCT*)rgbValue = sql_ts;
+				if (pcbValue)
+					*pcbValue = sizeof(TIMESTAMP_STRUCT);
+			}
+			break;
+#endif // returns text if old odbc
+		default: ;
+			char *str = mdb_col_to_string(mdb, mdb->pg_buf,
+				col->cur_value_start, col->col_type, col->cur_value_len);
+			int len = strlen(str);
+			if (stmt->pos >= len)
+				return SQL_NO_DATA;
+			if (!cbValueMax) {
+				if (pcbValue)
+					*pcbValue = len;
+				free(str);
+				return SQL_SUCCESS_WITH_INFO;
+			}
+			if (len - stmt->pos > cbValueMax) {
+				/* the buffer we were given is too small, so
+				   truncate it to the size of the buffer */
+				strncpy(rgbValue, str, cbValueMax);
+				if (pcbValue)
+					*pcbValue = cbValueMax;
+				stmt->pos += cbValueMax;
+				free(str);
+				strcpy(sqlState, "01004"); // trunctated
+				return SQL_SUCCESS_WITH_INFO;
+			}
+			strncpy(rgbValue, str + stmt->pos, len - stmt->pos);
+			if (pcbValue)
+				*pcbValue = len - stmt->pos;
+			stmt->pos += len - stmt->pos;
+			free(str);
+			break;
 	}
 	return SQL_SUCCESS;
 }
@@ -1998,33 +2080,33 @@
 	}
 	return 0;
 }*/
-static SQLSMALLINT _odbc_get_client_type(int srv_type)
+static SQLSMALLINT _odbc_get_client_type(MdbColumn *col)
 {
-	switch (srv_type) {
+	switch (col->col_type) {
 		case MDB_BOOL:
 			return SQL_BIT;
-			break;
 		case MDB_BYTE:
 			return SQL_TINYINT;
-			break;
 		case MDB_INT:
 			return SQL_SMALLINT;
-			break;
 		case MDB_LONGINT:
 			return SQL_INTEGER;
-			break;
 		case MDB_MONEY:
 			return SQL_DECIMAL;
-			break;
 		case MDB_FLOAT:
 			return SQL_FLOAT;
-			break;
 		case MDB_DOUBLE:
 			return SQL_DOUBLE;
-			break;
+		case MDB_DATETIME: ;
+#if ODBCVER >= 0x0300
+			const char *format = mdb_col_get_prop(col, "Format");
+			if (format && !strcmp(format, "Short Date"))
+				return SQL_TYPE_DATE;
+			else
+				return SQL_TYPE_TIMESTAMP;
+#endif // returns text otherwise
 		case MDB_TEXT:
 			return SQL_VARCHAR;
-			break;
 		default:
 			// fprintf(stderr,"Unknown type %d\n",srv_type);
 			break;
Index: mdbtools-0.6~pre1/include/mdbodbc.h
===================================================================
--- mdbtools-0.6~pre1.orig/include/mdbodbc.h
+++ mdbtools-0.6~pre1/include/mdbodbc.h
@@ -49,8 +49,8 @@
 	char query[4096];
 	struct _sql_bind_info *bind_head;
 	int rows_affected;
-	int icol;
-	int pos;
+	int icol; /* SQLGetData: last column */
+	int pos; /* SQLGetData: last position (truncated result) */
 };
 
 struct _sql_bind_info {

--Boundary-00=_HQtYO66l4N6T74z
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

------------------------------------------------------------------------------
Special Offer -- Download ArcSight Logger for FREE!
Finally, a world-class log management solution at an even better 
price-free! And you'll get a free "Love Thy Logs" t-shirt when you
download Logger. Secure your free ArcSight Logger TODAY!
http://p.sf.net/sfu/arcsisghtdev2dev
--Boundary-00=_HQtYO66l4N6T74z
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
mdbtools-dev mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mdbtools-dev

--Boundary-00=_HQtYO66l4N6T74z--