diff --git a/lib/modules/Sql.pmod/tds.pike b/lib/modules/Sql.pmod/tds.pike
index 3c4723a5d64769e971b3258233fe69ccd425c31c..f0101cf0d0f961194b112b44451cf1331719a647 100644
--- a/lib/modules/Sql.pmod/tds.pike
+++ b/lib/modules/Sql.pmod/tds.pike
@@ -1,5 +1,5 @@
 /*
- * $Id: tds.pike,v 1.9 2006/02/10 16:33:48 grubba Exp $
+ * $Id: tds.pike,v 1.10 2006/02/13 14:04:17 grubba Exp $
  *
  * A Pike implementation of the TDS protocol.
  *
@@ -7,12 +7,18 @@
  */
 
 #define TDS_DEBUG
+#define TDS_CONVERT_DEBUG
 
 #ifdef TDS_DEBUG
 #define TDS_WERROR(X...)	werror("TDS:" + X)
 #else
 #define TDS_WERROR(X...)
 #endif
+#ifdef TDS_CONVERT_DEBUG
+#define TDS_CONV_WERROR(X...)	werror("TDS: Convert: " + X)
+#else
+#define TDS_CONV_WERROR(X...)
+#endif
 
 static int filter_noprint(int char)
 {
@@ -831,7 +837,6 @@ static {
 
       res->cardinal_type = get_cardinal_type(res->column_type);
       res->varint_size = get_varint_size(res->column_type);
-      TDS_WERROR("Intermediate info: %O\n", res);
       switch(res->varint_size) {
       case 0:
 	res->column_size = get_size_by_type(res->column_type);
@@ -846,7 +851,6 @@ static {
 	res->column_size = inp->get_byte();
 	break;
       }
-      TDS_WERROR("Column size: %d bytes\n", res->column_size);
 
       res->timestamp = (res->cardinal_type == SYBBINARY) ||
 	(res->cardinal_type == TDS_UT_TIMESTAMP);
@@ -864,7 +868,6 @@ static {
       if (is_blob_type(res->cardinal_type)) {
 	TDS_WERROR("is_blob\n");
 	res->table = inp->get_string(inp->get_smallint());
-	TDS_WERROR("Table name: %O\n", res->table);
       }
       res->name = inp->get_string(inp->get_byte());
       TDS_WERROR("Column info: %O\n", res);
@@ -1050,7 +1053,10 @@ static {
 
     static string|int convert(string|int raw, mapping(string:mixed) info)
     {
-      if (!raw) return raw; /* NULL */
+      if (!raw) {
+	TDS_CONV_WERROR("%O ==> NULL\n", raw);
+	return raw; /* NULL */
+      }
       int cardinal_type;
       switch(cardinal_type = info->cardinal_type) {
       case SYBCHAR:
@@ -1066,42 +1072,65 @@ static {
       case SYBIMAGE:
       case XSYBBINARY:
       case XSYBVARBINARY:
+	TDS_CONV_WERROR("%O ==> %O\n", raw, raw);
 	return raw;
+      case SYBMONEYN:
       case SYBMONEY4:
-	{
-	  int val;
-	  sscanf(raw, "%-4c", val);
-	  if (val < 0) {
-	    int cents = -(val/50 - 1)/2;
-	    return sprintf("-%d.%02d", cents/100, cents%100);
-	  } else {
-	    int cents = (val/50 + 1)/2;
-	    return sprintf("%d.%02d", cents/100, cents%100);
-	  }
-	}
       case SYBMONEY:
 	{
 	  int val;
 	  string sgn = "";
-	  sscanf(raw, "%-8c", val);
+	  if (sizeof(raw) == 8) {
+	    sscanf(raw, "%-8c", val);
+	  } else {
+	    sscanf(raw, "%-4c", val);
+	  }
 	  if (val < 0) {
 	    sgn = "-";
 	    val = -val;
 	  }
 	  int cents = (val + 50)/100;
-	  return sprintf("%s%d.%02d", sgn, cents/100, cents%100);
+	  string res = sprintf("%s%d.%02d", sgn, cents/100, cents%100);
+	  TDS_CONV_WERROR("%O ==> %O\n", raw, res);
+	  return res;
 	}
       case SYBNUMERIC:
+	{
+	  string res =
+	    sprintf("%d", array_sscanf(raw[1..],
+				       "%-" + (sizeof(raw)-1) + "c")[0]);
+
+	  // Move decimal point @[scale] positions.
+	  int scale = info->column_scale;
+	  if (sizeof(res) < scale) {
+	    res = "0." + ("0" * (scale - sizeof(res))) + res;
+	  } else if (sizeof(res) == scale) {
+	    res = "0." + res;
+	  } else if (scale) {
+	    res = res[..sizeof(res)-(scale+1)] + "." +
+	      res[sizeof(res)-scale..];
+	  }
+
+	  // Fix the sign.
+	  if (!res[0]) {
+	    res = "-" + res;
+	  }
+	  TDS_CONV_WERROR("%O (scale: %d) ==> %O\n",
+			  raw, scale, res);
+	  return res;
+	}
       case SYBDECIMAL:
       case SYBREAL:
       case SYBFLT8:
       case SYBUNIQUE:
       default:
 	// FIXME:
-	TDS_WERROR("Not yet supported: %d\n", info->cardinal_type);
+	TDS_CONV_WERROR("Not yet supported: %d (%O)\n",
+			info->cardinal_type, raw);
 	return raw;
       case SYBBIT:
       case SYBBITN:
+	TDS_CONV_WERROR("%O ==> \"%d\"", raw, !!raw[0]);
 	return raw[0]?"1":"0";
       case SYBINT1:
       case SYBINT2:
@@ -1116,17 +1145,15 @@ static {
 	  } else {
 	    val = array_sscanf(raw + ("\x00"*8), "%-8c")[0];
 	  }
-	  TDS_WERROR("Converted %O ==> %d\n", raw, val);
+	  TDS_WERROR("%O ==> \"%d\"\n", raw, val);
 	  return sprintf("%d", val);
 	}
       case SYBDATETIMN:
-	if (sizeof(raw) == 8) cardinal_type = SYBDATETIME;
-	// FALL_THROUGH
       case SYBDATETIME:
       case SYBDATETIME4:
 	{
 	  int day, min, sec, sec_300;
-	  if (cardinal_type == SYBDATETIME) {
+	  if (sizeof(raw) == 8) {
 	    sscanf(raw, "%-4c%-4c", day, sec_300);
 	    sec = sec_300/300;
 	    sec_300 %= 300;
@@ -1152,11 +1179,12 @@ static {
 	  year += (century + 15)*100 + l;
 	  if (!l && !(year & 3) && ((year % 100) || !(year % 400)))
 	    yday++;
-	  return sprintf("%04d-%02d-%02dT%02d:%02d:%02d",
-			 year, mon, mday, hour, min, sec);
+	  string res = sprintf("%04d-%02d-%02dT%02d:%02d:%02d",
+			       year, mon, mday, hour, min, sec);
+	  TDS_CONV_WERROR("%O ==> %O\n", raw, res);
+	  return res;
 	}
       }
-      return raw;
     }
 
     static array(string|int) process_row(InPacket inp,
@@ -1183,7 +1211,6 @@ static {
 	case TDS_ROWFMT2_TOKEN:
 	case TDS7_RESULT_TOKEN:
 	  // Some other result starts here.
-	  //busy = 0;
 	  return 0;
 	case TDS_ROW_TOKEN:
 	  inp->get_byte();
@@ -1193,7 +1220,6 @@ static {
 	case TDS_DONEPROC_TOKEN:
 	case TDS_DONEINPROC_TOKEN:
 	  if (!leave_end_token) inp->get_byte();
-	  //busy = 0;
 	  return 0;
 	default:
 	  inp->get_byte();
@@ -1293,7 +1319,7 @@ static {
       this_program::password = auth;
       this_program::domain = domain;
 
-      TDS_WERROR("Connecting to %s:%d version %d.%d\n",
+      TDS_WERROR("Connecting to %s:%d with TDS version %d.%d\n",
 		 server, port, major_version, minor_version);
 
       socket = Stdio.File();
@@ -1449,6 +1475,23 @@ class big_query
   }
 }
 
+static compile_query compiled_insert_id =
+  compile_query("SELECT @@identity AS insert_id");
+
+int insert_id()
+{
+  object res = big_query(compiled_insert_id);
+  array(mapping(string:mixed)) field_info =
+    res->fetch_fields();
+  if (!field_info) return 0;
+  array(string|int) row = res->fetch_row();
+  if (!row) return 0;
+  foreach(field_info->name; int i; string name) {
+    if (name == "insert_id") return (int)row[i];
+  }
+  return 0;
+}
+
 string server_info()
 {
   return server_data;