diff --git a/src/modules/Odbc/odbc.c b/src/modules/Odbc/odbc.c
index ac7db85307ad355b64b275f0d2b1bc0394880e39..5e74d8525312f6a81a45c31314b929ff26d13240 100644
--- a/src/modules/Odbc/odbc.c
+++ b/src/modules/Odbc/odbc.c
@@ -1,5 +1,5 @@
 /*
- * $Id: odbc.c,v 1.8 1998/05/29 19:04:45 grubba Exp $
+ * $Id: odbc.c,v 1.9 1998/05/31 15:40:31 grubba Exp $
  *
  * Pike interface to ODBC compliant databases.
  *
@@ -15,7 +15,7 @@
 #endif /* HAVE_CONFIG_H */
 
 #include "global.h"
-RCSID("$Id: odbc.c,v 1.8 1998/05/29 19:04:45 grubba Exp $");
+RCSID("$Id: odbc.c,v 1.9 1998/05/31 15:40:31 grubba Exp $");
 
 #include "interpret.h"
 #include "object.h"
@@ -38,6 +38,8 @@ RCSID("$Id: odbc.c,v 1.8 1998/05/29 19:04:45 grubba Exp $");
 
 struct program *odbc_program = NULL;
 
+HENV odbc_henv = SQL_NULL_HENV;
+
 /*
  * Functions
  */
@@ -54,7 +56,7 @@ static INLINE void odbc_check_error(const char *fun, const char *msg,
 				    RETCODE code, void (*clean)(void))
 {
   if ((code != SQL_SUCCESS) && (code != SQL_SUCCESS_WITH_INFO)) {
-    odbc_error(fun, msg, PIKE_ODBC, PIKE_ODBC->hstmt, code, clean);
+    odbc_error(fun, msg, PIKE_ODBC, SQL_NULL_HSTMT, code, clean);
   }
 }
 
@@ -68,7 +70,7 @@ void odbc_error(const char *fun, const char *msg,
   SWORD errmsg_len = 0;
   SDWORD native_error;
 
-  _code = SQLError(odbc->henv, odbc->hdbc, hstmt, errcode, &native_error,
+  _code = SQLError(odbc_henv, odbc->hdbc, hstmt, errcode, &native_error,
 		   errmsg, SQL_MAX_MESSAGE_LENGTH-1, &errmsg_len);
   errmsg[errmsg_len] = '\0';
 
@@ -85,19 +87,29 @@ void odbc_error(const char *fun, const char *msg,
   switch(_code) {
   case SQL_SUCCESS:
   case SQL_SUCCESS_WITH_INFO:
-    error("%s():%s: %d:%s:%s\n", fun, msg, code, errcode, errmsg);
+    error("%s(): %s:\n"
+	  "%d:%s:%s\n",
+	  fun, msg, code, errcode, errmsg);
     break;
   case SQL_ERROR:
-    error("%s():%s: SQLError failed (%d:SQL_ERROR)\n", fun, msg, code);
+    error("%s(): %s:\n"
+	  "SQLError failed (%d:SQL_ERROR)\n",
+	  fun, msg, code);
     break;
   case SQL_NO_DATA_FOUND:
-    error("%s():%s: SQLError failed (%d:SQL_NO_DATA_FOUND)\n", fun, msg, code);
+    error("%s(): %s:\n"
+	  "SQLError failed (%d:SQL_NO_DATA_FOUND)\n",
+	  fun, msg, code);
     break;
   case SQL_INVALID_HANDLE:
-    error("%s():%s: SQLError failed (%d:SQL_INVALID_HANDLE)\n", fun, msg, code);
+    error("%s(): %s:\n"
+	  "SQLError failed (%d:SQL_INVALID_HANDLE)\n",
+	  fun, msg, code);
     break;
   default:
-    error("%s():%s: SQLError failed (%d:%d)\n", fun, msg, code, _code);
+    error("%s(): %s:\n"
+	  "SQLError failed (%d:%d)\n",
+	  fun, msg, code, _code);
     break;
   }
 }
@@ -114,24 +126,6 @@ static void clean_last_error(void)
   }
 }
 
