You are here

class ARC_sparql2sql_rewriter in Taxonomy import/export via XML 6

Same name and namespace in other branches
  1. 5.2 arc/ARC_sparql2sql_rewriter.php \ARC_sparql2sql_rewriter
  2. 5 arc/ARC_sparql2sql_rewriter.php \ARC_sparql2sql_rewriter
  3. 6.2 arc/ARC_sparql2sql_rewriter.php \ARC_sparql2sql_rewriter

Hierarchy

Expanded class hierarchy of ARC_sparql2sql_rewriter

1 string reference to 'ARC_sparql2sql_rewriter'
ARC_api::get_sparql2sql_rewriter in arc/ARC_api.php

File

arc/ARC_sparql2sql_rewriter.php, line 54

View source
class ARC_sparql2sql_rewriter {
  var $version = "0.3.5";
  var $logs = array();
  function __construct(&$api) {
    $this->api =& $api;
    $this->config = $this->api
      ->get_config();
  }
  function ARC_sparql2sql_rewriter(&$api) {
    $this
      ->__construct($api);
  }

  /*					*/
  function init($args = "") {

    /* infos, obj_props, dt_props, iri_alts */
    $this->infos = array();
    $this->obj_props = isset($this->config["obj_props"]) ? $this->config["obj_props"] : array();
    $this->dt_props = isset($this->config["dt_props"]) ? $this->config["dt_props"] : array();
    $this->iri_alts = array();
    $this->prop_table_infos = $this->api
      ->get_prop_table_infos();
    foreach (array(
      "infos",
      "objs_props",
      "dt_props",
      "iri_alts",
    ) as $cur_arg) {
      if (isset($args[$cur_arg]) && is_array($args[$cur_arg])) {
        $this->{$cur_arg} = $args[$cur_arg];
      }
    }
  }

  /*					*/
  function get_sql($args = "") {
    $this
      ->init($args);
    $this->term2alias = array();
    $this->optional_term2alias = array();
    $this->val_match_vars = array();
    $this->graphs = array();
    if (isset($this->infos["query_type"])) {
      $mthd = "get_" . $this->infos["query_type"] . "_sql";
      if (method_exists($this, $mthd)) {
        return $this
          ->{$mthd}();
      }
    }
    return $this->api
      ->error("Undefined or unsupported query type '" . $this->infos["query_type"] . "'.");
  }

  /*					*/
  function get_select_sql() {
    $infos = $this->infos;
    if (!$infos["result_vars"]) {
      return array(
        "error" => 'no result variables specified',
      );
    }
    if (isset($this->infos["patterns"])) {
      $this
        ->parse_patterns();

      /* creates where_code, optional_term2alias */
    }
    if (strpos($this->where_code, "__union_")) {
      return $this
        ->get_union_select_sql();
    }
    $left_join_code = $this
      ->get_left_join_code();

    /* detects alias_alternatives */

    /* select */
    $result = "SELECT";

    /* distinct */
    $result .= isset($infos["distinct"]) && $infos["distinct"] ? " DISTINCT" : "";

    /* count rows */
    if (isset($infos["count_rows"]) && $infos["count_rows"]) {
      $result .= " SQL_CALC_FOUND_ROWS";
    }

    /* vars */
    $result .= $this
      ->get_result_vars_code();

    /* from */
    $result .= $this
      ->get_from_code();

    /* left joins */
    $result .= strlen($left_join_code) ? "\n /* left-joins */" . $left_join_code : "";

    /* id2val joins */
    $id2val_join_code = $this
      ->get_id2val_join_code();
    $result .= strlen($id2val_join_code) ? $id2val_join_code : "";

    /* where */
    $result .= "\nWHERE \n ";
    $where_result = "";

    /* dataset restrictions */
    $dataset_code = $this
      ->get_dataset_code();
    $where_result .= strlen($dataset_code) ? "/* dataset restrictions */\n" . $dataset_code . "\n" : "";

    /* graph restrictions */
    $graph_code = $this
      ->get_graph_code();
    if (strlen($graph_code)) {
      $where_result .= strlen($where_result) ? " /* graph restrictions */\n AND \n " . $graph_code : " /* graph restrictions */\n " . $graph_code;
      $where_result .= "\n";
    }

    /* where_code */
    if (strlen($this->where_code)) {
      $where_result .= strlen($where_result) ? " /* triple patterns and filters */\n AND \n " : " /* triple patterns and filters */\n ";
      $where_result .= trim($this->where_code);
    }

    /* equi-joins */
    if ($equi_join_code = $this
      ->get_equi_join_code()) {
      $where_result .= strlen($where_result) ? "\n /* equi-joins */\n AND " . $equi_join_code : "\n /* equi-joins */\n " . $equi_join_code;
    }
    $result .= strlen($where_result) ? $where_result : "1";

    /* order by */
    $result .= $this
      ->get_order_by_code();

    /* limit/offset */
    $result .= $this
      ->get_limit_offset_code();
    return $result;
  }
  function get_union_select_sql() {
    $infos = $this->infos;
    $result = "";
    $where_code = trim($this->where_code);
    while (preg_match("/__union_([0-9]+)__/", $where_code, $matches)) {
      $union_id = $matches[1];
      $branches = $this->union_branches[$union_id];
      for ($i = 0, $i_max = count($branches); $i < $i_max; $i++) {
        $union_branch_id = $union_id . "_" . ($i + 1);
        $left_join_code = $this
          ->get_left_join_code();

        /* detects alias_alternatives */

        /* select */
        $cur_result = "SELECT";

        /* distinct, not on first branch */
        if (strlen($result)) {
          $cur_result .= isset($infos["distinct"]) && $infos["distinct"] ? " DISTINCT" : " ALL";
        }

        /* count rows */
        if (isset($infos["count_rows"]) && $infos["count_rows"]) {
          $result .= " SQL_CALC_FOUND_ROWS";
        }

        /* vars */
        $cur_result .= $this
          ->get_result_vars_code(array(
          "union_branch_id" => $union_branch_id,
        ));

        /* from */
        $cur_result .= $this
          ->get_from_code();

        /* left joins */
        $cur_result .= strlen($left_join_code) ? "\n /* left-joins */" . $left_join_code : "";

        /* id2val joins */
        $id2val_join_code = $this
          ->get_id2val_join_code();
        $cur_result .= strlen($id2val_join_code) ? $id2val_join_code : "";

        /* where */
        $cur_result .= "\nWHERE \n ";

        /* dataset restrictions */
        $dataset_code = $this
          ->get_dataset_code();
        $cur_result .= strlen($dataset_code) ? "/* dataset restrictions */\n" . $dataset_code . "\n" : "";

        /* graph restrictions */
        $graph_code = $this
          ->get_graph_code();
        if (strlen($graph_code)) {
          $cur_result .= " /* graph restrictions */";
          $cur_result .= strlen($dataset_code) ? "\n AND \n " . $graph_code : "\n " . $graph_code;
          $cur_result .= "\n";
        }

        /* where_code */
        $cur_result .= " /* triple patterns and filters */\n ";
        $cur_result .= strlen($graph_code . $dataset_code) ? "AND \n " : "";
        $cur_result .= trim($where_code);

        /* equi-joins */
        $equi_join_code = $this
          ->get_equi_join_code();
        $cur_result .= strlen($equi_join_code) ? "\n /* equi-joins */\n AND " . $equi_join_code : "";

        /* unions */
        $cur_branch = $branches[$i];
        $branch_result = str_replace("__union_" . $union_id . "__", $cur_branch, $cur_result);
        $result .= $i == 0 ? "(" . $branch_result . "\n)" : "\nUNION \n(" . $branch_result . "\n)";
      }
      $where_code = str_replace("__union_" . $union_id . "__", "", $where_code);
    }

    /* order by */
    $result .= $this
      ->get_order_by_code();

    /* limit/offset */
    $result .= $this
      ->get_limit_offset_code();
    return $result;
  }

  /*					*/
  function get_construct_sql() {

    /* uses result_vars mentioned in construct template triples */
    return $this
      ->get_select_sql();
  }

