Replace zu with PRIu64 and llu with new macro, PRIsz, which will make it easier to...
[collectd.git] / src / oracle.c
index fa7e72f..bf6aef5 100644 (file)
@@ -1,6 +1,7 @@
 /**
  * collectd - src/oracle.c
- * Copyright (C) 2008  Florian octo Forster
+ * Copyright (C) 2008,2009  noris network AG
+ * Copyright (C) 2012       Florian octo Forster
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * affiliates. Other names may be trademarks of their respective owners.
  *
  * Authors:
- *   Florian octo Forster <octo at noris.net>
+ *   Florian octo Forster <octo at collectd.org>
  **/
 
 #include "collectd.h"
+
 #include "common.h"
 #include "plugin.h"
+#include "utils_db_query.h"
 
 #include <oci.h>
 
 /*
  * Data types
  */
-struct o_query_s
-{
-  char    *name;
-  char    *statement;
-  char    *type;
-  char   **instances;
-  size_t   instances_num;
-  char   **values;
-  size_t   values_num;
-
-  OCIStmt *oci_statement;
-};
-typedef struct o_query_s o_query_t;
-
-struct o_database_s
-{
+struct o_database_s {
   char *name;
+  char *host;
   char *connect_id;
   char *username;
   char *password;
+  char *plugin_name;
 
-  o_query_t **queries;
-  size_t      queries_num;
+  udb_query_preparation_area_t **q_prep_areas;
+  udb_query_t **queries;
+  size_t queries_num;
 
   OCISvcCtx *oci_service_context;
 };
@@ -84,87 +75,81 @@ typedef struct o_database_s o_database_t;
 /*
  * Global variables
  */
-static o_query_t    **queries       = NULL;
-static size_t         queries_num   = 0;
-static o_database_t **databases     = NULL;
-static size_t         databases_num = 0;
+static udb_query_t **queries = NULL;
+static size_t queries_num = 0;
+static o_database_t **databases = NULL;
+static size_t databases_num = 0;
 
-OCIEnv   *oci_env = NULL;
+OCIEnv *oci_env = NULL;
 OCIError *oci_error = NULL;
 
 /*
  * Functions
  */
-static void o_report_error (const char *where, /* {{{ */
-    const char *what, OCIError *eh)
-{
+static void o_report_error(const char *where, /* {{{ */
+                           const char *db_name, const char *query_name,
+                           const char *what, OCIError *eh) {
   char buffer[2048];
   sb4 error_code;
   int status;
 
-  status = OCIErrorGet (eh, /* record number = */ 1,
-      /* sqlstate = */ NULL,
-      &error_code,
-      (text *) &buffer[0],
-      (ub4) sizeof (buffer),
-      OCI_HTYPE_ERROR);
-  buffer[sizeof (buffer) - 1] = 0;
+  if (db_name == NULL)
+    db_name = "(none)";
+  if (query_name == NULL)
+    query_name = "(none)";
 
-  if (status == OCI_SUCCESS)
-  {
-    size_t buffer_length;
-
-    buffer_length = strlen (buffer);
-    while ((buffer_length > 0) && (buffer[buffer_length - 1] < 32))
-    {
-      buffer_length--;
-      buffer[buffer_length] = 0;
-    }
+  /* An operation may cause / return multiple errors. Loop until we have
+   * handled all errors available (with a fail-save limit of 16). */
+  for (unsigned int record_number = 1; record_number <= 16; record_number++) {
+    memset(buffer, 0, sizeof(buffer));
+    error_code = -1;
 
-    ERROR ("oracle plugin: %s: %s failed: %s",
-        where, what, buffer);
-  }
-  else
-  {
-    ERROR ("oracle plugin: %s: %s failed. Additionally, OCIErrorGet failed with status %i.",
-        where, what, status);
-  }
-} /* }}} void o_report_error */
+    status = OCIErrorGet(eh, (ub4)record_number,
+                         /* sqlstate = */ NULL, &error_code, (text *)&buffer[0],
+                         (ub4)sizeof(buffer), OCI_HTYPE_ERROR);
+    buffer[sizeof(buffer) - 1] = 0;
 
-static void o_query_free (o_query_t *q) /* {{{ */
-{
-  size_t i;
-
-  if (q == NULL)
-    return;
-
-  sfree (q->name);
-  sfree (q->statement);
-  sfree (q->type);
+    if (status == OCI_NO_DATA)
+      return;
 
-  for (i = 0; i < q->instances_num; i++)
-    sfree (q->instances[i]);
-  sfree (q->instances);
+    if (status == OCI_SUCCESS) {
+      size_t buffer_length;
 
-  for (i = 0; i < q->values_num; i++)
-    sfree (q->values[i]);
-  sfree (q->values);
+      buffer_length = strlen(buffer);
+      while ((buffer_length > 0) && (buffer[buffer_length - 1] < 32)) {
+        buffer_length--;
+        buffer[buffer_length] = 0;
+      }
 
-  sfree (q);
-} /* }}} void o_query_free */
+      ERROR("oracle plugin: %s (db = %s, query = %s): %s failed: %s", where,
+            db_name, query_name, what, buffer);
+    } else {
+      ERROR("oracle plugin: %s (db = %s, query = %s): %s failed. "
+            "Additionally, OCIErrorGet failed with status %i.",
+            where, db_name, query_name, what, status);
+      return;
+    }
+  }
+} /* }}} void o_report_error */
 
-static void o_database_free (o_database_t *db) /* {{{ */
+static void o_database_free(o_database_t *db) /* {{{ */
 {
   if (db == NULL)
     return;
 
-  sfree (db->name);
-  sfree (db->connect_id);
-  sfree (db->username);
-  sfree (db->password);
-  sfree (db->queries);
+  sfree(db->name);
+  sfree(db->connect_id);
+  sfree(db->username);
+  sfree(db->password);
+  sfree(db->queries);
+  sfree(db->plugin_name);
+
+  if (db->q_prep_areas != NULL)
+    for (size_t i = 0; i < db->queries_num; ++i)
+      udb_query_delete_preparation_area(db->q_prep_areas[i]);
+  free(db->q_prep_areas);
 
-  sfree (db);
+  sfree(db);
 } /* }}} void o_database_free */
 
 /* Configuration handling functions {{{
@@ -172,11 +157,13 @@ static void o_database_free (o_database_t *db) /* {{{ */
  * <Plugin oracle>
  *   <Query "plugin_instance0">
  *     Statement "SELECT name, value FROM table"
- *     Type "gauge"
- *     InstancesFrom "name"
- *     ValuesFrom "value"
+ *     <Result>
+ *       Type "gauge"
+ *       InstancesFrom "name"
+ *       ValuesFrom "value"
+ *     </Result>
  *   </Query>
- *     
+ *
  *   <Database "plugin_instance1">
  *     ConnectID "db01"
  *     Username "oracle"
@@ -186,128 +173,54 @@ static void o_database_free (o_database_t *db) /* {{{ */
  * </Plugin>
  */
 
-static int o_config_set_string (char **ret_string, /* {{{ */
-    oconfig_item_t *ci)
-{
-  char *string;
-
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("oracle plugin: The `%s' config option "
-        "needs exactly one string argument.", ci->key);
-    return (-1);
-  }
-
-  string = strdup (ci->values[0].value.string);
-  if (string == NULL)
-  {
-    ERROR ("oracle plugin: strdup failed.");
-    return (-1);
-  }
-
-  if (*ret_string != NULL)
-    free (*ret_string);
-  *ret_string = string;
-
-  return (0);
-} /* }}} int o_config_set_string */
-
-static int o_config_add_string (char ***ret_array, /* {{{ */
-    size_t *ret_array_len, oconfig_item_t *ci)
+static int o_config_add_database(oconfig_item_t *ci) /* {{{ */
 {
-  char **array;
-  size_t array_len;
-  int i;
-
-  if (ci->values_num < 1)
-  {
-    WARNING ("oracle plugin: The `%s' config option "
-        "needs at least one argument.", ci->key);
-    return (-1);
-  }
-
-  for (i = 0; i < ci->values_num; i++)
-  {
-    if (ci->values[i].type != OCONFIG_TYPE_STRING)
-    {
-      WARNING ("oracle plugin: Argument %i to the `%s' option "
-          "is not a string.", i + 1, ci->key);
-      return (-1);
-    }
-  }
-
-  array_len = *ret_array_len;
-  array = (char **) realloc (*ret_array,
-      sizeof (char *) * (array_len + ci->values_num));
-  if (array == NULL)
-  {
-    ERROR ("oracle plugin: realloc failed.");
-    return (-1);
-  }
-  *ret_array = array;
-
-  for (i = 0; i < ci->values_num; i++)
-  {
-    array[array_len] = strdup (ci->values[i].value.string);
-    if (array[array_len] == NULL)
-    {
-      ERROR ("oracle plugin: strdup failed.");
-      *ret_array_len = array_len;
-      return (-1);
-    }
-    array_len++;
-  }
-
-  *ret_array_len = array_len;
-  return (0);
-} /* }}} int o_config_add_string */
-
-static int o_config_add_query (oconfig_item_t *ci) /* {{{ */
-{
-  o_query_t *q;
+  o_database_t *db;
   int status;
-  int i;
 
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("oracle plugin: The `Query' block "
-        "needs exactly one string argument.");
-    return (-1);
+  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
+    WARNING("oracle plugin: The `Database' block "
+            "needs exactly one string argument.");
+    return -1;
   }
 