-static void clean_henv(void)
-{
-  HENV henv = PIKE_ODBC->henv;
-  PIKE_ODBC->henv = SQL_NULL_HENV;
-  odbc_check_error("odbc_error", "Freeing HENV",
-		   SQLFreeEnv(henv), clean_last_error);
-}
-
-static void clean_hdbc(void)
-{
-  HDBC hdbc = PIKE_ODBC->hdbc;
-  PIKE_ODBC->hdbc = SQL_NULL_HDBC;
-  odbc_check_error("odbc_error", "Disconnecting HDBC",
-		   SQLDisconnect(hdbc), clean_henv);
-  odbc_check_error("odbc_error", "Freeing HDBC",
-		   SQLFreeConnect(hdbc), clean_henv);
-}
-
 /*
  * Glue functions
  */
@@ -140,34 +134,31 @@ static void init_odbc_struct(struct object *o)
 {
   RETCODE code;
 
-  PIKE_ODBC->henv = SQL_NULL_HENV;
   PIKE_ODBC->hdbc = SQL_NULL_HDBC;
-  PIKE_ODBC->hstmt = SQL_NULL_HSTMT;
-  PIKE_ODBC->last_error = NULL;
   PIKE_ODBC->affected_rows = 0;
+  PIKE_ODBC->flags = 0;
+  PIKE_ODBC->last_error = NULL;
 
   odbc_check_error("init_odbc_struct", "ODBC initialization failed",
-		   SQLAllocEnv(&(PIKE_ODBC->henv)), 0);
-
-  odbc_check_error("init_odbc_struct", "ODBC initialization failed",
-		   SQLAllocConnect(PIKE_ODBC->henv, &(PIKE_ODBC->hdbc)),
-		   clean_henv);
+		   SQLAllocConnect(odbc_henv, &(PIKE_ODBC->hdbc)), NULL);
 }
 
 static void exit_odbc_struct(struct object *o)
 {
-  RETCODE code;
-  HENV henv = PIKE_ODBC->henv;
   HDBC hdbc = PIKE_ODBC->hdbc;
 
-  PIKE_ODBC->hdbc = SQL_NULL_HDBC;
-  odbc_check_error("exit_odbc_struct", "ODBC disconnect failed",
-		   SQLDisconnect(hdbc), clean_henv);
-  odbc_check_error("exit_odbc_struct", "Freeing ODBC connection failed",
-		   SQLFreeConnect(hdbc), clean_henv);
-  PIKE_ODBC->henv = SQL_NULL_HENV;
-  odbc_check_error("exit_odbc_struct", "Freeing ODBC environment failed",
-		   SQLFreeEnv(henv), clean_last_error);
+  if (hdbc != SQL_NULL_HDBC) {
+    if (PIKE_ODBC->flags & PIKE_ODBC_CONNECTED) {
+      PIKE_ODBC->flags &= ~PIKE_ODBC_CONNECTED;
+      odbc_check_error("odbc_error", "Disconnecting HDBC",
+		       SQLDisconnect(hdbc), (void (*)(void))exit_odbc_struct);
+      /* NOTE: Potential recursion above! */
+    }
+    PIKE_ODBC->hdbc = SQL_NULL_HDBC;
+    odbc_check_error("odbc_error", "Freeing HDBC",
+		     SQLFreeConnect(hdbc), clean_last_error);
+  }
+  clean_last_error();
 }
 
 /*
@@ -209,11 +200,18 @@ static void f_create(INT32 args)
   if (!server) {
     server = make_shared_string("");
   }
+  if (PIKE_ODBC->flags & PIKE_ODBC_CONNECTED) {
+    PIKE_ODBC->flags &= ~PIKE_ODBC_CONNECTED;
+    /* Disconnect old hdbc */
+    odbc_check_error("odbc->create", "Disconnecting HDBC",
+		     SQLDisconnect(PIKE_ODBC->hdbc), NULL);
+  }
   odbc_check_error("odbc->create", "Connect failed",
 		   SQLConnect(PIKE_ODBC->hdbc, (unsigned char *)server->str,
 			      server->len, (unsigned char *)user->str,
 			      user->len, (unsigned char *)pwd->str,
 			      pwd->len), NULL);
+  PIKE_ODBC->flags |= PIKE_ODBC_CONNECTED;
   pop_n_elems(args);
 }
 
@@ -223,19 +221,15 @@ static void f_affected_rows(INT32 args)
   push_int(PIKE_ODBC->affected_rows);
 }
 
