Esempio n. 1
0
  /**
   * Evaluates the full-text match.
   *
   * @param qc query context
   * @return number of tokens, used for scoring
   * @throws QueryException query exception
   */
  private int contains(final QueryContext qc) throws QueryException {
    first = true;
    final FTLexer lexer = ftt.lexer(qc.ftToken);

    // use faster evaluation for default options
    int num = 0;
    if (fast) {
      for (final byte[] t : tokens) {
        final FTTokens qtok = ftt.cache(t);
        num = Math.max(num, ftt.contains(qtok, lexer) * qtok.length());
      }
      return num;
    }

    // find and count all occurrences
    final boolean all = mode == FTMode.ALL || mode == FTMode.ALL_WORDS;
    int oc = 0;
    for (final byte[] w : unique(tokens(qc))) {
      final FTTokens qtok = ftt.cache(w);
      final int o = ftt.contains(qtok, lexer);
      if (all && o == 0) return 0;
      num = Math.max(num, o * qtok.length());
      oc += o;
    }

    // check if occurrences are in valid range. if yes, return number of tokens
    final long mn = occ != null ? toLong(occ[0], qc) : 1;
    final long mx = occ != null ? toLong(occ[1], qc) : Long.MAX_VALUE;
    if (mn == 0 && oc == 0) matches = FTNot.not(matches);
    return oc >= mn && oc <= mx ? Math.max(1, num) : 0;
  }
Esempio n. 2
0
 /**
  * Returns the date in seconds.
  *
  * @return seconds
  */
 final BigDecimal seconds() {
   int z = tz;
   if (z == Short.MAX_VALUE) {
     // [CG] XQuery, DateTime: may be removed
     final long n = System.currentTimeMillis();
     z = Calendar.getInstance().getTimeZone().getOffset(n) / 60000;
   }
   return (sec == null ? BigDecimal.ZERO : sec)
       .add(BigDecimal.valueOf(Math.max(0, hou) * 3600 + Math.max(0, min) * 60 - z * 60));
 }
Esempio n. 3
0
  @Override
  public boolean indexAccessible(final IndexInfo ii) {
    /* If the following conditions yield true, the index is accessed:
     * - all query terms are statically available
     * - no FTTimes option is specified
     * - explicitly set case, diacritics and stemming match options do not
     *   conflict with index options. */
    data = ii.ic.data;
    final MetaData md = data.meta;
    final FTOpt fto = ftt.opt;

    /* Index will be applied if no explicit match options have been set
     * that conflict with the index options. As a consequence, though, index-
     * based querying might yield other results than sequential scanning. */
    if (occ != null
        || fto.cs != null && md.casesens == (fto.cs == FTCase.INSENSITIVE)
        || fto.isSet(DC) && md.diacritics != fto.is(DC)
        || fto.isSet(ST) && md.stemming != fto.is(ST)
        || fto.ln != null && !fto.ln.equals(md.language)) return false;

    // adopt database options to tokenizer
    fto.copy(md);

    // estimate costs if text is not known at compile time
    if (tokens == null) {
      ii.costs = Math.max(2, data.meta.size / 30);
      return true;
    }

    // summarize number of hits; break loop if no hits are expected
    final FTLexer ft = new FTLexer(fto);
    ii.costs = 0;
    for (byte[] t : tokens) {
      ft.init(t);
      while (ft.hasNext()) {
        final byte[] tok = ft.nextToken();
        if (fto.sw != null && fto.sw.contains(tok)) continue;

        if (fto.is(WC)) {
          // don't use index if one of the terms starts with a wildcard
          t = ft.get();
          if (t[0] == '.') return false;
          // don't use index if certain characters or more than 1 dot are found
          int d = 0;
          for (final byte w : t) {
            if (w == '{' || w == '\\' || w == '.' && ++d > 1) return false;
          }
        }
        // favor full-text index requests over exact queries
        final int costs = data.costs(ft);
        if (costs != 0) ii.costs += Math.max(2, costs / 100);
      }
    }
    return true;
  }
