Beispiel #1
0
static MString*
psql_make_sql_insert (DbTable* table)
{
  int n = 0;
  int max = table->schema->nfields;

  if (max <= 0) {
    logerror ("psql: Trying to insert 0 values into table '%s'\n", table->schema->name);
    goto fail_exit;
  }

  MString* mstr = mstring_create ();

  if (mstr == NULL) {
    logerror("psql: Failed to create managed string for preparing SQL INSERT statement\n");
    goto fail_exit;
  }

  /* Build SQL "INSERT INTO" statement */
  n += mstring_set (mstr, "INSERT INTO \"");
  n += mstring_cat (mstr, table->schema->name);
  n += mstring_cat (mstr, "\" VALUES ($1, $2, $3, $4"); /* metadata columns */
  while (max-- > 0)
    mstring_sprintf (mstr, ", $%d", 4 + table->schema->nfields - max);
  mstring_cat (mstr, ");");

  if (n != 0) goto fail_exit;
  return mstr;

 fail_exit:
  if (mstr) mstring_delete (mstr);
  return NULL;
}
Beispiel #2
0
/** Create a new out stream for sending over the network
 * \param transport string representing the protocol used to establish the connection (oml_strndup()'d locally)
 * \param hostname string representing the host to connect to (oml_strndup()'d locally)
 * \param service symbolic name or port number of the service to connect to (oml_strndup()'d locally)
 * \return a new OmlOutStream instance
 *
 * \see oml_strndup
 */
OmlOutStream*
net_stream_new(const char *transport, const char *hostname, const char *service)
{
    MString *dest;
    assert(transport != NULL && hostname != NULL && service != NULL);
    OmlNetOutStream* self = (OmlNetOutStream *)oml_malloc(sizeof(OmlNetOutStream));
    memset(self, 0, sizeof(OmlNetOutStream));

    dest = mstring_create();
    mstring_sprintf(dest, "%s://%s:%s", transport, hostname, service);
    self->dest = (char*)oml_strndup (mstring_buf(dest), mstring_len(dest));
    mstring_delete(dest);

    self->protocol = (char*)oml_strndup (transport, strlen (transport));
    self->host = (char*)oml_strndup (hostname, strlen (hostname));
    self->service = (char*)oml_strndup (service, strlen (service));

    logdebug("%s: Created OmlNetOutStream\n", self->dest);
    socket_set_non_blocking_mode(0);

    /* // Now see if we can connect to server */
    /* if (! open_socket(self)) { */
    /*   free(self); */
    /*   return NULL; */
    /* } */

    self->write = net_stream_write;
    self->close = net_stream_close;
    return (OmlOutStream*)self;
}
Beispiel #3
0
/** Create a new out stream for writing into a local file.
 *
 * \param file destination file (oml_strndup()'d locally)
 * \return a new OmlOutStream instance
 *
 * \see oml_strndup
 */
OmlOutStream*
file_stream_new(const char *file)
{
  MString *dest;
  OmlFileOutStream* self = (OmlFileOutStream *)oml_malloc(sizeof(OmlFileOutStream));
  memset(self, 0, sizeof(OmlFileOutStream));

  loginfo ("File_stream: opening local storage file '%s'\n", file);

  if (strcmp(file, "stdout") == 0 || strcmp(file, "-") == 0) {
    self->f = stdout;
  } else {
    if ((self->f = fopen(file, "a+")) == NULL) {
      logerror ("Can't open local storage file '%s'\n", file);
      return 0;
    }
  }

  dest = mstring_create();
  mstring_sprintf(dest, "file:%s", file);
  self->dest = (char*)oml_strndup (mstring_buf(dest), mstring_len(dest));
  mstring_delete(dest);

  self->write = file_stream_write;
  self->close = file_stream_close;
  return (OmlOutStream*)self;
}
Beispiel #4
0
/**
 *  @brief Do a key-value style select on a database table.
 *
 *  This function does a key lookup on a database table that is set up
 *  in key-value style.  The table can have more than two columns, but
 *  this function SELECT's two of them and returns the value of the
 *  value column.  It checks to make sure that the key returned is the
 *  one requested, then returns its corresponding value.
 *
 *  This function makes a lot of assumptions about the database and
 *  the table:
 *
 *  #- the database exists and is open
 *  #- the table exists in the database
 *  #- there is a column named key_column in the table
 *  #- there is a column named value_column in the table
 *
 *  The function does not check for any of these conditions, but just
 *  assumes they are true.  Be advised.
 *
 *  @param database the database to look up in.
 *  @param table the name of the table to look up in.
 *  @param key_column the name of the column holding the key strings.
 *  @param value_column the name of the column holding the value strings.
 *  @param key the key string to look up (i.e. WHERE key_column='key').
 *
 *  @return the string value corresponding to the given key, or NULL
 *  if an error occurred of if the key was not present in the table.
 */
