Skip to content
Snippets Groups Projects
Select Git revision
  • dsa-reorg
  • master default protected
  • siv-mode
  • delete-des-compat
  • delete-rsa_blind
  • aes-struct-layout
  • master-updates
  • release-3.4-fixes
  • struct-layout
  • attribute-deprecated
  • rename-data-symbols
  • x86_64-sha_ni-sha256
  • ecc-params-tweak
  • delete-old-aes
  • cmac-support
  • x86_64-sha_ni-sha1
  • gcm-ctr-opt
  • ctr-opt
  • skein
  • api-opaque-fix
  • curve448
  • nettle_3.4.1_release_20181204
  • nettle_3.4.1rc1
  • nettle_3.4_release_20171119
  • nettle_3.4rc2
  • nettle_3.4rc1
  • nettle_3.3_release_20161001
  • nettle_3.2_release_20160128
  • nettle_3.1.1_release_20150424
  • nettle_3.1_release_20150407
  • nettle_3.1rc3
  • nettle_3.1rc2
  • nettle_3.1rc1
  • nettle_3.0_release_20140607
  • nettle_2.7.1_release_20130528
  • nettle_2.7_release_20130424
  • nettle_2.6_release_20130116
  • nettle_2.5_release_20120707
  • converted-master-branch-to-git
  • nettle_2.4_release_20110903
  • nettle_2.3_release_20110902
41 results

cnd-copy.c

