PK ⒨Tʌ:w w SECURITY.mdnu ٘ # ADOdb Security Policy
## Supported Versions
The following releases of the library are currently being supported with
security updates. Please refer to the [project's home page](https://adodb.org)
for actual version numbers.
- Stable
- Legacy
- Development (Git *master* branch)
Older releases are no longer supported.
## Reporting a Vulnerability
If you discover a vulnerability in ADOdb, please contact
the [project's maintainer](https://github.com/dregad)
- by e-mail (look for it in the Git history)
- via private chat on [Gitter](https://gitter.im/dregad)
Kindly provide the following information in your report:
- Affected ADOdb version(s) or Git revision
- A clear and detailed description of the issue, including if possible a code
snippet to demonstrate or reproduce the vulnerability
- A patch for the issue if you have one, preferably in *Git diff* format
### CVE handling
To ensure a comprehensive and detailed declaration of the issue, we generally
prefer requesting CVE IDs ourselves, which usually happens after our analysis
confirms the vulnerability.
In case you have already obtained a CVE ID, do not forget to reference it in
your report.
### Credits
Let us know if and how you wish to be credited for the finding.
Your name, e-mail, company, etc. will be included as specified in the CVE
report, as well as in the Git commit message patching the issue.
PK ⒨TZBo o adodb-active-record.inc.phpnu ٘ _dbat
$_ADODB_ACTIVE_DBS = array();
$ACTIVE_RECORD_SAFETY = true;
$ADODB_ACTIVE_DEFVALS = false;
$ADODB_ACTIVE_CACHESECS = 0;
class ADODB_Active_DB {
var $db; // ADOConnection
var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
}
class ADODB_Active_Table {
var $name; // table name
var $flds; // assoc array of adofieldobjs, indexed by fieldname
var $keys; // assoc array of primary keys, indexed by fieldname
var $_created; // only used when stored as a cached file
var $_belongsTo = array();
var $_hasMany = array();
}
// $db = database connection
// $index = name of index - can be associative, for an example see
// PHPLens Issue No: 17790
// returns index into $_ADODB_ACTIVE_DBS
function ADODB_SetDatabaseAdapter(&$db, $index=false)
{
global $_ADODB_ACTIVE_DBS;
foreach($_ADODB_ACTIVE_DBS as $k => $d) {
if($d->db === $db) {
return $k;
}
}
$obj = new ADODB_Active_DB();
$obj->db = $db;
$obj->tables = array();
if ($index == false) {
$index = sizeof($_ADODB_ACTIVE_DBS);
}
$_ADODB_ACTIVE_DBS[$index] = $obj;
return sizeof($_ADODB_ACTIVE_DBS)-1;
}
class ADODB_Active_Record {
static $_changeNames = true; // dynamically pluralize table names
/** @var bool|string Allows override of global $ADODB_QUOTE_FIELDNAMES */
public $_quoteNames;
static $_foreignSuffix = '_id'; //
var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
var $_table; // tablename, if set in class definition then use it as table name
var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
var $_where; // where clause set in Load()
var $_saved = false; // indicates whether data is already inserted.
var $_lasterr = false; // last error message
var $_original = false; // the original values loaded or inserted, refreshed on update
var $foreignName; // CFR: class name when in a relationship
var $lockMode = ' for update '; // you might want to change to
static function UseDefaultValues($bool=null)
{
global $ADODB_ACTIVE_DEFVALS;
if (isset($bool)) {
$ADODB_ACTIVE_DEFVALS = $bool;
}
return $ADODB_ACTIVE_DEFVALS;
}
// should be static
static function SetDatabaseAdapter(&$db, $index=false)
{
return ADODB_SetDatabaseAdapter($db, $index);
}
public function __set($name, $value)
{
$name = str_replace(' ', '_', $name);
$this->$name = $value;
}
// php5 constructor
function __construct($table = false, $pkeyarr=false, $db=false)
{
global $_ADODB_ACTIVE_DBS, $ADODB_QUOTE_FIELDNAMES;
// Set the local override for field quoting, only if not defined yet
if (!isset($this->_quoteNames)) {
$this->_quoteNames = $ADODB_QUOTE_FIELDNAMES;
}
if ($db == false && is_object($pkeyarr)) {
$db = $pkeyarr;
$pkeyarr = false;
}
if (!$table) {
if (!empty($this->_table)) {
$table = $this->_table;
}
else $table = $this->_pluralize(get_class($this));
}
$this->foreignName = strtolower(get_class($this)); // CFR: default foreign name
if ($db) {
$this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
} else if (!isset($this->_dbat)) {
if (sizeof($_ADODB_ACTIVE_DBS) == 0) {
$this->Error(
"No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",
'ADODB_Active_Record::__constructor'
);
}
end($_ADODB_ACTIVE_DBS);
$this->_dbat = key($_ADODB_ACTIVE_DBS);
}
$this->_table = $table;
$this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
$this->UpdateActiveTable($pkeyarr);
}
function __wakeup()
{
$class = get_class($this);
new $class;
}
function _pluralize($table)
{
if (!ADODB_Active_Record::$_changeNames) {
return $table;
}
$ut = strtoupper($table);
$len = strlen($table);
$lastc = $ut[$len-1];
$lastc2 = substr($ut,$len-2);
switch ($lastc) {
case 'S':
return $table.'es';
case 'Y':
return substr($table,0,$len-1).'ies';
case 'X':
return $table.'es';
case 'H':
if ($lastc2 == 'CH' || $lastc2 == 'SH') {
return $table.'es';
}
default:
return $table.'s';
}
}
// CFR Lamest singular inflector ever - @todo Make it real!
// Note: There is an assumption here...and it is that the argument's length >= 4
function _singularize($tables)
{
if (!ADODB_Active_Record::$_changeNames) {
return $table;
}
$ut = strtoupper($tables);
$len = strlen($tables);
if($ut[$len-1] != 'S') {
return $tables; // I know...forget oxen
}
if($ut[$len-2] != 'E') {
return substr($tables, 0, $len-1);
}
switch($ut[$len-3]) {
case 'S':
case 'X':
return substr($tables, 0, $len-2);
case 'I':
return substr($tables, 0, $len-3) . 'y';
case 'H';
if($ut[$len-4] == 'C' || $ut[$len-4] == 'S') {
return substr($tables, 0, $len-2);
}
default:
return substr($tables, 0, $len-1); // ?
}
}
function hasMany($foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
{
$ar = new $foreignClass($foreignRef);
$ar->foreignName = $foreignRef;
$ar->UpdateActiveTable();
$ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix;
$table =& $this->TableInfo();
$table->_hasMany[$foreignRef] = $ar;
# $this->$foreignRef = $this->_hasMany[$foreignRef]; // WATCHME Removed assignment by ref. to please __get()
}
// use when you don't want ADOdb to auto-pluralize tablename
static function TableHasMany($table, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
{
$ar = new ADODB_Active_Record($table);
$ar->hasMany($foreignRef, $foreignKey, $foreignClass);
}
// use when you don't want ADOdb to auto-pluralize tablename
static function TableKeyHasMany($table, $tablePKey, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
{
if (!is_array($tablePKey)) {
$tablePKey = array($tablePKey);
}
$ar = new ADODB_Active_Record($table,$tablePKey);
$ar->hasMany($foreignRef, $foreignKey, $foreignClass);
}
// use when you want ADOdb to auto-pluralize tablename for you. Note that the class must already be defined.
// e.g. class Person will generate relationship for table Persons
static function ClassHasMany($parentclass, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
{
$ar = new $parentclass();
$ar->hasMany($foreignRef, $foreignKey, $foreignClass);
}
function belongsTo($foreignRef,$foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
{
global $inflector;
$ar = new $parentClass($this->_pluralize($foreignRef));
$ar->foreignName = $foreignRef;
$ar->parentKey = $parentKey;
$ar->UpdateActiveTable();
$ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix;
$table =& $this->TableInfo();
$table->_belongsTo[$foreignRef] = $ar;
# $this->$foreignRef = $this->_belongsTo[$foreignRef];
}
static function ClassBelongsTo($class, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
{
$ar = new $class();
$ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
}
static function TableBelongsTo($table, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
{
$ar = new ADODB_Active_Record($table);
$ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
}
static function TableKeyBelongsTo($table, $tablePKey, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
{
if (!is_array($tablePKey)) {
$tablePKey = array($tablePKey);
}
$ar = new ADODB_Active_Record($table, $tablePKey);
$ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
}
/**
* __get Access properties - used for lazy loading
*
* @param mixed $name
* @access protected
* @return mixed
*/
function __get($name)
{
return $this->LoadRelations($name, '', -1, -1);
}
/**
* @param string $name
* @param string $whereOrderBy : eg. ' AND field1 = value ORDER BY field2'
* @param offset
* @param limit
* @return mixed
*/
function LoadRelations($name, $whereOrderBy='', $offset=-1,$limit=-1)
{
$extras = array();
$table = $this->TableInfo();
if ($limit >= 0) {
$extras['limit'] = $limit;
}
if ($offset >= 0) {
$extras['offset'] = $offset;
}
if (strlen($whereOrderBy)) {
if (!preg_match('/^[ \n\r]*AND/i', $whereOrderBy)) {
if (!preg_match('/^[ \n\r]*ORDER[ \n\r]/i', $whereOrderBy)) {
$whereOrderBy = 'AND ' . $whereOrderBy;
}
}
}
if(!empty($table->_belongsTo[$name])) {
$obj = $table->_belongsTo[$name];
$columnName = $obj->foreignKey;
if(empty($this->$columnName)) {
$this->$name = null;
}
else {
if ($obj->parentKey) {
$key = $obj->parentKey;
}
else {
$key = reset($table->keys);
}
$arrayOfOne = $obj->Find($key.'='.$this->$columnName.' '.$whereOrderBy,false,false,$extras);
if ($arrayOfOne) {
$this->$name = $arrayOfOne[0];
return $arrayOfOne[0];
}
}
}
if(!empty($table->_hasMany[$name])) {
$obj = $table->_hasMany[$name];
$key = reset($table->keys);
$id = @$this->$key;
if (!is_numeric($id)) {
$db = $this->DB();
$id = $db->qstr($id);
}
$objs = $obj->Find($obj->foreignKey.'='.$id. ' '.$whereOrderBy,false,false,$extras);
if (!$objs) {
$objs = array();
}
$this->$name = $objs;
return $objs;
}
return array();
}
//////////////////////////////////
// update metadata
function UpdateActiveTable($pkeys=false,$forceUpdate=false)
{
global $_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
global $ADODB_ACTIVE_DEFVALS,$ADODB_FETCH_MODE;
$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
$table = $this->_table;
$tables = $activedb->tables;
$tableat = $this->_tableat;
if (!$forceUpdate && !empty($tables[$tableat])) {
$acttab = $tables[$tableat];
foreach($acttab->flds as $name => $fld) {
if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) {
$this->$name = $fld->default_value;
}
else {
$this->$name = null;
}
}
return;
}
$db = $activedb->db;
$fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
$fp = fopen($fname,'r');
@flock($fp, LOCK_SH);
$acttab = unserialize(fread($fp,100000));
fclose($fp);
if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) {
// abs(rand()) randomizes deletion, reducing contention to delete/refresh file
// ideally, you should cache at least 32 secs
foreach($acttab->flds as $name => $fld) {
if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) {
$this->$name = $fld->default_value;
}
else {
$this->$name = null;
}
}
$activedb->tables[$table] = $acttab;
//if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
return;
} else if ($db->debug) {
ADOConnection::outp("Refreshing cached active record file: $fname");
}
}
$activetab = new ADODB_Active_Table();
$activetab->name = $table;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
if ($db->fetchMode !== false) {
$savem = $db->SetFetchMode(false);
}
$cols = $db->MetaColumns($table);
if (isset($savem)) {
$db->SetFetchMode($savem);
}
$ADODB_FETCH_MODE = $save;
if (!$cols) {
$this->Error("Invalid table name: $table",'UpdateActiveTable');
return false;
}
$fld = reset($cols);
if (!$pkeys) {
if (isset($fld->primary_key)) {
$pkeys = array();
foreach($cols as $name => $fld) {
if (!empty($fld->primary_key)) {
$pkeys[] = $name;
}
}
} else
$pkeys = $this->GetPrimaryKeys($db, $table);
}
if (empty($pkeys)) {
$this->Error("No primary key found for table $table",'UpdateActiveTable');
return false;
}
$attr = array();
$keys = array();
switch (ADODB_ASSOC_CASE) {
case ADODB_ASSOC_CASE_LOWER:
foreach($cols as $name => $fldobj) {
$name = strtolower($name);
if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
$this->$name = $fldobj->default_value;
}
else {
$this->$name = null;
}
$attr[$name] = $fldobj;
}
foreach($pkeys as $k => $name) {
$keys[strtolower($name)] = strtolower($name);
}
break;
case ADODB_ASSOC_CASE_UPPER:
foreach($cols as $name => $fldobj) {
$name = strtoupper($name);
if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
$this->$name = $fldobj->default_value;
}
else {
$this->$name = null;
}
$attr[$name] = $fldobj;
}
foreach($pkeys as $k => $name) {
$keys[strtoupper($name)] = strtoupper($name);
}
break;
default:
foreach($cols as $name => $fldobj) {
if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
$this->$name = $fldobj->default_value;
}
else {
$this->$name = null;
}
$attr[$name] = $fldobj;
}
foreach($pkeys as $k => $name) {
$keys[$name] = $cols[strtoupper($name)]->name;
}
break;
}
$activetab->keys = $keys;
$activetab->flds = $attr;
if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
$activetab->_created = time();
$s = serialize($activetab);
if (!function_exists('adodb_write_file')) {
include_once(ADODB_DIR.'/adodb-csvlib.inc.php');
}
adodb_write_file($fname,$s);
}
if (isset($activedb->tables[$table])) {
$oldtab = $activedb->tables[$table];
if ($oldtab) {
$activetab->_belongsTo = $oldtab->_belongsTo;
$activetab->_hasMany = $oldtab->_hasMany;
}
}
$activedb->tables[$table] = $activetab;
}
function GetPrimaryKeys(&$db, $table)
{
return $db->MetaPrimaryKeys($table);
}
// error handler for both PHP4+5.
function Error($err,$fn)
{
global $_ADODB_ACTIVE_DBS;
$fn = get_class($this).'::'.$fn;
$this->_lasterr = $fn.': '.$err;
if ($this->_dbat < 0) {
$db = false;
}
else {
$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
$db = $activedb->db;
}
if (function_exists('adodb_throw')) {
if (!$db) {
adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
}
else {
adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
}
} else {
if (!$db || $db->debug) {
ADOConnection::outp($this->_lasterr);
}
}
}
// return last error message
function ErrorMsg()
{
if (!function_exists('adodb_throw')) {
if ($this->_dbat < 0) {
$db = false;
}
else {
$db = $this->DB();
}
// last error could be database error too
if ($db && $db->ErrorMsg()) {
return $db->ErrorMsg();
}
}
return $this->_lasterr;
}
function ErrorNo()
{
if ($this->_dbat < 0) {
return -9999; // no database connection...
}
$db = $this->DB();
return (int) $db->ErrorNo();
}
// retrieve ADOConnection from _ADODB_Active_DBs
function DB()
{
global $_ADODB_ACTIVE_DBS;
if ($this->_dbat < 0) {
$false = false;
$this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
return $false;
}
$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
$db = $activedb->db;
return $db;
}
// retrieve ADODB_Active_Table
function &TableInfo()
{
global $_ADODB_ACTIVE_DBS;
$activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
$table = $activedb->tables[$this->_tableat];
return $table;
}
// I have an ON INSERT trigger on a table that sets other columns in the table.
// So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook
function Reload()
{
$db = $this->DB();
if (!$db) {
return false;
}
$table = $this->TableInfo();
$where = $this->GenWhere($db, $table);
return($this->Load($where));
}
// set a numeric array (using natural table field ordering) as object properties
function Set(&$row)
{
global $ACTIVE_RECORD_SAFETY;
$db = $this->DB();
if (!$row) {
$this->_saved = false;
return false;
}
$this->_saved = true;
$table = $this->TableInfo();
if ($ACTIVE_RECORD_SAFETY && sizeof($table->flds) != sizeof($row)) {
#
$bad_size = TRUE;
if (sizeof($row) == 2 * sizeof($table->flds)) {
// Only keep string keys
$keys = array_filter(array_keys($row), 'is_string');
if (sizeof($keys) == sizeof($table->flds)) {
$bad_size = FALSE;
}
}
if ($bad_size) {
$this->Error("Table structure of $this->_table has changed","Load");
return false;
}
#
}
else
$keys = array_keys($row);
#
reset($keys);
$this->_original = array();
foreach($table->flds as $name=>$fld) {
$value = $row[current($keys)];
$this->$name = $value;
$this->_original[] = $value;
next($keys);
}
#
return true;
}
// get last inserted id for INSERT
function LastInsertID(&$db,$fieldname)
{
if ($db->hasInsertID) {
$val = $db->Insert_ID($this->_table,$fieldname);
}
else {
$val = false;
}
if (is_null($val) || $val === false)
{
$SQL = sprintf("SELECT MAX(%s) FROM %s",
$this->nameQuoter($db,$fieldname),
$this->nameQuoter($db,$this->_table)
);
// this might not work reliably in multi-user environment
return $db->GetOne($SQL);
}
return $val;
}
// quote data in where clause
function doquote(&$db, $val,$t)
{
switch($t) {
case 'L':
if (strpos($db->databaseType,'postgres') !== false) {
return $db->qstr($val);
}
case 'D':
case 'T':
if (empty($val)) {
return 'null';
}
case 'B':
case 'N':
case 'C':
case 'X':
if (is_null($val)) {
return 'null';
}
if (strlen($val)>0 &&
(strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")
) {
return $db->qstr($val);
break;
}
default:
return $val;
break;
}
}
// generate where clause for an UPDATE/SELECT
function GenWhere(&$db, &$table)
{
$keys = $table->keys;
$parr = array();
foreach($keys as $k) {
$f = $table->flds[$k];
if ($f) {
$columnName = $this->nameQuoter($db,$k);
$parr[] = $columnName.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
}
}
return implode(' AND ', $parr);
}
function _QName($n,$db=false)
{
if (!ADODB_Active_Record::$_quoteNames) {
return $n;
}
if (!$db) {
$db = $this->DB();
if (!$db) {
return false;
}
}
return $db->nameQuote.$n.$db->nameQuote;
}
//------------------------------------------------------------ Public functions below
function Load($where=null,$bindarr=false, $lock = false)
{
global $ADODB_FETCH_MODE;
$db = $this->DB();
if (!$db) {
return false;
}
$this->_where = $where;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
if ($db->fetchMode !== false) {
$savem = $db->SetFetchMode(false);
}
$qry = sprintf("SELECT * FROM %s",
$this->nameQuoter($db,$this->_table)
);
if($where) {
$qry .= ' WHERE '.$where;
}
if ($lock) {
$qry .= $this->lockMode;
}
$row = $db->GetRow($qry,$bindarr);
if (isset($savem)) {
$db->SetFetchMode($savem);
}
$ADODB_FETCH_MODE = $save;
return $this->Set($row);
}
function LoadLocked($where=null, $bindarr=false)
{
$this->Load($where,$bindarr,true);
}
# useful for multiple record inserts
# see PHPLens Issue No: 17795
function Reset()
{
$this->_where=null;
$this->_saved = false;
$this->_lasterr = false;
$this->_original = false;
$vars=get_object_vars($this);
foreach($vars as $k=>$v){
if(substr($k,0,1)!=='_'){
$this->{$k}=null;
}
}
$this->foreignName=strtolower(get_class($this));
return true;
}
// false on error
function Save()
{
if ($this->_saved) {
$ok = $this->Update();
}
else {
$ok = $this->Insert();
}
return $ok;
}
// false on error
function Insert()
{
$db = $this->DB();
if (!$db) {
return false;
}
$cnt = 0;
$table = $this->TableInfo();
$valarr = array();
$names = array();
$valstr = array();
foreach($table->flds as $name=>$fld) {
$val = $this->$name;
if(!is_array($val) || !is_null($val) || !array_key_exists($name, $table->keys)) {
$valarr[] = $val;
$names[] = $this->nameQuoter($db,$name);
$valstr[] = $db->Param($cnt);
$cnt += 1;
}
}
if (empty($names)){
foreach($table->flds as $name=>$fld) {
$valarr[] = null;
$names[] = $this->nameQuoter($db,$name);
$valstr[] = $db->Param($cnt);
$cnt += 1;
}
}
$tableName = $this->nameQuoter($db,$this->_table);
$sql = sprintf('INSERT INTO %s (%s) VALUES (%s)',
$tableName,
implode(',',$names),
implode(',',$valstr)
);
$ok = $db->Execute($sql,$valarr);
if ($ok) {
$this->_saved = true;
$autoinc = false;
foreach($table->keys as $k) {
if (is_null($this->$k)) {
$autoinc = true;
break;
}
}
if ($autoinc && sizeof($table->keys) == 1) {
$k = reset($table->keys);
$this->$k = $this->LastInsertID($db,$k);
}
}
$this->_original = $valarr;
return !empty($ok);
}
function Delete()
{
$db = $this->DB();
if (!$db) {
return false;
}
$table = $this->TableInfo();
$where = $this->GenWhere($db,$table);
$tableName = $this->nameQuoter($db,$this->_table);
$sql = sprintf('DELETE FROM %s WHERE %s',
$tableName,
$where
);
$ok = $db->Execute($sql);
return $ok ? true : false;
}
// returns an array of active record objects
function Find($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
{
$db = $this->DB();
if (!$db || empty($this->_table)) {
return false;
}
$arr = $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr,$extra);
return $arr;
}
// returns 0 on error, 1 on update, 2 on insert
function Replace()
{
$db = $this->DB();
if (!$db) {
return false;
}
$table = $this->TableInfo();
$pkey = $table->keys;
foreach($table->flds as $name=>$fld) {
$val = $this->$name;
/*
if (is_null($val)) {
if (isset($fld->not_null) && $fld->not_null) {
if (isset($fld->default_value) && strlen($fld->default_value)) {
continue;
}
else {
$this->Error("Cannot update null into $name","Replace");
return false;
}
}
}*/
if (is_null($val) && !empty($fld->auto_increment)) {
continue;
}
if (is_array($val)) {
continue;
}
$t = $db->MetaType($fld->type);
$arr[$name] = $this->doquote($db,$val,$t);
$valarr[] = $val;
}
if (!is_array($pkey)) {
$pkey = array($pkey);
}
switch (ADODB_ASSOC_CASE) {
case ADODB_ASSOC_CASE_LOWER:
foreach ($pkey as $k => $v) {
$pkey[$k] = strtolower($v);
}
break;
case ADODB_ASSOC_CASE_UPPER:
foreach ($pkey as $k => $v) {
$pkey[$k] = strtoupper($v);
}
break;
}
$newArr = array();
foreach($arr as $k=>$v)
$newArr[$this->nameQuoter($db,$k)] = $v;
$arr = $newArr;
$newPkey = array();
foreach($pkey as $k=>$v)
$newPkey[$k] = $this->nameQuoter($db,$v);
$pkey = $newPkey;
$tableName = $this->nameQuoter($db,$this->_table);
$ok = $db->Replace($tableName,$arr,$pkey);
if ($ok) {
$this->_saved = true; // 1= update 2=insert
if ($ok == 2) {
$autoinc = false;
foreach($table->keys as $k) {
if (is_null($this->$k)) {
$autoinc = true;
break;
}
}
if ($autoinc && sizeof($table->keys) == 1) {
$k = reset($table->keys);
$this->$k = $this->LastInsertID($db,$k);
}
}
$this->_original = $valarr;
}
return $ok;
}
// returns 0 on error, 1 on update, -1 if no change in data (no update)
function Update()
{
$db = $this->DB();
if (!$db) {
return false;
}
$table = $this->TableInfo();
$where = $this->GenWhere($db, $table);
if (!$where) {
$this->error("Where missing for table $table", "Update");
return false;
}
$valarr = array();
$neworig = array();
$pairs = array();
$i = -1;
$cnt = 0;
foreach($table->flds as $name=>$fld) {
$i += 1;
$val = $this->$name;
$neworig[] = $val;
if (isset($table->keys[$name]) || is_array($val)) {
continue;
}
if (is_null($val)) {
if (isset($fld->not_null) && $fld->not_null) {
if (isset($fld->default_value) && strlen($fld->default_value)) {
continue;
}
else {
$this->Error("Cannot set field $name to NULL","Update");
return false;
}
}
}
if (isset($this->_original[$i]) && strcmp($val,$this->_original[$i]) == 0) {
continue;
}
if (is_null($this->_original[$i]) && is_null($val)) {
continue;
}
$valarr[] = $val;
$pairs[] = $this->nameQuoter($db,$name).'='.$db->Param($cnt);
$cnt += 1;
}
if (!$cnt) {
return -1;
}
$tableName = $this->nameQuoter($db,$this->_table);
$sql = sprintf('UPDATE %s SET %s WHERE %s',
$tableName,
implode(',',$pairs),
$where);
$ok = $db->Execute($sql,$valarr);
if ($ok) {
$this->_original = $neworig;
return 1;
}
return 0;
}
function GetAttributeNames()
{
$table = $this->TableInfo();
if (!$table) {
return false;
}
return array_keys($table->flds);
}
/**
* Quotes the table, column and field names.
*
* This honours the internal {@see $_quoteNames} property, which overrides
* the global $ADODB_QUOTE_FIELDNAMES directive.
*
* @param ADOConnection $db The database connection
* @param string $name The table or column name to quote
*
* @return string The quoted name
*/
private function nameQuoter($db, $name)
{
global $ADODB_QUOTE_FIELDNAMES;
$save = $ADODB_QUOTE_FIELDNAMES;
$ADODB_QUOTE_FIELDNAMES = $this->_quoteNames;
$string = _adodb_quote_fieldname($db, $name);
$ADODB_QUOTE_FIELDNAMES = $save;
return $string;
}
};
function adodb_GetActiveRecordsClass(&$db, $class, $table,$whereOrderBy,$bindarr, $primkeyArr,
$extra)
{
global $_ADODB_ACTIVE_DBS;
$save = $db->SetFetchMode(ADODB_FETCH_NUM);
$qry = "select * from ".$table;
if (!empty($whereOrderBy)) {
$qry .= ' WHERE '.$whereOrderBy;
}
if(isset($extra['limit'])) {
$rows = false;
if(isset($extra['offset'])) {
$rs = $db->SelectLimit($qry, $extra['limit'], $extra['offset'],$bindarr);
} else {
$rs = $db->SelectLimit($qry, $extra['limit'],-1,$bindarr);
}
if ($rs) {
while (!$rs->EOF) {
$rows[] = $rs->fields;
$rs->MoveNext();
}
}
} else
$rows = $db->GetAll($qry,$bindarr);
$db->SetFetchMode($save);
$false = false;
if ($rows === false) {
return $false;
}
if (!class_exists($class)) {
$db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
return $false;
}
$arr = array();
// arrRef will be the structure that knows about our objects.
// It is an associative array.
// We will, however, return arr, preserving regular 0.. order so that
// obj[0] can be used by app developers.
$arrRef = array();
$bTos = array(); // Will store belongTo's indices if any
foreach($rows as $row) {
$obj = new $class($table,$primkeyArr,$db);
if ($obj->ErrorNo()){
$db->_errorMsg = $obj->ErrorMsg();
return $false;
}
$obj->Set($row);
$arr[] = $obj;
} // foreach($rows as $row)
return $arr;
}
PK ⒨Tu)` ` perf/perf-oci8.inc.phpnu ٘ array('RATIOH',
"select round((1-(phy.value / (cur.value + con.value)))*100,2)
from v\$sysstat cur, v\$sysstat con, v\$sysstat phy
where cur.name = 'db block gets' and
con.name = 'consistent gets' and
phy.name = 'physical reads'",
'=WarnCacheRatio'),
'sql cache hit ratio' => array( 'RATIOH',
'select round(100*(sum(pins)-sum(reloads))/sum(pins),2) from v$librarycache',
'increase shared_pool_size if too ratio low'),
'datadict cache hit ratio' => array('RATIOH',
"select
round((1 - (sum(getmisses) / (sum(gets) +
sum(getmisses))))*100,2)
from v\$rowcache",
'increase shared_pool_size if too ratio low'),
'memory sort ratio' => array('RATIOH',
"SELECT ROUND((100 * b.VALUE) /DECODE ((a.VALUE + b.VALUE),
0,1,(a.VALUE + b.VALUE)),2)
FROM v\$sysstat a,
v\$sysstat b
WHERE a.name = 'sorts (disk)'
AND b.name = 'sorts (memory)'",
"% of memory sorts compared to disk sorts - should be over 95%"),
'IO',
'data reads' => array('IO',
"select value from v\$sysstat where name='physical reads'"),
'data writes' => array('IO',
"select value from v\$sysstat where name='physical writes'"),
'Data Cache',
'data cache buffers' => array( 'DATAC',
"select a.value/b.value from v\$parameter a, v\$parameter b
where a.name = 'db_cache_size' and b.name= 'db_block_size'",
'Number of cache buffers. Tune db_cache_size if the data cache hit ratio is too low.'),
'data cache blocksize' => array('DATAC',
"select value from v\$parameter where name='db_block_size'",
'' ),
'Memory Pools',
'Mem Max Target (11g+)' => array( 'DATAC',
"select value from v\$parameter where name = 'memory_max_target'",
'The memory_max_size is the maximum value to which memory_target can be set.' ),
'Memory target (11g+)' => array( 'DATAC',
"select value from v\$parameter where name = 'memory_target'",
'If memory_target is defined then SGA and PGA targets are consolidated into one memory_target.' ),
'SGA Max Size' => array( 'DATAC',
"select nvl(value,0)/1024.0/1024 || 'M' from v\$parameter where name = 'sga_max_size'",
'The sga_max_size is the maximum value to which sga_target can be set.' ),
'SGA target' => array( 'DATAC',
"select nvl(value,0)/1024.0/1024 || 'M' from v\$parameter where name = 'sga_target'",
'If sga_target is defined then data cache, shared, java and large pool size can be 0. This is because all these pools are consolidated into one sga_target.' ),
'PGA aggr target' => array( 'DATAC',
"select nvl(value,0)/1024.0/1024 || 'M' from v\$parameter where name = 'pga_aggregate_target'",
'If pga_aggregate_target is defined then this is the maximum memory that can be allocated for cursor operations such as sorts, group by, joins, merges. When in doubt, set it to 20% of sga_target.' ),
'data cache size' => array('DATAC',
"select value from v\$parameter where name = 'db_cache_size'",
'db_cache_size' ),
'shared pool size' => array('DATAC',
"select value from v\$parameter where name = 'shared_pool_size'",
'shared_pool_size, which holds shared sql, stored procedures, dict cache and similar shared structs' ),
'java pool size' => array('DATAJ',
"select value from v\$parameter where name = 'java_pool_size'",
'java_pool_size' ),
'large pool buffer size' => array('CACHE',
"select value from v\$parameter where name='large_pool_size'",
'this pool is for large mem allocations (not because it is larger than shared pool), for MTS sessions, parallel queries, io buffers (large_pool_size) ' ),
'dynamic memory usage' => array('CACHE', "select '-' from dual", '=DynMemoryUsage'),
'Connections',
'current connections' => array('SESS',
'select count(*) from sys.v_$session where username is not null',
''),
'max connections' => array( 'SESS',
"select value from v\$parameter where name='sessions'",
''),
'Memory Utilization',
'data cache utilization ratio' => array('RATIOU',
"select round((1-bytes/sgasize)*100, 2)
from (select sum(bytes) sgasize from sys.v_\$sgastat) s, sys.v_\$sgastat f
where name = 'free memory' and pool = 'shared pool'",
'Percentage of data cache actually in use - should be over 85%'),
'shared pool utilization ratio' => array('RATIOU',
'select round((sga.bytes/case when p.value=0 then sga.bytes else to_number(p.value) end)*100,2)
from v$sgastat sga, v$parameter p
where sga.name = \'free memory\' and sga.pool = \'shared pool\'
and p.name = \'shared_pool_size\'',
'Percentage of shared pool actually used - too low is bad, too high is worse'),
'large pool utilization ratio' => array('RATIOU',
"select round((1-bytes/sgasize)*100, 2)
from (select sum(bytes) sgasize from sys.v_\$sgastat) s, sys.v_\$sgastat f
where name = 'free memory' and pool = 'large pool'",
'Percentage of large_pool actually in use - too low is bad, too high is worse'),
'sort buffer size' => array('CACHE',
"select value from v\$parameter where name='sort_area_size'",
'max in-mem sort_area_size (per query), uses memory in pga' ),
/*'pga usage at peak' => array('RATIOU',
'=PGA','Mb utilization at peak transactions (requires Oracle 9i+)'),*/
'Transactions',
'rollback segments' => array('ROLLBACK',
"select count(*) from sys.v_\$rollstat",
''),
'peak transactions' => array('ROLLBACK',
"select max_utilization tx_hwm
from sys.v_\$resource_limit
where resource_name = 'transactions'",
'Taken from high-water-mark'),
'max transactions' => array('ROLLBACK',
"select value from v\$parameter where name = 'transactions'",
'max transactions / rollback segments < 3.5 (or transactions_per_rollback_segment)'),
'Parameters',
'cursor sharing' => array('CURSOR',
"select value from v\$parameter where name = 'cursor_sharing'",
'Cursor reuse strategy. Recommended is FORCE (8i+) or SIMILAR (9i+). See cursor_sharing.'),
/*
'cursor reuse' => array('CURSOR',
"select count(*) from (select sql_text_wo_constants, count(*)
from t1
group by sql_text_wo_constants
having count(*) > 100)",'These are sql statements that should be using bind variables'),*/
'index cache cost' => array('COST',
"select value from v\$parameter where name = 'optimizer_index_caching'",
'=WarnIndexCost'),
'random page cost' => array('COST',
"select value from v\$parameter where name = 'optimizer_index_cost_adj'",
'=WarnPageCost'),
'Waits',
'Recent wait events' => array('WAITS','select \'Top 5 events\' from dual','=TopRecentWaits'),
// 'Historical wait SQL' => array('WAITS','select \'Last 2 days\' from dual','=TopHistoricalWaits'), -- requires AWR license
'Backup',
'Achivelog Mode' => array('BACKUP', 'select log_mode from v$database', '=LogMode'),
'DBID' => array('BACKUP','select dbid from v$database','Primary key of database, used for recovery with an RMAN Recovery Catalog'),
'Archive Log Dest' => array('BACKUP', "SELECT NVL(v1.value,v2.value)
FROM v\$parameter v1, v\$parameter v2 WHERE v1.name='log_archive_dest' AND v2.name='log_archive_dest_10'", ''),
'Flashback Area' => array('BACKUP', "select nvl(value,'Flashback Area not used') from v\$parameter where name=lower('DB_RECOVERY_FILE_DEST')", 'Flashback area is a folder where all backup data and logs can be stored and managed by Oracle. If Error: message displayed, then it is not in use.'),
'Flashback Usage' => array('BACKUP', "select nvl('-','Flashback Area not used') from v\$parameter where name=lower('DB_RECOVERY_FILE_DEST')", '=FlashUsage', 'Flashback area usage.'),
'Control File Keep Time' => array('BACKUP', "select value from v\$parameter where name='control_file_record_keep_time'",'No of days to keep RMAN info in control file. Recommended set to x2 or x3 times the frequency of your full backup.'),
'Recent RMAN Jobs' => array('BACKUP', "select '-' from dual", "=RMAN"),
// 'Control File Keep Time' => array('BACKUP', "select value from v\$parameter where name='control_file_record_keep_time'",'No of days to keep RMAN info in control file. I recommend it be set to x2 or x3 times the frequency of your full backup.'),
'Storage', 'Tablespaces' => array('TABLESPACE', "select '-' from dual", "=TableSpace"),
false
);
function __construct(&$conn)
{
global $gSQLBlockRows;
$gSQLBlockRows = 1000;
$savelog = $conn->LogSQL(false);
$this->version = $conn->ServerInfo();
$conn->LogSQL($savelog);
$this->conn = $conn;
}
function LogMode()
{
$mode = $this->conn->GetOne("select log_mode from v\$database");
if ($mode == 'ARCHIVELOG') return 'To turn off archivelog:
SQLPLUS> connect sys as sysdba;
SQLPLUS> shutdown immediate;
SQLPLUS> startup mount exclusive;
SQLPLUS> alter database noarchivelog;
SQLPLUS> alter database open;
';
return 'To turn on archivelog:
SQLPLUS> connect sys as sysdba;
SQLPLUS> shutdown immediate;
SQLPLUS> startup mount exclusive;
SQLPLUS> alter database archivelog;
SQLPLUS> archive log start;
SQLPLUS> alter database open;
';
}
function TopRecentWaits()
{
$rs = $this->conn->Execute("select * from (
select event, round(100*time_waited/(select sum(time_waited) from v\$system_event where wait_class <> 'Idle'),1) \"% Wait\",
total_waits,time_waited, average_wait,wait_class from v\$system_event where wait_class <> 'Idle' order by 2 desc
) where rownum <=5");
$ret = rs2html($rs,false,false,false,false);
return " ".$ret."
";
}
function TopHistoricalWaits()
{
$days = 2;
$rs = $this->conn->Execute("select * from ( SELECT
b.wait_class,B.NAME,
round(sum(wait_time+TIME_WAITED)/1000000) waitsecs,
parsing_schema_name,
C.SQL_TEXT, a.sql_id
FROM V\$ACTIVE_SESSION_HISTORY A
join V\$EVENT_NAME B on A.EVENT# = B.EVENT#
join V\$SQLAREA C on A.SQL_ID = C.SQL_ID
WHERE A.SAMPLE_TIME BETWEEN sysdate-$days and sysdate
and parsing_schema_name not in ('SYS','SYSMAN','DBSNMP','SYSTEM')
GROUP BY b.wait_class,parsing_schema_name,C.SQL_TEXT, B.NAME,A.sql_id
order by 3 desc) where rownum <=10");
$ret = rs2html($rs,false,false,false,false);
return " ".$ret."
";
}
function TableSpace()
{
$rs = $this->conn->Execute(
"select tablespace_name,round(sum(bytes)/1024/1024) as Used_MB,round(sum(maxbytes)/1024/1024) as Max_MB, round(sum(bytes)/sum(maxbytes),4) * 100 as PCT
from dba_data_files
group by tablespace_name order by 2 desc");
$ret = "Tablespace".rs2html($rs,false,false,false,false);
$rs = $this->conn->Execute("select * from dba_data_files order by tablespace_name, 1");
$ret .= "
Datafile".rs2html($rs,false,false,false,false);
return "
".$ret."
";
}
function RMAN()
{
$rs = $this->conn->Execute("select * from (select start_time, end_time, operation, status, mbytes_processed, output_device_type
from V\$RMAN_STATUS order by start_time desc) where rownum <=10");
$ret = rs2html($rs,false,false,false,false);
return " ".$ret."
";
}
function DynMemoryUsage()
{
if (@$this->version['version'] >= 11) {
$rs = $this->conn->Execute("select component, current_size/1024./1024 as \"CurrSize (M)\" from V\$MEMORY_DYNAMIC_COMPONENTS");
} else
$rs = $this->conn->Execute("select name, round(bytes/1024./1024,2) as \"CurrSize (M)\" from V\$sgainfo");
$ret = rs2html($rs,false,false,false,false);
return " ".$ret."
";
}
function FlashUsage()
{
$rs = $this->conn->Execute("select * from V\$FLASH_RECOVERY_AREA_USAGE");
$ret = rs2html($rs,false,false,false,false);
return " ".$ret."
";
}
function WarnPageCost($val)
{
if ($val == 100 && $this->version['version'] < 10) $s = 'Too High. ';
else $s = '';
return $s.'Recommended is 20-50 for TP, and 50 for data warehouses. Default is 100. See optimizer_index_cost_adj. ';
}
function WarnIndexCost($val)
{
if ($val == 0 && $this->version['version'] < 10) $s = 'Too Low. ';
else $s = '';
return $s.'Percentage of indexed data blocks expected in the cache.
Recommended is 20 (fast disk array) to 30 (slower hard disks). Default is 0.
See optimizer_index_caching.';
}
function PGA()
{
//if ($this->version['version'] < 9) return 'Oracle 9i or later required';
}
function PGA_Advice()
{
$t = "PGA Advice Estimate
";
if ($this->version['version'] < 9) return $t.'Oracle 9i or later required';
$rs = $this->conn->Execute('select a.MB,
case when a.targ = 1 then \'<<= Current \'
when a.targ < 1 or a.pct <= b.pct then null
else
\'- BETTER than Current by \'||round(a.pct/b.pct*100-100,2)||\'%\' end as "Percent Improved",
a.targ as "PGA Size Factor",a.pct "% Perf"
from
(select round(pga_target_for_estimate/1024.0/1024.0,0) MB,
pga_target_factor targ,estd_pga_cache_hit_percentage pct,rownum as r
from v$pga_target_advice) a left join
(select round(pga_target_for_estimate/1024.0/1024.0,0) MB,
pga_target_factor targ,estd_pga_cache_hit_percentage pct,rownum as r
from v$pga_target_advice) b on
a.r = b.r+1 where
b.pct < 100');
if (!$rs) return $t."Only in 9i or later";
// $rs->Close();
if ($rs->EOF) return $t."PGA could be too big";
return $t.rs2html($rs,false,false,true,false);
}
function Explain($sql,$partial=false)
{
$savelog = $this->conn->LogSQL(false);
$rs = $this->conn->SelectLimit("select ID FROM PLAN_TABLE");
if (!$rs) {
echo "Missing PLAN_TABLE
CREATE TABLE PLAN_TABLE (
STATEMENT_ID VARCHAR2(30),
TIMESTAMP DATE,
REMARKS VARCHAR2(80),
OPERATION VARCHAR2(30),
OPTIONS VARCHAR2(30),
OBJECT_NODE VARCHAR2(128),
OBJECT_OWNER VARCHAR2(30),
OBJECT_NAME VARCHAR2(30),
OBJECT_INSTANCE NUMBER(38),
OBJECT_TYPE VARCHAR2(30),
OPTIMIZER VARCHAR2(255),
SEARCH_COLUMNS NUMBER,
ID NUMBER(38),
PARENT_ID NUMBER(38),
POSITION NUMBER(38),
COST NUMBER(38),
CARDINALITY NUMBER(38),
BYTES NUMBER(38),
OTHER_TAG VARCHAR2(255),
PARTITION_START VARCHAR2(255),
PARTITION_STOP VARCHAR2(255),
PARTITION_ID NUMBER(38),
OTHER LONG,
DISTRIBUTION VARCHAR2(30)
);
";
return false;
}
$rs->Close();
// $this->conn->debug=1;
if ($partial) {
$sqlq = $this->conn->qstr($sql.'%');
$arr = $this->conn->GetArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq");
if ($arr) {
foreach($arr as $row) {
$sql = reset($row);
if (crc32($sql) == $partial) break;
}
}
}
$s = "Explain: ".htmlspecialchars($sql)."
";
$this->conn->BeginTrans();
$id = "ADODB ".microtime();
$rs = $this->conn->Execute("EXPLAIN PLAN SET STATEMENT_ID='$id' FOR $sql");
$m = $this->conn->ErrorMsg();
if ($m) {
$this->conn->RollbackTrans();
$this->conn->LogSQL($savelog);
$s .= "$m
";
return $s;
}
$rs = $this->conn->Execute("
select
''||lpad('--', (level-1)*2,'-') || trim(operation) || ' ' || trim(options)||'
' as Operation,
object_name,COST,CARDINALITY,bytes
FROM plan_table
START WITH id = 0 and STATEMENT_ID='$id'
CONNECT BY prior id=parent_id and statement_id='$id'");
$s .= rs2html($rs,false,false,false,false);
$this->conn->RollbackTrans();
$this->conn->LogSQL($savelog);
$s .= $this->Tracer($sql,$partial);
return $s;
}
function CheckMemory()
{
if ($this->version['version'] < 9) return 'Oracle 9i or later required';
$rs = $this->conn->Execute("
select a.name Buffer_Pool, b.size_for_estimate as cache_mb_estimate,
case when b.size_factor=1 then
'<<= Current'
when a.estd_physical_read_factor-b.estd_physical_read_factor > 0.001 and b.estd_physical_read_factor<1 then
'- BETTER than current by ' || round((1-b.estd_physical_read_factor)/b.estd_physical_read_factor*100,2) || '%'
else ' ' end as RATING,
b.estd_physical_read_factor \"Phys. Reads Factor\",
round((a.estd_physical_read_factor-b.estd_physical_read_factor)/b.estd_physical_read_factor*100,2) as \"% Improve\"
from (select size_for_estimate,size_factor,estd_physical_read_factor,rownum r,name from v\$db_cache_advice order by name,1) a ,
(select size_for_estimate,size_factor,estd_physical_read_factor,rownum r,name from v\$db_cache_advice order by name,1) b
where a.r = b.r-1 and a.name = b.name
");
if (!$rs) return false;
/*
The v$db_cache_advice utility show the marginal changes in physical data block reads for different sizes of db_cache_size
*/
$s = "Data Cache Advice Estimate
";
if ($rs->EOF) {
$s .= "Cache that is 50% of current size is still too big
";
} else {
$s .= "Ideal size of Data Cache is when %BETTER gets close to zero.";
$s .= rs2html($rs,false,false,false,false);
}
return $s.$this->PGA_Advice();
}
/*
Generate html for suspicious/expensive sql
*/
function tohtml(&$rs,$type)
{
$o1 = $rs->FetchField(0);
$o2 = $rs->FetchField(1);
$o3 = $rs->FetchField(2);
if ($rs->EOF) return 'None found
';
$check = '';
$sql = '';
$s = "\n\n".$o1->name.' | '.$o2->name.' | '.$o3->name.' |
';
while (!$rs->EOF) {
if ($check != $rs->fields[0].'::'.$rs->fields[1]) {
if ($check) {
$carr = explode('::',$check);
$prefix = "';
$suffix = '';
if (strlen($prefix)>2000) {
$prefix = '';
$suffix = '';
}
$s .= "\n".$carr[0].' | '.$carr[1].' | '.$prefix.$sql.$suffix.' |
';
}
$sql = $rs->fields[2];
$check = $rs->fields[0].'::'.$rs->fields[1];
} else
$sql .= $rs->fields[2];
if (substr($sql,strlen($sql)-1) == "\0") $sql = substr($sql,0,strlen($sql)-1);
$rs->MoveNext();
}
$rs->Close();
$carr = explode('::',$check);
$prefix = "';
$suffix = '';
if (strlen($prefix)>2000) {
$prefix = '';
$suffix = '';
}
$s .= "\n".$carr[0].' | '.$carr[1].' | '.$prefix.$sql.$suffix.' |
';
return $s."
\n\n";
}
// code thanks to Ixora.
// http://www.ixora.com.au/scripts/query_opt.htm
// requires oracle 8.1.7 or later
function SuspiciousSQL($numsql=10)
{
$sql = "
select
substr(to_char(s.pct, '99.00'), 2) || '%' load,
s.executions executes,
p.sql_text
from
(
select
address,
buffer_gets,
executions,
pct,
rank() over (order by buffer_gets desc) ranking
from
(
select
address,
buffer_gets,
executions,
100 * ratio_to_report(buffer_gets) over () pct
from
sys.v_\$sql
where
command_type != 47 and module != 'T.O.A.D.'
)
where
buffer_gets > 50 * executions
) s,
sys.v_\$sqltext p
where
s.ranking <= $numsql and
p.address = s.address
order by
1 desc, s.address, p.piece";
global $ADODB_CACHE_MODE;
if (isset($_GET['expsixora']) && isset($_GET['sql'])) {
$partial = empty($_GET['part']);
echo "".$this->Explain($_GET['sql'],$partial)."\n";
}
if (isset($_GET['sql'])) return $this->_SuspiciousSQL($numsql);
$s = '';
$timer = time();
$s .= $this->_SuspiciousSQL($numsql);
$timer = time() - $timer;
if ($timer > $this->noShowIxora) return $s;
$s .= '';
$save = $ADODB_CACHE_MODE;
$ADODB_CACHE_MODE = ADODB_FETCH_NUM;
if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
$savelog = $this->conn->LogSQL(false);
$rs = $this->conn->SelectLimit($sql);
$this->conn->LogSQL($savelog);
if (isset($savem)) $this->conn->SetFetchMode($savem);
$ADODB_CACHE_MODE = $save;
if ($rs) {
$s .= "\n
Ixora Suspicious SQL
";
$s .= $this->tohtml($rs,'expsixora');
}
return $s;
}
// code thanks to Ixora.
// http://www.ixora.com.au/scripts/query_opt.htm
// requires oracle 8.1.7 or later
function ExpensiveSQL($numsql = 10)
{
$sql = "
select
substr(to_char(s.pct, '99.00'), 2) || '%' load,
s.executions executes,
p.sql_text
from
(
select
address,
disk_reads,
executions,
pct,
rank() over (order by disk_reads desc) ranking
from
(
select
address,
disk_reads,
executions,
100 * ratio_to_report(disk_reads) over () pct
from
sys.v_\$sql
where
command_type != 47 and module != 'T.O.A.D.'
)
where
disk_reads > 50 * executions
) s,
sys.v_\$sqltext p
where
s.ranking <= $numsql and
p.address = s.address
order by
1 desc, s.address, p.piece
";
global $ADODB_CACHE_MODE;
if (isset($_GET['expeixora']) && isset($_GET['sql'])) {
$partial = empty($_GET['part']);
echo "".$this->Explain($_GET['sql'],$partial)."\n";
}
if (isset($_GET['sql'])) {
$var = $this->_ExpensiveSQL($numsql);
return $var;
}
$s = '';
$timer = time();
$s .= $this->_ExpensiveSQL($numsql);
$timer = time() - $timer;
if ($timer > $this->noShowIxora) return $s;
$s .= '';
$save = $ADODB_CACHE_MODE;
$ADODB_CACHE_MODE = ADODB_FETCH_NUM;
if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
$savelog = $this->conn->LogSQL(false);
$rs = $this->conn->Execute($sql);
$this->conn->LogSQL($savelog);
if (isset($savem)) $this->conn->SetFetchMode($savem);
$ADODB_CACHE_MODE = $save;
if ($rs) {
$s .= "\n
Ixora Expensive SQL
";
$s .= $this->tohtml($rs,'expeixora');
}
return $s;
}
function clearsql()
{
$perf_table = adodb_perf::table();
// using the naive "delete from $perf_table where created<".$this->conn->sysTimeStamp will cause the table to lock, possibly
// for a long time
$sql =
"DECLARE cnt pls_integer;
BEGIN
cnt := 0;
FOR rec IN (SELECT ROWID AS rr FROM $perf_table WHERE createdconn->Execute($sql);
}
}
PK ⒨Te%,d" d" perf/perf-mysql.inc.phpnu ٘ array('RATIO',
'=GetKeyHitRatio',
'=WarnCacheRatio'),
'InnoDB cache hit ratio' => array('RATIO',
'=GetInnoDBHitRatio',
'=WarnCacheRatio'),
'data cache hit ratio' => array('HIDE', # only if called
'=FindDBHitRatio',
'=WarnCacheRatio'),
'sql cache hit ratio' => array('RATIO',
'=GetQHitRatio',
''),
'IO',
'data reads' => array('IO',
'=GetReads',
'Number of selects (Key_reads is not accurate)'),
'data writes' => array('IO',
'=GetWrites',
'Number of inserts/updates/deletes * coef (Key_writes is not accurate)'),
'Data Cache',
'MyISAM data cache size' => array('DATAC',
array("show variables", 'key_buffer_size'),
'' ),
'BDB data cache size' => array('DATAC',
array("show variables", 'bdb_cache_size'),
'' ),
'InnoDB data cache size' => array('DATAC',
array("show variables", 'innodb_buffer_pool_size'),
'' ),
'Memory Usage',
'read buffer size' => array('CACHE',
array("show variables", 'read_buffer_size'),
'(per session)'),
'sort buffer size' => array('CACHE',
array("show variables", 'sort_buffer_size'),
'Size of sort buffer (per session)' ),
'table cache' => array('CACHE',
array("show variables", 'table_cache'),
'Number of tables to keep open'),
'Connections',
'current connections' => array('SESS',
array('show status','Threads_connected'),
''),
'max connections' => array( 'SESS',
array("show variables",'max_connections'),
''),
false
);
function __construct(&$conn)
{
$this->conn = $conn;
}
function Explain($sql,$partial=false)
{
if (strtoupper(substr(trim($sql),0,6)) !== 'SELECT') return 'Unable to EXPLAIN non-select statement
';
$save = $this->conn->LogSQL(false);
if ($partial) {
$sqlq = $this->conn->qstr($sql.'%');
$arr = $this->conn->GetArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq");
if ($arr) {
foreach($arr as $row) {
$sql = reset($row);
if (crc32($sql) == $partial) break;
}
}
}
$sql = str_replace('?',"''",$sql);
if ($partial) {
$sqlq = $this->conn->qstr($sql.'%');
$sql = $this->conn->GetOne("select sql1 from adodb_logsql where sql1 like $sqlq");
}
$s = 'Explain: '.htmlspecialchars($sql).'
';
$rs = $this->conn->Execute('EXPLAIN '.$sql);
$s .= rs2html($rs,false,false,false,false);
$this->conn->LogSQL($save);
$s .= $this->Tracer($sql);
return $s;
}
/**
* Returns a list of table statuses.
*
* @param string $orderby Unused (compatibility with parent method)
* @return string A formatted set of recordsets
*/
function tables($orderby='1')
{
if (!$this->tablesSQL) return false;
$rs = $this->conn->Execute($this->tablesSQL);
if (!$rs) return false;
$html = rs2html($rs,false,false,false,false);
return $html;
}
function GetReads()
{
global $ADODB_FETCH_MODE;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
$rs = $this->conn->Execute('show status');
if (isset($savem)) $this->conn->SetFetchMode($savem);
$ADODB_FETCH_MODE = $save;
if (!$rs) return 0;
$val = 0;
while (!$rs->EOF) {
switch($rs->fields[0]) {
case 'Com_select':
$val = $rs->fields[1];
$rs->Close();
return $val;
}
$rs->MoveNext();
}
$rs->Close();
return $val;
}
function GetWrites()
{
global $ADODB_FETCH_MODE;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
$rs = $this->conn->Execute('show status');
if (isset($savem)) $this->conn->SetFetchMode($savem);
$ADODB_FETCH_MODE = $save;
if (!$rs) return 0;
$val = 0.0;
while (!$rs->EOF) {
switch($rs->fields[0]) {
case 'Com_insert':
$val += $rs->fields[1]; break;
case 'Com_delete':
$val += $rs->fields[1]; break;
case 'Com_update':
$val += $rs->fields[1]/2;
$rs->Close();
return $val;
}
$rs->MoveNext();
}
$rs->Close();
return $val;
}
function FindDBHitRatio()
{
// first find out type of table
//$this->conn->debug=1;
global $ADODB_FETCH_MODE;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
$rs = $this->conn->Execute('show table status');
if (isset($savem)) $this->conn->SetFetchMode($savem);
$ADODB_FETCH_MODE = $save;
if (!$rs) return '';
$type = strtoupper($rs->fields[1]);
$rs->Close();
switch($type){
case 'MYISAM':
case 'ISAM':
return $this->DBParameter('MyISAM cache hit ratio').' (MyISAM)';
case 'INNODB':
return $this->DBParameter('InnoDB cache hit ratio').' (InnoDB)';
default:
return $type.' not supported';
}
}
function GetQHitRatio()
{
//Total number of queries = Qcache_inserts + Qcache_hits + Qcache_not_cached
$hits = $this->_DBParameter(array("show status","Qcache_hits"));
$total = $this->_DBParameter(array("show status","Qcache_inserts"));
$total += $this->_DBParameter(array("show status","Qcache_not_cached"));
$total += $hits;
if ($total) return round(($hits*100)/$total,2);
return 0;
}
/*
Use session variable to store Hit percentage, because MySQL
does not remember last value of SHOW INNODB STATUS hit ratio
# 1st query to SHOW INNODB STATUS
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
Buffer pool hit rate 1000 / 1000
# 2nd query to SHOW INNODB STATUS
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool activity since the last printout
*/
function GetInnoDBHitRatio()
{
global $ADODB_FETCH_MODE;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
if ($this->conn->fetchMode !== false) $savem = $this->conn->SetFetchMode(false);
$rs = $this->conn->Execute('show engine innodb status');
if (isset($savem)) $this->conn->SetFetchMode($savem);
$ADODB_FETCH_MODE = $save;
if (!$rs || $rs->EOF) return 0;
$stat = $rs->fields[0];
$rs->Close();
$at = strpos($stat,'Buffer pool hit rate');
$stat = substr($stat,$at,200);
if (preg_match('!Buffer pool hit rate\s*([0-9]*) / ([0-9]*)!',$stat,$arr)) {
$val = 100*$arr[1]/$arr[2];
$_SESSION['INNODB_HIT_PCT'] = $val;
return round($val,2);
} else {
if (isset($_SESSION['INNODB_HIT_PCT'])) return $_SESSION['INNODB_HIT_PCT'];
return 0;
}
return 0;
}
function GetKeyHitRatio()
{
$hits = $this->_DBParameter(array("show status","Key_read_requests"));
$reqs = $this->_DBParameter(array("show status","Key_reads"));
if ($reqs == 0) return 0;
return round(($hits/($reqs+$hits))*100,2);
}
// start hack
var $optimizeTableLow = 'CHECK TABLE %s FAST QUICK';
var $optimizeTableHigh = 'OPTIMIZE TABLE %s';
/**
* @see adodb_perf::optimizeTable()
*/
function optimizeTable( $table, $mode = ADODB_OPT_LOW)
{
if ( !is_string( $table)) return false;
$conn = $this->conn;
if ( !$conn) return false;
$sql = '';
switch( $mode) {
case ADODB_OPT_LOW : $sql = $this->optimizeTableLow; break;
case ADODB_OPT_HIGH : $sql = $this->optimizeTableHigh; break;
default :
// May don't use __FUNCTION__ constant for BC (__FUNCTION__ Added in PHP 4.3.0)
ADOConnection::outp( sprintf( "%s: '%s' using of undefined mode '%s'
", __CLASS__, __FUNCTION__, $mode));
return false;
}
$sql = sprintf( $sql, $table);
return $conn->Execute( $sql) !== false;
}
// end hack
}
PK ⒨T'|J perf/perf-sqlite3.inc.phpnu ٘ conn = $conn;
}
function tables($orderby='1')
{
if (!$this->tablesSQL){
return false;
}
$rs = $this->conn->execute($this->tablesSQL);
if (!$rs) {
return false;
}
$html = rs2html($rs, false, false, false, false);
return $html;
}
}
PK ⒨TW!6
perf/perf-db2.inc.phpnu ٘ array('RATIO',
"SELECT
case when sum(POOL_DATA_L_READS+POOL_INDEX_L_READS)=0 then 0
else 100*(1-sum(POOL_DATA_P_READS+POOL_INDEX_P_READS)/sum(POOL_DATA_L_READS+POOL_INDEX_L_READS)) end
FROM TABLE(SNAPSHOT_APPL('',-2)) as t",
'=WarnCacheRatio'),
'Data Cache',
'data cache buffers' => array('DATAC',
'select sum(npages) from SYSCAT.BUFFERPOOLS',
'See tuning reference.' ),
'cache blocksize' => array('DATAC',
'select avg(pagesize) from SYSCAT.BUFFERPOOLS',
'' ),
'data cache size' => array('DATAC',
'select sum(npages*pagesize) from SYSCAT.BUFFERPOOLS',
'' ),
'Connections',
'current connections' => array('SESS',
"SELECT count(*) FROM TABLE(SNAPSHOT_APPL_INFO('',-2)) as t",
''),
false
);
function __construct(&$conn)
{
$this->conn = $conn;
}
function Explain($sql,$partial=false)
{
$save = $this->conn->LogSQL(false);
if ($partial) {
$sqlq = $this->conn->qstr($sql.'%');
$arr = $this->conn->GetArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq");
if ($arr) {
foreach($arr as $row) {
$sql = reset($row);
if (crc32($sql) == $partial) break;
}
}
}
$qno = rand();
$ok = $this->conn->Execute("EXPLAIN PLAN SET QUERYNO=$qno FOR $sql");
ob_start();
if (!$ok) echo "Have EXPLAIN tables been created?
";
else {
$rs = $this->conn->Execute("select * from explain_statement where queryno=$qno");
if ($rs) rs2html($rs);
}
$s = ob_get_contents();
ob_end_clean();
$this->conn->LogSQL($save);
$s .= $this->Tracer($sql);
return $s;
}
/**
* Gets a list of tables
*
* @param int $throwaway discarded variable to match the parent method
* @return string The formatted table list
*/
function Tables($throwaway=0)
{
$rs = $this->conn->Execute("select tabschema,tabname,card as rows,
npages pages_used,fpages pages_allocated, tbspace tablespace
from syscat.tables where tabschema not in ('SYSCAT','SYSIBM','SYSSTAT') order by 1,2");
return rs2html($rs,false,false,false,false);
}
}
PK ⒨T W perf/perf-postgres.inc.phpnu ٘ array('RATIO',
"select case when count(*)=3 then 'TRUE' else 'FALSE' end from pg_settings where (name='stats_block_level' or name='stats_row_level' or name='stats_start_collector') and setting='on' ",
'Value must be TRUE to enable hit ratio statistics (stats_start_collector,stats_row_level and stats_block_level must be set to true in postgresql.conf)'),
'data cache hit ratio' => array('RATIO',
"select case when blks_hit=0 then 0 else round( ((1-blks_read::float/blks_hit)*100)::numeric, 2) end from pg_stat_database where datname='\$DATABASE'",
'=WarnCacheRatio'),
'IO',
'data reads' => array('IO',
'select sum(heap_blks_read+toast_blks_read) from pg_statio_user_tables',
),
'data writes' => array('IO',
'select round((sum(n_tup_ins/4.0+n_tup_upd/8.0+n_tup_del/4.0)/16)::numeric,2) from pg_stat_user_tables',
'Count of inserts/updates/deletes * coef'),
'Data Cache',
'data cache buffers' => array('DATAC',
"select setting from pg_settings where name='shared_buffers'",
'Number of cache buffers. Tuning'),
'cache blocksize' => array('DATAC',
'select 8192',
'(estimate)' ),
'data cache size' => array( 'DATAC',
"select setting::integer*8192 from pg_settings where name='shared_buffers'",
'' ),
'operating system cache size' => array( 'DATA',
"select setting::integer*8192 from pg_settings where name='effective_cache_size'",
'(effective cache size)' ),
'Memory Usage',
# Postgres 7.5 changelog: Rename server parameters SortMem and VacuumMem to work_mem and maintenance_work_mem;
'sort/work buffer size' => array('CACHE',
"select setting::integer*1024 from pg_settings where name='sort_mem' or name = 'work_mem' order by name",
'Size of sort buffer (per query)' ),
'Connections',
'current connections' => array('SESS',
'select count(*) from pg_stat_activity',
''),
'max connections' => array('SESS',
"select setting from pg_settings where name='max_connections'",
''),
'Parameters',
'rollback buffers' => array('COST',
"select setting from pg_settings where name='wal_buffers'",
'WAL buffers'),
'random page cost' => array('COST',
"select setting from pg_settings where name='random_page_cost'",
'Cost of doing a seek (default=4). See random_page_cost'),
false
);
function __construct(&$conn)
{
$this->conn = $conn;
}
var $optimizeTableLow = 'VACUUM %s';
var $optimizeTableHigh = 'VACUUM ANALYZE %s';
/**
* @see adodb_perf::optimizeTable()
*/
function optimizeTable($table, $mode = ADODB_OPT_LOW)
{
if(! is_string($table)) return false;
$conn = $this->conn;
if (! $conn) return false;
$sql = '';
switch($mode) {
case ADODB_OPT_LOW : $sql = $this->optimizeTableLow; break;
case ADODB_OPT_HIGH: $sql = $this->optimizeTableHigh; break;
default :
ADOConnection::outp(sprintf("%s: '%s' using of undefined mode '%s'
", __CLASS__, 'optimizeTable', $mode));
return false;
}
$sql = sprintf($sql, $table);
return $conn->Execute($sql) !== false;
}
function Explain($sql,$partial=false)
{
$save = $this->conn->LogSQL(false);
if ($partial) {
$sqlq = $this->conn->qstr($sql.'%');
$arr = $this->conn->getArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq");
if ($arr) {
foreach($arr as $row) {
$sql = reset($row);
if (crc32($sql) == $partial) break;
}
}
}
$sql = str_replace('?',"''",$sql);
$s = 'Explain: '.htmlspecialchars($sql).'
';
$rs = $this->conn->Execute('EXPLAIN '.$sql);
$this->conn->LogSQL($save);
$s .= '';
if ($rs)
while (!$rs->EOF) {
$s .= reset($rs->fields)."\n";
$rs->MoveNext();
}
$s .= '
';
$s .= $this->Tracer($sql,$partial);
return $s;
}
}
PK ⒨Tzp
perf/perf-mssqlnative.inc.phpnu ٘ array('RATIO',
"select round((a.cntr_value*100.0)/b.cntr_value,2) from master.dbo.sysperfinfo a, master.dbo.sysperfinfo b where a.counter_name = 'Buffer cache hit ratio' and b.counter_name='Buffer cache hit ratio base'",
'=WarnCacheRatio'),
'prepared sql hit ratio' => array('RATIO',
array('dbcc cachestats','Prepared',1,100),
''),
'adhoc sql hit ratio' => array('RATIO',
array('dbcc cachestats','Adhoc',1,100),
''),
'IO',
'data reads' => array('IO',
"select cntr_value from master.dbo.sysperfinfo where counter_name = 'Page reads/sec'"),
'data writes' => array('IO',
"select cntr_value from master.dbo.sysperfinfo where counter_name = 'Page writes/sec'"),
'Data Cache',
'data cache size' => array('DATAC',
"select cntr_value*8192 from master.dbo.sysperfinfo where counter_name = 'Total Pages' and object_name='SQLServer:Buffer Manager'",
'' ),
'data cache blocksize' => array('DATAC',
"select 8192",'page size'),
'Connections',
'current connections' => array('SESS',
'=sp_who',
''),
'max connections' => array('SESS',
"SELECT @@MAX_CONNECTIONS",
''),
false
);
function __construct(&$conn)
{
if ($conn->dataProvider == 'odbc') {
$this->sql1 = 'sql1';
//$this->explain = false;
}
$this->conn =& $conn;
}
function Explain($sql,$partial=false)
{
$save = $this->conn->LogSQL(false);
if ($partial) {
$sqlq = $this->conn->qstr($sql.'%');
$arr = $this->conn->GetArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq");
if ($arr) {
foreach($arr as $row) {
$sql = reset($row);
if (crc32($sql) == $partial) break;
}
}
}
$s = 'Explain: '.htmlspecialchars($sql).'
';
$this->conn->Execute("SET SHOWPLAN_ALL ON;");
$sql = str_replace('?',"''",$sql);
global $ADODB_FETCH_MODE;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
$rs =& $this->conn->Execute($sql);
//adodb_printr($rs);
$ADODB_FETCH_MODE = $save;
if ($rs) {
$rs->MoveNext();
$s .= ' Rows | IO | CPU | Plan |
';
while (!$rs->EOF) {
$s .= ''.round($rs->fields[8],1).' | '.round($rs->fields[9],3).' | '.round($rs->fields[10],3).' | '.htmlspecialchars($rs->fields[0])." |
\n"; ## NOTE CORRUPT tag is intentional!!!!
$rs->MoveNext();
}
$s .= '
';
$rs->NextRecordSet();
}
$this->conn->Execute("SET SHOWPLAN_ALL OFF;");
$this->conn->LogSQL($save);
$s .= $this->Tracer($sql);
return $s;
}
function Tables($orderby='1')
{
global $ADODB_FETCH_MODE;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
//$this->conn->debug=1;
$s = 'tablename | size_in_k | index size | reserved size |
';
$rs1 = $this->conn->Execute("select distinct name from sysobjects where xtype='U'");
if ($rs1) {
while (!$rs1->EOF) {
$tab = $rs1->fields[0];
$tabq = $this->conn->qstr($tab);
$rs2 = $this->conn->Execute("sp_spaceused $tabq");
if ($rs2) {
$s .= ''.$tab.' | '.$rs2->fields[3].' | '.$rs2->fields[4].' | '.$rs2->fields[2].' |
';
$rs2->Close();
}
$rs1->MoveNext();
}
$rs1->Close();
}
$ADODB_FETCH_MODE = $save;
return $s.'
';
}
function sp_who()
{
$arr = $this->conn->GetArray('sp_who');
return sizeof($arr);
}
function HealthCheck($cli=false)
{
$this->conn->Execute('dbcc traceon(3604)');
$html = adodb_perf::HealthCheck($cli);
$this->conn->Execute('dbcc traceoff(3604)');
return $html;
}
}
PK ⒨TWq perf/perf-mssql.inc.phpnu ٘ array('RATIO',
"select round((a.cntr_value*100.0)/b.cntr_value,2) from master.dbo.sysperfinfo a, master.dbo.sysperfinfo b where a.counter_name = 'Buffer cache hit ratio' and b.counter_name='Buffer cache hit ratio base'",
'=WarnCacheRatio'),
'prepared sql hit ratio' => array('RATIO',
array('dbcc cachestats','Prepared',1,100),
''),
'adhoc sql hit ratio' => array('RATIO',
array('dbcc cachestats','Adhoc',1,100),
''),
'IO',
'data reads' => array('IO',
"select cntr_value from master.dbo.sysperfinfo where counter_name = 'Page reads/sec'"),
'data writes' => array('IO',
"select cntr_value from master.dbo.sysperfinfo where counter_name = 'Page writes/sec'"),
'Data Cache',
'data cache size' => array('DATAC',
"select cntr_value*8192 from master.dbo.sysperfinfo where counter_name = 'Total Pages' and object_name='SQLServer:Buffer Manager'",
'' ),
'data cache blocksize' => array('DATAC',
"select 8192",'page size'),
'Connections',
'current connections' => array('SESS',
'=sp_who',
''),
'max connections' => array('SESS',
"SELECT @@MAX_CONNECTIONS",
''),
false
);
function __construct(&$conn)
{
if ($conn->dataProvider == 'odbc') {
$this->sql1 = 'sql1';
//$this->explain = false;
}
$this->conn = $conn;
}
function Explain($sql,$partial=false)
{
$save = $this->conn->LogSQL(false);
if ($partial) {
$sqlq = $this->conn->qstr($sql.'%');
$arr = $this->conn->GetArray("select distinct sql1 from adodb_logsql where sql1 like $sqlq");
if ($arr) {
foreach($arr as $row) {
$sql = reset($row);
if (crc32($sql) == $partial) break;
}
}
}
$s = 'Explain: '.htmlspecialchars($sql).'
';
$this->conn->Execute("SET SHOWPLAN_ALL ON;");
$sql = str_replace('?',"''",$sql);
global $ADODB_FETCH_MODE;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
$rs = $this->conn->Execute($sql);
//adodb_printr($rs);
$ADODB_FETCH_MODE = $save;
if ($rs && !$rs->EOF) {
$rs->MoveNext();
$s .= ' Rows | IO | CPU | Plan |
';
while (!$rs->EOF) {
$s .= ''.round($rs->fields[8],1).' | '.round($rs->fields[9],3).' | '.round($rs->fields[10],3).' | '.htmlspecialchars($rs->fields[0])." |
\n"; ## NOTE CORRUPT tag is intentional!!!!
$rs->MoveNext();
}
$s .= '
';
$rs->NextRecordSet();
}
$this->conn->Execute("SET SHOWPLAN_ALL OFF;");
$this->conn->LogSQL($save);
$s .= $this->Tracer($sql);
return $s;
}
function Tables()
{
global $ADODB_FETCH_MODE;
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
//$this->conn->debug=1;
$s = 'tablename | size_in_k | index size | reserved size |
';
$rs1 = $this->conn->Execute("select distinct name from sysobjects where xtype='U'");
if ($rs1) {
while (!$rs1->EOF) {
$tab = $rs1->fields[0];
$tabq = $this->conn->qstr($tab);
$rs2 = $this->conn->Execute("sp_spaceused $tabq");
if ($rs2) {
$s .= ''.$tab.' | '.$rs2->fields[3].' | '.$rs2->fields[4].' | '.$rs2->fields[2].' |
';
$rs2->Close();
}
$rs1->MoveNext();
}
$rs1->Close();
}
$ADODB_FETCH_MODE = $save;
return $s.'
';
}
function sp_who()
{
$arr = $this->conn->GetArray('sp_who');
return sizeof($arr);
}
function HealthCheck($cli=false)
{
$this->conn->Execute('dbcc traceon(3604)');
$html = adodb_perf::HealthCheck($cli);
$this->conn->Execute('dbcc traceoff(3604)');
return $html;
}
}
PK ⒨T/e e perf/perf-informix.inc.phpnu ٘ array('RATIOH',
"select round((1-(wt.value / (rd.value + wr.value)))*100,2)
from sysmaster:sysprofile wr, sysmaster:sysprofile rd, sysmaster:sysprofile wt
where rd.name = 'pagreads' and
wr.name = 'pagwrites' and
wt.name = 'buffwts'",
'=WarnCacheRatio'),
'IO',
'data reads' => array('IO',
"select value from sysmaster:sysprofile where name='pagreads'",
'Page reads'),
'data writes' => array('IO',
"select value from sysmaster:sysprofile where name='pagwrites'",
'Page writes'),
'Connections',
'current connections' => array('SESS',
'select count(*) from sysmaster:syssessions',
'Number of sessions'),
false
);
function __construct(&$conn)
{
$this->conn = $conn;
}
}
PK ⒨Tm- " datadict/datadict-informix.inc.phpnu ٘ connection->customMetaTypes[$meta]))
return $this->connection->customMetaTypes[$meta]['actual'];
switch($meta) {
case 'C': return 'VARCHAR';// 255
case 'XL':
case 'X': return 'TEXT';
case 'C2': return 'NVARCHAR';
case 'X2': return 'TEXT';
case 'B': return 'BLOB';
case 'D': return 'DATE';
case 'TS':
case 'T': return 'DATETIME YEAR TO SECOND';
case 'L': return 'SMALLINT';
case 'I': return 'INTEGER';
case 'I1': return 'SMALLINT';
case 'I2': return 'SMALLINT';
case 'I4': return 'INTEGER';
case 'I8': return 'DECIMAL(20)';
case 'F': return 'FLOAT';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
function AlterColumnSQL($tabname, $flds, $tableflds='', $tableoptions='')
{
if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
return array();
}
function DropColumnSQL($tabname, $flds, $tableflds='', $tableoptions='')
{
if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
return array();
}
// return string must begin with space
function _CreateSuffix($fname, &$ftype, $fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
{
if ($fautoinc) {
$ftype = 'SERIAL';
return '';
}
$suffix = '';
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fnotnull) $suffix .= ' NOT NULL';
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
}
PK ⒨T^?vVU
U
datadict/datadict-sqlite.inc.phpnu ٘ connection->customMetaTypes[$meta]))
return $this->connection->customMetaTypes[$meta]['actual'];
switch(strtoupper($meta)) {
case 'C': return 'VARCHAR'; // TEXT , TEXT affinity
case 'XL':return 'LONGTEXT'; // TEXT , TEXT affinity
case 'X': return 'TEXT'; // TEXT , TEXT affinity
case 'C2': return 'VARCHAR'; // TEXT , TEXT affinity
case 'X2': return 'LONGTEXT'; // TEXT , TEXT affinity
case 'B': return 'LONGBLOB'; // TEXT , NONE affinity , BLOB
case 'D': return 'DATE'; // NUMERIC , NUMERIC affinity
case 'T': return 'DATETIME'; // NUMERIC , NUMERIC affinity
case 'L': return 'TINYINT'; // NUMERIC , INTEGER affinity
case 'R':
case 'I4':
case 'I': return 'INTEGER'; // NUMERIC , INTEGER affinity
case 'I1': return 'TINYINT'; // NUMERIC , INTEGER affinity
case 'I2': return 'SMALLINT'; // NUMERIC , INTEGER affinity
case 'I8': return 'BIGINT'; // NUMERIC , INTEGER affinity
case 'F': return 'DOUBLE'; // NUMERIC , REAL affinity
case 'N': return 'NUMERIC'; // NUMERIC , NUMERIC affinity
default:
return $meta;
}
}
// return string must begin with space
function _CreateSuffix($fname,&$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
{
$suffix = '';
if ($funsigned) $suffix .= ' UNSIGNED';
if ($fnotnull) $suffix .= ' NOT NULL';
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fautoinc) $suffix .= ' AUTOINCREMENT';
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
function AlterColumnSQL($tabname, $flds, $tableflds='', $tableoptions='')
{
if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported natively by SQLite");
return array();
}
function DropColumnSQL($tabname, $flds, $tableflds='', $tableoptions='')
{
if ($this->debug) ADOConnection::outp("DropColumnSQL not supported natively by SQLite");
return array();
}
function RenameColumnSQL($tabname,$oldcolumn,$newcolumn,$flds='')
{
if ($this->debug) ADOConnection::outp("RenameColumnSQL not supported natively by SQLite");
return array();
}
}
PK ⒨T # # % datadict/datadict-mssqlnative.inc.phpnu ٘ type;
}
$t = strtoupper($t);
if (array_key_exists($t,$this->connection->customActualTypes))
return $this->connection->customActualTypes[$t];
$_typeConversion = array(
-155 => 'D',
93 => 'D',
-154 => 'D',
-2 => 'D',
91 => 'D',
12 => 'C',
1 => 'C',
-9 => 'C',
-8 => 'C',
-7 => 'L',
-6 => 'I2',
-5 => 'I8',
-11 => 'I',
4 => 'I',
5 => 'I4',
-1 => 'X',
-10 => 'X',
2 => 'N',
3 => 'N',
6 => 'N',
7 => 'N',
-152 => 'X',
-151 => 'X',
-4 => 'X',
-3 => 'X'
);
if (isset($_typeConversion[$t])) {
return $_typeConversion[$t];
}
return ADODB_DEFAULT_METATYPE;
}
function ActualType($meta)
{
$DATE_TYPE = 'DATETIME';
$meta = strtoupper($meta);
/*
* Add support for custom meta types. We do this
* first, that allows us to override existing types
*/
if (isset($this->connection->customMetaTypes[$meta]))
return $this->connection->customMetaTypes[$meta]['actual'];
switch(strtoupper($meta)) {
case 'C': return 'VARCHAR';
case 'XL': return (isset($this)) ? $this->typeXL : 'TEXT';
case 'X': return (isset($this)) ? $this->typeX : 'TEXT'; ## could be varchar(8000), but we want compat with oracle
case 'C2': return 'NVARCHAR';
case 'X2': return 'NTEXT';
case 'B': return 'IMAGE';
case 'D': return $DATE_TYPE;
case 'T': return 'TIME';
case 'L': return 'BIT';
case 'R':
case 'I': return 'INT';
case 'I1': return 'TINYINT';
case 'I2': return 'SMALLINT';
case 'I4': return 'INT';
case 'I8': return 'BIGINT';
case 'F': return 'REAL';
case 'N': return 'NUMERIC';
default:
return $meta;
}
}
function AddColumnSQL($tabname, $flds)
{
$tabname = $this->TableName ($tabname);
$f = array();
list($lines,) = $this->_GenFields($flds);
$s = "ALTER TABLE $tabname $this->addCol";
foreach($lines as $v) {
$f[] = "\n $v";
}
$s .= implode(', ',$f);
$sql[] = $s;
return $sql;
}
/**
* Get a column's default constraint.
*
* @param string $tabname
* @param string $colname
* @return string|null The Constraint's name, or null if there is none.
*/
function defaultConstraintName($tabname, $colname)
{
$sql = "SELECT name FROM sys.default_constraints
WHERE object_name(parent_object_id) = ?
AND col_name(parent_object_id, parent_column_id) = ?";
return $this->connection->getOne($sql, [$tabname, $colname]);
}
function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
{
$tabname = $this->TableName ($tabname);
$sql = array();
list($lines,,$idxs) = $this->_GenFields($flds);
$alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' ';
foreach($lines as $v) {
if ($not_null = preg_match('/NOT NULL/i',$v)) {
$v = preg_replace('/NOT NULL/i','',$v);
}
if (preg_match('/^([^ ]+) .*DEFAULT (\'[^\']+\'|\"[^\"]+\"|[^ ]+)/',$v,$matches)) {
list(,$colname,$default) = $matches;
$v = preg_replace('/^' . preg_quote($colname) . '\s/', '', $v);
$t = trim(str_replace('DEFAULT '.$default,'',$v));
if ( $constraintname = $this->defaultConstraintName($tabname,$colname) ) {
$sql[] = 'ALTER TABLE '.$tabname.' DROP CONSTRAINT '. $constraintname;
}
if ($not_null) {
$sql[] = $alter . $colname . ' ' . $t . ' NOT NULL';
} else {
$sql[] = $alter . $colname . ' ' . $t ;
}
$sql[] = 'ALTER TABLE ' . $tabname
. ' ADD CONSTRAINT DF__' . $tabname . '__' . $colname . '__' . dechex(rand())
. ' DEFAULT ' . $default . ' FOR ' . $colname;
} else {
$colname = strtok($v," ");
if ( $constraintname = $this->defaultConstraintName($tabname,$colname) ) {
$sql[] = 'ALTER TABLE '.$tabname.' DROP CONSTRAINT '. $constraintname;
}
if ($not_null) {
$sql[] = $alter . $v . ' NOT NULL';
} else {
$sql[] = $alter . $v;
}
}
}
if (is_array($idxs)) {
foreach($idxs as $idx => $idxdef) {
$sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
$sql = array_merge($sql, $sql_idxs);
}
}
return $sql;
}
/**
* Drop a column, syntax is ALTER TABLE table DROP COLUMN column,column
*
* @param string $tabname Table Name
* @param string[] $flds One, or an array of Fields To Drop
* @param string $tableflds Throwaway value to make the function match the parent
* @param string $tableoptions Throway value to make the function match the parent
*
* @return string[] The SQL necessary to drop the column
*/
function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
{
$tabname = $this->TableName ($tabname);
if (!is_array($flds)) {
/** @noinspection PhpParamsInspection */
$flds = explode(',', $flds);
}
$f = array();
$s = 'ALTER TABLE ' . $tabname;
foreach($flds as $v) {
if ( $constraintname = $this->defaultConstraintName($tabname,$v) ) {
$sql[] = 'ALTER TABLE ' . $tabname . ' DROP CONSTRAINT ' . $constraintname;
}
$f[] = ' DROP COLUMN ' . $this->NameQuote($v);
}
$s .= implode(', ',$f);
$sql[] = $s;
return $sql;
}
// return string must begin with space
/** @noinspection DuplicatedCode */
function _CreateSuffix($fname,&$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
{
$suffix = '';
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fautoinc) $suffix .= ' IDENTITY(1,1)';
if ($fnotnull) $suffix .= ' NOT NULL';
else if ($suffix == '') $suffix .= ' NULL';
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
/** @noinspection DuplicatedCode */
function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
{
$sql = array();
if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
$sql[] = sprintf ($this->dropIndex, $idxname, $tabname);
if ( isset($idxoptions['DROP']) )
return $sql;
}
if ( empty ($flds) ) {
return $sql;
}
$unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
$clustered = isset($idxoptions['CLUSTERED']) ? ' CLUSTERED' : '';
if ( is_array($flds) )
$flds = implode(', ',$flds);
$s = 'CREATE' . $unique . $clustered . ' INDEX ' . $idxname . ' ON ' . $tabname . ' (' . $flds . ')';
if ( isset($idxoptions[$this->upperName]) )
$s .= $idxoptions[$this->upperName];
$sql[] = $s;
return $sql;
}
function _GetSize($ftype, $ty, $fsize, $fprec, $options=false)
{
switch ($ftype) {
case 'INT':
case 'SMALLINT':
case 'TINYINT':
case 'BIGINT':
return $ftype;
}
if ($ty == 'T') {
return $ftype;
}
return parent::_GetSize($ftype, $ty, $fsize, $fprec, $options);
}
}
PK ⒨T2" " " datadict/datadict-firebird.inc.phpnu ٘ connection->customMetaTypes[$meta])) {
return $this->connection->customMetaTypes[$meta]['actual'];
}
switch($meta) {
case 'C':
return 'VARCHAR';
case 'XL':
return 'BLOB SUB_TYPE BINARY';
case 'X':
return 'BLOB SUB_TYPE TEXT';
case 'C2':
return 'VARCHAR(32765)'; // up to 32K
case 'X2':
return 'VARCHAR(4096)';
case 'V':
return 'CHAR';
case 'C1':
return 'CHAR(1)';
case 'B':
return 'BLOB';
case 'D':
return 'DATE';
case 'TS':
case 'T':
return 'TIMESTAMP';
case 'L':
case 'I1':
case 'I2':
return 'SMALLINT';
case 'I':
case 'I4':
return 'INTEGER';
case 'I8':
return 'BIGINT';
case 'F':
return 'DOUBLE PRECISION';
case 'N':
return 'DECIMAL';
default:
return $meta;
}
}
function nameQuote($name = null, $allowBrackets = false)
{
if (!is_string($name)) {
return false;
}
$name = trim($name);
if (!is_object($this->connection)) {
return $name;
}
$quote = $this->connection->nameQuote;
// if name is of the form `name`, quote it
if (preg_match('/^`(.+)`$/', $name, $matches)) {
return $quote . $matches[1] . $quote;
}
// if name contains special characters, quote it
if (!preg_match('/^[' . $this->nameRegex . ']+$/', $name)) {
return $quote . $name . $quote;
}
return $quote . $name . $quote;
}
function createDatabase($dbname, $options = false)
{
$sql = array();
$sql[] = "DECLARE EXTERNAL FUNCTION LOWER CSTRING(80) RETURNS CSTRING(80) FREE_IT ENTRY_POINT 'IB_UDF_lower' MODULE_NAME 'ib_udf'";
return $sql;
}
function _dropAutoIncrement($tabname)
{
if (strpos($tabname, '.') !== false) {
$tarr = explode('.', $tabname);
return 'DROP SEQUENCE ' . $tarr[0] . '."s_' . $tarr[1] . '"';
}
return 'DROP SEQUENCE s_' . $tabname;
}
function _createSuffix($fname, &$ftype, $fnotnull, $fdefault, $fautoinc, $fconstraint, $funsigned)
{
$suffix = '';
if (strlen($fdefault)) {
$suffix .= " DEFAULT $fdefault";
}
if ($fnotnull) {
$suffix .= ' NOT NULL';
}
if ($fautoinc) {
$this->seqField = $fname;
}
$fconstraint = preg_replace("/``/", "\"", $fconstraint);
if ($fconstraint) {
$suffix .= ' ' . $fconstraint;
}
return $suffix;
}
/**
* Generate the SQL to create table. Returns an array of sql strings.
*/
function createTableSQL($tabname, $flds, $tableoptions = array())
{
list($lines, $pkey, $idxs) = $this->_GenFields($flds, true);
// genfields can return FALSE at times
if ($lines == null) {
$lines = array();
}
$taboptions = $this->_Options($tableoptions);
$tabname = $this->TableName($tabname);
$sql = $this->_TableSQL($tabname, $lines, $pkey, $taboptions);
if ($this->autoIncrement && !isset($taboptions['DROP'])) {
$tsql = $this->_Triggers($tabname, $taboptions);
foreach ($tsql as $s) {
$sql[] = $s;
}
}
if (is_array($idxs)) {
foreach ($idxs as $idx => $idxdef) {
$sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
$sql = array_merge($sql, $sql_idxs);
}
}
return $sql;
}
/*
CREATE or replace TRIGGER jaddress_insert
before insert on jaddress
for each row
begin
IF ( NEW."seqField" IS NULL OR NEW."seqField" = 0 ) THEN
NEW."seqField" = GEN_ID("GEN_tabname", 1);
end;
*/
function _triggers($tabname, $taboptions)
{
if (!$this->seqField) {
return array();
}
$tab1 = preg_replace('/"/', '', $tabname);
if ($this->schema) {
$t = strpos($tab1, '.');
if ($t !== false) {
$tab = substr($tab1, $t + 1);
} else {
$tab = $tab1;
}
$seqField = $this->seqField;
$seqname = $this->schema . '.' . $this->seqPrefix . $tab;
$trigname = $this->schema . '.t_' . $this->seqPrefix . $tab;
} else {
$seqField = $this->seqField;
$seqname = $this->seqPrefix . $tab1;
$trigname = 't_' . $seqname;
}
if (isset($taboptions['DROP'])) {
$sql[] = "DROP SEQUENCE $seqname";
} elseif (isset($taboptions['REPLACE'])) {
$sql[] = "DROP SEQUENCE \"$seqname\"";
$sql[] = "CREATE SEQUENCE \"$seqname\"";
$sql[] = "ALTER TRIGGER \"$trigname\" BEFORE INSERT OR UPDATE AS BEGIN IF ( NEW.$seqField IS NULL OR NEW.$seqField = 0 ) THEN NEW.$seqField = GEN_ID(\"$seqname\", 1); END";
} else {
$sql[] = "CREATE SEQUENCE $seqname";
$sql[] = "CREATE TRIGGER $trigname FOR $tabname BEFORE INSERT OR UPDATE AS BEGIN IF ( NEW.$seqField IS NULL OR NEW.$seqField = 0 ) THEN NEW.$seqField = GEN_ID($seqname, 1); END";
}
$this->seqField = false;
return $sql;
}
/**
* Change the definition of one column
*
* @param string $tabname table-name
* @param string $flds column-name and type for the changed column
* @param string $tableflds Unused
* @param array|string $tableoptions Unused
*
* @return array with SQL strings
*/
public function alterColumnSQL($tabname, $flds, $tableflds = '', $tableoptions = '')
{
$tabname = $this->TableName($tabname);
$sql = array();
list($lines, , $idxs) = $this->_GenFields($flds);
// genfields can return FALSE at times
if ($lines == null) {
$lines = array();
}
$alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' ';
foreach ($lines as $v) {
/*
* The type must be preceded by the keyword 'TYPE'
*/
$vExplode = explode(' ', $v);
$vExplode = array_filter($vExplode);
array_splice($vExplode, 1, 0, array('TYPE'));
$v = implode(' ', $vExplode);
$sql[] = $alter . $v;
}
if (is_array($idxs)) {
foreach ($idxs as $idx => $idxdef) {
$sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
$sql = array_merge($sql, $sql_idxs);
}
}
return $sql;
}
}
PK ⒨T;Q Q datadict/datadict-ibase.inc.phpnu ٘ connection->customMetaTypes[$meta]))
return $this->connection->customMetaTypes[$meta]['actual'];
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL':
case 'X': return 'VARCHAR(4000)';
case 'C2': return 'VARCHAR'; // up to 32K
case 'X2': return 'VARCHAR(4000)';
case 'B': return 'BLOB';
case 'D': return 'DATE';
case 'TS':
case 'T': return 'TIMESTAMP';
case 'L': return 'SMALLINT';
case 'I': return 'INTEGER';
case 'I1': return 'SMALLINT';
case 'I2': return 'SMALLINT';
case 'I4': return 'INTEGER';
case 'I8': return 'INTEGER';
case 'F': return 'DOUBLE PRECISION';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
function AlterColumnSQL($tabname, $flds, $tableflds='', $tableoptions='')
{
if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
return array();
}
function DropColumnSQL($tabname, $flds, $tableflds='', $tableoptions='')
{
if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
return array();
}
}
PK ⒨TW datadict/datadict-mysql.inc.phpnu ٘ type;
$len = $fieldobj->max_length;
}
$is_serial = is_object($fieldobj) && $fieldobj->primary_key && $fieldobj->auto_increment;
$len = -1; // mysql max_length is not accurate
$t = strtoupper($t);
if (array_key_exists($t,$this->connection->customActualTypes))
return $this->connection->customActualTypes[$t];
switch ($t) {
case 'STRING':
case 'CHAR':
case 'VARCHAR':
case 'TINYBLOB':
case 'TINYTEXT':
case 'ENUM':
case 'SET':
if ($len <= $this->blobSize) return 'C';
case 'TEXT':
case 'LONGTEXT':
case 'MEDIUMTEXT':
return 'X';
// php_mysql extension always returns 'blob' even if 'text'
// so we have to check whether binary...
case 'IMAGE':
case 'LONGBLOB':
case 'BLOB':
case 'MEDIUMBLOB':
return !empty($fieldobj->binary) ? 'B' : 'X';
case 'YEAR':
case 'DATE': return 'D';
case 'TIME':
case 'DATETIME':
case 'TIMESTAMP': return 'T';
case 'FLOAT':
case 'DOUBLE':
return 'F';
case 'INT':
case 'INTEGER': return $is_serial ? 'R' : 'I';
case 'TINYINT': return $is_serial ? 'R' : 'I1';
case 'SMALLINT': return $is_serial ? 'R' : 'I2';
case 'MEDIUMINT': return $is_serial ? 'R' : 'I4';
case 'BIGINT': return $is_serial ? 'R' : 'I8';
default:
return ADODB_DEFAULT_METATYPE;
}
}
function ActualType($meta)
{
$meta = strtoupper($meta);
/*
* Add support for custom meta types. We do this
* first, that allows us to override existing types
*/
if (isset($this->connection->customMetaTypes[$meta]))
return $this->connection->customMetaTypes[$meta]['actual'];
switch($meta)
{
case 'C': return 'VARCHAR';
case 'XL':return 'LONGTEXT';
case 'X': return 'TEXT';
case 'C2': return 'VARCHAR';
case 'X2': return 'LONGTEXT';
case 'B': return 'LONGBLOB';
case 'D': return 'DATE';
case 'TS':
case 'T': return 'DATETIME';
case 'L': return 'TINYINT';
case 'R':
case 'I4':
case 'I': return 'INTEGER';
case 'I1': return 'TINYINT';
case 'I2': return 'SMALLINT';
case 'I8': return 'BIGINT';
case 'F': return 'DOUBLE';
case 'N': return 'NUMERIC';
default:
return $meta;
}
}
// return string must begin with space
function _CreateSuffix($fname,&$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
{
$suffix = '';
if ($funsigned) $suffix .= ' UNSIGNED';
if ($fnotnull) $suffix .= ' NOT NULL';
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fautoinc) $suffix .= ' AUTO_INCREMENT';
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
/*
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name [(create_definition,...)]
[table_options] [select_statement]
create_definition:
col_name type [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT]
[PRIMARY KEY] [reference_definition]
or PRIMARY KEY (index_col_name,...)
or KEY [index_name] (index_col_name,...)
or INDEX [index_name] (index_col_name,...)
or UNIQUE [INDEX] [index_name] (index_col_name,...)
or FULLTEXT [INDEX] [index_name] (index_col_name,...)
or [CONSTRAINT symbol] FOREIGN KEY [index_name] (index_col_name,...)
[reference_definition]
or CHECK (expr)
*/
/*
CREATE [UNIQUE|FULLTEXT] INDEX index_name
ON tbl_name (col_name[(length)],... )
*/
function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
{
$sql = array();
if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
if ($this->alterTableAddIndex) $sql[] = "ALTER TABLE $tabname DROP INDEX $idxname";
else $sql[] = sprintf($this->dropIndex, $idxname, $tabname);
if ( isset($idxoptions['DROP']) )
return $sql;
}
if ( empty ($flds) ) {
return $sql;
}
if (isset($idxoptions['FULLTEXT'])) {
$unique = ' FULLTEXT';
} elseif (isset($idxoptions['UNIQUE'])) {
$unique = ' UNIQUE';
} else {
$unique = '';
}
if ( is_array($flds) ) $flds = implode(', ',$flds);
if ($this->alterTableAddIndex) $s = "ALTER TABLE $tabname ADD $unique INDEX $idxname ";
else $s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname;
$s .= ' (' . $flds . ')';
if ( isset($idxoptions[$this->upperName]) )
$s .= $idxoptions[$this->upperName];
$sql[] = $s;
return $sql;
}
}
PK ⒨T; datadict/datadict-sybase.inc.phpnu ٘ type;
$len = $fieldobj->max_length;
}
$t = strtoupper($t);
if (array_key_exists($t,$this->connection->customActualTypes))
return $this->connection->customActualTypes[$t];
$len = -1; // mysql max_length is not accurate
switch ($t) {
case 'INT':
case 'INTEGER': return 'I';
case 'BIT':
case 'TINYINT': return 'I1';
case 'SMALLINT': return 'I2';
case 'BIGINT': return 'I8';
case 'REAL':
case 'FLOAT': return 'F';
default: return parent::MetaType($t,$len,$fieldobj);
}
}
function ActualType($meta)
{
$meta = strtoupper($meta);
/*
* Add support for custom meta types. We do this
* first, that allows us to override existing types
*/
if (isset($this->connection->customMetaTypes[$meta]))
return $this->connection->customMetaTypes[$meta]['actual'];
switch(strtoupper($meta)) {
case 'C': return 'VARCHAR';
case 'XL':
case 'X': return 'TEXT';
case 'C2': return 'NVARCHAR';
case 'X2': return 'NTEXT';
case 'B': return 'IMAGE';
case 'D': return 'DATETIME';
case 'TS':
case 'T': return 'DATETIME';
case 'L': return 'BIT';
case 'I': return 'INT';
case 'I1': return 'TINYINT';
case 'I2': return 'SMALLINT';
case 'I4': return 'INT';
case 'I8': return 'BIGINT';
case 'F': return 'REAL';
case 'N': return 'NUMERIC';
default:
return $meta;
}
}
function AddColumnSQL($tabname, $flds)
{
$tabname = $this->TableName ($tabname);
$f = array();
list($lines,$pkey) = $this->_GenFields($flds);
$s = "ALTER TABLE $tabname $this->addCol";
foreach($lines as $v) {
$f[] = "\n $v";
}
$s .= implode(', ',$f);
$sql[] = $s;
return $sql;
}
function AlterColumnSQL($tabname, $flds, $tableflds='', $tableoptions='')
{
$tabname = $this->TableName ($tabname);
$sql = array();
list($lines,$pkey) = $this->_GenFields($flds);
foreach($lines as $v) {
$sql[] = "ALTER TABLE $tabname $this->alterCol $v";
}
return $sql;
}
function DropColumnSQL($tabname, $flds, $tableflds='', $tableoptions='')
{
$tabname = $this->TableName($tabname);
if (!is_array($flds)) $flds = explode(',',$flds);
$f = array();
$s = "ALTER TABLE $tabname";
foreach($flds as $v) {
$f[] = "\n$this->dropCol ".$this->NameQuote($v);
}
$s .= implode(', ',$f);
$sql[] = $s;
return $sql;
}
// return string must begin with space
function _CreateSuffix($fname,&$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
{
$suffix = '';
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fautoinc) $suffix .= ' DEFAULT AUTOINCREMENT';
if ($fnotnull) $suffix .= ' NOT NULL';
else if ($suffix == '') $suffix .= ' NULL';
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
/*
CREATE TABLE
[ database_name.[ owner ] . | owner. ] table_name
( { < column_definition >
| column_name AS computed_column_expression
| < table_constraint > ::= [ CONSTRAINT constraint_name ] }
| [ { PRIMARY KEY | UNIQUE } [ ,...n ]
)
[ ON { filegroup | DEFAULT } ]
[ TEXTIMAGE_ON { filegroup | DEFAULT } ]
< column_definition > ::= { column_name data_type }
[ COLLATE < collation_name > ]
[ [ DEFAULT constant_expression ]
| [ IDENTITY [ ( seed , increment ) [ NOT FOR REPLICATION ] ] ]
]
[ ROWGUIDCOL]
[ < column_constraint > ] [ ...n ]
< column_constraint > ::= [ CONSTRAINT constraint_name ]
{ [ NULL | NOT NULL ]
| [ { PRIMARY KEY | UNIQUE }
[ CLUSTERED | NONCLUSTERED ]
[ WITH FILLFACTOR = fillfactor ]
[ON {filegroup | DEFAULT} ] ]
]
| [ [ FOREIGN KEY ]
REFERENCES ref_table [ ( ref_column ) ]
[ ON DELETE { CASCADE | NO ACTION } ]
[ ON UPDATE { CASCADE | NO ACTION } ]
[ NOT FOR REPLICATION ]
]
| CHECK [ NOT FOR REPLICATION ]
( logical_expression )
}
< table_constraint > ::= [ CONSTRAINT constraint_name ]
{ [ { PRIMARY KEY | UNIQUE }
[ CLUSTERED | NONCLUSTERED ]
{ ( column [ ASC | DESC ] [ ,...n ] ) }
[ WITH FILLFACTOR = fillfactor ]
[ ON { filegroup | DEFAULT } ]
]
| FOREIGN KEY
[ ( column [ ,...n ] ) ]
REFERENCES ref_table [ ( ref_column [ ,...n ] ) ]
[ ON DELETE { CASCADE | NO ACTION } ]
[ ON UPDATE { CASCADE | NO ACTION } ]
[ NOT FOR REPLICATION ]
| CHECK [ NOT FOR REPLICATION ]
( search_conditions )
}
*/
/*
CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name
ON { table | view } ( column [ ASC | DESC ] [ ,...n ] )
[ WITH < index_option > [ ,...n] ]
[ ON filegroup ]
< index_option > :: =
{ PAD_INDEX |
FILLFACTOR = fillfactor |
IGNORE_DUP_KEY |
DROP_EXISTING |
STATISTICS_NORECOMPUTE |
SORT_IN_TEMPDB
}
*/
function _IndexSQL($idxname, $tabname, $flds, $idxoptions)
{
$sql = array();
if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
$sql[] = sprintf ($this->dropIndex, $idxname, $tabname);
if ( isset($idxoptions['DROP']) )
return $sql;
}
if ( empty ($flds) ) {
return $sql;
}
$unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
$clustered = isset($idxoptions['CLUSTERED']) ? ' CLUSTERED' : '';
if ( is_array($flds) )
$flds = implode(', ',$flds);
$s = 'CREATE' . $unique . $clustered . ' INDEX ' . $idxname . ' ON ' . $tabname . ' (' . $flds . ')';
if ( isset($idxoptions[$this->upperName]) )
$s .= $idxoptions[$this->upperName];
$sql[] = $s;
return $sql;
}
}
PK ⒨T,u ! datadict/datadict-generic.inc.phpnu ٘ connection->customMetaTypes[$meta]))
return $this->connection->customMetaTypes[$meta]['actual'];
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL':
case 'X': return 'VARCHAR(250)';
case 'C2': return 'VARCHAR';
case 'X2': return 'VARCHAR(250)';
case 'B': return 'VARCHAR';
case 'D': return 'DATE';
case 'TS':
case 'T': return 'DATE';
case 'L': return 'DECIMAL(1)';
case 'I': return 'DECIMAL(10)';
case 'I1': return 'DECIMAL(3)';
case 'I2': return 'DECIMAL(5)';
case 'I4': return 'DECIMAL(10)';
case 'I8': return 'DECIMAL(20)';
case 'F': return 'DECIMAL(32,8)';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
function AlterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
{
if ($this->debug) ADOConnection::outp("AlterColumnSQL not supported");
return array();
}
function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
{
if ($this->debug) ADOConnection::outp("DropColumnSQL not supported");
return array();
}
}
/*
//db2
function ActualType($meta)
{
switch($meta) {
case 'C': return 'VARCHAR';
case 'X': return 'VARCHAR';
case 'C2': return 'VARCHAR'; // up to 32K
case 'X2': return 'VARCHAR';
case 'B': return 'BLOB';
case 'D': return 'DATE';
case 'T': return 'TIMESTAMP';
case 'L': return 'SMALLINT';
case 'I': return 'INTEGER';
case 'I1': return 'SMALLINT';
case 'I2': return 'SMALLINT';
case 'I4': return 'INTEGER';
case 'I8': return 'BIGINT';
case 'F': return 'DOUBLE';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
// ifx
function ActualType($meta)
{
switch($meta) {
case 'C': return 'VARCHAR';// 255
case 'X': return 'TEXT';
case 'C2': return 'NVARCHAR';
case 'X2': return 'TEXT';
case 'B': return 'BLOB';
case 'D': return 'DATE';
case 'T': return 'DATETIME';
case 'L': return 'SMALLINT';
case 'I': return 'INTEGER';
case 'I1': return 'SMALLINT';
case 'I2': return 'SMALLINT';
case 'I4': return 'INTEGER';
case 'I8': return 'DECIMAL(20)';
case 'F': return 'FLOAT';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
*/
PK ⒨TU3I I " datadict/datadict-postgres.inc.phpnu ٘ type;
$len = $fieldobj->max_length;
}
$t = strtoupper($t);
if (array_key_exists($t,$this->connection->customActualTypes))
return $this->connection->customActualTypes[$t];
$is_serial = is_object($fieldobj) && !empty($fieldobj->primary_key) && !empty($fieldobj->unique) &&
!empty($fieldobj->has_default) && substr($fieldobj->default_value,0,8) == 'nextval(';
switch ($t) {
case 'INTERVAL':
case 'CHAR':
case 'CHARACTER':
case 'VARCHAR':
case 'NAME':
case 'BPCHAR':
if ($len <= $this->blobSize) return 'C';
case 'TEXT':
return 'X';
case 'IMAGE': // user defined type
case 'BLOB': // user defined type
case 'BIT': // This is a bit string, not a single bit, so don't return 'L'
case 'VARBIT':
case 'BYTEA':
return 'B';
case 'BOOL':
case 'BOOLEAN':
return 'L';
case 'DATE':
return 'D';
case 'TIME':
case 'DATETIME':
case 'TIMESTAMP':
case 'TIMESTAMPTZ':
return 'T';
case 'INTEGER': return !$is_serial ? 'I' : 'R';
case 'SMALLINT':
case 'INT2': return !$is_serial ? 'I2' : 'R';
case 'INT4': return !$is_serial ? 'I4' : 'R';
case 'BIGINT':
case 'INT8': return !$is_serial ? 'I8' : 'R';
case 'OID':
case 'SERIAL':
return 'R';
case 'FLOAT4':
case 'FLOAT8':
case 'DOUBLE PRECISION':
case 'REAL':
return 'F';
default:
return ADODB_DEFAULT_METATYPE;
}
}
function actualType($meta)
{
$meta = strtoupper($meta);
/*
* Add support for custom meta types. We do this
* first, that allows us to override existing types
*/
if (isset($this->connection->customMetaTypes[$meta]))
return $this->connection->customMetaTypes[$meta]['actual'];
switch ($meta) {
case 'C': return 'VARCHAR';
case 'XL':
case 'X': return 'TEXT';
case 'C2': return 'VARCHAR';
case 'X2': return 'TEXT';
case 'B': return 'BYTEA';
case 'D': return 'DATE';
case 'TS':
case 'T': return 'TIMESTAMP';
case 'L': return 'BOOLEAN';
case 'I': return 'INTEGER';
case 'I1': return 'SMALLINT';
case 'I2': return 'INT2';
case 'I4': return 'INT4';
case 'I8': return 'INT8';
case 'F': return 'FLOAT8';
case 'N': return 'NUMERIC';
default:
return $meta;
}
}
/**
* Adding a new Column
*
* reimplementation of the default function as postgres does NOT allow to set the default in the same statement
*
* @param string $tabname table-name
* @param string $flds column-names and types for the changed columns
* @return array with SQL strings
*/
function addColumnSQL($tabname, $flds)
{
$tabname = $this->tableName($tabname);
$sql = array();
$not_null = false;
list($lines,$pkey) = $this->_genFields($flds);
$alter = 'ALTER TABLE ' . $tabname . $this->addCol . ' ';
foreach($lines as $v) {
if (($not_null = preg_match('/NOT NULL/i',$v))) {
$v = preg_replace('/NOT NULL/i','',$v);
}
if (preg_match('/^([^ ]+) .*DEFAULT (\'[^\']+\'|\"[^\"]+\"|[^ ]+)/',$v,$matches)) {
list(,$colname,$default) = $matches;
$sql[] = $alter . str_replace('DEFAULT '.$default,'',$v);
$sql[] = 'UPDATE '.$tabname.' SET '.$colname.'='.$default.' WHERE '.$colname.' IS NULL ';
$sql[] = 'ALTER TABLE '.$tabname.' ALTER COLUMN '.$colname.' SET DEFAULT ' . $default;
} else {
$sql[] = $alter . $v;
}
if ($not_null) {
list($colname) = explode(' ',$v);
$sql[] = 'ALTER TABLE '.$tabname.' ALTER COLUMN '.$colname.' SET NOT NULL';
}
}
return $sql;
}
function dropIndexSQL($idxname, $tabname = NULL)
{
return array(sprintf($this->dropIndex, $this->tableName($idxname), $this->tableName($tabname)));
}
/**
* Change the definition of one column
*
* Postgres can't do that on its own, you need to supply the complete
* definition of the new table, to allow recreating the table and copying
* the content over to the new table.
*
* @param string $tabname table-name
* @param string $flds column-name and type for the changed column
* @param string $tableflds complete definition of the new table, e.g. for postgres, default ''
* @param array $tableoptions options for the new table {@see CreateTableSQL()}, default ''
*
* @return array with SQL strings
*/
function alterColumnSQL($tabname, $flds, $tableflds='', $tableoptions='')
{
// Check if alter single column datatype available - works with 8.0+
$has_alter_column = 8.0 <= (float) @$this->serverInfo['version'];
if ($has_alter_column) {
$tabname = $this->tableName($tabname);
$sql = array();
list($lines,$pkey) = $this->_genFields($flds);
$set_null = false;
foreach($lines as $v) {
$alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' ';
if ($not_null = preg_match('/NOT NULL/i',$v)) {
$v = preg_replace('/NOT NULL/i','',$v);
}
// this next block doesn't work - there is no way that I can see to
// explicitly ask a column to be null using $flds
elseif ($set_null = preg_match('/NULL/i',$v)) {
// if they didn't specify not null, see if they explicitly asked for null
// Lookbehind pattern covers the case 'fieldname NULL datatype DEFAULT NULL'
// only the first NULL should be removed, not the one specifying
// the default value
$v = preg_replace('/(?metaColumns($tabname);
list(,$colname,$default) = $matches;
$alter .= $colname;
if ($this->connection) {
$old_coltype = $this->connection->metaType($existing[strtoupper($colname)]);
} else {
$old_coltype = $t;
}
$v = preg_replace('/^' . preg_quote($colname) . '\s/', '', $v);
$t = trim(str_replace('DEFAULT '.$default,'',$v));
// Type change from bool to int
if ( $old_coltype == 'L' && $t == 'INTEGER' ) {
$sql[] = $alter . ' DROP DEFAULT';
$sql[] = $alter . " TYPE $t USING ($colname::BOOL)::INT";
$sql[] = $alter . " SET DEFAULT $default";
}
// Type change from int to bool
else if ( $old_coltype == 'I' && $t == 'BOOLEAN' ) {
if( strcasecmp('NULL', trim($default)) != 0 ) {
$default = $this->connection->qstr($default);
}
$sql[] = $alter . ' DROP DEFAULT';
$sql[] = $alter . " TYPE $t USING CASE WHEN $colname = 0 THEN false ELSE true END";
$sql[] = $alter . " SET DEFAULT $default";
}
// Any other column types conversion
else {
$sql[] = $alter . " TYPE $t";
$sql[] = $alter . " SET DEFAULT $default";
}
}
else {
// drop default?
preg_match ('/^\s*(\S+)\s+(.*)$/',$v,$matches);
list (,$colname,$rest) = $matches;
$alter .= $colname;
$sql[] = $alter . ' TYPE ' . $rest;
}
#list($colname) = explode(' ',$v);
if ($not_null) {
// this does not error out if the column is already not null
$sql[] = $alter . ' SET NOT NULL';
}
if ($set_null) {
// this does not error out if the column is already null
$sql[] = $alter . ' DROP NOT NULL';
}
}
return $sql;
}
// does not have alter column
if (!$tableflds) {
if ($this->debug) ADOConnection::outp("AlterColumnSQL needs a complete table-definiton for PostgreSQL");
return array();
}
return $this->_recreate_copy_table($tabname, false, $tableflds,$tableoptions);
}
/**
* Drop one column
*
* Postgres < 7.3 can't do that on it's own, you need to supply the complete definition of the new table,
* to allow, recreating the table and copying the content over to the new table
* @param string $tabname table-name
* @param string $flds column-name and type for the changed column
* @param string $tableflds complete definition of the new table, eg. for postgres, default ''
* @param array $tableoptions options for the new table {@see CreateTableSQL}, default []
* @return array with SQL strings
*/
function dropColumnSQL($tabname, $flds, $tableflds='', $tableoptions='')
{
$has_drop_column = 7.3 <= (float) @$this->serverInfo['version'];
if (!$has_drop_column && !$tableflds) {
if ($this->debug) {
ADOConnection::outp("dropColumnSQL needs complete table-definiton for PostgreSQL < 7.3");
}
return array();
}
if ($has_drop_column) {
return ADODB_DataDict::dropColumnSQL($tabname, $flds);
}
return $this->_recreate_copy_table($tabname, $flds, $tableflds, $tableoptions);
}
/**
* Save the content into a temp. table, drop and recreate the original table and copy the content back in
*
* We also take care to set the values of the sequenz and recreate the indexes.
* All this is done in a transaction, to not loose the content of the table, if something went wrong!
* @internal
* @param string $tabname table-name
* @param string $dropflds column-names to drop
* @param string $tableflds complete definition of the new table, eg. for postgres
* @param array|string $tableoptions options for the new table see CreateTableSQL, default ''
* @return array with SQL strings
*/
function _recreate_copy_table($tabname, $dropflds, $tableflds, $tableoptions='')
{
if ($dropflds && !is_array($dropflds)) $dropflds = explode(',',$dropflds);
$copyflds = array();
foreach($this->metaColumns($tabname) as $fld) {
if (preg_match('/'.$fld->name.' (\w+)/i', $tableflds, $matches)) {
$new_type = strtoupper($matches[1]);
// AlterColumn of a char column to a nummeric one needs an explicit conversation
if (in_array($new_type, array('I', 'I2', 'I4', 'I8', 'N', 'F')) &&
in_array($fld->type, array('varchar','char','text','bytea'))
) {
$copyflds[] = "to_number($fld->name,'S9999999999999D99')";
} else {
// other column-type changes needs explicit decode, encode for bytea or cast otherwise
$new_actual_type = $this->actualType($new_type);
if (strtoupper($fld->type) != $new_actual_type) {
if ($new_actual_type == 'BYTEA' && $fld->type == 'text') {
$copyflds[] = "DECODE($fld->name, 'escape')";
} elseif ($fld->type == 'bytea' && $new_actual_type == 'TEXT') {
$copyflds[] = "ENCODE($fld->name, 'escape')";
} else {
$copyflds[] = "CAST($fld->name AS $new_actual_type)";
}
}
}
} else {
$copyflds[] = $fld->name;
}
// identify the sequence name and the fld its on
if ($fld->primary_key && $fld->has_default &&
preg_match("/nextval\('([^']+)'::(text|regclass)\)/", $fld->default_value, $matches)) {
$seq_name = $matches[1];
$seq_fld = $fld->name;
}
}
$copyflds = implode(', ', $copyflds);
$tempname = $tabname.'_tmp';
$aSql[] = 'BEGIN'; // we use a transaction, to make sure not to loose the content of the table
$aSql[] = "SELECT * INTO TEMPORARY TABLE $tempname FROM $tabname";
$aSql = array_merge($aSql,$this->dropTableSQL($tabname));
$aSql = array_merge($aSql,$this->createTableSQL($tabname, $tableflds, $tableoptions));
$aSql[] = "INSERT INTO $tabname SELECT $copyflds FROM $tempname";
if ($seq_name && $seq_fld) { // if we have a sequence we need to set it again
$seq_name = $tabname.'_'.$seq_fld.'_seq'; // has to be the name of the new implicit sequence
$aSql[] = "SELECT setval('$seq_name', MAX($seq_fld)) FROM $tabname";
}
$aSql[] = "DROP TABLE $tempname";
// recreate the indexes, if they not contain one of the dropped columns
foreach($this->metaIndexes($tabname) as $idx_name => $idx_data) {
if (substr($idx_name,-5) != '_pkey' && (!$dropflds || !count(array_intersect($dropflds,$idx_data['columns'])))) {
$aSql = array_merge($aSql,$this->createIndexSQL($idx_name, $tabname, $idx_data['columns'],
$idx_data['unique'] ? array('UNIQUE') : false));
}
}
$aSql[] = 'COMMIT';
return $aSql;
}
function dropTableSQL($tabname)
{
$sql = ADODB_DataDict::dropTableSQL($tabname);
$drop_seq = $this->_dropAutoIncrement($tabname);
if ($drop_seq) {
$sql[] = $drop_seq;
}
return $sql;
}
// return string must begin with space
function _createSuffix($fname, &$ftype, $fnotnull, $fdefault, $fautoinc, $fconstraint, $funsigned)
{
if ($fautoinc) {
$ftype = 'SERIAL';
return '';
}
$suffix = '';
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fnotnull) $suffix .= ' NOT NULL';
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
// search for a sequence for the given table (asumes the seqence-name contains the table-name!)
// if yes return sql to drop it
// this is still necessary if postgres < 7.3 or the SERIAL was created on an earlier version!!!
function _dropAutoIncrement($tabname)
{
$tabname = $this->connection->quote('%'.$tabname.'%');
$seq = $this->connection->getOne("SELECT relname FROM pg_class WHERE NOT relname ~ 'pg_.*' AND relname LIKE $tabname AND relkind='S'");
// check if a tables depends on the sequence and it therefore can't and don't need to be dropped separately
if (!$seq || $this->connection->getOne("SELECT relname FROM pg_class JOIN pg_depend ON pg_class.relfilenode=pg_depend.objid WHERE relname='$seq' AND relkind='S' AND deptype='i'")) {
return false;
}
return "DROP SEQUENCE ".$seq;
}
function renameTableSQL($tabname, $newname)
{
if (!empty($this->schema)) {
$rename_from = $this->tableName($tabname);
$schema_save = $this->schema;
$this->schema = false;
$rename_to = $this->tableName($newname);
$this->schema = $schema_save;
return array (sprintf($this->renameTable, $rename_from, $rename_to));
}
return array (sprintf($this->renameTable, $this->tableName($tabname), $this->tableName($newname)));
}
/*
CREATE [ [ LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name (
{ column_name data_type [ DEFAULT default_expr ] [ column_constraint [, ... ] ]
| table_constraint } [, ... ]
)
[ INHERITS ( parent_table [, ... ] ) ]
[ WITH OIDS | WITHOUT OIDS ]
where column_constraint is:
[ CONSTRAINT constraint_name ]
{ NOT NULL | NULL | UNIQUE | PRIMARY KEY |
CHECK (expression) |
REFERENCES reftable [ ( refcolumn ) ] [ MATCH FULL | MATCH PARTIAL ]
[ ON DELETE action ] [ ON UPDATE action ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
and table_constraint is:
[ CONSTRAINT constraint_name ]
{ UNIQUE ( column_name [, ... ] ) |
PRIMARY KEY ( column_name [, ... ] ) |
CHECK ( expression ) |
FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ]
[ MATCH FULL | MATCH PARTIAL ] [ ON DELETE action ] [ ON UPDATE action ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
*/
/*
CREATE [ UNIQUE ] INDEX index_name ON table
[ USING acc_method ] ( column [ ops_name ] [, ...] )
[ WHERE predicate ]
CREATE [ UNIQUE ] INDEX index_name ON table
[ USING acc_method ] ( func_name( column [, ... ]) [ ops_name ] )
[ WHERE predicate ]
*/
function _indexSQL($idxname, $tabname, $flds, $idxoptions)
{
$sql = array();
if ( isset($idxoptions['REPLACE']) || isset($idxoptions['DROP']) ) {
$sql[] = sprintf ($this->dropIndex, $idxname, $tabname);
if ( isset($idxoptions['DROP']) ) {
return $sql;
}
}
if (empty($flds)) {
return $sql;
}
$unique = isset($idxoptions['UNIQUE']) ? ' UNIQUE' : '';
$s = 'CREATE' . $unique . ' INDEX ' . $idxname . ' ON ' . $tabname . ' ';
if (isset($idxoptions['HASH'])) {
$s .= 'USING HASH ';
}
if (isset($idxoptions[$this->upperName])) {
$s .= $idxoptions[$this->upperName];
}
if (is_array($flds)) {
$flds = implode(', ', $flds);
}
$s .= '(' . $flds . ')';
$sql[] = $s;
return $sql;
}
function _getSize($ftype, $ty, $fsize, $fprec, $options=false)
{
if (strlen($fsize) && $ty != 'X' && $ty != 'B' && $ty != 'I' && strpos($ftype,'(') === false) {
$ftype .= "(".$fsize;
if (strlen($fprec)) $ftype .= ",".$fprec;
$ftype .= ')';
}
/*
* Handle additional options
*/
if (is_array($options)) {
foreach($options as $type=>$value) {
switch ($type) {
case 'ENUM':
$ftype .= '(' . $value . ')';
break;
default:
}
}
}
return $ftype;
}
function changeTableSQL($tablename, $flds, $tableoptions = false, $dropOldFlds=false)
{
global $ADODB_FETCH_MODE;
parent::changeTableSQL($tablename, $flds);
$save = $ADODB_FETCH_MODE;
$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
if ($this->connection->fetchMode !== false) {
$savem = $this->connection->setFetchMode(false);
}
// check table exists
$save_handler = $this->connection->raiseErrorFn;
$this->connection->raiseErrorFn = '';
$cols = $this->metaColumns($tablename);
$this->connection->raiseErrorFn = $save_handler;
if (isset($savem)) {
$this->connection->setFetchMode($savem);
}
$ADODB_FETCH_MODE = $save;
$sqlResult=array();
if ( empty($cols)) {
$sqlResult=$this->createTableSQL($tablename, $flds, $tableoptions);
} else {
$sqlResultAdd = $this->addColumnSQL($tablename, $flds);
$sqlResultAlter = $this->alterColumnSQL($tablename, $flds, '', $tableoptions);
$sqlResult = array_merge((array)$sqlResultAdd, (array)$sqlResultAlter);
if ($dropOldFlds) {
// already exists, alter table instead
list($lines,$pkey,$idxs) = $this->_genFields($flds);
// genfields can return FALSE at times
if ($lines == null) {
$lines = array();
}
$alter = 'ALTER TABLE ' . $this->tableName($tablename);
foreach ( $cols as $id => $v ) {
if ( !isset($lines[$id]) ) {
$sqlResult[] = $alter . $this->dropCol . ' ' . $v->name;
}
}
}
}
return $sqlResult;
}
} // end class
PK ⒨T @ datadict/datadict-db2.inc.phpnu ٘ connection->customMetaTypes[$meta]))
return $this->connection->customMetaTypes[$meta]['actual'];
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL': return 'CLOB';
case 'X': return 'VARCHAR(3600)';
case 'C2': return 'VARCHAR'; // up to 32K
case 'X2': return 'VARCHAR(3600)'; // up to 32000, but default page size too small
case 'B': return 'BLOB';
case 'D': return 'DATE';
case 'TS':
case 'T': return 'TIMESTAMP';
case 'L': return 'SMALLINT';
case 'I': return 'INTEGER';
case 'I1': return 'SMALLINT';
case 'I2': return 'SMALLINT';
case 'I4': return 'INTEGER';
case 'I8': return 'BIGINT';
case 'F': return 'DOUBLE';
case 'N': return 'DECIMAL';
default:
return $meta;
}
}
// return string must begin with space
function _CreateSuffix($fname,&$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
{
$suffix = '';
if ($fautoinc) return ' GENERATED ALWAYS AS IDENTITY'; # as identity start with
if (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fnotnull) $suffix .= ' NOT NULL';
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
function alterColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
{
$tabname = $this->TableName ($tabname);
$sql = array();
list($lines,$pkey,$idxs) = $this->_GenFields($flds);
// genfields can return FALSE at times
if ($lines == null) $lines = array();
$alter = 'ALTER TABLE ' . $tabname . $this->alterCol . ' ';
$dataTypeWords = array('SET','DATA','TYPE');
foreach($lines as $v)
{
/*
* We must now post-process the line to insert the 'SET DATA TYPE'
* text into the alter statement
*/
$e = explode(' ',$v);
array_splice($e,1,0,$dataTypeWords);
$v = implode(' ',$e);
$sql[] = $alter . $v;
}
if (is_array($idxs))
{
foreach($idxs as $idx => $idxdef) {
$sql_idxs = $this->CreateIndexSql($idx, $tabname, $idxdef['cols'], $idxdef['opts']);
$sql = array_merge($sql, $sql_idxs);
}
}
return $sql;
}
function dropColumnSql($tabname, $flds, $tableflds='',$tableoptions='')
{
$tabname = $this->connection->getMetaCasedValue($tabname);
$flds = $this->connection->getMetaCasedValue($flds);
if (ADODB_ASSOC_CASE == ADODB_ASSOC_CASE_NATIVE )
{
/*
* METACASE_NATIVE
*/
$tabname = $this->connection->nameQuote . $tabname . $this->connection->nameQuote;
$flds = $this->connection->nameQuote . $flds . $this->connection->nameQuote;
}
$sql = sprintf($this->dropCol,$tabname,$flds);
return (array)$sql;
}
function changeTableSQL($tablename, $flds, $tableoptions = false, $dropOldFields=false)
{
/**
Allow basic table changes to DB2 databases
DB2 will fatally reject changes to non character columns
*/
$validTypes = array("CHAR","VARC");
$invalidTypes = array("BIGI","BLOB","CLOB","DATE", "DECI","DOUB", "INTE", "REAL","SMAL", "TIME");
// check table exists
$cols = $this->metaColumns($tablename);
if ( empty($cols)) {
return $this->createTableSQL($tablename, $flds, $tableoptions);
}
// already exists, alter table instead
list($lines,$pkey) = $this->_GenFields($flds);
$alter = 'ALTER TABLE ' . $this->tableName($tablename);
$sql = array();
foreach ( $lines as $id => $v ) {
/*
* If the metaCasing was NATIVE the col returned with nameQuotes
* around the field. We need to remove this for the metaColumn
* match
*/
$id = str_replace($this->connection->nameQuote,'',$id);
if ( isset($cols[$id]) && is_object($cols[$id]) ) {
/**
If the first field of $v is the fieldname, and
the second is the field type/size, we assume its an
attempt to modify the column size, so check that it is allowed
$v can have an indeterminate number of blanks between the
fields, so account for that too
*/
$vargs = explode(' ' , $v);
// assume that $vargs[0] is the field name.
$i=0;
// Find the next non-blank value;
for ($i=1;$ialterCol . ' ' . $v;
} else {
$sql[] = $alter . $this->addCol . ' ' . $v;
}
}
return $sql;
}
}
PK ⒨TwXf datadict/datadict-sapdb.inc.phpnu ٘ connection->customMetaTypes[$meta]))
return $this->connection->customMetaTypes[$meta]['actual'];
switch($meta) {
case 'C': return 'VARCHAR';
case 'XL':
case 'X': return 'LONG';
case 'C2': return 'VARCHAR UNICODE';
case 'X2': return 'LONG UNICODE';
case 'B': return 'LONG';
case 'D': return 'DATE';
case 'TS':
case 'T': return 'TIMESTAMP';
case 'L': return 'BOOLEAN';
case 'I': return 'INTEGER';
case 'I1': return 'FIXED(3)';
case 'I2': return 'SMALLINT';
case 'I4': return 'INTEGER';
case 'I8': return 'FIXED(20)';
case 'F': return 'FLOAT(38)';
case 'N': return 'FIXED';
default:
return $meta;
}
}
function MetaType($t,$len=-1,$fieldobj=false)
{
if (is_object($t)) {
$fieldobj = $t;
$t = $fieldobj->type;
$len = $fieldobj->max_length;
}
$t = strtoupper($t);
if (array_key_exists($t,$this->connection->customActualTypes))
return $this->connection->customActualTypes[$t];
static $maxdb_type2adodb = array(
'VARCHAR' => 'C',
'CHARACTER' => 'C',
'LONG' => 'X', // no way to differ between 'X' and 'B' :-(
'DATE' => 'D',
'TIMESTAMP' => 'T',
'BOOLEAN' => 'L',
'INTEGER' => 'I4',
'SMALLINT' => 'I2',
'FLOAT' => 'F',
'FIXED' => 'N',
);
$type = isset($maxdb_type2adodb[$t]) ? $maxdb_type2adodb[$t] : ADODB_DEFAULT_METATYPE;
// convert integer-types simulated with fixed back to integer
if ($t == 'FIXED' && !$fieldobj->scale && ($len == 20 || $len == 3)) {
$type = $len == 20 ? 'I8' : 'I1';
}
if ($fieldobj->auto_increment) $type = 'R';
return $type;
}
// return string must begin with space
function _CreateSuffix($fname,&$ftype,$fnotnull,$fdefault,$fautoinc,$fconstraint,$funsigned)
{
$suffix = '';
if ($funsigned) $suffix .= ' UNSIGNED';
if ($fnotnull) $suffix .= ' NOT NULL';
if ($fautoinc) $suffix .= ' DEFAULT SERIAL';
elseif (strlen($fdefault)) $suffix .= " DEFAULT $fdefault";
if ($fconstraint) $suffix .= ' '.$fconstraint;
return $suffix;
}
function AddColumnSQL($tabname, $flds)
{
$tabname = $this->TableName ($tabname);
$sql = array();
list($lines,$pkey) = $this->_GenFields($flds);
return array( 'ALTER TABLE ' . $tabname . ' ADD (' . implode(', ',$lines) . ')' );
}
function AlterColumnSQL($tabname, $flds, $tableflds='', $tableoptions='')
{
$tabname = $this->TableName ($tabname);
$sql = array();
list($lines,$pkey) = $this->_GenFields($flds);
return array( 'ALTER TABLE ' . $tabname . ' MODIFY (' . implode(', ',$lines) . ')' );
}
function DropColumnSQL($tabname, $flds, $tableflds='',$tableoptions='')
{
$tabname = $this->TableName ($tabname);
if (!is_array($flds)) $flds = explode(',',$flds);
foreach($flds as $k => $v) {
$flds[$k] = $this->NameQuote($v);
}
return array( 'ALTER TABLE ' . $tabname . ' DROP (' . implode(', ',$flds) . ')' );
}
}
PK ⒨T'#