diff --git a/laravel/database/connection.php b/laravel/database/connection.php index 938ae97f92b..17a209ae7a5 100644 --- a/laravel/database/connection.php +++ b/laravel/database/connection.php @@ -92,6 +92,9 @@ protected function grammar() case 'pgsql': return $this->grammar = new Query\Grammars\Postgres($this); + case 'oracle': + return $this->grammar = new Query\Grammars\Oracle($this); + default: return $this->grammar = new Query\Grammars\Grammar($this); } diff --git a/laravel/database/connectors/oracle.php b/laravel/database/connectors/oracle.php new file mode 100644 index 00000000000..0b856bf0e2c --- /dev/null +++ b/laravel/database/connectors/oracle.php @@ -0,0 +1,67 @@ + PDO::CASE_UPPER, + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, + ); + + /** + * Establish a PDO database connection. + * + * @param array $config + * @return PDO + */ + public function connect($config) + { + extract($config); + + // The developer has the freedom of specifying a port for the Oracle database + // or no port will be used to make the connection by PDO. + if (isset($config['port'])) + { + $port = ":{$config['port']}"; + } + else + { + $port = ""; + } + + // If no host is specified, the database name must be defined in the + // tnsnames.ora file in %ORACLE_HOME%\network\admin + if (isset($config['host'])) + { + $dsn = "oci:dbname={$config['host']}{$port}/{$config['database']}"; + } + else + { + $dsn = "oci:dbname={$config['database']}"; + } + + // If a character set has been specified, we'll execute a query against + // the database to set the correct character set. By default, this is + // set to UTF-8 which should be fine for most scenarios. + if (isset($config['charset'])) + { + $dsn .= ";charset={$config['charset']}"; + } else { + $dsn .= ";charset=AL32UTF8"; + } + + $connection = new PDO($dsn, $username, $password, $this->options($config)); + + return $connection; + } + +} diff --git a/laravel/database/query/grammars/oracle.php b/laravel/database/query/grammars/oracle.php new file mode 100644 index 00000000000..f30282a261b --- /dev/null +++ b/laravel/database/query/grammars/oracle.php @@ -0,0 +1,139 @@ +insert($query, $values)." RETURNING $column"; + } + + /** + * Compile a SQL SELECT statement from a Query instance. + * + * @param Query $query + * @return string + */ + public function select(Query $query) + { + $sql = parent::components($query); + + // SQL Server does not currently implement an "OFFSET" type keyword, so we + // actually have to generate the ANSI standard SQL for doing offset like + // functionality. OFFSET is in SQL Server 2012, however. + if ($query->offset > 0) + { + return $this->ansi_offset($query, $sql); + } + + // Once all of the clauses have been compiled, we can join them all as + // one statement. Any segments that are null or an empty string will + // be removed from the array before imploding. + return $this->concatenate($sql); + } + + /** + * Compile the SELECT clause for a query. + * + * @param Query $query + * @return string + */ + protected function selects(Query $query) + { + if ( ! is_null($query->aggregate)) return; + + $select = ($query->distinct) ? 'SELECT DISTINCT ' : 'SELECT '; + + return $select.$this->columnize($query->selects); + } + + /** + * Generate the ANSI standard SQL for an offset clause. + * + * @param Query $query + * @param array $components + * @return array + */ + protected function ansi_offset(Query $query, $components) + { + // An ORDER BY clause is required to make this offset query work, so if + // one doesn't exist, we'll just create a dummy clause to trick the + // database and pacify it so it doesn't complain about the query. + if ( ! isset($components['orderings'])) + { + $components['orderings'] = 'ORDER BY 1'; + } + + // We need to add the row number to the query so we can compare it to + // the offset and limit values given for the statement. So we'll add + // an expression to the select for the row number. + $orderings = $components['orderings']; + + $components['selects'] .= ", ROW_NUMBER() OVER ({$orderings}) AS RowNum"; + + unset($components['orderings']); + + $start = $query->offset + 1; + + // Next we need to calculate the constraint that should be placed on + // the row number to get the correct offset and limit on the query. + // If there is not a limit, we'll just handle the offset. + if ($query->limit > 0) + { + $finish = $query->offset + $query->limit; + + $constraint = "BETWEEN {$start} AND {$finish}"; + } + else + { + $constraint = ">= {$start}"; + } + + // We're finally ready to build the final SQL query so we'll create + // a common table expression with the query and select all of the + // results with row numbers between the limit and offset. + $sql = $this->concatenate($components); + + return "SELECT * FROM ($sql) TempTable WHERE RowNum {$constraint}"; + } + + /** + * Compile the LIMIT clause for a query. + * + * @param Query $query + * @return string + */ + protected function limit(Query $query) + { + return ''; + } + + /** + * Compile the OFFSET clause for a query. + * + * @param Query $query + * @return string + */ + protected function offset(Query $query) + { + return ''; + } + +} \ No newline at end of file diff --git a/laravel/database/schema.php b/laravel/database/schema.php index c37fcd6363b..9f0344e9c90 100644 --- a/laravel/database/schema.php +++ b/laravel/database/schema.php @@ -186,6 +186,9 @@ public static function grammar(Connection $connection) case 'sqlite': return new Schema\Grammars\SQLite($connection); + + case 'oracle': + return new Schema\Grammars\Oracle($connection); } throw new \Exception("Schema operations not supported for [$driver]."); diff --git a/laravel/database/schema/grammars/oracle.php b/laravel/database/schema/grammars/oracle.php new file mode 100644 index 00000000000..16a7f5a439a --- /dev/null +++ b/laravel/database/schema/grammars/oracle.php @@ -0,0 +1,8 @@ +