Blame
  • Forked from Nettle / nettle
    Source project has a limited visibility.
    postgres.pike 13.72 KiB
    /*
     * This is part of the Postgres module for Pike.
     *
     * $Id: postgres.pike,v 1.32 2008/07/05 11:17:45 srb Exp $
     *
     */
    
    //! This is an interface to the Postgres (Postgres95, pgsql) database
    //! server. This module may or may not be availible on your Pike,
    //! depending whether the appropriate include and library files could
    //! be found at compile-time. Note that you @b{do not@} need to have a
    //! Postgres server running on your host to use this module: you can
    //! connect to the database over a TCP/IP socket.
    //!
    //! @note
    //! Also note that @b{this module uses blocking I/O@} I/O to connect
    //! to the server. Postgres is quite slow, and so you might want to
    //! consider this particular aspect. It is (at least should be)
    //! thread-safe, and so it can be used in a multithread environment.
    //!
    //! The behavior of the Postgres C API also depends on certain
    //! environment variables defined in the environment of the Pike
    //! interpreter.
    //!
    //! @string
    //!   @value "PGHOST"
    //!     Sets the name of the default host to connect to. It defaults
    //! 	to @expr{"localhost"@}.
    //!   @value "PGOPTIONS"
    //!     Sets some extra flags for the frontend-backend connection.
    //!     @b{do not set@} unless you're sure of what you're doing.
    //!   @value "PGPORT"
    //!     Sets the default port to connect to, otherwise it will use
    //!     compile-time defaults (that is: the time you compiled the postgres
    //! 	library, not the Pike driver).
    //!   @value "PGTTY"
    //!     Sets the file to be used for Postgres frontend debugging.
    //!     Do not use, unless you're sure of what you're doing.
    //!   @value "PGDATABASE"
    //!     Sets the default database to connect to.
    //!   @value "PGREALM"
    //!     Sets the default realm for Kerberos authentication. I never used
    //!   	this, so I can't help you.
    //! @endstring
    //!
    //! Refer to the Postgres documentation for further details.
    //!
    //! @seealso
    //!  @[Sql.Sql], @[Postgres.postgres], @[Sql.postgres_result]
    
    #pike __REAL_VERSION__
    
    #if constant(Postgres.postgres)
    
    #define ERROR(X) throw (({X,backtrace()}))
    
    inherit Postgres.postgres: mo;
    private protected mixed  callout;
    private string has_relexpires = "unknown";
    
    //! @decl void select_db(string dbname)
    //!
    //! This function allows you to connect to a database. Due to
    //! restrictions of the Postgres frontend-backend protocol, you always
    //! have to be connected to a database, so in fact this function just
    //! allows you to connect to a different database on the same server.
    //!
    //! @note
    //! This function @b{can@} raise exceptions if something goes wrong
    //! (backend process not running, not enough permissions..)
    //!
    //! @seealso
    //!   create
    
    //! @decl string error()
    //!
    //! This function returns the textual description of the last
    //! server-related error. Returns @expr{0@} if no error has occurred
    //! yet. It is not cleared upon reading (can be invoked multiple
    //! times, will return the same result until a new error occurs).
    //!
    //! @seealso
    //!   big_query
    
    //! @decl string host_info()
    //!
    //! This function returns a string describing what host are we talking to,
    //! and how (TCP/IP or UNIX sockets).
    
    //! @decl void reset()
    //!
    //! This function resets the connection to the backend. Can be used for
    //! a variety of reasons, for example to detect the status of a connection.
    //!
    //! @note
    //! This function is Postgres-specific, and thus it is not availible
    //! through the generic SQL-interface.
    
    //! @decl string version
    //!
    //! Should you need to report a bug to the author, please submit along with
    //! the report the driver version number, as returned by this call.
    
    private protected string glob_to_regexp (string glob) {
    	if (!glob||!sizeof(glob))
    		return 0;
    	return "^"+replace(glob,({"*","?","'","\\"}),({".*",".","\\'","\\\\"}))+"$";
    }
    
    protected private int mkbool(string s) {
    	if (s=="f")
    		return 0;
    	return 1;
    }
    
    //! @decl void create()
    //! @decl void create(string host, void|string database, void|string user,@
    //!                   void|string password)
    //!
    //! With no arguments, this function initializes (reinitializes if a
    //! connection had been previously set up) a connection to the
    //! Postgres backend. Since Postgres requires a database to be
    //! selected, it will try to connect to the default database. The
    //! connection may fail however for a variety of reasons, in this case
    //! the most likely of all is because you don't have enough authority
    //! to connect to that database. So use of this particular syntax is
    //! discouraged.
    //!
    //! The host argument can have the syntax @expr{"hostname"@} or
    //! @expr{"hostname:portname"@}. This allows to specify the TCP/IP
    //! port to connect to. If it is @expr{0@} or @expr{""@}, it will try
    //! to connect to localhost, default port.
    //!
    //! The database argument specifies the database to connect to. If
    //! @expr{0@} or @expr{""@}, it will try to connect to the specified
    //! database.
    //!
    //! The username and password arguments are silently ignored, since
    //! the Postgres C API doesn't allow to connect to the server as any
    //! user different than the user running the interface.
    //!
    //! @note
    //! You need to have a database selected before using the sql-object,
    //! otherwise you'll get exceptions when you try to query it. Also
    //! notice that this function @b{can@} raise exceptions if the db
    //! server doesn't respond, if the database doesn't exist or is not
    //! accessible by you.
    //!
    //! You don't need bothering about syncronizing the connection to the database:
    //! it is automatically closed (and the database is sync-ed) when the
    //! object is destroyed.
    //!
    //! @seealso
    //!   @[Postgres.postgres], @[Sql.Sql], @[postgres->select_db]
    void create(void|string host, void|string database, void|string user,
    		void|string _pass) {
    	string pass = _pass;
    	_pass = "CENSORED";
    	string real_host=host, real_db=database;
    	int port=0;
    	quote = this->_quote ? this->_quote : simple_quote;
    	if (stringp(host)&&(search(host,":")>=0))
    		if (sscanf(host,"%s:%d",real_host,port)!=2)
    			ERROR("Error in parsing the hostname argument.\n");
    	
    	mo::create(real_host||"",real_db||"",user||"",pass||"",port);
    }
    
    protected void poll (int delay)
    {
    	callout=call_out(poll,delay,delay);
    	big_query("");
    }
    
    //! @decl void set_notify_callback()
    //! @decl void set_notify_callback(function f)
    //! @decl void set_notify_callback(function f, int|float poll_delay)
    //!
    //! With Postgres you can associate events and notifications to tables.
    //! This function allows you to detect and handle such events.
    //!
    //! With no arguments, resets and removes any callback you might have
    //! put previously, and any polling cycle.
    //!
    //! With one argument, sets the notification callback (there can be only
    //! one for each sqlobject). 
    //! 
    //! With two arguments, sets a notification callback and sets a polling
    //! cycle.
    //!
    //! The polling cycle is necessary because of the way notifications are
    //! delivered, that is piggyback with a query result. This means that
    //! if you don't do any query, you'll receive no notification. The polling
    //! cycle starts a call_out cycle which will do an empty query when
    //! the specified interval expires, so that pending notifications 
    //! may be delivered.
    //!
    //! The callback function must return no value, and takes a string argument,
    //! which will be the name of the table on which the notification event
    //! has occured. In future versions, support for user-specified arguments
    //! will be added.
    //!
    //! @note
    //! The polling cycle can be run only if your process is in "event-driven mode"
    //! (that is, if 'main' has returned a negative number).
    //!
    //! This function is Postgres-specific, and thus it is not availible
    //! through the generic SQL-interface.
    //!
    //! @fixme
    //! An integer can be passed as first argument, but it's effect is
    //! not documented.
    void set_notify_callback(int|function f, int|float|void poll_delay) {
    	if (callout) {
    		remove_call_out(callout);
    		callout=0;
    	}
    	if (intp(f)) {
    		mo::_set_notify_callback(0);
    		return;
    	}
    	mo::_set_notify_callback(f);
    	if(poll_delay>0) 
    		poll(poll_delay);
    }
    
    function quote;
    string simple_quote(string s)
    {
      return replace(s, ({ "\\", "'", "\0" }), ({ "\\\\", "''", "\\0" }) );
    }
    
    //! This function creates a new database with the given name (assuming we
    //! have enough permissions to do this).
    //!
    //! @seealso
    //!   drop_db
    void create_db(string db) {
    	big_query(sprintf("CREATE DATABASE %s",db));
    }
    
    //! This function destroys a database and all the data it contains (assuming
    //! we have enough permissions to do so).
    //!
    //! @seealso
    //!   create_db
    void drop_db(string db) {
    	big_query(sprintf("DROP database %s",db));
    }
    
    //! This function returns a string describing the server we are
    //! talking to. It has the form @expr{"servername/serverversion"@}
    //! (like the HTTP protocol description) and is most useful in
    //! conjunction with the generic SQL-server module.
    string server_info () {
      return "Postgres/unknown";
    }
    
    //! Lists all the databases available on the server.
    //! If glob is specified, lists only those databases matching it.
    array(string) list_dbs (void|string glob) {
    	array name,ret=({});
    	object res=
    		big_query(
    				"SELECT datname from pg_database"+
    				((glob&&sizeof(glob))? " WHERE datname ~ '"+glob_to_regexp(glob)+"'" : "")
    				);
    	while (name=res->fetch_row()) {
    		ret += ({name[0]});
    	}
    	return sort(ret);
    }
    
    //! Returns an array containing the names of all the tables in the currently
    //! selected database.
    //! If a glob is specified, it will return only those tables
    //! whose name matches it.
    array(string) list_tables (void|string glob) {
    	array name,ret=({});
    	object res;
    	res=big_query(
    			"SELECT relname, relkind FROM pg_class, pg_user "
    			"WHERE ( relkind = 'r' OR relkind = 'i' OR relkind = 'S') "
    			"AND relname !~ '^pg_' "
    			"AND usesysid = relowner " +
    			((glob && sizeof(glob)) ? "AND relname ~ '"+glob_to_regexp(glob)+"' " : "") +
    			"ORDER BY relname"
    			);
    	while (name=res->fetch_row()) {
    		ret += ({name[0]});
    	}
    	return ret;
    }
    
    //! Returns a mapping, indexed on the column name, of mappings describing
    //! the attributes of a table of the current database.
    //! If a glob is specified, will return descriptions only of the columns
    //! matching it.
    //!
    //! The currently defined fields are:
    //!
    //! @mapping
    //!   @member int "has_rules"
    //!
    //!   @member int "is_shared"
    //!
    //!   @member string "owner"
    //!     The textual representation of a Postgres uid.
    //!
    //!   @member string "length"
    //!
    //!   @member string "text"
    //!     A textual description of the internal (to the server) type-name
    //!
    //!   @member mixed "default"
    //!
    //!   @member string "expires"
    //!     The "relexpires" attribute for the table. Obsolescent; modern
    //!     versions of Postgres don't seem to use this feature, so don't
    //!     count on this field to contain any useful value.
    //!
    //! @endmapping
    //!
    array(mapping(string:mixed)) list_fields (string table, void|string wild)
    {
      array row, ret=({});
      string schema;
    
      if (has_relexpires == "unknown")
      {
        if (catch (big_query("SELECT relexpires FROM pg_class WHERE 1 = 0")))
          has_relexpires = "no";
        else
          has_relexpires = "yes";
      }
    
      sscanf(table, "%s.%s", schema, table);
    
      object res = big_query(
    	"SELECT a.attnum, a.attname, t.typname, a.attlen, c.relowner, "
    	"c.relisshared, c.relhasrules, t.typdefault " +
            (has_relexpires == "yes" ? ", c.relexpires " : "") +
    	(schema ? ", s.schemaname " : "") +
    	"FROM pg_class c, pg_attribute a, pg_type t " +
    	(schema ? ", pg_tables s " : "") +
    	"WHERE c.relname = '"+table+"' AND a.attnum > 0 " +
    	(schema ? "AND s.tablename = '"+table+"' " : "") +
    	"AND a.attrelid = c.oid AND a.atttypid = t.oid ORDER BY attnum");
    
      while (row = res->fetch_row())
      {
        if (wild && sizeof(wild) && !glob(wild, row[1]))
          continue;
        ret +=
          ({ ([
    	 "name":	row[1],
             "type":	row[2],
             "length":	row[3],
    	 "owner":	row[4],
             "is_shared":	mkbool(row[5]),
    	 "has_rules":   mkbool(row[6]),
    	 "default":     row[7],
             "expires":     (sizeof(row) > 8 ? row[8] : 0)
           ]) });
      }
      return ret;
    }
    
    //! This is the only provided interface which allows you to query the
    //! database. If you wish to use the simpler "query" function, you need to
    //! use the @[Sql.Sql] generic SQL-object.
    //!
    //! It returns a postgres_result object (which conforms to the
    //! @[Sql.sql_result] standard interface for accessing data). I
    //! recommend using @[query()] for simpler queries (because it is
    //! easier to handle, but stores all the result in memory), and
    //! @[big_query()] for queries you expect to return huge amounts of
    //! data (it's harder to handle, but fetches results on demand).
    //!
    //! @note
    //! This function @b{can@} raise exceptions.
    //!
    //! @seealso
    //!   @[Sql.Sql], @[Sql.sql_result]
    int|object big_query(object|string q, mapping(string|int:mixed)|void bindings)
    {  
      if(stringp(q) && String.width(q)>8)
        q=string_to_utf8(q);
      if (!bindings)
        return ::big_query(q);
      int pi=0,rep=0;
      array(string|int) paramValues=allocate(sizeof(bindings));
      array(string) from=allocate(sizeof(bindings));
      array(string) to=allocate(sizeof(bindings));
      foreach(bindings; mixed name; mixed value) {
        // Throws if mapping key is empty string.
        if(stringp(name)) {
          if(name[0]!=':')
            name=":"+name;
          if(name[1]=='_') {
            // Special parameter
            continue;
          }
        }
        from[rep]=name;
        string rval;
        if(multisetp(value)) {
          rval=sizeof(value) ? indices(value)[0] : "";
        }
        else {
          if(zero_type(value))
            paramValues[pi++]=UNDEFINED;
          else {
            if(stringp(value) && String.width(value)>8)
              value=string_to_utf8(value);
            paramValues[pi++]=(string)value;
          }
          rval="$"+(string)pi;
        }
        to[rep++]=rval;
      }
      paramValues= pi ? paramValues[..pi-1] : UNDEFINED;
      if(rep--) {
        q=replace(q,from[..rep],to[..rep]);
      }
      return ::big_query(q, paramValues);
    }
    
    #else
    constant this_program_does_not_exist=1;
    #endif /* constant(Postgres.postgres) */