Source for file postgresql.php

Documentation is available at postgresql.php

  1. <?php
  2. /**
  3.  * @package     Joomla.Platform
  4.  * @subpackage  Database
  5.  *
  6.  * @copyright   Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7.  * @license     GNU General Public License version 2 or later; see LICENSE
  8.  */
  9.  
  10. defined('JPATH_PLATFORM'or die;
  11.  
  12. /**
  13.  * PostgreSQL database driver
  14.  *
  15.  * @package     Joomla.Platform
  16.  * @subpackage  Database
  17.  * @since       12.1
  18.  */
  19. {
  20.     /**
  21.      * The database driver name
  22.      *
  23.      * @var    string 
  24.      * @since  12.1
  25.      */
  26.     public $name = 'postgresql';
  27.  
  28.     /**
  29.      * Quote for named objects
  30.      *
  31.      * @var    string 
  32.      * @since  12.1
  33.      */
  34.     protected $nameQuote = '"';
  35.  
  36.     /**
  37.      * The null/zero date string
  38.      *
  39.      * @var    string 
  40.      * @since  12.1
  41.      */
  42.     protected $nullDate = '1970-01-01 00:00:00';
  43.  
  44.     /**
  45.      * The minimum supported database version.
  46.      *
  47.      * @var    string 
  48.      * @since  12.1
  49.      */
  50.     protected static $dbMinimum '8.3.18';
  51.  
  52.     /**
  53.      * Operator used for concatenation
  54.      *
  55.      * @var    string 
  56.      * @since  12.1
  57.      */
  58.     protected $concat_operator = '||';
  59.  
  60.     /**
  61.      * JDatabaseDriverPostgresqlQuery object returned by getQuery
  62.      *
  63.      * @var    JDatabaseDriverPostgresqlQuery 
  64.      * @since  12.1
  65.      */
  66.     protected $queryObject = null;
  67.  
  68.     /**
  69.      * Database object constructor
  70.      *
  71.      * @param   array  $options  List of options used to configure the connection
  72.      *
  73.      * @since    12.1
  74.      */
  75.     public function __construct$options )
  76.     {
  77.         $options['host'(isset($options['host'])) $options['host''localhost';
  78.         $options['user'(isset($options['user'])) $options['user''';
  79.         $options['password'(isset($options['password'])) $options['password''';
  80.         $options['database'(isset($options['database'])) $options['database''';
  81.  
  82.         // Finalize initialization
  83.         parent::__construct($options);
  84.     }
  85.  
  86.     /**
  87.      * Database object destructor
  88.      *
  89.      * @since   12.1
  90.      */
  91.     public function __destruct()
  92.     {
  93.         $this->disconnect();
  94.     }
  95.  
  96.     /**
  97.      * Connects to the database if needed.
  98.      *
  99.      * @return  void  Returns void if the database connected successfully.
  100.      *
  101.      * @since   12.1
  102.      * @throws  RuntimeException
  103.      */
  104.     public function connect()
  105.     {
  106.         if ($this->connection)
  107.         {
  108.             return;
  109.         }
  110.  
  111.         // Make sure the postgresql extension for PHP is installed and enabled.
  112.         if (!function_exists('pg_connect'))
  113.         {
  114.             throw new RuntimeException('PHP extension pg_connect is not available.');
  115.         }
  116.  
  117.         // Build the DSN for the connection.
  118.         $dsn "host={$this->options['host']} dbname={$this->options['database']} user={$this->options['user']} password={$this->options['password']}";
  119.  
  120.         // Attempt to connect to the server.
  121.         if (!($this->connection = @pg_connect($dsn)))
  122.         {
  123.             throw new RuntimeException('Error connecting to PGSQL database.');
  124.         }
  125.  
  126.         pg_set_error_verbosity($this->connectionPGSQL_ERRORS_DEFAULT);
  127.         pg_query('SET standard_conforming_strings=off');
  128.     }
  129.  
  130.     /**
  131.      * Disconnects the database.
  132.      *
  133.      * @return  void 
  134.      *
  135.      * @since   12.1
  136.      */
  137.     public function disconnect()
  138.     {
  139.         // Close the connection.
  140.         if (is_resource($this->connection))
  141.         {
  142.             foreach ($this->disconnectHandlers as $h)
  143.             {
  144.                 call_user_func_array($harray&$this));
  145.             }
  146.  
  147.             pg_close($this->connection);
  148.         }
  149.  
  150.         $this->connection = null;
  151.     }
  152.  
  153.     /**
  154.      * Method to escape a string for usage in an SQL statement.
  155.      *
  156.      * @param   string   $text   The string to be escaped.
  157.      * @param   boolean  $extra  Optional parameter to provide extra escaping.
  158.      *
  159.      * @return  string  The escaped string.
  160.      *
  161.      * @since   12.1
  162.      */
  163.     public function escape($text$extra false)
  164.     {
  165.         $this->connect();
  166.  
  167.         $result pg_escape_string($this->connection$text);
  168.  
  169.         if ($extra)
  170.         {
  171.             $result addcslashes($result'%_');
  172.         }
  173.  
  174.         return $result;
  175.     }
  176.  
  177.     /**
  178.      * Test to see if the PostgreSQL connector is available
  179.      *
  180.      * @return  boolean  True on success, false otherwise.
  181.      *
  182.      * @since   12.1
  183.      */
  184.     public static function test()
  185.     {
  186.         return (function_exists('pg_connect'));
  187.     }
  188.  
  189.     /**
  190.      * Determines if the connection to the server is active.
  191.      *
  192.      * @return    boolean 
  193.      *
  194.      * @since    12.1
  195.      */
  196.     public function connected()
  197.     {
  198.         $this->connect();
  199.  
  200.         if (is_resource($this->connection))
  201.         {
  202.             return pg_ping($this->connection);
  203.         }
  204.  
  205.         return false;
  206.     }
  207.  
  208.     /**
  209.      * Drops a table from the database.
  210.      *
  211.      * @param   string   $tableName  The name of the database table to drop.
  212.      * @param   boolean  $ifExists   Optionally specify that the table must exist before it is dropped.
  213.      *
  214.      * @return  boolean 
  215.      *
  216.      * @since   12.1
  217.      * @throws  RuntimeException
  218.      */
  219.     public function dropTable($tableName$ifExists true)
  220.     {
  221.         $this->connect();
  222.  
  223.         $this->setQuery('DROP TABLE ' ($ifExists 'IF EXISTS ' ''$this->quoteName($tableName));
  224.         $this->execute();
  225.  
  226.         return true;
  227.     }
  228.  
  229.     /**
  230.      * Get the number of affected rows for the previous executed SQL statement.
  231.      *
  232.      * @return  integer  The number of affected rows in the previous operation
  233.      *
  234.      * @since   12.1
  235.      */
  236.     public function getAffectedRows()
  237.     {
  238.         $this->connect();
  239.  
  240.         return pg_affected_rows($this->cursor);
  241.     }
  242.  
  243.     /**
  244.      * Method to get the database collation in use by sampling a text field of a table in the database.
  245.      *
  246.      * @return  mixed  The collation in use by the database or boolean false if not supported.
  247.      *
  248.      * @since   12.1
  249.      * @throws  RuntimeException
  250.      */
  251.     public function getCollation()
  252.     {
  253.         $this->connect();
  254.  
  255.         $this->setQuery('SHOW LC_COLLATE');
  256.         $array $this->loadAssocList();
  257.  
  258.         return $array[0]['lc_collate'];
  259.     }
  260.  
  261.     /**
  262.      * Get the number of returned rows for the previous executed SQL statement.
  263.      *
  264.      * @param   resource  $cur  An optional database cursor resource to extract the row count from.
  265.      *
  266.      * @return  integer   The number of returned rows.
  267.      *
  268.      * @since   12.1
  269.      */
  270.     public function getNumRows($cur null)
  271.     {
  272.         $this->connect();
  273.  
  274.         return pg_num_rows((int) $cur $cur $this->cursor);
  275.     }
  276.  
  277.     /**
  278.      * Get the current or query, or new JDatabaseQuery object.
  279.      *
  280.      * @param   boolean  $new    False to return the last query set, True to return a new JDatabaseQuery object.
  281.      * @param   boolean  $asObj  False to return last query as string, true to get JDatabaseQueryPostgresql object.
  282.      *
  283.      * @return  JDatabaseQuery  The current query object or a new object extending the JDatabaseQuery class.
  284.      *
  285.      * @since   12.1
  286.      * @throws  RuntimeException
  287.      */
  288.     public function getQuery($new false$asObj false)
  289.     {
  290.         if ($new)
  291.         {
  292.             // Make sure we have a query class for this driver.
  293.             if (!class_exists('JDatabaseQueryPostgresql'))
  294.             {
  295.                 throw new RuntimeException('JDatabaseQueryPostgresql Class not found.');
  296.             }
  297.  
  298.             $this->queryObject = new JDatabaseQueryPostgresql($this);
  299.  
  300.             return $this->queryObject;
  301.         }
  302.         else
  303.         {
  304.             if ($asObj)
  305.             {
  306.                 return $this->queryObject;
  307.             }
  308.             else
  309.             {
  310.                 return $this->sql;
  311.             }
  312.         }
  313.     }
  314.  
  315.     /**
  316.      * Shows the table CREATE statement that creates the given tables.
  317.      *
  318.      * This is unsuported by PostgreSQL.
  319.      *
  320.      * @param   mixed  $tables  A table name or a list of table names.
  321.      *
  322.      * @return  string  An empty char because this function is not supported by PostgreSQL.
  323.      *
  324.      * @since   12.1
  325.      */
  326.     public function getTableCreate($tables)
  327.     {
  328.         return '';
  329.     }
  330.  
  331.     /**
  332.      * Retrieves field information about a given table.
  333.      *
  334.      * @param   string   $table     The name of the database table.
  335.      * @param   boolean  $typeOnly  True to only return field types.
  336.      *
  337.      * @return  array  An array of fields for the database table.
  338.      *
  339.      * @since   12.1
  340.      * @throws  RuntimeException
  341.      */
  342.     public function getTableColumns($table$typeOnly true)
  343.     {
  344.         $this->connect();
  345.  
  346.         $result array();
  347.  
  348.         $tableSub $this->replacePrefix($table);
  349.  
  350.         $this->setQuery('
  351.             SELECT a.attname AS "column_name",
  352.                 pg_catalog.format_type(a.atttypid, a.atttypmod) as "type",
  353.                 CASE WHEN a.attnotnull IS TRUE
  354.                     THEN \'NO\'
  355.                     ELSE \'YES\'
  356.                 END AS "null",
  357.                 CASE WHEN pg_catalog.pg_get_expr(adef.adbin, adef.adrelid, true) IS NOT NULL
  358.                     THEN pg_catalog.pg_get_expr(adef.adbin, adef.adrelid, true)
  359.                 END as "Default",
  360.                 CASE WHEN pg_catalog.col_description(a.attrelid, a.attnum) IS NULL
  361.                 THEN \'\'
  362.                 ELSE pg_catalog.col_description(a.attrelid, a.attnum)
  363.                 END  AS "comments"
  364.             FROM pg_catalog.pg_attribute a
  365.             LEFT JOIN pg_catalog.pg_attrdef adef ON a.attrelid=adef.adrelid AND a.attnum=adef.adnum
  366.             LEFT JOIN pg_catalog.pg_type t ON a.atttypid=t.oid
  367.             WHERE a.attrelid =
  368.                 (SELECT oid FROM pg_catalog.pg_class WHERE relname=' $this->quote($tableSub'
  369.                     AND relnamespace = (SELECT oid FROM pg_catalog.pg_namespace WHERE
  370.                     nspname = \'public\')
  371.                 )
  372.             AND a.attnum > 0 AND NOT a.attisdropped
  373.             ORDER BY a.attnum'
  374.         );
  375.  
  376.         $fields $this->loadObjectList();
  377.  
  378.         if ($typeOnly)
  379.         {
  380.             foreach ($fields as $field)
  381.             {
  382.                 $result[$field->column_namepreg_replace("/[(0-9)]/"''$field->type);
  383.             }
  384.         }
  385.         else
  386.         {
  387.             foreach ($fields as $field)
  388.             {
  389.                 $result[$field->column_name$field;
  390.             }
  391.         }
  392.  
  393.         /* Change Postgresql's NULL::* type with PHP's null one */
  394.         foreach ($fields as $field)
  395.         {
  396.             if (preg_match("/^NULL::*/"$field->Default))
  397.             {
  398.                 $field->Default null;
  399.             }
  400.         }
  401.  
  402.         return $result;
  403.     }
  404.  
  405.     /**
  406.      * Get the details list of keys for a table.
  407.      *
  408.      * @param   string  $table  The name of the table.
  409.      *
  410.      * @return  array  An array of the column specification for the table.
  411.      *
  412.      * @since   12.1
  413.      * @throws  RuntimeException
  414.      */
  415.     public function getTableKeys($table)
  416.     {
  417.         $this->connect();
  418.  
  419.         // To check if table exists and prevent SQL injection
  420.         $tableList $this->getTableList();
  421.  
  422.         if (in_array($table$tableList))
  423.         {
  424.             // Get the details columns information.
  425.             $this->setQuery('
  426.                 SELECT indexname AS "idxName", indisprimary AS "isPrimary", indisunique  AS "isUnique",
  427.                     CASE WHEN indisprimary = true THEN
  428.                         ( SELECT \'ALTER TABLE \' || tablename || \' ADD \' || pg_catalog.pg_get_constraintdef(const.oid, true)
  429.                             FROM pg_constraint AS const WHERE const.conname= pgClassFirst.relname )
  430.                     ELSE pg_catalog.pg_get_indexdef(indexrelid, 0, true)
  431.                     END AS "Query"
  432.                 FROM pg_indexes
  433.                 LEFT JOIN pg_class AS pgClassFirst ON indexname=pgClassFirst.relname
  434.                 LEFT JOIN pg_index AS pgIndex ON pgClassFirst.oid=pgIndex.indexrelid
  435.                 WHERE tablename=' $this->quote($table' ORDER BY indkey'
  436.             );
  437.  
  438.             $keys $this->loadObjectList();
  439.  
  440.             return $keys;
  441.         }
  442.  
  443.         return false;
  444.     }
  445.  
  446.     /**
  447.      * Method to get an array of all tables in the database.
  448.      *
  449.      * @return  array  An array of all the tables in the database.
  450.      *
  451.      * @since   12.1
  452.      * @throws  RuntimeException
  453.      */
  454.     public function getTableList()
  455.     {
  456.         $this->connect();
  457.  
  458.         $query $this->getQuery(true)
  459.             ->select('table_name')
  460.             ->from('information_schema.tables')
  461.             ->where('table_type=' $this->quote('BASE TABLE'))
  462.             ->where('table_schema NOT IN (' $this->quote('pg_catalog'', ' $this->quote('information_schema'')')
  463.             ->order('table_name ASC');
  464.  
  465.         $this->setQuery($query);
  466.         $tables $this->loadColumn();
  467.  
  468.         return $tables;
  469.     }
  470.  
  471.     /**
  472.      * Get the details list of sequences for a table.
  473.      *
  474.      * @param   string  $table  The name of the table.
  475.      *
  476.      * @return  array  An array of sequences specification for the table.
  477.      *
  478.      * @since   12.1
  479.      * @throws  RuntimeException
  480.      */
  481.     public function getTableSequences($table)
  482.     {
  483.         $this->connect();
  484.  
  485.         // To check if table exists and prevent SQL injection
  486.         $tableList $this->getTableList();
  487.  
  488.         if (in_array($table$tableList))
  489.         {
  490.             $name array(
  491.                 's.relname''n.nspname''t.relname''a.attname''info.data_type''info.minimum_value''info.maximum_value',
  492.                 'info.increment''info.cycle_option'
  493.             );
  494.             $as array('sequence''schema''table''column''data_type''minimum_value''maximum_value''increment''cycle_option');
  495.  
  496.             if (version_compare($this->getVersion()'9.1.0'>= 0)
  497.             {
  498.                 $name[.= 'info.start_value';
  499.                 $as[.= 'start_value';
  500.             }
  501.  
  502.             // Get the details columns information.
  503.             $query $this->getQuery(true)
  504.                 ->select($this->quoteName($name$as))
  505.                 ->from('pg_class AS s')
  506.                 ->join('LEFT'"pg_depend d ON d.objid=s.oid AND d.classid='pg_class'::regclass AND d.refclassid='pg_class'::regclass")
  507.                 ->join('LEFT''pg_class t ON t.oid=d.refobjid')
  508.                 ->join('LEFT''pg_namespace n ON n.oid=t.relnamespace')
  509.                 ->join('LEFT''pg_attribute a ON a.attrelid=t.oid AND a.attnum=d.refobjsubid')
  510.                 ->join('LEFT''information_schema.sequences AS info ON info.sequence_name=s.relname')
  511.                 ->where("s.relkind='S' AND d.deptype='a' AND t.relname=" $this->quote($table));
  512.             $this->setQuery($query);
  513.             $seq $this->loadObjectList();
  514.  
  515.             return $seq;
  516.         }
  517.  
  518.         return false;
  519.     }
  520.  
  521.     /**
  522.      * Get the version of the database connector.
  523.      *
  524.      * @return  string  The database connector version.
  525.      *
  526.      * @since   12.1
  527.      */
  528.     public function getVersion()
  529.     {
  530.         $this->connect();
  531.         $version pg_version($this->connection);
  532.  
  533.         return $version['server'];
  534.     }
  535.  
  536.     /**
  537.      * Method to get the auto-incremented value from the last INSERT statement.
  538.      * To be called after the INSERT statement, it's MANDATORY to have a sequence on
  539.      * every primary key table.
  540.      *
  541.      * To get the auto incremented value it's possible to call this function after
  542.      * INSERT INTO query, or use INSERT INTO with RETURNING clause.
  543.      *
  544.      * @example with insertid() call:
  545.      *         $query = $this->getQuery(true)
  546.      *             ->insert('jos_dbtest')
  547.      *             ->columns('title,start_date,description')
  548.      *             ->values("'testTitle2nd','1971-01-01','testDescription2nd'");
  549.      *         $this->setQuery($query);
  550.      *         $this->execute();
  551.      *         $id = $this->insertid();
  552.      *
  553.      * @example with RETURNING clause:
  554.      *         $query = $this->getQuery(true)
  555.      *             ->insert('jos_dbtest')
  556.      *             ->columns('title,start_date,description')
  557.      *             ->values("'testTitle2nd','1971-01-01','testDescription2nd'")
  558.      *             ->returning('id');
  559.      *         $this->setQuery($query);
  560.      *         $id = $this->loadResult();
  561.      *
  562.      * @return  integer  The value of the auto-increment field from the last inserted row.
  563.      *
  564.      * @since   12.1
  565.      */
  566.     public function insertid()
  567.     {
  568.         $this->connect();
  569.         $insertQuery $this->getQuery(falsetrue);
  570.         $table $insertQuery->__get('insert')->getElements();
  571.  
  572.         /* find sequence column name */
  573.         $colNameQuery $this->getQuery(true);
  574.         $colNameQuery->select('column_default')
  575.             ->from('information_schema.columns')
  576.             ->where("table_name=" $this->quote($this->replacePrefix(str_replace('"'''$table[0])))'AND')
  577.             ->where("column_default LIKE '%nextval%'");
  578.  
  579.         $this->setQuery($colNameQuery);
  580.         $colName $this->loadRow();
  581.         $changedColName str_replace('nextval''currval'$colName);
  582.  
  583.         $insertidQuery $this->getQuery(true);
  584.         $insertidQuery->select($changedColName);
  585.         $this->setQuery($insertidQuery);
  586.         $insertVal $this->loadRow();
  587.  
  588.         return $insertVal[0];
  589.     }
  590.  
  591.     /**
  592.      * Locks a table in the database.
  593.      *
  594.      * @param   string  $tableName  The name of the table to unlock.
  595.      *
  596.      * @return  JDatabaseDriverPostgresql  Returns this object to support chaining.
  597.      *
  598.      * @since   12.1
  599.      * @throws  RuntimeException
  600.      */
  601.     public function lockTable($tableName)
  602.     {
  603.         $this->transactionStart();
  604.         $this->setQuery('LOCK TABLE ' $this->quoteName($tableName' IN ACCESS EXCLUSIVE MODE')->execute();
  605.  
  606.         return $this;
  607.     }
  608.  
  609.     /**
  610.      * Execute the SQL statement.
  611.      *
  612.      * @return  mixed  A database cursor resource on success, boolean false on failure.
  613.      *
  614.      * @since   12.1
  615.      * @throws  RuntimeException
  616.      */
  617.     public function execute()
  618.     {
  619.         $this->connect();
  620.  
  621.         if (!is_resource($this->connection))
  622.         {
  623.             JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED'$this->errorNum$this->errorMsg)JLog::ERROR'database');
  624.             throw new RuntimeException($this->errorMsg$this->errorNum);
  625.         }
  626.  
  627.         // Take a local copy so that we don't modify the original query and cause issues later
  628.         $query $this->replacePrefix((string) $this->sql);
  629.  
  630.         if (!($this->sql instanceof JDatabaseQuery&& ($this->limit > || $this->offset > 0))
  631.         {
  632.             $query .= ' LIMIT ' $this->limit . ' OFFSET ' $this->offset;
  633.         }
  634.  
  635.         // Increment the query counter.
  636.         $this->count++;
  637.  
  638.         // Reset the error values.
  639.         $this->errorNum = 0;
  640.         $this->errorMsg = '';
  641.  
  642.         // If debugging is enabled then let's log the query.
  643.         if ($this->debug)
  644.         {
  645.             // Add the query to the object queue.
  646.             $this->log[$query;
  647.  
  648.             JLog::add($queryJLog::DEBUG'databasequery');
  649.  
  650.             $this->timings[microtime(true);
  651.         }
  652.  
  653.         // Execute the query. Error suppression is used here to prevent warnings/notices that the connection has been lost.
  654.         $this->cursor = @pg_query($this->connection$query);
  655.  
  656.         if ($this->debug)
  657.         {
  658.             $this->timings[microtime(true);
  659.  
  660.             if (defined('DEBUG_BACKTRACE_IGNORE_ARGS'))
  661.             {
  662.                 $this->callStacks[debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
  663.             }
  664.             else
  665.             {
  666.                 $this->callStacks[debug_backtrace();
  667.             }
  668.         }
  669.  
  670.         // If an error occurred handle it.
  671.         if (!$this->cursor)
  672.         {
  673.             // Check if the server was disconnected.
  674.             if (!$this->connected())
  675.             {
  676.                 try
  677.                 {
  678.                     // Attempt to reconnect.
  679.                     $this->connection = null;
  680.                     $this->connect();
  681.                 }
  682.                 // If connect fails, ignore that exception and throw the normal exception.
  683.                 catch (RuntimeException $e)
  684.                 {
  685.                     // Get the error number and message.
  686.                     $this->errorNum = (int) pg_result_error_field($this->cursorPGSQL_DIAG_SQLSTATE' ';
  687.                     $this->errorMsg = JText::_('JLIB_DATABASE_QUERY_FAILED'"\n" pg_last_error($this->connection"\nSQL=" $query;
  688.  
  689.                     // Throw the normal query exception.
  690.                     JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED'$this->errorNum$this->errorMsg)JLog::ERROR'databasequery');
  691.                     throw new RuntimeException($this->errorMsg);
  692.                 }
  693.  
  694.                 // Since we were able to reconnect, run the query again.
  695.                 return $this->execute();
  696.             }
  697.             // The server was not disconnected.
  698.             else
  699.             {
  700.                 // Get the error number and message.
  701.                 $this->errorNum = (int) pg_result_error_field($this->cursorPGSQL_DIAG_SQLSTATE' ';
  702.                 $this->errorMsg = JText::_('JLIB_DATABASE_QUERY_FAILED'"\n" pg_last_error($this->connection"\nSQL=" $query;
  703.  
  704.                 // Throw the normal query exception.
  705.                 JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED'$this->errorNum$this->errorMsg)JLog::ERROR'databasequery');
  706.                 throw new RuntimeException($this->errorMsg);
  707.             }
  708.         }
  709.  
  710.         return $this->cursor;
  711.     }
  712.  
  713.     /**
  714.      * Renames a table in the database.
  715.      *
  716.      * @param   string  $oldTable  The name of the table to be renamed
  717.      * @param   string  $newTable  The new name for the table.
  718.      * @param   string  $backup    Not used by PostgreSQL.
  719.      * @param   string  $prefix    Not used by PostgreSQL.
  720.      *
  721.      * @return  JDatabaseDriverPostgresql  Returns this object to support chaining.
  722.      *
  723.      * @since   12.1
  724.      * @throws  RuntimeException
  725.      */
  726.     public function renameTable($oldTable$newTable$backup null$prefix null)
  727.     {
  728.         $this->connect();
  729.  
  730.         // To check if table exists and prevent SQL injection
  731.         $tableList $this->getTableList();
  732.  
  733.         // Origin Table does not exist
  734.         if (!in_array($oldTable$tableList))
  735.         {
  736.             // Origin Table not found
  737.             throw new RuntimeException('Table not found in Postgresql database.');
  738.         }
  739.         else
  740.         {
  741.             /* Rename indexes */
  742.             $this->setQuery(
  743.                 'SELECT relname
  744.                     FROM pg_class
  745.                     WHERE oid IN (
  746.                         SELECT indexrelid
  747.                         FROM pg_index, pg_class
  748.                         WHERE pg_class.relname=' $this->quote($oldTabletrue'
  749.                         AND pg_class.oid=pg_index.indrelid );'
  750.             );
  751.  
  752.             $oldIndexes $this->loadColumn();
  753.  
  754.             foreach ($oldIndexes as $oldIndex)
  755.             {
  756.                 $changedIdxName str_replace($oldTable$newTable$oldIndex);
  757.                 $this->setQuery('ALTER INDEX ' $this->escape($oldIndex' RENAME TO ' $this->escape($changedIdxName));
  758.                 $this->execute();
  759.             }
  760.  
  761.             /* Rename sequence */
  762.             $this->setQuery(
  763.                 'SELECT relname
  764.                     FROM pg_class
  765.                     WHERE relkind = \'S\'
  766.                     AND relnamespace IN (
  767.                         SELECT oid
  768.                         FROM pg_namespace
  769.                         WHERE nspname NOT LIKE \'pg_%\'
  770.                         AND nspname != \'information_schema\'
  771.                     )
  772.                     AND relname LIKE \'%' $oldTable '%\' ;'
  773.             );
  774.  
  775.             $oldSequences $this->loadColumn();
  776.  
  777.             foreach ($oldSequences as $oldSequence)
  778.             {
  779.                 $changedSequenceName str_replace($oldTable$newTable$oldSequence);
  780.                 $this->setQuery('ALTER SEQUENCE ' $this->escape($oldSequence' RENAME TO ' $this->escape($changedSequenceName));
  781.                 $this->execute();
  782.             }
  783.  
  784.             /* Rename table */
  785.             $this->setQuery('ALTER TABLE ' $this->escape($oldTable' RENAME TO ' $this->escape($newTable));
  786.             $this->execute();
  787.         }
  788.  
  789.         return true;
  790.     }
  791.  
  792.     /**
  793.      * Selects the database, but redundant for PostgreSQL
  794.      *
  795.      * @param   string  $database  Database name to select.
  796.      *
  797.      * @return  boolean  Always true
  798.      *
  799.      * @since   12.1
  800.      */
  801.     public function select($database)
  802.     {
  803.         return true;
  804.     }
  805.  
  806.     /**
  807.      * Custom settings for UTF support
  808.      *
  809.      * @return  integer  Zero on success, -1 on failure
  810.      *
  811.      * @since   12.1
  812.      */
  813.     public function setUTF()
  814.     {
  815.         $this->connect();
  816.  
  817.         return pg_set_client_encoding($this->connection'UTF8');
  818.     }
  819.  
  820.     /**
  821.      * This function return a field value as a prepared string to be used in a SQL statement.
  822.      *
  823.      * @param   array   $columns      Array of table's column returned by ::getTableColumns.
  824.      * @param   string  $field_name   The table field's name.
  825.      * @param   string  $field_value  The variable value to quote and return.
  826.      *
  827.      * @return  string  The quoted string.
  828.      *
  829.      * @since   12.1
  830.      */
  831.     public function sqlValue($columns$field_name$field_value)
  832.     {
  833.         switch ($columns[$field_name])
  834.         {
  835.             case 'boolean':
  836.                 $val 'NULL';
  837.  
  838.                 if ($field_value == 't')
  839.                 {
  840.                     $val 'TRUE';
  841.                 }
  842.                 elseif ($field_value == 'f')
  843.                 {
  844.                     $val 'FALSE';
  845.                 }
  846.  
  847.                 break;
  848.  
  849.             case 'bigint':
  850.             case 'bigserial':
  851.             case 'integer':
  852.             case 'money':
  853.             case 'numeric':
  854.             case 'real':
  855.             case 'smallint':
  856.             case 'serial':
  857.             case 'numeric,':
  858.                 $val strlen($field_value== 'NULL' $field_value;
  859.                 break;
  860.  
  861.             case 'date':
  862.             case 'timestamp without time zone':
  863.                 if (empty($field_value))
  864.                 {
  865.                     $field_value $this->getNullDate();
  866.                 }
  867.  
  868.                 $val $this->quote($field_value);
  869.                 break;
  870.  
  871.             default:
  872.                 $val $this->quote($field_value);
  873.                 break;
  874.         }
  875.  
  876.         return $val;
  877.     }
  878.  
  879.     /**
  880.      * Method to commit a transaction.
  881.      *
  882.      * @param   boolean  $toSavepoint  If true, commit to the last savepoint.
  883.      *
  884.      * @return  void 
  885.      *
  886.      * @since   12.1
  887.      * @throws  RuntimeException
  888.      */
  889.     public function transactionCommit($toSavepoint false)
  890.     {
  891.         $this->connect();
  892.  
  893.         if (!$toSavepoint || $this->transactionDepth <= 1)
  894.         {
  895.             if ($this->setQuery('COMMIT')->execute())
  896.             {
  897.                 $this->transactionDepth = 0;
  898.             }
  899.  
  900.             return;
  901.         }
  902.  
  903.         $this->transactionDepth--;
  904.     }
  905.  
  906.     /**
  907.      * Method to roll back a transaction.
  908.      *
  909.      * @param   boolean  $toSavepoint  If true, rollback to the last savepoint.
  910.      *
  911.      * @return  void 
  912.      *
  913.      * @since   12.1
  914.      * @throws  RuntimeException
  915.      */
  916.     public function transactionRollback($toSavepoint false)
  917.     {
  918.         $this->connect();
  919.  
  920.         if (!$toSavepoint || $this->transactionDepth <= 1)
  921.         {
  922.             if ($this->setQuery('ROLLBACK')->execute())
  923.             {
  924.                 $this->transactionDepth = 0;
  925.             }
  926.  
  927.             return;
  928.         }
  929.  
  930.         $savepoint 'SP_' ($this->transactionDepth - 1);
  931.         $this->setQuery('ROLLBACK TO SAVEPOINT ' $this->quoteName($savepoint));
  932.  
  933.         if ($this->execute())
  934.         {
  935.             $this->transactionDepth--;
  936.             $this->setQuery('RELEASE SAVEPOINT ' $this->quoteName($savepoint))->execute();
  937.         }
  938.     }
  939.  
  940.     /**
  941.      * Method to initialize a transaction.
  942.      *
  943.      * @param   boolean  $asSavepoint  If true and a transaction is already active, a savepoint will be created.
  944.      *
  945.      * @return  void 
  946.      *
  947.      * @since   12.1
  948.      * @throws  RuntimeException
  949.      */
  950.     public function transactionStart($asSavepoint false)
  951.     {
  952.         $this->connect();
  953.  
  954.         if (!$asSavepoint || !$this->transactionDepth)
  955.         {
  956.             if ($this->setQuery('START TRANSACTION')->execute())
  957.             {
  958.                 $this->transactionDepth = 1;
  959.             }
  960.  
  961.             return;
  962.         }
  963.  
  964.         $savepoint 'SP_' $this->transactionDepth;
  965.         $this->setQuery('SAVEPOINT ' $this->quoteName($savepoint));
  966.  
  967.         if ($this->execute())
  968.         {
  969.             $this->transactionDepth++;
  970.         }
  971.     }
  972.  
  973.     /**
  974.      * Method to fetch a row from the result set cursor as an array.
  975.      *
  976.      * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
  977.      *
  978.      * @return  mixed  Either the next row from the result set or false if there are no more rows.
  979.      *
  980.      * @since   12.1
  981.      */
  982.     protected function fetchArray($cursor null)
  983.     {
  984.         return pg_fetch_row($cursor $cursor $this->cursor);
  985.     }
  986.  
  987.     /**
  988.      * Method to fetch a row from the result set cursor as an associative array.
  989.      *
  990.      * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
  991.      *
  992.      * @return  mixed  Either the next row from the result set or false if there are no more rows.
  993.      *
  994.      * @since   12.1
  995.      */
  996.     protected function fetchAssoc($cursor null)
  997.     {
  998.         return pg_fetch_assoc($cursor $cursor $this->cursor);
  999.     }
  1000.  
  1001.     /**
  1002.      * Method to fetch a row from the result set cursor as an object.
  1003.      *
  1004.      * @param   mixed   $cursor  The optional result set cursor from which to fetch the row.
  1005.      * @param   string  $class   The class name to use for the returned row object.
  1006.      *
  1007.      * @return  mixed   Either the next row from the result set or false if there are no more rows.
  1008.      *
  1009.      * @since   12.1
  1010.      */
  1011.     protected function fetchObject($cursor null$class 'stdClass')
  1012.     {
  1013.         return pg_fetch_object(is_null($cursor$this->cursor : $cursornull$class);
  1014.     }
  1015.  
  1016.     /**
  1017.      * Method to free up the memory used for the result set.
  1018.      *
  1019.      * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
  1020.      *
  1021.      * @return  void 
  1022.      *
  1023.      * @since   12.1
  1024.      */
  1025.     protected function freeResult($cursor null)
  1026.     {
  1027.         pg_free_result($cursor $cursor $this->cursor);
  1028.     }
  1029.  
  1030.     /**
  1031.      * Inserts a row into a table based on an object's properties.
  1032.      *
  1033.      * @param   string  $table    The name of the database table to insert into.
  1034.      * @param   object  &$object  A reference to an object whose public properties match the table fields.
  1035.      * @param   string  $key      The name of the primary key. If provided the object property is updated.
  1036.      *
  1037.      * @return  boolean    True on success.
  1038.      *
  1039.      * @since   12.1
  1040.      * @throws  RuntimeException
  1041.      */
  1042.     public function insertObject($table&$object$key null)
  1043.     {
  1044.         $columns $this->getTableColumns($table);
  1045.  
  1046.         $fields array();
  1047.         $values array();
  1048.  
  1049.         // Iterate over the object variables to build the query fields and values.
  1050.         foreach (get_object_vars($objectas $k => $v)
  1051.         {
  1052.             // Only process non-null scalars.
  1053.             if (is_array($vor is_object($vor $v === null)
  1054.             {
  1055.                 continue;
  1056.             }
  1057.  
  1058.             // Ignore any internal fields.
  1059.             if ($k[0== '_')
  1060.             {
  1061.                 continue;
  1062.             }
  1063.  
  1064.             // Prepare and sanitize the fields and values for the database query.
  1065.             $fields[$this->quoteName($k);
  1066.             $values[$this->sqlValue($columns$k$v);
  1067.         }
  1068.  
  1069.         // Create the base insert statement.
  1070.         $query $this->getQuery(true)
  1071.             ->insert($this->quoteName($table))
  1072.             ->columns($fields)
  1073.             ->values(implode(','$values));
  1074.  
  1075.         $retVal false;
  1076.  
  1077.         if ($key)
  1078.         {
  1079.             $query->returning($key);
  1080.  
  1081.             // Set the query and execute the insert.
  1082.             $this->setQuery($query);
  1083.  
  1084.             $id $this->loadResult();
  1085.  
  1086.             if ($id)
  1087.             {
  1088.                 $object->$key $id;
  1089.                 $retVal true;
  1090.             }
  1091.         }
  1092.         else
  1093.         {
  1094.             // Set the query and execute the insert.
  1095.             $this->setQuery($query);
  1096.  
  1097.             if ($this->execute())
  1098.             {
  1099.                 $retVal true;
  1100.             }
  1101.         }
  1102.  
  1103.         return $retVal;
  1104.     }
  1105.  
  1106.     /**
  1107.      * Test to see if the PostgreSQL connector is available.
  1108.      *
  1109.      * @return  boolean  True on success, false otherwise.
  1110.      *
  1111.      * @since   12.1
  1112.      */
  1113.     public static function isSupported()
  1114.     {
  1115.         return (function_exists('pg_connect'));
  1116.     }
  1117.  
  1118.     /**
  1119.      * Returns an array containing database's table list.
  1120.      *
  1121.      * @return  array  The database's table list.
  1122.      *
  1123.      * @since   12.1
  1124.      */
  1125.     public function showTables()
  1126.     {
  1127.         $this->connect();
  1128.  
  1129.         $query $this->getQuery(true)
  1130.             ->select('table_name')
  1131.             ->from('information_schema.tables')
  1132.             ->where('table_type = ' $this->quote('BASE TABLE'))
  1133.             ->where('table_schema NOT IN (' $this->quote('pg_catalog'', ' $this->quote('information_schema'' )');
  1134.  
  1135.         $this->setQuery($query);
  1136.         $tableList $this->loadColumn();
  1137.  
  1138.         return $tableList;
  1139.     }
  1140.  
  1141.     /**
  1142.      * Get the substring position inside a string
  1143.      *
  1144.      * @param   string  $substring  The string being sought
  1145.      * @param   string  $string     The string/column being searched
  1146.      *
  1147.      * @return  integer  The position of $substring in $string
  1148.      *
  1149.      * @since   12.1
  1150.      */
  1151.     public function getStringPositionSQL$substring$string )
  1152.     {
  1153.         $this->connect();
  1154.  
  1155.         $query "SELECT POSITION( $substring IN $string )";
  1156.         $this->setQuery($query);
  1157.         $position $this->loadRow();
  1158.  
  1159.         return $position['position'];
  1160.     }
  1161.  
  1162.     /**
  1163.      * Generate a random value
  1164.      *
  1165.      * @return  float  The random generated number
  1166.      *
  1167.      * @since   12.1
  1168.      */
  1169.     public function getRandom()
  1170.     {
  1171.         $this->connect();
  1172.  
  1173.         $this->setQuery('SELECT RANDOM()');
  1174.         $random $this->loadAssoc();
  1175.  
  1176.         return $random['random'];
  1177.     }
  1178.  
  1179.     /**
  1180.      * Get the query string to alter the database character set.
  1181.      *
  1182.      * @param   string  $dbName  The database name
  1183.      *
  1184.      * @return  string  The query that alter the database query string
  1185.      *
  1186.      * @since   12.1
  1187.      */
  1188.     public function getAlterDbCharacterSet$dbName )
  1189.     {
  1190.         $query 'ALTER DATABASE ' $this->quoteName($dbName' SET CLIENT_ENCODING TO ' $this->quote('UTF8');
  1191.  
  1192.         return $query;
  1193.     }
  1194.  
  1195.     /**
  1196.      * Get the query string to create new Database in correct PostgreSQL syntax.
  1197.      *
  1198.      * @param   object   $options  object coming from "initialise" function to pass user and database name to database driver.
  1199.      * @param   boolean  $utf      True if the database supports the UTF-8 character set, not used in PostgreSQL "CREATE DATABASE" query.
  1200.      *
  1201.      * @return  string    The query that creates database, owned by $options['user']
  1202.      *
  1203.      * @since   12.1
  1204.      */
  1205.     public function getCreateDbQuery($options$utf)
  1206.     {
  1207.         $query 'CREATE DATABASE ' $this->quoteName($options->db_name' OWNER ' $this->quoteName($options->db_user);
  1208.  
  1209.         if ($utf)
  1210.         {
  1211.             $query .= ' ENCODING ' $this->quote('UTF-8');
  1212.         }
  1213.  
  1214.         return $query;
  1215.     }
  1216.  
  1217.     /**
  1218.      * This function replaces a string identifier <var>$prefix</var> with the string held is the
  1219.      * <var>tablePrefix</var> class variable.
  1220.      *
  1221.      * @param   string  $query   The SQL statement to prepare.
  1222.      * @param   string  $prefix  The common table prefix.
  1223.      *
  1224.      * @return  string  The processed SQL statement.
  1225.      *
  1226.      * @since   12.1
  1227.      */
  1228.     public function replacePrefix($query$prefix '#__')
  1229.     {
  1230.         $query trim($query);
  1231.  
  1232.         if (strpos($query'\''))
  1233.         {
  1234.             // Sequence name quoted with ' ' but need to be replaced
  1235.             if (strpos($query'currval'))
  1236.             {
  1237.                 $query explode('currval'$query);
  1238.  
  1239.                 for ($nIndex 1$nIndex count($query)$nIndex $nIndex 2)
  1240.                 {
  1241.                     $query[$nIndexstr_replace($prefix$this->tablePrefix$query[$nIndex]);
  1242.                 }
  1243.  
  1244.                 $query implode('currval'$query);
  1245.             }
  1246.  
  1247.             // Sequence name quoted with ' ' but need to be replaced
  1248.             if (strpos($query'nextval'))
  1249.             {
  1250.                 $query explode('nextval'$query);
  1251.  
  1252.                 for ($nIndex 1$nIndex count($query)$nIndex $nIndex 2)
  1253.                 {
  1254.                     $query[$nIndexstr_replace($prefix$this->tablePrefix$query[$nIndex]);
  1255.                 }
  1256.  
  1257.                 $query implode('nextval'$query);
  1258.             }
  1259.  
  1260.             // Sequence name quoted with ' ' but need to be replaced
  1261.             if (strpos($query'setval'))
  1262.             {
  1263.                 $query explode('setval'$query);
  1264.  
  1265.                 for ($nIndex 1$nIndex count($query)$nIndex $nIndex 2)
  1266.                 {
  1267.                     $query[$nIndexstr_replace($prefix$this->tablePrefix$query[$nIndex]);
  1268.                 }
  1269.  
  1270.                 $query implode('setval'$query);
  1271.             }
  1272.  
  1273.             $explodedQuery explode('\''$query);
  1274.  
  1275.             for ($nIndex 0$nIndex count($explodedQuery)$nIndex $nIndex 2)
  1276.             {
  1277.                 if (strpos($explodedQuery[$nIndex]$prefix))
  1278.                 {
  1279.                     $explodedQuery[$nIndexstr_replace($prefix$this->tablePrefix$explodedQuery[$nIndex]);
  1280.                 }
  1281.             }
  1282.  
  1283.             $replacedQuery implode('\''$explodedQuery);
  1284.         }
  1285.         else
  1286.         {
  1287.             $replacedQuery str_replace($prefix$this->tablePrefix$query);
  1288.         }
  1289.  
  1290.         return $replacedQuery;
  1291.     }
  1292.  
  1293.     /**
  1294.      * Method to release a savepoint.
  1295.      *
  1296.      * @param   string  $savepointName  Savepoint's name to release
  1297.      *
  1298.      * @return  void 
  1299.      *
  1300.      * @since   12.1
  1301.      */
  1302.     public function releaseTransactionSavepoint$savepointName )
  1303.     {
  1304.         $this->connect();
  1305.         $this->setQuery('RELEASE SAVEPOINT ' $this->quoteName($this->escape($savepointName)));
  1306.         $this->execute();
  1307.     }
  1308.  
  1309.     /**
  1310.      * Method to create a savepoint.
  1311.      *
  1312.      * @param   string  $savepointName  Savepoint's name to create
  1313.      *
  1314.      * @return  void 
  1315.      *
  1316.      * @since   12.1
  1317.      */
  1318.     public function transactionSavepoint$savepointName )
  1319.     {
  1320.         $this->connect();
  1321.         $this->setQuery('SAVEPOINT ' $this->quoteName($this->escape($savepointName)));
  1322.         $this->execute();
  1323.     }
  1324.  
  1325.     /**
  1326.      * Unlocks tables in the database, this command does not exist in PostgreSQL,
  1327.      * it is automatically done on commit or rollback.
  1328.      *
  1329.      * @return  JDatabaseDriverPostgresql  Returns this object to support chaining.
  1330.      *
  1331.      * @since   12.1
  1332.      * @throws  RuntimeException
  1333.      */
  1334.     public function unlockTables()
  1335.     {
  1336.         $this->transactionCommit();
  1337.  
  1338.         return $this;
  1339.     }
  1340.  
  1341.     /**
  1342.      * Updates a row in a table based on an object's properties.
  1343.      *
  1344.      * @param   string   $table    The name of the database table to update.
  1345.      * @param   object   &$object  A reference to an object whose public properties match the table fields.
  1346.      * @param   array    $key      The name of the primary key.
  1347.      * @param   boolean  $nulls    True to update null fields or false to ignore them.
  1348.      *
  1349.      * @return  boolean  True on success.
  1350.      *
  1351.      * @since   12.1
  1352.      * @throws  RuntimeException
  1353.      */
  1354.     public function updateObject($table&$object$key$nulls false)
  1355.     {
  1356.         $columns $this->getTableColumns($table);
  1357.         $fields  array();
  1358.         $where   array();
  1359.  
  1360.         if (is_string($key))
  1361.         {
  1362.             $key array($key);
  1363.         }
  1364.  
  1365.         if (is_object($key))
  1366.         {
  1367.             $key = (array) $key;
  1368.         }
  1369.  
  1370.         // Create the base update statement.
  1371.         $statement 'UPDATE ' $this->quoteName($table' SET %s WHERE %s';
  1372.  
  1373.         // Iterate over the object variables to build the query fields/value pairs.
  1374.         foreach (get_object_vars($objectas $k => $v)
  1375.         {
  1376.             // Only process scalars that are not internal fields.
  1377.             if (is_array($vor is_object($vor $k[0== '_')
  1378.             {
  1379.                 continue;
  1380.             }
  1381.  
  1382.             // Set the primary key to the WHERE clause instead of a field to update.
  1383.             if (in_array($k$key))
  1384.             {
  1385.                 $key_val $this->sqlValue($columns$k$v);
  1386.                 $where[$this->quoteName($k'=' $key_val;
  1387.                 continue;
  1388.             }
  1389.  
  1390.             // Prepare and sanitize the fields and values for the database query.
  1391.             if ($v === null)
  1392.             {
  1393.                 // If the value is null and we want to update nulls then set it.
  1394.                 if ($nulls)
  1395.                 {
  1396.                     $val 'NULL';
  1397.                 }
  1398.                 // If the value is null and we do not want to update nulls then ignore this field.
  1399.                 else
  1400.                 {
  1401.                     continue;
  1402.                 }
  1403.             }
  1404.             // The field is not null so we prep it for update.
  1405.             else
  1406.             {
  1407.                 $val $this->sqlValue($columns$k$v);
  1408.             }
  1409.  
  1410.             // Add the field to be updated.
  1411.             $fields[$this->quoteName($k'=' $val;
  1412.         }
  1413.  
  1414.         // We don't have any fields to update.
  1415.         if (empty($fields))
  1416.         {
  1417.             return true;
  1418.         }
  1419.  
  1420.         // Set the query and execute the update.
  1421.         $this->setQuery(sprintf($statementimplode(","$fields)implode(' AND '$where)));
  1422.  
  1423.         return $this->execute();
  1424.     }
  1425. }

Documentation generated on Tue, 19 Nov 2013 15:11:08 +0100 by phpDocumentor 1.4.3