📄 expr.inc.php
字号:
if (in_array($value, array('AND','OR','NOT')))
{
$value = strtolower($value);
}
$this->value= $value;
$this->fuzzy = $fuzzy;
$this->proximity = $proximity;
}
public function getValue()
{
return $this->value;
}
/**
* Converts the value to a string
*
* @return unknown
*/
public function __toString()
{
return (string) "\"$this->value\"";
}
public function toViz(&$str, $phase)
{
if ($phase == 0)
{
$expr_id = $this->getExprId();
$value = addslashes($this->value);
$str .= "struct$expr_id [style=ellipse, label=\"$expr_id: \\\"$value\\\"\"]\n";
}
}
public function getSQL($field, $fieldname, $op, $not=false)
{
$val = $this->getValue();
if (strpos($val, '*') !== false || strpos($val, '?') !== false)
{
$val = str_replace(array('?','*'), array('_','%'), $val);
}
switch($op)
{
case ExprOp::LIKE:
break;
case ExprOp::CONTAINS:
$val = "%$val%";
break;
case ExprOp::STARTS_WITH:
$val = "$val%";
break;
case ExprOp::ENDS_WITH:
$val = "%$val";
break;
}
$val = $field->modifyValue($val);
$quote = '';
if ($field->isValueQuoted())
{
$val = addslashes($val);
$quote = '\'';
}
switch($op)
{
case ExprOp::LIKE:
$sql = "$fieldname LIKE $quote$val$quote";
if ($not) $sql = "not ($sql)";
break;
case ExprOp::CONTAINS:
$sql = "$fieldname LIKE $quote$val$quote";
if ($not) $sql = "not ($sql)";
break;
case ExprOp::STARTS_WITH:
$sql = "$fieldname LIKE $quote$val$quote";
if ($not) $sql = "not ($sql)";
break;
case ExprOp::ENDS_WITH:
$sql = "$fieldname LIKE $quote$val$quote";
if ($not) $sql = "not ($sql)";
break;
case ExprOp::IS:
if ($not)
$sql = "$fieldname != $quote$val$quote";
else
$sql = "$fieldname = $quote$val$quote";
break;
case ExprOp::GREATER_THAN :
if ($not)
$sql = "$fieldname <= $quote$val$quote";
else
$sql = "$fieldname > $quote$val$quote";
break;
case ExprOp::GREATER_THAN_EQUAL :
if ($not)
$sql = "$fieldname < $quote$val$quote";
else
$sql = "$fieldname >= $quote$val$quote";
break;
case ExprOp::LESS_THAN :
if ($not)
$sql = "$fieldname >= $quote$val$quote";
else
$sql = "$fieldname < $quote$val$quote";
break;
case ExprOp::LESS_THAN_EQUAL :
if ($not)
$sql = "$fieldname > $quote$val$quote";
else
$sql = "$fieldname <= $quote$val$quote";
break;
default:
throw new Exception(sprintf(_kt('Unknown op: %s'), $op));
}
return $sql;
}
}
class ValueListExpr extends Expr
{
/**
* The value
*
* @var mixed
*/
protected $values;
/**
* Constructor for the value expression
*
* @param mixed $value
*/
public function __construct($value)
{
parent::__construct($value);
$this->values=array($value);
}
public function addValue($value)
{
$this->values[] = $value;
}
public function getValue($param=null)
{
if (!empty($param))
{
return $this->values[$param];
}
$str = '';
foreach($this->values as $value)
{
if ($str != '') $str .= ',';
$str .= "\"$value\"";
}
return $str;
}
/**
* Converts the value to a string
*
* @return unknown
*/
public function __toString()
{
return $this->getValue();
}
public function toViz(&$str, $phase)
{
if ($phase == 0)
{
$expr_id = $this->getExprId();
$str .= "struct$expr_id [style=ellipse, label=\"$expr_id: ";
$i=0;
foreach($this->values as $value)
{
if ($i++>0) $str .= ',';
$value = addslashes($value);
$str .= "\\\"$value\\\"";
}
$str .= "\"]\n";
}
}
public function rewrite(&$left, &$op, &$right, &$not)
{
if (count($this->values) == 1)
{
$right = new ValueExpr($this->values[0]);
return;
}
$newops = array();
foreach($this->values as $value)
{
$classname = get_class($left);
$class = new $classname;
$newop = new OpExpr($class, $op, $value);
$newops[] = $newop;
}
$result = $newops[0];
for($i=1;$i<count($newops);$i++)
{
$result = new OpExpr($result, ExprOp::OP_OR, $newops[$i]);
}
$left = $result->left();
$op = $result->op();
$right = $result->right();
}
}
class BetweenValueExpr extends ValueExpr
{
protected $endvalue;
public function __construct($start, $end)
{
parent::__construct($start);
$this->endvalue = $end;
}
public function getStart()
{
return $this->getValue();
}
public function getEnd()
{
return $this->endvalue;
}
/**
* Converts the value to a string
*
* @return unknown
*/
public function __toString()
{
return (string) $this->value . ' AND ' . $this->endvalue;
}
public function toViz(&$str, $phase)
{
if ($phase == 0)
{
$value = addslashes($this->value);
$value2 = addslashes($this->endvalue);
$expr_id = $this->getExprId();
$str .= "struct$expr_id [style=rounded, label=\"$expr_id: $value AND $value2\"]\n";
}
}
public function getSQL($field, $fieldname, $op, $not=false)
{
if ($op != ExprOp::BETWEEN)
{
throw new Exception(sprintf(_kt('Unexpected operator: %s'), $op));
}
$quote = '';
$start = $field->modifyValue($this->getStart());
$end = $field->modifyValue($this->getEnd());
if ($field->isValueQuoted())
{
$start = addslashes($start);
$end = addslashes($end);
$quote = '\'';
}
$not = $not?' NOT ':'';
return "$not ($fieldname $op $quote$start$quote AND $quote$end$quote) ";
}
}
interface QueryBuilder
{
function buildComplexQuery($expr);
function buildSimpleQuery($op, $group);
function getRanking($result);
function getResultText($result);
}
class TextQueryBuilder implements QueryBuilder
{
private $text;
private $query;
public function buildComplexQuery($expr)
{
$left = $expr->left();
$right = $expr->right();
if (DefaultOpCollection::isBoolean($expr))
{
$query = '(' . $this->buildComplexQuery($left) . ' ' . $expr->op() . ' ' . $this->buildComplexQuery($right) . ')';
if ($expr->not())
{
$query = "NOT $query";
}
}
else
{
$fieldname = $left->getField();
$value = addslashes($right->getValue());
$not = $expr->not()?' NOT ':'';
if (empty($value))
{
// minor hack to prevent the case of 'field:'. results are no 'field:""'
$value = ' ';
}
if (strpos($value, ' ') === false)
{
$query = "$not$fieldname:$value";
}
else
{
$query = "$not$fieldname:\"$value\"";
}
}
return $query;
}
public function buildSimpleQuery($op, $group)
{
$query = '';
foreach($group as $expr)
{
if (!empty($query))
{
$query .= " $op ";
}
$left = $expr->left();
$right = $expr->right();
$fieldname = $left->getField();
$value = addslashes($right->getValue());
$not = $expr->not()?' NOT ':'';
if (strpos($value, ' ') !== false)
$query .= "$not$fieldname:\"$value\"";
else
$query .= "$not$fieldname:$value";
}
return $query;
}
public function getRanking($result)
{
$init = $result->Rank;
$score=0;
$ranker = RankManager::get();
$score += $init *$ranker->scoreField('DocumentText', 'S');
return $score;
}
public function setQuery($query)
{
$this->query = $query;
}
function getResultText($result)
{
// not require!
return '';
}
}
class SQLQueryBuilder implements QueryBuilder
{
private $used_tables;
private $aliases;
private $sql;
private $db;
private $metadata;
private $context;
public function __construct($context)
{
$this->context = $context;
switch ($context)
{
case ExprContext::DOCUMENT:
$this->used_tables = array(
'documents'=>1,
'document_metadata_version'=>1,
'document_content_version'=>0,
'tag_words'=>0,
'document_fields_link'=>0
);
$this->aliases = array(
'documents'=>'d',
'document_metadata_version'=>'dmv',
'document_content_version'=>'dcv',
'tag_words'=>'tw',
'document_fields_link'=>'pdfl'
);
break;
case ExprContext::FOLDER:
$this->used_tables = array(
'folders'=>1,
);
$this->aliases = array(
'folders'=>'f',
);
break;
default:
throw new Exception('This was not expected - Context = ' . $context);
}
$this->sql = '';
$this->db = array();
$this->metadata = array();
}
/**
* This looks up a table name to find the appropriate alias.
*
* @param string $tablename
* @return string
*/
private function resolveTableToAlias($tablename)
{
if (array_key_exists($tablename, $this->aliases))
{
return $this->aliases[$tablename];
}
throw new Exception("Unknown tablename '$tablename'");
}
private function exploreExprs($expr, $parent=null)
{
if ($expr->isMetadataField())
{
$this->metadata[] = & $parent;
}
elseif ($expr->isDBExpr())
{
if (($this->context & $expr->appliesToContext()) == $this->context)
{
$this->db[] = & $parent;
$tablename = $expr->getTable();
if (array_key_exists($tablename, $this->used_tables))
{
$this->used_tables[$tablename]++;
}
}
}
elseif ($expr->isOpExpr())
{
$left = & $expr->left();
$right = & $expr->right();
if (DefaultOpCollection::isBoolean($expr))
{
$this->exploreExprs($left, $expr);
$this->exploreExprs($right, $expr);
}
else
{
// if it is not a boolean, we only need to explore left as it is the one where the main field is defined.
$this->exploreExprs($left, $expr);
}
}
}
private function exploreGroup($group)
{
// split up metadata and determine table usage
foreach($group as $expr)
{
$field = $expr->left();
if ($field->isMetadataField())
{
$this->metadata[] = $expr->getParent();
}
elseif ($field->isDBExpr())
{
$this->db[] = $expr->getParent();
$tablename = $field->getTable();
if (array_key_exists($tablename, $this->used_tables))
{
$this->used_tables[$tablename]++;
}
}
}
}
private function getFieldnameFromExpr($expr)
{
$field = $expr->left();
if (is_null($field->getJoinTable()))
{
$alias = $this->resolveTableToAlias($field->getTable());
$fieldname = $alias . '.' . $field->getField();
}
else
{
$offset = $this->resolveJoinOffset($expr);
$matching = $field->getMatchingField();
$tablename = $field->getJoinTable();
$fieldname = "$tablename$offset.$matching";
}
return $fieldname;
}
private function getSQLEvalExpr($expr)
{
$left = $expr->left();
$right = $expr->right();
$isNot = $expr->not();
if ($left->isMetadataField() )
{
if ($this->context == ExprContext::DOCUMENT)
{
$offset = $this->resolveMetadataOffset($expr) + 1;
$fieldset = $left->getField();
$query = '(';
if ($isNot)
{
$query .= "df$offset.name IS NULL OR ";
}
$query .= '(' . "df$offset.name='$fieldset' AND " . $right->getSQL($left, "dfl$offset.value", $expr->op(), $isNot) . ')';
$query .= ')';
}
else
{
$query = 'false';
}
}
else
{
if ($this->context == ExprContext::FOLDER && $left->getContext() != ExprContext::FOLDER)
{
$query = 'false';
}
else
{
$fieldname = $this->getFieldnameFromExpr($expr);
$query = $right->getSQL($left, $left->modifyName($fieldname), $expr->op(), $isNot);
}
}
return $query;
}
private function buildCoreSQL()
{
if (count($this->metadata) + count($this->db) == 0)
{
// return empty result set
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -