Login   Register  
PHP Classes
elePHPant
Icontem

File: crdb.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Sandeep.C.R  >  CRDB  >  crdb.php  >  Download  
File: crdb.php
Role: Class source
Content type: text/plain
Description: main class file
Class: CRDB
Access data in MySQL tables using object notations
Author: By
Last change: // Fixed bug in join which wrongly guessing table columns for join,
// from the tables that are not yet seen.
Date: 3 years ago
Size: 30,502 bytes
 

Contents

Class file image Download
<?php
// Database Abstraction class 2011
// March 30 13:22:14 IST 2011

// Fixed bug in join which wrongly guessing table columns for join, from the tables that are not yet seen.
// Made UTF8 the default encoding
// Added a encoding property to set the default encoding,eg: $crdb->encoding = 'utf8'
// Fixed bug with delete when used with joins
// Added provision for specifien scalar values in joins on clasues using by casting value into object
// Bug fix in _row functon when rownum execced available rows
// Added _row($rowNum)  function to retrive $rowNum th row of result as a stdObj Object instead of rowset object
// Added Support for custom operators in select query when arrays are passed
// Added join column guessing,(to be tested)
// Fixed bug that causes bad sql when using or() and start_group()/_where() together
// Fixed bug that causes queries to run twice.
// Fixed _set_link function
// Added notice in case of non existant table during insert
// Added object support for group by to include mysql functions
// added custom result columns
// echo for debugging queries 
// Requires php version >=5.2.3
// sandeepcr2@gmail.com
class crdb_table
{
	private $table_name;
	private $parent;
	public  $insert_id;
	public  $affected_rows;
	function __construct()
	{
		@list($table_name,$parent)=func_get_args();
		$this->table_name=$table_name;
		$this->parent=$parent;
	}
	private function notice($msg)
	{
		if(function_exists('debug_backtrace'))
		{
			$stack=debug_backtrace(false);
			foreach($stack as $v)
			if(isset($v['file']) && substr($v['file'],-8)!='crdb.php' )
			{
				$error_line="<br/>\n".'<b>Called from:'.$v['file'].',Line:<span style="color:red">'.$v['line']."</span></b><br/>";
				break;
			}
		}
		trigger_error($msg.$error_line,E_USER_WARNING);
	}
	function __call($column_name,$args)
	{
		$operator='=';
		$table_name=$this->table_name;
		if(count($args)==2):
		list($operator,$value)=$args;
		if(is_int($operator) && $column_name=='limit') :
		return $this->parent->$table_name()->limit($operator,$value);
		else:
		return $this->parent->$table_name()->$column_name($operator,$value);
		endif;
		elseif(count($args)==1):
		return $this->parent->$table_name()->$column_name($args[0]);
		elseif(count($args)==0):
		return $this->parent->{$this->table_name}()->$column_name();
		endif;
	}
}
class crdb_rowset  extends crdb  implements Iterator,Countable
{
	private $parent;
	private $table;
	private $where;
	protected $suffix;
	protected $result_columns;
	private $result;
	private $offset;
	private $current;	
	private $end;
	protected $join_obj;
	protected $join_query;
	private $group_start_count;
	function __construct()
	{
		if(func_num_args()==3)
		{
			$args=func_get_args();
			list($this->table,$this->where,$this->parent)=$args;
		}
		elseif(func_num_args()==2)
		{
			$args=func_get_args();
			list($this->join_query,$this->join_obj)=$args;
			$this->parent=$this->join_obj->crdb;
		}
		$this->suffix= array_fill_keys(array('order_by','desc_order_by','group_by','limit'), array());
		$this->result=null;
		$this->result_columns='*';
		$this->escape=$this->parent->escape;
		$this->group_start_count=0;
	}
	private function notice($msg)
	{
		if(function_exists('debug_backtrace'))
		{
			$stack=debug_backtrace(false);
			foreach($stack as $v)
			if(isset($v['file']) && substr($v['file'],-8)!='crdb.php' )
			{
				$error_line="<br/>\n".'<b>Called from:'.$v['file'].',Line:<span style="color:red">'.$v['line']."</span></b></br>";
				break;
			}
		}
		trigger_error($msg.$error_line,E_USER_WARNING);
	}
	private function query($query)
	{
		if($this->parent->debug) echo $query;
		$return= mysql_query($query,$this->parent->link);
		if($return===false && $this->parent->debug > 1 ) $this->notice(mysql_error($this->parent->link).PHP_EOL.'</br>');
		return $return;
	}
	private function get_suffix()
	{
		$suffix=$group_by_suffix='';
		$order_by=array();
		if(!empty($this->suffix['order_by']))
		{
			foreach($this->suffix['order_by'] as $v) if(is_object($v)) $order_by[]=$v->scalar;else $order_by[]="`$v`";
		}
		if(!empty($this->suffix['group_by']))
		{
			foreach($this->suffix['group_by'] as $v) if(is_object($v)) $group_by[]=$v->scalar;else $group_by[]="`$v`";
		}
		if(!empty($this->suffix['desc_order_by']))
		{
			foreach($this->suffix['desc_order_by'] as $v) if(is_object($v))  $order_by[]=" {$v->scalar} DESC ";else $order_by[]=" `$v` DESC ";
		}
		if(count($this->suffix['group_by'])>0)
		{
			$suffix.=" GROUP BY ".join(",",$group_by);
		}
		if(count($order_by)>0)
		{
			$suffix.=" ORDER BY ".join(',',$order_by);
		}
		if(count($this->suffix['limit'])>0)
		{
			$suffix.= $this->suffix['limit'];
		}
		return $suffix;
	}
	private function exe()
	{
		if(func_num_args() >0)
		{
			$args=func_get_args();
			return $this->__call('exe',$args);
		}
		if(is_null($this->result) )
		{
			$suffix=$this->get_suffix();
			if(strlen($this->where)>0)
			{
				if($this->group_start_count>0)
				{
					$this->where.=str_repeat(' ) ', $this->group_start_count);
					$this->group_start_count=0;
				}
				if(!empty($this->join_query))
				{
					if($this->result_columns=='*'):
					$query="SELECT {$this->join_query[0]} FROM  {$this->join_query[1]} WHERE {$this->where} {$suffix}";
					else:
					$query="SELECT {$this->result_columns} FROM  {$this->join_query[1]} WHERE {$this->where} {$suffix}";
					endif;
				}
				else
				{
					$query="SELECT {$this->result_columns} FROM `{$this->table}` WHERE {$this->where} {$suffix}";
				}
			}
			else
			{
				if(!empty($this->join_query))
				{
					if($this->result_columns=='*'):
					$query="SELECT {$this->join_query[0]} FROM {$this->join_query[1]}  {$suffix}";
					else:
					$query="SELECT {$this->result_columns} FROM {$this->join_query[1]}  {$suffix}";
					endif;
				}
				else
				{
					$query="SELECT {$this->result_columns} FROM `{$this->table}` {$suffix}";
				}
			}
			if($result=$this->query($query))
			{
				$this->result=$result;
				$this->current=null;
				$this->end=false;
			}
		}
	}
	public function count()
	{
		if(func_num_args() >0)
		{
			$args=func_get_args();
			return $this->__call('count',$args);
		}
		$this->exe();
		if(is_resource($this->result)) return mysql_num_rows($this->result);else return false;
	}
	public function current()
	{
		if(func_num_args() >0)
		{
			$args=func_get_args();
			return $this->__call('current',$args);
		}
		$this->exe();
		$row=$this->current;
		$this->current=mysql_fetch_object($this->result);			
		if($this->current==false) $this->end=true;		
		return $row;
	}
	public function key()
	{
		if(func_num_args() >0)
		{
			$args=func_get_args();
			return $this->__call('key',$args);
		}
		$this->exe();
		return $this->offset++;
	}
	public function next()
	{
		if(func_num_args() >0)
		{
			$args=func_get_args();
			return $this->__call('next',$args);
		}
		$this->exe();						
	}
	public function rewind()
	{
		if(func_num_args() >0)
		{
			$args=func_get_args();
			return $this->__call('rewind',$args);
		}		
		$this->exe();
		if(is_resource($this->result))
		{
			if(is_resource($this->result) &&  mysql_num_rows($this->result)>0)	
			{
				mysql_data_seek($this->result,0);
				$this->offset=0;
				$this->end=false;
				$this->current=mysql_fetch_object($this->result);
			}
		}
	}
	public function valid()
	{
		if(func_num_args() >0)
		{
			$args=func_get_args();
			return $this->__call('valid',$args);
		}
		if(is_resource($this->result) && mysql_num_rows($this->result)>0 && !$this->end) return true;else return false;
	}
	function  __call($column_name,$args)
	{
		$operator='=';
		$this->result=null;
		if(count($args)>1):
		list($operator,$value)=$args;
		if((is_int($operator) || is_null($operator)) && $column_name=='limit'):
		{
			if(is_null($operator)) $this->notice("Blank value given for offset,limit pair");
			$clone=clone $this;
			$clone->suffix['limit']=" LIMIT $operator,$value ";
			return $clone;
		}
		endif;
		elseif(count($args)==0):
		switch($column_name)
		{
			case 'or':
				$clone=clone $this;
				$clone->where.=' OR ';
				return $clone;
			case 'start_group':
				$clone=clone $this;
				if((substr($clone->where,-3) !='OR ') && (substr($clone->where,-4)) !='AND ' && (strlen($clone->where) > 0  )) $clone->where.=' AND ';
				$clone->where.=' ( ';
				$clone->group_start_count++;
				return $clone;
			case 'end_group':
				$clone=clone $this;
				$clone->where.=' ) ';
				$clone->group_start_count--;
				return $clone;
			case 'delete':
				if(strlen($this->where)>0) return $this->__unset('all');
				else $this->notice('No WHERE Clause for delete.Use `empty()` method to delete all rows.');
				return false;
			case 'empty':
				return $this->__unset('all');
			case 'order_by':
				return new crdb_ext($this,'order_by');
			case 'desc_order_by':
				return new crdb_ext($this,'desc_order_by');
			case 'group_by':
				return new crdb_ext($this,'group_by');
			case 'group_by':
				return new crdb_ext($this,'group_by');
			case 'max':
				return new crdb_ext($this,'max');
			case 'min':
				return new crdb_ext($this,'min');
			case 'sum':
				return new crdb_ext($this,'sum');
			case 'avg':
				return new crdb_ext($this,'avg');
			case 'average':
				return new crdb_ext($this,'avg');
			case 'distinct':
				return new crdb_ext($this,'distinct');
			case 'result':
				$this->exe();
				if(is_resource($this->result))
				{
					$return=array();
					while($row=mysql_fetch_object($this->result))
					{
						$return[]=$row;
					}
				return $return;
				}
		}
		else:
		$value=$args[0];
		endif;
		if(!empty($this->join_query))
		{
			if(isset($this->join_obj->join_aliases[$column_name]))
			{
				$column_name=$this->join_obj->join_aliases[$column_name];
			}
			else
			{
				$this->notice("No column `$column_name` in specified tables.");
			}
		}
		else
		{
			if(isset($this->parent->table_columns[$this->table][$column_name]))
			{
				$column_name="`$column_name`";
			}
			else
			{
				$this->notice("No column `$column_name` in  table `{$this->table}`");
			}
		}
		$clone=clone $this;
		if(substr($clone->where,-3)=='OR ' or substr($clone->where,-2)=='( 'or strlen($clone->where)==0) $combine='';else $combine= ' AND ';
		if(is_string($value)):
		$value=$this->escape($value);
		$clone->where=$clone->where." $combine $column_name $operator \"$value\" ";
		elseif(is_null($value)):
			if(trim($operator)=='!'):
				$clone->where=$clone->where." $combine $column_name IS NOT NULL";				
			else:				
				$clone->where=$clone->where." $combine $column_name IS NULL";	
			endif;
		elseif(is_object($value)):
		$clone->where=$clone->where." $combine $column_name $operator {$value->scalar}";
		elseif(is_array($value)):
		foreach($value as &$v) $v=$this->escape($v);
		$value_list='"'.join('","',$value).'"';
		if($operator != '=') 
		{
			$clone->where=$clone->where." $combine $column_name $operator ( $value_list )";
		}else 
		{
			$clone->where=$clone->where." $combine $column_name IN( $value_list )";
		}
		else:
		$clone->where=$clone->where." $combine $column_name $operator $value ";
		endif;		
		return $clone;
	}
	function _columns($str)
	{
		$clone=clone $this;
		$clone->result_columns=" $str ";
		return $clone;
	}
	function _where($str)
	{
		$clone=clone $this;
		$str=trim($str);
		if( (strtoupper(substr($str,0,4))=='AND ') || (strtoupper(substr($str,0,3))=='OR ')  )
		{	
			$clone->where.=$str;
			return $clone;
		}
		if(strlen($clone->where)>0 && (strtoupper(substr($clone->where,-4))!==' OR ') && (strtoupper(substr($clone->where,-3))!==' ( ') ) $clone->where.=" AND $str ";else $clone->where.=$str;
		return $clone;
	}
	function _row($rowNum)
	{
	$this->exe();
	if(is_resource($this->result))
	{
	$return=array();
	$totalRows = mysql_num_rows($this->result);
	if(($rowNum >= 0) && ($rowNum < $totalRows)) 
	{
	mysql_data_seek($this->result,$rowNum);
	}elseif(($rowNum < 0) && -$rowNum < $totalRows)
	{
	mysql_data_seek($this->result,$totalRows+$rowNum);
	}
	else return false;
	$row=mysql_fetch_object($this->result);
	return $row;
	}
	}
	function __unset($arg)
	{
		if($arg=='all')
		{
			if(!empty($this->join_query))
			{
				$tables=join('`,`',array_keys($this->join_obj->tables));
				if(strlen($this->where)>0)
				$query="DELETE `$tables` FROM {$this->join_query[1]}  where {$this->where}";
				else
				$query="DELETE `$tables` FROM  {$this->join_query[1]}";
			}
			else
			{
				if(strlen($this->where)>0)
				$query="DELETE FROM `{$this->table}` where {$this->where}";
				else
				$query="DELETE FROM `{$this->table}`";
			}
			$return=$this->query($query);
			$affected_rows=mysql_affected_rows($this->parent->link);
			if(empty($this->join_query)) $this->parent->crdb_table_objects[$this->table]->affected_rows=$affected_rows;
			else
			{
				foreach($this->join_obj->tables as $k=>$v)
				{
					$this->parent->crdb_table_objects[$v]->affected_rows=$affected_rows;
				}
			}
			$this->result=null;
			return $return;
		}
	}
	function __get($column_name)
	{
		//$this->result=null;
		$this->rewind();
		if(is_resource($this->result)) $count=mysql_num_rows($this->result);else return false;
		if($count>0)
		{
			if(property_exists($this->current, $column_name)) return $this->current->$column_name;
			else
			{
				$this->notice("No Column `$column_name` in result.Columns should be accessed in format 'tablealias_columnsname' when a join performed.");
			}
		}
		else return false;
	}
	function __set($column_name,$value)
	{
		$this->result=null;
		if(is_object($value))    $value=$value->scalar;else
		{
			$value=$this->escape($value);
			$value="\"$value\"";
		}
		if(!empty($this->join_query))
		{
			$column_name=$this->join_obj->join_aliases[$column_name];
			if(strlen($this->where)>0)
			$query="update {$this->join_query[1]} set $column_name =$value where {$this->where}";
			else
			$query="update {$this->join_query[1]} set $column_name =$value";
		}
		else
		{
			if(!isset($this->parent->table_columns[$this->table][$column_name]))
			{
				$this->notice("No Column `$column_name` in table {$this->table}");
				return;
			}
			if(strlen($this->where)>0)
			$query="update `{$this->table}` set `$column_name` =$value where {$this->where}";
			else
			$query="update `{$this->table}` set `$column_name` =$value";
		}
		$result=$this->query($query);
		$affected_rows=mysql_affected_rows($this->parent->link);
		if(empty($this->join_query))
		$this->parent->crdb_table_objects[$this->table]->affected_rows=$affected_rows;
		else
		{
			foreach($this->join_obj->tables as $k=>$v)
			{
				$this->parent->crdb_table_objects[$k]->affected_rows=$affected_rows;
			}
		}
	}
}