char*
psql_get_key_value (Database *database, const char *table,
                    const char *key_column, const char *value_column,
                    const char *key)
{
  if (database == NULL || table == NULL || key_column == NULL ||
      value_column == NULL || key == NULL)
    return NULL;

  PGresult *res;
  PsqlDB *psqldb = (PsqlDB*) database->handle;
  MString *stmt = mstring_create();
  mstring_sprintf (stmt, "SELECT %s FROM %s WHERE %s='%s';",
                   value_column, table, key_column, key);

  res = PQexec (psqldb->conn, mstring_buf (stmt));

  if (PQresultStatus(res) != PGRES_TUPLES_OK) {
    logerror("psql:%s: Error trying to get %s[%s]; (%s).\n",
             database->name, table, key, PQerrorMessage(psqldb->conn));
    goto fail_exit;
  }

  if (PQntuples (res) == 0)
    goto fail_exit;
  if (PQnfields (res) < 1)
    goto fail_exit;

  if (PQntuples (res) > 1)
    logwarn("psql:%s: Key-value lookup for key '%s' in %s(%s, %s) returned more than one possible key.\n",
             database->name, key, table, key_column, value_column);

  char *value = NULL;
  value = PQgetvalue (res, 0, 0);

  if (value != NULL)
    value = xstrndup (value, strlen (value));

  PQclear (res);
  mstring_delete (stmt);
  return value;

 fail_exit:
  PQclear (res);
  mstring_delete (stmt);
  return NULL;
}
Beispiel #5
0
static int
psql_set_sender_id (Database *database, const char *name, int id)
{
  MString *mstr = mstring_create();
  mstring_sprintf (mstr, "%d", id);
  int ret = psql_set_key_value (database, "_senders", "name", "id", name, mstring_buf (mstr));
  mstring_delete (mstr);
  return ret;
}
Beispiel #6
0
/** Setup the PostgreSQL backend.
 *
 * \return 0 on success, -1 otherwise
 */
int
psql_backend_setup ()
{
  MString *str, *conninfo;

  loginfo ("psql: Sending experiment data to PostgreSQL server %s:%s as user '%s'\n",
           pg_host, pg_port, pg_user);

  conninfo = psql_prepare_conninfo("postgres", pg_host, pg_port, pg_user, pg_pass, pg_conninfo);
  PGconn *conn = PQconnectdb (mstring_buf (conninfo));

  if (PQstatus (conn) != CONNECTION_OK) {
    logerror ("psql: Could not connect to PostgreSQL database (conninfo \"%s\"): %s\n",
         mstring_buf(conninfo), PQerrorMessage (conn));
    mstring_delete(conninfo);
    return -1;
  }

  /* oml2-server must be able to create new databases, so check that
     our user has the required role attributes */
  str = mstring_create();
  mstring_sprintf (str, "SELECT rolcreatedb FROM pg_roles WHERE rolname='%s'", pg_user);
  PGresult *res = PQexec (conn, mstring_buf (str));
  mstring_delete(str);
  if (PQresultStatus (res) != PGRES_TUPLES_OK) {
    logerror ("psql: Failed to determine role privileges for role '%s': %s\n",
         pg_user, PQerrorMessage (conn));
    return -1;
  }
  char *has_create = PQgetvalue (res, 0, 0);
  if (strcmp (has_create, "t") == 0)
    logdebug ("psql: User '%s' has CREATE DATABASE privileges\n", pg_user);
  else {
    logerror ("psql: User '%s' does not have required role CREATE DATABASE\n", pg_user);
    return -1;
  }

  mstring_delete(conninfo);
  PQclear (res);
  PQfinish (conn);

  return 0;
}
Beispiel #7
0
int
psql_table_free (Database *database, DbTable *table)
{
  (void)database;
  PsqlTable *psqltable = (PsqlTable*)table->handle;
  if (psqltable) {
    mstring_delete (psqltable->insert_stmt);
    xfree (psqltable);
  }
  return 0;
}
Beispiel #8
0
/**
 * \brief Definition of the meta function of the oml net writer
 * \param writer the net writer that will send the data to the server
 * \param str the string to send
 * \return 1 if successful, 0 otherwise
 */
