Location: PHPKode > scripts > DBInterface > dbinterface/dbi.inc.php
<?
	# Ejecuta un sql y devuelve el resultado en query. V2 orientada a objetos
		define( 'DBI_FETCH_OBJECT', 1);
		define( 'DBI_FETCH_ASSOC', 2);
		define( 'DBI_FETCH_ORDERED', 3);
		
		// Constantes de Errores
		define( 'DBI_MYSQL_DUP_ENTRY', 1062);
		
		class DBI
		{
			var $conn;					# Conexión
			var $transac;				# Identificador de transacciones
			var $sql;					# SQL a ejecutar por la funcion 'query'
			var $num_rows;				# Cantidad de registros devueltos.
			var $pg_tableAutoIndex = '_id_seq'; # Sufijo para la table que mantiene el indice automatico en postgresql
			var $query = null;			# Puntero al resultado.
			var $row;					# Registro actual.
			var $last_id;				# Last insert ID.
			var $affected_rows;			# Cantidad de registros afectados.
			var $tabla;					# Tabla afectada por el ultima insert.
			var $where;
			var $values;	
			var $limit;
			var $order;
			var $debug = FALSE;			# $debug
			var $db;					# Database to connect.
			var $usuario;				# User to connect to the server.
			var $clave;					# Pass to connect to the server.
			var $server;				# Server to connect.
			var $tipo;					# RDBMS server.
			var $result_index;
			var $simbolo_variable = '@';# Simbolo usado por las variable en los store procedures.
			var $exceptions = array();	# Hash con ['error_code'] y ['function'] para la cazacion de las excepciones.
			var $subqueries = array();
			var $print_subsql = false;
			
			# Abre una conexion persistente con el server y selecciona la base de datos
			function &DBI( $db='', $usuario='', $clave='', $server='', $tipo='' ){
				require_once( 'DB.php' );

				$this->db 		= ( $db		 != '' ? $db	  : ( $CFG_SQL_db		? $CFG_SQL_db		: CFG_SQL_db		) );
				$this->usuario	= ( $usuario != '' ? $usuario : ( $CFG_SQL_usuario	? $CFG_SQL_usuario	: CFG_SQL_usuario	) );
				$this->clave	= ( $clave	 != '' ? $clave	  : ( $CFG_SQL_clave	? $CFG_SQL_clave	: CFG_SQL_clave		) );
				$this->server	= ( $server	 != '' ? $server  : ( $CFG_SQL_server	? $CFG_SQL_server	: CFG_SQL_server	) );
				$this->tipo		= ( $tipo	 != '' ? $tipo	  : ( $CFG_SQL_tipo		? $CFG_SQL_tipo		: CFG_SQL_tipo		) );

				$dsn = array(
						'phptype' => $this->tipo,
						'username' => $this->usuario,
						'password' => $this->clave,
						'hostspec' => $this->server,
						'database' => $this->db
				);

				$this->conn = DB::connect( $dsn, true);
				$this->error($this->conn);
				
				if( $this->db == '' ){
					echo "Error de configuración por defecto: la constante CFG_SQL_db no esta definida.";
					return false;
				}
				return true;
			}
			
			# Ejecuta el query pasado como parametro o contenido en 'sql',
			# teniendo este untimo mas prioridad.
			# Si el query devuelve algun registro el segundo parametro
			# indica la ejecución y devolucion del fetch si es asignado.
			# Su valor puede ser:
			#		
			#		1 = fetch_object()
			#		2 = fetch()
			#		3 = fetch_assoc()
			#		4 = fetch_assoc() sin conteo de registros, uso interno
			#
			function query($sql='', $fetch=0)
			{
				if( is_a( $this->query ,"DB_Result" ) )
				{
					$this->query->free();
				}
				if(!$this->conn)$this->DBI($this->db,$this->usuario,$this->clave,$this->server,$this->tipo);
				if($sql=='')$sql = $this->sql;else $this->sql=$sql;
				if($this->sql!=''){
					if( preg_match("/\A\s*select/ism", $this->sql ) )
					{
						$this->num_rows=0;
						if( $this->tipo == 'mssql' ){
							$this->query = @mssql_query( $this->sql );
						}else{
							$this->query = $this->conn->query( $this->sql );
						}
						$this->error($this->query);
						
						# Si el parametro fetch es 4 no se cuentan los registros.
						if( $fetch != 4 ) $this->count();
						
						switch( $fetch )
						{
							case DBI_FETCH_OBJECT :
								return $this->fetch_object();
							case DBI_FETCH_ORDERED :
								return $this->fetch();
							case DBI_FETCH_ASSOC || 4 :
								return $this->fetch_assoc();
						}
					}
					elseif( preg_match("/\A\s*execute/ism", $this->sql ) )
					{
						$this->query=$this->conn->query($this->sql);
					}
					else
					{
						if( $fetch == 1 )
						{
							$this->query=$this->conn->query($this->sql);
						}
						elseif( count( $fetch ) > 1 )
						{
							$query_prepare=$this->conn->prepare($this->sql );
							$this->query=$this->conn->executeMultiple($query_prepare, $fetch);
						}
						else
						{
							$query_prepare = $this->conn->prepare($this->sql);
							if($this->debug) $this->print_sql();
							if($fetch)
								$this->query = $this->conn->execute($query_prepare, $fetch);
							else
								$this->query = $this->conn->execute($query_prepare);
						}
						$this->num_rows=0;
					}
					if( $this->error($this->query) )
					{
						return false;
					}
					return $this->query;
				}
				else
				{
					return false;
				}
			}
			# Funciones para Transacciones
			function begin()
			{
				if( $this->tipo == 'mysql' )
				{
					$this->query('SET AUTOCOMMIT=0');
				}
				$this->query('BEGIN');
				$this->transac =  true;
			}
			
			function commit()
			{
				if( $this->transac )
				{
					if( $this->tipo == 'mysql' )
					{
						if( $this->query('COMMIT') )
						{
							$this->transac = false;
						}
						$this->query('SET AUTOCOMMIT=1');
					}
					elseif( $this->tipo == 'pgsql' )
					{
						if( $this->query('COMMIT') )
						{
							$this->transac = false;
						}
					}
					else
					{
						die("La Esta base no tiene soporte de transacciones en DBI o no se ha iniciado la misma!<br><br>Por el momento unicamente se soporta MySQL/Innodb, PostgreSQL y Interbase/Firebird.");
					}
				}
			}
			
			function rollback()
			{
				if( $this->transac )
				{
					if( $this->tipo == 'mysql' )
					{
						$this->query('ROLLBACK');
						$this->query('SET AUTOCOMMIT=1');
					}
					elseif( $this->tipo == 'pgsql' )
					{
						$this->query('ROLLBACK');
					}
					else
					{
						die("Esta base no tiene soporte de transacciones en DBI o no se ha iniciado la misma!<br><br>Por el momento unicamente se soporta MySQL/Innodb, PostgreSQL y Interbase/Firebird.");
					}
				}
			}
			# Fin de funciones para transacciones			

			# Crea los SQLs
			function sql( $accion, $tabla, $valores, $where = '', $order = '', $limit = '', $fetch = '', $tabla_insert_select = '', $campos_insert_select = '' )
			{
				if( $this )
				{
					$sql_query = &$this;
				}
				else
				{
					$sql_query = new DBI;
				}
				$accion = strtolower( $accion );

				# Arma los pares de campo-valor para los querys que los necesitan
				if( $valores && ( $accion == 'select' || $accion == 'execute' || $accion == 'update' || $accion == 'insert' || $accion == 'insert_multiple' || $accion == 'replace' ) )
				{
					preg_match_all(
								"/
								(.+?) 			#Nombre del campo
								(?(?==)
									=
									((?(?=\\s*')
										\\s*'.*?'|
										.*?
									))
								)
								(?(?=\\s*\\\\{0},)
									\\s*\\\\{0},|		#Coma separadora de tuplas
									\\s*$		# Final de la cadena
								)
								/sx",
								$valores,
								$pares
					);
					$campos = $pares[1];
					$valores = $pares[2];
					
					$sep			= '';
					$sql_set		= '';
					$sql_valores	= '';
					
					for( $i = 0 ; $i < sizeof($campos) ; $i++)
					{
						$campo = '';
						$valor = '';
						if( trim($valores[$i]) != '' ){
							if( substr( $campos[$i], -5 ) == '::sql' )
							{
								$campo = trim(substr( $campos[$i], 0, -5 ));
								$this->subqueries[] = $campo;
								$valor = trim($valores[$i]);
							}else{
								$campo = trim($campos[$i]);
								$valor = str_replace( '\,',',',trim($valores[$i]));
							}
						}
						else
						{
							if( $accion == 'select' )
							{
								$campo = trim( $campos[$i] );
								$valor = trim($valores[$i] );
							}
							elseif( substr( $campos[$i], -6 ) == '::blob' )
							{
								$campo = trim(substr( $campos[$i], 0, -6 ));
								
								if( substr( $campo, -6 ) == '_image' ){
									$campo_nombre = substr( $campo, 0, -6 );
								}else{
									$campo_nombre = $campo;
								}
								
								$data = getfile( $GLOBALS[ $campo ] );
								
								# Campos y Valores SQL para Update
								if( $accion == 'update' )
								{
									if($GLOBALS[$campo."_delete"])
									{
										#Blob
										$sql_set .= "$sep $campo = null";
										$sep = ',';
										#File Name
										$sql_set .= "$sep ".$campo_nombre."_name = ''";
										
										#Mime Type
										$sql_set .= "$sep ".$campo_nombre."_mime = ''";
									}
									else
									{
										if($data)
										{
											#Blob
											$data = "'".addslashes($data)."'";
											$sql_set .= "$sep $campo = $data";
											$sep = ',';
											
											#File Name
											$sql_set .= "$sep ".$campo_nombre."_name = '".$GLOBALS[ $campo.'_name']."'";
											
											#Mime Type
											$sql_set .= "$sep ".$campo_nombre."_mime = '".$GLOBALS[ $campo.'_type']."'";
										}
									}
								}
								
								# Campos y Valores SQL para Insert
								if( $accion == 'insert' || $accion == 'replace' || $accion == 'insert_multiple' )
								{
									#Blob
									$sql_campos .= "$sep $campo";
									$sql_valores .= "$sep '".addslashes($data)."'";
									$sep = ',';
									#File Name
									$sql_campos .= "$sep ".$campo_nombre."_name";
									$sql_valores .= "$sep '".$GLOBALS[ $campo.'_name']."'";
									
									#Mime Type
									$sql_campos .= "$sep ".$campo_nombre."_mime";
									$sql_valores .= "$sep '".$GLOBALS[ $campo.'_type']."'";
								}
							}
							else
							{
								$campo = trim($campos[$i]);
								if( isset( $GLOBALS[$campo] ) )
								{
									if( is_array( $GLOBALS[$campo] ) )
									{
										$array_campo = $campo;
										foreach( $GLOBALS[$campo] as $array_valor )
										{
											$array_valores[] = "'$array_valor'";
										}
									}
									elseif( is_string( $campo ) && $campo != 'id' )
									{
										$valor = "'".$GLOBALS[$campo]."'";
									}else{
										$valor = $GLOBALS[$campo];
									}
								}
							}
						}
						if( $accion == 'execute' && $valor == '' )
						{
							$valor = "''";
						}
						if( $accion != 'select' && $campo != '' && $valor != '' )
						{
							# Campos y Valores SQL para Update
							if( $accion == 'update' ){
								$sql_set .= "$sep $campo = $valor";
							}
							else if( $accion == 'execute')
							{
								$sql_set .= "$sep $this->simbolo_variable$campo = $valor";
							}
							else if( $accion == 'insert' || $accion == 'replace' || $accion == 'insert_multiple' )
							{
								$sql_campos .= "$sep $campo";
								$sql_valores .= "$sep $valor";
							}
							$sep = ',';
						}
						
						if( $accion == 'select' )
						{
							$sql_campos .= $sep.' '.( $valor ? "$valor as ": '' ).' '.$campo;
							$sep = ',';
						}
					}
				}

				# SQL para Select
				if( $accion == 'select' )
				{
					if( $where != '' ) $sql_where = "WHERE $where";
					if( $order != '' ) $sql_order = "ORDER BY $order";
					
					if( $limit != '' ) $sql_limit = "LIMIT $limit";
					return $sql_query->query( "SELECT $sql_campos FROM $tabla $sql_where $sql_order $sql_limit" , $fetch );
				}
				# SQL para Update
				if( $accion == 'update')
				{
					if( $where != '' )
					{
						$sql_where = "WHERE $where";
					}
					if( $sql_set == '' )
					{
						return false;
					}
					return $sql_query->query( "UPDATE $tabla SET $sql_set $sql_where",1);
				}
				# SQL para Execute
				if( $accion == 'execute')
				{
					return $sql_query->query( "EXECUTE $tabla $sql_set",1);
				}
				# SQL para Insert
				if( $accion == 'insert' )
				{
					return $sql_query->query("INSERT INTO $tabla ($sql_campos) VALUES ($sql_valores)",1);
				}
				if( $accion == 'insert_multiple')
				{
					$ret_id = array();
					if( $array_campo )
					{
						foreach( $array_valores as $array_valor )
						{
							$ret_id[] = $sql_query->query("INSERT INTO $tabla ($sql_campos,$array_campo) VALUES ($sql_valores,$array_valor)",1);
						}
					}
					return $ret_id;
				}
				# SQL para Select
				if( $accion == 'insert_select' )
				{
					if( $campos_insert != '' ) $sql_campos = "( $campos_insert_select )";
					if( $where != '' ) $sql_where = "WHERE $where";
					if( $limit != '' ) $sql_limit = "LIMIT $limit";
					return $sql_query->query( "INSERT INTO $tabla_insert_select $sql_campos SELECT $valores FROM $tabla $sql_where $sql_limit" , 1 );
				}
				# SQL para Replace
				if( $accion == 'replace' )
				{
					return $sql_query->query( "REPLACE INTO $tabla ($sql_campos) VALUES ($sql_valores)",1);
				}
				# SQL para Delete
				if( $accion == 'delete' )
				{
					if( $valores != '' )
						return $sql_query->query( "DELETE FROM $tabla WHERE $valores",1);
					else
						ferror("Debe pasar un argumento para WHERE, si desea borrar todo ingrese un comparación que de verdadero. Ej.: '1=1'.");
				}
				return false;
			}
			
			/*
			* Selects records from a given table.
			* SELECT $values FROM $table WHERE $where ORDER BY $order LIMIT $limit
			* @author Alejandro Vidal Quiroga <hide@address.com>
			* @param string $table SQL from part.
			* @param string $values SQL select part.
			* @param string $where SQL where part.
			* @param string $order SQL order by part.
			* @param string $limit SQL limit part.
			* @param bool $fetch If true fetch_object a row atomatically.
			* @return mixed If called estatically returns a DBI object whith the obtained recordset,
			* if called from an object returns the number of records obtained.
			*/
			function select( $table, $values = '*', $where = '', $order = '', $limit = '', $fetch = '' ){
				if( $this ){
					$sql_query = &$this;
				}else{
					$sql_query = new DBI;
				}
				$sql_query->tabla = $table;
				$sql_query->values = $values;
				$sql_query->where = $where;
				$sql_query->order = $order;
				$sql_query->limit = $limit;
				if( $sql_query->sql( 'select' , $table , $values , $where, $order, $limit, $fetch ) ){
					if( $this ){
						return $sql_query->num_rows();
					}else{
						return $sql_query;
					}
				}
				return false;
			}

			function union_select( $table, $values = '*', $where = '', $limit = '' )
			{
				if( $this )
				{
					$sql_query = &$this;
				}
				else
				{
					$sql_query = new DBI;
				}
				$sql_query->tabla = $table;
				if( $sql_query->sql( 'union_select' , $table , $values , $where, '', $limit, $fetch ) )
				{
					return $sql_query;
				}
				return false;
			}
			
			/**
			* Genera el sql necesario para hacer una UNION entre dos querys, ejem.:
			* dbi::union( dbi::union_select( 'clientes_1', 'nombre' ), dbi::union_select( 'clientes_2', 'nombre' ), 'ALL', 'nombre' );
			* se le puede pasar cualquier cantidad de union_selects, sien los dos ultimos parametros opcionales siempre el all y order.
			* @author Alejandro Vidal Quiroga <hide@address.com>
			* @param string $all Indica si se utilizará la expresion ALL para la union. Default no.
			* @param string $order El orden que se utilizará para la union. Default ninguno.
			* @return dbi If succesful return the dbi result, else return false.
			*/
			function union()
			{
				if( $this )
				{
					$sql_query = &$this;
				}
				else
				{
					$sql_query = new DBI;
				}
				
				$ret = false;
				if ( func_num_args() > 1 ) {
					$parms = func_get_args();
					
					$sep = '';
					$sep_union = 'UNION'.( $parms[sizeof($parms)-2] ? ' ALL' : '' );
					
					foreach( $parms as $sql )
					{
						if( is_a( $sql, 'dbi' ) )
						{
							$sql_query->sql .= $sep.' '.$sql->sql.' ';
							$sep = $sep_union;
						}
					}
					if( is_string( $parms[sizeof($parms)-1] ) )
					{
						$sql_query->sql .= "ORDER BY ".$parms[sizeof($parms)-1];
					}
					if( $sql_query->query() )
					{
						$ret = $sql_query;
					}
				}
				return $ret;
			}

			/**
			* Update a record into a table. It can search the field values into the
			* $GLOBALS array and process blob if you add "::blob" sufix to the field name.
			* It's compatible with the "Image DBI Architecture":
			* "fieldname_image" is a blob field.
			* "fieldname_name" has the file name.
			* "fieldname_mime" has the file mime.
			* @author Alejandro Vidal Quiroga <hide@address.com>
			* @param string $table The table where the record will be inserted.
			* @param string $values The values for the new record fields.
			* @return int If succesful return the inserted record id, else return false.
			*/
			function update( $tabla, $valores, $where){
				if( $this ){
					$sql_query = &$this;
				}else{
					$sql_query = new DBI;
				}
				$sql_query->tabla = $tabla;
				if( $sql_query->sql( 'update' , $sql_query->tabla , $valores , $where) ){
					return $sql_query->affected_rows();
				}
				return false;
			}

			function execute( $sp, $values = '', $fetch = 0 )
			{
				if( $this )
				{
					$sql_query = &$this;
				}
				else
				{
					$sql_query = new DBI;
				}
				if( $sql_query->sql('execute', $sp, $values, '', '', $fetch ) )
				{
					$sql_query->free();
					return true;
				}
				return false;
			}
			
			function execute_insert_file( $sp, $blob, $values )
			{
				if( $this )
				{
					$sql_query = &$this;
				}
				else
				{
					$sql_query = new DBI;
				}
				$values = $blob."=\"".addslashes(addslashes( addcslashes( getfile($GLOBALS[$blob]), "," )))."\",".
						$blob."_name='".$GLOBALS[$blob.'_name']."',".
						$blob."_mime='".$GLOBALS[$blob.'_type']."',".			
						$values;
						
				return $sql_query->execute(
						$sp,
						$values
				);
			}

			function execute_insert( $sp, $values )
			{
				if( $this )
				{
					$sql_query = &$this;
				}
				else
				{
					$sql_query = new DBI;
				}
				if( $sql_query->sql('execute', $sp, $values ) )
				{
					$sql_query->fetch_object();
					$sql_query->last_id = $sql_query->row->id;

					return $sql_query->last_id;
				}
				return false;
			}

			function execute_select( $sp, $values = '' )
			{
				if( $this )
				{
					$sql_query = &$this;
				}
				else
				{
					$sql_query = new DBI;
				}
				if( $sql_query->sql('execute', $sp, $values ) )
				{
					return $sql_query;
				}
				return false;
			}

			function execute_record( $sp, $values = '' )
			{
				if( $this )
				{
					$sql_query = &$this;
				}
				else
				{
					$sql_query = new DBI;
				}
				if( $sql_query->sql('execute', $sp, $values, '', '' ) )
				{
					$sql_query->fetch_object();
					$reg = $sql_query->row;
					if( !$this ){
						$sql_query->free();
					}
					return $reg;
				}
				return false;
			}
			/**
			* Insert a record into a table. It can search the field values into the
			* $GLOBALS array and process blob if you add "::blob" sufix to the field name.
			* It's compatible with the "Image DBI Architecture":
			* "fieldname_image" is a blob field.
			* "fieldname_name" has the file name.
			* "fieldname_mime" has the file mime.
			* @author Alejandro Vidal Quiroga <hide@address.com>
			* @param string $table The table where the record will be inserted.
			* @param string $values The values for the new record fields.
			* @return int If succesful return the inserted record id, else return false.
			*/
			function insert( $table, $values )
			{
				if( $this ){
					$sql_query = &$this;
				}else{
					$sql_query = new DBI;
				}
				$sql_query->tabla = $table;				
				if($sql_query->sql('insert', $sql_query->tabla, $values)){
					return $sql_query->last_id();
				}
				return false;
			}
			
			function insert_multiple( $table, $values )
			{
				if( $this )
				{
					$sql_query = &$this;
				}
				else
				{
					$sql_query = new DBI;
				}
				$sql_query->tabla = $table;
				
				return $sql_query->sql('insert_multiple', $sql_query->tabla, $values);
			}
			
			/*
			* Insert selected records from a query.
			* INSERT INTO $table_insert SELECT $values FROM $table WHERE $where LIMIT $limit
			* @author Alejandro Vidal Quiroga <hide@address.com>
			* @param string $table_insert SQL INSERT part.
			* @param string $table SQL FROM part.
			* @param string $values SQL SELECT part.
			* @param string $where SQL WHERE part.
			* @param string $limit SQL LIMIT part.
			* @return integer It returns how much rows are affected.
			*/
			function insert_select( $table_insert, $campos_insert, $table, $values = '*', $where = '', $limit = '' ){
				if( $this ){
					$sql_query = &$this;
				}else{
					$sql_query = new DBI;
				}
				$sql_query->tabla = $table;
				if( $sql_query->sql( 'insert_select' , $table , $values , $where, '', $limit, '', $table_insert, $campos_insert ) ){
					return $sql_query->affected_rows();
				}
				return false;
			}
			
			/**
			* Replace a record into a table if there is one with the same key value, if there isn't
			* a new record is generated. It can search the field values into the
			* $GLOBALS array and process blob if you add "::blob" sufix to the field name.
			* It's compatible with the "Image DBI Architecture":
			* "fieldname_image" is a blob field.
			* "fieldname_name" has the file name.
			* "fieldname_mime" has the file mime.
			* @author Alejandro Vidal Quiroga <hide@address.com>
			* @param string $table The table where the record will be inserted or replaced.
			* @param string $values The values for the new record fields.
			* @return int If succesful return the inserted record id, else return false.
			*/
			function replace( $table, $values ){
				if( $this ){
					$sql_query = &$this;
				}else{
					$sql_query = new DBI;
				}
				$sql_query->tabla = $table;				
				if( $sql_query->sql( 'replace', $sql_query->tabla, $values ) ){
					return true;
				}
				return false;
			}
			/**
			* Insert a record on a table. It can search the field values into the
			* $GLOBALS array and process blob if you add "::blob" sufix to a field name.
			* It's compatible with the "Image DBI Architecture":
			* "fieldname_image" is a blob field.
			* "fieldname_name" has the file name.
			* "fieldname_mime" has the file mime.
			* @author Alejandro Vidal Quiroga <hide@address.com>
			* @param string $table The table where the record will be inserted.
			* @param string $values The values for the new record fields.
			* @param string $auto_id Auto index field.
			* @return int If succesful return the inserted record, else return false.
			*/
			function insert_record( $table, $values, $auto_id = 'id' ){
				if( $this ){
					$sql_query = &$this;
				}else{
					$sql_query = new DBI;
				}
				if( $id = $sql_query->insert( $table, $values ) )
				{
					return $sql_query->record( $table, "$auto_id=$id" );
				}
				return false;
			}
			
			# Implementación Delete de SQL
			function delete( $tabla, $where){
				if( $this ){
					$sql_query = &$this;
				}else{
					$sql_query = new DBI;
				}
				$sql_query->tabla = $tabla;
				if($sql_query->sql('delete', $tabla, $where)){
					return $sql_query->affected_rows();
				}
				return false;
			}
			
			# Cuenta los registros del query
			function count()
			{
				if( $this->tipo == 'ibase' )
				{
					$sql = preg_replace('/SELECT.*FROM/is','SELECT COUNT(*) AS "dbi_nro" FROM',$this->sql);
					if( $this->query( $sql, 4 ) )
					{
						$this->num_rows = $this->row['dbi_nro'];
						return true;
					}
				}
				elseif( $this->tipo == 'mssql' )
				{
					$this->num_rows = @mssql_num_rows( $this->query );
				}
				else
				{
					$this->num_rows = $this->query->numRows();
				}
				
				if( $this->error( $this->num_rows ) )
				{
					return true;
				}
				return false;
			}

			# Libera el objeto

			function free()
			{
				if( $this->query )
				{
					$this->query->free();
					$this->sql = '';
					$this->num_rows = 0;
					$this->last_id = 0;
					return true;
				}
				return false;
			}

			# Cierra el objeto
			function close()
			{
				$this->conn->disconnect();
				$this->sql='';
				$this->num_rows=0;
				$this->last_id=0;
				return true;
			}
			
			# Vuelve el puntero al registro 0
			function reset()
			{
				if( $this->query )
				{
					if( $this->num_rows() > 0 )
					{
						if( $this->tipo == 'mysql')
						{
							if( mysql_data_seek( $this->query->result, 0) )
							{
								return true;
							}
						}
						elseif( $this->tipo == 'mssql')
						{
							if( mssql_data_seek( $this->query->result, 0) )
							{
								return true;
							}
						}
						else
						{
							die('Error: no se tiene información para resetear este server.');
						}
					}
				}
				return false;
			}
			
			# Devuelve el ID del ultimo registro insertado.
			function last_id()
			{
				if( $this->tipo == 'ibase' )
				{
					$this->last_id = $this->campo( 'last_insert_ids', "'$tabla'" , 'ID', 'tabla');
				}
				elseif( $this->tipo == 'mysql' )
				{
					$this->last_id = mysql_insert_id();
				}
				elseif( $this->tipo == 'pgsql' )
				{
					$this->last_id = $this->camposql( "SELECT currval('".$this->tabla.$this->pg_tableAutoIndex."')" );
				}
				return $this->last_id;
			}

			# Devuelve el numero de registros.
			function num_rows()
			{
				return $this->num_rows;
			}

			# Devuelve el numero de registros.
			function affected_rows()
			{
				$this->affected_rows = $this->conn->affectedRows();
				if( !$this->error( $this->affected_rows ) )
				{
					return $this->affected_rows;
				}
				return false;
			}

			# Imprime el SQL en buffer.
			function print_sql( $retornar = false, $error=false )
			{
				if($error)
				{
					$sql_formateado=preg_replace('/\r/m', '', $error);
				}
				else
				{
					$sql_formateado=preg_replace('/\r/m', '', $this->sql);
				}
				if( $retornar )
				{
					return "<table width=\"100%\" align=\"left\" bgcolor=\"#cccccc\"><tr><td bgcolor=\"#FFFFFF\"><font face=\"verdana\" color=\"#000000\" size=\"3\"><b><pre>".htmlentities($sql_formateado)."</pre></b></font></td></tr></table><br>";
				}
				else
				{
					echo "<table width=\"100%\" align=\"left\" bgcolor=\"#cccccc\"><tr><td bgcolor=\"#FFFFFF\"><font face=\"verdana\" color=\"#000000\" size=\"3\"><b><pre>".htmlentities($sql_formateado)."</pre></b></font></td></tr></table><br>";
				}
				return true;
			}

			function error_catch( $codigo, $funcion )
			{
				$this->exceptions[$codigo] = $funcion;
			}

			# Notifica si hubo algun error.
			function errno()
			{
				switch( $this->tipo )
				{
					case 'mysql':
						$ret = mysql_errno();
						break;
					case 'mssql':
						$ret = mssql_get_last_message();
						break;
					default:
						$ret = false;
				}
				return $ret;
			}
			
			function error( $obj )
			{
				if( DB::isError( $obj ) )
				{
					if( is_array( $this->exceptions ) && array_key_exists( $this->errno(), $this->exceptions ) )
					{
						eval( $this->exceptions[ $this->errno() ]."();");
					}
					else
					{
						$this->rollback();
						$msg_error_text=
							"Sitio: ".$_SERVER['HTTP_HOST']."\n".
							"Pagina: ".basename($_SERVER['SCRIPT_FILENAME'])."\n".
							$obj->getMessage()."\n".
							$this->print_sql(1, $obj->getUserinfo())."\n"
						;
						$msg_error="
							Sitio: ".$_SERVER['HTTP_HOST']."<br>
							Pagina: ".basename($_SERVER['SCRIPT_FILENAME'])."<br>
							<font color=\"#FF0000\">".$obj->getMessage()."</font><br>
							".$this->print_sql(1, $obj->getUserinfo())."
							<br>
						";
						if(CFG_debug==true){
							echo $msg_error;
						}else{
							$boundary = md5( rand() );
							mail(
								CFG_mailError,
								'Error: '.CFG_site,
								"--$boundary\nContent-Type: text/plain\n\n$msg_error_text\n--$boundary\nContent-Type: text/html\n\n$msg_error",
								"MIME-Version: 1.0\nContent-Type: multipart/alternative;\n\tboundary=\"$boundary\"\n\n"
							);
							?>							
							<br>
							<table width="90%" bgcolor="#FFFFFF">
								<tr><td>
										<font color="#FF0000">
										Ha ocurrido un error, se ha notificado del mismo al administrador del sistema.<br>
										</font>
										<br>
										<font color="#000000">
										Si desea enviar un comentario haga click <a href="mailto:<?=CFG_mailError?>"><font color="#000000">aqui</font></a>.
										</font>
								</td></tr>
							</table>
							<br>
							<?
							exit();
						}
					}
					return true;
				}
				return false;
			}

			# Devuelve y setea a la propiedad 'row' el siguiente registro en modo ARRAY.
			function fetch( $row_num=NULL )
			{
				$this->row=$this->query->fetchRow(DB_FETCHMODE_ORDERED, $row_num);
				if( !$this->error($this->row) )
				{
					return $this->row;
				}
				else
				{
					return false;
				}
			}

			# Devuelve el siguiente registro en modo OBJETO.
			function fetch_object($row_num=NULL)
			{
				$this->row=$this->query->fetchRow(DB_FETCHMODE_OBJECT, $row_num);
				if(!$this->error($this->row))
				{
					$campos = get_object_vars( $this->row );
					if( is_array( $campos ) )
					{
						$campos = array_keys( $campos );
						foreach( $campos as $campo )
						{
							if( in_array( $campo, $this->subqueries ) )
							{
								preg_match_all( '/\(#([^)]+)\)/', $this->row->{$campo}, $subcampos );
								array_pop( $subcampos );
								$sql = $this->row->{$campo};
								foreach( $subcampos[0] as $subcampo )
								{
									$sql = str_replace( "$subcampo", "'".$this->row->{substr($subcampo,2,-1)}."'", $sql );
								}
								$subquery = new dbi();
								$subquery->query( stripslashes($sql) );
								if( $this->print_subsql )
								{
									$subquery->print_sql();
								}
								$subquery->fetch();
								$this->row->{$campo} = $subquery->row[0];
							}
						}
					}
					return $this->row;
				}
				else
				{
					return false;
				}
			}

			# Devuelve el siguiente registro en modo Asociativo.
			function fetch_assoc( $row_num=NULL )
			 {
				$this->row = $this->query->fetchRow( DB_FETCHMODE_ASSOC, $row_num );
				if( !$this->error($this->row) )
				{
					return $this->row;
				}
				else
				{
					return false;
				}
			}
			
			# Value: Devuelve el valor del campo especificado
			# identificado por su tabla y condición.
			function value( $tabla , $where , $campo )
			{
				if( $this )
				{
					$campos = &$this;
				}
				else
				{
					$campos=new DBI;
				}
				$campos->record( $tabla , $where, $campo, DBI_FETCH_ORDERED );
				$valor = $campos->row[0];
				if( !$this )
				{
					$campos->free();
				}
				return $valor;
			}

			# Record: almacena todos los campos de un registro
			# identificado por su tabla y condición.
			function record( $tabla , $where = '1=1', $campos = '*', $fetch = DBI_FETCH_OBJECT )
			{	
				if( $this )
				{
					$registro = &$this;
				}
				else
				{
					$registro = new DBI;
				}
				$registro->select( $tabla, $campos, $where, '', '1', $fetch );
				$reg = $registro->row;
				if( !$this )
				{
					$registro->free();
				}
				return $reg;
			}

			# Devuelve un volcado XML de la consulta SQL
			function XMLdump( $sql , $nombre = 'Registro')
			{
				$registros = new DBI($this->db,$this->usuario,$this->clave,$this->server,$this->tipo);		
				$registros->query($sql);
				$buffer = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n";
				$buffer .= "<registros>\r\n";
				while ( $registro = $registros->fetch_assoc() ) {
					$buffer .= "\t<".htmlspecialchars($nombre)." id=\"".$registro['ID']."\">\r\n";
					foreach ($registro as $campo => $valor) {
						$buffer .= "\t\t<".htmlspecialchars($campo).">".htmlspecialchars($valor)."</".htmlspecialchars($campo).">\r\n";
					}
					$buffer .= "\t</".htmlspecialchars($nombre).">\r\n";

				}

				$buffer .= "</registros>\r\n";

				return $buffer;

			}
			function arrayFields()
			{
					$array = array();
					$registro = $this->query->tableInfo();
					for( $i = 0 ; $i < count($registro) ; $i++ ){
						$array[$i]['name'] = $registro[$i]['name'];
						$array[$i]['type'] = $registro[$i]['type'];
						$array[$i]['len'] = $registro[$i]['len'];
					}
					return $array;
			}
			
			function arrayDump()
			{
					$array = array();
					$i=0;
					while( $registro = $this->fetch_assoc() )
					{
						foreach($registro as $campo => $valor)
						{
							$array[$i][$campo]=$valor;
						}
						$i++;
					}
					return $array;
			}
			
			// Este metodo tranforma el contenido del campo "propiedad" en una propiedad real
			// y el contenido del campo "valor" en el valor de esta propiedad, devolviendo el
			// objeto creado.
			function objectDump( $tabla, $campo_propiedad = 'propiedad', $campo_valor='valor', $where='1=1' )
			{
				$object = array();
				
				if( $propiedades = dbi::select( $tabla, "DISTINCT( $campo_propiedad ) as propiedad, $campo_valor as valor", $where) )
				{
					while( $propiedad = $propiedades->fetch_object() )
					{
						$object[ $propiedad->propiedad ] = $propiedad->valor;
					}
					return (object)$object;
				}
				
				return false;
			}
			
			/**
			* Concatena mediante un separador un campo dado de la consulta actual. Necesita que
			* se halla realizado una consulta previamente.
			* @author Alejandro Vidal Quiroga <hide@address.com>
			* @param string $field The field name witch will be concatenate.
			* @param string $separator The caracter witch will be saparate the values.
			* @return string
			*/
			function concatField( $field, $with = ',' )
			{
					$values = '';
					$sep = '';
					while ( $registro = $this->fetch_assoc() )
					{
						$values .= "$sep$registro[$field]";
						$sep = $with;
					}
					return $values;
			}
			# Dibuja una tabla con los campos seleccionados
			function tabla( $print = 0 )
			{
				if( !$this )
				{
					echo "Debe hacer una consulta primero!";
					return false;
				}
				else
				{
					$i = 1;
					while( $this->fetch_assoc() )
					{
						$registro='';
						foreach( $this->row as $campo => $valor )
						{
							if( $i )
							{
								$campos .= "<td>".htmlentities($campo)."</td>";
							}
							$registro .= "<td>".( $valor ? nl2br(htmlentities($valor)) : '&nbsp;' )."</td>";
						}
						$i = 0;
						$registros .= "<tr>$registro</tr>";
					}
					$tabla = '<table width="100%" border="1"><tr>'.$campos.'</tr>'.$registros.'</table>';
					if( $print )
					{
						echo $tabla;
					}
					return $tabla;
				}
			}
		}

		# Se arma un objeto DBI por defecto llamado "db"
		if( $db != 'no' ) $db = new DBI;
?>
Return current item: DBInterface