class crdb_join extends crdb_rowset
{
	public  $join_aliases;
	private $foreign_keys;
	protected $tables;
	protected $table_columns;
	protected $crdb;
	private $type;
	private $join_on_clauses;
	private $join_types;
	private $last_join_type;
	private $on_context;
	private $last_table_alias;
	function _end()
	{
		$tables=$this->tables;
		$tables_seen = array();
		foreach($tables as $k=>$v)
		{
			$tables_seen[$k] = $v;
			if(!isset($current_table))
			{
				$current_table=$v;
				$current_alias=$k;
				$table_str="`$current_table` as `$current_alias` ";
			}
			else
			{
				$columns=null;
				$join_operator='=';
				if(isset($this->join_on_clauses[$k]))
				{
					$on_clause=$this->join_on_clauses[$k];
					$current_table=$v;
					$current_alias=$k;
				}
				else
				{
					if(isset($this->foreign_keys[$current_table][$v]))
					{
						$columns=$this->foreign_keys[$current_table][$v];
					}
					elseif(isset($this->foreign_keys[$v][$current_table]))
					{
						$columns=array_reverse($this->foreign_keys[$v][$current_table]);
					}
					if(!$columns)
					{
						foreach($this->crdb->table_columns[$v] as $column_array )
						{
							foreach($tables_seen as $table_in_join)
							{
								foreach($this->crdb->table_columns[$table_in_join] as $search_column_array)
								{
									if((strtolower(str_replace('_','',$search_column_array['Field'])) == strtolower(str_replace('_','',$v.$column_array['Field']))) || (strtolower(str_replace('_','',$table_in_join.$search_column_array['Field'])) == strtolower(str_replace('_','',$column_array['Field']))))
									{
										$columns = array($search_column_array['Field'],$column_array['Field']);
										$current_alias = array_search( $table_in_join,$tables);
										break 3;
									}
								}
							}
						}
					}
					if($columns)
					{
						list($src_column,$dst_column)=$columns;
						$on_clause=" `$current_alias`.`$src_column` $join_operator `$k`.`$dst_column` ";
						$current_table=$v;
						$current_alias=$k;
					}
					else
					{
						$this->notice("No Key to connect tables `$current_table` and `$v` ." );
					}
				}
				if(isset($this->join_types[$k])) $join_type=$this->join_types[$k];else $join_type=$this->type;
				$table_str.=" $join_type `$v` as `$k` ON ( $on_clause ) ";
			}
			foreach($this->table_columns[$v] as $column)
			{
				$query_columns[]="`$k`.`$column` as `{$k}_{$column}` ";
				$this->join_aliases["{$k}_{$column}"]=" `$k`.`$column` ";
			}
		}
		return new crdb_rowset(array(join(',',$query_columns), $table_str),$this);
	}