static int
meta(OmlWriter* writer, char* str)
{
  OmlTextWriter* self = (OmlTextWriter*)writer;
  if (self->bufferedWriter == NULL) return 0;

  MString *mstr = mstring_create();
  mstring_set (mstr, str);
  mstring_cat (mstr, "\n");
  bw_push_meta(self->bufferedWriter, (uint8_t*)mstring_buf (mstr), mstring_len (mstr));

  mstring_delete (mstr);
  return 1;
}
Beispiel #9
0
/** Helper function to build and send a database-related event to the server hook.
 *
 * \param self Database on which the event happened
 * \param event event to report
 *
 * \return 0 on success (even if the hook is disabled), -1 otherwise
 *
 * \see HOOK_CMD_DBCREATED, HOOK_CMD_DBOPENED, HOOK_CMD_DBCLOSED
 */
static int
database_hook_send_event(Database *self, const char* event){
  char dburi[PATH_MAX+1];
  MString *hook_command = mstring_create();

  if(hook_enabled()) {
    if(!self->get_uri(self, dburi, sizeof(dburi))) {
      logwarn("%s: Unable to get full URI to database for hook\n", self->name);

    } else if (mstring_sprintf(hook_command, "%s %s\n",
          event, dburi) == -1) {
      logwarn("%s: Failed to construct command string for event hook\n", self->name);
      mstring_delete(hook_command);
      return -1;

    } else if(hook_write(mstring_buf(hook_command), mstring_len(hook_command)) < (int)mstring_len(hook_command)) {
      logwarn("%s: Failed to send command string to event hook: %s\n", self->name, strerror(errno));
      mstring_delete(hook_command);
      return -1;
    }
  }

  return 0;
}
Beispiel #10
0
/**
 * \brief Called when a node connects via TCP
 * \param
 * \return
 */
void
on_connect (Socket* client_sock, void* handle)
{
  (void)handle;  // This parameter is unused
  MString *mstr = mstring_create ();

  mstring_sprintf (mstr,"%s.%d", resultfile_name, session->client_count);
  logdebug("New client (index %d) connected\n", session->client_count);
  session->client_count++;

  Client* client = client_new(client_sock, page_size, mstring_buf (mstr),
                              downstream_port, downstream_address);

  mstring_delete (mstr);

  session_add_client (session, client);
  client->session = session;

  client->recv_event = eventloop_on_read_in_channel(client_sock, client_callback,
                                                    status_callback, (void*)client);

  pthread_create (&client->thread, NULL, client_send_thread, (void*)client);
}
Beispiel #11
0
/** Create or open an PostgreSQL database
 * \param db the databse to associate with the sqlite3 database
 * \return 0 if successful, -1 otherwise
 */