Esempio n. 4
0
  /**
   * Adds the specified dayTime duration.
   *
   * @param add value to be added
   */
  private void add(final BigDecimal add) {
    // normalized modulo: sc % 60  vs.  (-sc + sc % 60 + 60 + sc) % 60
    final BigDecimal sc = sec().add(add);
    sec =
        sc.signum() >= 0
            ? sc.remainder(BD60)
            : sc.negate().add(sc.remainder(BD60)).add(BD60).add(sc).remainder(BD60);

    final long mn = Math.max(min(), 0) + div(sc.longValue(), 60);
    min = (byte) mod(mn, 60);
    final long ho = Math.max(hou, 0) + div(mn, 60);
    hou = (byte) mod(ho, 24);
    final long da = div(ho, 24);

    final long[] ymd = ymd(days().add(BigDecimal.valueOf(da)));
    yea = ymd[0];
    mon = (byte) ymd[1];
    day = (byte) ymd[2];
  }
Esempio n. 5
0
 /**
  * Merges two matches.
  *
  * @param i1 first item
  * @param i2 second item
  */
 private static void and(final FTNode i1, final FTNode i2) {
   final FTMatches all = new FTMatches((byte) Math.max(i1.matches().pos, i2.matches().pos));
   for (final FTMatch s1 : i1.matches()) {
     for (final FTMatch s2 : i2.matches()) {
       all.add(new FTMatch(s1.size() + s2.size()).add(s1).add(s2));
     }
   }
   i1.score(Scoring.avg(i1.score() + i2.score(), 2));
   i1.matches(all);
 }
Esempio n. 6
0
  /**
   * Compiles the filter expression, excluding the root node.
   *
   * @param ctx query context
   * @return compiled expression
   */
  private Expr opt(final QueryContext ctx) {
    // evaluate return type
    final SeqType t = root.type();

    // determine number of results and type
    final long s = root.size();
    if (s != -1) {
      if (pos != null) {
        size = Math.max(0, s + 1 - pos.min) - Math.max(0, s - pos.max);
      } else if (last) {
        size = s > 0 ? 1 : 0;
      }
      // no results will remain: return empty sequence
      if (size == 0) return optPre(null, ctx);
      type = SeqType.get(t.type, size);
    } else {
      type = SeqType.get(t.type, t.zeroOrOne() ? Occ.ZERO_ONE : Occ.ZERO_MORE);
    }

    // no numeric predicates.. use simple iterator
    if (!super.has(Flag.FCS)) return new IterFilter(this);

    // one single position() or last() function specified: return single value
    if (preds.length == 1
        && (last || pos != null)
        && root.isValue()
        && t.one()
        && (last || pos.min == 1 && pos.max == 1)) return optPre(root, ctx);

    // only choose deterministic and context-independent offsets; e.g., skip:
    // (1 to 10)[random:integer(10)]  or  (1 to 10)[.]
    boolean off = false;
    if (preds.length == 1) {
      final Expr p = preds[0];
      final SeqType st = p.type();
      off = st.type.isNumber() && st.zeroOrOne() && !p.has(Flag.CTX) && !p.has(Flag.NDT);
      if (off) type = SeqType.get(type.type, Occ.ZERO_ONE);
    }

    // iterator for simple numeric predicate
    return off || useIterator() ? new IterPosFilter(this, off) : this;
  }
Esempio n. 7
0
 /**
  * Rounds values.
  *
  * @param qc query context
  * @param even half-to-even flag
  * @return number
  * @throws QueryException query exception
  */
 ANum round(final QueryContext qc, final boolean even) throws QueryException {
   final ANum num = toNumber(exprs[0], qc);
   final long p = exprs.length == 1 ? 0 : Math.max(Integer.MIN_VALUE, toLong(exprs[1], qc));
   return num == null ? null : p > Integer.MAX_VALUE ? num : num.round((int) p, even);
 }
