<?php if(!defined('GLADIUS_HI_VER')){header("HTTP/1.0 404 Not Found");die;}
## Gladius Database Engine
# @author legolas558
# @version 0.8.1
# Licensed under GNU General Public License (GPL)
#
#
# SELECT command interpretation
#

if (!defined('_G__FIELD'))
	define('_G__FIELD', '(\\w+(\\.((\\w+)|\\*))?)|(\\*)');

	$fields = array();	// mapped as (field_name, alias, is_function)
	// (1) get the selected fields
	while (preg_match('/\\s*((\\w+\\s*\\([^\\)]*\\))|'._G__FIELD.')(\\s+(as\\s+)?(\\w+))?\\s*(,)?/iA',
		$this->sql, $m, PREG_OFFSET_CAPTURE, $this->offset)) {

		$last = count($m)-1;
		$this->offset = $m[$last][1]+strlen($m[$last][0]);
		
		if ($last==9) {
			$alias = $m[9][0];
			if (gladius_reserved(gladius_strtoupper($alias))) {
				if ($m[$last-1][1]!=-1) {
					$this->_error(_G__INVALID_ALIAS, $alias);
					$result = false;
					return;
				}
				// save the last field of the SELECT query and break matching
				$fields[] = array($m[1][0], '', $m[2][1]!=-1);
				$this->offset= $m[0][1] + strlen($m[0][0]);
				break;
			}
		} else
			$alias = $m[9][0];

		// alias unicity will later be checked
		$fields[] = array($m[1][0], $alias, $m[2][1]!=-1);
		
		if ($m[$last][0]!=',')
			break;
	} // WEND
	
	if (empty($fields)) {
		$this->_error(_G__MALFORMED_SQL);
		$result = false;
		return;
	}
	
	// (2) get the source tables
	$from = array();
	if (!$this->_parse_from($from)) {
		$result = false;
		return;
	}
	
	// (3) initialize the source tables
	if (false ===($result = $this->_create_rs($from)))
		return;

	$result->in_subquery = $subquery;
	
	//(4) load the directly selected fields
	if (!$result->_load_fields($fields, $result->aliases) ||
	//(5) parse the WHERE clause and the interested fields
		!$result->_parse_where_expr()) {
		$result = false;
		return;
	}
	
//	debug_chain($result->where);
	
	$result->_aggregate = count($result->_calc_fields);
	
	if (!$subquery) {
		if ($result->_aggregate) {
			if (!$result->_parse_group_expr()) {
				$result = false;
				return;
			}
		} else {
			if (!$result->_parse_order_expr()) {
				$result = false;
				return;
			}
		}
	}
	
	$limits = $result->_parse_limit();
	if ($limits === false) {
		$this->_error(_G__INVALID_LIMIT);
		$result = false;
		return;
	}
	
	if (!$subquery) {
		if (!$this->_terminated()) {
			$result = false;
			return;
		}
	} else {
		// terminate the subquery
		if (preg_match('/\\s*\\)\\s*/A', $this->sql, $m, PREG_OFFSET_CAPTURE, $this->offset)) {
			$this->offset = strlen($m[0][0])+$m[0][1];
		} else {
			$this->_error(_G__INVALID_TERMINATION);
			$result = false;
			return;
		}
	}
	
	//dicriminate between where columns and other columns
	foreach($result->allfields as $fo) {
		$col =& $this->_pick_column($fo->table, $fo->name);	// cache all fields
		if (!isset($col)) {
			$result = false;
			return;
		}
		if (!in_array($fo->name, $result->where_fields))
			$result->iteration_arg[] = $fo->name;	// index the non-where fields
	}

	$result->initiate();
	
	// setup value decoders
	global $GLADIUS_CUSTOM_DATA;
	$result->keys = array();
	$i = 0;
	foreach ($result->fields as $fo) {
		if (in_array($fo->type, $GLADIUS_CUSTOM_DATA)) {
			if (($result->fetch_mode == GLADIUS_FETCH_NUM) || ($result->fetch_mode == GLADIUS_FETCH_BOTH))
				$result->keys[$fo->name] = $i++;
			else
				$result->keys[$fo->name] = $result->fields[$fo->name]->alias;
		}
	}
	
	// if there's something to order, then get the full result
	if (!empty($result->order_way)) {
		include_once GLADIUS_DIR.'gladius_order.php';

		// iteration argument will contain fields not updated by WHERE evaluation + ordering fields not in the selected list
		$result->iteration_arg = array_merge($result->iteration_arg, $result->order_fields);
		// perform iteration without limits (we have to sort the data and then crop the selected)
		// code should be optimized just to consider order and where fields and finally add the other data too
		$result->limit_from = 0;
		$result->limit_length = 0;

		// create a rowset with ordering fields too
		while ($result->_iterate('_order_fetch')) { }
		
		if ($result->row_count==0) {
			$this->_success(0);
			return;
		}
		
		// calculate the aggregate fields
		$result->_calculate_fields();

		// apply ordering
		rowsort($result);
		
		$result->limit_from = $limits[0];
		$result->limit_length = $limits[1];

		// fix the resultset
		$result->recompile_rowset();

		unset($result->order_way);
		unset($result->order_ids);
		$open = true;
	} else {
		$result->limit_from = $limits[0];
		$result->limit_length = $limits[1];
		
		// if there are no aggregate functions proceed as normal
		if (!$result->_aggregate) {
			$result->_iterate('_fetch_row');
			$open = $result->EOF;
		} else {
			// calculate aggregate fileds if there are records
			if ($result->RecordCount())
				$result->_calculate_fields();
			$open = true;
		}
	}

	if (!$subquery)
		$this->_success($result->row_count, 'row', $open);
?>