int
psql_create_database(Database* db)
{
  MString *conninfo;
  MString *str;
  PGconn  *conn;
  PGresult *res = NULL;
  int ret = -1;

  loginfo ("psql:%s: Accessing database\n", db->name);

  /*
   * Make a connection to the database server -- check if the
   * requested database exists or not by connecting to the 'postgres'
   * database and querying that.
   */
  conninfo = psql_prepare_conninfo("postgres", pg_host, pg_port, pg_user, pg_pass, pg_conninfo);
  conn = PQconnectdb(mstring_buf (conninfo));

  /* Check to see that the backend connection was successfully made */
  if (PQstatus(conn) != CONNECTION_OK) {
    logerror ("psql: Could not connect to PostgreSQL database (conninfo \"%s\"): %s\n",
         mstring_buf(conninfo), PQerrorMessage (conn));
    goto cleanup_exit;
  }
  PQsetNoticeReceiver(conn, psql_receive_notice, "postgres");

  str = mstring_create();
  mstring_sprintf (str, "SELECT datname from pg_database where datname='%s';", db->name);
  res = PQexec (conn, mstring_buf (str));

  if (PQresultStatus (res) != PGRES_TUPLES_OK) {
    logerror ("psql: Could not get list of existing databases\n");
    goto cleanup_exit;
  }

  /* No result rows means database doesn't exist, so create it instead */
  if (PQntuples (res) == 0) {
    loginfo ("psql:%s: Database does not exist, creating it\n", db->name);
    mstring_set (str, "");
    mstring_sprintf (str, "CREATE DATABASE \"%s\";", db->name);

    res = PQexec (conn, mstring_buf (str));
    if (PQresultStatus (res) != PGRES_COMMAND_OK) {
      logerror ("psql:%s: Could not create database: %s\n", db->name, PQerrorMessage (conn));
      goto cleanup_exit;
    }
  }

  PQfinish (conn);
  mstring_delete(conninfo);

  /* Now that the database should exist, make a connection to the it for real */
  conninfo = psql_prepare_conninfo(db->name, pg_host, pg_port, pg_user, pg_pass, pg_conninfo);
  conn = PQconnectdb(mstring_buf (conninfo));

  /* Check to see that the backend connection was successfully made */
  if (PQstatus(conn) != CONNECTION_OK) {
    logerror ("psql:%s: Could not connect to PostgreSQL database (conninfo \"%s\"): %s\n",
        db->name, mstring_buf(conninfo), PQerrorMessage (conn));
    goto cleanup_exit;
  }
  PQsetNoticeReceiver(conn, psql_receive_notice, db->name);

  PsqlDB* self = (PsqlDB*)xmalloc(sizeof(PsqlDB));
  self->conn = conn;
  self->last_commit = time (NULL);

  db->create = psql_create_database;
  db->release = psql_release;
  db->table_create = psql_table_create;
  db->table_create_meta = psql_table_create_meta;
  db->table_free = psql_table_free;
  db->insert = psql_insert;
  db->add_sender_id = psql_add_sender_id;
  db->get_metadata = psql_get_metadata;
  db->set_metadata = psql_set_metadata;
  db->get_uri = psql_get_uri;
  db->get_table_list = psql_get_table_list;

  db->handle = self;

  begin_transaction (self);

  /* Everything was successufl, prepare for cleanup */
  ret = 0;

cleanup_exit:
  if (res) PQclear (res);
  if (ret) PQfinish (conn); /* If return !=0, cleanup connection */

  mstring_delete (str);
  mstring_delete (conninfo);
  return ret;
}
Beispiel #12
0
TableDescr*
psql_get_table_list (Database *database, int *num_tables)
{
  PsqlDB *self = database->handle;
  const char *stmt_tablename =
    "SELECT tablename FROM pg_tables WHERE tablename NOT LIKE 'pg%' AND tablename NOT LIKE 'sql%';";
  PGresult *res;
  TableDescr *tables = NULL;
  int rows, cols, i;

  *num_tables = -1;
  res = PQexec (self->conn, stmt_tablename);
  if (PQresultStatus (res) != PGRES_TUPLES_OK) {
    logerror("psql:%s: Couldn't get list of tables: %s\n",
        database->name, PQerrorMessage (self->conn));
    PQclear (res);
    return NULL;
  }
  rows = PQntuples (res);
  cols = PQnfields (res);

  if (cols < 1)
    return NULL;

  int have_meta = 0;
  for (i = 0; i < rows && !have_meta; i++)
    if (strcmp (PQgetvalue (res, i, 0), "_experiment_metadata") == 0)
      have_meta = 1;

  if(!have_meta)
    logdebug("psql:%s: No metadata found\n", database->name);

  *num_tables = 0;

  for (i = 0; i < rows; i++) {
    char *val = PQgetvalue (res, i, 0);
    logdebug("psql:%s: Found table '%s'", database->name, val);
    MString *str = mstring_create ();
    TableDescr *t = NULL;

    if (have_meta) {
      mstring_sprintf (str, "SELECT value FROM _experiment_metadata WHERE key='table_%s';", val);
      PGresult *schema_res = PQexec (self->conn, mstring_buf (str));
      if (PQresultStatus (schema_res) != PGRES_TUPLES_OK) {
        logdebug("psql:%s: Couldn't get schema for table '%s': %s; skipping\n",
            database->name, val, PQerrorMessage (self->conn));
        mstring_delete (str);
        continue;
      }
      int rows = PQntuples (schema_res);
      if (rows == 0) {
        logdebug("psql:%s: Metadata for table '%s' found but empty\n", database->name, val);
        t = table_descr_new (val, NULL); // Don't know the schema for this table
      } else {
        logdebug("psql:%s: Stored schema for table '%s': %s\n", database->name, val, PQgetvalue (schema_res, 0, 0));
        struct schema *schema = schema_from_meta (PQgetvalue (schema_res, 0, 0));
        t = table_descr_new (val, schema);
      }
      PQclear (schema_res);
      mstring_delete (str);
    } else {
      t = table_descr_new (val, NULL);
    }

    if (t) {
      t->next = tables;
      tables = t;
      (*num_tables)++;
    }
  }

  return tables;
}
Beispiel #13
0
/**
 * @brief Create a PostgreSQL table
 * @param db the database that contains the sqlite3 db
 * @param table the table to associate in sqlite3 database
 * @return 0 if successful, -1 otherwise
 */