  /*					*/
  function get_describe_sql($infos = "", $limit = 100) {

    /* called by ARC RDF Store once for all vars, then for each result_iri separately */
    if ($infos) {
      $this->infos = $infos;
    }
    if (isset($this->infos["result_vars"]) && count($this->infos["result_vars"])) {
      return $this
        ->get_select_sql();
    }
    elseif ($this->infos["result_iris"]) {
      $iri = $this->infos["result_iris"][0];

      //$q='SELECT ?ref_s ?ref_p ?p ?o WHERE { { ?ref_s  ?ref_p  <'.$iri.'> } UNION { <'.$iri.'> ?p ?o } }';
      $q = 'SELECT DISTINCT ?p ?o WHERE { <' . $iri . '> ?p ?o } ORDER BY ?p';
      $q .= $limit ? ' LIMIT ' . $limit : "";
      $parser = $this->api
        ->get_sparql_parser();
      $parser
        ->parse($q);
      $this->infos = $parser
        ->get_infos();
      return $this
        ->get_select_sql();
    }
    return "";
  }

  /*					*/
  function get_ask_sql() {
    $this->infos["result_vars"] = array(
      "__ask_var__",
    );
    $this->infos["limit"] = 1;
    $sql = $this
      ->get_select_sql();
    $sql = str_replace("SELECT", "SELECT 1 AS `success`", $sql);
    return $sql;
  }

  /*					*/
  function get_best_table_name($alias = "") {
    $store_type = $this->config["store_type"];
    $prefix = $this->config["prefix"];
    $has_prop_tables = isset($this->config["prop_tables"]) && count($this->config["prop_tables"]) ? true : false;
    if ($store_type == "basic") {
      return $prefix . "_triple";
    }
    if (isset($this->alias_prop_infos[$alias])) {
      $a_info = $this->alias_prop_infos[$alias];

      /* graph check */
      if ($a_info["in_graph"]) {
        return $prefix . "_triple_all_wdup";
      }
      if ($store_type == "split") {

        /* try concrete p iri */
        if ($a_info["p_term_type"] == "iri") {
          $p_iri = $a_info["p_term_val"];

          /* check prop_table_infos */
          if (isset($this->prop_table_infos[$p_iri])) {
            return $this->prop_table_infos[$p_iri]["tbl"];
          }

          /* o is literal */
          if ($a_info["o_term_type"] == "literal" || in_array($p_iri, $this->dt_props)) {
            return $prefix . "_triple_dp";
          }

          /* o is iri */
          if ($a_info["o_term_type"] == "iri" || in_array($p_iri, $this->obj_props)) {
            return $prefix . "_triple_op";
          }
        }

        /* o is literal */
        if ($a_info["o_term_type"] == "literal") {
          return $prefix . "_triple_dp_all";
        }

        /* o is iri */
        if ($a_info["o_term_type"] == "iri") {
          return $prefix . "_triple_op_all";
        }

        /* o is obj */
        if ($a_info["o_term_type"] == "var") {
          $o_var_val = $a_info["o_term_val"];
          if (($col_occurs = $this->var_col_occurs[$o_var_val]) && in_array("s", $col_occurs)) {

            /* used to join => obj prop */
            return $has_prop_tables ? $prefix . "_triple_op_all" : $prefix . "_triple_op";
          }
        }
      }
    }
    return $store_type == "split" ? $prefix . "_triple_all" : $prefix . "_triple";
  }

  /*					*/
  function get_result_vars_code($args = "") {
    $result = "";
    $union_branch_id = "";
    if (is_array($args)) {
      foreach ($args as $k => $v) {
        ${$k} = $v;
      }
    }

    /* union_branch_id */
    $vars = $this->infos["result_vars"] ? $this->infos["result_vars"] : array();
    $added_aliases = array();

    /* each id2val join needs a separate alias */
    $conv_id = in_array($this->config["id_type"], array(
      "hash_int",
      "incr_int",
    ));
    foreach ($vars as $cur_var) {
      if (($alias_infos = @$this->term2alias[$cur_var]) || ($alias_infos = @$this->optional_term2alias[$cur_var])) {
        $result .= strlen($result) ? ", \n " : "\n ";
        $null_var = false;

        /* whether var occurs in global pattern or current union_branch */
        $alias_info = $alias_infos[0];
        if ($union_branch_id) {
          $null_var = true;
          foreach ($alias_infos as $cur_alias_info) {

            /* todo: nested unions */
            if (!$cur_alias_info["union_branch_id"] || $cur_alias_info["union_branch_id"] == $union_branch_id) {

              /* global var */
              $null_var = false;
              $alias_info = $cur_alias_info;
              break;
            }
          }
        }
        $alias = $alias_info["alias"];
        $col = $alias_info["col"];
        $term = $alias_info["term"];
        $tbl_alias = "V" . $alias;
        $alias_ext = 2;
        while (in_array($tbl_alias, $added_aliases)) {
          $tbl_alias = "V" . $alias . "_" . $alias_ext;
          $alias_ext++;
        }
        $full_tbl_alias = $tbl_alias . ".val";

        /* alias alternatives (peer optionals handling) */
        if ($alts = @$this->alias_alternatives["T" . $alias . "." . $col]) {
          $sub_result = "IFNULL(" . $tbl_alias . ".val, ";
          $sub_result_2 = "IFNULL(T" . $alias . ".__placeholder__, ";
          for ($i = 0, $i_max = count($alts); $i < $i_max; $i++) {
            $cur_alt = $alts[$i];
            $alt_alias = $cur_alt["alias"];
            $alt_col = $cur_alt["col"];
            $alt_tbl_alias = "V" . $alt_alias;
            $alias_ext = 2;
            while (in_array($alt_tbl_alias, $added_aliases)) {
              $alt_tbl_alias = $cur_alt . "_" . $alias_ext;
              $alias_ext++;
            }
            $sub_result .= $i < $i_max - 1 ? "IFNULL(" . $alt_tbl_alias . ".val" : $alt_tbl_alias . ".val";
            $sub_result_2 .= $i < $i_max - 1 ? "IFNULL(T" . $alt_alias . ".__placeholder__" : "T" . $alt_alias . ".__placeholder__";
          }
          for ($i = 0; $i < $i_max; $i++) {
            $sub_result .= ")";
            $sub_result_2 .= ")";
          }
          $full_tbl_alias = $sub_result;
        }
        $result .= $null_var ? "CONCAT('NULL ', " . $full_tbl_alias . ") AS `" . $cur_var . "`" : $full_tbl_alias . " AS `" . $cur_var . "`";
        $added_aliases[] = $tbl_alias;
        if ($col == "s") {
          if (@$sub_result_2) {
            $result .= ",\n   " . str_replace("__placeholder__", "s_type", $sub_result_2) . " AS `" . $cur_var . "__type`";
          }
          else {
            $result .= ",\n   T" . $alias . ".s_type AS `" . $cur_var . "__type`";
          }
        }
        if ($col == "o") {
          if (@$sub_result_2) {
            $result .= ",\n   " . str_replace("__placeholder__", "o_type", $sub_result_2) . " AS `" . $cur_var . "__type`";
            $result .= ",\n   " . str_replace("__placeholder__", "o_lang", $sub_result_2) . " AS `" . $cur_var . "__lang`";
            if ($conv_id) {
              $result .= ",\n   CONV(" . str_replace("__placeholder__", "o_dt", $sub_result_2) . ", 10, 16) AS `" . $cur_var . "__dt`";
            }
            else {
              $result .= ",\n   " . str_replace("__placeholder__", "o_dt", $sub_result_2) . " AS `" . $cur_var . "__dt`";
            }
          }
          else {
            $result .= ",\n   T" . $alias . ".o_type AS `" . $cur_var . "__type`";
            $result .= ",\n   T" . $alias . ".o_lang AS `" . $cur_var . "__lang`";
            if ($conv_id) {
              $result .= ",\n   CONV(T" . $alias . ".o_dt, 10, 16) AS `" . $cur_var . "__dt`";
            }
            else {
              $result .= ",\n   T" . $alias . ".o_dt AS `" . $cur_var . "__dt`";
            }
          }
        }
      }
      elseif ($alias_infos = @$this->graph_term2alias[$cur_var]) {
        $alias = $alias_infos[0]["alias"];
        $tbl_alias = "V" . $alias . "_g";
        $result .= strlen($result) ? ", \n " : "\n ";
        $result .= $tbl_alias . ".val AS `" . $cur_var . "`";
      }
    }
    return $result;
  }