Esempio n. 8
0
  /**
   * Evaluates the specified query.
   *
   * @param query query
   * @return success flag
   */
  final boolean query(final String query) {
    final Performance p = new Performance();
    String error;
    if (exception != null) {
      error = Util.message(exception);
    } else {
      try {
        long hits = 0;
        final boolean run = options.get(MainOptions.RUNQUERY);
        final boolean serial = options.get(MainOptions.SERIALIZE);
        final int runs = Math.max(1, options.get(MainOptions.RUNS));
        for (int r = 0; r < runs; ++r) {
          // reuse existing processor instance
          if (r != 0) qp = null;
          qp(query, context);
          parse(p);
          if (r == 0) plan(false);

          qp.compile();
          info.compiling += p.time();
          if (r == 0) plan(true);
          if (!run) continue;

          final PrintOutput po = r == 0 && serial ? out : new NullOutput();
          try (final Serializer ser = qp.getSerializer(po)) {
            if (maxResults >= 0) {
              result = qp.cache(maxResults);
              info.evaluating += p.time();
              result.serialize(ser);
              hits = result.size();
            } else {
              hits = 0;
              final Iter ir = qp.iter();
              info.evaluating += p.time();
              for (Item it; (it = ir.next()) != null; ) {
                ser.serialize(it);
                ++hits;
                checkStop();
              }
            }
          }
          qp.close();
          info.serializing += p.time();
        }
        // dump some query info
        // out.flush();

        // remove string list if global locking is used and if query is updating
        if (soptions.get(StaticOptions.GLOBALLOCK) && qp.updating) {
          info.readLocked = null;
          info.writeLocked = null;
        }
        return info(info.toString(qp, out.size(), hits, options.get(MainOptions.QUERYINFO)));

      } catch (final QueryException | IOException ex) {
        exception = ex;
        error = Util.message(ex);
      } catch (final ProcException ex) {
        error = INTERRUPTED;
      } catch (final StackOverflowError ex) {
        Util.debug(ex);
        error = BASX_STACKOVERFLOW.desc;
      } catch (final RuntimeException ex) {
        extError("");
        Util.debug(info());
        throw ex;
      } finally {
        // close processor after exceptions
        if (qp != null) qp.close();
      }
    }
    return extError(error);
  }
Esempio n. 9
0
 /**
  * Returns a day count.
  *
  * @return days
  */
 final BigDecimal days() {
   final long y = yea == Long.MAX_VALUE ? 1 : yea;
   return days(y + ADD_NEG, Math.max(mon, 0), Math.max(day, 0));
 }
Esempio n. 10
0
  /**
   * Analyzes the specified patterns.
   *
   * @param patterns patterns
   * @return picture variables
   */
  private Picture[] analyze(final byte[][] patterns) {
    // pictures
    final int picL = patterns.length;
    final Picture[] pics = new Picture[picL];

    // analyze patterns
    for (int p = 0; p < picL; p++) {
      final byte[] pt = patterns[p];
      final Picture pic = new Picture();

      // position (integer/fractional)
      int pos = 0;
      // active character found
      boolean act = false;
      // number of characters after exponent
      int exp = -1;
      // number of optional characters
      final int[] opt = new int[2];

      // loop through all characters
      final int pl = pt.length;
      for (int i = 0, cl; i < pl; i += cl) {
        final int ch = ch(pt, i);
        cl = cl(pt, i);
        boolean active = contains(actives, ch);

        if (ch == decimal) {
          ++pos;
          act = false;
        } else if (ch == optional) {
          opt[pos]++;
        } else if (ch == exponent) {
          if (act && containsActive(pt, i + cl)) {
            exp = 0;
          } else {
            active = false;
          }
        } else if (ch == grouping) {
          if (pos == 0) pic.group[pos] = Array.add(pic.group[pos], pic.min[pos] + opt[pos]);
        } else if (contains(digits, ch)) {
          if (exp == -1) pic.min[pos]++;
          else exp++;
        }

        if (active) {
          act = true;
        } else {
          // passive characters
          pic.pc |= ch == percent;
          pic.pm |= ch == permille;
          // prefixes/suffixes
          pic.prefSuf[pos == 0 && act ? pos + 1 : pos].add(ch);
        }
      }
      // finalize integer-part-grouping-positions
      final int[] igp = pic.group[0];
      final int igl = igp.length;
      for (int g = 0; g < igl; ++g) igp[g] = pic.min[0] + opt[0] - igp[g];

      // check if integer-part-grouping-positions are regular
      // if yes, they are replaced with a single position
      if (igl > 1) {
        boolean reg = true;
        final int i = igp[igl - 1];
        for (int g = igl - 2; g >= 0; --g) reg &= i * igl == igp[g];
        if (reg) pic.group[0] = new int[] {i};
      }

      pic.maxFrac = pic.min[1] + opt[1];
      pic.minExp = Math.max(0, exp);
      pics[p] = pic;
    }
    return pics;
  }