static int
table_create (Database* db, DbTable* table, int backend_create)
{
  if (db == NULL) {
    logerror("psql: Tried to create a table in a NULL database\n");
    return -1;
  }
  if (table == NULL) {
    logerror("psql:%s: Tried to create a table from a NULL definition\n", db->name);
    return -1;
  }
  if (table->schema == NULL) {
    logerror("psql:%s: No schema defined for table, cannot create\n", db->name);
    return -1;
  }
  MString *insert = NULL, *create = NULL;
  PsqlDB* psqldb = (PsqlDB*)db->handle;
  PGresult *res;

  if (backend_create) {
    int sindex = table->schema->index;
    table->schema->index = -1;
    MString *mstr = mstring_create ();
    mstring_sprintf (mstr, "table_%s", table->schema->name);
    const char *meta = schema_to_meta (table->schema);
    table->schema->index = sindex;
    logdebug("psql:%s: SET META: %s\n", db->name, meta);
    psql_set_metadata (db, mstring_buf (mstr), meta);
    create = schema_to_sql (table->schema, oml_to_postgresql_type);
    if (!create) {
      logerror("psql:%s: Failed to build SQL CREATE TABLE statement string for table '%s'\n",
          db->name, table->schema->name);
      goto fail_exit;
    }
    if (sql_stmt (psqldb, mstring_buf (create))) {
      logerror("psql:%s: Could not create table '%s': %s\n",
          db->name, table->schema->name,
          PQerrorMessage (psqldb->conn));
      goto fail_exit;
    }
  }

  insert = psql_make_sql_insert (table);
  if (!insert) {
    logerror("psql:%s: Failed to build SQL INSERT INTO statement for table '%s'\n",
          db->name, table->schema->name);
    goto fail_exit;
  }
  /* Prepare the insert statement and update statement  */
  PsqlTable* psqltable = (PsqlTable*)xmalloc(sizeof(PsqlTable));
  table->handle = psqltable;

  MString *insert_name = mstring_create();
  mstring_set (insert_name, "OMLInsert-");
  mstring_cat (insert_name, table->schema->name);
  res = PQprepare(psqldb->conn,
                  mstring_buf (insert_name),
                  mstring_buf (insert),
                  table->schema->nfields + 4, // FIXME:  magic number of metadata cols
                  NULL);

  if (PQresultStatus(res) != PGRES_COMMAND_OK) {
    logerror("psql:%s: Could not prepare statement: %s\n",
        db->name, PQerrorMessage(psqldb->conn));
    PQclear(res);
    goto fail_exit;
    return -1;
  }
  PQclear(res);
  psqltable->insert_stmt = insert_name;

  if (create) mstring_delete (create);
  if (insert) mstring_delete (insert);
  return 0;

fail_exit:
  if (create) mstring_delete (create);
  if (insert) mstring_delete (insert);
  return -1;
}