  /*					*/
  function get_from_code() {
    $result = "";
    $added_aliases = array();

    /* t_count */
    for ($i = 1; $i <= $this->t_count; $i++) {
      if (!in_array($i, $this->optional_t_counts)) {
        $result .= strlen($result) ? ", \n " : "\nFROM (\n ";
        $tbl_alias = "T" . $i;
        $alias_ext = 2;
        while (in_array($tbl_alias, $added_aliases)) {
          $tbl_alias = "T" . $i . "_" . $alias_ext;
          $alias_ext++;
        }
        $cur_tbl_name = $this
          ->get_best_table_name($i);
        $result .= $cur_tbl_name . " " . $tbl_alias;
        $added_aliases[] = $tbl_alias;
      }
    }

    /* union_t_count */
    if ($this->union_count) {
      $min_union_t_count = $this->union_t_counts["base_t_count"] + 1;
      $max_union_t_count = $min_union_t_count;
      foreach ($this->union_t_counts as $union_id => $cur_max_t_count) {
        $max_union_t_count = max($cur_max_t_count, $max_union_t_count);
      }
      for ($i = $min_union_t_count; $i <= $max_union_t_count; $i++) {
        if (!in_array($i, $this->optional_t_counts)) {
          $result .= strlen($result) ? ", \n " : "\nFROM (\n ";
          $tbl_alias = "T" . $i;
          $alias_ext = 2;
          while (in_array($tbl_alias, $added_aliases)) {
            $tbl_alias = "T" . $i . "_" . $alias_ext;
            $alias_ext++;
          }
          $cur_tbl_name = $this
            ->get_best_table_name($i);
          $result .= $cur_tbl_name . " " . $tbl_alias;
          $added_aliases[] = $tbl_alias;
        }
      }
    }
    $result .= strlen($result) ? "\n)" : "";
    return $result;
  }

  /*					*/
  function get_equi_join_code() {
    $result = "";
    $added_joins = array();
    foreach ($this->term2alias as $name => $alias_infos) {
      for ($i = 1, $i_max = count($alias_infos); $i < $i_max; $i++) {
        $cur_alias_info_1 = $alias_infos[$i - 1];
        $cur_alias_1 = $cur_alias_info_1["alias"];
        $cur_col_1 = $cur_alias_info_1["col"];
        $cur_term_1 = $cur_alias_info_1["term"];
        $tbl_alias_1 = "T" . $cur_alias_1 . "." . $cur_col_1;
        $cur_alias_info_2 = $alias_infos[$i];
        $cur_alias_2 = $cur_alias_info_2["alias"];
        $cur_col_2 = $cur_alias_info_2["col"];
        $cur_term_2 = $cur_alias_info_2["term"];
        $tbl_alias_2 = "T" . $cur_alias_2 . "." . $cur_col_2;
        if ($tbl_alias_1 != $tbl_alias_2) {
          if (!in_array($tbl_alias_1 . "=" . $tbl_alias_2, $added_joins) && !in_array($tbl_alias_2 . "=" . $tbl_alias_1, $added_joins)) {
            $result .= strlen($result) ? "\n AND " : "";
            $result .= $tbl_alias_1 . "=" . $tbl_alias_2;
            $added_joins[] = $tbl_alias_1 . "=" . $tbl_alias_2;
          }
        }
      }
    }
    return $result;
  }

  /*					*/
  function get_left_join_code() {
    $result = "";
    $added_aliases = array();
    $optional_sets = array();
    $alias2parent_optional = array();
    foreach ($this->optional_term2alias as $name => $alias_infos) {

      //$result.="\n".$name;
      foreach ($alias_infos as $alias_info) {
        $joined_alias = $alias_info["alias"];

        //$result.="\n".$joined_alias;
        if (!in_array("T" . $joined_alias, $added_aliases)) {
          $joined_col = $alias_info["col"];
          $joined_term = $alias_info["term"];
          $joined_term_val = $joined_term["val"];
          if (($ref_alias_infos = @$this->term2alias[$joined_term_val]) || ($ref_alias_infos = @$this->optional_term2alias[$joined_term_val])) {
            $ref_alias_info = $ref_alias_infos[0];
            $ref_alias = $ref_alias_info["alias"];
            $ref_col = $ref_alias_info["col"];
            $cur_tbl_name = $this
              ->get_best_table_name($joined_alias);
            $result .= "\n LEFT JOIN " . $cur_tbl_name . " T" . $joined_alias . " ON ";
            $result .= "\n  (";
            $result .= "\n   T" . $joined_alias . "." . $joined_col . "=T" . $ref_alias . "." . $ref_col;

            /* alias patterns */
            if ($patterns = $this->optional_patterns["T" . $joined_alias]) {
              foreach ($patterns as $cur_pattern) {
                $result .= "\n   AND\n   " . $cur_pattern;
              }
            }

            /* other terms in current alias pattern */
            $term_infos = $this->alias2term[$joined_alias];
            foreach ($term_infos as $cur_term_info) {
              $cur_term = $cur_term_info["term"];
              $cur_term_type = $cur_term["type"];
              $cur_term_val = $cur_term["val"];
              $cur_col = $cur_term_info["col"];
              if ($cur_col != $joined_col) {

                //$result.="\nother: ".$cur_term_val." (".$cur_col.")";
                $other_alias_infos = false;

                /* check if term is used in non-optional patterns */
                if ($other_alias_infos = @$this->term2alias[$cur_term_val]) {
                }
                elseif ($pre_other_alias_infos = @$this->optional_term2alias[$cur_term_val]) {
                  $other_alias_infos = array();
                  foreach ($pre_other_alias_infos as $cur_other_alias_info) {
                    if ($cur_other_alias_info["alias"] < $joined_alias) {
                      $other_alias_infos[] = $cur_other_alias_info;
                    }
                  }
                }
                if ($other_alias_infos) {
                  foreach ($other_alias_infos as $cur_other_alias_info) {
                    $other_alias = $cur_other_alias_info["alias"];
                    $other_col = $cur_other_alias_info["col"];
                    $other_tbl_alias = "T" . $other_alias . "." . $other_col;
                    $result .= "\n   AND (";
                    $result .= "T" . $joined_alias . "." . $cur_col . "=" . $other_tbl_alias;

                    /* find out if other_col is in different optional */
                    if ($cur_other_alias_info["optional_count"] && $cur_other_alias_info["optional_count"] != $alias_info["optional_count"]) {
                      $result .= " OR " . $other_tbl_alias . " IS NULL";
                      if (!isset($this->alias_alternatives[$other_tbl_alias])) {
                        $this->alias_alternatives[$other_tbl_alias] = array();
                      }
                      $this->alias_alternatives[$other_tbl_alias][] = array(
                        "alias" => $joined_alias,
                        "col" => $cur_col,
                      );
                    }
                    $result .= ")";
                  }
                }
              }
            }

            /* dataset restrictions */
            if ($dataset_code = $this
              ->get_dataset_code(true, $joined_alias)) {
              $result .= "\n   AND\n   " . $dataset_code;
            }
            $result .= "\n  )";
            $added_aliases[] = "T" . $joined_alias;
          }

          /* optional groups */
          if (!array_key_exists($alias_info["optional_count"], $optional_sets)) {
            $optional_sets[$alias_info["optional_count"]] = array(
              "T" . $joined_alias . "." . $joined_col,
            );
            if ($parent_optional_count = $alias_info["parent_optional_count"]) {
              $alias2parent_optional["T" . $joined_alias . "." . $joined_col] = $parent_optional_count;
            }
          }
          else {
            $optional_sets[$alias_info["optional_count"]][] = "T" . $joined_alias . "." . $joined_col;
          }
        }
      }
    }

    /* optional sets */
    $sub_result = "";
    foreach ($optional_sets as $k => $cur_set) {
      $null_set = $cur_set;
      $not_null_set = $cur_set;
      $set_entry = $cur_set[0];
      while ($parent_set_id = @$alias2parent_optional[$set_entry]) {

        /* nested optional, only NOT NULL if all parent patterns are NOT NULL as well */
        $parent_set = $optional_sets[$parent_set_id];
        $set_entry = $parent_set[0];
        foreach ($parent_set as $cur_alias) {
          if (!in_array($cur_alias, $not_null_set)) {
            $not_null_set[] = $cur_alias;
          }
        }
      }
      if (count($not_null_set) > 1) {

        /* not null */
        $not_null_code = "";
        foreach ($not_null_set as $cur_alias) {
          $not_null_code .= strlen($not_null_code) ? " AND " : "";
          $not_null_code .= $cur_alias . " IS NOT NULL";
        }

        /* null */
        $null_code = "";
        foreach ($null_set as $cur_alias) {
          $null_code .= strlen($null_code) ? " AND " : "";
          $null_code .= $cur_alias . " IS NULL";
        }
        $sub_result .= strlen($sub_result) ? " AND " : "";
        $sub_result .= "((" . $not_null_code . ") OR (" . $null_code . "))";
        $sub_result .= "\n";
      }
    }
    if ($sub_result) {
      $this->where_code .= strlen($this->where_code) ? "\n AND " : "\n";
      $this->where_code .= $sub_result;
    }
    return $result;
  }