-static void f_insert_id(INT32 args)
-{
-  /**********************************************/
-}
-
 static void f_select_db(INT32 args)
 {
   /**********************************************/
 }
 
-void free_hstmt(HSTMT hstmt)
+/* Needed since free_string() can be a macro */
+static void odbc_free_string(struct pike_string *s)
 {
-  SQLFreeStmt(hstmt, SQL_DROP);		/* Ignore return value. */
+  free_string(s);
 }
 
 static void f_big_query(INT32 args)
@@ -243,50 +237,54 @@ static void f_big_query(INT32 args)
   ONERROR ebuf;
   HSTMT hstmt = SQL_NULL_HSTMT;
   struct pike_string *q = NULL;
+#ifdef DEBUG
+  struct svalue *save_sp = sp + 1 - args;
+#endif /* DEBUG */
 
   get_all_args("odbc->big_query", args, "%S", &q);
 
-  odbc_check_error("odbc->big_query", "Statement allocation failed",
-		   SQLAllocStmt(PIKE_ODBC->hdbc, &hstmt), NULL);
-  PIKE_ODBC->hstmt = hstmt;
+  add_ref(q);
+  SET_ONERROR(ebuf, odbc_free_string, q);
 
-  SET_ONERROR(ebuf, free_hstmt, hstmt);
-
-  odbc_check_error("odbc->big_query", "Query failed",
-		   SQLExecDirect(hstmt, (unsigned char *)q->str,
-				 q->len), NULL);
   pop_n_elems(args);
 
-  odbc_check_error("odbc->big_query", "Couldn't get the number of fields",
-		   SQLNumResultCols(hstmt, &(PIKE_ODBC->num_fields)), NULL);
+  clean_last_error();
 
-  odbc_check_error("odbc->big_query", "Couldn't get the number of rows",
-		   SQLRowCount(hstmt, &(PIKE_ODBC->affected_rows)), NULL);
+  /* Allocate the statement (result) object */
+  ref_push_object(fp->current_object);
+  push_object(clone_object(odbc_result_program, 1));
 
-  if (PIKE_ODBC->num_fields) {
-    /* PIKE_ODBC->hstmt=hstmt; */
-    ref_push_object(fp->current_object);
+  UNSET_ONERROR(ebuf);
 
-    push_object(clone_object(odbc_result_program, 1));
+  /* Potential return value is now in place */
 
-    /* hstmt is now handled by the result program. */
-    UNSET_ONERROR(ebuf);
-  } else {
-    odbc_check_error("odbc->big_query", "Couldn't commit query",
-		     SQLTransact(PIKE_ODBC->henv, PIKE_ODBC->hdbc,
-				 SQL_COMMIT), NULL);
+  PIKE_ODBC->affected_rows = 0;
 
-    UNSET_ONERROR(ebuf);
+  /* Do the actual query */
+  push_string(q);
+  apply(sp[-2].u.object, "execute", 1);
+  
+  if (sp[-1].type != T_INT) {
+    error("odbc->big_query(): Unexpected return value from "
+	  "odbc_result->execute().\n");
+  }
 
-    /* hstmt is still handled by us. */
-    if (hstmt != SQL_NULL_HSTMT) {
-      PIKE_ODBC->hstmt = SQL_NULL_HSTMT;
-      odbc_check_error("odbc->big_query", "Freeing of HSTMT failed",
-		       SQLFreeStmt(hstmt, SQL_DROP), NULL);
-    }
+  if (!sp[-1].u.integer) {
+    pop_n_elems(2);	/* Zap the result object too */
+
+    odbc_check_error("odbc->big_query", "Couldn't commit query",
+		     SQLTransact(odbc_henv, PIKE_ODBC->hdbc, SQL_COMMIT),
+		     NULL);
 
     push_int(0);
+  } else {
+    pop_stack();	/* Keep the result object */
   }
+#ifdef DEBUG
+  if (sp != save_sp) {
+    fatal("Stack error in odbc->big_query().\n");
+  }
+#endif /* DEBUG */
 }
 
 static void f_create_db(INT32 args)