-  q = (o_query_t *) malloc (sizeof (*q));
-  if (q == NULL)
-  {
-    ERROR ("oracle plugin: malloc failed.");
-    return (-1);
+  db = calloc(1, sizeof(*db));
+  if (db == NULL) {
+    ERROR("oracle plugin: calloc failed.");
+    return -1;
   }
-  memset (q, 0, sizeof (*q));
+  db->name = NULL;
+  db->host = NULL;
+  db->connect_id = NULL;
+  db->username = NULL;
+  db->password = NULL;
+  db->plugin_name = NULL;
 
-  status = o_config_set_string (&q->name, ci);
-  if (status != 0)
-  {
-    sfree (q);
-    return (status);
+  status = cf_util_get_string(ci, &db->name);
+  if (status != 0) {
+    sfree(db);
+    return status;
   }
 
-  /* Fill the `o_query_t' structure.. */
-  for (i = 0; i < ci->children_num; i++)
-  {
+  /* Fill the `o_database_t' structure.. */
+  for (int i = 0; i < ci->children_num; i++) {
     oconfig_item_t *child = ci->children + i;
 
-    if (strcasecmp ("Statement", child->key) == 0)
-      status = o_config_set_string (&q->statement, child);
-    else if (strcasecmp ("Type", child->key) == 0)
-      status = o_config_set_string (&q->type, child);
-    else if (strcasecmp ("InstancesFrom", child->key) == 0)
-      status = o_config_add_string (&q->instances, &q->instances_num, child);
-    else if (strcasecmp ("ValuesFrom", child->key) == 0)
-      status = o_config_add_string (&q->values, &q->values_num, child);
-    else
-    {
-      WARNING ("oracle plugin: Option `%s' not allowed here.", child->key);
+    if (strcasecmp("ConnectID", child->key) == 0)
+      status = cf_util_get_string(child, &db->connect_id);
+    else if (strcasecmp("Host", child->key) == 0)
+      status = cf_util_get_string(child, &db->host);
+    else if (strcasecmp("Username", child->key) == 0)
+      status = cf_util_get_string(child, &db->username);
+    else if (strcasecmp("Password", child->key) == 0)
+      status = cf_util_get_string(child, &db->password);
+    else if (strcasecmp("Plugin", child->key) == 0)
+      status = cf_util_get_string(child, &db->plugin_name);
+    else if (strcasecmp("Query", child->key) == 0)
+      status = udb_query_pick_from_list(child, queries, queries_num,
+                                        &db->queries, &db->queries_num);
+    else {
+      WARNING("oracle plugin: Option `%s' not allowed here.", child->key);
       status = -1;
     }
 
@@ -316,712 +229,485 @@ static int o_config_add_query (oconfig_item_t *ci) /* {{{ */
   }
 
   /* Check that all necessary options have been given. */
-  while (status == 0)
-  {
-    if (q->statement == NULL)
-    {
-      WARNING ("oracle plugin: `Statement' not given for query `%s'", q->name);
-      status = -1;
-    }
-    if (q->type == NULL)
-    {
-      WARNING ("oracle plugin: `Type' not given for query `%s'", q->name);
+  while (status == 0) {
+    if (db->connect_id == NULL) {
+      WARNING("oracle plugin: `ConnectID' not given for query `%s'", db->name);
       status = -1;
     }
-    if (q->instances == NULL)
-    {
-      WARNING ("oracle plugin: `InstancesFrom' not given for query `%s'", q->name);
+    if (db->username == NULL) {
+      WARNING("oracle plugin: `Username' not given for query `%s'", db->name);
       status = -1;
     }
-    if (q->values == NULL)
-    {
-      WARNING ("oracle plugin: `ValuesFrom' not given for query `%s'", q->name);
+    if (db->password == NULL) {
+      WARNING("oracle plugin: `Password' not given for query `%s'", db->name);
       status = -1;
     }
 
     break;
   } /* while (status == 0) */
 
-  /* If all went well, add this query to the list of queries within the
-   * database structure. */
-  if (status == 0)
-  {
-    o_query_t **temp;
+  while ((status == 0) && (db->queries_num > 0)) {
+    db->q_prep_areas = (udb_query_preparation_area_t **)calloc(
+        db->queries_num, sizeof(*db->q_prep_areas));
 
-    temp = (o_query_t **) realloc (queries,
-        sizeof (*queries) * (queries_num + 1));
-    if (temp == NULL)
-    {
-      ERROR ("oracle plugin: realloc failed");
+    if (db->q_prep_areas == NULL) {
+      WARNING("oracle plugin: calloc failed");
       status = -1;
-    }
-    else
-    {
-      queries = temp;
-      queries[queries_num] = q;
-      queries_num++;
-    }
-  }
-
-  if (status != 0)
-  {
-    o_query_free (q);
-    return (-1);
-  }
-
-  return (0);
-} /* }}} int o_config_add_query */
-
-static int o_config_add_database_query (o_database_t *db, /* {{{ */
-    oconfig_item_t *ci)
-{
-  o_query_t *q;
-  o_query_t **temp;
-  size_t i;
-
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("oracle plugin: The `Query' config option "
-        "needs exactly one string argument.");
-    return (-1);
-  }
-
-  q = NULL;
-  for (i = 0; i < queries_num; i++)
-  {
-    if (strcasecmp (queries[i]->name, ci->values[0].value.string) == 0)
-    {
-      q = queries[i];
       break;
     }
-  }
-
-  if (q == NULL)
-  {
-    WARNING ("oracle plugin: Database `%s': Unknown query `%s'. "
-        "Please make sure that the <Query \"%s\"> block comes before "
-        "the <Database \"%s\"> block.",
-        db->name, ci->values[0].value.string,
-        ci->values[0].value.string, db->name);
-    return (-1);
-  }
-
-  temp = (o_query_t **) realloc (db->queries,
-      sizeof (*db->queries) * (db->queries_num + 1));
-  if (temp == NULL)
-  {
-    ERROR ("oracle plugin: realloc failed");
-    return (-1);
-  }
-  else
-  {
-    db->queries = temp;
-    db->queries[db->queries_num] = q;
-    db->queries_num++;
-  }
-
-  return (0);
-} /* }}} int o_config_add_database_query */
 
-static int o_config_add_database (oconfig_item_t *ci) /* {{{ */
-{
-  o_database_t *db;
-  int status;
-  int i;
-
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("oracle plugin: The `Database' block "
-        "needs exactly one string argument.");
-    return (-1);
-  }
+    for (int i = 0; i < db->queries_num; ++i) {
+      db->q_prep_areas[i] = udb_query_allocate_preparation_area(db->queries[i]);
 
-  db = (o_database_t *) malloc (sizeof (*db));
-  if (db == NULL)
-  {
-    ERROR ("oracle plugin: malloc failed.");
-    return (-1);
-  }
-  memset (db, 0, sizeof (*db));
-
-  status = o_config_set_string (&db->name, ci);
-  if (status != 0)
-  {
-    sfree (db);
-    return (status);
-  }
-
-  /* Fill the `o_database_t' structure.. */
-  for (i = 0; i < ci->children_num; i++)
-  {
-    oconfig_item_t *child = ci->children + i;
-
-    if (strcasecmp ("ConnectID", child->key) == 0)
-      status = o_config_set_string (&db->connect_id, child);
-    else if (strcasecmp ("Username", child->key) == 0)
-      status = o_config_set_string (&db->username, child);
-    else if (strcasecmp ("Password", child->key) == 0)
-      status = o_config_set_string (&db->password, child);
-    else if (strcasecmp ("Query", child->key) == 0)
-      status = o_config_add_database_query (db, child);
-    else
-    {
-      WARNING ("oracle plugin: Option `%s' not allowed here.", child->key);
-      status = -1;
-    }
-
-    if (status != 0)
-      break;
-  }
-
-  /* Check that all necessary options have been given. */
-  while (status == 0)
-  {
-    if (db->connect_id == NULL)
-    {
-      WARNING ("oracle plugin: `ConnectID' not given for query `%s'", db->name);
-      status = -1;
-    }
-    if (db->username == NULL)
-    {
-      WARNING ("oracle plugin: `Username' not given for query `%s'", db->name);
-      status = -1;
-    }
-    if (db->password == NULL)
-    {
-      WARNING ("oracle plugin: `Password' not given for query `%s'", db->name);
-      status = -1;
+      if (db->q_prep_areas[i] == NULL) {
+        WARNING("oracle plugin: udb_query_allocate_preparation_area failed");
+        status = -1;
+        break;
+      }
     }
 
     break;
-  } /* while (status == 0) */
+  }
 
   /* If all went well, add this query to the list of queries within the
    * database structure. */
-  if (status == 0)
-  {
+  if (status == 0) {
     o_database_t **temp;
 
-    temp = (o_database_t **) realloc (databases,
-        sizeof (*databases) * (databases_num + 1));
-    if (temp == NULL)
-    {
-      ERROR ("oracle plugin: realloc failed");
+    temp = realloc(databases, sizeof(*databases) * (databases_num + 1));
+    if (temp == NULL) {
+      ERROR("oracle plugin: realloc failed");
       status = -1;
-    }
-    else
-    {
+    } else {
       databases = temp;
       databases[databases_num] = db;
       databases_num++;
     }
   }
 
-  if (status != 0)
-  {
-    o_database_free (db);
-    return (-1);
+  if (status != 0) {
+    o_database_free(db);
+    return -1;
   }
 
-  return (0);
+  return 0;
 } /* }}} int o_config_add_database */
 
-static int o_config (oconfig_item_t *ci) /* {{{ */
+static int o_config(oconfig_item_t *ci) /* {{{ */
 {
-  int i;
-
-  for (i = 0; i < ci->children_num; i++)
-  {
+  for (int i = 0; i < ci->children_num; i++) {
     oconfig_item_t *child = ci->children + i;
-    if (strcasecmp ("Query", child->key) == 0)
-      o_config_add_query (child);
-    else if (strcasecmp ("Database", child->key) == 0)
-      o_config_add_database (child);
-    else
-    {
-      WARNING ("snmp plugin: Ignoring unknown config option `%s'.", child->key);
+    if (strcasecmp("Query", child->key) == 0)
+      udb_query_create(&queries, &queries_num, child,
+                       /* callback = */ NULL);
+    else if (strcasecmp("Database", child->key) == 0)
+      o_config_add_database(child);
+    else {
+      WARNING("oracle plugin: Ignoring unknown config option `%s'.",
+              child->key);
+    }
+
+    if (queries_num > 0) {
+      DEBUG(
+          "oracle plugin: o_config: queries_num = %" PRIsz "; queries[0] = %p; "
+          "udb_query_get_user_data (queries[0]) = %p;",
+          queries_num, (void *)queries[0], udb_query_get_user_data(queries[0]));
     }
   } /* for (ci->children) */
 
-  return (0);
+  return 0;
 } /* }}} int o_config */
 
 /* }}} End of configuration handling functions */
 
-static int o_init (void) /* {{{ */
+static int o_init(void) /* {{{ */
 {
   int status;
 
   if (oci_env != NULL)
-    return (0);
-
-  status = OCIEnvCreate (&oci_env,
-      /* mode = */ OCI_THREADED,
-      /* context        = */ NULL,
-      /* malloc         = */ NULL,
-      /* realloc        = */ NULL,
-      /* free           = */ NULL,
-      /* user_data_size = */ 0,
-      /* user_data_ptr  = */ NULL);
-  if (status != 0)
-  {
-    ERROR ("oracle plugin: OCIEnvCreate failed with status %i.", status);
-    return (-1);
-  }
-
-  status = OCIHandleAlloc (oci_env, (void *) &oci_error, OCI_HTYPE_ERROR,
-      /* user_data_size = */ 0, /* user_data = */ NULL);
-  if (status != OCI_SUCCESS)
-  {
-    ERROR ("oracle plugin: OCIHandleAlloc (OCI_HTYPE_ERROR) failed "
-        "with status %i.", status);
-    return (-1);
-  }
-
-  return (0);
+    return 0;
+
+  status = OCIEnvCreate(&oci_env,
+                        /* mode = */ OCI_THREADED,
+                        /* context        = */ NULL,
+                        /* malloc         = */ NULL,
+                        /* realloc        = */ NULL,
+                        /* free           = */ NULL,
+                        /* user_data_size = */ 0,
+                        /* user_data_ptr  = */ NULL);
+  if (status != 0) {
+    ERROR("oracle plugin: OCIEnvCreate failed with status %i.", status);
+    return -1;
+  }
+
+  status = OCIHandleAlloc(oci_env, (void *)&oci_error, OCI_HTYPE_ERROR,
+                          /* user_data_size = */ 0, /* user_data = */ NULL);
+  if (status != OCI_SUCCESS) {
+    ERROR("oracle plugin: OCIHandleAlloc (OCI_HTYPE_ERROR) failed "
+          "with status %i.",
+          status);
+    return -1;
+  }
+
+  return 0;
 } /* }}} int o_init */
 
-static void o_submit (o_database_t *db, o_query_t *q, /* {{{ */
-    const data_set_t *ds, char **buffer_instances, char **buffer_values)
-{
-  value_list_t vl = VALUE_LIST_INIT;
-  size_t i;
-
-  assert (((size_t) ds->ds_num) == q->values_num);
+static int o_read_database_query(o_database_t *db, /* {{{ */
+                                 udb_query_t *q,
+                                 udb_query_preparation_area_t *prep_area) {
+  char **column_names;
+  char **column_values;
+  size_t column_num;
 
-  vl.values = (value_t *) malloc (sizeof (value_t) * q->values_num);
-  if (vl.values == NULL)
-  {
-    ERROR ("oracle plugin: malloc failed.");
-    return;
-  }
-  vl.values_len = ds->ds_num;
-
-  for (i = 0; i < q->values_num; i++)
-  {
-    char *endptr;
-
-    endptr = NULL;
-    errno = 0;
-    if (ds->ds[i].type == DS_TYPE_COUNTER)
-      vl.values[i].counter = (counter_t) strtoll (buffer_values[i],
-          &endptr, /* base = */ 0);
-    else if (ds->ds[i].type == DS_TYPE_GAUGE)
-      vl.values[i].gauge = (gauge_t) strtod (buffer_values[i], &endptr);
-    else
-      errno = EINVAL;
-
-    if ((endptr == buffer_values[i]) || (errno != 0))
-    {
-      WARNING ("oracle plugin: o_submit: Parsing `%s' as %s failed.",
-          buffer_values[i],
-          (ds->ds[i].type == DS_TYPE_COUNTER) ? "counter" : "gauge");
-      vl.values[i].gauge = NAN;
-    }
-  }
-
-  vl.time = time (NULL);
-  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
-  sstrncpy (vl.plugin, "oracle", sizeof (vl.plugin));
-  sstrncpy (vl.plugin_instance, db->name, sizeof (vl.type_instance));
-  sstrncpy (vl.type, q->type, sizeof (vl.type));
-  strjoin (vl.type_instance, sizeof (vl.type_instance),
-      buffer_instances, q->instances_num, "-");
-  vl.type_instance[sizeof (vl.type_instance) - 1] = 0;
-
-  plugin_dispatch_values (&vl);
-} /* }}} void o_submit */
-
-static int o_read_database_query (o_database_t *db, /* {{{ */
-    o_query_t *q)
-{
-  const data_set_t *ds;
-  ub4 param_counter; /* == number of columns */
-  int status;
-  size_t i;
-  ub4 j;
-
-  /* Scratch area for OCI to write values to */
-  char **buffer_instances;
-  char **buffer_values;
-
-  /* List of indizes of the instance and value columns. Only used for error
-   * checking. */
-  size_t *index_instances;
-  size_t *index_values;
+  OCIStmt *oci_statement;
 
   /* List of `OCIDefine' pointers. These defines map columns to the buffer
- * space declared above. */
  * space declared above. */
   OCIDefine **oci_defines;
 
-  ds = plugin_get_ds (q->type); /* {{{ */
-  if (ds == NULL)
-  {
-    WARNING ("oracle plugin: o_read_database_query (%s, %s): "
-        "plugin_get_ds (%s) failed. Please check if the type exists, "
-        "see types.db(5).",
-        db->name, q->name, q->type);
-    return (-1);
-  } /* }}} */
+  int status;
 
-  if (((size_t) ds->ds_num) != q->values_num)
-  {
-    ERROR ("oracle plugin: o_read_database_query (%s, %s): "
-        "The query `%s' uses the type `%s' which requires exactly "
-        "%i value%s, but you specified %zu value-column%s. "
-        "See types.db(5) for details.",
-        db->name, q->name,
-        q->name, q->type,
-        ds->ds_num, (ds->ds_num == 1) ? "" : "s",
-        q->values_num, (q->values_num == 1) ? "" : "s");
-    return (-1);
-  }
+  oci_statement = udb_query_get_user_data(q);
 
   /* Prepare the statement */
-  if (q->oci_statement == NULL) /* {{{ */
-  {
-    status = OCIHandleAlloc (oci_env, (void *) &q->oci_statement,
-        OCI_HTYPE_STMT, /* user_data_size = */ 0, /* user_data = */ NULL);
-    if (status != OCI_SUCCESS)
-    {
-      o_report_error ("o_read_database_query", "OCIHandleAlloc", oci_error);
-      q->oci_statement = NULL;
-      return (-1);
-    }
-
-    status = OCIStmtPrepare (q->oci_statement, oci_error,
-        (text *) q->statement, (ub4) strlen (q->statement),
-        /* language = */ OCI_NTV_SYNTAX,
-        /* mode     = */ OCI_DEFAULT);
-    if (status != OCI_SUCCESS)
-    {
-      o_report_error ("o_read_database_query", "OCIStmtPrepare", oci_error);
-      OCIHandleFree (q->oci_statement, OCI_HTYPE_STMT);
-      q->oci_statement = NULL;
-      return (-1);
-    }
-    assert (q->oci_statement != NULL);
+  if (oci_statement == NULL) /* {{{ */
+  {
+    const char *statement;
+
+    statement = udb_query_get_statement(q);
+    assert(statement != NULL);
+
+    status = OCIHandleAlloc(oci_env, (void *)&oci_statement, OCI_HTYPE_STMT,
+                            /* user_data_size = */ 0, /* user_data = */ NULL);
+    if (status != OCI_SUCCESS) {
+      o_report_error("o_read_database_query", db->name, udb_query_get_name(q),
+                     "OCIHandleAlloc", oci_error);
+      oci_statement = NULL;
+      return -1;
+    }
+
+    status = OCIStmtPrepare(oci_statement, oci_error, (text *)statement,
+                            (ub4)strlen(statement),
+                            /* language = */ OCI_NTV_SYNTAX,
+                            /* mode     = */ OCI_DEFAULT);
+    if (status != OCI_SUCCESS) {
+      o_report_error("o_read_database_query", db->name, udb_query_get_name(q),
+                     "OCIStmtPrepare", oci_error);
+      OCIHandleFree(oci_statement, OCI_HTYPE_STMT);
+      oci_statement = NULL;
+      return -1;
+    }
+    udb_query_set_user_data(q, oci_statement);
+
+    DEBUG("oracle plugin: o_read_database_query (%s, %s): "
+          "Successfully allocated statement handle.",
+          db->name, udb_query_get_name(q));
   } /* }}} */
 
+  assert(oci_statement != NULL);
+
   /* Execute the statement */
-  status = OCIStmtExecute (db->oci_service_context, /* {{{ */
-      q->oci_statement,
-      oci_error,
-      /* iters = */ 0,
-      /* rowoff = */ 0,
-      /* snap_in = */ NULL, /* snap_out = */ NULL,
-      /* mode = */ OCI_DEFAULT);
-  if (status != OCI_SUCCESS)
-  {
-    o_report_error ("o_read_database_query", "OCIStmtExecute", oci_error);
-    ERROR ("oracle plugin: o_read_database_query: "
-        "Failing statement was: %s", q->statement);
-    return (-1);
+  status = OCIStmtExecute(db->oci_service_context, /* {{{ */
+                          oci_statement, oci_error,
+                          /* iters = */ 0,
+                          /* rowoff = */ 0,
+                          /* snap_in = */ NULL, /* snap_out = */ NULL,
+                          /* mode = */ OCI_DEFAULT);
+  if (status != OCI_SUCCESS) {
+    o_report_error("o_read_database_query", db->name, udb_query_get_name(q),
+                   "OCIStmtExecute", oci_error);
+    return -1;
   } /* }}} */
 
   /* Acquire the number of columns returned. */
-  param_counter = 0;
-  status = OCIAttrGet (q->oci_statement, OCI_HTYPE_STMT, /* {{{ */
-      &param_counter, /* size pointer = */ NULL, 
-      OCI_ATTR_PARAM_COUNT, oci_error);
-  if (status != OCI_SUCCESS)
-  {
-    o_report_error ("o_read_database_query", "OCIAttrGet", oci_error);
-    return (-1);
-  } /* }}} */
-
-  /* Allocate the following buffers:
-   * 
-   *  - buffer_instances    q->instances_num x DATA_MAX_NAME_LEN
-   *  - buffer_values       q->values_num    x NUMBER_BUFFER_SIZE
-   *  - index_instances     q->instances_num
-   *  - index_values        q->values_num
-   *  - oci_defines         q->instances_num+q->values_num
-   * {{{ */
+  do /* {{{ */
+  {
+    ub4 param_counter = 0;
+    status = OCIAttrGet(oci_statement, OCI_HTYPE_STMT, /* {{{ */
+                        &param_counter, /* size pointer = */ NULL,
+                        OCI_ATTR_PARAM_COUNT, oci_error);
+    if (status != OCI_SUCCESS) {
+      o_report_error("o_read_database_query", db->name, udb_query_get_name(q),
+                     "OCIAttrGet", oci_error);
+      return -1;
+    } /* }}} */
+
+    column_num = (size_t)param_counter;
+  } while (0); /* }}} */
+
+/* Allocate the following buffers:
+ *
+ *  +---------------+-----------------------------------+
+ *  ! Name          ! Size                              !
+ *  +---------------+-----------------------------------+
+ *  ! column_names  ! column_num x DATA_MAX_NAME_LEN    !
+ *  ! column_values ! column_num x DATA_MAX_NAME_LEN    !
+ *  ! oci_defines   ! column_num x sizeof (OCIDefine *) !
+ *  +---------------+-----------------------------------+
+ *
+ * {{{ */
 #define NUMBER_BUFFER_SIZE 64
 
-#define FREE_ALL \
-  if (buffer_instances != NULL) { \
-    sfree (buffer_instances[0]); \
-    sfree (buffer_instances); \
-  } \
-  if (buffer_values != NULL) { \
-    sfree (buffer_values[0]); \
-    sfree (buffer_values); \
-  } \
-  sfree (index_instances); \
-  sfree (index_values); \
-  sfree (oci_defines)
-
-#define ALLOC_OR_FAIL(ptr, ptr_size) \
-  do { \
-    size_t alloc_size = (size_t) ((ptr_size)); \
-    (ptr) = malloc (alloc_size); \
-    if ((ptr) == NULL) { \
-      FREE_ALL; \
-      ERROR ("oracle plugin: o_read_database_query: malloc failed."); \
-      return (-1); \
-    } \
-    memset ((ptr), 0, alloc_size); \
+#define FREE_ALL                                                               \
+  if (column_names != NULL) {                                                  \
+    sfree(column_names[0]);                                                    \
+    sfree(column_names);                                                       \
+  }                                                                            \
+  if (column_values != NULL) {                                                 \
+    sfree(column_values[0]);                                                   \
+    sfree(column_values);                                                      \
+  }                                                                            \
+  sfree(oci_defines)
+
+#define ALLOC_OR_FAIL(ptr, ptr_size)                                           \
+  do {                                                                         \
+    size_t alloc_size = (size_t)((ptr_size));                                  \
+    (ptr) = calloc(1, alloc_size);                                             \
+    if ((ptr) == NULL) {                                                       \
+      FREE_ALL;                                                                \
+      ERROR("oracle plugin: o_read_database_query: calloc failed.");           \
+      return -1;                                                               \
+    }                                                                          \
   } while (0)
 
   /* Initialize everything to NULL so the above works. */
-  buffer_instances = NULL;
-  buffer_values    = NULL;
-  index_instances  = NULL;
-  index_values     = NULL;
-  oci_defines      = NULL;
-
-  ALLOC_OR_FAIL (buffer_instances, q->instances_num * sizeof (char *));
-  ALLOC_OR_FAIL (buffer_instances[0], q->instances_num * DATA_MAX_NAME_LEN
-      * sizeof (char));
-  for (i = 1; i < q->instances_num; i++)
-    buffer_instances[i] = buffer_instances[i - 1] + DATA_MAX_NAME_LEN;
-
-  ALLOC_OR_FAIL (buffer_values, q->values_num * sizeof (char *));
-  ALLOC_OR_FAIL (buffer_values[0], q->values_num * NUMBER_BUFFER_SIZE
-      * sizeof (char));
-  for (i = 1; i < q->values_num; i++)
-    buffer_values[i] = buffer_values[i - 1] + NUMBER_BUFFER_SIZE;
-
-  ALLOC_OR_FAIL (index_instances, q->instances_num * sizeof (size_t));
-  ALLOC_OR_FAIL (index_values, q->values_num * sizeof (size_t));
-
-  ALLOC_OR_FAIL (oci_defines, (q->instances_num + q->values_num)
-      * sizeof (OCIDefine *));
+  column_names = NULL;
+  column_values = NULL;
+  oci_defines = NULL;
+
+  ALLOC_OR_FAIL(column_names, column_num * sizeof(char *));
+  ALLOC_OR_FAIL(column_names[0], column_num * DATA_MAX_NAME_LEN);
+  for (size_t i = 1; i < column_num; i++)
+    column_names[i] = column_names[i - 1] + DATA_MAX_NAME_LEN;
+
+  ALLOC_OR_FAIL(column_values, column_num * sizeof(char *));
+  ALLOC_OR_FAIL(column_values[0], column_num * DATA_MAX_NAME_LEN);
+  for (size_t i = 1; i < column_num; i++)
+    column_values[i] = column_values[i - 1] + DATA_MAX_NAME_LEN;
+
+  ALLOC_OR_FAIL(oci_defines, column_num * sizeof(OCIDefine *));
   /* }}} End of buffer allocations. */
 
   /* ``Define'' the returned data, i. e. bind the columns to the buffers
-   * returned above. */
-  for (j = 1; j <= param_counter; j++) /* {{{ */
+   * allocated above. */
+  for (size_t i = 0; i < column_num; i++) /* {{{ */
   {
     char *column_name;
-    size_t column_name_length;
-    char column_name_copy[DATA_MAX_NAME_LEN];
-    size_t i;
+    ub4 column_name_length;
     OCIParam *oci_param;
 
     oci_param = NULL;
 
-    status = OCIParamGet (q->oci_statement, OCI_HTYPE_STMT, oci_error,
-        (void *) &oci_param, j);
-    if (status != OCI_SUCCESS)
-    {
+    status = OCIParamGet(oci_statement, OCI_HTYPE_STMT, oci_error,
+                         (void *)&oci_param, (ub4)(i + 1));
+    if (status != OCI_SUCCESS) {
       /* This is probably alright */
-      DEBUG ("oracle plugin: o_read_database_query: status = %#x (= %i);", status, status);
-      o_report_error ("o_read_database_query", "OCIParamGet", oci_error);
+      DEBUG("oracle plugin: o_read_database_query: status = %#x (= %i);",
+            status, status);
+      o_report_error("o_read_database_query", db->name, udb_query_get_name(q),
+                     "OCIParamGet", oci_error);
       status = OCI_SUCCESS;
       break;
     }
 
     column_name = NULL;
     column_name_length = 0;
-    status = OCIAttrGet (oci_param, OCI_DTYPE_PARAM,
-        &column_name, &column_name_length, OCI_ATTR_NAME, oci_error);
-    if (status != OCI_SUCCESS)
-    {
-      o_report_error ("o_read_database_query", "OCIAttrGet (OCI_ATTR_NAME)",
-          oci_error);
+    status = OCIAttrGet(oci_param, OCI_DTYPE_PARAM, &column_name,
+                        &column_name_length, OCI_ATTR_NAME, oci_error);
+    if (status != OCI_SUCCESS) {
+      OCIDescriptorFree(oci_param, OCI_DTYPE_PARAM);
+      o_report_error("o_read_database_query", db->name, udb_query_get_name(q),
+                     "OCIAttrGet (OCI_ATTR_NAME)", oci_error);
       continue;
     }
 
-    /* Ensure null-termination. */
-    memset (column_name_copy, 0, sizeof (column_name_copy));
-    if (column_name_length >= sizeof (column_name_copy))
-      column_name_length = sizeof (column_name_copy) - 1;
-    memcpy (column_name_copy, column_name, column_name_length);
-    column_name_copy[column_name_length] = 0;
-
-    DEBUG ("oracle plugin: o_read_database_query: column_name[%u] = %s; column_name_length = %zu;",
-        (unsigned int) j, column_name_copy, column_name_length);
-
-    for (i = 0; i < q->instances_num; i++)
-    {
-      if (strcasecmp (q->instances[i], column_name_copy) != 0)
-        continue;
-
-      status = OCIDefineByPos (q->oci_statement,
-          &oci_defines[i], oci_error, j,
-          buffer_instances[i], DATA_MAX_NAME_LEN, SQLT_STR,
-          NULL, NULL, NULL, OCI_DEFAULT);
-      index_instances[i] = j;
-
-      DEBUG ("oracle plugin: o_read_database_query: column[%u] (%s) -> instances[%zu]",
-          (unsigned int) j, column_name_copy, i);
-      break;
-    }
-
-    for (i = 0; i < q->values_num; i++)
-    {
-      if (strcasecmp (q->values[i], column_name_copy) != 0)
-        continue;
-
-      status = OCIDefineByPos (q->oci_statement,
-          &oci_defines[q->instances_num + i], oci_error, j,
-          buffer_values[i], NUMBER_BUFFER_SIZE, SQLT_STR,
-          NULL, NULL, NULL, OCI_DEFAULT);
-      index_values[i] = j;
+    OCIDescriptorFree(oci_param, OCI_DTYPE_PARAM);
+    oci_param = NULL;
 
-      DEBUG ("oracle plugin: o_read_database_query: column[%u] (%s) -> values[%zu]",
-          (unsigned int) j, column_name_copy, i);
-      break;
+    /* Copy the name to column_names. Warning: The ``string'' returned by OCI
+     * may not be null terminated! */
+    memset(column_names[i], 0, DATA_MAX_NAME_LEN);
+    if (column_name_length >= DATA_MAX_NAME_LEN)
+      column_name_length = DATA_MAX_NAME_LEN - 1;
+    memcpy(column_names[i], column_name, column_name_length);
+    column_names[i][column_name_length] = 0;
+
+    DEBUG("oracle plugin: o_read_database_query: column_names[%" PRIsz "] = %s;"
+          " column_name_length = %" PRIu32 ";",
+          i, column_names[i], (uint32_t)column_name_length);
+
+    status = OCIDefineByPos(oci_statement, &oci_defines[i], oci_error,
+                            (ub4)(i + 1), column_values[i], DATA_MAX_NAME_LEN,
+                            SQLT_STR, NULL, NULL, NULL, OCI_DEFAULT);
+    if (status != OCI_SUCCESS) {
+      o_report_error("o_read_database_query", db->name, udb_query_get_name(q),
+                     "OCIDefineByPos", oci_error);
+      continue;
     }
   } /* for (j = 1; j <= param_counter; j++) */
   /* }}} End of the ``define'' stuff. */
 
-  /* Iterate over all indizes and check that all columns from which we're
-   * supposed to read instances or values have been found. */
-  /* {{{ */
-  status = 0;
-  for (i = 0; i < q->instances_num; i++)
-  {
-    if (index_instances[i] > 0)
-      continue;
-
-    ERROR ("oracle plugin: o_read_database_query (%s, %s): "
-        "Instance %zu of the `%s' query should be read from the column `%s', "
-        "but that column wasn't returned by the SQL statement. Please check "
-        "your configuration.",
-        db->name, q->name, (i + 1), q->name, q->instances[i]);
-    status++;
-  }
-
-  for (i = 0; i < q->values_num; i++)
-  {
-    if (index_values[i] > 0)
-      continue;
-
-    ERROR ("oracle plugin: o_read_database_query (%s, %s): "
-        "Value %zu of the `%s' query should be read from the column `%s', "
-        "but that column wasn't returned by the SQL statement. Please check "
-        "your configuration.",
-        db->name, q->name, (i + 1), q->name, q->values[i]);
-    status++;
-  }
-
-  if (status != 0)
-  {
+  status = udb_query_prepare_result(
+      q, prep_area, (db->host != NULL) ? db->host : hostname_g,
+      /* plugin = */ (db->plugin_name != NULL) ? db->plugin_name : "oracle",
+      db->name, column_names, column_num,
+      /* interval = */ 0);
+  if (status != 0) {
+    ERROR("oracle plugin: o_read_database_query (%s, %s): "
+          "udb_query_prepare_result failed.",
+          db->name, udb_query_get_name(q));
     FREE_ALL;
-    return (-1);
+    return -1;
   }
-  /* }}} */
 
   /* Fetch and handle all the rows that matched the query. */
   while (42) /* {{{ */
   {
-    status = OCIStmtFetch2 (q->oci_statement, oci_error,
-        /* nrows = */ 1, /* orientation = */ OCI_FETCH_NEXT,
-        /* fetch offset = */ 0, /* mode = */ OCI_DEFAULT);
-    if (status == OCI_NO_DATA)
-    {
+    status = OCIStmtFetch2(oci_statement, oci_error,
+                           /* nrows = */ 1, /* orientation = */ OCI_FETCH_NEXT,
+                           /* fetch offset = */ 0, /* mode = */ OCI_DEFAULT);
+    if (status == OCI_NO_DATA) {
       status = OCI_SUCCESS;
       break;
-    }
-    else if ((status != OCI_SUCCESS) && (status != OCI_SUCCESS_WITH_INFO))
-    {
-      o_report_error ("o_read_database_query", "OCIStmtFetch2", oci_error);
+    } else if ((status != OCI_SUCCESS) && (status != OCI_SUCCESS_WITH_INFO)) {
+      o_report_error("o_read_database_query", db->name, udb_query_get_name(q),
+                     "OCIStmtFetch2", oci_error);
       break;
     }
 
-    for (i = 0; i < q->instances_num; i++)
-    {
-      DEBUG ("oracle plugin: o_read_database_query: "
-          "buffer_instances[%zu] = %s;",
-           i, buffer_instances[i]);
+    status = udb_query_handle_result(q, prep_area, column_values);
+    if (status != 0) {
+      WARNING("oracle plugin: o_read_database_query (%s, %s): "
+              "udb_query_handle_result failed.",
+              db->name, udb_query_get_name(q));
     }
-
-    for (i = 0; i < q->values_num; i++)
-    {
-      DEBUG ("oracle plugin: o_read_database_query: "
-          "buffer_values[%zu] = %s;",
-           i, buffer_values[i]);
-    }
-
-    o_submit (db, q, ds, buffer_instances, buffer_values);
   } /* }}} while (42) */
 
-  /* DEBUG ("oracle plugin: o_read_database_query: This statement succeeded: %s", q->statement); */
+  /* DEBUG ("oracle plugin: o_read_database_query: This statement succeeded:
+   * %s", q->statement); */
   FREE_ALL;
 
-  return (0);
+  return 0;
 #undef FREE_ALL
 #undef ALLOC_OR_FAIL
 } /* }}} int o_read_database_query */
 
-static int o_read_database (o_database_t *db) /* {{{ */
+static int o_read_database(o_database_t *db) /* {{{ */
 {
-  size_t i;
   int status;
 
-  if (db->oci_service_context == NULL)
-  {
-    status = OCILogon (oci_env, oci_error,
-        &db->oci_service_context,
-        (OraText *) db->username, (ub4) strlen (db->username),
-        (OraText *) db->password, (ub4) strlen (db->password),
-        (OraText *) db->connect_id, (ub4) strlen (db->connect_id));
-    if (status != OCI_SUCCESS)
-    {
-      o_report_error ("o_read_database", "OCILogon", oci_error);
-      DEBUG ("oracle plugin: OCILogon (%s): db->oci_service_context = %p;",
-          db->connect_id, db->oci_service_context);
+  if (db->oci_service_context != NULL) {
+    OCIServer *server_handle;
+    ub4 connection_status;
+
+    server_handle = NULL;
+    status = OCIAttrGet((void *)db->oci_service_context, OCI_HTYPE_SVCCTX,
+                        (void *)&server_handle, /* size pointer = */ NULL,
+                        OCI_ATTR_SERVER, oci_error);
+    if (status != OCI_SUCCESS) {
+      o_report_error("o_read_database", db->name, NULL, "OCIAttrGet",
+                     oci_error);
+      return -1;
+    }
+
+    if (server_handle == NULL) {
+      connection_status = OCI_SERVER_NOT_CONNECTED;
+    } else /* if (server_handle != NULL) */
+    {
+      connection_status = 0;
+      status = OCIAttrGet((void *)server_handle, OCI_HTYPE_SERVER,
+                          (void *)&connection_status, /* size pointer = */ NULL,
+                          OCI_ATTR_SERVER_STATUS, oci_error);
+      if (status != OCI_SUCCESS) {
+        o_report_error("o_read_database", db->name, NULL, "OCIAttrGet",
+                       oci_error);
+        return -1;
+      }
+    }
+
+    if (connection_status != OCI_SERVER_NORMAL) {
+      INFO("oracle plugin: Connection to %s lost. Trying to reconnect.",
+           db->name);
+      OCIHandleFree(db->oci_service_context, OCI_HTYPE_SVCCTX);
+      db->oci_service_context = NULL;
+    }
+  } /* if (db->oci_service_context != NULL) */
+
+  if (db->oci_service_context == NULL) {
+    status = OCILogon(oci_env, oci_error, &db->oci_service_context,
+                      (OraText *)db->username, (ub4)strlen(db->username),
+                      (OraText *)db->password, (ub4)strlen(db->password),
+                      (OraText *)db->connect_id, (ub4)strlen(db->connect_id));
+    if ((status != OCI_SUCCESS) && (status != OCI_SUCCESS_WITH_INFO)) {
+      char errfunc[256];
+
+      snprintf(errfunc, sizeof(errfunc), "OCILogon(\"%s\")", db->connect_id);
+
+      o_report_error("o_read_database", db->name, NULL, errfunc, oci_error);
+      DEBUG("oracle plugin: OCILogon (%s): db->oci_service_context = %p;",
+            db->connect_id, db->oci_service_context);
       db->oci_service_context = NULL;
-      return (-1);
+      return -1;
+    } else if (status == OCI_SUCCESS_WITH_INFO) {
+      /* TODO: Print NOTIFY message. */
     }
-    assert (db->oci_service_context != NULL);
+    assert(db->oci_service_context != NULL);
   }
 
-  DEBUG ("oracle plugin: o_read_database: db->connect_id = %s; db->oci_service_context = %p;",
-      db->connect_id, db->oci_service_context);
+  DEBUG("oracle plugin: o_read_database: db->connect_id = %s; "
+        "db->oci_service_context = %p;",
+        db->connect_id, db->oci_service_context);
 
-  for (i = 0; i < db->queries_num; i++)
-    o_read_database_query (db, db->queries[i]);
+  for (size_t i = 0; i < db->queries_num; i++)
+    o_read_database_query(db, db->queries[i], db->q_prep_areas[i]);
 
-  return (0);
+  return 0;
 } /* }}} int o_read_database */
 
-static int o_read (void) /* {{{ */
+static int o_read(void) /* {{{ */
 {
   size_t i;
 
   for (i = 0; i < databases_num; i++)
-    o_read_database (databases[i]);
+    o_read_database(databases[i]);
 
-  return (0);
+  return 0;
 } /* }}} int o_read */
 
-static int o_shutdown (void) /* {{{ */
+static int o_shutdown(void) /* {{{ */
 {
   size_t i;
 
   for (i = 0; i < databases_num; i++)
-    if (databases[i]->oci_service_context != NULL)
-    {
-      OCIHandleFree (databases[i]->oci_service_context, OCI_HTYPE_SVCCTX);
+    if (databases[i]->oci_service_context != NULL) {
+      OCIHandleFree(databases[i]->oci_service_context, OCI_HTYPE_SVCCTX);
       databases[i]->oci_service_context = NULL;
     }
-  
-  for (i = 0; i < queries_num; i++)
-    if (queries[i]->oci_statement != NULL)
-    {
-      OCIHandleFree (queries[i]->oci_statement, OCI_HTYPE_STMT);
-      queries[i]->oci_statement = NULL;
+
+  for (i = 0; i < queries_num; i++) {
+    OCIStmt *oci_statement;
+
+    oci_statement = udb_query_get_user_data(queries[i]);
+    if (oci_statement != NULL) {
+      OCIHandleFree(oci_statement, OCI_HTYPE_STMT);
+      udb_query_set_user_data(queries[i], NULL);
     }
-  
-  OCIHandleFree (oci_env, OCI_HTYPE_ENV);
-  return (0);
+  }
+
+  OCIHandleFree(oci_env, OCI_HTYPE_ENV);
+  oci_env = NULL;
+
+  udb_query_free(queries, queries_num);
+  queries = NULL;
+  queries_num = 0;
+
+  return 0;
 } /* }}} int o_shutdown */
 
-void module_register (void) /* {{{ */
+void module_register(void) /* {{{ */
 {
-  plugin_register_complex_config ("oracle", o_config);
-  plugin_register_init ("oracle", o_init);
-  plugin_register_read ("oracle", o_read);
-  plugin_register_shutdown ("oracle", o_shutdown);
+  plugin_register_complex_config("oracle", o_config);
+  plugin_register_init("oracle", o_init);
+  plugin_register_read("oracle", o_read);
+  plugin_register_shutdown("oracle", o_shutdown);
 } /* }}} void module_register */
-
-/*
- * vim: shiftwidth=2 softtabstop=2 et fdm=marker
- */