  /*					*/
  function get_id2val_join_code() {
    $result = "\n /* id2val joins */";
    $vars = $this->infos["result_vars"] ? $this->infos["result_vars"] : array();

    /* add regex'd vars */
    foreach ($this->val_match_vars as $cur_var) {
      if (!in_array($cur_var, $vars)) {
        $vars[] = $cur_var;
      }
    }
    $added_aliases = array();

    /* each id2val join needs a separate alias */
    $tbl_name = $this->config["prefix"] . "_id2val";
    $var2tbl_alias = array();
    foreach ($vars as $cur_var) {
      $tbl_alias = "";
      if (($alias_infos = @$this->term2alias[$cur_var]) || ($alias_infos = @$this->optional_term2alias[$cur_var])) {
        $alias_info = $alias_infos[0];
        $alias = $alias_info["alias"];
        $col = $alias_info["col"];
        $term = $alias_info["term"];
        $tbl_alias = "V" . $alias;
        $alias_ext = 2;
        while (in_array($tbl_alias, $added_aliases)) {
          $tbl_alias = "V" . $alias . "_" . $alias_ext;
          $alias_ext++;
        }
        $result .= "\n LEFT JOIN " . $tbl_name . " " . $tbl_alias . " ON (";
        $result .= "" . $tbl_alias . ".id=T" . $alias . "." . $col;
        $result .= ")";
        $added_aliases[] = $tbl_alias;

        /* alias alternatives */
        if ($alias_info["optional_count"]) {
          foreach ($alias_infos as $cur_alias_info) {
            $cur_tbl_alias = "T" . $cur_alias_info["alias"] . "." . $cur_alias_info["col"];
            if ($alts = @$this->alias_alternatives[$cur_tbl_alias]) {
              foreach ($alts as $cur_alt) {
                $alt_alias = $cur_alt["alias"];
                $alt_col = $cur_alt["col"];
                $alt_tbl_alias = "V" . $alt_alias;
                $alias_ext = 2;
                while (in_array($alt_tbl_alias, $added_aliases)) {
                  $alt_tbl_alias = $cur_alt . "_" . $alias_ext;
                  $alias_ext++;
                }
                $result .= "\n LEFT JOIN " . $tbl_name . " " . $alt_tbl_alias . " ON (";
                $result .= "" . $alt_tbl_alias . ".id=T" . $alt_alias . "." . $alt_col;
                $result .= ")";
              }
            }
          }
        }
      }
      elseif ($alias_infos = @$this->graph_term2alias[$cur_var]) {
        $alias = $alias_infos[0]["alias"];
        $tbl_alias = "V" . $alias . "_g";
        $result .= "\n LEFT JOIN " . $tbl_name . " " . $tbl_alias . " ON (";
        $result .= "" . $tbl_alias . ".id=T" . $alias . ".g";
        $result .= ")";
      }
      if ($tbl_alias) {
        $var2tbl_alias[$cur_var] = $tbl_alias;
      }
    }

    /* regex'd vars */
    foreach ($this->val_match_vars as $cur_var) {
      $this->where_code = str_replace("V__regex_match_" . $cur_var . "__", $var2tbl_alias[$cur_var], $this->where_code);
    }
    return $result;
  }

  /*					*/
  function get_order_by_code() {
    $result = "";
    if ($conds = @$this->infos["order_conditions"]) {
      foreach ($conds as $cur_cond) {
        $cur_cond_type = $cur_cond["type"];
        $mthd = "get_" . $cur_cond_type . "_order_by_code";
        if (method_exists($this, $mthd)) {
          if ($sub_result = $this
            ->{$mthd}($cur_cond)) {
            $result .= strlen($result) ? ",\n " : "\n ";
            $result .= $sub_result;
          }
        }
      }
    }
    return trim($result) ? "\nORDER BY " . $result : "";
  }
  function get_var_order_by_code($cond = "") {
    $result = "";
    $var = $cond["val"];
    if (($alias_infos = @$this->term2alias[$var]) || ($alias_infos = @$this->optional_term2alias[$var])) {
      $alias_info = $alias_infos[0];
      $alias = $alias_info["alias"];
      $col = $alias_info["col"];
      $term = $alias_info["term"];
      $tbl_alias = "T" . $alias;
      if ($col != "o" && in_array($var, $this->infos["result_vars"])) {
        $result .= rawurlencode($var);
      }
      elseif ($col == "o") {

        /* todo type casting if var is numeric */
        $result .= $tbl_alias . ".o_comp";
      }
      else {

        /* todo: sort by val, not by id */
        $result .= $tbl_alias . "." . $col;
      }
    }
    elseif ($alias_infos = @$this->graph_term2alias[$var]) {
      $alias = $alias_infos[0]["alias"];
      $tbl_alias = "V" . $alias . "_g";

      //$result.=strlen($result) ? ", \n " : "\n ";
      $result .= $tbl_alias . ".val";
    }
    return $result;
  }
  function get_expression_order_by_code($cond = "") {
    $result = "";
    $expr = $cond["expression"];
    $expr_type = $expr["type"];
    $mthd = "get_" . $expr_type . "_order_by_code";
    if (method_exists($this, $mthd)) {
      $result .= $this
        ->{$mthd}($expr);
    }
    if ($result && ($dir = $cond["direction"])) {
      $result .= " " . rawurlencode(strtoupper($dir));
    }
    return $result;
  }

  /*					*/
  function get_limit_offset_code() {
    $result = "";
    $offset = @$this->infos["offset"] ? $this->infos["offset"] : 0;
    $limit = @$this->infos["limit"] ? $this->infos["limit"] : 0;
    if ($limit) {
      $result = "\nLIMIT " . rawurlencode($offset) . "," . rawurlencode($limit);
    }
    elseif ($offset) {
      $result = "\nOFFSET " . rawurlencode($offset);
    }
    return $result;
  }