@@ -319,20 +317,28 @@ static void f_reload(INT32 args)
 void pike_module_init(void)
 {
 #ifdef HAVE_ODBC
+  RETCODE err = SQLAllocEnv(&odbc_henv);
+
+  if (err != SQL_SUCCESS) {
+    error("odbc_module_init(): SQLAllocEnv() failed with code %08x\n", err);
+  }
+
   start_new_program();
   add_storage(sizeof(struct precompiled_odbc));
 
   add_function("error", f_error, "function(void:int|string)", ID_PUBLIC);
   add_function("create", f_create, "function(string|void, string|void, string|void, string|void:void)", ID_PUBLIC);
-  add_function("affected_rows", f_affected_rows, "function(void:int)", ID_PUBLIC);
-  add_function("insert_id", f_insert_id, "function(void:int)", ID_PUBLIC);
+
   add_function("select_db", f_select_db, "function(string:void)", ID_PUBLIC);
   add_function("big_query", f_big_query, "function(string:int|object)", ID_PUBLIC);
+  add_function("affected_rows", f_affected_rows, "function(void:int)", ID_PUBLIC);
+  /* NOOP's: */
   add_function("create_db", f_create_db, "function(string:void)", ID_PUBLIC);
   add_function("drop_db", f_drop_db, "function(string:void)", ID_PUBLIC);
   add_function("shutdown", f_shutdown, "function(void:void)", ID_PUBLIC);
   add_function("reload", f_reload, "function(void:void)", ID_PUBLIC);
 #if 0
+  add_function("insert_id", f_insert_id, "function(void:int)", ID_PUBLIC);
   add_function("statistics", f_statistics, "function(void:string)", ID_PUBLIC);
   add_function("server_info", f_server_info, "function(void:string)", ID_PUBLIC);
   add_function("host_info", f_host_info, "function(void:string)", ID_PUBLIC);
@@ -365,6 +371,15 @@ void pike_module_exit(void)
     free_program(odbc_program);
     odbc_program = NULL;
   }
+
+  if (odbc_henv != SQL_NULL_HENV) {
+    RETCODE err = SQLFreeEnv(odbc_henv);
+    odbc_henv = SQL_NULL_HENV;
+
+    if ((err != SQL_SUCCESS) && (err != SQL_SUCCESS_WITH_INFO)) {
+      error("odbc_module_exit(): SQLFreeEnv() failed with code %08x\n", err);
+    }
+  }
 #endif /* HAVE_ODBC */
 }
  
diff --git a/src/modules/Odbc/odbc_result.c b/src/modules/Odbc/odbc_result.c
index 4bc8ef496a0353f41368c4fccffed099ee485fde..10e22f26eb36c0338b0b704186e496b50f9ad9f2 100644
--- a/src/modules/Odbc/odbc_result.c
+++ b/src/modules/Odbc/odbc_result.c
@@ -1,5 +1,5 @@
 /*
- * $Id: odbc_result.c,v 1.8 1998/04/20 18:53:43 grubba Exp $
+ * $Id: odbc_result.c,v 1.9 1998/05/31 15:40:33 grubba Exp $
  *
  * Pike  interface to ODBC compliant databases
  *
@@ -17,7 +17,7 @@
 #ifdef HAVE_ODBC
 
 #include "global.h"
-RCSID("$Id: odbc_result.c,v 1.8 1998/04/20 18:53:43 grubba Exp $");
+RCSID("$Id: odbc_result.c,v 1.9 1998/05/31 15:40:33 grubba Exp $");
 
 #include "interpret.h"
 #include "object.h"
@@ -31,10 +31,13 @@ RCSID("$Id: odbc_result.c,v 1.8 1998/04/20 18:53:43 grubba Exp $");
 #include "array.h"
 #include "builtin_functions.h"
 #include "pike_memory.h"
+#include "pike_macros.h"
 #include "module_support.h"
 
 #include "precompiled_odbc.h"
 
+#define ODBC_DEBUG
+
 /*
  * Globals
  */
@@ -104,16 +107,14 @@ static void exit_res_struct(struct object *o)
 static void odbc_fix_fields(void)
 {
   int i;
-  struct odbc_field_info {
-    int type;	/* Pike-type */
-    int size;
-  } *odbc_fields = alloca(sizeof(struct odbc_field_info)*PIKE_ODBC_RES->num_fields);
+  unsigned long *odbc_field_sizes = alloca(sizeof(unsigned long) *
+					   PIKE_ODBC_RES->num_fields);
   size_t buf_size = 1024;
   unsigned char *buf = alloca(buf_size);
   int membuf_size = 0;
   char *membuf = NULL;
 
-  if ((!buf)||(!odbc_fields)) {
+  if ((!buf)||(!odbc_field_sizes)) {
     error("odbc_fix_fields(): Out of memory\n");
   }
 
@@ -144,8 +145,16 @@ static void odbc_fix_fields(void)
 	error("odbc_fix_fields(): Out of memory\n");
       }
     }