	private function notice($msg)
	{
		if(function_exists('debug_backtrace'))
		{
			$stack=debug_backtrace(false);
			foreach($stack as $v)
			if(isset($v['file']) && substr($v['file'],-8)!='crdb.php' )
			{
				$error_line="<br/>\n".'<b>Called from:'.$v['file'].',Line:<span style="color:red">'.$v['line']."</span></b><br/>";
				break;
			}
		}
		trigger_error($msg.$error_line,E_USER_WARNING);
	}
	public function __construct($type,$crdb,$foreign_keys)
	{
		$this->tables=array();
		$this->foreign_keys=$foreign_keys;
		$this->crdb=$crdb;
		$this->type=$type;
		$this->escape =$crdb->escape;
		$this->on_context=false;
	}
	public function __get($name)
	{
		if($name=='_end' || $name=='end')
		{
			return $this->_end();
		}
		if($name=='_on' || $name=='on')
		{
			$this->on_context=true;
			return $this;
		}
		if($name=='_join' || $name=='join')
		{
			$this->on_context=false;
			$this->last_join_type=' JOIN ';
			return $this;
		}
		if($name=='_left_join' || $name=='left_join')
		{
			$this->on_context=false;
			$this->last_join_type=' LEFT JOIN ';
			return $this;
		}
	}
	private function get_column_from_alias($column_alias)
	{
		foreach($this->tables  as $alias=>$table_name)
		{
			foreach($this->table_columns[$table_name] as $k=>$v)
			{
				if($alias.'_'.$v==$column_alias)    return "`$alias`.`$v`";
			}
		}
	}
	public function __call($table_name,$args)
	{
		if($this->on_context)
		{
			if(!$column_one=$this->get_column_from_alias($table_name))
			{
				foreach($this->tables as $k=>$v)
				{
					if(substr($table_name,0,strlen($k))==$k) $this->notice("No column with name `".substr($table_name,strlen($k)+1)."` in table `$v`" );
				}
				$this->notice("Column alias `$table_name` is not defined.");
			}
			$operator=' = ';
			if(count($args)==1) $alias=$args[0];
			elseif(count($args)==2) list($operator,$alias)=$args;
			if(isset($args[0]))
			{
				if(is_object($alias))
				{
					$column_two = $this->escape((string)$alias->scalar);	
				}else 
				if(!$column_two=$this->get_column_from_alias($alias))
				{
					foreach($this->tables as $k=>$v)
					{
						if(substr($alias,0,strlen($k))==$k) $this->notice("No column with name `".substr($alias,strlen($k)+1)."` in table `$v`" );
					}
					$this->notice("Column alias `$alias` is not defined.");

				}
			}
			else
			{
				$this->notice("column name missing");
			}
			if(isset($this->join_on_clauses[$this->last_table_alias]))
			{
				$this->join_on_clauses[$this->last_table_alias].="AND $column_one $operator $column_two ";
			}
			else
			{
				$this->join_on_clauses[$this->last_table_alias]="$column_one $operator $column_two ";
			}
			return $this;
		}
		else
		{
			if(isset($args[0]))
			{
				if(!isset($this->crdb->crdb_table_objects[$table_name]))
				{
					$this->notice("No Table `$table_name`.");
					return $this;
				}
				$this->last_table_alias=$args[0];
				$this->tables[$args[0]]=$table_name;
				$this->join_types[$args[0]]=$this->last_join_type;
				if($result=mysql_query("SHOW COLUMNS FROM `$table_name`"))
				{
					if(!isset($this->table_columns[$table_name]))
					{
						while($row=mysql_fetch_array($result))
						{
							$this->table_columns[$table_name][]=$row[0];
						}
					}
				}
				return $this;
			}
		}
	}
}
class crdb_ext extends crdb_rowset
{
	private $rowset;
	private $ext_name;
	public function crdb_ext($rowset,$ext_name)
	{
		$this->rowset=clone $rowset;
		$this->ext_name=$ext_name;
	}
	public function fields()
	{
		$args=func_get_args();
		if($this->ext_name=='order_by')
		{
			$this->rowset->suffix['order_by']+=$args;
		}
		elseif($this->ext_name=='desc_order_by')
		{
			$this->rowset->suffix['desc_order_by']+=$args;
		}
		elseif($this->ext_name=='group_by')
		{
			$this->rowset->suffix['group_by']+=$args;
		}
		elseif($this->ext_name=='distinct')
		{
			$fields=join('`,`',$args);
			$this->rowset->result_columns=" DISTINCT ( `$fields` ) ";
		}
		return $this->rowset;
	}
	public function __get($field)
	{
		if($this->ext_name=='order_by'):
		$this->rowset->suffix['order_by'][]=$field;
		elseif($this->ext_name=='desc_order_by'):
		$this->rowset->suffix['desc_order_by'][]=$field;
		elseif($this->ext_name=='group_by'):
		$this->rowset->suffix['group_by'][]="$field";
		elseif($this->ext_name=='max'):
		if(!empty($this->rowset->join_query)):
		$full_field_name=$this->rowset->join_obj->join_aliases[$field];
		$this->rowset->result_columns=" MAX($full_field_name) as `$field`";
		else:
		$this->rowset->result_columns=" MAX(`$field`) as `$field`";
		endif;
		return $this->rowset->$field;
		elseif($this->ext_name=='min'):
		if(!empty($this->rowset->join_query)):
		$full_field_name=$this->rowset->join_obj->join_aliases[$field];
		$this->rowset->result_columns=" MIN($full_field_name) as `$field`";
		else:
		$this->rowset->result_columns=" MIN(`$field`) as `$field`";
		endif;
		return $this->rowset->$field;
		elseif($this->ext_name=='sum'):
		if(!empty($this->rowset->join_query)):
		$full_field_name=$this->rowset->join_obj->join_aliases[$field];
		$this->rowset->result_columns=" SUM($full_field_name) as `$field`";
		else:
		$this->rowset->result_columns=" SUM(`$field`) as `$field`";
		endif;
		return $this->rowset->$field;
		elseif($this->ext_name=='avg'):
		if(!empty($this->rowset->join_query)):
		$full_field_name=$this->rowset->join_obj->join_aliases[$field];
		$this->rowset->result_columns=" AVG($full_field_name) as `$field`";
		else:
		$this->rowset->result_columns=" AVG(`$field`) as `$field`";
		endif;
		return $this->rowset->$field;
		elseif($this->ext_name=='distinct'):
		if(!empty($this->rowset->join_query)):
		$full_field_name=$this->rowset->join_obj->join_aliases[$field];
		$this->rowset->result_columns=" DISTINCT($full_field_name) as `$field`";
		else:
		$this->rowset->result_columns=" DISTINCT(`$field`) as `$field`";
		endif;
		return $this->rowset;
		endif;
		return $this->rowset;
	}
}
class crdb
{
	protected $link;
	private $table_primary_keys;
	protected $table_columns;
	private $foreign_keys;
	protected $crdb_table_objects;
	protected $debug;
	protected $escape;
	public function __construct($link,$foreign_keys=array())
	{
		$this->link=$link;
		mysql_query("SET NAMES utf8",$this->link);
		$this->escape=true;
		$table_result=mysql_query("show tables",$this->link);
		$this->foreign_keys=$foreign_keys;
		if($table_result!== FALSE && mysql_num_rows($table_result) > 0)
		while($row=mysql_fetch_array($table_result))
		{
			$this->crdb_table_objects[$row[0]]=   new crdb_table($row[0],$this);
			$table_data=mysql_query("describe `{$row[0]}`",$this->link);
			while($column_data=mysql_fetch_array($table_data))
			{
				if($column_data['Key']=='PRI' && !isset($this->table_primary_keys[$row[0]]))  $this->table_primary_keys[$row[0]]=$column_data['Field'];
				$this->table_columns[$row[0]][$column_data['Field']]=$column_data;
			}
		}
	}
	private function notice($msg)
	{
		if(function_exists('debug_backtrace'))
		{
			$stack=debug_backtrace(false);
			foreach($stack as $v)
			if(isset($v['file']) && substr($v['file'],-8)!='crdb.php' )
			{
				$error_line="<br/>\n<b>Called from:".$v['file'].',Line:<span style=\"color:red\">'.$v['line']."</span></b><br/>";
				break;
			}
		}
		trigger_error($msg.$error_line,E_USER_WARNING);
	}
	protected function escape($str)
	{
		if(strpos($str,"\"")===false || (!$this->escape)) return $str;
		$parts=explode('"',$str);
		$total=count($parts)-1;
		foreach($parts as $k=>&$v)
		{
			if( ( strspn(strrev($v),'\\') % 2 )==0 && $k<$total) $v.='\\';
		}
		$return=join('"',$parts);
		if(substr($return,0,1)=="\"") $return ="\\".$return;
		return $return;
	}
	private function query($query)
	{
		if($this->debug) echo $query;
		$return=mysql_query($query,$this->link);
		if($return===false && $this->debug > 1  ) $this->notice(mysql_error($this->link).PHP_EOL.'</br>');
		return $return;
	}
	public function __set($table_name,$value)
	{
		$query='';
		$tuples=array();
		
		if(is_array($value))
		{
			if(!isset($this->table_columns[$table_name]))
			{
				$this->notice("No Table `$table_name`.");
				return;
			}
			foreach($this->table_columns[$table_name] as $k=>$v)
			{
				if(isset($value[$k]))
				{
					if(is_object($value[$k])) $tuples[]="`$k`={$value[$k]->scalar}";
					else
					{
						$value[$k]=$this->escape($value[$k]);
						$tuples[$k]="`$k`=\"{$value[$k]}\"";
					}
				}
			}
			if(count($tuples)>0)
			{
				if(isset($this->table_primary_keys[$table_name]) && isset($value[$this->table_primary_keys[$table_name]]) && count($this->$table_name($value[$this->table_primary_keys[$table_name]])) > 0  )
				{
					$primary_key_tuple=$tuples[$this->table_primary_keys[$table_name]];	
					unset($tuples[$this->table_primary_keys[$table_name]]);
					$query="UPDATE `$table_name` SET ".join(',',$tuples)." WHERE $primary_key_tuple";
				}
				else
				{
					$query="INSERT INTO `$table_name` SET ".join(',',$tuples);
				}
			}
			if($this->query($query,$this->link))
			{	
				$this->crdb_table_objects[$table_name]->insert_id=mysql_insert_id($this->link);
				$this->crdb_table_objects[$table_name]->affected_rows=mysql_affected_rows($this->link);
			}
		}
		elseif(is_object($value))
		{
			foreach($this->table_columns[$table_name] as $k=>$v)
			{
				if(isset($value->$k))
				{
					$value->$k=$this->escape($value->$k);
					$tuples[]="`$k`=\"{$value->$k}\"";
				}
			}
			if(count($tuples)>0)
			{
				$query="INSERT INTO `$table_name` SET ".join(',',$tuples);
			}
			if($this->query($query,$this->link))
			{
				$this->crdb_table_objects[$table_name]->insert_id=mysql_insert_id($this->link);
				$this->crdb_table_objects[$table_name]->affected_rows=mysql_affected_rows($this->link);
			}
		}
		else
		{
			if($table_name=='debug')
			{
				$this->debug=$value;
				return;
			}
			if($table_name=='escape')
			{
				$this->escape=$value;
				return;
			}
			if($table_name=='encoding')
			{
				mysql_query("SET NAMES $value",$this->link);
			}
		}
	}
	public function __isset($table_name)
	{
		if(isset($this->crdb_table_objects[$table_name]) ) return true;else return false;
	}
	public function __get($table_name)
	{
		if($table_name=='_join') return new crdb_join('JOIN',$this,$this->foreign_keys);
		if($table_name=='_left_join') return new crdb_join('LEFT JOIN',$this,$this->foreign_keys);
		if($table_name=='_right_join') return new crdb_join('RIGHT JOIN',$this,$this->foreign_keys);
		if(isset($this->crdb_table_objects[$table_name])) return $this->crdb_table_objects[$table_name];
		else
		{
			$this->notice("Table `$table_name` doesn't exist.");
		}
	}
	public function __call($table_name,$arg)
	{
		$where='';
		if(isset($this->crdb_table_objects[$table_name]))
		{
			if(count($arg)>0)
			{
				if(!is_null($arg[0]))
				{
					if(isset($this->table_primary_keys[$table_name]))
					{
						if(is_array($arg[0]))
						{
							foreach($arg[0] as &$v) $v=$this->escape($v);
							$value_list='"'.join('","',$arg[0]).'"';
							$where=" `{$this->table_primary_keys[$table_name]}` IN( $value_list )";
						}
						else
						{
							$where="  `{$this->table_primary_keys[$table_name]}` =\"{$arg[0]}\"";
						}
					}
					else
					{
						$this->notice("No Primary Key Defined For Table `$table_name`");
					}
				}
				else
				{
					$this->notice("Null value specified for primary key value");
					$where=" false  ";
				}
			}
			return new crdb_rowset($table_name,$where,$this);
		}
		else
		{
			$this->notice("Table `$table_name` doesn't exist.");
		}
	}
	public function _set_link($link)
	{
		$this->__construct($link);
	}
	public function _query($query,$mode=2,$link=NULL)
	{
		if($link) $result=mysql_query($query,$link) ;else  $result=mysql_query($query);
		if($result)
		{
			if(gettype($result)!='boolean' )
			{
				if($mode==0)
				{
					if($row=mysql_fetch_array($result))	return $row[0];else return NULL;
				}
				elseif($mode==1)
				{
					if($row=mysql_fetch_object($result))	return $row;else return array();
				}
				else
				{
					if(mysql_num_rows($result)==0) return array();
					if($mode==2)
					{
						while($row=mysql_fetch_object($result))
						{
							$return[]=$row;
						}
					}
					else
					{
						while($row=mysql_fetch_array($result))
						{
							$return[]=$row;
						}
					}
					return $return;
				}
			}
			else return true;

		}
		else
		{
			return false;
		}
	}
}
?>