  /*					*/
  function get_graph_code() {
    $result = "";
    $added_joins = array();
    foreach ($this->graphs as $alias => $graph) {
      $graph_type = $graph["type"];
      $graph_val = $graph["val"];
      if ($graph_type == "iri") {
        $result .= strlen($result) ? "\n AND " : "";
        $result .= "T" . $alias . ".g=" . $this->api
          ->get_id($graph_val, 1);
        $result .= " /* " . str_replace("*", "", str_replace("#", "::", htmlspecialchars($graph_val))) . " */ ";
      }
      elseif ($graph_type == "var") {

        /* graph joins */
        $alias_infos = $this->graph_term2alias[$graph_val];
        $alias_1 = $alias_infos[0]["alias"];
        for ($i = 1, $i_max = count($alias_infos); $i < $i_max; $i++) {
          $cur_alias_info = $alias_infos[$i];
          $cur_alias = $cur_alias_info["alias"];
          $cur_join = "T" . $alias_1 . ".g=T" . $cur_alias . ".g";
          if ($alias_1 != $cur_alias && !in_array($cur_join, $added_joins)) {
            $result .= strlen($result) ? "\n AND " : "";
            $result .= $cur_join;
            $added_joins[] = $cur_join;
          }
        }

        /* graph occurences in triple patterns */
        if ($alias_infos = @$this->term2alias[$graph_val]) {
          $alias_info = $alias_infos[0];
          $alias = $alias_info["alias"];
          $col = $alias_info["col"];
          $cur_join = "T" . $alias_1 . ".g=T" . $alias . "." . $col;
          if ($alias_1 != $alias && !in_array($cur_join, $added_joins)) {
            $result .= strlen($result) ? "\n AND " : "";
            $result .= $cur_join;
            $added_joins[] = $cur_join;
          }
        }
      }
    }
    return $result;
  }
  function get_dataset_code($for_optionals = false, $exact_alias = false) {
    $result = "";
    $added_aliases = array();
    $sets = $this->infos["datasets"];
    $n_sets = $this->infos["named_datasets"];
    if (!count($sets) && !count($n_sets)) {
      return $result;
    }

    /* non-graph'd patterns */
    foreach ($this->non_graph_aliases as $cur_alias) {
      $sub_result = "";
      if (!$exact_alias || $exact_alias == $cur_alias) {
        if (!$for_optionals && !in_array($cur_alias, $this->optional_t_counts) || $for_optionals && in_array($cur_alias, $this->optional_t_counts)) {

          /* datasets */
          foreach ($sets as $cur_set) {
            $sub_result .= strlen($sub_result) ? "\n  OR " : " ";
            $sub_result .= "T" . $cur_alias . ".g=" . $this->api
              ->get_id($cur_set, 1);
            $sub_result .= " /* " . str_replace("*", "", str_replace("#", "::", htmlspecialchars($cur_set))) . " */ ";
          }
        }
      }
      if ($sub_result) {
        $result .= strlen($result) ? "\n AND " : " ";
        $result .= "(" . $sub_result . ")";
      }
    }

    /* graph'd patterns */
    foreach ($this->graphs as $cur_alias => $graph) {
      $graph_type = $graph["type"];
      $graph_val = $graph["val"];
      if (!$exact_alias || $exact_alias == $cur_alias) {
        if ($graph_type == "var" && (!$for_optionals && !in_array($cur_alias, $this->optional_t_counts)) || $for_optionals && in_array($cur_alias, $this->optional_t_counts)) {
          $sub_result = "";

          /* named datasets, if set */
          if (($my_sets = $n_sets) || ($my_sets = $sets)) {
            foreach ($my_sets as $cur_set) {
              $sub_result .= strlen($sub_result) ? "\n  OR " : " ";
              $sub_result .= "T" . $cur_alias . ".g=" . $this->api
                ->get_id($cur_set, 1);
              $sub_result .= " /* " . str_replace("*", "", str_replace("#", "::", htmlspecialchars($cur_set))) . " */ ";
            }
          }
          if ($sub_result) {
            $result .= strlen($result) ? "\n AND " : " ";
            $result .= "(" . $sub_result . ")";
          }
        }
      }
    }
    return $result;
  }

  /*					*/
  function parse_patterns() {
    $infos = $this->infos;
    $where_code = "";
    $this->t_count = 0;
    $this->optional_count = 0;
    $this->union_count = 0;

    /* abs union count */
    $this->term2alias = array();
    $this->alias2term = array();
    $this->optional_term2alias = array();
    $this->optional_t_counts = array();
    $this->optional_patterns = array();
    $this->union_t_counts = array();

    /* individual t_counts for each union branch */
    $this->union_branches = array();
    $this->graphs = array();
    $this->graph_term2alias = array();
    $this->non_graph_aliases = array();
    $this->alias_alternatives = array();

    /* for peer optionals with common terms */
    $this->val_match_vars = array();

    /* for REGEX matching */
    $this->alias_prop_infos = array();
    $this->var_col_occurs = array();

    /* col positions (s,p,o) a var is used (needed to detect obj_props for table splitting) */
    $ind = " ";
    $cur_args = array(
      "ind" => $ind,
      "in_optional" => false,
      "optional_count" => 0,
      "parent_optional_count" => 0,
      "in_union" => false,
      "union_count" => 0,
      "union_branch_id" => "",
      "in_graph" => false,
      "graph" => array(),
      "pattern" => "",
    );
    $nl = "\n";
    $ind = $cur_args["ind"];
    $ni = $nl . $ind;
    foreach ($infos["patterns"] as $cur_pattern) {
      $cur_args["pattern"] = $cur_pattern;
      $sub_r = $this
        ->parse_pattern($cur_args);
      if (trim($sub_r)) {
        $where_code .= strlen($where_code) ? $ni . "AND" . $ni . "(" . $nl . " " . str_replace("\n", "\n ", $sub_r) . $ni . ")" : $sub_r;
      }
    }
    $this->where_code = $where_code;
  }

  /*					*/
  function parse_pattern($args = "") {
    $r = "";
    if (is_array($args) && isset($args["pattern"]) && ($pattern = $args["pattern"])) {
      $nl = "\n";
      $ind = $args["ind"];
      $ni = $nl . $ind;
      $cur_type = isset($pattern["type"]) ? $pattern["type"] : "";
      if ($cur_type) {
        $mthd = "parse_" . $cur_type . "_pattern";
        if (method_exists($this, $mthd)) {
          $r .= $this
            ->{$mthd}($args);
        }
      }
      elseif (count($pattern)) {

        /* has sub-patterns */
        foreach ($pattern as $sub_pattern) {
          $args["pattern"] = $sub_pattern;
          $sub_r = $this
            ->parse_pattern($args);
          if (trim($sub_r)) {
            $r .= strlen($r) ? $ni . "AND" . $ni . "(" . $nl . " " . str_replace("\n", "\n ", $sub_r) . $ni . ")" : $sub_r;
          }
        }
      }
    }
    return $r;
  }

  /*					*/
  function parse_group_pattern($args = "") {
    $r = "";
    $pattern = $args["pattern"];
    if (isset($pattern["entries"]) && ($entries = $pattern["entries"])) {
      $nl = "\n";
      $ind = $args["ind"];
      $ni = $nl . $ind;
      $args["ind"] .= " ";
      foreach ($entries as $cur_pattern) {
        $args["pattern"] = $cur_pattern;
        $sub_r = $this
          ->parse_pattern($args);
        if (trim($sub_r)) {
          $r .= strlen($r) ? $ni . "AND" . $ni . "(" . $nl . " " . str_replace("\n", "\n ", $sub_r) . $ni . ")" : $sub_r;
        }
      }
    }
    return $r ? $ind . "(\n" . $r . $ni . ")" : "";
  }

  /*					*/
  function parse_graph_pattern($args = "") {
    $pattern = $args["pattern"];
    $args["in_graph"] = true;
    $args["graph"] = $pattern["graph"];
    $sub_pattern = $pattern["pattern"];
    $args["pattern"] = $sub_pattern;
    $args["ind"] .= " ";
    return $this
      ->parse_pattern($args);
  }