-    odbc_fields[i].type = T_STRING;
-    odbc_fields[i].size = precision+1;
+#ifdef ODBC_DEBUG
+    fprintf(stderr, "ODBC:odbc_fix_fields():\n"
+	    "name:%s\n"
+	    "sql_type:%d\n"
+	    "precision:%ld\n"
+	    "scale:%d\n"
+	    "nullable:%d\n",
+	    buf, sql_type, precision, scale, nullable);
+#endif /* ODBC_DEBUG */
+    odbc_field_sizes[i] = precision+1;
     /* Create the mapping */
     push_text("name");
     push_string(make_shared_binary_string((char *)buf, name_len));
@@ -156,44 +165,48 @@ static void odbc_fix_fields(void)
       break;
     case SQL_DATE:
       push_text("date");
-       odbc_fields[i].size = 7;
+      odbc_field_sizes[i] = 12;
       break;
     case SQL_DECIMAL:
       push_text("decimal");
-      odbc_fields[i].size += 2;
+      odbc_field_sizes[i] += 2;
       break;
     case SQL_DOUBLE:
       push_text("double");
-      /* odbc_fields[i].size = 8; */
-      /* odbc_fields[i].type = T_FLOAT; */
       break;
     case SQL_INTEGER:
       push_text("integer");
-      /* odbc_fields[i].size = 4; */
-      /* odbc_fields[i].type = T_INT; */
       break;
     case SQL_LONGVARBINARY:
       push_text("long blob");
+      if (odbc_field_sizes[i] > 0x100000) {
+	/* Don't allocate more than 1M */
+	odbc_field_sizes[i] = 0x100000;
+      }
       break;
     case SQL_LONGVARCHAR:
       push_text("var string");
+      if (odbc_field_sizes[i] > 0x100000) {
+	/* Don't allocate more than 1M */
+	odbc_field_sizes[i] = 0x100000;
+      }
       break;
     case SQL_REAL:
       push_text("float");
-      /* odbc_fields[i].size = 4; */
-      /* odbc_fields[i].type = T_FLOAT; */
       break;
     case SQL_SMALLINT:
       push_text("short");
-      /* odbc_fields[i].size = 4; */
-      /* odbc_fields[i].type = T_INT; */
       break;
     case SQL_TIMESTAMP:
       push_text("time");
-      odbc_fields[i].size = 22 + scale;
+      odbc_field_sizes[i] = 22 + scale;
       break;
     case SQL_VARCHAR:
       push_text("var string");
+      if (odbc_field_sizes[i] > 0x100000) {
+	/* Don't allocate more than 1M */
+	odbc_field_sizes[i] = 0x100000;
+      }
       break;
     default:
       push_text("unknown");
@@ -217,10 +230,10 @@ static void odbc_fix_fields(void)
     f_aggregate_mapping(5*2);
 
     /* Align to longlong-word size */
-    odbc_fields[i].size += 7;
-    odbc_fields[i].size &= ~7;
+    odbc_field_sizes[i] += 7;
+    odbc_field_sizes[i] &= ~7;
 
-    membuf_size += odbc_fields[i].size;
+    membuf_size += odbc_field_sizes[i];
   }
   f_aggregate(PIKE_ODBC_RES->num_fields);
 
