annotate sites/all/libraries/ARC2/arc/store/ARC2_StoreSelectQueryHandler.php @ 4:ce11bbd8f642

added modules
author danieleb <danielebarchiesi@me.com>
date Thu, 19 Sep 2013 10:38:44 +0100
parents
children
rev   line source
danielebarchiesi@4 1 <?php
danielebarchiesi@4 2 /**
danielebarchiesi@4 3 * ARC2 RDF Store SELECT Query Handler
danielebarchiesi@4 4 *
danielebarchiesi@4 5 * @author Benjamin Nowack
danielebarchiesi@4 6 * @license http://arc.semsol.org/license
danielebarchiesi@4 7 * @homepage <http://arc.semsol.org/>
danielebarchiesi@4 8 * @package ARC2
danielebarchiesi@4 9 * @version 2010-11-16
danielebarchiesi@4 10 *
danielebarchiesi@4 11 */
danielebarchiesi@4 12
danielebarchiesi@4 13 ARC2::inc('StoreQueryHandler');
danielebarchiesi@4 14
danielebarchiesi@4 15 class ARC2_StoreSelectQueryHandler extends ARC2_StoreQueryHandler {
danielebarchiesi@4 16
danielebarchiesi@4 17 function __construct($a, &$caller) {/* caller has to be a store */
danielebarchiesi@4 18 parent::__construct($a, $caller);
danielebarchiesi@4 19 }
danielebarchiesi@4 20
danielebarchiesi@4 21 function __init() {/* db_con */
danielebarchiesi@4 22 parent::__init();
danielebarchiesi@4 23 $this->store = $this->caller;
danielebarchiesi@4 24 $con = $this->store->getDBCon();
danielebarchiesi@4 25 $this->handler_type = 'select';
danielebarchiesi@4 26 $this->engine_type = $this->v('store_engine_type', 'MyISAM', $this->a);
danielebarchiesi@4 27 $this->cache_results = $this->v('store_cache_results', 0, $this->a);
danielebarchiesi@4 28 }
danielebarchiesi@4 29
danielebarchiesi@4 30 /* */
danielebarchiesi@4 31
danielebarchiesi@4 32 function runQuery($infos) {
danielebarchiesi@4 33 $con = $this->store->getDBCon();
danielebarchiesi@4 34 $rf = $this->v('result_format', '', $infos);
danielebarchiesi@4 35 $this->infos = $infos;
danielebarchiesi@4 36 $this->infos['null_vars'] = array();
danielebarchiesi@4 37 $this->indexes = array();
danielebarchiesi@4 38 $this->pattern_order_offset = 0;
danielebarchiesi@4 39 $q_sql = $this->getSQL();
danielebarchiesi@4 40
danielebarchiesi@4 41 /* debug result formats */
danielebarchiesi@4 42 if ($rf == 'sql') return $q_sql;
danielebarchiesi@4 43 if ($rf == 'structure') return $this->infos;
danielebarchiesi@4 44 if ($rf == 'index') return $this->indexes;
danielebarchiesi@4 45 /* create intermediate results (ID-based) */
danielebarchiesi@4 46 $tmp_tbl = $this->createTempTable($q_sql);
danielebarchiesi@4 47 /* join values */
danielebarchiesi@4 48 $r = $this->getFinalQueryResult($q_sql, $tmp_tbl);
danielebarchiesi@4 49 /* remove intermediate results */
danielebarchiesi@4 50 if (!$this->cache_results) {
danielebarchiesi@4 51 $this->queryDB('DROP TABLE IF EXISTS ' . $tmp_tbl, $con);
danielebarchiesi@4 52 }
danielebarchiesi@4 53 return $r;
danielebarchiesi@4 54 }
danielebarchiesi@4 55
danielebarchiesi@4 56 function getSQL() {
danielebarchiesi@4 57 $r = '';
danielebarchiesi@4 58 $nl = "\n";
danielebarchiesi@4 59 $this->buildInitialIndexes();
danielebarchiesi@4 60 foreach ($this->indexes as $i => $index) {
danielebarchiesi@4 61 $this->index = array_merge($this->getEmptyIndex(), $index);
danielebarchiesi@4 62 $this->analyzeIndex($this->getPattern('0'));
danielebarchiesi@4 63 $sub_r = $this->getQuerySQL();
danielebarchiesi@4 64 $r .= $r ? $nl . 'UNION' . $this->getDistinctSQL() . $nl : '';
danielebarchiesi@4 65 $r .= $this->is_union_query ? '(' . $sub_r . ')' : $sub_r;
danielebarchiesi@4 66 $this->indexes[$i] = $this->index;
danielebarchiesi@4 67 }
danielebarchiesi@4 68 $r .= $this->is_union_query ? $this->getLIMITSQL() : '';
danielebarchiesi@4 69 if ($this->v('order_infos', 0, $this->infos['query'])) {
danielebarchiesi@4 70 $r = preg_replace('/SELECT(\s+DISTINCT)?\s*/', 'SELECT\\1 NULL AS `_pos_`, ', $r);
danielebarchiesi@4 71 }
danielebarchiesi@4 72 $pd_count = $this->problematicDependencies();
danielebarchiesi@4 73 if ($pd_count) {
danielebarchiesi@4 74 /* re-arranging the patterns sometimes reduces the LEFT JOIN dependencies */
danielebarchiesi@4 75 $set_sql = 0;
danielebarchiesi@4 76 if (!$this->pattern_order_offset) $set_sql = 1;
danielebarchiesi@4 77 if (!$set_sql && ($pd_count < $this->opt_sql_pd_count)) $set_sql = 1;
danielebarchiesi@4 78 if (!$set_sql && ($pd_count == $this->opt_sql_pd_count) && (strlen($r) < strlen($this->opt_sql))) $set_sql = 1;
danielebarchiesi@4 79 if ($set_sql) {
danielebarchiesi@4 80 $this->opt_sql = $r;
danielebarchiesi@4 81 $this->opt_sql_pd_count = $pd_count;
danielebarchiesi@4 82 }
danielebarchiesi@4 83 $this->pattern_order_offset++;
danielebarchiesi@4 84 if ($this->pattern_order_offset > 5) {
danielebarchiesi@4 85 return $this->opt_sql;
danielebarchiesi@4 86 }
danielebarchiesi@4 87 return $this->getSQL();
danielebarchiesi@4 88 }
danielebarchiesi@4 89 return $r;
danielebarchiesi@4 90 }
danielebarchiesi@4 91
danielebarchiesi@4 92 function buildInitialIndexes() {
danielebarchiesi@4 93 $this->dependency_log = array();
danielebarchiesi@4 94 $this->index = $this->getEmptyIndex();
danielebarchiesi@4 95 $this->buildIndex($this->infos['query']['pattern'], 0);
danielebarchiesi@4 96 $tmp = $this->index;
danielebarchiesi@4 97 $this->analyzeIndex($this->getPattern('0'));
danielebarchiesi@4 98 $this->initial_index = $this->index;
danielebarchiesi@4 99 $this->index = $tmp;
danielebarchiesi@4 100 $this->is_union_query = $this->index['union_branches'] ? 1 : 0;
danielebarchiesi@4 101 $this->indexes = $this->is_union_query ? $this->getUnionIndexes($this->index) : array($this->index);
danielebarchiesi@4 102 }
danielebarchiesi@4 103
danielebarchiesi@4 104 function createTempTable($q_sql) {
danielebarchiesi@4 105 $con = $this->store->getDBCon();
danielebarchiesi@4 106 $v = $this->store->getDBVersion();
danielebarchiesi@4 107 if ($this->cache_results) {
danielebarchiesi@4 108 $tbl = $this->store->getTablePrefix() . 'Q' . md5($q_sql);
danielebarchiesi@4 109 }
danielebarchiesi@4 110 else {
danielebarchiesi@4 111 $tbl = $this->store->getTablePrefix() . 'Q' . md5($q_sql . time() . uniqid(rand()));
danielebarchiesi@4 112 }
danielebarchiesi@4 113 if (strlen($tbl) > 64) $tbl = 'Q' . md5($tbl);
danielebarchiesi@4 114 $tmp_sql = 'CREATE TEMPORARY TABLE ' . $tbl . ' ( ' . $this->getTempTableDef($tbl, $q_sql) . ') ';
danielebarchiesi@4 115 $tmp_sql .= (($v < '04-01-00') && ($v >= '04-00-18')) ? 'ENGINE' : (($v >= '04-01-02') ? 'ENGINE' : 'TYPE');
danielebarchiesi@4 116 $tmp_sql .= '=' . $this->engine_type;/* HEAP doesn't support AUTO_INCREMENT, and MySQL breaks on MEMORY sometimes */
danielebarchiesi@4 117 if (!$this->queryDB($tmp_sql, $con) && !$this->queryDB(str_replace('CREATE TEMPORARY', 'CREATE', $tmp_sql), $con)) {
danielebarchiesi@4 118 return $this->addError(mysql_error($con));
danielebarchiesi@4 119 }
danielebarchiesi@4 120 mysql_unbuffered_query('INSERT INTO ' . $tbl . ' ' . "\n" . $q_sql, $con);
danielebarchiesi@4 121 if ($er = mysql_error($con)) $this->addError($er);
danielebarchiesi@4 122 return $tbl;
danielebarchiesi@4 123 }
danielebarchiesi@4 124
danielebarchiesi@4 125 function getEmptyIndex() {
danielebarchiesi@4 126 return array(
danielebarchiesi@4 127 'from' => array(),
danielebarchiesi@4 128 'join' => array(),
danielebarchiesi@4 129 'left_join' => array(),
danielebarchiesi@4 130 'vars' => array(), 'graph_vars' => array(), 'graph_uris' => array(),
danielebarchiesi@4 131 'bnodes' => array(),
danielebarchiesi@4 132 'triple_patterns' => array(),
danielebarchiesi@4 133 'sub_joins' => array(),
danielebarchiesi@4 134 'constraints' => array(),
danielebarchiesi@4 135 'union_branches'=> array(),
danielebarchiesi@4 136 'patterns' => array(),
danielebarchiesi@4 137 'havings' => array()
danielebarchiesi@4 138 );
danielebarchiesi@4 139 }
danielebarchiesi@4 140
danielebarchiesi@4 141 function getTempTableDef($tmp_tbl, $q_sql) {
danielebarchiesi@4 142 $col_part = preg_replace('/^SELECT\s*(DISTINCT)?(.*)FROM.*$/s', '\\2', $q_sql);
danielebarchiesi@4 143 $parts = explode(',', $col_part);
danielebarchiesi@4 144 $has_order_infos = $this->v('order_infos', 0, $this->infos['query']);
danielebarchiesi@4 145 $r = '';
danielebarchiesi@4 146 $added = array();
danielebarchiesi@4 147 foreach ($parts as $part) {
danielebarchiesi@4 148 if (preg_match('/\.?(.+)\s+AS\s+`(.+)`/U', trim($part), $m) && !isset($added[$m[2]])) {
danielebarchiesi@4 149 $col = $m[1];
danielebarchiesi@4 150 $alias = $m[2];
danielebarchiesi@4 151 if ($alias == '_pos_') continue;
danielebarchiesi@4 152 $r .= $r ? ',' : '';
danielebarchiesi@4 153 $r .= "\n `" . $alias . "` int UNSIGNED";
danielebarchiesi@4 154 $added[$alias] = 1;
danielebarchiesi@4 155 }
danielebarchiesi@4 156 }
danielebarchiesi@4 157 if ($has_order_infos) {
danielebarchiesi@4 158 $r = "\n" . '`_pos_` mediumint NOT NULL AUTO_INCREMENT PRIMARY KEY, ' . $r;
danielebarchiesi@4 159 }
danielebarchiesi@4 160 return $r ? $r . "\n" : '';
danielebarchiesi@4 161 }
danielebarchiesi@4 162
danielebarchiesi@4 163 function getFinalQueryResult($q_sql, $tmp_tbl) {
danielebarchiesi@4 164 /* var names */
danielebarchiesi@4 165 $vars = array();
danielebarchiesi@4 166 $aggregate_vars = array();
danielebarchiesi@4 167 foreach ($this->infos['query']['result_vars'] as $entry) {
danielebarchiesi@4 168 if ($entry['aggregate']) {
danielebarchiesi@4 169 $vars[] = $entry['alias'];
danielebarchiesi@4 170 $aggregate_vars[] = $entry['alias'];
danielebarchiesi@4 171 }
danielebarchiesi@4 172 else {
danielebarchiesi@4 173 $vars[] = $entry['var'];
danielebarchiesi@4 174 }
danielebarchiesi@4 175 }
danielebarchiesi@4 176 /* result */
danielebarchiesi@4 177 $r = array('variables' => $vars);
danielebarchiesi@4 178 $v_sql = $this->getValueSQL($tmp_tbl, $q_sql);
danielebarchiesi@4 179 //echo "\n\n" . $v_sql;
danielebarchiesi@4 180 $t1 = ARC2::mtime();
danielebarchiesi@4 181 $con = $this->store->getDBCon();
danielebarchiesi@4 182 $rs = mysql_unbuffered_query($v_sql, $con);
danielebarchiesi@4 183 if ($er = mysql_error($con)) {
danielebarchiesi@4 184 $this->addError($er);
danielebarchiesi@4 185 }
danielebarchiesi@4 186 $t2 = ARC2::mtime();
danielebarchiesi@4 187 $rows = array();
danielebarchiesi@4 188 $types = array(0 => 'uri', 1 => 'bnode', 2 => 'literal');
danielebarchiesi@4 189 if ($rs) {
danielebarchiesi@4 190 while ($pre_row = mysql_fetch_array($rs)) {
danielebarchiesi@4 191 $row = array();
danielebarchiesi@4 192 foreach ($vars as $var) {
danielebarchiesi@4 193 if (isset($pre_row[$var])) {
danielebarchiesi@4 194 $row[$var] = $pre_row[$var];
danielebarchiesi@4 195 $row[$var . ' type'] = isset($pre_row[$var . ' type']) ? $types[$pre_row[$var . ' type']] : (in_array($var, $aggregate_vars) ? 'literal' : 'uri');
danielebarchiesi@4 196 if (isset($pre_row[$var . ' lang_dt']) && ($lang_dt = $pre_row[$var . ' lang_dt'])) {
danielebarchiesi@4 197 if (preg_match('/^([a-z]+(\-[a-z0-9]+)*)$/i', $lang_dt)) {
danielebarchiesi@4 198 $row[$var . ' lang'] = $lang_dt;
danielebarchiesi@4 199 }
danielebarchiesi@4 200 else {
danielebarchiesi@4 201 $row[$var . ' datatype'] = $lang_dt;
danielebarchiesi@4 202 }
danielebarchiesi@4 203 }
danielebarchiesi@4 204 }
danielebarchiesi@4 205 }
danielebarchiesi@4 206 if ($row || !$vars) {
danielebarchiesi@4 207 $rows[] = $row;
danielebarchiesi@4 208 }
danielebarchiesi@4 209 }
danielebarchiesi@4 210 }
danielebarchiesi@4 211 $r['rows'] = $rows;
danielebarchiesi@4 212 return $r;
danielebarchiesi@4 213 }
danielebarchiesi@4 214
danielebarchiesi@4 215 /* */
danielebarchiesi@4 216
danielebarchiesi@4 217 function buildIndex($pattern, $id) {
danielebarchiesi@4 218 $pattern['id'] = $id;
danielebarchiesi@4 219 $type = $this->v('type', '', $pattern);
danielebarchiesi@4 220 if (($type == 'filter') && $this->v('constraint', 0, $pattern)) {
danielebarchiesi@4 221 $sub_pattern = $pattern['constraint'];
danielebarchiesi@4 222 $sub_pattern['parent_id'] = $id;
danielebarchiesi@4 223 $sub_id = $id . '_0';
danielebarchiesi@4 224 $this->buildIndex($sub_pattern, $sub_id);
danielebarchiesi@4 225 $pattern['constraint'] = $sub_id;
danielebarchiesi@4 226 }
danielebarchiesi@4 227 else {
danielebarchiesi@4 228 $sub_patterns = $this->v('patterns', array(), $pattern);
danielebarchiesi@4 229 $keys = array_keys($sub_patterns);
danielebarchiesi@4 230 $spc = count($sub_patterns);
danielebarchiesi@4 231 if (($spc > 4) && $this->pattern_order_offset) {
danielebarchiesi@4 232 $keys = array();
danielebarchiesi@4 233 for ($i = 0 ; $i < $spc; $i++) {
danielebarchiesi@4 234 $keys[$i] = $i + $this->pattern_order_offset;
danielebarchiesi@4 235 while ($keys[$i] >= $spc) $keys[$i] -= $spc;
danielebarchiesi@4 236 }
danielebarchiesi@4 237 }
danielebarchiesi@4 238 foreach ($keys as $i => $key) {
danielebarchiesi@4 239 $sub_pattern = $sub_patterns[$key];
danielebarchiesi@4 240 $sub_pattern['parent_id'] = $id;
danielebarchiesi@4 241 $sub_id = $id . '_' . $key;
danielebarchiesi@4 242 $this->buildIndex($sub_pattern, $sub_id);
danielebarchiesi@4 243 $pattern['patterns'][$i] = $sub_id;
danielebarchiesi@4 244 if ($type == 'union') {
danielebarchiesi@4 245 $this->index['union_branches'][] = $sub_id;
danielebarchiesi@4 246 }
danielebarchiesi@4 247 }
danielebarchiesi@4 248 }
danielebarchiesi@4 249 $this->index['patterns'][$id] = $pattern;
danielebarchiesi@4 250 }
danielebarchiesi@4 251
danielebarchiesi@4 252 /* */
danielebarchiesi@4 253
danielebarchiesi@4 254 function analyzeIndex($pattern) {
danielebarchiesi@4 255 $type = $this->v('type', '', $pattern);
danielebarchiesi@4 256 if (!$type) {
danielebarchiesi@4 257 //echo '<!-- ' . var_export($this->infos, 1) . ' -->';
danielebarchiesi@4 258 return false;
danielebarchiesi@4 259 }
danielebarchiesi@4 260 $type = $pattern['type'];
danielebarchiesi@4 261 $id = $pattern['id'];
danielebarchiesi@4 262 /* triple */
danielebarchiesi@4 263 if ($type == 'triple') {
danielebarchiesi@4 264 foreach (array('s', 'p', 'o') as $term) {
danielebarchiesi@4 265 if ($pattern[$term . '_type'] == 'var') {
danielebarchiesi@4 266 $val = $pattern[$term];
danielebarchiesi@4 267 $this->index['vars'][$val] = array_merge($this->v($val, array(), $this->index['vars']), array(array('table' => $pattern['id'], 'col' =>$term)));
danielebarchiesi@4 268 }
danielebarchiesi@4 269 if ($pattern[$term . '_type'] == 'bnode') {
danielebarchiesi@4 270 $val = $pattern[$term];
danielebarchiesi@4 271 $this->index['bnodes'][$val] = array_merge($this->v($val, array(), $this->index['bnodes']), array(array('table' => $pattern['id'], 'col' =>$term)));
danielebarchiesi@4 272 }
danielebarchiesi@4 273 }
danielebarchiesi@4 274 $this->index['triple_patterns'][] = $pattern['id'];
danielebarchiesi@4 275 /* joins */
danielebarchiesi@4 276 if ($this->isOptionalPattern($id)) {
danielebarchiesi@4 277 $this->index['left_join'][] = $id;
danielebarchiesi@4 278 }
danielebarchiesi@4 279 elseif (!$this->index['from']) {
danielebarchiesi@4 280 $this->index['from'][] = $id;
danielebarchiesi@4 281 }
danielebarchiesi@4 282 elseif (!$this->getJoinInfos($id)) {
danielebarchiesi@4 283 $this->index['from'][] = $id;
danielebarchiesi@4 284 }
danielebarchiesi@4 285 else {
danielebarchiesi@4 286 $this->index['join'][] = $id;
danielebarchiesi@4 287 }
danielebarchiesi@4 288 /* graph infos, graph vars */
danielebarchiesi@4 289 $this->index['patterns'][$id]['graph_infos'] = $this->getGraphInfos($id);
danielebarchiesi@4 290 foreach ($this->index['patterns'][$id]['graph_infos'] as $info) {
danielebarchiesi@4 291 if ($info['type'] == 'graph') {
danielebarchiesi@4 292 if ($info['var']) {
danielebarchiesi@4 293 $val = $info['var']['value'];
danielebarchiesi@4 294 $this->index['graph_vars'][$val] = array_merge($this->v($val, array(), $this->index['graph_vars']), array(array('table' => $id)));
danielebarchiesi@4 295 }
danielebarchiesi@4 296 elseif ($info['uri']) {
danielebarchiesi@4 297 $val = $info['uri'];
danielebarchiesi@4 298 $this->index['graph_uris'][$val] = array_merge($this->v($val, array(), $this->index['graph_uris']), array(array('table' => $id)));
danielebarchiesi@4 299 }
danielebarchiesi@4 300 }
danielebarchiesi@4 301 }
danielebarchiesi@4 302 }
danielebarchiesi@4 303 $sub_ids = $this->v('patterns', array(), $pattern);
danielebarchiesi@4 304 foreach ($sub_ids as $sub_id) {
danielebarchiesi@4 305 $this->analyzeIndex($this->getPattern($sub_id));
danielebarchiesi@4 306 }
danielebarchiesi@4 307 }
danielebarchiesi@4 308
danielebarchiesi@4 309 /* */
danielebarchiesi@4 310
danielebarchiesi@4 311 function getGraphInfos($id) {
danielebarchiesi@4 312 $r = array();
danielebarchiesi@4 313 if ($id) {
danielebarchiesi@4 314 $pattern = $this->index['patterns'][$id];
danielebarchiesi@4 315 $type = $pattern['type'];
danielebarchiesi@4 316 /* graph */
danielebarchiesi@4 317 if ($type == 'graph') {
danielebarchiesi@4 318 $r[] = array('type' => 'graph', 'var' => $pattern['var'], 'uri' => $pattern['uri']);
danielebarchiesi@4 319 }
danielebarchiesi@4 320 $p_pattern = $this->index['patterns'][$pattern['parent_id']];
danielebarchiesi@4 321 if (isset($p_pattern['graph_infos'])) {
danielebarchiesi@4 322 return array_merge($p_pattern['graph_infos'], $r);
danielebarchiesi@4 323 }
danielebarchiesi@4 324 return array_merge($this->getGraphInfos($pattern['parent_id']), $r);
danielebarchiesi@4 325 }
danielebarchiesi@4 326 /* FROM / FROM NAMED */
danielebarchiesi@4 327 else {
danielebarchiesi@4 328 if (isset($this->infos['query']['dataset'])) {
danielebarchiesi@4 329 foreach ($this->infos['query']['dataset'] as $set) {
danielebarchiesi@4 330 $r[] = array_merge(array('type' => 'dataset'), $set);
danielebarchiesi@4 331 }
danielebarchiesi@4 332 }
danielebarchiesi@4 333 }
danielebarchiesi@4 334 return $r;
danielebarchiesi@4 335 }
danielebarchiesi@4 336
danielebarchiesi@4 337 /* */
danielebarchiesi@4 338
danielebarchiesi@4 339 function getPattern($id) {
danielebarchiesi@4 340 if (is_array($id)) {
danielebarchiesi@4 341 return $id;
danielebarchiesi@4 342 }
danielebarchiesi@4 343 return $this->v($id, array(), $this->index['patterns']);
danielebarchiesi@4 344 }
danielebarchiesi@4 345
danielebarchiesi@4 346 function getInitialPattern($id) {
danielebarchiesi@4 347 return $this->v($id, array(), $this->initial_index['patterns']);
danielebarchiesi@4 348 }
danielebarchiesi@4 349
danielebarchiesi@4 350 /* */
danielebarchiesi@4 351
danielebarchiesi@4 352 function getUnionIndexes($pre_index) {
danielebarchiesi@4 353 $r = array();
danielebarchiesi@4 354 $branches = array();
danielebarchiesi@4 355 $min_depth = 1000;
danielebarchiesi@4 356 /* only process branches with minimum depth */
danielebarchiesi@4 357 foreach ($pre_index['union_branches'] as $id) {
danielebarchiesi@4 358 $branches[$id] = count(preg_split('/\_/', $id));
danielebarchiesi@4 359 $min_depth = min($min_depth, $branches[$id]);
danielebarchiesi@4 360 }
danielebarchiesi@4 361 foreach ($branches as $branch_id => $depth) {
danielebarchiesi@4 362 if ($depth == $min_depth) {
danielebarchiesi@4 363 $union_id = preg_replace('/\_[0-9]+$/', '', $branch_id);
danielebarchiesi@4 364 $index = array('keeping' => $branch_id, 'union_branches' => array(), 'patterns' => $pre_index['patterns']);
danielebarchiesi@4 365 $old_branches = $index['patterns'][$union_id]['patterns'];
danielebarchiesi@4 366 $skip_id = ($old_branches[0] == $branch_id) ? $old_branches[1] : $old_branches[0];
danielebarchiesi@4 367 $index['patterns'][$union_id]['type'] = 'group';
danielebarchiesi@4 368 $index['patterns'][$union_id]['patterns'] = array($branch_id);
danielebarchiesi@4 369 $has_sub_unions = 0;
danielebarchiesi@4 370 foreach ($index['patterns'] as $pattern_id => $pattern) {
danielebarchiesi@4 371 if (preg_match('/^' .$skip_id. '/', $pattern_id)) {
danielebarchiesi@4 372 unset($index['patterns'][$pattern_id]);
danielebarchiesi@4 373 }
danielebarchiesi@4 374 elseif ($pattern['type'] == 'union') {
danielebarchiesi@4 375 foreach ($pattern['patterns'] as $sub_union_branch_id) {
danielebarchiesi@4 376 $index['union_branches'][] = $sub_union_branch_id;
danielebarchiesi@4 377 }
danielebarchiesi@4 378 }
danielebarchiesi@4 379 }
danielebarchiesi@4 380 if ($index['union_branches']) {
danielebarchiesi@4 381 $r = array_merge($r, $this->getUnionIndexes($index));
danielebarchiesi@4 382 }
danielebarchiesi@4 383 else {
danielebarchiesi@4 384 $r[] = $index;
danielebarchiesi@4 385 }
danielebarchiesi@4 386 }
danielebarchiesi@4 387 }
danielebarchiesi@4 388 return $r;
danielebarchiesi@4 389 }
danielebarchiesi@4 390
danielebarchiesi@4 391 /* */
danielebarchiesi@4 392
danielebarchiesi@4 393 function isOptionalPattern($id) {
danielebarchiesi@4 394 $pattern = $this->getPattern($id);
danielebarchiesi@4 395 if ($this->v('type', '', $pattern) == 'optional') {
danielebarchiesi@4 396 return 1;
danielebarchiesi@4 397 }
danielebarchiesi@4 398 if ($this->v('parent_id', '0', $pattern) == '0') {
danielebarchiesi@4 399 return 0;
danielebarchiesi@4 400 }
danielebarchiesi@4 401 return $this->isOptionalPattern($pattern['parent_id']);
danielebarchiesi@4 402 }
danielebarchiesi@4 403
danielebarchiesi@4 404 function getOptionalPattern($id) {
danielebarchiesi@4 405 $pn = $this->getPattern($id);
danielebarchiesi@4 406 do {
danielebarchiesi@4 407 $pn = $this->getPattern($pn['parent_id']);
danielebarchiesi@4 408 } while ($pn['parent_id'] && ($pn['type'] != 'optional'));
danielebarchiesi@4 409 return $pn['id'];
danielebarchiesi@4 410 }
danielebarchiesi@4 411
danielebarchiesi@4 412 function sameOptional($id, $id2) {
danielebarchiesi@4 413 return $this->getOptionalPattern($id) == $this->getOptionalPattern($id2);
danielebarchiesi@4 414 }
danielebarchiesi@4 415
danielebarchiesi@4 416 /* */
danielebarchiesi@4 417
danielebarchiesi@4 418 function isUnionPattern($id) {
danielebarchiesi@4 419 $pattern = $this->getPattern($id);
danielebarchiesi@4 420 if ($this->v('type', '', $pattern) == 'union') {
danielebarchiesi@4 421 return 1;
danielebarchiesi@4 422 }
danielebarchiesi@4 423 if ($this->v('parent_id', '0', $pattern) == '0') {
danielebarchiesi@4 424 return 0;
danielebarchiesi@4 425 }
danielebarchiesi@4 426 return $this->isUnionPattern($pattern['parent_id']);
danielebarchiesi@4 427 }
danielebarchiesi@4 428
danielebarchiesi@4 429 /* */
danielebarchiesi@4 430
danielebarchiesi@4 431 function getValueTable($col) {
danielebarchiesi@4 432 return $this->store->getTablePrefix() . (preg_match('/^(s|o)$/', $col) ? $col . '2val' : 'id2val');
danielebarchiesi@4 433 }
danielebarchiesi@4 434
danielebarchiesi@4 435 function getGraphTable() {
danielebarchiesi@4 436 return $this->store->getTablePrefix() . 'g2t';
danielebarchiesi@4 437 }
danielebarchiesi@4 438
danielebarchiesi@4 439 /* */
danielebarchiesi@4 440
danielebarchiesi@4 441 function getQuerySQL() {
danielebarchiesi@4 442 $nl = "\n";
danielebarchiesi@4 443 $where_sql = $this->getWHERESQL(); /* pre-fills $index['sub_joins'] $index['constraints'] */
danielebarchiesi@4 444 $order_sql = $this->getORDERSQL(); /* pre-fills $index['sub_joins'] $index['constraints'] */
danielebarchiesi@4 445 return '' .
danielebarchiesi@4 446 ($this->is_union_query ? 'SELECT' : 'SELECT' . $this->getDistinctSQL()) . $nl .
danielebarchiesi@4 447 $this->getResultVarsSQL() . $nl . /* fills $index['sub_joins'] */
danielebarchiesi@4 448 $this->getFROMSQL() .
danielebarchiesi@4 449 $this->getAllJoinsSQL() .
danielebarchiesi@4 450 $this->getWHERESQL() .
danielebarchiesi@4 451 $this->getGROUPSQL() .
danielebarchiesi@4 452 $this->getORDERSQL() .
danielebarchiesi@4 453 ($this->is_union_query ? '' : $this->getLIMITSQL()) .
danielebarchiesi@4 454 $nl .
danielebarchiesi@4 455 '';
danielebarchiesi@4 456 }
danielebarchiesi@4 457
danielebarchiesi@4 458 /* */
danielebarchiesi@4 459
danielebarchiesi@4 460 function getDistinctSQL() {
danielebarchiesi@4 461 if ($this->is_union_query) {
danielebarchiesi@4 462 return ($this->v('distinct', 0, $this->infos['query']) || $this->v('reduced', 0, $this->infos['query'])) ? '' : ' ALL';
danielebarchiesi@4 463 }
danielebarchiesi@4 464 return ($this->v('distinct', 0, $this->infos['query']) || $this->v('reduced', 0, $this->infos['query'])) ? ' DISTINCT' : '';
danielebarchiesi@4 465 }
danielebarchiesi@4 466
danielebarchiesi@4 467 /* */
danielebarchiesi@4 468
danielebarchiesi@4 469 function getResultVarsSQL() {
danielebarchiesi@4 470 $r = '';
danielebarchiesi@4 471 $vars = $this->infos['query']['result_vars'];
danielebarchiesi@4 472 $nl = "\n";
danielebarchiesi@4 473 $added = array();
danielebarchiesi@4 474 foreach ($vars as $var) {
danielebarchiesi@4 475 $var_name = $var['var'];
danielebarchiesi@4 476 $tbl_alias = '';
danielebarchiesi@4 477 if ($tbl_infos = $this->getVarTableInfos($var_name, 0)) {
danielebarchiesi@4 478 $tbl = $tbl_infos['table'];
danielebarchiesi@4 479 $col = $tbl_infos['col'];
danielebarchiesi@4 480 $tbl_alias = $tbl_infos['table_alias'];
danielebarchiesi@4 481 }
danielebarchiesi@4 482 elseif ($var_name == 1) {/* ASK query */
danielebarchiesi@4 483 $r .= '1 AS `success`';
danielebarchiesi@4 484 }
danielebarchiesi@4 485 else {
danielebarchiesi@4 486 $this->addError('Result variable "' .$var_name. '" not used in query.');
danielebarchiesi@4 487 }
danielebarchiesi@4 488 if ($tbl_alias) {
danielebarchiesi@4 489 /* aggregate */
danielebarchiesi@4 490 if ($var['aggregate']) {
danielebarchiesi@4 491 $conv_code = '';
danielebarchiesi@4 492 if (strtolower($var['aggregate']) != 'count') {
danielebarchiesi@4 493 $tbl_alias = 'V_' . $tbl . '_' . $col . '.val';
danielebarchiesi@4 494 $conv_code = '0 + ';
danielebarchiesi@4 495 }
danielebarchiesi@4 496 if (!isset($added[$var['alias']])) {
danielebarchiesi@4 497 $r .= $r ? ',' . $nl . ' ' : ' ';
danielebarchiesi@4 498 $distinct_code = (strtolower($var['aggregate']) == 'count') && $this->v('distinct', 0, $this->infos['query']) ? 'DISTINCT ' : '';
danielebarchiesi@4 499 $r .= $var['aggregate'] . '(' . $conv_code . $distinct_code . $tbl_alias. ') AS `' . $var['alias'] . '`';
danielebarchiesi@4 500 $added[$var['alias']] = 1;
danielebarchiesi@4 501 }
danielebarchiesi@4 502 }
danielebarchiesi@4 503 /* normal var */
danielebarchiesi@4 504 else {
danielebarchiesi@4 505 if (!isset($added[$var_name])) {
danielebarchiesi@4 506 $r .= $r ? ',' . $nl . ' ' : ' ';
danielebarchiesi@4 507 $r .= $tbl_alias . ' AS `' . $var_name . '`';
danielebarchiesi@4 508 $is_s = ($col == 's');
danielebarchiesi@4 509 $is_p = ($col == 'p');
danielebarchiesi@4 510 $is_o = ($col == 'o');
danielebarchiesi@4 511 if ($tbl_alias == 'NULL') {
danielebarchiesi@4 512 /* type / add in UNION queries? */
danielebarchiesi@4 513 if ($is_s || $is_o) {
danielebarchiesi@4 514 $r .= ', ' . $nl . ' NULL AS `' . $var_name . ' type`';
danielebarchiesi@4 515 }
danielebarchiesi@4 516 /* lang_dt / always add it in UNION queries, the var may be used as s/p/o */
danielebarchiesi@4 517 if ($is_o || $this->is_union_query) {
danielebarchiesi@4 518 $r .= ', ' . $nl . ' NULL AS `' . $var_name . ' lang_dt`';
danielebarchiesi@4 519 }
danielebarchiesi@4 520 }
danielebarchiesi@4 521 else {
danielebarchiesi@4 522 /* type */
danielebarchiesi@4 523 if ($is_s || $is_o) {
danielebarchiesi@4 524 $r .= ', ' . $nl . ' ' .$tbl_alias . '_type AS `' . $var_name . ' type`';
danielebarchiesi@4 525 }
danielebarchiesi@4 526 /* lang_dt / always add it in UNION queries, the var may be used as s/p/o */
danielebarchiesi@4 527 if ($is_o) {
danielebarchiesi@4 528 $r .= ', ' . $nl . ' ' .$tbl_alias . '_lang_dt AS `' . $var_name . ' lang_dt`';
danielebarchiesi@4 529 }
danielebarchiesi@4 530 elseif ($this->is_union_query) {
danielebarchiesi@4 531 $r .= ', ' . $nl . ' NULL AS `' . $var_name . ' lang_dt`';
danielebarchiesi@4 532 }
danielebarchiesi@4 533 }
danielebarchiesi@4 534 $added[$var_name] = 1;
danielebarchiesi@4 535 }
danielebarchiesi@4 536 }
danielebarchiesi@4 537 if (!in_array($tbl_alias, $this->index['sub_joins'])) {
danielebarchiesi@4 538 $this->index['sub_joins'][] = $tbl_alias;
danielebarchiesi@4 539 }
danielebarchiesi@4 540 }
danielebarchiesi@4 541 }
danielebarchiesi@4 542 return $r ? $r : '1 AS `success`';
danielebarchiesi@4 543 }
danielebarchiesi@4 544
danielebarchiesi@4 545 function getVarTableInfos($var, $ignore_initial_index = 1) {
danielebarchiesi@4 546 if ($var == '*') {
danielebarchiesi@4 547 return array('table' => '', 'col' => '', 'table_alias' => '*');
danielebarchiesi@4 548 }
danielebarchiesi@4 549 if ($infos = $this->v($var, 0, $this->index['vars'])) {
danielebarchiesi@4 550 $infos[0]['table_alias'] = 'T_' . $infos[0]['table'] . '.' . $infos[0]['col'];
danielebarchiesi@4 551 return $infos[0];
danielebarchiesi@4 552 }
danielebarchiesi@4 553 if ($infos = $this->v($var, 0, $this->index['graph_vars'])) {
danielebarchiesi@4 554 $infos[0]['col'] = 'g';
danielebarchiesi@4 555 $infos[0]['table_alias'] = 'G_' . $infos[0]['table'] . '.' . $infos[0]['col'];
danielebarchiesi@4 556 return $infos[0];
danielebarchiesi@4 557 }
danielebarchiesi@4 558 if ($this->is_union_query && !$ignore_initial_index) {
danielebarchiesi@4 559 if (($infos = $this->v($var, 0, $this->initial_index['vars'])) || ($infos = $this->v($var, 0, $this->initial_index['graph_vars']))) {
danielebarchiesi@4 560 if (!in_array($var, $this->infos['null_vars'])) {
danielebarchiesi@4 561 $this->infos['null_vars'][] = $var;
danielebarchiesi@4 562 }
danielebarchiesi@4 563 $infos[0]['table_alias'] = 'NULL';
danielebarchiesi@4 564 $infos[0]['col'] = !isset($infos[0]['col']) ? '' : $infos[0]['col'];
danielebarchiesi@4 565 return $infos[0];
danielebarchiesi@4 566 }
danielebarchiesi@4 567 }
danielebarchiesi@4 568 return 0;
danielebarchiesi@4 569 }
danielebarchiesi@4 570
danielebarchiesi@4 571 /* */
danielebarchiesi@4 572
danielebarchiesi@4 573 function getFROMSQL() {
danielebarchiesi@4 574 $from_ids = $this->index['from'];
danielebarchiesi@4 575 $r = '';
danielebarchiesi@4 576 foreach ($from_ids as $from_id) {
danielebarchiesi@4 577 $r .= $r ? ', ' : '';
danielebarchiesi@4 578 $r .= $this->getTripleTable($from_id) . ' T_' . $from_id;
danielebarchiesi@4 579 }
danielebarchiesi@4 580 /* MySQL 5 requires parentheses in case of multiple tables */
danielebarchiesi@4 581 /* MySQL >5.5 (?) does not allow parentheses in case of a single table anymore! */
danielebarchiesi@4 582 $r = (count($from_ids) > 1) ? '(' . $r . ')' : $r;
danielebarchiesi@4 583 return $r ? 'FROM ' . $r : '';
danielebarchiesi@4 584 }
danielebarchiesi@4 585
danielebarchiesi@4 586 /* */
danielebarchiesi@4 587
danielebarchiesi@4 588 function getOrderedJoinIDs() {
danielebarchiesi@4 589 return array_merge($this->index['from'], $this->index['join'], $this->index['left_join']);
danielebarchiesi@4 590 }
danielebarchiesi@4 591
danielebarchiesi@4 592 function getJoinInfos($id) {
danielebarchiesi@4 593 $r = array();
danielebarchiesi@4 594 $tbl_ids = $this->getOrderedJoinIDs();
danielebarchiesi@4 595 $pattern = $this->getPattern($id);
danielebarchiesi@4 596 foreach ($tbl_ids as $tbl_id) {
danielebarchiesi@4 597 $tbl_pattern = $this->getPattern($tbl_id);
danielebarchiesi@4 598 if ($tbl_id != $id) {
danielebarchiesi@4 599 foreach (array('s', 'p', 'o') as $tbl_term) {
danielebarchiesi@4 600 foreach (array('var', 'bnode', 'uri') as $term_type) {
danielebarchiesi@4 601 if ($tbl_pattern[$tbl_term . '_type'] == $term_type) {
danielebarchiesi@4 602 foreach (array('s', 'p', 'o') as $term) {
danielebarchiesi@4 603 if (($pattern[$term . '_type'] == $term_type) && ($tbl_pattern[$tbl_term] == $pattern[$term])) {
danielebarchiesi@4 604 $r[] = array('term' => $term, 'join_tbl' => $tbl_id, 'join_term' => $tbl_term);
danielebarchiesi@4 605 }
danielebarchiesi@4 606 }
danielebarchiesi@4 607 }
danielebarchiesi@4 608 }
danielebarchiesi@4 609 }
danielebarchiesi@4 610 }
danielebarchiesi@4 611 }
danielebarchiesi@4 612 return $r;
danielebarchiesi@4 613 }
danielebarchiesi@4 614
danielebarchiesi@4 615 function getAllJoinsSQL() {
danielebarchiesi@4 616 $js = $this->getJoins();
danielebarchiesi@4 617 $ljs = $this->getLeftJoins();
danielebarchiesi@4 618 $entries = array_merge($js, $ljs);
danielebarchiesi@4 619 $id2code = array();
danielebarchiesi@4 620 foreach ($entries as $entry) {
danielebarchiesi@4 621 if (preg_match('/([^\s]+) ON (.*)/s', $entry, $m)) {
danielebarchiesi@4 622 $id2code[$m[1]] = $entry;
danielebarchiesi@4 623 }
danielebarchiesi@4 624 }
danielebarchiesi@4 625 $deps = array();
danielebarchiesi@4 626 foreach ($id2code as $id => $code) {
danielebarchiesi@4 627 $deps[$id]['rank'] = 0;
danielebarchiesi@4 628 foreach ($id2code as $other_id => $other_code) {
danielebarchiesi@4 629 $deps[$id]['rank'] += ($id != $other_id) && preg_match('/' . $other_id . '/', $code) ? 1 : 0;
danielebarchiesi@4 630 $deps[$id][$other_id] = ($id != $other_id) && preg_match('/' . $other_id . '/', $code) ? 1 : 0;
danielebarchiesi@4 631 }
danielebarchiesi@4 632 }
danielebarchiesi@4 633 $r = '';
danielebarchiesi@4 634 do {
danielebarchiesi@4 635 /* get next 0-rank */
danielebarchiesi@4 636 $next_id = 0;
danielebarchiesi@4 637 foreach ($deps as $id => $infos) {
danielebarchiesi@4 638 if ($infos['rank'] == 0) {
danielebarchiesi@4 639 $next_id = $id;
danielebarchiesi@4 640 break;
danielebarchiesi@4 641 }
danielebarchiesi@4 642 }
danielebarchiesi@4 643 if ($next_id) {
danielebarchiesi@4 644 $r .= "\n" . $id2code[$next_id];
danielebarchiesi@4 645 unset($deps[$next_id]);
danielebarchiesi@4 646 foreach ($deps as $id => $infos) {
danielebarchiesi@4 647 $deps[$id]['rank'] = 0;
danielebarchiesi@4 648 unset($deps[$id][$next_id]);
danielebarchiesi@4 649 foreach ($infos as $k => $v) {
danielebarchiesi@4 650 if (!in_array($k, array('rank', $next_id))) {
danielebarchiesi@4 651 $deps[$id]['rank'] += $v;
danielebarchiesi@4 652 $deps[$id][$k] = $v;
danielebarchiesi@4 653 }
danielebarchiesi@4 654 }
danielebarchiesi@4 655 }
danielebarchiesi@4 656 }
danielebarchiesi@4 657 }
danielebarchiesi@4 658 while ($next_id);
danielebarchiesi@4 659 if ($deps) {
danielebarchiesi@4 660 $this->addError('Not all patterns could be rewritten to SQL JOINs');
danielebarchiesi@4 661 }
danielebarchiesi@4 662 return $r;
danielebarchiesi@4 663 }
danielebarchiesi@4 664
danielebarchiesi@4 665 function getJoins() {
danielebarchiesi@4 666 $r = array();
danielebarchiesi@4 667 $nl = "\n";
danielebarchiesi@4 668 foreach ($this->index['join'] as $id) {
danielebarchiesi@4 669 $sub_r = $this->getJoinConditionSQL($id);
danielebarchiesi@4 670 $r[] = 'JOIN ' . $this->getTripleTable($id) . ' T_' . $id . ' ON (' . $sub_r . $nl . ')';
danielebarchiesi@4 671 }
danielebarchiesi@4 672 foreach (array_merge($this->index['from'], $this->index['join']) as $id) {
danielebarchiesi@4 673 if ($sub_r = $this->getRequiredSubJoinSQL($id)) {
danielebarchiesi@4 674 $r[] = $sub_r;
danielebarchiesi@4 675 }
danielebarchiesi@4 676 }
danielebarchiesi@4 677 return $r;
danielebarchiesi@4 678 }
danielebarchiesi@4 679
danielebarchiesi@4 680 function getLeftJoins() {
danielebarchiesi@4 681 $r = array();
danielebarchiesi@4 682 $nl = "\n";
danielebarchiesi@4 683 foreach ($this->index['left_join'] as $id) {
danielebarchiesi@4 684 $sub_r = $this->getJoinConditionSQL($id);
danielebarchiesi@4 685 $r[] = 'LEFT JOIN ' . $this->getTripleTable($id) . ' T_' . $id . ' ON (' . $sub_r . $nl . ')';
danielebarchiesi@4 686 }
danielebarchiesi@4 687 foreach ($this->index['left_join'] as $id) {
danielebarchiesi@4 688 if ($sub_r = $this->getRequiredSubJoinSQL($id, 'LEFT')) {
danielebarchiesi@4 689 $r[] = $sub_r;
danielebarchiesi@4 690 }
danielebarchiesi@4 691 }
danielebarchiesi@4 692 return $r;
danielebarchiesi@4 693 }
danielebarchiesi@4 694
danielebarchiesi@4 695 function getJoinConditionSQL($id) {
danielebarchiesi@4 696 $r = '';
danielebarchiesi@4 697 $nl = "\n";
danielebarchiesi@4 698 $infos = $this->getJoinInfos($id);
danielebarchiesi@4 699 $pattern = $this->getPattern($id);
danielebarchiesi@4 700
danielebarchiesi@4 701 $tbl = 'T_' . $id;
danielebarchiesi@4 702 /* core dependency */
danielebarchiesi@4 703 $d_tbls = $this->getDependentJoins($id);
danielebarchiesi@4 704 foreach ($d_tbls as $d_tbl) {
danielebarchiesi@4 705 if (preg_match('/^T_([0-9\_]+)\.[spo]+/', $d_tbl, $m) && ($m[1] != $id)) {
danielebarchiesi@4 706 if ($this->isJoinedBefore($m[1], $id) && !in_array($m[1], array_merge($this->index['from'], $this->index['join']))) {
danielebarchiesi@4 707 $r .= $r ? $nl . ' AND ' : $nl . ' ';
danielebarchiesi@4 708 $r .= '(' . $d_tbl . ' IS NOT NULL)';
danielebarchiesi@4 709 }
danielebarchiesi@4 710 $this->logDependency($id, $d_tbl);
danielebarchiesi@4 711 }
danielebarchiesi@4 712 }
danielebarchiesi@4 713 /* triple-based join info */
danielebarchiesi@4 714 foreach ($infos as $info) {
danielebarchiesi@4 715 if ($this->isJoinedBefore($info['join_tbl'], $id) && $this->joinDependsOn($id, $info['join_tbl'])) {
danielebarchiesi@4 716 $r .= $r ? $nl . ' AND ' : $nl . ' ';
danielebarchiesi@4 717 $r .= '(' . $tbl . '.' . $info['term'] . ' = T_' . $info['join_tbl'] . '.' . $info['join_term'] . ')';
danielebarchiesi@4 718 }
danielebarchiesi@4 719 }
danielebarchiesi@4 720 /* filters etc */
danielebarchiesi@4 721 if ($sub_r = $this->getPatternSQL($pattern, 'join__T_' . $id)) {
danielebarchiesi@4 722 $r .= $r ? $nl . ' AND ' . $sub_r : $nl . ' ' . '(' . $sub_r . ')';
danielebarchiesi@4 723 }
danielebarchiesi@4 724 return $r;
danielebarchiesi@4 725 }
danielebarchiesi@4 726
danielebarchiesi@4 727 /**
danielebarchiesi@4 728 * A log of identified table join dependencies in getJoinConditionSQL
danielebarchiesi@4 729 *
danielebarchiesi@4 730 */
danielebarchiesi@4 731
danielebarchiesi@4 732 function logDependency($id, $tbl) {
danielebarchiesi@4 733 if (!isset($this->dependency_log[$id])) $this->dependency_log[$id] = array();
danielebarchiesi@4 734 if (!in_array($tbl, $this->dependency_log[$id])) {
danielebarchiesi@4 735 $this->dependency_log[$id][] = $tbl;
danielebarchiesi@4 736 }
danielebarchiesi@4 737 }
danielebarchiesi@4 738
danielebarchiesi@4 739 /**
danielebarchiesi@4 740 * checks whether entries in the dependecy log could perhaps be optimized
danielebarchiesi@4 741 * (triggers re-ordering of patterns
danielebarchiesi@4 742 */
danielebarchiesi@4 743
danielebarchiesi@4 744 function problematicDependencies() {
danielebarchiesi@4 745 foreach ($this->dependency_log as $id => $tbls) {
danielebarchiesi@4 746 if (count($tbls) > 1) return count($tbls);
danielebarchiesi@4 747 }
danielebarchiesi@4 748 return 0;
danielebarchiesi@4 749 }
danielebarchiesi@4 750
danielebarchiesi@4 751 function isJoinedBefore($tbl_1, $tbl_2) {
danielebarchiesi@4 752 $tbl_ids = $this->getOrderedJoinIDs();
danielebarchiesi@4 753 foreach ($tbl_ids as $id) {
danielebarchiesi@4 754 if ($id == $tbl_1) {
danielebarchiesi@4 755 return 1;
danielebarchiesi@4 756 }
danielebarchiesi@4 757 if ($id == $tbl_2) {
danielebarchiesi@4 758 return 0;
danielebarchiesi@4 759 }
danielebarchiesi@4 760 }
danielebarchiesi@4 761 }
danielebarchiesi@4 762
danielebarchiesi@4 763 function joinDependsOn($id, $id2) {
danielebarchiesi@4 764 if (in_array($id2, array_merge($this->index['from'], $this->index['join']))) {
danielebarchiesi@4 765 return 1;
danielebarchiesi@4 766 }
danielebarchiesi@4 767 $d_tbls = $this->getDependentJoins($id2);
danielebarchiesi@4 768 //echo $id . ' :: ' . $id2 . '=>' . print_r($d_tbls, 1);
danielebarchiesi@4 769 foreach ($d_tbls as $d_tbl) {
danielebarchiesi@4 770 if (preg_match('/^T_' .$id. '\./', $d_tbl)) {
danielebarchiesi@4 771 return 1;
danielebarchiesi@4 772 }
danielebarchiesi@4 773 }
danielebarchiesi@4 774 return 0;
danielebarchiesi@4 775 }
danielebarchiesi@4 776
danielebarchiesi@4 777 function getDependentJoins($id) {
danielebarchiesi@4 778 $r = array();
danielebarchiesi@4 779 /* sub joins */
danielebarchiesi@4 780 foreach ($this->index['sub_joins'] as $alias) {
danielebarchiesi@4 781 if (preg_match('/^(T|V|G)_' . $id . '/', $alias)) {
danielebarchiesi@4 782 $r[] = $alias;
danielebarchiesi@4 783 }
danielebarchiesi@4 784 }
danielebarchiesi@4 785 /* siblings in shared optional */
danielebarchiesi@4 786 $o_id = $this->getOptionalPattern($id);
danielebarchiesi@4 787 foreach ($this->index['sub_joins'] as $alias) {
danielebarchiesi@4 788 if (preg_match('/^(T|V|G)_' . $o_id . '/', $alias) && !in_array($alias, $r)) {
danielebarchiesi@4 789 $r[] = $alias;
danielebarchiesi@4 790 }
danielebarchiesi@4 791 }
danielebarchiesi@4 792 foreach ($this->index['left_join'] as $alias) {
danielebarchiesi@4 793 if (preg_match('/^' . $o_id . '/', $alias) && !in_array($alias, $r)) {
danielebarchiesi@4 794 $r[] = 'T_' . $alias . '.s';
danielebarchiesi@4 795 }
danielebarchiesi@4 796 }
danielebarchiesi@4 797 return $r;
danielebarchiesi@4 798 }
danielebarchiesi@4 799
danielebarchiesi@4 800 /* */
danielebarchiesi@4 801
danielebarchiesi@4 802 function getRequiredSubJoinSQL($id, $prefix = '') {/* id is a triple pattern id. Optional FILTERS and GRAPHs are getting added to the join directly */
danielebarchiesi@4 803 $nl = "\n";
danielebarchiesi@4 804 $r = '';
danielebarchiesi@4 805 foreach ($this->index['sub_joins'] as $alias) {
danielebarchiesi@4 806 if (preg_match('/^V_' . $id . '_([a-z\_]+)\.val$/', $alias, $m)) {
danielebarchiesi@4 807 $col = $m[1];
danielebarchiesi@4 808 $sub_r = '';
danielebarchiesi@4 809 if ($this->isOptionalPattern($id)) {
danielebarchiesi@4 810 $pattern = $this->getPattern($id);
danielebarchiesi@4 811 do {
danielebarchiesi@4 812 $pattern = $this->getPattern($pattern['parent_id']);
danielebarchiesi@4 813 } while ($pattern['parent_id'] && ($pattern['type'] != 'optional'));
danielebarchiesi@4 814 $sub_r = $this->getPatternSQL($pattern, 'sub_join__V_' . $id);
danielebarchiesi@4 815 }
danielebarchiesi@4 816 $sub_r = $sub_r ? $nl . ' AND (' . $sub_r . ')' : '';
danielebarchiesi@4 817 /* lang dt only on literals */
danielebarchiesi@4 818 if ($col == 'o_lang_dt') {
danielebarchiesi@4 819 $sub_sub_r = 'T_' . $id . '.o_type = 2';
danielebarchiesi@4 820 $sub_r .= $nl . ' AND (' . $sub_sub_r . ')';
danielebarchiesi@4 821 }
danielebarchiesi@4 822 //$cur_prefix = $prefix ? $prefix . ' ' : 'STRAIGHT_';
danielebarchiesi@4 823 $cur_prefix = $prefix ? $prefix . ' ' : '';
danielebarchiesi@4 824 if ($col == 'g') {
danielebarchiesi@4 825 $r .= trim($cur_prefix . 'JOIN '. $this->getValueTable($col) . ' V_' .$id . '_' . $col. ' ON (' .$nl. ' (G_' . $id . '.' . $col. ' = V_' . $id. '_' . $col. '.id) ' . $sub_r . $nl . ')');
danielebarchiesi@4 826 }
danielebarchiesi@4 827 else {
danielebarchiesi@4 828 $r .= trim($cur_prefix . 'JOIN '. $this->getValueTable($col) . ' V_' .$id . '_' . $col. ' ON (' .$nl. ' (T_' . $id . '.' . $col. ' = V_' . $id. '_' . $col. '.id) ' . $sub_r . $nl . ')');
danielebarchiesi@4 829 }
danielebarchiesi@4 830 }
danielebarchiesi@4 831 elseif (preg_match('/^G_' . $id . '\.g$/', $alias, $m)) {
danielebarchiesi@4 832 $pattern = $this->getPattern($id);
danielebarchiesi@4 833 $sub_r = $this->getPatternSQL($pattern, 'graph_sub_join__G_' . $id);
danielebarchiesi@4 834 $sub_r = $sub_r ? $nl . ' AND ' . $sub_r : '';
danielebarchiesi@4 835 /* dataset restrictions */
danielebarchiesi@4 836 $gi = $this->getGraphInfos($id);
danielebarchiesi@4 837 $sub_sub_r = '';
danielebarchiesi@4 838 $added_gts = array();
danielebarchiesi@4 839 foreach ($gi as $set) {
danielebarchiesi@4 840 if (isset($set['graph']) && !in_array($set['graph'], $added_gts)) {
danielebarchiesi@4 841 $sub_sub_r .= $sub_sub_r !== '' ? ',' : '';
danielebarchiesi@4 842 $sub_sub_r .= $this->getTermID($set['graph'], 'g');
danielebarchiesi@4 843 $added_gts[] = $set['graph'];
danielebarchiesi@4 844 }
danielebarchiesi@4 845 }
danielebarchiesi@4 846 $sub_r .= ($sub_sub_r !== '') ? $nl . ' AND (G_' . $id . '.g IN (' . $sub_sub_r . '))' : ''; // /* ' . str_replace('#' , '::', $set['graph']) . ' */';
danielebarchiesi@4 847 /* other graph join conditions */
danielebarchiesi@4 848 foreach ($this->index['graph_vars'] as $var => $occurs) {
danielebarchiesi@4 849 $occur_tbls = array();
danielebarchiesi@4 850 foreach ($occurs as $occur) {
danielebarchiesi@4 851 $occur_tbls[] = $occur['table'];
danielebarchiesi@4 852 if ($occur['table'] == $id) break;
danielebarchiesi@4 853 }
danielebarchiesi@4 854 foreach($occur_tbls as $tbl) {
danielebarchiesi@4 855 if (($tbl != $id) && in_array($id, $occur_tbls) && $this->isJoinedBefore($tbl, $id)) {
danielebarchiesi@4 856 $sub_r .= $nl . ' AND (G_' .$id. '.g = G_' .$tbl. '.g)';
danielebarchiesi@4 857 }
danielebarchiesi@4 858 }
danielebarchiesi@4 859 }
danielebarchiesi@4 860 //$cur_prefix = $prefix ? $prefix . ' ' : 'STRAIGHT_';
danielebarchiesi@4 861 $cur_prefix = $prefix ? $prefix . ' ' : '';
danielebarchiesi@4 862 $r .= trim($cur_prefix . 'JOIN '. $this->getGraphTable() . ' G_' .$id . ' ON (' .$nl. ' (T_' . $id . '.t = G_' .$id. '.t)' . $sub_r . $nl . ')');
danielebarchiesi@4 863 }
danielebarchiesi@4 864 }
danielebarchiesi@4 865 return $r;
danielebarchiesi@4 866 }
danielebarchiesi@4 867
danielebarchiesi@4 868 /* */
danielebarchiesi@4 869
danielebarchiesi@4 870 function getWHERESQL() {
danielebarchiesi@4 871 $r = '';
danielebarchiesi@4 872 $nl = "\n";
danielebarchiesi@4 873 /* standard constraints */
danielebarchiesi@4 874 $sub_r = $this->getPatternSQL($this->getPattern('0'), 'where');
danielebarchiesi@4 875 /* additional constraints */
danielebarchiesi@4 876 foreach ($this->index['from'] as $id) {
danielebarchiesi@4 877 if ($sub_sub_r = $this->getConstraintSQL($id)) {
danielebarchiesi@4 878 $sub_r .= $sub_r ? $nl . ' AND ' . $sub_sub_r : $sub_sub_r;
danielebarchiesi@4 879 }
danielebarchiesi@4 880 }
danielebarchiesi@4 881 $r .= $sub_r ? $sub_r : '';
danielebarchiesi@4 882 /* left join dependencies */
danielebarchiesi@4 883 foreach ($this->index['left_join'] as $id) {
danielebarchiesi@4 884 $d_joins = $this->getDependentJoins($id);
danielebarchiesi@4 885 $added = array();
danielebarchiesi@4 886 $d_aliases = array();
danielebarchiesi@4 887 //echo $id . ' =>' . print_r($d_joins, 1);
danielebarchiesi@4 888 $id_alias = 'T_' . $id . '.s';
danielebarchiesi@4 889 foreach ($d_joins as $alias) {
danielebarchiesi@4 890 if (preg_match('/^(T|V|G)_([0-9\_]+)(_[spo])?\.([a-z\_]+)/', $alias, $m)) {
danielebarchiesi@4 891 $tbl_type = $m[1];
danielebarchiesi@4 892 $tbl_pattern_id = $m[2];
danielebarchiesi@4 893 $suffix = $m[3];
danielebarchiesi@4 894 if (($tbl_pattern_id >= $id) && $this->sameOptional($tbl_pattern_id, $id)) {/* get rid of dependency permutations and nested optionals */
danielebarchiesi@4 895 if (!in_array($tbl_type . '_' . $tbl_pattern_id . $suffix, $added)) {
danielebarchiesi@4 896 $sub_r .= $sub_r ? ' AND ' : '';
danielebarchiesi@4 897 $sub_r .= $alias . ' IS NULL';
danielebarchiesi@4 898 $d_aliases[] = $alias;
danielebarchiesi@4 899 $added[] = $tbl_type . '_' . $tbl_pattern_id . $suffix;
danielebarchiesi@4 900 $id_alias = ($tbl_pattern_id == $id) ? $alias : $id_alias;
danielebarchiesi@4 901 }
danielebarchiesi@4 902 }
danielebarchiesi@4 903 }
danielebarchiesi@4 904 }
danielebarchiesi@4 905 if (count($d_aliases) > 2) {/* @@todo fix this! */
danielebarchiesi@4 906 $sub_r1 = ' /* '.$id_alias.' dependencies */';
danielebarchiesi@4 907 $sub_r2 = '((' . $id_alias . ' IS NULL) OR (CONCAT(' . join(', ', $d_aliases) . ') IS NOT NULL))';
danielebarchiesi@4 908 $r .= $r ? $nl . $sub_r1 . $nl . ' AND ' .$sub_r2 : $sub_r1 . $nl . $sub_r2;
danielebarchiesi@4 909 }
danielebarchiesi@4 910 }
danielebarchiesi@4 911 return $r ? $nl . 'WHERE ' . $r : '';
danielebarchiesi@4 912 }
danielebarchiesi@4 913
danielebarchiesi@4 914 /* */
danielebarchiesi@4 915
danielebarchiesi@4 916 function addConstraintSQLEntry($id, $sql) {
danielebarchiesi@4 917 if (!isset($this->index['constraints'][$id])) {
danielebarchiesi@4 918 $this->index['constraints'][$id] = array();
danielebarchiesi@4 919 }
danielebarchiesi@4 920 if (!in_array($sql, $this->index['constraints'][$id])) {
danielebarchiesi@4 921 $this->index['constraints'][$id][] = $sql;
danielebarchiesi@4 922 }
danielebarchiesi@4 923 }
danielebarchiesi@4 924
danielebarchiesi@4 925 function getConstraintSQL($id) {
danielebarchiesi@4 926 $r = '';
danielebarchiesi@4 927 $nl = "\n";
danielebarchiesi@4 928 $constraints = $this->v($id, array(), $this->index['constraints']);
danielebarchiesi@4 929 foreach ($constraints as $constraint) {
danielebarchiesi@4 930 $r .= $r ? $nl . ' AND ' . $constraint : $constraint;
danielebarchiesi@4 931 }
danielebarchiesi@4 932 return $r;
danielebarchiesi@4 933 }
danielebarchiesi@4 934
danielebarchiesi@4 935 /* */
danielebarchiesi@4 936
danielebarchiesi@4 937 function getPatternSQL($pattern, $context) {
danielebarchiesi@4 938 $type = $this->v('type', '', $pattern);
danielebarchiesi@4 939 if (!$type) {
danielebarchiesi@4 940 return '';
danielebarchiesi@4 941 }
danielebarchiesi@4 942 $m = 'get' . ucfirst($type) . 'PatternSQL';
danielebarchiesi@4 943 return method_exists($this, $m) ? $this->$m($pattern, $context) : $this->getDefaultPatternSQL($pattern, $context);
danielebarchiesi@4 944 }
danielebarchiesi@4 945
danielebarchiesi@4 946 function getDefaultPatternSQL($pattern, $context) {
danielebarchiesi@4 947 $r = '';
danielebarchiesi@4 948 $nl = "\n";
danielebarchiesi@4 949 $sub_ids = $this->v('patterns', array(), $pattern);
danielebarchiesi@4 950 foreach ($sub_ids as $sub_id) {
danielebarchiesi@4 951 $sub_r = $this->getPatternSQL($this->getPattern($sub_id), $context);
danielebarchiesi@4 952 $r .= ($r && $sub_r) ? $nl . ' AND (' . $sub_r . ')' : ($sub_r ? $sub_r : '');
danielebarchiesi@4 953 }
danielebarchiesi@4 954 return $r ? $r : '';
danielebarchiesi@4 955 }
danielebarchiesi@4 956
danielebarchiesi@4 957 function getTriplePatternSQL($pattern, $context) {
danielebarchiesi@4 958 $r = '';
danielebarchiesi@4 959 $nl = "\n";
danielebarchiesi@4 960 $id = $pattern['id'];
danielebarchiesi@4 961 /* s p o */
danielebarchiesi@4 962 $vars = array();
danielebarchiesi@4 963 foreach (array('s', 'p', 'o') as $term) {
danielebarchiesi@4 964 $sub_r = '';
danielebarchiesi@4 965 $type = $pattern[$term . '_type'];
danielebarchiesi@4 966 if ($type == 'uri') {
danielebarchiesi@4 967 $term_id = $this->getTermID($pattern[$term], $term);
danielebarchiesi@4 968 $sub_r = '(T_' . $id . '.' . $term . ' = ' . $term_id . ') /* ' . preg_replace('/[\#\*\>]/' , '::', $pattern[$term]) . ' */';
danielebarchiesi@4 969 }
danielebarchiesi@4 970 elseif ($type == 'literal') {
danielebarchiesi@4 971 $term_id = $this->getTermID($pattern[$term], $term);
danielebarchiesi@4 972 $sub_r = '(T_' . $id . '.' . $term . ' = ' . $term_id . ') /* ' . preg_replace('/[\#\n\*\>]/' , ' ', $pattern[$term]) . ' */';
danielebarchiesi@4 973 if (($lang_dt = $this->v1($term . '_lang', '', $pattern)) || ($lang_dt = $this->v1($term . '_datatype', '', $pattern))) {
danielebarchiesi@4 974 $lang_dt_id = $this->getTermID($lang_dt);
danielebarchiesi@4 975 $sub_r .= $nl . ' AND (T_' . $id . '.' .$term. '_lang_dt = ' . $lang_dt_id . ') /* ' . preg_replace('/[\#\*\>]/' , '::', $lang_dt) . ' */';
danielebarchiesi@4 976 }
danielebarchiesi@4 977 }
danielebarchiesi@4 978 elseif ($type == 'var') {
danielebarchiesi@4 979 $val = $pattern[$term];
danielebarchiesi@4 980 if (isset($vars[$val])) {/* repeated var in pattern */
danielebarchiesi@4 981 $sub_r = '(T_' . $id . '.' . $term . '=' . 'T_' . $id . '.' . $vars[$val] . ')';
danielebarchiesi@4 982 }
danielebarchiesi@4 983 $vars[$val] = $term;
danielebarchiesi@4 984 if ($infos = $this->v($val, 0, $this->index['graph_vars'])) {/* graph var in triple pattern */
danielebarchiesi@4 985 $sub_r .= $sub_r ? $nl . ' AND ' : '';
danielebarchiesi@4 986 $tbl = $infos[0]['table'];
danielebarchiesi@4 987 $sub_r .= 'G_' . $tbl . '.g = T_' . $id . '.' . $term;
danielebarchiesi@4 988 }
danielebarchiesi@4 989 }
danielebarchiesi@4 990 if ($sub_r) {
danielebarchiesi@4 991 if (preg_match('/^(join)/', $context) || (preg_match('/^where/', $context) && in_array($id, $this->index['from']))) {
danielebarchiesi@4 992 $r .= $r ? $nl . ' AND ' . $sub_r : $sub_r;
danielebarchiesi@4 993 }
danielebarchiesi@4 994 }
danielebarchiesi@4 995 }
danielebarchiesi@4 996 /* g */
danielebarchiesi@4 997 if ($infos = $pattern['graph_infos']) {
danielebarchiesi@4 998 $tbl_alias = 'G_' . $id . '.g';
danielebarchiesi@4 999 if (!in_array($tbl_alias, $this->index['sub_joins'])) {
danielebarchiesi@4 1000 $this->index['sub_joins'][] = $tbl_alias;
danielebarchiesi@4 1001 }
danielebarchiesi@4 1002 $sub_r = array('graph_var' => '', 'graph_uri' => '', 'from' => '', 'from_named' => '');
danielebarchiesi@4 1003 foreach ($infos as $info) {
danielebarchiesi@4 1004 $type = $info['type'];
danielebarchiesi@4 1005 if ($type == 'graph') {
danielebarchiesi@4 1006 if ($info['uri']) {
danielebarchiesi@4 1007 $term_id = $this->getTermID($info['uri'], 'g');
danielebarchiesi@4 1008 $sub_r['graph_uri'] .= $sub_r['graph_uri'] ? $nl . ' AND ' : '';
danielebarchiesi@4 1009 $sub_r['graph_uri'] .= '(' .$tbl_alias. ' = ' . $term_id . ') /* ' . preg_replace('/[\#\*\>]/' , '::', $info['uri']) . ' */';
danielebarchiesi@4 1010 }
danielebarchiesi@4 1011 }
danielebarchiesi@4 1012 }
danielebarchiesi@4 1013 if ($sub_r['from'] && $sub_r['from_named']) {
danielebarchiesi@4 1014 $sub_r['from_named'] = '';
danielebarchiesi@4 1015 }
danielebarchiesi@4 1016 if (!$sub_r['from'] && !$sub_r['from_named']) {
danielebarchiesi@4 1017 $sub_r['graph_var'] = '';
danielebarchiesi@4 1018 }
danielebarchiesi@4 1019 if (preg_match('/^(graph_sub_join)/', $context)) {
danielebarchiesi@4 1020 foreach ($sub_r as $g_type => $g_sql) {
danielebarchiesi@4 1021 if ($g_sql) {
danielebarchiesi@4 1022 $r .= $r ? $nl . ' AND ' . $g_sql : $g_sql;
danielebarchiesi@4 1023 }
danielebarchiesi@4 1024 }
danielebarchiesi@4 1025 }
danielebarchiesi@4 1026 }
danielebarchiesi@4 1027 /* optional sibling filters? */
danielebarchiesi@4 1028 if (preg_match('/^(join|sub_join)/', $context) && $this->isOptionalPattern($id)) {
danielebarchiesi@4 1029 $o_pattern = $pattern;
danielebarchiesi@4 1030 do {
danielebarchiesi@4 1031 $o_pattern = $this->getPattern($o_pattern['parent_id']);
danielebarchiesi@4 1032 } while ($o_pattern['parent_id'] && ($o_pattern['type'] != 'optional'));
danielebarchiesi@4 1033 if ($sub_r = $this->getPatternSQL($o_pattern, 'optional_filter' . preg_replace('/^(.*)(__.*)$/', '\\2', $context))) {
danielebarchiesi@4 1034 $r .= $r ? $nl . ' AND ' . $sub_r : $sub_r;
danielebarchiesi@4 1035 }
danielebarchiesi@4 1036 /* created constraints */
danielebarchiesi@4 1037 if ($sub_r = $this->getConstraintSQL($id)) {
danielebarchiesi@4 1038 $r .= $r ? $nl . ' AND ' . $sub_r : $sub_r;
danielebarchiesi@4 1039 }
danielebarchiesi@4 1040 }
danielebarchiesi@4 1041 /* result */
danielebarchiesi@4 1042 if (preg_match('/^(where)/', $context) && $this->isOptionalPattern($id)) {
danielebarchiesi@4 1043 return '';
danielebarchiesi@4 1044 }
danielebarchiesi@4 1045 return $r;
danielebarchiesi@4 1046 }
danielebarchiesi@4 1047
danielebarchiesi@4 1048 /* */
danielebarchiesi@4 1049
danielebarchiesi@4 1050 function getFilterPatternSQL($pattern, $context) {
danielebarchiesi@4 1051 $r = '';
danielebarchiesi@4 1052 $id = $pattern['id'];
danielebarchiesi@4 1053 $constraint_id = $this->v1('constraint', '', $pattern);
danielebarchiesi@4 1054 $constraint = $this->getPattern($constraint_id);
danielebarchiesi@4 1055 $constraint_type = $constraint['type'];
danielebarchiesi@4 1056 if ($constraint_type == 'built_in_call') {
danielebarchiesi@4 1057 $r = $this->getBuiltInCallSQL($constraint, $context);
danielebarchiesi@4 1058 }
danielebarchiesi@4 1059 elseif ($constraint_type == 'expression') {
danielebarchiesi@4 1060 $r = $this->getExpressionSQL($constraint, $context, '', 'filter');
danielebarchiesi@4 1061 }
danielebarchiesi@4 1062 else {
danielebarchiesi@4 1063 $m = 'get' . ucfirst($constraint_type) . 'ExpressionSQL';
danielebarchiesi@4 1064 if (method_exists($this, $m)) {
danielebarchiesi@4 1065 $r = $this->$m($constraint, $context, '', 'filter');
danielebarchiesi@4 1066 }
danielebarchiesi@4 1067 }
danielebarchiesi@4 1068 if ($this->isOptionalPattern($id) && !preg_match('/^(join|optional_filter)/', $context)) {
danielebarchiesi@4 1069 return '';
danielebarchiesi@4 1070 }
danielebarchiesi@4 1071 /* unconnected vars in FILTERs eval to false */
danielebarchiesi@4 1072 $sub_r = $this->hasUnconnectedFilterVars($id);
danielebarchiesi@4 1073 if ($sub_r) {
danielebarchiesi@4 1074 if ($sub_r == 'alias') {
danielebarchiesi@4 1075 if (!in_array($r, $this->index['havings'])) $this->index['havings'][] = $r;
danielebarchiesi@4 1076 return '';
danielebarchiesi@4 1077 }
danielebarchiesi@4 1078 elseif (preg_match('/^T([^\s]+\.)g (.*)$/s', $r, $m)) {/* graph filter */
danielebarchiesi@4 1079 return 'G' . $m[1] . 't ' . $m[2];
danielebarchiesi@4 1080 }
danielebarchiesi@4 1081 elseif (preg_match('/^\(*V[^\s]+_g\.val .*$/s', $r, $m)) {/* graph value filter, @@improveMe */
danielebarchiesi@4 1082 //return $r;
danielebarchiesi@4 1083 }
danielebarchiesi@4 1084 else {
danielebarchiesi@4 1085 return 'FALSE';
danielebarchiesi@4 1086 }
danielebarchiesi@4 1087 }
danielebarchiesi@4 1088 /* some really ugly tweaks */
danielebarchiesi@4 1089 /* empty language filter: FILTER ( lang(?v) = '' ) */
danielebarchiesi@4 1090 $r = preg_replace('/\(\/\* language call \*\/ ([^\s]+) = ""\)/s', '((\\1 = "") OR (\\1 LIKE "%:%"))', $r);
danielebarchiesi@4 1091 return $r;
danielebarchiesi@4 1092 }
danielebarchiesi@4 1093
danielebarchiesi@4 1094 /**
danielebarchiesi@4 1095 * Checks if vars in the given (filter) pattern are used within the filter's scope.
danielebarchiesi@4 1096 */
danielebarchiesi@4 1097
danielebarchiesi@4 1098 function hasUnconnectedFilterVars($filter_pattern_id) {
danielebarchiesi@4 1099 $scope_id = $this->getFilterScope($filter_pattern_id);
danielebarchiesi@4 1100 $vars = $this->getFilterVars($filter_pattern_id);
danielebarchiesi@4 1101 $r = 0;
danielebarchiesi@4 1102 foreach ($vars as $var_name) {
danielebarchiesi@4 1103 if ($this->isUsedTripleVar($var_name, $scope_id)) continue;
danielebarchiesi@4 1104 if ($this->isAliasVar($var_name)) {
danielebarchiesi@4 1105 $r = 'alias';
danielebarchiesi@4 1106 break;
danielebarchiesi@4 1107 }
danielebarchiesi@4 1108 $r = 1;
danielebarchiesi@4 1109 break;
danielebarchiesi@4 1110 }
danielebarchiesi@4 1111 return $r;
danielebarchiesi@4 1112 }
danielebarchiesi@4 1113
danielebarchiesi@4 1114 /**
danielebarchiesi@4 1115 * Returns the given filter pattern's scope (the id of the parent group pattern).
danielebarchiesi@4 1116 */
danielebarchiesi@4 1117
danielebarchiesi@4 1118 function getFilterScope($filter_pattern_id) {
danielebarchiesi@4 1119 $patterns = $this->initial_index['patterns'];
danielebarchiesi@4 1120 $r = '';
danielebarchiesi@4 1121 foreach ($patterns as $id => $p) {
danielebarchiesi@4 1122 /* the id has to be sub-part of the given filter id */
danielebarchiesi@4 1123 if (!preg_match('/^' . $id . '.+/', $filter_pattern_id)) continue;
danielebarchiesi@4 1124 /* we are looking for a group or union */
danielebarchiesi@4 1125 if (!preg_match('/^(group|union)$/', $p['type'])) continue;
danielebarchiesi@4 1126 /* we are looking for the longest/deepest match */
danielebarchiesi@4 1127 if (strlen($id) > strlen($r)) $r = $id;
danielebarchiesi@4 1128 }
danielebarchiesi@4 1129 return $r;
danielebarchiesi@4 1130 }
danielebarchiesi@4 1131
danielebarchiesi@4 1132 /**
danielebarchiesi@4 1133 * Builds a list of vars used in the given (filter) pattern.
danielebarchiesi@4 1134 */
danielebarchiesi@4 1135
danielebarchiesi@4 1136 function getFilterVars($filter_pattern_id) {
danielebarchiesi@4 1137 $r = array();
danielebarchiesi@4 1138 $patterns = $this->initial_index['patterns'];
danielebarchiesi@4 1139 /* find vars in the given filter (i.e. the given id is part of their pattern id) */
danielebarchiesi@4 1140 foreach ($patterns as $id => $p) {
danielebarchiesi@4 1141 if (!preg_match('/^' . $filter_pattern_id . '.+/', $id)) continue;
danielebarchiesi@4 1142 $var_name = '';
danielebarchiesi@4 1143 if ($p['type'] == 'var') {
danielebarchiesi@4 1144 $var_name = $p['value'];
danielebarchiesi@4 1145 }
danielebarchiesi@4 1146 elseif (($p['type'] == 'built_in_call') && ($p['call'] == 'bound')) {
danielebarchiesi@4 1147 $var_name = $p['args'][0]['value'];
danielebarchiesi@4 1148 }
danielebarchiesi@4 1149 if ($var_name && !in_array($var_name, $r)) {
danielebarchiesi@4 1150 $r[] = $var_name;
danielebarchiesi@4 1151 }
danielebarchiesi@4 1152 }
danielebarchiesi@4 1153 return $r;
danielebarchiesi@4 1154 }
danielebarchiesi@4 1155
danielebarchiesi@4 1156 /**
danielebarchiesi@4 1157 * Checks if $var_name appears as result projection alias.
danielebarchiesi@4 1158 */
danielebarchiesi@4 1159
danielebarchiesi@4 1160 function isAliasVar($var_name) {
danielebarchiesi@4 1161 foreach ($this->infos['query']['result_vars'] as $r_var) {
danielebarchiesi@4 1162 if ($r_var['alias'] == $var_name) return 1;
danielebarchiesi@4 1163 }
danielebarchiesi@4 1164 return 0;
danielebarchiesi@4 1165 }
danielebarchiesi@4 1166
danielebarchiesi@4 1167 /**
danielebarchiesi@4 1168 * Checks if $var_name is used in a triple pattern in the given scope
danielebarchiesi@4 1169 */
danielebarchiesi@4 1170
danielebarchiesi@4 1171 function isUsedTripleVar($var_name, $scope_id = '0') {
danielebarchiesi@4 1172 $patterns = $this->initial_index['patterns'];
danielebarchiesi@4 1173 foreach ($patterns as $id => $p) {
danielebarchiesi@4 1174 if ($p['type'] != 'triple') continue;
danielebarchiesi@4 1175 if (!preg_match('/^' . $scope_id . '.+/', $id)) continue;
danielebarchiesi@4 1176 foreach (array('s', 'p', 'o') as $term) {
danielebarchiesi@4 1177 if ($p[$term . '_type'] != 'var') continue;
danielebarchiesi@4 1178 if ($p[$term] == $var_name) return 1;
danielebarchiesi@4 1179 }
danielebarchiesi@4 1180 }
danielebarchiesi@4 1181 }
danielebarchiesi@4 1182
danielebarchiesi@4 1183 /* */
danielebarchiesi@4 1184
danielebarchiesi@4 1185 function getExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
danielebarchiesi@4 1186 $r = '';
danielebarchiesi@4 1187 $nl = "\n";
danielebarchiesi@4 1188 $type = $this->v1('type', '', $pattern);
danielebarchiesi@4 1189 $sub_type = $this->v1('sub_type', $type, $pattern);
danielebarchiesi@4 1190 if (preg_match('/^(and|or)$/', $sub_type)) {
danielebarchiesi@4 1191 foreach ($pattern['patterns'] as $sub_id) {
danielebarchiesi@4 1192 $sub_pattern = $this->getPattern($sub_id);
danielebarchiesi@4 1193 $sub_pattern_type = $sub_pattern['type'];
danielebarchiesi@4 1194 if ($sub_pattern_type == 'built_in_call') {
danielebarchiesi@4 1195 $sub_r = $this->getBuiltInCallSQL($sub_pattern, $context, '', $parent_type);
danielebarchiesi@4 1196 }
danielebarchiesi@4 1197 else {
danielebarchiesi@4 1198 $sub_r = $this->getExpressionSQL($sub_pattern, $context, '', $parent_type);
danielebarchiesi@4 1199 }
danielebarchiesi@4 1200 if ($sub_r) {
danielebarchiesi@4 1201 $r .= $r ? ' ' . strtoupper($sub_type). ' (' .$sub_r. ')' : '(' . $sub_r . ')';
danielebarchiesi@4 1202 }
danielebarchiesi@4 1203 }
danielebarchiesi@4 1204 }
danielebarchiesi@4 1205 elseif ($sub_type == 'built_in_call') {
danielebarchiesi@4 1206 $r = $this->getBuiltInCallSQL($pattern, $context, $val_type, $parent_type);
danielebarchiesi@4 1207 }
danielebarchiesi@4 1208 elseif (preg_match('/literal/', $sub_type)) {
danielebarchiesi@4 1209 $r = $this->getLiteralExpressionSQL($pattern, $context, $val_type, $parent_type);
danielebarchiesi@4 1210 }
danielebarchiesi@4 1211 elseif ($sub_type) {
danielebarchiesi@4 1212 $m = 'get' . ucfirst($sub_type) . 'ExpressionSQL';
danielebarchiesi@4 1213 if (method_exists($this, $m)) {
danielebarchiesi@4 1214 $r = $this->$m($pattern, $context, '', $parent_type);
danielebarchiesi@4 1215 }
danielebarchiesi@4 1216 }
danielebarchiesi@4 1217 /* skip expressions that reference non-yet-joined tables */
danielebarchiesi@4 1218 if (preg_match('/__(T|V|G)_(.+)$/', $context, $m)) {
danielebarchiesi@4 1219 $context_pattern_id = $m[2];
danielebarchiesi@4 1220 $context_table_type = $m[1];
danielebarchiesi@4 1221 if (preg_match_all('/((T|V|G)(\_[0-9])+)/', $r, $m)) {
danielebarchiesi@4 1222 $aliases = $m[1];
danielebarchiesi@4 1223 $keep = 1;
danielebarchiesi@4 1224 foreach ($aliases as $alias) {
danielebarchiesi@4 1225 if (preg_match('/(T|V|G)_(.*)$/', $alias, $m)) {
danielebarchiesi@4 1226 $tbl_type = $m[1];
danielebarchiesi@4 1227 $tbl = $m[2];
danielebarchiesi@4 1228 if (!$this->isJoinedBefore($tbl, $context_pattern_id)) {
danielebarchiesi@4 1229 $keep = 0;
danielebarchiesi@4 1230 }
danielebarchiesi@4 1231 elseif (($context_pattern_id == $tbl) && preg_match('/(TV)/', $context_table_type . $tbl_type)) {
danielebarchiesi@4 1232 $keep = 0;
danielebarchiesi@4 1233 }
danielebarchiesi@4 1234 }
danielebarchiesi@4 1235 }
danielebarchiesi@4 1236 $r = $keep ? $r : '';
danielebarchiesi@4 1237 }
danielebarchiesi@4 1238 }
danielebarchiesi@4 1239 return $r ? '(' . $r . ')' : $r;
danielebarchiesi@4 1240 }
danielebarchiesi@4 1241
danielebarchiesi@4 1242 function detectExpressionValueType($pattern_ids) {
danielebarchiesi@4 1243 foreach ($pattern_ids as $id) {
danielebarchiesi@4 1244 $pattern = $this->getPattern($id);
danielebarchiesi@4 1245 $type = $this->v('type', '', $pattern);
danielebarchiesi@4 1246 if (($type == 'literal') && isset($pattern['datatype'])) {
danielebarchiesi@4 1247 if (in_array($pattern['datatype'], array($this->xsd . 'integer', $this->xsd . 'float', $this->xsd . 'double'))) {
danielebarchiesi@4 1248 return 'numeric';
danielebarchiesi@4 1249 }
danielebarchiesi@4 1250 }
danielebarchiesi@4 1251 }
danielebarchiesi@4 1252 return '';
danielebarchiesi@4 1253 }
danielebarchiesi@4 1254
danielebarchiesi@4 1255 /* */
danielebarchiesi@4 1256
danielebarchiesi@4 1257 function getRelationalExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
danielebarchiesi@4 1258 $r = '';
danielebarchiesi@4 1259 $val_type = $this->detectExpressionValueType($pattern['patterns']);
danielebarchiesi@4 1260 $op = $pattern['operator'];
danielebarchiesi@4 1261 foreach ($pattern['patterns'] as $sub_id) {
danielebarchiesi@4 1262 $sub_pattern = $this->getPattern($sub_id);
danielebarchiesi@4 1263 $sub_pattern['parent_op'] = $op;
danielebarchiesi@4 1264 $sub_type = $sub_pattern['type'];
danielebarchiesi@4 1265 $m = ($sub_type == 'built_in_call') ? 'getBuiltInCallSQL' : 'get' . ucfirst($sub_type) . 'ExpressionSQL';
danielebarchiesi@4 1266 $m = str_replace('ExpressionExpression', 'Expression', $m);
danielebarchiesi@4 1267 $sub_r = method_exists($this, $m) ? $this->$m($sub_pattern, $context, $val_type, 'relational') : '';
danielebarchiesi@4 1268 $r .= $r ? ' ' . $op . ' ' . $sub_r : $sub_r;
danielebarchiesi@4 1269 }
danielebarchiesi@4 1270 return $r ? '(' . $r . ')' : $r;
danielebarchiesi@4 1271 }
danielebarchiesi@4 1272
danielebarchiesi@4 1273 function getAdditiveExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
danielebarchiesi@4 1274 $r = '';
danielebarchiesi@4 1275 $val_type = $this->detectExpressionValueType($pattern['patterns']);
danielebarchiesi@4 1276 foreach ($pattern['patterns'] as $sub_id) {
danielebarchiesi@4 1277 $sub_pattern = $this->getPattern($sub_id);
danielebarchiesi@4 1278 $sub_type = $this->v('type', '', $sub_pattern);
danielebarchiesi@4 1279 $m = ($sub_type == 'built_in_call') ? 'getBuiltInCallSQL' : 'get' . ucfirst($sub_type) . 'ExpressionSQL';
danielebarchiesi@4 1280 $m = str_replace('ExpressionExpression', 'Expression', $m);
danielebarchiesi@4 1281 $sub_r = method_exists($this, $m) ? $this->$m($sub_pattern, $context, $val_type, 'additive') : '';
danielebarchiesi@4 1282 $r .= $r ? ' ' . $sub_r : $sub_r;
danielebarchiesi@4 1283 }
danielebarchiesi@4 1284 return $r;
danielebarchiesi@4 1285 }
danielebarchiesi@4 1286
danielebarchiesi@4 1287 function getMultiplicativeExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
danielebarchiesi@4 1288 $r = '';
danielebarchiesi@4 1289 $val_type = $this->detectExpressionValueType($pattern['patterns']);
danielebarchiesi@4 1290 foreach ($pattern['patterns'] as $sub_id) {
danielebarchiesi@4 1291 $sub_pattern = $this->getPattern($sub_id);
danielebarchiesi@4 1292 $sub_type = $sub_pattern['type'];
danielebarchiesi@4 1293 $m = ($sub_type == 'built_in_call') ? 'getBuiltInCallSQL' : 'get' . ucfirst($sub_type) . 'ExpressionSQL';
danielebarchiesi@4 1294 $m = str_replace('ExpressionExpression', 'Expression', $m);
danielebarchiesi@4 1295 $sub_r = method_exists($this, $m) ? $this->$m($sub_pattern, $context, $val_type, 'multiplicative') : '';
danielebarchiesi@4 1296 $r .= $r ? ' ' . $sub_r : $sub_r;
danielebarchiesi@4 1297 }
danielebarchiesi@4 1298 return $r;
danielebarchiesi@4 1299 }
danielebarchiesi@4 1300
danielebarchiesi@4 1301 /* */
danielebarchiesi@4 1302
danielebarchiesi@4 1303 function getVarExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
danielebarchiesi@4 1304 $var = $pattern['value'];
danielebarchiesi@4 1305 $info = $this->getVarTableInfos($var);
danielebarchiesi@4 1306 if (!$tbl = $info['table']) {
danielebarchiesi@4 1307 /* might be an aggregate var */
danielebarchiesi@4 1308 $vars = $this->infos['query']['result_vars'];
danielebarchiesi@4 1309 foreach ($vars as $test_var) {
danielebarchiesi@4 1310 if ($test_var['alias'] == $pattern['value']) {
danielebarchiesi@4 1311 return '`' . $pattern['value'] . '`';
danielebarchiesi@4 1312 }
danielebarchiesi@4 1313 }
danielebarchiesi@4 1314 return '';
danielebarchiesi@4 1315 }
danielebarchiesi@4 1316 $col = $info['col'];
danielebarchiesi@4 1317 if (($context == 'order') && ($col == 'o')) {
danielebarchiesi@4 1318 $tbl_alias = 'T_' . $tbl . '.o_comp';
danielebarchiesi@4 1319 }
danielebarchiesi@4 1320 elseif ($context == 'sameterm') {
danielebarchiesi@4 1321 $tbl_alias = 'T_' . $tbl . '.' . $col;
danielebarchiesi@4 1322 }
danielebarchiesi@4 1323 elseif (($parent_type == 'relational') && ($col == 'o') && (preg_match('/[\<\>]/', $this->v('parent_op', '', $pattern)))) {
danielebarchiesi@4 1324 $tbl_alias = 'T_' . $tbl . '.o_comp';
danielebarchiesi@4 1325 }
danielebarchiesi@4 1326 else {
danielebarchiesi@4 1327 $tbl_alias = 'V_' . $tbl . '_' . $col . '.val';
danielebarchiesi@4 1328 if (!in_array($tbl_alias, $this->index['sub_joins'])) {
danielebarchiesi@4 1329 $this->index['sub_joins'][] = $tbl_alias;
danielebarchiesi@4 1330 }
danielebarchiesi@4 1331 }
danielebarchiesi@4 1332 $op = $this->v('operator', '', $pattern);
danielebarchiesi@4 1333 if (preg_match('/^(filter|and)/', $parent_type)) {
danielebarchiesi@4 1334 if ($op == '!') {
danielebarchiesi@4 1335 $r = '(((' . $tbl_alias . ' = 0) AND (CONCAT("1", ' . $tbl_alias . ') != 1))'; /* 0 and no string */
danielebarchiesi@4 1336 $r .= ' OR (' . $tbl_alias . ' IN ("", "false")))'; /* or "", or "false" */
danielebarchiesi@4 1337 }
danielebarchiesi@4 1338 else {
danielebarchiesi@4 1339 $r = '((' . $tbl_alias . ' != 0)'; /* not null */
danielebarchiesi@4 1340 $r .= ' OR ((CONCAT("1", ' . $tbl_alias . ') = 1) AND (' . $tbl_alias . ' NOT IN ("", "false"))))'; /* string, and not "" or "false" */
danielebarchiesi@4 1341 }
danielebarchiesi@4 1342 }
danielebarchiesi@4 1343 else {
danielebarchiesi@4 1344 $r = trim($op . ' ' . $tbl_alias);
danielebarchiesi@4 1345 if ($val_type == 'numeric') {
danielebarchiesi@4 1346 if (preg_match('/__(T|V|G)_(.+)$/', $context, $m)) {
danielebarchiesi@4 1347 $context_pattern_id = $m[2];
danielebarchiesi@4 1348 $context_table_type = $m[1];
danielebarchiesi@4 1349 }
danielebarchiesi@4 1350 else {
danielebarchiesi@4 1351 $context_pattern_id = $pattern['id'];
danielebarchiesi@4 1352 $context_table_type = 'T';
danielebarchiesi@4 1353 }
danielebarchiesi@4 1354 if ($this->isJoinedBefore($tbl, $context_pattern_id)) {
danielebarchiesi@4 1355 $add = ($tbl != $context_pattern_id) ? 1 : 0;
danielebarchiesi@4 1356 $add = (!$add && ($context_table_type == 'V')) ? 1 : 0;
danielebarchiesi@4 1357 if ($add) {
danielebarchiesi@4 1358 $this->addConstraintSQLEntry($context_pattern_id, '(' .$r. ' = "0" OR ' . $r . '*1.0 != 0)');
danielebarchiesi@4 1359 }
danielebarchiesi@4 1360 }
danielebarchiesi@4 1361 }
danielebarchiesi@4 1362 }
danielebarchiesi@4 1363 return $r;
danielebarchiesi@4 1364 }
danielebarchiesi@4 1365
danielebarchiesi@4 1366 /* */
danielebarchiesi@4 1367
danielebarchiesi@4 1368 function getUriExpressionSQL($pattern, $context, $val_type = '') {
danielebarchiesi@4 1369 $val = $pattern['uri'];
danielebarchiesi@4 1370 $r = $pattern['operator'];
danielebarchiesi@4 1371 $r .= is_numeric($val) ? ' ' . $val : ' "' . mysql_real_escape_string($val, $this->store->getDBCon()) . '"';
danielebarchiesi@4 1372 return $r;
danielebarchiesi@4 1373 }
danielebarchiesi@4 1374
danielebarchiesi@4 1375 /* */
danielebarchiesi@4 1376
danielebarchiesi@4 1377 function getLiteralExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
danielebarchiesi@4 1378 $val = $pattern['value'];
danielebarchiesi@4 1379 $r = $pattern['operator'];
danielebarchiesi@4 1380 if (is_numeric($val) && $this->v('datatype', 0, $pattern)) {
danielebarchiesi@4 1381 $r .= ' ' . $val;
danielebarchiesi@4 1382 }
danielebarchiesi@4 1383 elseif (preg_match('/^(true|false)$/i', $val) && ($this->v1('datatype', '', $pattern) == 'http://www.w3.org/2001/XMLSchema#boolean')) {
danielebarchiesi@4 1384 $r .= ' ' . strtoupper($val);
danielebarchiesi@4 1385 }
danielebarchiesi@4 1386 elseif ($parent_type == 'regex') {
danielebarchiesi@4 1387 $sub_r = mysql_real_escape_string($val, $this->store->getDBCon());
danielebarchiesi@4 1388 $r .= ' "' . preg_replace('/\x5c\x5c/', '\\', $sub_r) . '"';
danielebarchiesi@4 1389 }
danielebarchiesi@4 1390 else {
danielebarchiesi@4 1391 $r .= ' "' . mysql_real_escape_string($val, $this->store->getDBCon()) . '"';
danielebarchiesi@4 1392 }
danielebarchiesi@4 1393 if (($lang_dt = $this->v1('lang', '', $pattern)) || ($lang_dt = $this->v1('datatype', '', $pattern))) {
danielebarchiesi@4 1394 /* try table/alias via var in siblings */
danielebarchiesi@4 1395 if ($var = $this->findSiblingVarExpression($pattern['id'])) {
danielebarchiesi@4 1396 if (isset($this->index['vars'][$var])) {
danielebarchiesi@4 1397 $infos = $this->index['vars'][$var];
danielebarchiesi@4 1398 foreach ($infos as $info) {
danielebarchiesi@4 1399 if ($info['col'] == 'o') {
danielebarchiesi@4 1400 $tbl = $info['table'];
danielebarchiesi@4 1401 $term_id = $this->getTermID($lang_dt);
danielebarchiesi@4 1402 if ($pattern['operator'] != '!=') {
danielebarchiesi@4 1403 if (preg_match('/__(T|V|G)_(.+)$/', $context, $m)) {
danielebarchiesi@4 1404 $context_pattern_id = $m[2];
danielebarchiesi@4 1405 $context_table_type = $m[1];
danielebarchiesi@4 1406 }
danielebarchiesi@4 1407 elseif ($context == 'where') {
danielebarchiesi@4 1408 $context_pattern_id = $tbl;
danielebarchiesi@4 1409 }
danielebarchiesi@4 1410 else {
danielebarchiesi@4 1411 $context_pattern_id = $pattern['id'];
danielebarchiesi@4 1412 }
danielebarchiesi@4 1413 if ($tbl == $context_pattern_id) {/* @todo better dependency check */
danielebarchiesi@4 1414 if ($term_id || ($lang_dt != 'http://www.w3.org/2001/XMLSchema#integer')) {/* skip if simple int, but no id */
danielebarchiesi@4 1415 $this->addConstraintSQLEntry($context_pattern_id, 'T_' . $tbl . '.o_lang_dt = ' . $term_id . ' /* ' . preg_replace('/[\#\*\>]/' , '::', $lang_dt) . ' */');
danielebarchiesi@4 1416 }
danielebarchiesi@4 1417 }
danielebarchiesi@4 1418 }
danielebarchiesi@4 1419 break;
danielebarchiesi@4 1420 }
danielebarchiesi@4 1421 }
danielebarchiesi@4 1422 }
danielebarchiesi@4 1423 }
danielebarchiesi@4 1424 }
danielebarchiesi@4 1425 return trim($r);
danielebarchiesi@4 1426 }
danielebarchiesi@4 1427
danielebarchiesi@4 1428 function findSiblingVarExpression($id) {
danielebarchiesi@4 1429 $pattern = $this->getPattern($id);
danielebarchiesi@4 1430 do {
danielebarchiesi@4 1431 $pattern = $this->getPattern($pattern['parent_id']);
danielebarchiesi@4 1432 } while ($pattern['parent_id'] && ($pattern['type'] != 'expression'));
danielebarchiesi@4 1433 $sub_patterns = $this->v('patterns', array(), $pattern);
danielebarchiesi@4 1434 foreach ($sub_patterns as $sub_id) {
danielebarchiesi@4 1435 $sub_pattern = $this->getPattern($sub_id);
danielebarchiesi@4 1436 if ($sub_pattern['type'] == 'var') {
danielebarchiesi@4 1437 return $sub_pattern['value'];
danielebarchiesi@4 1438 }
danielebarchiesi@4 1439 }
danielebarchiesi@4 1440 return '';
danielebarchiesi@4 1441 }
danielebarchiesi@4 1442
danielebarchiesi@4 1443 /* */
danielebarchiesi@4 1444
danielebarchiesi@4 1445 function getFunctionExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
danielebarchiesi@4 1446 $fnc_uri = $pattern['uri'];
danielebarchiesi@4 1447 $op = $this->v('operator', '', $pattern);
danielebarchiesi@4 1448 if ($op) $op .= ' ';
danielebarchiesi@4 1449 if ($this->allow_extension_functions) {
danielebarchiesi@4 1450 /* mysql functions */
danielebarchiesi@4 1451 if (preg_match('/^http\:\/\/web\-semantics\.org\/ns\/mysql\/(.*)$/', $fnc_uri, $m)) {
danielebarchiesi@4 1452 $fnc_name = strtoupper($m[1]);
danielebarchiesi@4 1453 $sub_r = '';
danielebarchiesi@4 1454 foreach ($pattern['args'] as $arg) {
danielebarchiesi@4 1455 $sub_r .= $sub_r ? ', ' : '';
danielebarchiesi@4 1456 $sub_r .= $this->getExpressionSQL($arg, $context, $val_type, $parent_type);
danielebarchiesi@4 1457 }
danielebarchiesi@4 1458 return $op . $fnc_name . '(' . $sub_r . ')';
danielebarchiesi@4 1459 }
danielebarchiesi@4 1460 /* any other: ignore */
danielebarchiesi@4 1461 }
danielebarchiesi@4 1462 /* simple type conversions */
danielebarchiesi@4 1463 if (strpos($fnc_uri, 'http://www.w3.org/2001/XMLSchema#') === 0) {
danielebarchiesi@4 1464 return $op . $this->getExpressionSQL($pattern['args'][0], $context, $val_type, $parent_type);
danielebarchiesi@4 1465 }
danielebarchiesi@4 1466 return '';
danielebarchiesi@4 1467 }
danielebarchiesi@4 1468
danielebarchiesi@4 1469 /* */
danielebarchiesi@4 1470
danielebarchiesi@4 1471 function getBuiltInCallSQL($pattern, $context) {
danielebarchiesi@4 1472 $call = $pattern['call'];
danielebarchiesi@4 1473 $m = 'get' . ucfirst($call) . 'CallSQL';
danielebarchiesi@4 1474 if (method_exists($this, $m)) {
danielebarchiesi@4 1475 return $this->$m($pattern, $context);
danielebarchiesi@4 1476 }
danielebarchiesi@4 1477 else {
danielebarchiesi@4 1478 $this->addError('Unknown built-in call "' . $call . '"');
danielebarchiesi@4 1479 }
danielebarchiesi@4 1480 return '';
danielebarchiesi@4 1481 }
danielebarchiesi@4 1482
danielebarchiesi@4 1483 function getBoundCallSQL($pattern, $context) {
danielebarchiesi@4 1484 $r = '';
danielebarchiesi@4 1485 $var = $pattern['args'][0]['value'];
danielebarchiesi@4 1486 $info = $this->getVarTableInfos($var);
danielebarchiesi@4 1487 if (!$tbl = $info['table']) {
danielebarchiesi@4 1488 return '';
danielebarchiesi@4 1489 }
danielebarchiesi@4 1490 $col = $info['col'];
danielebarchiesi@4 1491 $tbl_alias = 'T_' . $tbl . '.' . $col;
danielebarchiesi@4 1492 if ($pattern['operator'] == '!') {
danielebarchiesi@4 1493 return $tbl_alias . ' IS NULL';
danielebarchiesi@4 1494 }
danielebarchiesi@4 1495 return $tbl_alias . ' IS NOT NULL';
danielebarchiesi@4 1496 }
danielebarchiesi@4 1497
danielebarchiesi@4 1498 function getHasTypeCallSQL($pattern, $context, $type) {
danielebarchiesi@4 1499 $r = '';
danielebarchiesi@4 1500 $var = $pattern['args'][0]['value'];
danielebarchiesi@4 1501 $info = $this->getVarTableInfos($var);
danielebarchiesi@4 1502 if (!$tbl = $info['table']) {
danielebarchiesi@4 1503 return '';
danielebarchiesi@4 1504 }
danielebarchiesi@4 1505 $col = $info['col'];
danielebarchiesi@4 1506 $tbl_alias = 'T_' . $tbl . '.' . $col . '_type';
danielebarchiesi@4 1507 return $tbl_alias . ' ' .$this->v('operator', '', $pattern) . '= ' . $type;
danielebarchiesi@4 1508 }
danielebarchiesi@4 1509
danielebarchiesi@4 1510 function getIsliteralCallSQL($pattern, $context) {
danielebarchiesi@4 1511 return $this->getHasTypeCallSQL($pattern, $context, 2);
danielebarchiesi@4 1512 }
danielebarchiesi@4 1513
danielebarchiesi@4 1514 function getIsblankCallSQL($pattern, $context) {
danielebarchiesi@4 1515 return $this->getHasTypeCallSQL($pattern, $context, 1);
danielebarchiesi@4 1516 }
danielebarchiesi@4 1517
danielebarchiesi@4 1518 function getIsiriCallSQL($pattern, $context) {
danielebarchiesi@4 1519 return $this->getHasTypeCallSQL($pattern, $context, 0);
danielebarchiesi@4 1520 }
danielebarchiesi@4 1521
danielebarchiesi@4 1522 function getIsuriCallSQL($pattern, $context) {
danielebarchiesi@4 1523 return $this->getHasTypeCallSQL($pattern, $context, 0);
danielebarchiesi@4 1524 }
danielebarchiesi@4 1525
danielebarchiesi@4 1526 function getStrCallSQL($pattern, $context) {
danielebarchiesi@4 1527 $sub_pattern = $pattern['args'][0];
danielebarchiesi@4 1528 $sub_type = $sub_pattern['type'];
danielebarchiesi@4 1529 $m = 'get' . ucfirst($sub_type) . 'ExpressionSQL';
danielebarchiesi@4 1530 if (method_exists($this, $m)) {
danielebarchiesi@4 1531 return $this->$m($sub_pattern, $context);
danielebarchiesi@4 1532 }
danielebarchiesi@4 1533 }
danielebarchiesi@4 1534
danielebarchiesi@4 1535 function getFunctionCallSQL($pattern, $context) {
danielebarchiesi@4 1536 $f_uri = $pattern['uri'];
danielebarchiesi@4 1537 if (preg_match('/(integer|double|float|string)$/', $f_uri)) {/* skip conversions */
danielebarchiesi@4 1538 $sub_pattern = $pattern['args'][0];
danielebarchiesi@4 1539 $sub_type = $sub_pattern['type'];
danielebarchiesi@4 1540 $m = 'get' . ucfirst($sub_type) . 'ExpressionSQL';
danielebarchiesi@4 1541 if (method_exists($this, $m)) {
danielebarchiesi@4 1542 return $this->$m($sub_pattern, $context);
danielebarchiesi@4 1543 }
danielebarchiesi@4 1544 }
danielebarchiesi@4 1545 }
danielebarchiesi@4 1546
danielebarchiesi@4 1547 function getLangDatatypeCallSQL($pattern, $context) {
danielebarchiesi@4 1548 $r = '';
danielebarchiesi@4 1549 if (isset($pattern['patterns'])) { /* proceed with first argument only (assumed as base type for type promotion) */
danielebarchiesi@4 1550 $sub_pattern = array('args' => array($pattern['patterns'][0]));
danielebarchiesi@4 1551 return $this->getLangDatatypeCallSQL($sub_pattern, $context);
danielebarchiesi@4 1552 }
danielebarchiesi@4 1553 if (!isset($pattern['args'])) {
danielebarchiesi@4 1554 return 'FALSE';
danielebarchiesi@4 1555 }
danielebarchiesi@4 1556 $sub_type = $pattern['args'][0]['type'];
danielebarchiesi@4 1557 if ($sub_type != 'var') {
danielebarchiesi@4 1558 return $this->getLangDatatypeCallSQL($pattern['args'][0], $context);
danielebarchiesi@4 1559 }
danielebarchiesi@4 1560 $var = $pattern['args'][0]['value'];
danielebarchiesi@4 1561 $info = $this->getVarTableInfos($var);
danielebarchiesi@4 1562 if (!$tbl = $info['table']) {
danielebarchiesi@4 1563 return '';
danielebarchiesi@4 1564 }
danielebarchiesi@4 1565 $col = 'o_lang_dt';
danielebarchiesi@4 1566 $tbl_alias = 'V_' . $tbl . '_' . $col . '.val';
danielebarchiesi@4 1567 if (!in_array($tbl_alias, $this->index['sub_joins'])) {
danielebarchiesi@4 1568 $this->index['sub_joins'][] = $tbl_alias;
danielebarchiesi@4 1569 }
danielebarchiesi@4 1570 $op = $this->v('operator', '', $pattern);
danielebarchiesi@4 1571 $r = trim($op . ' ' . $tbl_alias);
danielebarchiesi@4 1572 return $r;
danielebarchiesi@4 1573 }
danielebarchiesi@4 1574
danielebarchiesi@4 1575 function getDatatypeCallSQL($pattern, $context) {
danielebarchiesi@4 1576 return '/* datatype call */ ' . $this->getLangDatatypeCallSQL($pattern, $context);
danielebarchiesi@4 1577 }
danielebarchiesi@4 1578
danielebarchiesi@4 1579 function getLangCallSQL($pattern, $context) {
danielebarchiesi@4 1580 return '/* language call */ ' . $this->getLangDatatypeCallSQL($pattern, $context);
danielebarchiesi@4 1581 }
danielebarchiesi@4 1582
danielebarchiesi@4 1583 function getLangmatchesCallSQL($pattern, $context) {
danielebarchiesi@4 1584 if (count($pattern['args']) == 2) {
danielebarchiesi@4 1585 $arg_1 = $pattern['args'][0];
danielebarchiesi@4 1586 $arg_2 = $pattern['args'][1];
danielebarchiesi@4 1587 $sub_r_1 = $this->getBuiltInCallSQL($arg_1, $context);/* adds value join */
danielebarchiesi@4 1588 $sub_r_2 = $this->getExpressionSQL($arg_2, $context);
danielebarchiesi@4 1589 $op = $this->v('operator', '', $pattern);
danielebarchiesi@4 1590 if (preg_match('/^([\"\'])([^\'\"]+)/', $sub_r_2, $m)) {
danielebarchiesi@4 1591 if ($m[2] == '*') {
danielebarchiesi@4 1592 $r = ($op == '!') ? 'NOT (' . $sub_r_1 . ' REGEXP "^[a-zA-Z\-]+$"' . ')' : $sub_r_1 . ' REGEXP "^[a-zA-Z\-]+$"';
danielebarchiesi@4 1593 }
danielebarchiesi@4 1594 else {
danielebarchiesi@4 1595 $r = ($op == '!') ? $sub_r_1 . ' NOT LIKE ' . $m[1] . $m[2] . '%' . $m[1] : $sub_r_1 . ' LIKE ' . $m[1] . $m[2] . '%' . $m[1];
danielebarchiesi@4 1596 }
danielebarchiesi@4 1597 }
danielebarchiesi@4 1598 else {
danielebarchiesi@4 1599 $r = ($op == '!') ? $sub_r_1 . ' NOT LIKE CONCAT(' . $sub_r_2 . ', "%")' : $sub_r_1 . ' LIKE CONCAT(' . $sub_r_2 . ', "%")';
danielebarchiesi@4 1600 }
danielebarchiesi@4 1601 return $r;
danielebarchiesi@4 1602 }
danielebarchiesi@4 1603 return '';
danielebarchiesi@4 1604 }
danielebarchiesi@4 1605
danielebarchiesi@4 1606 function getSametermCallSQL($pattern, $context) {
danielebarchiesi@4 1607 if (count($pattern['args']) == 2) {
danielebarchiesi@4 1608 $arg_1 = $pattern['args'][0];
danielebarchiesi@4 1609 $arg_2 = $pattern['args'][1];
danielebarchiesi@4 1610 $sub_r_1 = $this->getExpressionSQL($arg_1, 'sameterm');
danielebarchiesi@4 1611 $sub_r_2 = $this->getExpressionSQL($arg_2, 'sameterm');
danielebarchiesi@4 1612 $op = $this->v('operator', '', $pattern);
danielebarchiesi@4 1613 $r = $sub_r_1 . ' ' . $op . '= ' . $sub_r_2;
danielebarchiesi@4 1614 return $r;
danielebarchiesi@4 1615 }
danielebarchiesi@4 1616 return '';
danielebarchiesi@4 1617 }
danielebarchiesi@4 1618
danielebarchiesi@4 1619 function getRegexCallSQL($pattern, $context) {
danielebarchiesi@4 1620 $ac = count($pattern['args']);
danielebarchiesi@4 1621 if ($ac >= 2) {
danielebarchiesi@4 1622 foreach ($pattern['args'] as $i => $arg) {
danielebarchiesi@4 1623 $var = 'sub_r_' . ($i + 1);
danielebarchiesi@4 1624 $$var = $this->getExpressionSQL($arg, $context, '', 'regex');
danielebarchiesi@4 1625 }
danielebarchiesi@4 1626 $sub_r_3 = (isset($sub_r_3) && preg_match('/[\"\'](.+)[\"\']/', $sub_r_3, $m)) ? strtolower($m[1]) : '';
danielebarchiesi@4 1627 $op = ($this->v('operator', '', $pattern) == '!') ? ' NOT' : '';
danielebarchiesi@4 1628 if (!$sub_r_1 || !$sub_r_2) return '';
danielebarchiesi@4 1629 $is_simple_search = preg_match('/^[\(\"]+(\^)?([a-z0-9\_\-\s]+)(\$)?[\)\"]+$/is', $sub_r_2, $m);
danielebarchiesi@4 1630 $is_simple_search = preg_match('/^[\(\"]+(\^)?([^\\\*\[\]\}\{\(\)\"\'\?\+\.]+)(\$)?[\)\"]+$/is', $sub_r_2, $m);
danielebarchiesi@4 1631 $is_o_search = preg_match('/o\.val\)*$/', $sub_r_1);
danielebarchiesi@4 1632 /* fulltext search (may have "|") */
danielebarchiesi@4 1633 if ($is_simple_search && $is_o_search && !$op && (strlen($m[2]) > 8) && $this->store->hasFulltextIndex()) {
danielebarchiesi@4 1634 /* MATCH variations */
danielebarchiesi@4 1635 if (($val_parts = preg_split('/\|/', $m[2]))) {
danielebarchiesi@4 1636 return 'MATCH(' . trim($sub_r_1, '()') . ') AGAINST("' . join(' ', $val_parts) . '")';
danielebarchiesi@4 1637 }
danielebarchiesi@4 1638 else {
danielebarchiesi@4 1639 return 'MATCH(' . trim($sub_r_1, '()') . ') AGAINST("' . $m[2] . '")';
danielebarchiesi@4 1640 }
danielebarchiesi@4 1641 }
danielebarchiesi@4 1642 if (preg_match('/\|/', $sub_r_2)) $is_simple_search = 0;
danielebarchiesi@4 1643 /* LIKE */
danielebarchiesi@4 1644 if ($is_simple_search && ($sub_r_3 == 'i')) {
danielebarchiesi@4 1645 $sub_r_2 = $m[1] ? $m[2] : '%' . $m[2];
danielebarchiesi@4 1646 $sub_r_2 .= isset($m[3]) && $m[3] ? '' : '%';
danielebarchiesi@4 1647 return $sub_r_1 . $op . ' LIKE "' . $sub_r_2 . '"';
danielebarchiesi@4 1648 }
danielebarchiesi@4 1649 /* REGEXP */
danielebarchiesi@4 1650 $opt = ($sub_r_3 == 'i') ? '' : 'BINARY ';
danielebarchiesi@4 1651 return $sub_r_1 . $op . ' REGEXP ' . $opt . $sub_r_2;
danielebarchiesi@4 1652 }
danielebarchiesi@4 1653 return '';
danielebarchiesi@4 1654 }
danielebarchiesi@4 1655
danielebarchiesi@4 1656 /* */
danielebarchiesi@4 1657
danielebarchiesi@4 1658 function getGROUPSQL() {
danielebarchiesi@4 1659 $r = '';
danielebarchiesi@4 1660 $nl = "\n";
danielebarchiesi@4 1661 $infos = $this->v('group_infos', array(), $this->infos['query']);
danielebarchiesi@4 1662 foreach ($infos as $info) {
danielebarchiesi@4 1663 $var = $info['value'];
danielebarchiesi@4 1664 if ($tbl_infos = $this->getVarTableInfos($var, 0)) {
danielebarchiesi@4 1665 $tbl_alias = $tbl_infos['table_alias'];
danielebarchiesi@4 1666 $r .= $r ? ', ' : 'GROUP BY ';
danielebarchiesi@4 1667 $r .= $tbl_alias;
danielebarchiesi@4 1668 }
danielebarchiesi@4 1669 }
danielebarchiesi@4 1670 $hr = '';
danielebarchiesi@4 1671 foreach ($this->index['havings'] as $having) {
danielebarchiesi@4 1672 $hr .= $hr ? ' AND' : ' HAVING';
danielebarchiesi@4 1673 $hr .= '(' . $having . ')';
danielebarchiesi@4 1674 }
danielebarchiesi@4 1675 $r .= $hr;
danielebarchiesi@4 1676 return $r ? $nl . $r : $r;
danielebarchiesi@4 1677 }
danielebarchiesi@4 1678
danielebarchiesi@4 1679 /* */
danielebarchiesi@4 1680
danielebarchiesi@4 1681 function getORDERSQL() {
danielebarchiesi@4 1682 $r = '';
danielebarchiesi@4 1683 $nl = "\n";
danielebarchiesi@4 1684 $infos = $this->v('order_infos', array(), $this->infos['query']);
danielebarchiesi@4 1685 foreach ($infos as $info) {
danielebarchiesi@4 1686 $type = $info['type'];
danielebarchiesi@4 1687 $ms = array('expression' => 'getExpressionSQL', 'built_in_call' => 'getBuiltInCallSQL', 'function_call' => 'getFunctionCallSQL');
danielebarchiesi@4 1688 $m = isset($ms[$type]) ? $ms[$type] : 'get' . ucfirst($type) . 'ExpressionSQL';
danielebarchiesi@4 1689 if (method_exists($this, $m)) {
danielebarchiesi@4 1690 $sub_r = '(' . $this->$m($info, 'order') . ')';
danielebarchiesi@4 1691 $sub_r .= $this->v('direction', '', $info) == 'desc' ? ' DESC' : '';
danielebarchiesi@4 1692 $r .= $r ? ',' .$nl . $sub_r : $sub_r;
danielebarchiesi@4 1693 }
danielebarchiesi@4 1694 }
danielebarchiesi@4 1695 return $r ? $nl . 'ORDER BY ' . $r : '';
danielebarchiesi@4 1696 }
danielebarchiesi@4 1697
danielebarchiesi@4 1698 /* */
danielebarchiesi@4 1699
danielebarchiesi@4 1700 function getLIMITSQL() {
danielebarchiesi@4 1701 $r = '';
danielebarchiesi@4 1702 $nl = "\n";
danielebarchiesi@4 1703 $limit = $this->v('limit', -1, $this->infos['query']);
danielebarchiesi@4 1704 $offset = $this->v('offset', -1, $this->infos['query']);
danielebarchiesi@4 1705 if ($limit != -1) {
danielebarchiesi@4 1706 $offset = ($offset == -1) ? 0 : mysql_real_escape_string($offset, $this->store->getDBCon());
danielebarchiesi@4 1707 $r = 'LIMIT ' . $offset . ',' . $limit;
danielebarchiesi@4 1708 }
danielebarchiesi@4 1709 elseif ($offset != -1) {
danielebarchiesi@4 1710 $r = 'LIMIT ' . mysql_real_escape_string($offset, $this->store->getDBCon()) . ',999999999999'; /* mysql doesn't support stand-alone offsets .. */
danielebarchiesi@4 1711 }
danielebarchiesi@4 1712 return $r ? $nl . $r : '';
danielebarchiesi@4 1713 }
danielebarchiesi@4 1714
danielebarchiesi@4 1715 /* */
danielebarchiesi@4 1716
danielebarchiesi@4 1717 function getValueSQL($q_tbl, $q_sql) {
danielebarchiesi@4 1718 $r = '';
danielebarchiesi@4 1719 /* result vars */
danielebarchiesi@4 1720 $vars = $this->infos['query']['result_vars'];
danielebarchiesi@4 1721 $nl = "\n";
danielebarchiesi@4 1722 $v_tbls = array('JOIN' => array(), 'LEFT JOIN' => array());
danielebarchiesi@4 1723 $vc = 1;
danielebarchiesi@4 1724 foreach ($vars as $var) {
danielebarchiesi@4 1725 $var_name = $var['var'];
danielebarchiesi@4 1726 $r .= $r ? ',' . $nl . ' ' : ' ';
danielebarchiesi@4 1727 $col = '';
danielebarchiesi@4 1728 $tbl = '';
danielebarchiesi@4 1729 if ($var_name != '*') {
danielebarchiesi@4 1730 if (in_array($var_name, $this->infos['null_vars'])) {
danielebarchiesi@4 1731 if (isset($this->initial_index['vars'][$var_name])) {
danielebarchiesi@4 1732 $col = $this->initial_index['vars'][$var_name][0]['col'];
danielebarchiesi@4 1733 $tbl = $this->initial_index['vars'][$var_name][0]['table'];
danielebarchiesi@4 1734 }
danielebarchiesi@4 1735 if (isset($this->initial_index['graph_vars'][$var_name])) {
danielebarchiesi@4 1736 $col = 'g';
danielebarchiesi@4 1737 $tbl = $this->initial_index['graph_vars'][$var_name][0]['table'];
danielebarchiesi@4 1738 }
danielebarchiesi@4 1739 }
danielebarchiesi@4 1740 elseif (isset($this->index['vars'][$var_name])) {
danielebarchiesi@4 1741 $col = $this->index['vars'][$var_name][0]['col'];
danielebarchiesi@4 1742 $tbl = $this->index['vars'][$var_name][0]['table'];
danielebarchiesi@4 1743 }
danielebarchiesi@4 1744 }
danielebarchiesi@4 1745 if ($var['aggregate']) {
danielebarchiesi@4 1746 $r .= 'TMP.`' . $var['alias'] . '`';
danielebarchiesi@4 1747 }
danielebarchiesi@4 1748 else {
danielebarchiesi@4 1749 $join_type = in_array($tbl, array_merge($this->index['from'], $this->index['join'])) ? 'JOIN' : 'LEFT JOIN';/* val may be NULL */
danielebarchiesi@4 1750 $v_tbls[$join_type][] = array('t_col' => $col, 'q_col' => $var_name, 'vc' => $vc);
danielebarchiesi@4 1751 $r .= 'V' . $vc . '.val AS `' . $var_name . '`';
danielebarchiesi@4 1752 if (in_array($col, array('s', 'o'))) {
danielebarchiesi@4 1753 if (strpos($q_sql, '`' . $var_name . ' type`')) {
danielebarchiesi@4 1754 $r .= ', ' . $nl . ' TMP.`' . $var_name . ' type` AS `' . $var_name . ' type`';
danielebarchiesi@4 1755 //$r .= ', ' . $nl . ' CASE TMP.`' . $var_name . ' type` WHEN 2 THEN "literal" WHEN 1 THEN "bnode" ELSE "uri" END AS `' . $var_name . ' type`';
danielebarchiesi@4 1756 }
danielebarchiesi@4 1757 else {
danielebarchiesi@4 1758 $r .= ', ' . $nl . ' NULL AS `' . $var_name . ' type`';
danielebarchiesi@4 1759 }
danielebarchiesi@4 1760 }
danielebarchiesi@4 1761 $vc++;
danielebarchiesi@4 1762 if ($col == 'o') {
danielebarchiesi@4 1763 $v_tbls[$join_type][] = array('t_col' => 'id', 'q_col' => $var_name . ' lang_dt', 'vc' => $vc);
danielebarchiesi@4 1764 if (strpos($q_sql, '`' . $var_name . ' lang_dt`')) {
danielebarchiesi@4 1765 $r .= ', ' .$nl. ' V' . $vc . '.val AS `' . $var_name . ' lang_dt`';
danielebarchiesi@4 1766 $vc++;
danielebarchiesi@4 1767 }
danielebarchiesi@4 1768 else {
danielebarchiesi@4 1769 $r .= ', ' .$nl. ' NULL AS `' . $var_name . ' lang_dt`';
danielebarchiesi@4 1770 }
danielebarchiesi@4 1771 }
danielebarchiesi@4 1772 }
danielebarchiesi@4 1773 }
danielebarchiesi@4 1774 if (!$r) $r = '*';
danielebarchiesi@4 1775 /* from */
danielebarchiesi@4 1776 $r .= $nl . 'FROM (' . $q_tbl . ' TMP)';
danielebarchiesi@4 1777 foreach (array('JOIN', 'LEFT JOIN') as $join_type) {
danielebarchiesi@4 1778 foreach ($v_tbls[$join_type] as $v_tbl) {
danielebarchiesi@4 1779 $tbl = $this->getValueTable($v_tbl['t_col']);
danielebarchiesi@4 1780 $var_name = preg_replace('/^([^\s]+)(.*)$/', '\\1', $v_tbl['q_col']);
danielebarchiesi@4 1781 $cur_join_type = in_array($var_name, $this->infos['null_vars']) ? 'LEFT JOIN' : $join_type;
danielebarchiesi@4 1782 if (!strpos($q_sql, '`' . $v_tbl['q_col'].'`')) continue;
danielebarchiesi@4 1783 $r .= $nl . ' ' . $cur_join_type . ' ' . $tbl . ' V' . $v_tbl['vc'] . ' ON (
danielebarchiesi@4 1784 (V' . $v_tbl['vc'] . '.id = TMP.`' . $v_tbl['q_col'].'`)
danielebarchiesi@4 1785 )';
danielebarchiesi@4 1786 }
danielebarchiesi@4 1787 }
danielebarchiesi@4 1788 /* create pos columns, id needed */
danielebarchiesi@4 1789 if ($this->v('order_infos', array(), $this->infos['query'])) {
danielebarchiesi@4 1790 $r .= $nl . ' ORDER BY _pos_';
danielebarchiesi@4 1791 }
danielebarchiesi@4 1792 return 'SELECT' . $nl . $r;
danielebarchiesi@4 1793 }
danielebarchiesi@4 1794
danielebarchiesi@4 1795 /* */
danielebarchiesi@4 1796
danielebarchiesi@4 1797 }
danielebarchiesi@4 1798
danielebarchiesi@4 1799