  /*					*/
  function parse_triples_pattern($args = "") {
    $result = "";
    $pattern = $args["pattern"];
    if (is_array($args)) {
      foreach ($args as $k => $v) {
        ${$k} = $v;
      }
    }
    if ($triples = $pattern["triples"]) {
      foreach ($triples as $cur_t) {
        if (!$in_union) {
          $this->t_count++;
          $cur_t_count = $this->t_count;
        }
        else {
          $this->union_t_counts[$union_branch_id]++;
          $cur_t_count = $this->union_t_counts[$union_branch_id];
        }
        $tbl_alias = "T" . $cur_t_count;
        if ($in_optional && !in_array($cur_t_count, $this->optional_t_counts)) {
          $this->optional_t_counts[] = $cur_t_count;
          $this->logs[] = "adding " . $cur_t_count . " to optional_t_counts";
        }
        if ($in_graph) {
          $this->graphs[$cur_t_count] = $graph;
          if ($graph["type"] == "var") {
            $graph_val = $graph["val"];
            if (!isset($this->graph_term2alias[$graph_val])) {
              $this->graph_term2alias[$graph_val] = array();
            }
            $this->graph_term2alias[$graph_val][] = array(
              "alias" => $cur_t_count,
              "col" => "g",
            );
          }
        }
        elseif (!in_array($cur_t_count, $this->non_graph_aliases)) {
          $this->non_graph_aliases[] = $cur_t_count;
        }
        $this->alias_prop_infos[$cur_t_count] = array(
          "in_graph" => $in_graph,
        );
        foreach (array(
          "s",
          "p",
          "o",
        ) as $cur_col) {
          $cur_term = $cur_t[$cur_col];
          $cur_term_type = $cur_term["type"];
          $cur_term_val = $cur_term["val"];
          $cur_term_lang = isset($cur_term["lang"]) ? $cur_term["lang"] : "";
          $cur_term_dt = isset($cur_term["dt"]) ? $cur_term["dt"] : "";
          $sub_result = "";
          if ($cur_col == "p") {
            $this->alias_prop_infos[$cur_t_count]["p_term_type"] = $cur_term_type;
            $this->alias_prop_infos[$cur_t_count]["p_term_val"] = $cur_term_val;
          }
          if ($cur_col == "o") {
            $this->alias_prop_infos[$cur_t_count]["o_term_type"] = $cur_term_type;
            $this->alias_prop_infos[$cur_t_count]["o_term_val"] = $cur_term_val;
          }
          if ($cur_term_type == "iri") {
            $sub_result .= "(\n" . $ind;
            $sub_result .= " " . $tbl_alias . "." . $cur_col . "=" . $this->api
              ->get_id($cur_term_val, 1);
            $sub_result .= " /* " . str_replace("*", "", str_replace("#", "::", htmlspecialchars($cur_term_val))) . " */ ";

            /* iri alternatives expansion */
            if (isset($this->iri_alts) && isset($this->iri_alts[$cur_term_val]) && ($iri_alts = $this->iri_alts[$cur_term_val])) {
              foreach ($iri_alts as $cur_iri_alt) {
                $sub_result .= "\n" . $ind . "OR ";
                $sub_result .= $tbl_alias . "." . $cur_col . "=" . $this->api
                  ->get_id($cur_iri_alt, 1);
                $sub_result .= " /* " . str_replace("*", "", str_replace("#", "::", htmlspecialchars($cur_iri_alt))) . " */ ";
              }
            }
            $sub_result .= "\n" . $ind . ")";
          }
          elseif ($cur_term_type == "literal") {
            $sub_result .= "(\n" . $ind;
            $sub_result .= " " . $tbl_alias . "." . $cur_col . "=" . $this->api
              ->get_id($cur_term_val, 1);
            $sub_result .= " /* " . str_replace("*", "", str_replace("#", "::", htmlspecialchars($cur_term_val))) . " */ ";
            if ($cur_col == "o") {
              if ($cur_term_lang) {
                $sub_result .= "\n" . $ind . " AND ";
                $sub_result .= $tbl_alias . ".o_lang='" . rawurlencode($cur_term_lang) . "'";
              }
              elseif ($cur_term_dt) {
                $sub_result .= "\n" . $ind . " AND ";
                $sub_result .= $tbl_alias . ".o_dt=" . $this->api
                  ->get_id($cur_term_dt, 1);
                $sub_result .= " /* " . str_replace("*", "", str_replace("#", "::", htmlspecialchars($cur_term_dt))) . " */ ";
              }
            }
            $sub_result .= "\n" . $ind . ")";
          }
          else {
            if ($cur_term_type == "bnode") {

              //$cur_term_val=str_replace(":", "_", $cur_term_val);
            }

            /* term2alias/optional_term2alias */
            $term2alias_array = $in_optional ? "optional_term2alias" : "term2alias";
            $term2alias_array_obj = $this->{$term2alias_array};
            if (!isset($term2alias_array_obj[$cur_term_val])) {
              eval('$this->' . $term2alias_array . '[$cur_term_val]=array();');
            }
            eval('$this->' . $term2alias_array . '[$cur_term_val][]=array("alias"=>$cur_t_count, "col"=>$cur_col, "term"=>$cur_term, "optional_count"=>$optional_count, "parent_optional_count"=>$parent_optional_count, "union_branch_id"=>$union_branch_id, "in_graph"=>$in_graph, "graph"=>$graph);');

            /* alias2term */
            if (!isset($this->alias2term[$cur_t_count])) {
              $this->alias2term[$cur_t_count] = array();
            }
            $this->alias2term[$cur_t_count][] = array(
              "term" => $cur_term,
              "col" => $cur_col,
            );

            /* col occurrence */
            if (!isset($this->var_col_occurs[$cur_term_val])) {
              $this->var_col_occurs[$cur_term_val] = array();
            }
            $this->var_col_occurs[$cur_term_val][] = $cur_col;
          }
          if ($sub_result) {
            if ($in_optional) {
              if (!isset($this->optional_patterns[$tbl_alias])) {
                $this->optional_patterns[$tbl_alias] = array();
              }
              $this->optional_patterns[$tbl_alias][] = $sub_result;
              $this->logs[] = "adding " . $sub_result . " to optional_patterns[" . $tbl_alias . "]";
            }
            else {
              $result .= strlen($result) ? "\n" . $ind . "AND\n" . $ind : "" . $ind;
              $result .= $sub_result;
            }
          }
        }
      }
    }
    return $result;
  }

  /*					*/
  function parse_optional_pattern($args = "") {
    $pattern = $args["pattern"];
    $args["in_optional"] = true;
    $args["parent_optional_count"] = $args["optional_count"];
    $this->optional_count++;
    $args["optional_count"] = $this->optional_count;
    $sub_pattern = $pattern["pattern"];
    $args["pattern"] = $sub_pattern;
    $args["ind"] .= " ";
    return $this
      ->parse_pattern($args);
  }

  /*					*/
  function parse_union_pattern($args = "") {
    $result = "";
    $union_count = 0;
    if (is_array($args)) {
      foreach ($args as $k => $v) {
        ${$k} = $v;
      }
    }
    if ($entries = $pattern["entries"]) {
      $this->union_count++;
      $base_t_count = 100 + $this->t_count;
      if (!array_key_exists("base_t_count", $this->union_t_counts)) {
        $this->union_t_counts["base_t_count"] = $base_t_count;
      }
      $pos = 0;
      $this->union_branches[$this->union_count] = array();
      foreach ($entries as $cur_pattern) {
        $cur_type = $cur_pattern["type"];
        if (!$cur_type) {
          $cur_pattern = $cur_pattern[0];
          $cur_type = $cur_pattern["type"];
        }
        $pos++;
        $union_branch_id = $this->union_count . "_" . $pos;
        $this->union_t_counts[$union_branch_id] = $base_t_count;
        $cur_args = array(
          "ind" => $ind . " ",
          "in_optional" => $in_optional,
          "optional_count" => $optional_count,
          "parent_optional_count" => $parent_optional_count,
          "in_union" => true,
          "union_count" => $this->union_count,
          "union_branch_id" => $union_branch_id,
          "pattern" => $cur_pattern,
        );
        $mthd = "parse_" . $cur_type . "_pattern";
        if (method_exists($this, $mthd)) {
          if ($sub_code = $this
            ->{$mthd}($cur_args)) {
            $this->union_branches[$this->union_count][] = $sub_code;
            $result .= strlen($result) ? "" : "__union_" . $this->union_count . "__";

            //$result.=(strlen($result)) ? "\n".$ind."OR\n".$ind."(\n ".str_replace("\n", "\n ", $sub_code)."\n".$ind.")" : $sub_code;
          }
        }
      }
    }
    return strlen($result) ? $ind . "(\n" . $result . "\n" . $ind . ")" : "";
  }