@@ -237,35 +250,14 @@ static void odbc_fix_fields(void)
    * Now it's time to bind the columns
    */
   for (i=0; i < PIKE_ODBC_RES->num_fields; i++) {
-    PIKE_ODBC_RES->field_info[i].type = odbc_fields[i].type;
     PIKE_ODBC_RES->field_info[i].buf = membuf;
-    PIKE_ODBC_RES->field_info[i].size = odbc_fields[i].size;
+    PIKE_ODBC_RES->field_info[i].size = odbc_field_sizes[i];
     
-    switch(odbc_fields[i].type) {
-    case T_STRING:
-      odbc_check_error("odbc_fix_fields", "Couldn't bind string field",
-		       SQLBindCol(PIKE_ODBC_RES->hstmt, i+1,
-				  SQL_C_CHAR, membuf, odbc_fields[i].size,
-				  &PIKE_ODBC_RES->field_info[i].len), NULL);
-      break;
-    case T_INT:
-      odbc_check_error("odbc_fix_fields", "Couldn't bind integer field",
-		       SQLBindCol(PIKE_ODBC_RES->hstmt, i+1,
-				  SQL_C_SLONG, membuf, odbc_fields[i].size,
-				  &PIKE_ODBC_RES->field_info[i].len), NULL);
-      break;
-    case T_FLOAT:
-      odbc_check_error("odbc_fix_fields", "Couldn't bind float field",
-		       SQLBindCol(PIKE_ODBC_RES->hstmt, i+1,
-				  SQL_C_DOUBLE, membuf, odbc_fields[i].size,
-				  &PIKE_ODBC_RES->field_info[i].len), NULL);
-      break;
-    default:
-      error("odbc_fix_fields(): Internal error: Unhandled type:%d\n",
-	    odbc_fields[i].type);
-      break;
-    }
-    membuf += odbc_fields[i].size;
+    odbc_check_error("odbc_fix_fields", "Couldn't bind string field",
+		     SQLBindCol(PIKE_ODBC_RES->hstmt, i+1,
+				SQL_C_CHAR, membuf, odbc_field_sizes[i],
+				&PIKE_ODBC_RES->field_info[i].len), NULL);
+    membuf += odbc_field_sizes[i];
   }
 }
 
@@ -276,6 +268,8 @@ static void odbc_fix_fields(void)
 /* void create(object(odbc)) */
 static void f_create(INT32 args)
 {
+  HSTMT hstmt = SQL_NULL_HSTMT;
+
   if (!args) {
     error("Too few arguments to odbc_result()\n");
   }
@@ -285,23 +279,41 @@ static void f_create(INT32 args)
 						odbc_program)))) {
     error("Bad argument 1 to odbc_result()\n");
   }
- 
   add_ref(PIKE_ODBC_RES->obj = sp[-args].u.object);
-  PIKE_ODBC_RES->hstmt = PIKE_ODBC_RES->odbc->hstmt;
-  PIKE_ODBC_RES->odbc->hstmt = SQL_NULL_HSTMT;
-  
-  pop_n_elems(args);
- 
-  if (PIKE_ODBC_RES->hstmt == SQL_NULL_HSTMT) {
-    free_object(PIKE_ODBC_RES->obj);
-    PIKE_ODBC_RES->odbc = NULL;
-    PIKE_ODBC_RES->obj = NULL;
-    error("odbc_result(): No result to clone\n");
+
+  odbc_check_error("odbc_result", "Statement allocation failed",
+		   SQLAllocStmt(PIKE_ODBC_RES->odbc->hdbc, &hstmt), NULL);
+  PIKE_ODBC_RES->hstmt = hstmt;
+}
+
+static void f_execute(INT32 args)
+{
+  struct pike_string *q = NULL;
+  HSTMT hstmt = PIKE_ODBC_RES->hstmt;
+
+  get_all_args("odbc_result->execute", args, "%S", &q);
+
+  odbc_check_error("odbc_result->execute", "Query failed",
+		   SQLExecDirect(hstmt, (unsigned char *)q->str, q->len),
+		   NULL);
+
+  odbc_check_error("odbc_result->execute", "Couldn't get the number of fields",
+		   SQLNumResultCols(hstmt, &(PIKE_ODBC_RES->num_fields)),
+		   NULL);
+
+  odbc_check_error("odbc_result->execute", "Couldn't get the number of rows",
+		   SQLRowCount(hstmt, &(PIKE_ODBC_RES->num_rows)), NULL);
+
+  PIKE_ODBC_RES->odbc->affected_rows = PIKE_ODBC_RES->num_rows;
+
+  if (PIKE_ODBC_RES->num_fields) {
+    odbc_fix_fields();
   }
-  PIKE_ODBC_RES->num_fields = PIKE_ODBC_RES->odbc->num_fields;
-  PIKE_ODBC_RES->num_rows = PIKE_ODBC_RES->odbc->affected_rows;
-  
-  odbc_fix_fields();
+
+  pop_n_elems(args);
+
+  /* Result */
+  push_int(PIKE_ODBC_RES->num_fields);
 }
  
 /* int num_rows() */
