Added index hints for CUBRID and Mysql.

git-svn-id: http://xe-core.googlecode.com/svn/branches/1.5.0@9472 201d5d3c-b55e-5fd7-737f-ddc643e51545
This commit is contained in:
ucorina 2011-10-03 17:35:25 +00:00
parent 0b8949cfeb
commit 96b60466be
18 changed files with 350 additions and 4 deletions

View file

@ -28,6 +28,9 @@
require(_XE_PATH_.'classes/db/queryparts/expression/UpdateExpression.class.php');
require(_XE_PATH_.'classes/db/queryparts/table/Table.class.php');
require(_XE_PATH_.'classes/db/queryparts/table/JoinTable.class.php');
require(_XE_PATH_.'classes/db/queryparts/table/CubridTableWithHint.class.php');
require(_XE_PATH_.'classes/db/queryparts/table/MysqlTableWithHint.class.php');
require(_XE_PATH_.'classes/db/queryparts/table/IndexHint.class.php');
require(_XE_PATH_.'classes/db/queryparts/condition/ConditionGroup.class.php');
require(_XE_PATH_.'classes/db/queryparts/condition/Condition.class.php');
require(_XE_PATH_.'classes/db/queryparts/condition/ConditionWithArgument.class.php');
@ -557,6 +560,15 @@
$where = $query->getWhereString($with_values);
if($where != '') $where = ' WHERE ' . $where;
$tableObjects = $query->getTables();
$index_hint_list = '';
foreach($tableObjects as $tableObject){
if(is_a($tableObject, 'CubridTableWithHint'))
$index_hint_list .= $tableObject->getIndexHintString() . ', ';
}
if($index_hint_list != '')
$index_hint_list = 'USING INDEX ' . substr($index_hint_list, 0, -2);
$groupBy = $query->getGroupByString();
if($groupBy != '') $groupBy = ' GROUP BY ' . $groupBy;
@ -566,7 +578,7 @@
$limit = $query->getLimitString();
if($limit != '') $limit = ' LIMIT ' . $limit;
return $select . ' ' . $from . ' ' . $where . ' ' . $groupBy . ' ' . $orderBy . ' ' . $limit;
return $select . ' ' . $from . ' ' . $where . ' ' . $index_hint_list . ' ' . $groupBy . ' ' . $orderBy . ' ' . $limit;
}
function getDeleteSql($query, $with_values = true){

View file

@ -0,0 +1,25 @@
<?php
class CubridTableWithHint extends Table {
var $name;
var $alias;
var $index_hints_list;
function CubridTableWithHint($name, $alias = NULL, $index_hints_list){
parent::Table($name, $alias);
$this->index_hints_list = $index_hints_list;
}
function getIndexHintString(){
$result = '';
foreach($this->index_hints_list as $index_hint){
$result .= $this->alias . '.' . $index_hint->getIndexName()
. ($index_hint->getIndexHintType() == 'FORCE' ? '(+)' : '') . ', ';
}
$result = substr($result, 0, -2);
return $result;
}
}
?>

View file

@ -0,0 +1,21 @@
<?php
class IndexHint {
var $index_name;
var $index_hint_type;
function IndexHint($index_name, $index_hint_type){
$this->index_name = $index_name;
$this->index_hint_type = $index_hint_type;
}
function getIndexName(){
return $this->index_name;
}
function getIndexHintType() {
return $this->index_hint_type;
}
}
?>

View file

@ -0,0 +1,36 @@
<?php
class MysqlTableWithHint extends Table {
var $name;
var $alias;
var $index_hints_list;
function MysqlTableWithHint($name, $alias = NULL, $index_hints_list){
parent::Table($name, $alias);
$this->index_hints_list = $index_hints_list;
}
function toString(){
$result = parent::toString();
$use_index_hint = ''; $force_index_hint = ''; $ignore_index_hint = '';
foreach($this->index_hints_list as $index_hint){
$index_hint_type = $index_hint->getIndexHintType();
if($index_hint_type == 'USE') $use_index_hint .= $index_hint->getIndexName() . ', ';
else if($index_hint_type == 'FORCE') $force_index_hint .= $index_hint->getIndexName() . ', ';
else if($index_hint_type == 'IGNORE') $ignore_index_hint .= $index_hint->getIndexName() . ', ';
}
if($use_index_hint != ''){
$result .= ' USE INDEX (' . substr($use_index_hint, 0, -2) . ') ';
}
if($force_index_hint != ''){
$result .= ' FORCE INDEX (' . substr($force_index_hint, 0, -2) . ') ';
}
if($ignore_index_hint != ''){
$result .= ' IGNORE INDEX (' . substr($ignore_index_hint, 0, -2) . ') ';
}
return $result;
}
}
?>

View file

@ -15,6 +15,7 @@
require(_XE_PATH_.'classes/xml/xmlquery/tags/query/QueryTag.class.php');
require(_XE_PATH_.'classes/xml/xmlquery/tags/table/TableTag.class.php');
require(_XE_PATH_.'classes/xml/xmlquery/tags/table/HintTableTag.class.php');
require(_XE_PATH_.'classes/xml/xmlquery/tags/table/TablesTag.class.php');
require(_XE_PATH_.'classes/xml/xmlquery/tags/column/ColumnTag.class.php');

View file

@ -139,7 +139,10 @@ class QueryTag {
}
function getTables(){
return $this->tables = new TablesTag($this->query->tables);
if($this->query->index_hint->attrs->for == 'ALL' || Context::getDBType() == strtolower($this->query->index_hint->attrs->for))
return $this->tables = new TablesTag($this->query->tables, $this->query->index_hint);
else
return $this->tables = new TablesTag($this->query->tables);
}
function getConditions(){

View file

@ -0,0 +1,48 @@
<?php
/**
* @class HintTableTag
* @author Arnia Sowftare
* @brief Models the <table> tag inside an XML Query file
* and the corresponding <index_hint> tag
*
*/
class HintTableTag extends TableTag {
var $index;
/**
* @brief Initialises Table Tag properties
* @param XML <table> tag $table
*/
function HintTableTag($table, $index){
parent::TableTag($table);
$this->index = $index;
}
function getTableString(){
$dbParser = DB::getParser();
$dbType = ucfirst(Context::getDBType());
$result = sprintf('new %sTableWithHint(\'%s\'%s, array('
, $dbType
, $dbParser->escape($this->name)
, $this->alias ? ', \'' . $dbParser->escape($this->alias) .'\'' : ', null'
//, ', \'' . $dbParser->escape($this->index->name) .'\', \'' . $this->index->type .'\''
);
foreach($this->index as $indx){
$result .= "new IndexHint(";
$result .= '\'' . $dbParser->escape($indx->name) .'\', \'' . $indx->type .'\'' . ') , ';
}
$result = substr($result, 0, -2);
$result .= '))';
return $result;
}
function getArguments(){
if(!isset($this->conditionsTag)) return array();
return $this->conditionsTag->getArguments();
}
}
?>

View file

@ -19,18 +19,32 @@
class TablesTag {
var $tables;
function TablesTag($xml_tables_tag){
function TablesTag($xml_tables_tag, $xml_index_hints_tag = NULL){
$this->tables = array();
$xml_tables = $xml_tables_tag->table;
if(!is_array($xml_tables)) $xml_tables = array($xml_tables);
if($xml_index_hints_tag){
$index_nodes = $xml_index_hints_tag->index;
if(!is_array($index_nodes)) $index_nodes = array($index_nodes);
foreach($index_nodes as $index_node) {
if(!$indexes[$index_node->attrs->table]) $indexes[$index_node->attrs->table] = array();
$count = count($indexes[$index_node->attrs->table]);
$indexes[$index_node->attrs->table][$count]->name = $index_node->attrs->name;
$indexes[$index_node->attrs->table][$count]->type = $index_node->attrs->type;
}
}
foreach($xml_tables as $tag){
if($tag->attrs->query == 'true'){
$this->tables[] = new QueryTag($tag, true);
}
else {
$this->tables[] = new TableTag($tag);
if($indexes && $indexes[$tag->attrs->name])
$this->tables[] = new HintTableTag($tag, $indexes[$tag->attrs->name]);
else
$this->tables[] = new TableTag($tag);
}
}
}

View file

@ -13,6 +13,7 @@
require_once(_XE_PATH_.'test-phpUnit/db/CubridOnlineTest.php');
require_once(_XE_PATH_.'test-phpUnit/db/MssqlTest.php');
require_once(_XE_PATH_.'test-phpUnit/db/MssqlOnlineTest.php');
require_once(_XE_PATH_.'test-phpUnit/db/MysqlTest.php');
require_once(_XE_PATH_.'config/config.inc.php');
// require_once(_XE_PATH_.'classes/object/Object.class.php');
@ -26,6 +27,7 @@
require_once(_XE_PATH_.'classes/db/DB.class.php');
require_once(_XE_PATH_.'classes/db/DBCubrid.class.php');
require_once(_XE_PATH_.'classes/db/DBMssql.class.php');
require_once(_XE_PATH_.'classes/db/DBMysql.class.php');
require_once(_XE_PATH_.'classes/xml/xmlquery/DBParser.class.php');
require_once(_XE_PATH_.'classes/xml/xmlquery/argument/Argument.class.php');
@ -38,6 +40,9 @@
require_once(_XE_PATH_.'classes/db/queryparts/expression/UpdateExpression.class.php');
require_once(_XE_PATH_.'classes/db/queryparts/table/Table.class.php');
require_once(_XE_PATH_.'classes/db/queryparts/table/JoinTable.class.php');
require_once(_XE_PATH_.'classes/db/queryparts/table/CubridTableWithHint.class.php');
require_once(_XE_PATH_.'classes/db/queryparts/table/MysqlTableWithHint.class.php');
require_once(_XE_PATH_.'classes/db/queryparts/table/IndexHint.class.php');
require_once(_XE_PATH_.'classes/db/queryparts/condition/ConditionGroup.class.php');
require_once(_XE_PATH_.'classes/db/queryparts/condition/Condition.class.php');
require_once(_XE_PATH_.'classes/db/queryparts/condition/ConditionWithArgument.class.php');
@ -50,6 +55,7 @@
require_once(_XE_PATH_.'classes/db/queryparts/Subquery.class.php');
require_once(_XE_PATH_.'classes/xml/xmlquery/tags/table/TableTag.class.php');
require_once(_XE_PATH_.'classes/xml/xmlquery/tags/table/HintTableTag.class.php');
require_once(_XE_PATH_.'classes/xml/xmlquery/tags/condition/ConditionTag.class.php');
require_once(_XE_PATH_.'classes/xml/xmlquery/queryargument/QueryArgument.class.php');
require_once(_XE_PATH_.'classes/xml/xmlquery/queryargument/SortQueryArgument.class.php');

View file

@ -0,0 +1,29 @@
<?php
/**
* Base class for tests for Mysql SQL syntax
*/
class MysqlTest extends DBTest {
/**
* Prepare runtime context - tell DB class that current DB is CUBRID
*/
protected function setUp() {
$oContext = &Context::getInstance();
$db_info->master_db = array('db_type' => 'mysql','db_table_prefix' => 'xe_');
$db_info->slave_db = array(array('db_type' => 'mysql','db_table_prefix' => 'xe_'));
$oContext->setDbInfo($db_info);
DB::getParser(true);
}
/**
* Free resources - reset static DB and QueryParser
*/
protected function tearDown() {
unset($GLOBALS['__DB__']);
}
}
?>

View file

@ -0,0 +1,39 @@
<?php
class CubridIndexHintTest extends CubridTest {
var $xmlPath = 'data/';
function CubridIndexHintTest(){
$this->xmlPath = str_replace('CubridIndexHintTest.php', '', str_replace('\\', '/', __FILE__)) . $this->xmlPath;
}
function _test($xml_file, $argsString, $expected){
var_dump($xml_file);
$this->_testQuery($xml_file, $argsString, $expected, 'getSelectSql');
}
function testOneUseIndexHintAndOneTable(){
$xml_file = $this->xmlPath . "one_index_hint_one_table.xml";
$argsString = '';
$expected = 'select * from "xe_member" as "member" using index "member"."idx_member_list_order"';
$this->_test($xml_file, $argsString, $expected);
}
function testTwoUseIndexHintsAndOneTable(){
$xml_file = $this->xmlPath . "two_index_hints_one_table.xml";
$argsString = '';
$expected = 'select * from "xe_member" as "member" using index "member"."idx_member_list_order", "member"."idx_member_srl"';
$this->_test($xml_file, $argsString, $expected);
}
function testThreeUseIndexHintsAndTwoTables(){
$xml_file = $this->xmlPath . "three_index_hints_two_tables.xml";
$argsString = '';
$expected = 'select * from "xe_member" as "member", "xe_document" as "document"
using index "member"."idx_member_list_order", "member"."idx_member_srl", "document"."idx_document_srl"';
$this->_test($xml_file, $argsString, $expected);
}
}
?>

View file

@ -0,0 +1,11 @@
<query id="index_hint" action="select">
<tables>
<table name="member" alias="member" />
</tables>
<columns>
<column name="*" />
</columns>
<index_hint for="CUBRID">
<index table="member" name="idx_member_list_order" type="USE" />
</index_hint>
</query>

View file

@ -0,0 +1,14 @@
<query id="index_hint" action="select">
<tables>
<table name="member" alias="member" />
<table name="document" alias="document" />
</tables>
<columns>
<column name="*" />
</columns>
<index_hint for="CUBRID">
<index table="member" name="idx_member_list_order" type="USE" />
<index table="member" name="idx_member_srl" type="USE" />
<index table="document" name="idx_document_srl" type="USE" />
</index_hint>
</query>

View file

@ -0,0 +1,12 @@
<query id="index_hint" action="select">
<tables>
<table name="member" alias="member" />
</tables>
<columns>
<column name="*" />
</columns>
<index_hint for="CUBRID">
<index table="member" name="idx_member_list_order" type="USE" />
<index table="member" name="idx_member_srl" type="USE" />
</index_hint>
</query>

View file

@ -0,0 +1,38 @@
<?php
class MysqlIndexHintTest extends MysqlTest {
var $xmlPath = 'data/';
function MysqlIndexHintTest(){
$this->xmlPath = str_replace('MysqlIndexHintTest.php', '', str_replace('\\', '/', __FILE__)) . $this->xmlPath;
}
function _test($xml_file, $argsString, $expected){
$this->_testQuery($xml_file, $argsString, $expected, 'getSelectSql');
}
function testOneUseIndexHintAndOneTable(){
$xml_file = $this->xmlPath . "one_index_hint_one_table.xml";
$argsString = '';
$expected = 'select * from `xe_member` as `member` use index (`idx_member_list_order`)';
$this->_test($xml_file, $argsString, $expected);
}
function testTwoUseIndexHintsAndOneTable(){
$xml_file = $this->xmlPath . "two_index_hints_one_table.xml";
$argsString = '';
$expected = 'select * from `xe_member` as `member` use index (`idx_member_list_order`, `idx_member_srl`)';
$this->_test($xml_file, $argsString, $expected);
}
function testThreeUseIndexHintsAndTwoTables(){
$xml_file = $this->xmlPath . "three_index_hints_two_tables.xml";
$argsString = '';
$expected = 'select * from `xe_member` as `member` use index (`idx_member_list_order`, `idx_member_srl`)
, `xe_document` as `document` use index (`idx_document_srl`)';
$this->_test($xml_file, $argsString, $expected);
}
}
?>

View file

@ -0,0 +1,11 @@
<query id="index_hint" action="select">
<tables>
<table name="member" alias="member" />
</tables>
<columns>
<column name="*" />
</columns>
<index_hint for="MYSQL">
<index table="member" name="idx_member_list_order" type="USE" />
</index_hint>
</query>

View file

@ -0,0 +1,14 @@
<query id="index_hint" action="select">
<tables>
<table name="member" alias="member" />
<table name="document" alias="document" />
</tables>
<columns>
<column name="*" />
</columns>
<index_hint for="MYSQL">
<index table="member" name="idx_member_list_order" type="USE" />
<index table="member" name="idx_member_srl" type="USE" />
<index table="document" name="idx_document_srl" type="USE" />
</index_hint>
</query>

View file

@ -0,0 +1,12 @@
<query id="index_hint" action="select">
<tables>
<table name="member" alias="member" />
</tables>
<columns>
<column name="*" />
</columns>
<index_hint for="MYSQL">
<index table="member" name="idx_member_list_order" type="USE" />
<index table="member" name="idx_member_srl" type="USE" />
</index_hint>
</query>