  /*					*/
  function parse_filter_pattern($args) {
    $r = "";
    $pattern = $args["pattern"];
    $sub_type = isset($pattern["sub_type"]) ? $pattern["sub_type"] : "";
    if ($sub_type) {
      $args["ind"] .= " ";
      $mthd = "parse_" . $sub_type . "_filter_pattern";
      if (method_exists($this, $mthd)) {
        $sub_r = $this
          ->{$mthd}($args);
        if (trim($sub_r)) {
          $r .= $sub_r;
        }
      }
    }
    return $r;
  }
  function parse_expression_filter_pattern($args) {
    $r = "";
    if (is_array($args)) {
      foreach ($args as $k => $v) {
        ${$k} = $v;
      }
    }

    /* for now: some hard-coded expressions only */
    if (isset($pattern["expression"])) {
      $expr = $pattern["expression"];
      if (!isset($expr["type"])) {
        if (isset($expr["expressions"])) {
          $args["pattern"] = $expr;
          return $this
            ->parse_expression_filter_pattern($args);
        }
      }
      else {

        /* built_in_call */
        if ($expr["type"] == "built_in_call") {
          $sub_r = $this
            ->parse_built_in_call_filter_pattern(array(
            "pattern" => $expr,
          ));
          if (trim($sub_r)) {
            $r .= $sub_r;
          }
        }
      }
    }
    elseif (isset($pattern["expressions"]) && ($exprs = $pattern["expressions"])) {

      /* ?var <|> numeric|literal|?var */
      if (count($exprs) == 2 && @$exprs[0]["type"] == "var" && ($var_val = @$exprs[0]["val"]) && ($expr_2_type = $exprs[1]["type"]) && in_array($expr_2_type, array(
        "numeric",
        "literal",
        "var",
      )) && ($val_2 = $exprs[1]["val"]) && ($operator = $exprs[1]["operator"]) && in_array($operator, array(
        "<",
        ">",
        "<=",
        ">=",
        "=",
        "!=",
      ))) {

        /* var */
        if (($alias_infos = @$this->term2alias[$var_val]) || ($alias_infos = @$this->optional_term2alias[$var_val]) || ($alias_infos = @$this->graph_term2alias[$var_val])) {
          $alias_info = $alias_infos[0];
          $alias = $alias_info["alias"];
          $col = $alias_info["col"];
          $tbl_code = $col == "o" && !in_array($operator, array(
            "=",
            "!=",
          )) ? "T" . $alias . ".o_comp" : ($col == "g" ? "T" . $alias . ".g" : "V" . $alias . "." . $col);
          if ($operator == "!=") {
            $r .= " NOT (";
          }
          $r .= in_array($expr_2_type, array(
            "numeric",
            "literal",
          )) && is_numeric($val_2) ? "CAST(" . $tbl_code . " AS SIGNED) +0.00" : $tbl_code;

          /* operator */
          $r .= $operator != "!=" ? " " . $operator . " " : " = ";

          /* literal */
          if (in_array($expr_2_type, array(
            "numeric",
            "literal",
          ))) {
            if (is_numeric($val_2)) {
              $r .= ($modifier = $exprs[1]["modifier"]) && $modifier == "-" ? $modifier : "";
              $r .= $val_2;
            }
            elseif (isset($exprs[1]["delim_code"]) && ($delim_code = $exprs[1]["delim_code"])) {
              $delim_code_char = $delim_code[0];
              $r .= $delim_code_char . str_replace($delim_code_char, "", $val_2) . $delim_code_char;
            }
          }
          if (in_array($expr_2_type, array(
            "var",
          ))) {
            if (($ais = @$this->term2alias[$val_2]) || ($ais = @$this->optional_term2alias[$val_2]) || ($ais = @$this->graph_term2alias[$val_2])) {
              $ai = $ais[0];
              $a = $ai["alias"];
              $col = $ai["col"];
              $r .= $col == "o" && !in_array($operator, array(
                "=",
                "!=",
              )) ? "T" . $a . ".o_comp" : ($col == "g" ? "T" . $a . ".g" : "V" . $a . "." . $col);
            }
            else {
              $r = "";
            }
          }
          $r .= $r && $operator == "!=" ? ")" : "";
        }
      }

      /* LANG(?var)="en" */
      if (count($exprs) == 2 && isset($exprs[0]["type"]) && isset($exprs[1]["type"]) && $exprs[0]["type"] == "built_in_call" && $exprs[0]["call"] == "lang" && isset($exprs[0]["expression"]) && isset($exprs[0]["expression"]["type"]) && $exprs[0]["expression"]["type"] == "var" && ($var_val = $exprs[0]["expression"]["val"]) && $exprs[1]["type"] == "literal" && ($lang_val = $exprs[1]["val"]) && ($operator = $exprs[1]["operator"]) && in_array($operator, array(
        "=",
        "!=",
      ))) {

        /* var */
        if (($alias_infos = @$this->term2alias[$var_val]) || ($alias_infos = @$this->optional_term2alias[$var_val]) || ($alias_infos = @$this->graph_term2alias[$var_val])) {
          $alias_info = $alias_infos[0];
          $alias = $alias_info["alias"];
          $tbl_code = "T" . $alias . ".o_lang";
          $r .= $tbl_code;

          /* operator */
          $r .= " " . $operator . " ";

          /* lang */
          if ($delim_code = $exprs[1]["delim_code"]) {
            $delim_code_char = $delim_code[0];
            $r .= $delim_code_char . rawurlencode(str_replace($delim_code_char, "", $lang_val)) . $delim_code_char;
          }
        }
      }
      if (trim($r)) {
        if (!$in_optional) {
          return $ind . $r;
        }
        else {

          /* add to optional patterns for left joins */
          if (($alias_infos = @$this->term2alias[$var_val]) || ($alias_infos = @$this->optional_term2alias[$var_val])) {
            $alias_info = $alias_infos[0];
            $alias = $alias_info["alias"];
            $tbl_alias = "T" . $alias;
            if (!isset($this->optional_patterns[$tbl_alias])) {
              $this->optional_patterns[$tbl_alias] = array();
            }
            $this->optional_patterns[$tbl_alias][] = "(\n" . $ind . $r . "\n" . substr($ind, 0, -1) . ")";
          }
        }
      }
    }

    /* result */
    return trim($r);
  }