@@ -345,22 +357,8 @@ static void f_fetch_row(INT32 args)
  
     for (i=0; i < PIKE_ODBC_RES->num_fields; i++) {
       if (PIKE_ODBC_RES->field_info[i].len != SQL_NULL_DATA) {
-	switch (PIKE_ODBC_RES->field_info[i].type) {
-	case T_INT:
-	  push_int(*((int *)PIKE_ODBC_RES->field_info[i].buf));
-	  break;
-	case T_FLOAT:
-	  push_float(*((double *)PIKE_ODBC_RES->field_info[i].buf));
-	  break;
-	case T_STRING:
-	  push_string(make_shared_binary_string(PIKE_ODBC_RES->field_info[i].buf,
-						PIKE_ODBC_RES->field_info[i].len));
-	  break;
-	default:
-	  error("odbc->fetch_row(): Internal error: Unknown type (%d)\n",
-		PIKE_ODBC_RES->field_info[i].type);
-	  break;
-	}
+	push_string(make_shared_binary_string(PIKE_ODBC_RES->field_info[i].buf,
+					      PIKE_ODBC_RES->field_info[i].len));
       } else {
 	/* NULL */
 	push_int(0);
@@ -407,8 +405,14 @@ void init_odbc_res_programs(void)
  
   start_new_program();
   add_storage(sizeof(struct precompiled_odbc_result));
+
+  map_variable("_odbc", "object", 0,
+	       OFFSETOF(precompiled_odbc_result, obj), T_OBJECT);
+  map_variable("_fields", "array(mapping(string:mixed))", 0,
+	       OFFSETOF(precompiled_odbc_result, fields), T_ARRAY);
  
   add_function("create", f_create, "function(object:void)", ID_PUBLIC);
+  add_function("execute", f_execute, "function(string:int)", ID_PUBLIC);
   add_function("num_rows", f_num_rows, "function(void:int)", ID_PUBLIC);
   add_function("num_fields", f_num_fields, "function(void:int)", ID_PUBLIC);
 #ifdef SUPPORT_FIELD_SEEK
diff --git a/src/modules/Odbc/precompiled_odbc.h b/src/modules/Odbc/precompiled_odbc.h
index d91f9d9828445478dc181472feb86df467420543..1eff0d3fbcc74ed210d4aee1ab4fd9bd7baa1d9d 100644
--- a/src/modules/Odbc/precompiled_odbc.h
+++ b/src/modules/Odbc/precompiled_odbc.h
@@ -1,5 +1,5 @@
 /*
- * $Id: precompiled_odbc.h,v 1.3 1997/11/02 22:19:35 grubba Exp $
+ * $Id: precompiled_odbc.h,v 1.4 1998/05/31 15:40:34 grubba Exp $
  *
  * Pike interface to ODBC compliant databases.
  *
@@ -37,18 +37,15 @@ extern struct program *odbc_result_program;
  */
 
 struct field_info {
-  int type;		/* Pike-type */
   SDWORD len;
   int size;		/* Size of buffer */
   void *buf;
 };
 
 struct precompiled_odbc {
-  HENV henv;
   HDBC hdbc;
-  HSTMT hstmt;
-  SWORD num_fields;
-  SDWORD affected_rows;
+  int affected_rows;
+  unsigned int flags;
   struct pike_string *last_error;
 };
 
@@ -56,8 +53,8 @@ struct precompiled_odbc_result {
   struct object *obj;
   struct precompiled_odbc *odbc;
   HSTMT hstmt;
-  int num_fields;
-  int num_rows;
+  SWORD num_fields;
+  SDWORD num_rows;
   struct array *fields;
   struct field_info *field_info;
 };
@@ -69,6 +66,9 @@ struct precompiled_odbc_result {
 #define PIKE_ODBC	((struct precompiled_odbc *)(fp->current_storage))
 #define PIKE_ODBC_RES	((struct precompiled_odbc_result *)(fp->current_storage))
 
+/* Flags */
+#define PIKE_ODBC_CONNECTED	1
+
 /*
  * Prototypes
  */