mirror of
https://gitlab.com/hashborgir/d2tools.git
synced 2025-10-14 00:44:23 -05:00
Begin Refactor
This commit is contained in:
1667
vendor/gabordemooij/redbean/RedBeanPHP/QueryWriter/AQueryWriter.php
vendored
Normal file
1667
vendor/gabordemooij/redbean/RedBeanPHP/QueryWriter/AQueryWriter.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
364
vendor/gabordemooij/redbean/RedBeanPHP/QueryWriter/CUBRID.php
vendored
Normal file
364
vendor/gabordemooij/redbean/RedBeanPHP/QueryWriter/CUBRID.php
vendored
Normal file
@@ -0,0 +1,364 @@
|
||||
<?php
|
||||
|
||||
namespace RedBeanPHP\QueryWriter;
|
||||
use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter;
|
||||
use RedBeanPHP\QueryWriter as QueryWriter;
|
||||
use RedBeanPHP\Adapter\DBAdapter as DBAdapter;
|
||||
use RedBeanPHP\Adapter as Adapter;
|
||||
use RedBeanPHP\RedException\SQL as SQLException;
|
||||
|
||||
/**
|
||||
* RedBeanPHP CUBRID Writer.
|
||||
* This is a QueryWriter class for RedBeanPHP.
|
||||
* This QueryWriter provides support for the CUBRID database platform.
|
||||
*
|
||||
* @file RedBeanPHP/QueryWriter/CUBRID.php
|
||||
* @author Gabor de Mooij and the RedBeanPHP Community
|
||||
* @license BSD/GPLv2
|
||||
*
|
||||
* @copyright
|
||||
* (c) copyright G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community.
|
||||
* This source file is subject to the BSD/GPLv2 License that is bundled
|
||||
* with this source code in the file license.txt.
|
||||
*/
|
||||
class CUBRID extends AQueryWriter implements QueryWriter
|
||||
{
|
||||
/**
|
||||
* Data types
|
||||
*/
|
||||
const C_DATATYPE_INTEGER = 0;
|
||||
const C_DATATYPE_DOUBLE = 1;
|
||||
const C_DATATYPE_STRING = 2;
|
||||
const C_DATATYPE_SPECIAL_DATE = 80;
|
||||
const C_DATATYPE_SPECIAL_DATETIME = 81;
|
||||
const C_DATATYPE_SPECIFIED = 99;
|
||||
|
||||
/**
|
||||
* @var DBAdapter
|
||||
*/
|
||||
protected $adapter;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $quoteCharacter = '`';
|
||||
|
||||
/**
|
||||
* This method adds a foreign key from type and field to
|
||||
* target type and target field.
|
||||
* The foreign key is created without an action. On delete/update
|
||||
* no action will be triggered. The FK is only used to allow database
|
||||
* tools to generate pretty diagrams and to make it easy to add actions
|
||||
* later on.
|
||||
* This methods accepts a type and infers the corresponding table name.
|
||||
*
|
||||
* @param string $type type that will have a foreign key field
|
||||
* @param string $targetType points to this type
|
||||
* @param string $property field that contains the foreign key value
|
||||
* @param string $targetProperty field where the fk points to
|
||||
* @param boolean $isDep is dependent
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function buildFK( $type, $targetType, $property, $targetProperty, $isDep = FALSE )
|
||||
{
|
||||
$table = $this->esc( $type );
|
||||
$tableNoQ = $this->esc( $type, TRUE );
|
||||
$targetTable = $this->esc( $targetType );
|
||||
$targetTableNoQ = $this->esc( $targetType, TRUE );
|
||||
$column = $this->esc( $property );
|
||||
$columnNoQ = $this->esc( $property, TRUE );
|
||||
$targetColumn = $this->esc( $targetProperty );
|
||||
if ( !is_null( $this->getForeignKeyForTypeProperty( $tableNoQ, $columnNoQ ) ) ) return FALSE;
|
||||
$needsToDropFK = FALSE;
|
||||
$casc = ( $isDep ? 'CASCADE' : 'SET NULL' );
|
||||
$sql = "ALTER TABLE $table ADD CONSTRAINT FOREIGN KEY($column) REFERENCES $targetTable($targetColumn) ON DELETE $casc ";
|
||||
try {
|
||||
$this->adapter->exec( $sql );
|
||||
} catch( SQLException $e ) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AQueryWriter::getKeyMapForType
|
||||
*/
|
||||
protected function getKeyMapForType( $type )
|
||||
{
|
||||
$sqlCode = $this->adapter->get("SHOW CREATE TABLE `{$type}`");
|
||||
if (!isset($sqlCode[0])) return array();
|
||||
$matches = array();
|
||||
preg_match_all( '/CONSTRAINT\s+\[([\w_]+)\]\s+FOREIGN\s+KEY\s+\(\[([\w_]+)\]\)\s+REFERENCES\s+\[([\w_]+)\](\s+ON\s+DELETE\s+(CASCADE|SET\sNULL|RESTRICT|NO\sACTION)\s+ON\s+UPDATE\s+(SET\sNULL|RESTRICT|NO\sACTION))?/', $sqlCode[0]['CREATE TABLE'], $matches );
|
||||
$list = array();
|
||||
if (!isset($matches[0])) return $list;
|
||||
$max = count($matches[0]);
|
||||
for($i = 0; $i < $max; $i++) {
|
||||
$label = $this->makeFKLabel( $matches[2][$i], $matches[3][$i], 'id' );
|
||||
$list[ $label ] = array(
|
||||
'name' => $matches[1][$i],
|
||||
'from' => $matches[2][$i],
|
||||
'table' => $matches[3][$i],
|
||||
'to' => 'id',
|
||||
'on_update' => $matches[6][$i],
|
||||
'on_delete' => $matches[5][$i]
|
||||
);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* Most of the time, you do not need to use this constructor,
|
||||
* since the facade takes care of constructing and wiring the
|
||||
* RedBeanPHP core objects. However if you would like to
|
||||
* assemble an OODB instance yourself, this is how it works:
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* <code>
|
||||
* $database = new RPDO( $dsn, $user, $pass );
|
||||
* $adapter = new DBAdapter( $database );
|
||||
* $writer = new PostgresWriter( $adapter );
|
||||
* $oodb = new OODB( $writer, FALSE );
|
||||
* $bean = $oodb->dispense( 'bean' );
|
||||
* $bean->name = 'coffeeBean';
|
||||
* $id = $oodb->store( $bean );
|
||||
* $bean = $oodb->load( 'bean', $id );
|
||||
* </code>
|
||||
*
|
||||
* The example above creates the 3 RedBeanPHP core objects:
|
||||
* the Adapter, the Query Writer and the OODB instance and
|
||||
* wires them together. The example also demonstrates some of
|
||||
* the methods that can be used with OODB, as you see, they
|
||||
* closely resemble their facade counterparts.
|
||||
*
|
||||
* The wiring process: create an RPDO instance using your database
|
||||
* connection parameters. Create a database adapter from the RPDO
|
||||
* object and pass that to the constructor of the writer. Next,
|
||||
* create an OODB instance from the writer. Now you have an OODB
|
||||
* object.
|
||||
*
|
||||
* @param Adapter $adapter Database Adapter
|
||||
*/
|
||||
public function __construct( Adapter $adapter )
|
||||
{
|
||||
$this->typeno_sqltype = array(
|
||||
CUBRID::C_DATATYPE_INTEGER => ' INTEGER ',
|
||||
CUBRID::C_DATATYPE_DOUBLE => ' DOUBLE ',
|
||||
CUBRID::C_DATATYPE_STRING => ' STRING ',
|
||||
CUBRID::C_DATATYPE_SPECIAL_DATE => ' DATE ',
|
||||
CUBRID::C_DATATYPE_SPECIAL_DATETIME => ' DATETIME ',
|
||||
);
|
||||
|
||||
$this->sqltype_typeno = array();
|
||||
|
||||
foreach ( $this->typeno_sqltype as $k => $v ) {
|
||||
$this->sqltype_typeno[trim( ( $v ) )] = $k;
|
||||
}
|
||||
|
||||
$this->sqltype_typeno['STRING(1073741823)'] = self::C_DATATYPE_STRING;
|
||||
|
||||
$this->adapter = $adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the datatype to be used for primary key IDS and
|
||||
* foreign keys. Returns one if the data type constants.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getTypeForID()
|
||||
{
|
||||
return self::C_DATATYPE_INTEGER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::getTables
|
||||
*/
|
||||
public function getTables()
|
||||
{
|
||||
$rows = $this->adapter->getCol( "SELECT class_name FROM db_class WHERE is_system_class = 'NO';" );
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::createTable
|
||||
*/
|
||||
public function createTable( $table )
|
||||
{
|
||||
$sql = 'CREATE TABLE '
|
||||
. $this->esc( $table )
|
||||
. ' ("id" integer AUTO_INCREMENT, CONSTRAINT "pk_'
|
||||
. $this->esc( $table, TRUE )
|
||||
. '_id" PRIMARY KEY("id"))';
|
||||
|
||||
$this->adapter->exec( $sql );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::getColumns
|
||||
*/
|
||||
public function getColumns( $table )
|
||||
{
|
||||
$table = $this->esc( $table );
|
||||
|
||||
$columnsRaw = $this->adapter->get( "SHOW COLUMNS FROM $table" );
|
||||
|
||||
$columns = array();
|
||||
foreach ( $columnsRaw as $r ) {
|
||||
$columns[$r['Field']] = $r['Type'];
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::scanType
|
||||
*/
|
||||
public function scanType( $value, $flagSpecial = FALSE )
|
||||
{
|
||||
$this->svalue = $value;
|
||||
|
||||
if ( is_null( $value ) ) {
|
||||
return self::C_DATATYPE_INTEGER;
|
||||
}
|
||||
|
||||
if ( $flagSpecial ) {
|
||||
if ( preg_match( '/^\d{4}\-\d\d-\d\d$/', $value ) ) {
|
||||
return self::C_DATATYPE_SPECIAL_DATE;
|
||||
}
|
||||
if ( preg_match( '/^\d{4}\-\d\d-\d\d\s\d\d:\d\d:\d\d$/', $value ) ) {
|
||||
return self::C_DATATYPE_SPECIAL_DATETIME;
|
||||
}
|
||||
}
|
||||
|
||||
$value = strval( $value );
|
||||
|
||||
if ( !$this->startsWithZeros( $value ) ) {
|
||||
if ( is_numeric( $value ) && ( floor( $value ) == $value ) && $value >= -2147483647 && $value <= 2147483647 ) {
|
||||
return self::C_DATATYPE_INTEGER;
|
||||
}
|
||||
if ( is_numeric( $value ) ) {
|
||||
return self::C_DATATYPE_DOUBLE;
|
||||
}
|
||||
}
|
||||
|
||||
return self::C_DATATYPE_STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::code
|
||||
*/
|
||||
public function code( $typedescription, $includeSpecials = FALSE )
|
||||
{
|
||||
$r = ( ( isset( $this->sqltype_typeno[$typedescription] ) ) ? $this->sqltype_typeno[$typedescription] : self::C_DATATYPE_SPECIFIED );
|
||||
|
||||
if ( $includeSpecials ) {
|
||||
return $r;
|
||||
}
|
||||
|
||||
if ( $r >= QueryWriter::C_DATATYPE_RANGE_SPECIAL ) {
|
||||
return self::C_DATATYPE_SPECIFIED;
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addColumn
|
||||
*/
|
||||
public function addColumn( $type, $column, $field )
|
||||
{
|
||||
$table = $type;
|
||||
$type = $field;
|
||||
|
||||
$table = $this->esc( $table );
|
||||
$column = $this->esc( $column );
|
||||
|
||||
$type = array_key_exists( $type, $this->typeno_sqltype ) ? $this->typeno_sqltype[$type] : '';
|
||||
|
||||
$this->adapter->exec( "ALTER TABLE $table ADD COLUMN $column $type " );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addUniqueIndex
|
||||
*/
|
||||
public function addUniqueConstraint( $type, $properties )
|
||||
{
|
||||
$tableNoQ = $this->esc( $type, TRUE );
|
||||
$columns = array();
|
||||
foreach( $properties as $key => $column ) $columns[$key] = $this->esc( $column );
|
||||
$table = $this->esc( $type );
|
||||
sort( $columns ); // else we get multiple indexes due to order-effects
|
||||
$name = 'UQ_' . sha1( implode( ',', $columns ) );
|
||||
$sql = "ALTER TABLE $table ADD CONSTRAINT UNIQUE $name (" . implode( ',', $columns ) . ")";
|
||||
try {
|
||||
$this->adapter->exec( $sql );
|
||||
} catch( SQLException $e ) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::sqlStateIn
|
||||
*/
|
||||
public function sqlStateIn( $state, $list, $extraDriverDetails = array() )
|
||||
{
|
||||
return ( $state == 'HY000' ) ? ( count( array_diff( array(
|
||||
QueryWriter::C_SQLSTATE_INTEGRITY_CONSTRAINT_VIOLATION,
|
||||
QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
|
||||
QueryWriter::C_SQLSTATE_NO_SUCH_TABLE
|
||||
), $list ) ) !== 3 ) : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addIndex
|
||||
*/
|
||||
public function addIndex( $type, $name, $column )
|
||||
{
|
||||
try {
|
||||
$table = $this->esc( $type );
|
||||
$name = preg_replace( '/\W/', '', $name );
|
||||
$column = $this->esc( $column );
|
||||
$this->adapter->exec( "CREATE INDEX $name ON $table ($column) " );
|
||||
return TRUE;
|
||||
} catch ( SQLException $e ) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addFK
|
||||
*/
|
||||
public function addFK( $type, $targetType, $property, $targetProperty, $isDependent = FALSE )
|
||||
{
|
||||
return $this->buildFK( $type, $targetType, $property, $targetProperty, $isDependent );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::wipeAll
|
||||
*/
|
||||
public function wipeAll()
|
||||
{
|
||||
if (AQueryWriter::$noNuke) throw new \Exception('The nuke() command has been disabled using noNuke() or R::feature(novice/...).');
|
||||
foreach ( $this->getTables() as $t ) {
|
||||
foreach ( $this->getKeyMapForType( $t ) as $k ) {
|
||||
$this->adapter->exec( "ALTER TABLE \"$t\" DROP FOREIGN KEY \"{$k['name']}\"" );
|
||||
}
|
||||
}
|
||||
foreach ( $this->getTables() as $t ) {
|
||||
$this->adapter->exec( "DROP TABLE \"$t\"" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::esc
|
||||
*/
|
||||
public function esc( $dbStructure, $noQuotes = FALSE )
|
||||
{
|
||||
return parent::esc( strtolower( $dbStructure ), $noQuotes );
|
||||
}
|
||||
}
|
352
vendor/gabordemooij/redbean/RedBeanPHP/QueryWriter/Firebird.php
vendored
Normal file
352
vendor/gabordemooij/redbean/RedBeanPHP/QueryWriter/Firebird.php
vendored
Normal file
@@ -0,0 +1,352 @@
|
||||
<?php
|
||||
|
||||
namespace RedBeanPHP\QueryWriter;
|
||||
|
||||
/* Experimental */
|
||||
|
||||
/**
|
||||
* This driver has been created in 2015 but it has never been distributed
|
||||
* because it was never finished. However, in the true spirit of open source
|
||||
* it is now available in the source of RedBeanPHP.
|
||||
*
|
||||
* Consider this driver experimental or help me finish it to
|
||||
* support the Firebird/Interbase database series.
|
||||
*
|
||||
*/
|
||||
|
||||
use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter;
|
||||
use RedBeanPHP\QueryWriter as QueryWriter;
|
||||
use RedBeanPHP\Adapter\DBAdapter as DBAdapter;
|
||||
use RedBeanPHP\Adapter as Adapter;
|
||||
use RedBeanPHP\RedException\SQL as SQLException;
|
||||
|
||||
/**
|
||||
* RedBeanPHP Firebird/Interbase QueryWriter.
|
||||
* This is a QueryWriter class for RedBeanPHP.
|
||||
* This QueryWriter provides support for the Firebird/Interbase database platform.
|
||||
*
|
||||
* *** Warning - Experimental Software | Not ready for Production ****
|
||||
*
|
||||
* @file RedBeanPHP/QueryWriter/Firebird.php
|
||||
* @author Gabor de Mooij and the RedBeanPHP Community
|
||||
* @license BSD/GPLv2
|
||||
*
|
||||
* @copyright
|
||||
* (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community.
|
||||
* This source file is subject to the BSD/GPLv2 License that is bundled
|
||||
* with this source code in the file license.txt.
|
||||
*/
|
||||
class Firebird extends AQueryWriter implements QueryWriter
|
||||
{
|
||||
/**
|
||||
* Data types
|
||||
*/
|
||||
const C_DATATYPE_INTEGER = 2;
|
||||
const C_DATATYPE_FLOAT = 3;
|
||||
const C_DATATYPE_TEXT = 5;
|
||||
|
||||
/**
|
||||
* @var DBAdapter
|
||||
*/
|
||||
protected $adapter;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $quoteCharacter = '"';
|
||||
|
||||
/**
|
||||
* Returns the insert suffix SQL Snippet
|
||||
*
|
||||
* @param string $table table
|
||||
*
|
||||
* @return string $sql SQL Snippet
|
||||
*/
|
||||
protected function getInsertSuffix( $table )
|
||||
{
|
||||
return 'RETURNING id ';
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AQueryWriter::getKeyMapForType
|
||||
*/
|
||||
protected function getKeyMapForType( $type )
|
||||
{
|
||||
$table = $this->esc( $type, TRUE );
|
||||
$keys = $this->adapter->get('
|
||||
SELECT
|
||||
information_schema.key_column_usage.constraint_name AS `name`,
|
||||
information_schema.key_column_usage.referenced_table_name AS `table`,
|
||||
information_schema.key_column_usage.column_name AS `from`,
|
||||
information_schema.key_column_usage.referenced_column_name AS `to`,
|
||||
information_schema.referential_constraints.update_rule AS `on_update`,
|
||||
information_schema.referential_constraints.delete_rule AS `on_delete`
|
||||
FROM information_schema.key_column_usage
|
||||
INNER JOIN information_schema.referential_constraints
|
||||
ON (
|
||||
information_schema.referential_constraints.constraint_name = information_schema.key_column_usage.constraint_name
|
||||
AND information_schema.referential_constraints.constraint_schema = information_schema.key_column_usage.constraint_schema
|
||||
AND information_schema.referential_constraints.constraint_catalog = information_schema.key_column_usage.constraint_catalog
|
||||
)
|
||||
WHERE
|
||||
information_schema.key_column_usage.table_schema IN ( SELECT DATABASE() )
|
||||
AND information_schema.key_column_usage.table_name = ?
|
||||
AND information_schema.key_column_usage.constraint_name != \'PRIMARY\'
|
||||
AND information_schema.key_column_usage.referenced_table_name IS NOT NULL
|
||||
', array($table));
|
||||
$keyInfoList = array();
|
||||
foreach ( $keys as $k ) {
|
||||
$label = $this->makeFKLabel( $k['from'], $k['table'], $k['to'] );
|
||||
$keyInfoList[$label] = array(
|
||||
'name' => $k['name'],
|
||||
'from' => $k['from'],
|
||||
'table' => $k['table'],
|
||||
'to' => $k['to'],
|
||||
'on_update' => $k['on_update'],
|
||||
'on_delete' => $k['on_delete']
|
||||
);
|
||||
}
|
||||
return $keyInfoList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Adapter $adapter Database Adapter
|
||||
*/
|
||||
public function __construct( Adapter $adapter )
|
||||
{
|
||||
$this->typeno_sqltype = array(
|
||||
Firebird::C_DATATYPE_INTEGER => 'INTEGER',
|
||||
Firebird::C_DATATYPE_FLOAT => 'FLOAT',
|
||||
Firebird::C_DATATYPE_TEXT => 'VARCHAR(8190)',
|
||||
);
|
||||
|
||||
$this->sqltype_typeno = array();
|
||||
|
||||
foreach ( $this->typeno_sqltype as $k => $v ) {
|
||||
$this->sqltype_typeno[trim( strtoupper( $v ) )] = $k;
|
||||
}
|
||||
|
||||
$this->adapter = $adapter;
|
||||
$this->encoding = $this->adapter->getDatabase()->getMysqlEncoding();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the datatype to be used for primary key IDS and
|
||||
* foreign keys. Returns one if the data type constants.
|
||||
*
|
||||
* @return integer $const data type to be used for IDS.
|
||||
*/
|
||||
public function getTypeForID()
|
||||
{
|
||||
return self::C_DATATYPE_INTEGER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::getTables
|
||||
*/
|
||||
public function getTables()
|
||||
{
|
||||
return $this->adapter->getCol( 'SELECT RDB$RELATION_NAME FROM RDB$RELATIONS
|
||||
WHERE RDB$VIEW_BLR IS NULL AND
|
||||
(RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG = 0)');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::createTable
|
||||
*/
|
||||
public function createTable( $table )
|
||||
{
|
||||
$tableNoQ = $this->esc( $table );
|
||||
$tableSQL = "CREATE TABLE \"{$table}\" ( id INT )";
|
||||
$dropGeneratorSQL = "DROP GENERATOR gen{$table}";
|
||||
$generatorSQL = "CREATE GENERATOR gen{$table}";
|
||||
$generatorSQL2 = "SET GENERATOR gen{$table} TO 0";
|
||||
$triggerSQL = "
|
||||
CREATE TRIGGER ai{$table} FOR \"{$table}\"
|
||||
ACTIVE BEFORE INSERT POSITION 0
|
||||
AS
|
||||
BEGIN
|
||||
if (NEW.id is NULL) then NEW.id = GEN_ID(gen{$table}, 1);
|
||||
END
|
||||
";
|
||||
|
||||
try { $this->adapter->exec( $dropGeneratorSQL ); }catch( SQLException $e ) {};
|
||||
$this->adapter->exec( $tableSQL );
|
||||
$this->adapter->exec( $generatorSQL );
|
||||
$this->adapter->exec( $generatorSQL2 );
|
||||
$this->adapter->exec( $triggerSQL );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::widenColumn
|
||||
*/
|
||||
public function widenColumn( $type, $property, $dataType )
|
||||
{
|
||||
if ( !isset($this->typeno_sqltype[$dataType]) ) return FALSE;
|
||||
|
||||
$table = $this->esc( $type );
|
||||
$column = $this->esc( $property );
|
||||
|
||||
$newType = $this->typeno_sqltype[$dataType];
|
||||
|
||||
$this->adapter->exec( "ALTER TABLE $table ALTER COLUMN $column TYPE $newType " );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::getColumns
|
||||
*/
|
||||
public function getColumns( $table )
|
||||
{
|
||||
$columnsRaw = $this->adapter->getAssoc( '
|
||||
SELECT
|
||||
RDB$RELATION_FIELDS.RDB$FIELD_NAME,
|
||||
CASE RDB$FIELDS.RDB$FIELD_TYPE
|
||||
WHEN 10 THEN \'FLOAT\'
|
||||
WHEN 8 THEN \'INTEGER\'
|
||||
WHEN 37 THEN \'VARCHAR\'
|
||||
ELSE RDB$FIELDS.RDB$FIELD_TYPE
|
||||
END AS FTYPE
|
||||
FROM RDB$RELATION_FIELDS
|
||||
LEFT JOIN RDB$FIELDS ON RDB$RELATION_FIELDS.RDB$FIELD_SOURCE = RDB$FIELDS.RDB$FIELD_NAME
|
||||
WHERE RDB$RELATION_FIELDS.RDB$RELATION_NAME = \''.($this->esc($table, true)).'\'
|
||||
ORDER BY RDB$RELATION_FIELDS.RDB$FIELD_POSITION
|
||||
');
|
||||
$columns = array();
|
||||
foreach( $columnsRaw as $rawKey => $columnRaw ) {
|
||||
$columns[ trim( $rawKey ) ] = trim( $columnRaw );
|
||||
}
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::scanType
|
||||
*/
|
||||
public function scanType( $value, $flagSpecial = FALSE )
|
||||
{
|
||||
if ( AQueryWriter::canBeTreatedAsInt( $value ) ) {
|
||||
return FireBird::C_DATATYPE_INTEGER;
|
||||
}
|
||||
if ( !$this->startsWithZeros( $value ) && is_numeric( $value ) ) {
|
||||
return FireBird::C_DATATYPE_DOUBLE;
|
||||
}
|
||||
return FireBird::C_DATATYPE_TEXT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::code
|
||||
*/
|
||||
public function code( $typedescription, $includeSpecials = FALSE )
|
||||
{
|
||||
if ( isset( $this->sqltype_typeno[$typedescription] ) ) {
|
||||
return $this->sqltype_typeno[$typedescription];
|
||||
} else {
|
||||
return self::C_DATATYPE_SPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addUniqueIndex
|
||||
*/
|
||||
public function addUniqueConstraint( $type, $properties )
|
||||
{
|
||||
$tableNoQ = $this->esc( $type, TRUE );
|
||||
$columns = array();
|
||||
foreach( $properties as $key => $column ) $columns[$key] = $this->esc( $column );
|
||||
$table = $this->esc( $type );
|
||||
sort( $columns ); // Else we get multiple indexes due to order-effects
|
||||
$name = 'UQ_'.substr( sha1( implode( ',', $columns ) ), 0, 28);
|
||||
try {
|
||||
$sql = "ALTER TABLE $table
|
||||
ADD CONSTRAINT $name UNIQUE (" . implode( ',', $columns ) . ")";
|
||||
$this->adapter->exec( $sql );
|
||||
} catch ( SQLException $e ) {
|
||||
//do nothing, dont use alter table ignore, this will delete duplicate records in 3-ways!
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addIndex
|
||||
*/
|
||||
public function addIndex( $type, $name, $property )
|
||||
{
|
||||
try {
|
||||
$table = $this->esc( $type );
|
||||
$name = preg_replace( '/\W/', '', $name );
|
||||
$column = $this->esc( $property );
|
||||
$this->adapter->exec( "CREATE INDEX $name ON $table ($column) " );
|
||||
return TRUE;
|
||||
} catch ( SQLException $e ) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addFK
|
||||
*/
|
||||
public function addFK( $type, $targetType, $property, $targetProperty, $isDependent = FALSE )
|
||||
{
|
||||
$table = $this->esc( $type );
|
||||
$targetTable = $this->esc( $targetType );
|
||||
$targetTableNoQ = $this->esc( $targetType, TRUE );
|
||||
$field = $this->esc( $property );
|
||||
$fieldNoQ = $this->esc( $property, TRUE );
|
||||
$targetField = $this->esc( $targetProperty );
|
||||
$targetFieldNoQ = $this->esc( $targetProperty, TRUE );
|
||||
$tableNoQ = $this->esc( $type, TRUE );
|
||||
$fieldNoQ = $this->esc( $property, TRUE );
|
||||
if ( !is_null( $this->getForeignKeyForTypeProperty( $tableNoQ, $fieldNoQ ) ) ) return FALSE;
|
||||
|
||||
//Widen the column if it's incapable of representing a foreign key (at least INT).
|
||||
$columns = $this->getColumns( $tableNoQ );
|
||||
$idType = $this->getTypeForID();
|
||||
if ( $this->code( $columns[$fieldNoQ] ) !== $idType ) {
|
||||
$this->widenColumn( $type, $property, $idType );
|
||||
}
|
||||
|
||||
$fkName = 'fk_'.($tableNoQ.'_'.$fieldNoQ);
|
||||
$cName = 'c_'.$fkName;
|
||||
try {
|
||||
$this->adapter->exec( "
|
||||
ALTER TABLE {$table}
|
||||
ADD CONSTRAINT $cName
|
||||
FOREIGN KEY $fkName ( {$fieldNoQ} ) REFERENCES {$targetTableNoQ}
|
||||
({$targetFieldNoQ}) ON DELETE " . ( $isDependent ? 'CASCADE' : 'SET NULL' ) . ' ON UPDATE '.( $isDependent ? 'CASCADE' : 'SET NULL' ).';');
|
||||
} catch ( SQLException $e ) {
|
||||
// Failure of fk-constraints is not a problem
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::sqlStateIn
|
||||
*/
|
||||
public function sqlStateIn( $state, $list, $extraDriverDetails = array() )
|
||||
{
|
||||
$stateMap = array(
|
||||
'42S02' => QueryWriter::C_SQLSTATE_NO_SUCH_TABLE,
|
||||
'42S22' => QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
|
||||
'23000' => QueryWriter::C_SQLSTATE_INTEGRITY_CONSTRAINT_VIOLATION
|
||||
);
|
||||
|
||||
return in_array( ( isset( $stateMap[$state] ) ? $stateMap[$state] : '0' ), $list );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::wipeAll
|
||||
*/
|
||||
public function wipeAll()
|
||||
{
|
||||
if (AQueryWriter::$noNuke) throw new \Exception('The nuke() command has been disabled using noNuke() or R::feature(novice/...).');
|
||||
$tables = $this->getTables();
|
||||
foreach( $tables as $table ) {
|
||||
$table = trim( $table );
|
||||
$this->adapter->exec( "DROP TABLE \"{$table}\" " );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
460
vendor/gabordemooij/redbean/RedBeanPHP/QueryWriter/MySQL.php
vendored
Normal file
460
vendor/gabordemooij/redbean/RedBeanPHP/QueryWriter/MySQL.php
vendored
Normal file
@@ -0,0 +1,460 @@
|
||||
<?php
|
||||
|
||||
namespace RedBeanPHP\QueryWriter;
|
||||
|
||||
use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter;
|
||||
use RedBeanPHP\QueryWriter as QueryWriter;
|
||||
use RedBeanPHP\Adapter\DBAdapter as DBAdapter;
|
||||
use RedBeanPHP\Adapter as Adapter;
|
||||
use RedBeanPHP\RedException\SQL as SQLException;
|
||||
|
||||
/**
|
||||
* RedBeanPHP MySQLWriter.
|
||||
* This is a QueryWriter class for RedBeanPHP.
|
||||
* This QueryWriter provides support for the MySQL/MariaDB database platform.
|
||||
*
|
||||
* @file RedBeanPHP/QueryWriter/MySQL.php
|
||||
* @author Gabor de Mooij and the RedBeanPHP Community
|
||||
* @license BSD/GPLv2
|
||||
*
|
||||
* @copyright
|
||||
* (c) G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community.
|
||||
* This source file is subject to the BSD/GPLv2 License that is bundled
|
||||
* with this source code in the file license.txt.
|
||||
*/
|
||||
class MySQL extends AQueryWriter implements QueryWriter
|
||||
{
|
||||
/**
|
||||
* Data types
|
||||
*/
|
||||
const C_DATATYPE_BOOL = 0;
|
||||
const C_DATATYPE_UINT32 = 2;
|
||||
const C_DATATYPE_DOUBLE = 3;
|
||||
const C_DATATYPE_TEXT7 = 4; //InnoDB cant index varchar(255) utf8mb4 - so keep 191 as long as possible
|
||||
const C_DATATYPE_TEXT8 = 5;
|
||||
const C_DATATYPE_TEXT16 = 6;
|
||||
const C_DATATYPE_TEXT32 = 7;
|
||||
const C_DATATYPE_SPECIAL_DATE = 80;
|
||||
const C_DATATYPE_SPECIAL_DATETIME = 81;
|
||||
const C_DATATYPE_SPECIAL_TIME = 83; //MySQL time column (only manual)
|
||||
const C_DATATYPE_SPECIAL_POINT = 90;
|
||||
const C_DATATYPE_SPECIAL_LINESTRING = 91;
|
||||
const C_DATATYPE_SPECIAL_POLYGON = 92;
|
||||
const C_DATATYPE_SPECIAL_MONEY = 93;
|
||||
const C_DATATYPE_SPECIAL_JSON = 94; //JSON support (only manual)
|
||||
|
||||
const C_DATATYPE_SPECIFIED = 99;
|
||||
|
||||
/**
|
||||
* @var DBAdapter
|
||||
*/
|
||||
protected $adapter;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $quoteCharacter = '`';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $DDLTemplates = array(
|
||||
'addColumn' => array(
|
||||
'*' => 'ALTER TABLE %s ADD %s %s '
|
||||
),
|
||||
'createTable' => array(
|
||||
'*' => 'CREATE TABLE %s (id INT( 11 ) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY ( id )) ENGINE = InnoDB DEFAULT CHARSET=%s COLLATE=%s '
|
||||
),
|
||||
'widenColumn' => array(
|
||||
'*' => 'ALTER TABLE `%s` CHANGE %s %s %s '
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* @see AQueryWriter::getKeyMapForType
|
||||
*/
|
||||
protected function getKeyMapForType( $type )
|
||||
{
|
||||
$databaseName = $this->adapter->getCell('SELECT DATABASE()');
|
||||
$table = $this->esc( $type, TRUE );
|
||||
$keys = $this->adapter->get('
|
||||
SELECT
|
||||
information_schema.key_column_usage.constraint_name AS `name`,
|
||||
information_schema.key_column_usage.referenced_table_name AS `table`,
|
||||
information_schema.key_column_usage.column_name AS `from`,
|
||||
information_schema.key_column_usage.referenced_column_name AS `to`,
|
||||
information_schema.referential_constraints.update_rule AS `on_update`,
|
||||
information_schema.referential_constraints.delete_rule AS `on_delete`
|
||||
FROM information_schema.key_column_usage
|
||||
INNER JOIN information_schema.referential_constraints
|
||||
ON information_schema.referential_constraints.constraint_name = information_schema.key_column_usage.constraint_name
|
||||
WHERE
|
||||
information_schema.key_column_usage.table_schema = :database
|
||||
AND information_schema.referential_constraints.constraint_schema = :database
|
||||
AND information_schema.key_column_usage.constraint_schema = :database
|
||||
AND information_schema.key_column_usage.table_name = :table
|
||||
AND information_schema.key_column_usage.constraint_name != \'PRIMARY\'
|
||||
AND information_schema.key_column_usage.referenced_table_name IS NOT NULL
|
||||
', array( ':database' => $databaseName, ':table' => $table ) );
|
||||
$keyInfoList = array();
|
||||
foreach ( $keys as $k ) {
|
||||
$label = $this->makeFKLabel( $k['from'], $k['table'], $k['to'] );
|
||||
$keyInfoList[$label] = array(
|
||||
'name' => $k['name'],
|
||||
'from' => $k['from'],
|
||||
'table' => $k['table'],
|
||||
'to' => $k['to'],
|
||||
'on_update' => $k['on_update'],
|
||||
'on_delete' => $k['on_delete']
|
||||
);
|
||||
}
|
||||
return $keyInfoList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* Most of the time, you do not need to use this constructor,
|
||||
* since the facade takes care of constructing and wiring the
|
||||
* RedBeanPHP core objects. However if you would like to
|
||||
* assemble an OODB instance yourself, this is how it works:
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* <code>
|
||||
* $database = new RPDO( $dsn, $user, $pass );
|
||||
* $adapter = new DBAdapter( $database );
|
||||
* $writer = new PostgresWriter( $adapter );
|
||||
* $oodb = new OODB( $writer, FALSE );
|
||||
* $bean = $oodb->dispense( 'bean' );
|
||||
* $bean->name = 'coffeeBean';
|
||||
* $id = $oodb->store( $bean );
|
||||
* $bean = $oodb->load( 'bean', $id );
|
||||
* </code>
|
||||
*
|
||||
* The example above creates the 3 RedBeanPHP core objects:
|
||||
* the Adapter, the Query Writer and the OODB instance and
|
||||
* wires them together. The example also demonstrates some of
|
||||
* the methods that can be used with OODB, as you see, they
|
||||
* closely resemble their facade counterparts.
|
||||
*
|
||||
* The wiring process: create an RPDO instance using your database
|
||||
* connection parameters. Create a database adapter from the RPDO
|
||||
* object and pass that to the constructor of the writer. Next,
|
||||
* create an OODB instance from the writer. Now you have an OODB
|
||||
* object.
|
||||
*
|
||||
* @param Adapter $adapter Database Adapter
|
||||
* @param array $options options array
|
||||
*/
|
||||
public function __construct( Adapter $adapter, $options = array() )
|
||||
{
|
||||
$this->typeno_sqltype = array(
|
||||
MySQL::C_DATATYPE_BOOL => ' TINYINT(1) UNSIGNED ',
|
||||
MySQL::C_DATATYPE_UINT32 => ' INT(11) UNSIGNED ',
|
||||
MySQL::C_DATATYPE_DOUBLE => ' DOUBLE ',
|
||||
MySQL::C_DATATYPE_TEXT7 => ' VARCHAR(191) ',
|
||||
MYSQL::C_DATATYPE_TEXT8 => ' VARCHAR(255) ',
|
||||
MySQL::C_DATATYPE_TEXT16 => ' TEXT ',
|
||||
MySQL::C_DATATYPE_TEXT32 => ' LONGTEXT ',
|
||||
MySQL::C_DATATYPE_SPECIAL_DATE => ' DATE ',
|
||||
MySQL::C_DATATYPE_SPECIAL_DATETIME => ' DATETIME ',
|
||||
MySQL::C_DATATYPE_SPECIAL_TIME => ' TIME ',
|
||||
MySQL::C_DATATYPE_SPECIAL_POINT => ' POINT ',
|
||||
MySQL::C_DATATYPE_SPECIAL_LINESTRING => ' LINESTRING ',
|
||||
MySQL::C_DATATYPE_SPECIAL_POLYGON => ' POLYGON ',
|
||||
MySQL::C_DATATYPE_SPECIAL_MONEY => ' DECIMAL(10,2) ',
|
||||
MYSQL::C_DATATYPE_SPECIAL_JSON => ' JSON '
|
||||
);
|
||||
|
||||
$this->sqltype_typeno = array();
|
||||
|
||||
foreach ( $this->typeno_sqltype as $k => $v ) {
|
||||
$this->sqltype_typeno[trim( strtolower( $v ) )] = $k;
|
||||
}
|
||||
|
||||
$this->adapter = $adapter;
|
||||
$this->encoding = $this->adapter->getDatabase()->getMysqlEncoding();
|
||||
$me = $this;
|
||||
if (!isset($options['noInitcode']))
|
||||
$this->adapter->setInitCode(function($version) use(&$me) {
|
||||
try {
|
||||
if (strpos($version, 'maria')===FALSE && intval($version)>=8) {
|
||||
$me->useFeature('ignoreDisplayWidth');
|
||||
}
|
||||
} catch( \Exception $e ){}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables certain features/dialects.
|
||||
*
|
||||
* - ignoreDisplayWidth required for MySQL8+
|
||||
* (automatically set by setup() if you pass dsn instead of PDO object)
|
||||
*
|
||||
* @param string $name feature ID
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function useFeature($name) {
|
||||
if ($name == 'ignoreDisplayWidth') {
|
||||
$this->typeno_sqltype[MySQL::C_DATATYPE_BOOL] = ' TINYINT UNSIGNED ';
|
||||
$this->typeno_sqltype[MySQL::C_DATATYPE_UINT32] = ' INT UNSIGNED ';
|
||||
foreach ( $this->typeno_sqltype as $k => $v ) {
|
||||
$this->sqltype_typeno[trim( strtolower( $v ) )] = $k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the datatype to be used for primary key IDS and
|
||||
* foreign keys. Returns one if the data type constants.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getTypeForID()
|
||||
{
|
||||
return self::C_DATATYPE_UINT32;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::getTables
|
||||
*/
|
||||
public function getTables()
|
||||
{
|
||||
return $this->adapter->getCol( 'show tables' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::createTable
|
||||
*/
|
||||
public function createTable( $type )
|
||||
{
|
||||
$table = $this->esc( $type );
|
||||
|
||||
$charset_collate = $this->adapter->getDatabase()->getMysqlEncoding( TRUE );
|
||||
$charset = $charset_collate['charset'];
|
||||
$collate = $charset_collate['collate'];
|
||||
|
||||
$sql = sprintf( $this->getDDLTemplate( 'createTable', $type ), $table, $charset, $collate );
|
||||
|
||||
$this->adapter->exec( $sql );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::getColumns
|
||||
*/
|
||||
public function getColumns( $table )
|
||||
{
|
||||
$columnsRaw = $this->adapter->get( "DESCRIBE " . $this->esc( $table ) );
|
||||
|
||||
$columns = array();
|
||||
foreach ( $columnsRaw as $r ) {
|
||||
$columns[$r['Field']] = $r['Type'];
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::scanType
|
||||
*/
|
||||
public function scanType( $value, $flagSpecial = FALSE )
|
||||
{
|
||||
$this->svalue = $value;
|
||||
|
||||
if ( is_null( $value ) ) return MySQL::C_DATATYPE_BOOL;
|
||||
if ( $value === INF ) return MySQL::C_DATATYPE_TEXT7;
|
||||
|
||||
if ( $flagSpecial ) {
|
||||
if ( preg_match( '/^-?\d+\.\d{2}$/', $value ) ) {
|
||||
return MySQL::C_DATATYPE_SPECIAL_MONEY;
|
||||
}
|
||||
if ( preg_match( '/^\d{4}\-\d\d-\d\d$/', $value ) ) {
|
||||
return MySQL::C_DATATYPE_SPECIAL_DATE;
|
||||
}
|
||||
if ( preg_match( '/^\d{4}\-\d\d-\d\d\s\d\d:\d\d:\d\d$/', $value ) ) {
|
||||
return MySQL::C_DATATYPE_SPECIAL_DATETIME;
|
||||
}
|
||||
if ( preg_match( '/^POINT\(/', $value ) ) {
|
||||
return MySQL::C_DATATYPE_SPECIAL_POINT;
|
||||
}
|
||||
if ( preg_match( '/^LINESTRING\(/', $value ) ) {
|
||||
return MySQL::C_DATATYPE_SPECIAL_LINESTRING;
|
||||
}
|
||||
if ( preg_match( '/^POLYGON\(/', $value ) ) {
|
||||
return MySQL::C_DATATYPE_SPECIAL_POLYGON;
|
||||
}
|
||||
if ( self::$flagUseJSONColumns && $this->isJSON( $value ) ) {
|
||||
return self::C_DATATYPE_SPECIAL_JSON;
|
||||
}
|
||||
}
|
||||
|
||||
//setter turns TRUE FALSE into 0 and 1 because database has no real bools (TRUE and FALSE only for test?).
|
||||
if ( $value === FALSE || $value === TRUE || $value === '0' || $value === '1' || $value === 0 || $value === 1 ) {
|
||||
return MySQL::C_DATATYPE_BOOL;
|
||||
}
|
||||
|
||||
if ( is_float( $value ) ) return self::C_DATATYPE_DOUBLE;
|
||||
|
||||
if ( !$this->startsWithZeros( $value ) ) {
|
||||
|
||||
if ( is_numeric( $value ) && ( floor( $value ) == $value ) && $value >= 0 && $value <= 4294967295 ) {
|
||||
return MySQL::C_DATATYPE_UINT32;
|
||||
}
|
||||
|
||||
if ( is_numeric( $value ) ) {
|
||||
return MySQL::C_DATATYPE_DOUBLE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( mb_strlen( $value, 'UTF-8' ) <= 191 ) {
|
||||
return MySQL::C_DATATYPE_TEXT7;
|
||||
}
|
||||
|
||||
if ( mb_strlen( $value, 'UTF-8' ) <= 255 ) {
|
||||
return MySQL::C_DATATYPE_TEXT8;
|
||||
}
|
||||
|
||||
if ( mb_strlen( $value, 'UTF-8' ) <= 65535 ) {
|
||||
return MySQL::C_DATATYPE_TEXT16;
|
||||
}
|
||||
|
||||
return MySQL::C_DATATYPE_TEXT32;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::code
|
||||
*/
|
||||
public function code( $typedescription, $includeSpecials = FALSE )
|
||||
{
|
||||
if ( isset( $this->sqltype_typeno[$typedescription] ) ) {
|
||||
$r = $this->sqltype_typeno[$typedescription];
|
||||
} else {
|
||||
$r = self::C_DATATYPE_SPECIFIED;
|
||||
}
|
||||
|
||||
if ( $includeSpecials ) {
|
||||
return $r;
|
||||
}
|
||||
|
||||
if ( $r >= QueryWriter::C_DATATYPE_RANGE_SPECIAL ) {
|
||||
return self::C_DATATYPE_SPECIFIED;
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addUniqueIndex
|
||||
*/
|
||||
public function addUniqueConstraint( $type, $properties )
|
||||
{
|
||||
$tableNoQ = $this->esc( $type, TRUE );
|
||||
$columns = array();
|
||||
foreach( $properties as $key => $column ) $columns[$key] = $this->esc( $column );
|
||||
$table = $this->esc( $type );
|
||||
sort( $columns ); // Else we get multiple indexes due to order-effects
|
||||
$name = 'UQ_' . sha1( implode( ',', $columns ) );
|
||||
try {
|
||||
$sql = "ALTER TABLE $table
|
||||
ADD UNIQUE INDEX $name (" . implode( ',', $columns ) . ")";
|
||||
$this->adapter->exec( $sql );
|
||||
} catch ( SQLException $e ) {
|
||||
//do nothing, dont use alter table ignore, this will delete duplicate records in 3-ways!
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addIndex
|
||||
*/
|
||||
public function addIndex( $type, $name, $property )
|
||||
{
|
||||
try {
|
||||
$table = $this->esc( $type );
|
||||
$name = preg_replace( '/\W/', '', $name );
|
||||
$column = $this->esc( $property );
|
||||
$this->adapter->exec( "CREATE INDEX $name ON $table ($column) " );
|
||||
return TRUE;
|
||||
} catch ( SQLException $e ) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addFK
|
||||
* @return bool
|
||||
*/
|
||||
public function addFK( $type, $targetType, $property, $targetProperty, $isDependent = FALSE )
|
||||
{
|
||||
$table = $this->esc( $type );
|
||||
$targetTable = $this->esc( $targetType );
|
||||
$targetTableNoQ = $this->esc( $targetType, TRUE );
|
||||
$field = $this->esc( $property );
|
||||
$fieldNoQ = $this->esc( $property, TRUE );
|
||||
$targetField = $this->esc( $targetProperty );
|
||||
$targetFieldNoQ = $this->esc( $targetProperty, TRUE );
|
||||
$tableNoQ = $this->esc( $type, TRUE );
|
||||
$fieldNoQ = $this->esc( $property, TRUE );
|
||||
if ( !is_null( $this->getForeignKeyForTypeProperty( $tableNoQ, $fieldNoQ ) ) ) return FALSE;
|
||||
|
||||
//Widen the column if it's incapable of representing a foreign key (at least INT).
|
||||
$columns = $this->getColumns( $tableNoQ );
|
||||
$idType = $this->getTypeForID();
|
||||
if ( $this->code( $columns[$fieldNoQ] ) !== $idType ) {
|
||||
$this->widenColumn( $type, $property, $idType );
|
||||
}
|
||||
|
||||
$fkName = 'fk_'.($tableNoQ.'_'.$fieldNoQ);
|
||||
$cName = 'c_'.$fkName;
|
||||
try {
|
||||
$this->adapter->exec( "
|
||||
ALTER TABLE {$table}
|
||||
ADD CONSTRAINT $cName
|
||||
FOREIGN KEY $fkName ( `{$fieldNoQ}` ) REFERENCES `{$targetTableNoQ}`
|
||||
(`{$targetFieldNoQ}`) ON DELETE " . ( $isDependent ? 'CASCADE' : 'SET NULL' ) . ' ON UPDATE '.( $isDependent ? 'CASCADE' : 'SET NULL' ).';');
|
||||
} catch ( SQLException $e ) {
|
||||
// Failure of fk-constraints is not a problem
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::sqlStateIn
|
||||
*/
|
||||
public function sqlStateIn( $state, $list, $extraDriverDetails = array() )
|
||||
{
|
||||
$stateMap = array(
|
||||
'42S02' => QueryWriter::C_SQLSTATE_NO_SUCH_TABLE,
|
||||
'42S22' => QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
|
||||
'23000' => QueryWriter::C_SQLSTATE_INTEGRITY_CONSTRAINT_VIOLATION,
|
||||
);
|
||||
|
||||
if ( $state == 'HY000' && !empty( $extraDriverDetails[1] ) ) {
|
||||
$driverCode = $extraDriverDetails[1];
|
||||
|
||||
if ( $driverCode == '1205' && in_array( QueryWriter::C_SQLSTATE_LOCK_TIMEOUT, $list ) ) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return in_array( ( isset( $stateMap[$state] ) ? $stateMap[$state] : '0' ), $list );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::wipeAll
|
||||
*/
|
||||
public function wipeAll()
|
||||
{
|
||||
if (AQueryWriter::$noNuke) throw new \Exception('The nuke() command has been disabled using noNuke() or R::feature(novice/...).');
|
||||
$this->adapter->exec( 'SET FOREIGN_KEY_CHECKS = 0;' );
|
||||
|
||||
foreach ( $this->getTables() as $t ) {
|
||||
try { $this->adapter->exec( "DROP TABLE IF EXISTS `$t`" ); } catch ( SQLException $e ) { ; }
|
||||
try { $this->adapter->exec( "DROP VIEW IF EXISTS `$t`" ); } catch ( SQLException $e ) { ; }
|
||||
}
|
||||
|
||||
$this->adapter->exec( 'SET FOREIGN_KEY_CHECKS = 1;' );
|
||||
}
|
||||
}
|
436
vendor/gabordemooij/redbean/RedBeanPHP/QueryWriter/PostgreSQL.php
vendored
Normal file
436
vendor/gabordemooij/redbean/RedBeanPHP/QueryWriter/PostgreSQL.php
vendored
Normal file
@@ -0,0 +1,436 @@
|
||||
<?php
|
||||
|
||||
namespace RedBeanPHP\QueryWriter;
|
||||
|
||||
use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter;
|
||||
use RedBeanPHP\QueryWriter as QueryWriter;
|
||||
use RedBeanPHP\Adapter\DBAdapter as DBAdapter;
|
||||
use RedBeanPHP\Adapter as Adapter;
|
||||
use RedBeanPHP\RedException\SQL as SQLException;
|
||||
|
||||
/**
|
||||
* RedBeanPHP PostgreSQL Query Writer.
|
||||
* This is a QueryWriter class for RedBeanPHP.
|
||||
* This QueryWriter provides support for the PostgreSQL database platform.
|
||||
*
|
||||
* @file RedBeanPHP/QueryWriter/PostgreSQL.php
|
||||
* @author Gabor de Mooij and the RedBeanPHP Community
|
||||
* @license BSD/GPLv2
|
||||
*
|
||||
* @copyright
|
||||
* (c) copyright G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community.
|
||||
* This source file is subject to the BSD/GPLv2 License that is bundled
|
||||
* with this source code in the file license.txt.
|
||||
*/
|
||||
class PostgreSQL extends AQueryWriter implements QueryWriter
|
||||
{
|
||||
/**
|
||||
* Data types
|
||||
*/
|
||||
const C_DATATYPE_INTEGER = 0;
|
||||
const C_DATATYPE_DOUBLE = 1;
|
||||
const C_DATATYPE_TEXT = 3;
|
||||
const C_DATATYPE_SPECIAL_DATE = 80;
|
||||
const C_DATATYPE_SPECIAL_DATETIME = 81;
|
||||
const C_DATATYPE_SPECIAL_TIME = 82; //TIME (no zone) only manual
|
||||
const C_DATATYPE_SPECIAL_TIMEZ = 83; //TIME (plus zone) only manual
|
||||
const C_DATATYPE_SPECIAL_POINT = 90;
|
||||
const C_DATATYPE_SPECIAL_LSEG = 91;
|
||||
const C_DATATYPE_SPECIAL_CIRCLE = 92;
|
||||
const C_DATATYPE_SPECIAL_MONEY = 93;
|
||||
const C_DATATYPE_SPECIAL_POLYGON = 94;
|
||||
const C_DATATYPE_SPECIAL_MONEY2 = 95; //Numbers only money, i.e. fixed point numeric
|
||||
const C_DATATYPE_SPECIAL_JSON = 96; //JSON support (only manual)
|
||||
const C_DATATYPE_SPECIFIED = 99;
|
||||
|
||||
/**
|
||||
* @var DBAdapter
|
||||
*/
|
||||
protected $adapter;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $quoteCharacter = '"';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $defaultValue = 'DEFAULT';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $DDLTemplates = array(
|
||||
'addColumn' => array(
|
||||
'*' => 'ALTER TABLE %s ADD %s %s '
|
||||
),
|
||||
'createTable' => array(
|
||||
'*' => 'CREATE TABLE %s (id SERIAL PRIMARY KEY) '
|
||||
),
|
||||
'widenColumn' => array(
|
||||
'*' => 'ALTER TABLE %s ALTER COLUMN %s TYPE %s'
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the insert suffix SQL Snippet
|
||||
*
|
||||
* @param string $table table
|
||||
*
|
||||
* @return string $sql SQL Snippet
|
||||
*/
|
||||
protected function getInsertSuffix( $table )
|
||||
{
|
||||
return 'RETURNING id ';
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AQueryWriter::getKeyMapForType
|
||||
*/
|
||||
protected function getKeyMapForType( $type )
|
||||
{
|
||||
$table = $this->esc( $type, TRUE );
|
||||
$keys = $this->adapter->get( '
|
||||
SELECT
|
||||
information_schema.key_column_usage.constraint_name AS "name",
|
||||
information_schema.key_column_usage.column_name AS "from",
|
||||
information_schema.constraint_table_usage.table_name AS "table",
|
||||
information_schema.constraint_column_usage.column_name AS "to",
|
||||
information_schema.referential_constraints.update_rule AS "on_update",
|
||||
information_schema.referential_constraints.delete_rule AS "on_delete"
|
||||
FROM information_schema.key_column_usage
|
||||
INNER JOIN information_schema.constraint_table_usage
|
||||
ON (
|
||||
information_schema.key_column_usage.constraint_name = information_schema.constraint_table_usage.constraint_name
|
||||
AND information_schema.key_column_usage.constraint_schema = information_schema.constraint_table_usage.constraint_schema
|
||||
AND information_schema.key_column_usage.constraint_catalog = information_schema.constraint_table_usage.constraint_catalog
|
||||
)
|
||||
INNER JOIN information_schema.constraint_column_usage
|
||||
ON (
|
||||
information_schema.key_column_usage.constraint_name = information_schema.constraint_column_usage.constraint_name
|
||||
AND information_schema.key_column_usage.constraint_schema = information_schema.constraint_column_usage.constraint_schema
|
||||
AND information_schema.key_column_usage.constraint_catalog = information_schema.constraint_column_usage.constraint_catalog
|
||||
)
|
||||
INNER JOIN information_schema.referential_constraints
|
||||
ON (
|
||||
information_schema.key_column_usage.constraint_name = information_schema.referential_constraints.constraint_name
|
||||
AND information_schema.key_column_usage.constraint_schema = information_schema.referential_constraints.constraint_schema
|
||||
AND information_schema.key_column_usage.constraint_catalog = information_schema.referential_constraints.constraint_catalog
|
||||
)
|
||||
WHERE
|
||||
information_schema.key_column_usage.table_catalog = current_database()
|
||||
AND information_schema.key_column_usage.table_schema = ANY( current_schemas( FALSE ) )
|
||||
AND information_schema.key_column_usage.table_name = ?
|
||||
', array( $type ) );
|
||||
$keyInfoList = array();
|
||||
foreach ( $keys as $k ) {
|
||||
$label = $this->makeFKLabel( $k['from'], $k['table'], $k['to'] );
|
||||
$keyInfoList[$label] = array(
|
||||
'name' => $k['name'],
|
||||
'from' => $k['from'],
|
||||
'table' => $k['table'],
|
||||
'to' => $k['to'],
|
||||
'on_update' => $k['on_update'],
|
||||
'on_delete' => $k['on_delete']
|
||||
);
|
||||
}
|
||||
return $keyInfoList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* Most of the time, you do not need to use this constructor,
|
||||
* since the facade takes care of constructing and wiring the
|
||||
* RedBeanPHP core objects. However if you would like to
|
||||
* assemble an OODB instance yourself, this is how it works:
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* <code>
|
||||
* $database = new RPDO( $dsn, $user, $pass );
|
||||
* $adapter = new DBAdapter( $database );
|
||||
* $writer = new PostgresWriter( $adapter );
|
||||
* $oodb = new OODB( $writer, FALSE );
|
||||
* $bean = $oodb->dispense( 'bean' );
|
||||
* $bean->name = 'coffeeBean';
|
||||
* $id = $oodb->store( $bean );
|
||||
* $bean = $oodb->load( 'bean', $id );
|
||||
* </code>
|
||||
*
|
||||
* The example above creates the 3 RedBeanPHP core objects:
|
||||
* the Adapter, the Query Writer and the OODB instance and
|
||||
* wires them together. The example also demonstrates some of
|
||||
* the methods that can be used with OODB, as you see, they
|
||||
* closely resemble their facade counterparts.
|
||||
*
|
||||
* The wiring process: create an RPDO instance using your database
|
||||
* connection parameters. Create a database adapter from the RPDO
|
||||
* object and pass that to the constructor of the writer. Next,
|
||||
* create an OODB instance from the writer. Now you have an OODB
|
||||
* object.
|
||||
*
|
||||
* @param Adapter $adapter Database Adapter
|
||||
*/
|
||||
public function __construct( Adapter $adapter )
|
||||
{
|
||||
$this->typeno_sqltype = array(
|
||||
self::C_DATATYPE_INTEGER => ' integer ',
|
||||
self::C_DATATYPE_DOUBLE => ' double precision ',
|
||||
self::C_DATATYPE_TEXT => ' text ',
|
||||
self::C_DATATYPE_SPECIAL_DATE => ' date ',
|
||||
self::C_DATATYPE_SPECIAL_TIME => ' time ',
|
||||
self::C_DATATYPE_SPECIAL_TIMEZ => ' time with time zone ',
|
||||
self::C_DATATYPE_SPECIAL_DATETIME => ' timestamp without time zone ',
|
||||
self::C_DATATYPE_SPECIAL_POINT => ' point ',
|
||||
self::C_DATATYPE_SPECIAL_LSEG => ' lseg ',
|
||||
self::C_DATATYPE_SPECIAL_CIRCLE => ' circle ',
|
||||
self::C_DATATYPE_SPECIAL_MONEY => ' money ',
|
||||
self::C_DATATYPE_SPECIAL_MONEY2 => ' numeric(10,2) ',
|
||||
self::C_DATATYPE_SPECIAL_POLYGON => ' polygon ',
|
||||
self::C_DATATYPE_SPECIAL_JSON => ' json ',
|
||||
);
|
||||
|
||||
$this->sqltype_typeno = array();
|
||||
|
||||
foreach ( $this->typeno_sqltype as $k => $v ) {
|
||||
$this->sqltype_typeno[trim( strtolower( $v ) )] = $k;
|
||||
}
|
||||
|
||||
$this->adapter = $adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the datatype to be used for primary key IDS and
|
||||
* foreign keys. Returns one if the data type constants.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getTypeForID()
|
||||
{
|
||||
return self::C_DATATYPE_INTEGER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::getTables
|
||||
*/
|
||||
public function getTables()
|
||||
{
|
||||
return $this->adapter->getCol( 'SELECT table_name FROM information_schema.tables WHERE table_schema = ANY( current_schemas( FALSE ) )' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::createTable
|
||||
*/
|
||||
public function createTable( $type )
|
||||
{
|
||||
$table = $this->esc( $type );
|
||||
|
||||
$this->adapter->exec( sprintf( $this->getDDLTemplate( 'createTable', $type ), $table ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::getColumns
|
||||
*/
|
||||
public function getColumns( $table )
|
||||
{
|
||||
$table = $this->esc( $table, TRUE );
|
||||
|
||||
$columnsRaw = $this->adapter->get( "SELECT column_name, data_type FROM information_schema.columns WHERE table_name='$table' AND table_schema = ANY( current_schemas( FALSE ) )" );
|
||||
|
||||
$columns = array();
|
||||
foreach ( $columnsRaw as $r ) {
|
||||
$columns[$r['column_name']] = $r['data_type'];
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::scanType
|
||||
*/
|
||||
public function scanType( $value, $flagSpecial = FALSE )
|
||||
{
|
||||
$this->svalue = $value;
|
||||
|
||||
if ( $value === INF ) return self::C_DATATYPE_TEXT;
|
||||
|
||||
if ( $flagSpecial && $value ) {
|
||||
if ( preg_match( '/^\d{4}\-\d\d-\d\d$/', $value ) ) {
|
||||
return PostgreSQL::C_DATATYPE_SPECIAL_DATE;
|
||||
}
|
||||
|
||||
if ( preg_match( '/^\d{4}\-\d\d-\d\d\s\d\d:\d\d:\d\d(\.\d{1,6})?$/', $value ) ) {
|
||||
return PostgreSQL::C_DATATYPE_SPECIAL_DATETIME;
|
||||
}
|
||||
|
||||
if ( preg_match( '/^\([\d\.]+,[\d\.]+\)$/', $value ) ) {
|
||||
return PostgreSQL::C_DATATYPE_SPECIAL_POINT;
|
||||
}
|
||||
|
||||
if ( preg_match( '/^\[\([\d\.]+,[\d\.]+\),\([\d\.]+,[\d\.]+\)\]$/', $value ) ) {
|
||||
return PostgreSQL::C_DATATYPE_SPECIAL_LSEG;
|
||||
}
|
||||
|
||||
if ( preg_match( '/^\<\([\d\.]+,[\d\.]+\),[\d\.]+\>$/', $value ) ) {
|
||||
return PostgreSQL::C_DATATYPE_SPECIAL_CIRCLE;
|
||||
}
|
||||
|
||||
if ( preg_match( '/^\((\([\d\.]+,[\d\.]+\),?)+\)$/', $value ) ) {
|
||||
return PostgreSQL::C_DATATYPE_SPECIAL_POLYGON;
|
||||
}
|
||||
|
||||
if ( preg_match( '/^\-?(\$|€|¥|£)[\d,\.]+$/', $value ) ) {
|
||||
return PostgreSQL::C_DATATYPE_SPECIAL_MONEY;
|
||||
}
|
||||
|
||||
if ( preg_match( '/^-?\d+\.\d{2}$/', $value ) ) {
|
||||
return PostgreSQL::C_DATATYPE_SPECIAL_MONEY2;
|
||||
}
|
||||
if ( self::$flagUseJSONColumns && $this->isJSON( $value ) ) {
|
||||
return self::C_DATATYPE_SPECIAL_JSON;
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_float( $value ) ) return self::C_DATATYPE_DOUBLE;
|
||||
|
||||
if ( $this->startsWithZeros( $value ) ) return self::C_DATATYPE_TEXT;
|
||||
|
||||
if ( $value === FALSE || $value === TRUE || $value === NULL || ( is_numeric( $value )
|
||||
&& AQueryWriter::canBeTreatedAsInt( $value )
|
||||
&& $value < 2147483648
|
||||
&& $value > -2147483648 )
|
||||
) {
|
||||
return self::C_DATATYPE_INTEGER;
|
||||
} elseif ( is_numeric( $value ) ) {
|
||||
return self::C_DATATYPE_DOUBLE;
|
||||
} else {
|
||||
return self::C_DATATYPE_TEXT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::code
|
||||
*/
|
||||
public function code( $typedescription, $includeSpecials = FALSE )
|
||||
{
|
||||
$r = ( isset( $this->sqltype_typeno[$typedescription] ) ) ? $this->sqltype_typeno[$typedescription] : 99;
|
||||
|
||||
if ( $includeSpecials ) return $r;
|
||||
|
||||
if ( $r >= QueryWriter::C_DATATYPE_RANGE_SPECIAL ) {
|
||||
return self::C_DATATYPE_SPECIFIED;
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::widenColumn
|
||||
*/
|
||||
public function widenColumn( $beanType, $column, $datatype )
|
||||
{
|
||||
$table = $beanType;
|
||||
$type = $datatype;
|
||||
|
||||
$table = $this->esc( $table );
|
||||
$column = $this->esc( $column );
|
||||
|
||||
$newtype = $this->typeno_sqltype[$type];
|
||||
|
||||
$this->adapter->exec( sprintf( $this->getDDLTemplate( 'widenColumn', $beanType, $column ), $table, $column, $newtype ) );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addUniqueIndex
|
||||
*/
|
||||
public function addUniqueConstraint( $type, $properties )
|
||||
{
|
||||
$tableNoQ = $this->esc( $type, TRUE );
|
||||
$columns = array();
|
||||
foreach( $properties as $key => $column ) $columns[$key] = $this->esc( $column );
|
||||
$table = $this->esc( $type );
|
||||
sort( $columns ); //else we get multiple indexes due to order-effects
|
||||
$name = "UQ_" . sha1( $table . implode( ',', $columns ) );
|
||||
$sql = "ALTER TABLE {$table}
|
||||
ADD CONSTRAINT $name UNIQUE (" . implode( ',', $columns ) . ")";
|
||||
try {
|
||||
$this->adapter->exec( $sql );
|
||||
} catch( SQLException $e ) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::sqlStateIn
|
||||
*/
|
||||
public function sqlStateIn( $state, $list, $extraDriverDetails = array() )
|
||||
{
|
||||
$stateMap = array(
|
||||
'42P01' => QueryWriter::C_SQLSTATE_NO_SUCH_TABLE,
|
||||
'42703' => QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN,
|
||||
'23505' => QueryWriter::C_SQLSTATE_INTEGRITY_CONSTRAINT_VIOLATION,
|
||||
'55P03' => QueryWriter::C_SQLSTATE_LOCK_TIMEOUT
|
||||
);
|
||||
return in_array( ( isset( $stateMap[$state] ) ? $stateMap[$state] : '0' ), $list );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addIndex
|
||||
*/
|
||||
public function addIndex( $type, $name, $property )
|
||||
{
|
||||
$table = $this->esc( $type );
|
||||
$name = preg_replace( '/\W/', '', $name );
|
||||
$column = $this->esc( $property );
|
||||
|
||||
try {
|
||||
$this->adapter->exec( "CREATE INDEX {$name} ON $table ({$column}) " );
|
||||
return TRUE;
|
||||
} catch ( SQLException $e ) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addFK
|
||||
*/
|
||||
public function addFK( $type, $targetType, $property, $targetProperty, $isDep = FALSE )
|
||||
{
|
||||
$table = $this->esc( $type );
|
||||
$targetTable = $this->esc( $targetType );
|
||||
$field = $this->esc( $property );
|
||||
$targetField = $this->esc( $targetProperty );
|
||||
$tableNoQ = $this->esc( $type, TRUE );
|
||||
$fieldNoQ = $this->esc( $property, TRUE );
|
||||
if ( !is_null( $this->getForeignKeyForTypeProperty( $tableNoQ, $fieldNoQ ) ) ) return FALSE;
|
||||
try{
|
||||
$delRule = ( $isDep ? 'CASCADE' : 'SET NULL' );
|
||||
$this->adapter->exec( "ALTER TABLE {$table}
|
||||
ADD FOREIGN KEY ( {$field} ) REFERENCES {$targetTable}
|
||||
({$targetField}) ON DELETE {$delRule} ON UPDATE {$delRule} DEFERRABLE ;" );
|
||||
return TRUE;
|
||||
} catch ( SQLException $e ) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::wipeAll
|
||||
*/
|
||||
public function wipeAll()
|
||||
{
|
||||
if (AQueryWriter::$noNuke) throw new \Exception('The nuke() command has been disabled using noNuke() or R::feature(novice/...).');
|
||||
$this->adapter->exec( 'SET CONSTRAINTS ALL DEFERRED' );
|
||||
|
||||
foreach ( $this->getTables() as $t ) {
|
||||
$t = $this->esc( $t );
|
||||
//Some plugins (PostGIS have unremovable tables/views), avoid exceptions.
|
||||
try { $this->adapter->exec( "DROP TABLE IF EXISTS $t CASCADE " ); }catch( \Exception $e ) {}
|
||||
}
|
||||
|
||||
$this->adapter->exec( 'SET CONSTRAINTS ALL IMMEDIATE' );
|
||||
}
|
||||
}
|
496
vendor/gabordemooij/redbean/RedBeanPHP/QueryWriter/SQLiteT.php
vendored
Normal file
496
vendor/gabordemooij/redbean/RedBeanPHP/QueryWriter/SQLiteT.php
vendored
Normal file
@@ -0,0 +1,496 @@
|
||||
<?php
|
||||
|
||||
namespace RedBeanPHP\QueryWriter;
|
||||
|
||||
use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter;
|
||||
use RedBeanPHP\QueryWriter as QueryWriter;
|
||||
use RedBeanPHP\Adapter\DBAdapter as DBAdapter;
|
||||
use RedBeanPHP\Adapter as Adapter;
|
||||
use RedBeanPHP\RedException\SQL as SQLException;
|
||||
|
||||
/**
|
||||
* RedBeanPHP SQLiteWriter with support for SQLite types
|
||||
* This is a QueryWriter class for RedBeanPHP.
|
||||
* This QueryWriter provides support for the SQLite database platform.
|
||||
*
|
||||
* @file RedBeanPHP/QueryWriter/SQLiteT.php
|
||||
* @author Gabor de Mooij and the RedBeanPHP Community
|
||||
* @license BSD/GPLv2
|
||||
*
|
||||
* @copyright
|
||||
* (c) copyright G.J.G.T. (Gabor) de Mooij and the RedBeanPHP Community.
|
||||
* This source file is subject to the BSD/GPLv2 License that is bundled
|
||||
* with this source code in the file license.txt.
|
||||
*/
|
||||
class SQLiteT extends AQueryWriter implements QueryWriter
|
||||
{
|
||||
/**
|
||||
* Data types
|
||||
*/
|
||||
const C_DATATYPE_INTEGER = 0;
|
||||
const C_DATATYPE_NUMERIC = 1;
|
||||
const C_DATATYPE_TEXT = 2;
|
||||
const C_DATATYPE_SPECIFIED = 99;
|
||||
|
||||
/**
|
||||
* @var DBAdapter
|
||||
*/
|
||||
protected $adapter;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $quoteCharacter = '`';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $DDLTemplates = array(
|
||||
'addColumn' => array(
|
||||
'*' => 'ALTER TABLE `%s` ADD `%s` %s'
|
||||
),
|
||||
'createTable' => array(
|
||||
'*' => 'CREATE TABLE %s ( id INTEGER PRIMARY KEY AUTOINCREMENT )'
|
||||
),
|
||||
'widenColumn' => array(
|
||||
'*' => ',`%s` %s '
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets all information about a table (from a type).
|
||||
*
|
||||
* Format:
|
||||
* array(
|
||||
* name => name of the table
|
||||
* columns => array( name => datatype )
|
||||
* indexes => array() raw index information rows from PRAGMA query
|
||||
* keys => array() raw key information rows from PRAGMA query
|
||||
* )
|
||||
*
|
||||
* @param string $type type you want to get info of
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTable( $type )
|
||||
{
|
||||
$tableName = $this->esc( $type, TRUE );
|
||||
$columns = $this->getColumns( $type );
|
||||
$indexes = $this->getIndexes( $type );
|
||||
$keys = $this->getKeyMapForType( $type );
|
||||
|
||||
$table = array(
|
||||
'columns' => $columns,
|
||||
'indexes' => $indexes,
|
||||
'keys' => $keys,
|
||||
'name' => $tableName
|
||||
);
|
||||
|
||||
$this->tableArchive[$tableName] = $table;
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a table. Updates the table structure.
|
||||
* In SQLite we can't change columns, drop columns, change or add foreign keys so we
|
||||
* have a table-rebuild function. You simply load your table with getTable(), modify it and
|
||||
* then store it with putTable()...
|
||||
*
|
||||
* @param array $tableMap information array
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function putTable( $tableMap )
|
||||
{
|
||||
$table = $tableMap['name'];
|
||||
$q = array();
|
||||
$q[] = "DROP TABLE IF EXISTS tmp_backup;";
|
||||
|
||||
$oldColumnNames = array_keys( $this->getColumns( $table ) );
|
||||
|
||||
foreach ( $oldColumnNames as $k => $v ) $oldColumnNames[$k] = "`$v`";
|
||||
|
||||
$q[] = "CREATE TEMPORARY TABLE tmp_backup(" . implode( ",", $oldColumnNames ) . ");";
|
||||
$q[] = "INSERT INTO tmp_backup SELECT * FROM `$table`;";
|
||||
$q[] = "PRAGMA foreign_keys = 0 ";
|
||||
$q[] = "DROP TABLE `$table`;";
|
||||
|
||||
$newTableDefStr = '';
|
||||
foreach ( $tableMap['columns'] as $column => $type ) {
|
||||
if ( $column != 'id' ) {
|
||||
$newTableDefStr .= sprintf( $this->getDDLTemplate( 'widenColumn', $table, $column ), $column, $type );
|
||||
}
|
||||
}
|
||||
|
||||
$fkDef = '';
|
||||
foreach ( $tableMap['keys'] as $key ) {
|
||||
$fkDef .= ", FOREIGN KEY(`{$key['from']}`)
|
||||
REFERENCES `{$key['table']}`(`{$key['to']}`)
|
||||
ON DELETE {$key['on_delete']} ON UPDATE {$key['on_update']}";
|
||||
}
|
||||
|
||||
$q[] = "CREATE TABLE `$table` ( `id` INTEGER PRIMARY KEY AUTOINCREMENT $newTableDefStr $fkDef );";
|
||||
|
||||
foreach ( $tableMap['indexes'] as $name => $index ) {
|
||||
if ( strpos( $name, 'UQ_' ) === 0 ) {
|
||||
$cols = explode( '__', substr( $name, strlen( 'UQ_' . $table ) ) );
|
||||
foreach ( $cols as $k => $v ) $cols[$k] = "`$v`";
|
||||
$q[] = "CREATE UNIQUE INDEX $name ON `$table` (" . implode( ',', $cols ) . ")";
|
||||
} else $q[] = "CREATE INDEX $name ON `$table` ({$index['name']}) ";
|
||||
}
|
||||
|
||||
$q[] = "INSERT INTO `$table` SELECT * FROM tmp_backup;";
|
||||
$q[] = "DROP TABLE tmp_backup;";
|
||||
$q[] = "PRAGMA foreign_keys = 1 ";
|
||||
|
||||
foreach ( $q as $sq ) $this->adapter->exec( $sq );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the an array describing the indexes for type $type.
|
||||
*
|
||||
* @param string $type type to describe indexes of
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getIndexes( $type )
|
||||
{
|
||||
$table = $this->esc( $type, TRUE );
|
||||
$indexes = $this->adapter->get( "PRAGMA index_list('$table')" );
|
||||
|
||||
$indexInfoList = array();
|
||||
foreach ( $indexes as $i ) {
|
||||
$indexInfoList[$i['name']] = $this->adapter->getRow( "PRAGMA index_info('{$i['name']}') " );
|
||||
|
||||
$indexInfoList[$i['name']]['unique'] = $i['unique'];
|
||||
}
|
||||
|
||||
return $indexInfoList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a foreign key to a type.
|
||||
* Note: cant put this in try-catch because that can hide the fact
|
||||
* that database has been damaged.
|
||||
*
|
||||
* @param string $type type you want to modify table of
|
||||
* @param string $targetType target type
|
||||
* @param string $field field of the type that needs to get the fk
|
||||
* @param string $targetField field where the fk needs to point to
|
||||
* @param integer $buildopt 0 = NO ACTION, 1 = ON DELETE CASCADE
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function buildFK( $type, $targetType, $property, $targetProperty, $constraint = FALSE )
|
||||
{
|
||||
$table = $this->esc( $type, TRUE );
|
||||
$targetTable = $this->esc( $targetType, TRUE );
|
||||
$column = $this->esc( $property, TRUE );
|
||||
$targetColumn = $this->esc( $targetProperty, TRUE );
|
||||
|
||||
$tables = $this->getTables();
|
||||
if ( !in_array( $targetTable, $tables ) ) return FALSE;
|
||||
|
||||
if ( !is_null( $this->getForeignKeyForTypeProperty( $table, $column ) ) ) return FALSE;
|
||||
$t = $this->getTable( $table );
|
||||
$consSQL = ( $constraint ? 'CASCADE' : 'SET NULL' );
|
||||
$label = 'from_' . $column . '_to_table_' . $targetTable . '_col_' . $targetColumn;
|
||||
$t['keys'][$label] = array(
|
||||
'table' => $targetTable,
|
||||
'from' => $column,
|
||||
'to' => $targetColumn,
|
||||
'on_update' => $consSQL,
|
||||
'on_delete' => $consSQL
|
||||
);
|
||||
$this->putTable( $t );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AQueryWriter::getKeyMapForType
|
||||
*/
|
||||
protected function getKeyMapForType( $type )
|
||||
{
|
||||
$table = $this->esc( $type, TRUE );
|
||||
$keys = $this->adapter->get( "PRAGMA foreign_key_list('$table')" );
|
||||
$keyInfoList = array();
|
||||
foreach ( $keys as $k ) {
|
||||
$label = $this->makeFKLabel( $k['from'], $k['table'], $k['to'] );
|
||||
$keyInfoList[$label] = array(
|
||||
'name' => $label,
|
||||
'from' => $k['from'],
|
||||
'table' => $k['table'],
|
||||
'to' => $k['to'],
|
||||
'on_update' => $k['on_update'],
|
||||
'on_delete' => $k['on_delete']
|
||||
);
|
||||
}
|
||||
return $keyInfoList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* Most of the time, you do not need to use this constructor,
|
||||
* since the facade takes care of constructing and wiring the
|
||||
* RedBeanPHP core objects. However if you would like to
|
||||
* assemble an OODB instance yourself, this is how it works:
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* <code>
|
||||
* $database = new RPDO( $dsn, $user, $pass );
|
||||
* $adapter = new DBAdapter( $database );
|
||||
* $writer = new PostgresWriter( $adapter );
|
||||
* $oodb = new OODB( $writer, FALSE );
|
||||
* $bean = $oodb->dispense( 'bean' );
|
||||
* $bean->name = 'coffeeBean';
|
||||
* $id = $oodb->store( $bean );
|
||||
* $bean = $oodb->load( 'bean', $id );
|
||||
* </code>
|
||||
*
|
||||
* The example above creates the 3 RedBeanPHP core objects:
|
||||
* the Adapter, the Query Writer and the OODB instance and
|
||||
* wires them together. The example also demonstrates some of
|
||||
* the methods that can be used with OODB, as you see, they
|
||||
* closely resemble their facade counterparts.
|
||||
*
|
||||
* The wiring process: create an RPDO instance using your database
|
||||
* connection parameters. Create a database adapter from the RPDO
|
||||
* object and pass that to the constructor of the writer. Next,
|
||||
* create an OODB instance from the writer. Now you have an OODB
|
||||
* object.
|
||||
*
|
||||
* @param Adapter $adapter Database Adapter
|
||||
*/
|
||||
public function __construct( Adapter $adapter )
|
||||
{
|
||||
$this->typeno_sqltype = array(
|
||||
SQLiteT::C_DATATYPE_INTEGER => 'INTEGER',
|
||||
SQLiteT::C_DATATYPE_NUMERIC => 'NUMERIC',
|
||||
SQLiteT::C_DATATYPE_TEXT => 'TEXT',
|
||||
);
|
||||
|
||||
$this->sqltype_typeno = array();
|
||||
|
||||
foreach ( $this->typeno_sqltype as $k => $v ) {
|
||||
$this->sqltype_typeno[$v] = $k;
|
||||
}
|
||||
|
||||
$this->adapter = $adapter;
|
||||
$this->adapter->setOption( 'setInitQuery', ' PRAGMA foreign_keys = 1 ' );
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the datatype to be used for primary key IDS and
|
||||
* foreign keys. Returns one if the data type constants.
|
||||
*
|
||||
* @return integer $const data type to be used for IDS.
|
||||
*/
|
||||
public function getTypeForID()
|
||||
{
|
||||
return self::C_DATATYPE_INTEGER;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::scanType
|
||||
*/
|
||||
public function scanType( $value, $flagSpecial = FALSE )
|
||||
{
|
||||
$this->svalue = $value;
|
||||
|
||||
if ( $value === NULL ) return self::C_DATATYPE_INTEGER;
|
||||
if ( $value === INF ) return self::C_DATATYPE_TEXT;
|
||||
|
||||
if ( $this->startsWithZeros( $value ) ) return self::C_DATATYPE_TEXT;
|
||||
|
||||
if ( $value === TRUE || $value === FALSE ) return self::C_DATATYPE_INTEGER;
|
||||
|
||||
if ( is_numeric( $value ) && ( intval( $value ) == $value ) && $value < 2147483648 && $value > -2147483648 ) return self::C_DATATYPE_INTEGER;
|
||||
|
||||
if ( ( is_numeric( $value ) && $value < 2147483648 && $value > -2147483648)
|
||||
|| preg_match( '/\d{4}\-\d\d\-\d\d/', $value )
|
||||
|| preg_match( '/\d{4}\-\d\d\-\d\d\s\d\d:\d\d:\d\d/', $value )
|
||||
) {
|
||||
return self::C_DATATYPE_NUMERIC;
|
||||
}
|
||||
|
||||
return self::C_DATATYPE_TEXT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addColumn
|
||||
*/
|
||||
public function addColumn( $table, $column, $type )
|
||||
{
|
||||
$column = $this->check( $column );
|
||||
$table = $this->check( $table );
|
||||
$type = $this->typeno_sqltype[$type];
|
||||
|
||||
$this->adapter->exec( sprintf( $this->getDDLTemplate( 'addColumn', $table, $column ), $table, $column, $type ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::code
|
||||
*/
|
||||
public function code( $typedescription, $includeSpecials = FALSE )
|
||||
{
|
||||
$r = ( ( isset( $this->sqltype_typeno[$typedescription] ) ) ? $this->sqltype_typeno[$typedescription] : 99 );
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::widenColumn
|
||||
*/
|
||||
public function widenColumn( $type, $column, $datatype )
|
||||
{
|
||||
$t = $this->getTable( $type );
|
||||
|
||||
$t['columns'][$column] = $this->typeno_sqltype[$datatype];
|
||||
|
||||
$this->putTable( $t );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::getTables();
|
||||
*/
|
||||
public function getTables()
|
||||
{
|
||||
return $this->adapter->getCol( "SELECT name FROM sqlite_master
|
||||
WHERE type='table' AND name!='sqlite_sequence';" );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::createTable
|
||||
*/
|
||||
public function createTable( $type )
|
||||
{
|
||||
$table = $this->esc( $type );
|
||||
|
||||
$sql = sprintf( $this->getDDLTemplate( 'createTable', $type ), $table );
|
||||
|
||||
$this->adapter->exec( $sql );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::getColumns
|
||||
*/
|
||||
public function getColumns( $table )
|
||||
{
|
||||
$table = $this->esc( $table, TRUE );
|
||||
|
||||
$columnsRaw = $this->adapter->get( "PRAGMA table_info('$table')" );
|
||||
|
||||
$columns = array();
|
||||
foreach ( $columnsRaw as $r ) $columns[$r['name']] = $r['type'];
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addUniqueIndex
|
||||
*/
|
||||
public function addUniqueConstraint( $type, $properties )
|
||||
{
|
||||
$tableNoQ = $this->esc( $type, TRUE );
|
||||
$name = 'UQ_' . $this->esc( $type, TRUE ) . implode( '__', $properties );
|
||||
$t = $this->getTable( $type );
|
||||
$t['indexes'][$name] = array( 'name' => $name );
|
||||
try {
|
||||
$this->putTable( $t );
|
||||
} catch( SQLException $e ) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::sqlStateIn
|
||||
*/
|
||||
public function sqlStateIn( $state, $list, $extraDriverDetails = array() )
|
||||
{
|
||||
$stateMap = array(
|
||||
'23000' => QueryWriter::C_SQLSTATE_INTEGRITY_CONSTRAINT_VIOLATION
|
||||
);
|
||||
if ( $state == 'HY000'
|
||||
&& isset($extraDriverDetails[1])
|
||||
&& $extraDriverDetails[1] == 1
|
||||
&& ( in_array( QueryWriter::C_SQLSTATE_NO_SUCH_TABLE, $list )
|
||||
|| in_array( QueryWriter::C_SQLSTATE_NO_SUCH_COLUMN, $list )
|
||||
)) {
|
||||
return TRUE;
|
||||
}
|
||||
return in_array( ( isset( $stateMap[$state] ) ? $stateMap[$state] : '0' ), $list );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an SQL snippet to be used for the next queryRecord() operation.
|
||||
* SQLite has no SELECT-FOR-UPDATE and filters this.
|
||||
*
|
||||
* @param string $sql SQL snippet to use in SELECT statement.
|
||||
*
|
||||
* return self
|
||||
*/
|
||||
public function setSQLSelectSnippet( $sqlSelectSnippet = '' ) {
|
||||
if ( $sqlSelectSnippet === AQueryWriter::C_SELECT_SNIPPET_FOR_UPDATE) $sqlSelectSnippet = '';
|
||||
$this->sqlSelectSnippet = $sqlSelectSnippet;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addIndex
|
||||
*/
|
||||
public function addIndex( $type, $name, $column )
|
||||
{
|
||||
$columns = $this->getColumns( $type );
|
||||
if ( !isset( $columns[$column] ) ) return FALSE;
|
||||
|
||||
$table = $this->esc( $type );
|
||||
$name = preg_replace( '/\W/', '', $name );
|
||||
$column = $this->esc( $column, TRUE );
|
||||
|
||||
try {
|
||||
$t = $this->getTable( $type );
|
||||
$t['indexes'][$name] = array( 'name' => $column );
|
||||
$this->putTable( $t );
|
||||
return TRUE;
|
||||
} catch( SQLException $exception ) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::wipe
|
||||
*/
|
||||
public function wipe( $type )
|
||||
{
|
||||
$table = $this->esc( $type );
|
||||
|
||||
$this->adapter->exec( "DELETE FROM $table " );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::addFK
|
||||
*/
|
||||
public function addFK( $type, $targetType, $property, $targetProperty, $isDep = FALSE )
|
||||
{
|
||||
return $this->buildFK( $type, $targetType, $property, $targetProperty, $isDep );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see QueryWriter::wipeAll
|
||||
*/
|
||||
public function wipeAll()
|
||||
{
|
||||
if (AQueryWriter::$noNuke) throw new \Exception('The nuke() command has been disabled using noNuke() or R::feature(novice/...).');
|
||||
$this->adapter->exec( 'PRAGMA foreign_keys = 0 ' );
|
||||
|
||||
foreach ( $this->getTables() as $t ) {
|
||||
try { $this->adapter->exec( "DROP TABLE IF EXISTS `$t`" ); } catch ( SQLException $e ) { ; }
|
||||
try { $this->adapter->exec( "DROP TABLE IF EXISTS `$t`" ); } catch ( SQLException $e ) { ; }
|
||||
}
|
||||
|
||||
$this->adapter->exec( 'PRAGMA foreign_keys = 1 ' );
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user