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 import driver.
  14.  *
  15.  * @package     Joomla.Platform
  16.  * @subpackage  Database
  17.  * @since       12.1
  18.  */
  19. {
  20.     /**
  21.      * Checks if all data and options are in order prior to exporting.
  22.      *
  23.      * @return  JDatabaseImporterPostgresql  Method supports chaining.
  24.      *
  25.      * @since   12.1
  26.      * @throws  Exception if an error is encountered.
  27.      */
  28.     public function check()
  29.     {
  30.         // Check if the db connector has been set.
  31.         if (!($this->db instanceof JDatabaseDriverPostgresql))
  32.         {
  33.             throw new Exception('JPLATFORM_ERROR_DATABASE_CONNECTOR_WRONG_TYPE');
  34.         }
  35.  
  36.         // Check if the tables have been specified.
  37.         if (empty($this->from))
  38.         {
  39.             throw new Exception('JPLATFORM_ERROR_NO_TABLES_SPECIFIED');
  40.         }
  41.  
  42.         return $this;
  43.     }
  44.  
  45.     /**
  46.      * Get the SQL syntax to add a column.
  47.      *
  48.      * @param   string            $table  The table name.
  49.      * @param   SimpleXMLElement  $field  The XML field definition.
  50.      *
  51.      * @return  string 
  52.      *
  53.      * @since   12.1
  54.      */
  55.     protected function getAddColumnSQL($tableSimpleXMLElement $field)
  56.     {
  57.         return 'ALTER TABLE ' $this->db->quoteName($table' ADD COLUMN ' $this->getColumnSQL($field);
  58.     }
  59.  
  60.     /**
  61.      * Get the SQL syntax to add an index.
  62.      *
  63.      * @param   SimpleXMLElement  $field  The XML index definition.
  64.      *
  65.      * @return  string 
  66.      *
  67.      * @since   12.1
  68.      */
  69.     protected function getAddIndexSQL(SimpleXMLElement $field)
  70.     {
  71.         return (string) $field['Query'];
  72.     }
  73.  
  74.     /**
  75.      * Get alters for table if there is a difference.
  76.      *
  77.      * @param   SimpleXMLElement  $structure  The XML structure of the table.
  78.      *
  79.      * @return  array 
  80.      *
  81.      * @since   12.1
  82.      */
  83.     protected function getAlterTableSQL(SimpleXMLElement $structure)
  84.     {
  85.         $table $this->getRealTableName($structure['name']);
  86.         $oldFields $this->db->getTableColumns($table);
  87.         $oldKeys $this->db->getTableKeys($table);
  88.         $oldSequence $this->db->getTableSequences($table);
  89.         $alters array();
  90.  
  91.         // Get the fields and keys from the XML that we are aiming for.
  92.         $newFields $structure->xpath('field');
  93.         $newKeys $structure->xpath('key');
  94.         $newSequence $structure->xpath('sequence');
  95.  
  96.         /* Sequence section */
  97.         $oldSeq $this->getSeqLookup($oldSequence);
  98.         $newSequenceLook $this->getSeqLookup($newSequence);
  99.  
  100.         foreach ($newSequenceLook as $kSeqName => $vSeq)
  101.         {
  102.             if (isset($oldSeq[$kSeqName]))
  103.             {
  104.                 // The field exists, check it's the same.
  105.                 $column $oldSeq[$kSeqName][0];
  106.  
  107.                 /* For older database version that doesn't support these fields use default values */
  108.                 if (version_compare($this->db->getVersion()'9.1.0'0)
  109.                 {
  110.                     $column->Min_Value '1';
  111.                     $column->Max_Value '9223372036854775807';
  112.                     $column->Increment '1';
  113.                     $column->Cycle_option 'NO';
  114.                     $column->Start_Value '1';
  115.                 }
  116.  
  117.                 // Test whether there is a change.
  118.                 $change ((string) $vSeq[0]['Type'!= $column->Type|| ((string) $vSeq[0]['Start_Value'!= $column->Start_Value)
  119.                     || ((string) $vSeq[0]['Min_Value'!= $column->Min_Value|| ((string) $vSeq[0]['Max_Value'!= $column->Max_Value)
  120.                     || ((string) $vSeq[0]['Increment'!= $column->Increment|| ((string) $vSeq[0]['Cycle_option'!= $column->Cycle_option)
  121.                     || ((string) $vSeq[0]['Table'!= $column->Table|| ((string) $vSeq[0]['Column'!= $column->Column)
  122.                     || ((string) $vSeq[0]['Schema'!= $column->Schema|| ((string) $vSeq[0]['Name'!= $column->Name);
  123.  
  124.                 if ($change)
  125.                 {
  126.                     $alters[$this->getChangeSequenceSQL($kSeqName$vSeq);
  127.                 }
  128.  
  129.                 // Unset this field so that what we have left are fields that need to be removed.
  130.                 unset($oldSeq[$kSeqName]);
  131.             }
  132.             else
  133.             {
  134.                 // The sequence is new
  135.                 $alters[$this->getAddSequenceSQL($newSequenceLook[$kSeqName][0]);
  136.             }
  137.         }
  138.  
  139.         // Any sequences left are orphans
  140.         foreach ($oldSeq as $name => $column)
  141.         {
  142.             // Delete the sequence.
  143.             $alters[$this->getDropSequenceSQL($name);
  144.         }
  145.  
  146.         /* Field section */
  147.         // Loop through each field in the new structure.
  148.         foreach ($newFields as $field)
  149.         {
  150.             $fName = (string) $field['Field'];
  151.  
  152.             if (isset($oldFields[$fName]))
  153.             {
  154.                 // The field exists, check it's the same.
  155.                 $column $oldFields[$fName];
  156.  
  157.                 // Test whether there is a change.
  158.                 $change ((string) $field['Type'!= $column->Type|| ((string) $field['Null'!= $column->Null)
  159.                     || ((string) $field['Default'!= $column->Default);
  160.  
  161.                 if ($change)
  162.                 {
  163.                     $alters[$this->getChangeColumnSQL($table$field);
  164.                 }
  165.  
  166.                 // Unset this field so that what we have left are fields that need to be removed.
  167.                 unset($oldFields[$fName]);
  168.             }
  169.             else
  170.             {
  171.                 // The field is new.
  172.                 $alters[$this->getAddColumnSQL($table$field);
  173.             }
  174.         }
  175.  
  176.         // Any columns left are orphans
  177.         foreach ($oldFields as $name => $column)
  178.         {
  179.             // Delete the column.
  180.             $alters[$this->getDropColumnSQL($table$name);
  181.         }
  182.  
  183.         /* Index section */
  184.         // Get the lookups for the old and new keys
  185.         $oldLookup $this->getIdxLookup($oldKeys);
  186.         $newLookup $this->getIdxLookup($newKeys);
  187.  
  188.         // Loop through each key in the new structure.
  189.         foreach ($newLookup as $name => $keys)
  190.         {
  191.             // Check if there are keys on this field in the existing table.
  192.             if (isset($oldLookup[$name]))
  193.             {
  194.                 $same true;
  195.                 $newCount count($newLookup[$name]);
  196.                 $oldCount count($oldLookup[$name]);
  197.  
  198.                 // There is a key on this field in the old and new tables. Are they the same?
  199.                 if ($newCount == $oldCount)
  200.                 {
  201.                     for ($i 0$i $newCount$i++)
  202.                     {
  203.                         // Check only query field -> different query means different index
  204.                         $same ((string) $newLookup[$name][$i]['Query'== $oldLookup[$name][$i]->Query);
  205.  
  206.                         if (!$same)
  207.                         {
  208.                             // Break out of the loop. No need to check further.
  209.                             break;
  210.                         }
  211.                     }
  212.                 }
  213.                 else
  214.                 {
  215.                     // Count is different, just drop and add.
  216.                     $same false;
  217.                 }
  218.  
  219.                 if (!$same)
  220.                 {
  221.                     $alters[$this->getDropIndexSQL($name);
  222.                     $alters[]  = (string) $newLookup[$name][0]['Query'];
  223.                 }
  224.  
  225.                 // Unset this field so that what we have left are fields that need to be removed.
  226.                 unset($oldLookup[$name]);
  227.             }
  228.             else
  229.             {
  230.                 // This is a new key.
  231.                 $alters[= (string) $newLookup[$name][0]['Query'];
  232.             }
  233.         }
  234.  
  235.         // Any keys left are orphans.
  236.         foreach ($oldLookup as $name => $keys)
  237.         {
  238.             if ($oldLookup[$name][0]->is_primary == 'TRUE')
  239.             {
  240.                 $alters[$this->getDropPrimaryKeySQL($table$oldLookup[$name][0]->Index);
  241.             }
  242.             else
  243.             {
  244.                 $alters[$this->getDropIndexSQL($name);
  245.             }
  246.         }
  247.  
  248.         return $alters;
  249.     }
  250.  
  251.     /**
  252.      * Get the SQL syntax to drop a sequence.
  253.      *
  254.      * @param   string  $name  The name of the sequence to drop.
  255.      *
  256.      * @return  string 
  257.      *
  258.      * @since   12.1
  259.      */
  260.     protected function getDropSequenceSQL($name)
  261.     {
  262.         return 'DROP SEQUENCE ' $this->db->quoteName($name);
  263.     }
  264.  
  265.     /**
  266.      * Get the syntax to add a sequence.
  267.      *
  268.      * @param   SimpleXMLElement  $field  The XML definition for the sequence.
  269.      *
  270.      * @return  string 
  271.      *
  272.      * @since   12.1
  273.      */
  274.     protected function getAddSequenceSQL($field)
  275.     {
  276.         /* For older database version that doesn't support these fields use default values */
  277.         if (version_compare($this->db->getVersion()'9.1.0'0)
  278.         {
  279.             $field['Min_Value''1';
  280.             $field['Max_Value''9223372036854775807';
  281.             $field['Increment''1';
  282.             $field['Cycle_option''NO';
  283.             $field['Start_Value''1';
  284.         }
  285.  
  286.         return 'CREATE SEQUENCE ' . (string) $field['Name'.
  287.             ' INCREMENT BY ' . (string) $field['Increment'' MINVALUE ' $field['Min_Value'.
  288.             ' MAXVALUE ' . (string) $field['Max_Value'' START ' . (string) $field['Start_Value'.
  289.             (((string) $field['Cycle_option'== 'NO'' NO' ''' CYCLE' .
  290.             ' OWNED BY ' $this->db->quoteName((string) $field['Schema''.' . (string) $field['Table''.' . (string) $field['Column']);
  291.     }
  292.  
  293.     /**
  294.      * Get the syntax to alter a sequence.
  295.      *
  296.      * @param   SimpleXMLElement  $field  The XML definition for the sequence.
  297.      *
  298.      * @return  string 
  299.      *
  300.      * @since   12.1
  301.      */
  302.     protected function getChangeSequenceSQL($field)
  303.     {
  304.         /* For older database version that doesn't support these fields use default values */
  305.         if (version_compare($this->db->getVersion()'9.1.0'0)
  306.         {
  307.             $field['Min_Value''1';
  308.             $field['Max_Value''9223372036854775807';
  309.             $field['Increment''1';
  310.             $field['Cycle_option''NO';
  311.             $field['Start_Value''1';
  312.         }
  313.  
  314.         return 'ALTER SEQUENCE ' . (string) $field['Name'.
  315.             ' INCREMENT BY ' . (string) $field['Increment'' MINVALUE ' . (string) $field['Min_Value'.
  316.             ' MAXVALUE ' . (string) $field['Max_Value'' START ' . (string) $field['Start_Value'.
  317.             ' OWNED BY ' $this->db->quoteName((string) $field['Schema''.' . (string) $field['Table''.' . (string) $field['Column']);
  318.     }
  319.  
  320.     /**
  321.      * Get the syntax to alter a column.
  322.      *
  323.      * @param   string            $table  The name of the database table to alter.
  324.      * @param   SimpleXMLElement  $field  The XML definition for the field.
  325.      *
  326.      * @return  string 
  327.      *
  328.      * @since   12.1
  329.      */
  330.     protected function getChangeColumnSQL($tableSimpleXMLElement $field)
  331.     {
  332.         return 'ALTER TABLE ' $this->db->quoteName($table' ALTER COLUMN ' $this->db->quoteName((string) $field['Field']' '
  333.             . $this->getAlterColumnSQL($table$field);
  334.     }
  335.  
  336.     /**
  337.      * Get the SQL syntax for a single column that would be included in a table create statement.
  338.      *
  339.      * @param   string            $table  The name of the database table to alter.
  340.      * @param   SimpleXMLElement  $field  The XML field definition.
  341.      *
  342.      * @return  string 
  343.      *
  344.      * @since   12.1
  345.      */
  346.     protected function getAlterColumnSQL($table$field)
  347.     {
  348.         // TODO Incorporate into parent class and use $this.
  349.         $blobs array('text''smalltext''mediumtext''largetext');
  350.  
  351.         $fName = (string) $field['Field'];
  352.         $fType = (string) $field['Type'];
  353.         $fNull = (string) $field['Null'];
  354.         $fDefault (isset($field['Default']&& $field['Default'!= 'NULL' ?
  355.                         preg_match('/^[0-9]$/'$field['Default']$field['Default'$this->db->quote((string) $field['Default'])
  356.                     : null;
  357.  
  358.         $query ' TYPE ' $fType;
  359.  
  360.         if ($fNull == 'NO')
  361.         {
  362.             if (in_array($fType$blobs|| $fDefault === null)
  363.             {
  364.                 $query .= ",\nALTER COLUMN " $this->db->quoteName($fName' SET NOT NULL' .
  365.                         ",\nALTER COLUMN " $this->db->quoteName($fName' DROP DEFAULT';
  366.             }
  367.             else
  368.             {
  369.                 $query .= ",\nALTER COLUMN " $this->db->quoteName($fName' SET NOT NULL' .
  370.                         ",\nALTER COLUMN " $this->db->quoteName($fName' SET DEFAULT ' $fDefault;
  371.             }
  372.         }
  373.         else
  374.         {
  375.             if ($fDefault !== null)
  376.             {
  377.                 $query .= ",\nALTER COLUMN " $this->db->quoteName($fName' DROP NOT NULL' .
  378.                         ",\nALTER COLUMN " $this->db->quoteName($fName' SET DEFAULT ' $fDefault;
  379.             }
  380.         }
  381.  
  382.         /* sequence was created in other function, here is associated a default value but not yet owner */
  383.         if (strpos($fDefault'nextval'!== false)
  384.         {
  385.             $query .= ";\nALTER SEQUENCE " $this->db->quoteName($table '_' $fName '_seq'' OWNED BY ' $this->db->quoteName($table '.' $fName);
  386.         }
  387.  
  388.         return $query;
  389.     }
  390.  
  391.     /**
  392.      * Get the SQL syntax for a single column that would be included in a table create statement.
  393.      *
  394.      * @param   SimpleXMLElement  $field  The XML field definition.
  395.      *
  396.      * @return  string 
  397.      *
  398.      * @since   12.1
  399.      */
  400.     protected function getColumnSQL(SimpleXMLElement $field)
  401.     {
  402.         // TODO Incorporate into parent class and use $this.
  403.         $blobs array('text''smalltext''mediumtext''largetext');
  404.  
  405.         $fName = (string) $field['Field'];
  406.         $fType = (string) $field['Type'];
  407.         $fNull = (string) $field['Null'];
  408.         $fDefault (isset($field['Default']&& $field['Default'!= 'NULL' ?
  409.                         preg_match('/^[0-9]$/'$field['Default']$field['Default'$this->db->quote((string) $field['Default'])
  410.                     : null;
  411.  
  412.         /* nextval() as default value means that type field is serial */
  413.         if (strpos($fDefault'nextval'!== false)
  414.         {
  415.             $query $this->db->quoteName($fName' SERIAL';
  416.         }
  417.         else
  418.         {
  419.             $query $this->db->quoteName($fName' ' $fType;
  420.  
  421.             if ($fNull == 'NO')
  422.             {
  423.                 if (in_array($fType$blobs|| $fDefault === null)
  424.                 {
  425.                     $query .= ' NOT NULL';
  426.                 }
  427.                 else
  428.                 {
  429.                     $query .= ' NOT NULL DEFAULT ' $fDefault;
  430.                 }
  431.             }
  432.             else
  433.             {
  434.                 if ($fDefault !== null)
  435.                 {
  436.                     $query .= ' DEFAULT ' $fDefault;
  437.                 }
  438.             }
  439.         }
  440.  
  441.         return $query;
  442.     }
  443.  
  444.     /**
  445.      * Get the SQL syntax to drop an index.
  446.      *
  447.      * @param   string  $name  The name of the key to drop.
  448.      *
  449.      * @return  string 
  450.      *
  451.      * @since   12.1
  452.      */
  453.     protected function getDropIndexSQL($name)
  454.     {
  455.         return 'DROP INDEX ' $this->db->quoteName($name);
  456.     }
  457.  
  458.     /**
  459.      * Get the SQL syntax to drop a key.
  460.      *
  461.      * @param   string  $table  The table name.
  462.      * @param   string  $name   The constraint name.
  463.      *
  464.      * @return  string 
  465.      *
  466.      * @since   12.1
  467.      */
  468.     protected function getDropPrimaryKeySQL($table$name)
  469.     {
  470.         return 'ALTER TABLE ONLY ' $this->db->quoteName($table' DROP CONSTRAINT ' $this->db->quoteName($name);
  471.     }
  472.  
  473.     /**
  474.      * Get the details list of keys for a table.
  475.      *
  476.      * @param   array  $keys  An array of objects that comprise the keys for the table.
  477.      *
  478.      * @return  array  The lookup array. array({key name} => array(object, ...))
  479.      *
  480.      * @since   12.1
  481.      * @throws  Exception
  482.      */
  483.     protected function getIdxLookup($keys)
  484.     {
  485.         // First pass, create a lookup of the keys.
  486.         $lookup array();
  487.  
  488.         foreach ($keys as $key)
  489.         {
  490.             if ($key instanceof SimpleXMLElement)
  491.             {
  492.                 $kName = (string) $key['Index'];
  493.             }
  494.             else
  495.             {
  496.                 $kName $key->Index;
  497.             }
  498.  
  499.             if (empty($lookup[$kName]))
  500.             {
  501.                 $lookup[$kNamearray();
  502.             }
  503.  
  504.             $lookup[$kName][$key;
  505.         }
  506.  
  507.         return $lookup;
  508.     }
  509.  
  510.     /**
  511.      * Get the details list of sequences for a table.
  512.      *
  513.      * @param   array  $sequences  An array of objects that comprise the sequences for the table.
  514.      *
  515.      * @return  array  The lookup array. array({key name} => array(object, ...))
  516.      *
  517.      * @since   12.1
  518.      * @throws  Exception
  519.      */
  520.     protected function getSeqLookup($sequences)
  521.     {
  522.         // First pass, create a lookup of the keys.
  523.         $lookup array();
  524.  
  525.         foreach ($sequences as $seq)
  526.         {
  527.             if ($seq instanceof SimpleXMLElement)
  528.             {
  529.                 $sName = (string) $seq['Name'];
  530.             }
  531.             else
  532.             {
  533.                 $sName $seq->Name;
  534.             }
  535.  
  536.             if (empty($lookup[$sName]))
  537.             {
  538.                 $lookup[$sNamearray();
  539.             }
  540.  
  541.             $lookup[$sName][$seq;
  542.         }
  543.  
  544.         return $lookup;
  545.     }
  546. }

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