  /*					*/
  function parse_built_in_call_filter_pattern($args = "") {
    $result = "";
    $call = "";
    if (is_array($args)) {
      foreach ($args as $k => $v) {
        ${$k} = $v;
      }
    }
    if (is_array($pattern["call"])) {
      $pattern = $pattern["call"];
    }
    if (is_array($pattern)) {
      foreach ($pattern as $k => $v) {
        ${$k} = $v;
      }
    }

    /* bound */
    if ($call == "bound" && $var) {
      if ($alias_infos = @$this->optional_term2alias[$var]) {
        $alias_info = $alias_infos[0];
        $alias = $alias_info["alias"];
        $col = $alias_info["col"];
        $result .= $modifier == "!" ? "T" . $alias . "." . $col . " IS NULL" : "T" . $alias . "." . $col . " IS NOT NULL";
      }
    }

    /* isIRI/isURI */
    if (in_array($call, array(
      "isiri",
      "isuri",
    )) && ($expr = $expression) && $expr["type"] == "var" && ($var_val = $expr["val"])) {
      if (($alias_infos = @$this->term2alias[$var_val]) || ($alias_infos = @$this->optional_term2alias[$var_val])) {
        $alias_info = $alias_infos[0];
        $alias = $alias_info["alias"];
        $col = $alias_info["col"];
        if ($col == "p") {

          /* p is always an IRI */
          if ($alias_info["optional_count"]) {
            $result .= $expr["modifier"] == "!" ? "(T" . $alias . "." . $col . " IS NULL OR 0)" : "";
          }
          else {
            $result .= $expr["modifier"] == "!" ? "0" : "";
          }
        }
        else {
          if ($alias_info["optional_count"]) {
            $result .= $expr["modifier"] == "!" ? "(T" . $alias . "." . $col . " IS NULL OR NOT (T" . $alias . "." . $col . "_type=0))" : "(T" . $alias . "." . $col . " IS NULL OR T" . $alias . "." . $col . "_type=0)";
          }
          else {
            $result .= $expr["modifier"] == "!" ? " NOT (T" . $alias . "." . $col . "_type=0)" : " T" . $alias . "." . $col . "_type=0";
          }
        }
      }
    }

    /* isBlank */
    if (in_array($call, array(
      "isblank",
    )) && ($expr = $expression) && $expr["type"] == "var" && ($var_val = $expr["val"])) {
      if (($alias_infos = @$this->term2alias[$var_val]) || ($alias_infos = @$this->optional_term2alias[$var_val])) {
        $alias_info = $alias_infos[0];
        $alias = $alias_info["alias"];
        $col = $alias_info["col"];
        if ($col == "p") {

          /* p is never a bnode */
          if ($alias_info["optional_count"]) {
            $result .= $expr["modifier"] == "!" ? "" : "(T" . $alias . "." . $col . " IS NULL OR 0)";
          }
          else {
            $result .= $expr["modifier"] == "!" ? "" : "0";
          }
        }
        else {
          if ($alias_info["optional_count"]) {
            $result .= $expr["modifier"] == "!" ? "(T" . $alias . "." . $col . " IS NULL OR NOT (T" . $alias . "." . $col . "_type=1))" : "(T" . $alias . "." . $col . " IS NULL OR T" . $alias . "." . $col . "_type=1)";
          }
          else {
            $result .= $expr["modifier"] == "!" ? " NOT (T" . $alias . "." . $col . "_type=1)" : " T" . $alias . "." . $col . "_type=1";
          }
        }
      }
    }

    /* isLiteral */
    if (in_array($call, array(
      "isliteral",
    )) && ($expr = $expression) && $expr["type"] == "var" && ($var_val = $expr["val"])) {
      if (($alias_infos = @$this->term2alias[$var_val]) || ($alias_infos = @$this->optional_term2alias[$var_val])) {
        $alias_info = $alias_infos[0];
        $alias = $alias_info["alias"];
        $col = $alias_info["col"];
        if ($col == "p") {

          /* p is never a literal */
          if ($alias_info["optional_count"]) {
            $result .= $expr["modifier"] == "!" ? "" : "(T" . $alias . "." . $col . " IS NULL OR 0)";
          }
          else {
            $result .= $expr["modifier"] == "!" ? "" : "0";
          }
        }
        else {
          if ($alias_info["optional_count"]) {
            $result .= $expr["modifier"] == "!" ? "(T" . $alias . "." . $col . " IS NULL OR (T" . $alias . "." . $col . "_type < 2))" : "(T" . $alias . "." . $col . " IS NULL OR T" . $alias . "." . $col . "_type > 1)";
          }
          else {
            $result .= $expr["modifier"] == "!" ? "(T" . $alias . "." . $col . "_type < 2)" : " T" . $alias . "." . $col . "_type > 1";
          }
        }
      }
    }

    /* regex */
    if (($call = "regex") && ($exprs = @$expressions) && (count($exprs) == 3 || count($exprs) == 2)) {
      $sub_result = "";

      /* expr 1 */
      $expr_1 = $exprs[0];
      if (isset($expr_1["call"]) && $expr_1["call"] == "str") {
        $expr_1 = $expr_1["expression"];
      }
      if ($expr_1["type"] == "var" && ($var_val = $expr_1["val"]) && ($expr_2 = $exprs[1]) && in_array($expr_2["type"], array(
        "literal",
        "var",
      )) && ($match_val = $expr_2["val"])) {
        $use_like = false;
        $prefix = "";
        $suffix = "";
        $sql_snippet = "";
        if ($expr_2["type"] == "literal") {
          if (preg_match("/^([\\^]?)([a-z0-9_\\-\\@ \\:\\.,]+)([\$]?)\$/i", $match_val, $matches)) {

            /* simple string search */
            $use_like = true;
            $prefix = $matches[1] == '^' ? "" : "%";
            $suffix = $matches[3] == '$' ? "" : "%";
            $match_val = $matches[2];

            //$match_val=(substr($match_val, 0, 1)=='%') ? "\\".$match_val : $match_val;/* escape leading % */

            //$match_val=(substr($match_val, 0, 1)=='_') ? "\\".$match_val : $match_val;/* escape leading _ */
            $sql_snippet = $this->config["encode_values"] ? "LIKE '" . $prefix . rawurlencode($match_val) . $suffix . "'" : "LIKE '" . $prefix . mysql_real_escape_string($match_val) . $suffix . "'";
          }
          else {
            $match_val = mysql_real_escape_string($match_val);
            $sql_snippet = "REGEXP '" . $match_val . "'";

            /* won't work properly with "encode_values" */
          }
        }
        elseif ($expr_2["type"] == "var") {
          if (($alias_infos = @$this->term2alias[$match_val]) || ($alias_infos = @$this->optional_term2alias[$match_val])) {
            $alias_info = $alias_infos[0];
            $alias = $alias_info["alias"];
            $col = $alias_info["col"];
            $sql_snippet = "REGEXP T" . $alias . "." . $col;
          }
        }
        if ($sql_snippet && ($alias_infos = @$this->term2alias[$var_val]) || ($alias_infos = @$this->optional_term2alias[$var_val])) {
          $alias_info = $alias_infos[0];
          $alias = $alias_info["alias"];
          $col = $alias_info["col"];
          $sub_result = "V__regex_match_" . $var_val . "__.val " . $sql_snippet;
          $result .= @$modifier && $modifier == "!" ? " NOT (" . $sub_result . ")" : " " . $sub_result;
          $this->val_match_vars[] = $var_val;
        }
      }
    }

    /* langMatches */
    if (($call = "langmatches") && ($exprs = @$expressions) && count($exprs) == 2) {
      $sub_result = "";

      /* expr 1 */
      $expr_1 = $exprs[0];
      if (isset($expr_1["call"]) && $expr_1["call"] == "lang") {
        $expr_1 = $expr_1["expression"];
      }
      if ($expr_1["type"] == "var" && ($var_val = $expr_1["val"]) && ($expr_2 = $exprs[1]) && in_array($expr_2["type"], array(
        "literal",
        "var",
      )) && ($lang_val = $expr_2["val"])) {
        if (($alias_infos = @$this->term2alias[$var_val]) || ($alias_infos = @$this->optional_term2alias[$var_val])) {
          $alias_info = $alias_infos[0];
          $alias = $alias_info["alias"];
          $prefix = "";
          $suffix = "";
          $sql_snippet = "";
          if ($expr_2["type"] == "literal") {
            if ($lang_val == "*") {
              $sql_snippet .= @$modifier && $modifier == "!" ? "(T" . $alias . ".o_lang='')" : " NOT (T" . $alias . ".o_lang='')";
            }
            else {
              $sql_snippet .= @$modifier && $modifier == "!" ? " NOT (T" . $alias . ".o_lang LIKE '%" . rawurlencode($lang_val) . "%')" : " (T" . $alias . ".o_lang LIKE '%" . rawurlencode($lang_val) . "%')";
            }
          }
          elseif ($expr_2["type"] == "var") {
            if (($alias_infos2 = @$this->term2alias[$lang_val]) || ($alias_infos2 = @$this->optional_term2alias[$lang_val])) {
              $alias_info2 = $alias_infos2[0];
              $alias2 = $alias_info2["alias"];
              $col = $alias_info2["col"];
              $sql_snippet .= @$modifier && $modifier == "!" ? " NOT (T" . $alias . ".o_lang LIKE T" . $alias2 . ".o_lang)" : " (T" . $alias . ".o_lang LIKE T" . $alias2 . ".o_lang)";
            }
          }
          if ($sql_snippet) {
            $result .= " " . $sql_snippet;
          }
        }
      }
    }
    return $result;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
ARC_sparql2sql_rewriter::$logs property
ARC_sparql2sql_rewriter::$version property
ARC_sparql2sql_rewriter::ARC_sparql2sql_rewriter function
ARC_sparql2sql_rewriter::get_ask_sql function
ARC_sparql2sql_rewriter::get_best_table_name function
ARC_sparql2sql_rewriter::get_construct_sql function
ARC_sparql2sql_rewriter::get_dataset_code function
ARC_sparql2sql_rewriter::get_describe_sql function
ARC_sparql2sql_rewriter::get_equi_join_code function
ARC_sparql2sql_rewriter::get_expression_order_by_code function
ARC_sparql2sql_rewriter::get_from_code function
ARC_sparql2sql_rewriter::get_graph_code function
ARC_sparql2sql_rewriter::get_id2val_join_code function
ARC_sparql2sql_rewriter::get_left_join_code function
ARC_sparql2sql_rewriter::get_limit_offset_code function
ARC_sparql2sql_rewriter::get_order_by_code function
ARC_sparql2sql_rewriter::get_result_vars_code function
ARC_sparql2sql_rewriter::get_select_sql function
ARC_sparql2sql_rewriter::get_sql function
ARC_sparql2sql_rewriter::get_union_select_sql function
ARC_sparql2sql_rewriter::get_var_order_by_code function
ARC_sparql2sql_rewriter::init function
ARC_sparql2sql_rewriter::parse_built_in_call_filter_pattern function
ARC_sparql2sql_rewriter::parse_expression_filter_pattern function
ARC_sparql2sql_rewriter::parse_filter_pattern function
ARC_sparql2sql_rewriter::parse_graph_pattern function
ARC_sparql2sql_rewriter::parse_group_pattern function
ARC_sparql2sql_rewriter::parse_optional_pattern function
ARC_sparql2sql_rewriter::parse_pattern function
ARC_sparql2sql_rewriter::parse_patterns function
ARC_sparql2sql_rewriter::parse_triples_pattern function
ARC_sparql2sql_rewriter::parse_union_pattern function
ARC_sparql2sql_rewriter::__construct function