yajra / laravel-oci8

Oracle DB driver for Laravel via OCI8
https://yajrabox.com/docs/laravel-oci8
MIT License
829 stars 237 forks source link

Problem with "wrapTable" function using it in "compileUpsert" #875

Closed sebaris closed 1 week ago

sebaris commented 1 month ago

Summary of problem or feature request

In the class Yajra\Oci8\Query\Grammars\OracleGrammar.php when the compileUpsert method is called to form the respective SQL referring to Eloquent's upsert method. Every table name must go through the wrapTable function which always adds the schema prefix.

Line 657 calls wrapTable but with a temporary name "laravel_source", when the schema prefix is ​​added this will fail because the table does not exist.

Code snippet of problem

$source = $this->wrapTable('laravel_source'); //line 657

In the wrapTable function, line 245

public function wrapTable($table) {
     if ($this->isExpression($table)) {
         return $this->getValue($table);
     }

     if (strpos(strtolower($table), ' as ') !== false) {
         $table = str_replace(' as ', ' ', strtolower($table));
     }

     $tableName = $this->wrap($this->tablePrefix.$table, true);
     $segments = explode(' ', $table);
     if (count($segments) > 1) {
         $tableName = $this->wrap($this->tablePrefix.$segments[0]).' '.$segments[1];
     }

     return $this->getSchemaPrefix() . $tableName; //The problem in line 245
}

This could be solved by adding a check that the table exists to add the prefix, if it does not exist only the table name is returned

//Line 245
$schemaPrefix = ($this->hasTable($table)) ? $this->getSchemaPrefix() : '';
return $schemaPrefix.$tableName;

//Create two functionts
/**
 * Determine if the given table exists.
 *
 * @param  string  $table
 * @return bool
 */
private function hasTable($table)
{
    $sql = $this->compileTableExists();

    $database = $this->connection->getConfig('username');
    if ($this->connection->getConfig('prefix_schema')) {
        $database = $this->connection->getConfig('prefix_schema');
    }
    $table = $this->connection->getTablePrefix() . $table;

    return count($this->connection->select($sql, [$database, $table])) > 0;
}

/**
 * Compile the query to determine if a table exists.
 *
 * @return string
 */
private function compileTableExists()
{
    return 'select * from all_tables where upper(owner) = upper(?) and upper(table_name) = upper(?)';
}

I hope this can help. thanks.

System details

yajra commented 1 month ago

Thanks for reporting, will review this further given the time.

Concerning hasTable, we can re-use the schema grammar to check the table existence if needed.

Please feel free to submit a PR if possible. Thanks!

github-actions[bot] commented 1 week ago

This issue is stale because it has been open for 30 days with no activity.