Package com.orientechnologies.orient.core.sql

Source Code of com.orientechnologies.orient.core.sql.OCommandExecutorSQLUpdate

/*
* Copyright 1999-2010 Luca Garulli (l.garulli--at--orientechnologies.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.orientechnologies.orient.core.sql;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import com.orientechnologies.common.parser.OStringParser;
import com.orientechnologies.common.util.OPair;
import com.orientechnologies.orient.core.command.OCommandRequestText;
import com.orientechnologies.orient.core.command.OCommandResultListener;
import com.orientechnologies.orient.core.exception.OCommandExecutionException;
import com.orientechnologies.orient.core.metadata.schema.OProperty;
import com.orientechnologies.orient.core.metadata.schema.OType;
import com.orientechnologies.orient.core.metadata.security.ODatabaseSecurityResources;
import com.orientechnologies.orient.core.metadata.security.ORole;
import com.orientechnologies.orient.core.query.OQuery;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.filter.OSQLFilterItem;
import com.orientechnologies.orient.core.sql.functions.OSQLFunctionRuntime;
import com.orientechnologies.orient.core.sql.query.OSQLAsynchQuery;

/**
* SQL UPDATE command.
*
* @author Luca Garulli
*
*/
public class OCommandExecutorSQLUpdate extends OCommandExecutorSQLAbstract implements OCommandResultListener {
  public static final String                  KEYWORD_UPDATE    = "UPDATE";
  private static final String                  KEYWORD_SET        = "SET";
  private static final String                  KEYWORD_ADD        = "ADD";
  private static final String                  KEYWORD_PUT        = "PUT";
  private static final String                  KEYWORD_REMOVE    = "REMOVE";
  private Map<String, Object>                  setEntries        = new LinkedHashMap<String, Object>();
  private Map<String, Object>                  addEntries        = new LinkedHashMap<String, Object>();
  private Map<String, OPair<String, Object>>  putEntries        = new LinkedHashMap<String, OPair<String, Object>>();
  private Map<String, Object>                  removeEntries      = new LinkedHashMap<String, Object>();
  private OQuery<?>                            query;
  private int                                  recordCount        = 0;
  private String                              subjectName;
  private static final Object                  EMPTY_VALUE        = new Object();
  private int                                  parameterCounter  = 0;
  private Map<Object, Object>                  parameters;

  @SuppressWarnings("unchecked")
  public OCommandExecutorSQLUpdate parse(final OCommandRequestText iRequest) {
    iRequest.getDatabase().checkSecurity(ODatabaseSecurityResources.COMMAND, ORole.PERMISSION_UPDATE);

    init(iRequest.getDatabase(), iRequest.getText());

    setEntries.clear();
    query = null;
    recordCount = 0;

    final StringBuilder word = new StringBuilder();

    int pos = OSQLHelper.nextWord(text, textUpperCase, 0, word, true);
    if (pos == -1 || !word.toString().equals(OCommandExecutorSQLUpdate.KEYWORD_UPDATE))
      throw new OCommandSQLParsingException("Keyword " + OCommandExecutorSQLUpdate.KEYWORD_UPDATE + " not found", text, 0);

    int newPos = OSQLHelper.nextWord(text, textUpperCase, pos, word, true);
    if (newPos == -1)
      throw new OCommandSQLParsingException("Invalid target", text, pos);

    pos = newPos;

    subjectName = word.toString();

    newPos = OSQLHelper.nextWord(text, textUpperCase, pos, word, true);
    if (newPos == -1
        || (!word.toString().equals(KEYWORD_SET) && !word.toString().equals(KEYWORD_ADD) && !word.toString().equals(KEYWORD_PUT) && !word
            .toString().equals(KEYWORD_REMOVE)))
      throw new OCommandSQLParsingException("Expected keyword " + KEYWORD_SET + "," + KEYWORD_ADD + "," + KEYWORD_PUT + " or "
          + KEYWORD_REMOVE, text, pos);

    pos = newPos;

    while (pos != -1 && !word.toString().equals(OCommandExecutorSQLAbstract.KEYWORD_WHERE)) {
      if (word.toString().equals(KEYWORD_SET))
        pos = parseSetFields(word, pos);
      else if (word.toString().equals(KEYWORD_ADD))
        pos = parseAddFields(word, pos);
      else if (word.toString().equals(KEYWORD_PUT))
        pos = parsePutFields(word, pos);
      else if (word.toString().equals(KEYWORD_REMOVE))
        pos = parseRemoveFields(word, pos);
      else
        break;
    }

    String whereCondition = word.toString();

    if (whereCondition.equals(OCommandExecutorSQLAbstract.KEYWORD_WHERE))
      query = new OSQLAsynchQuery<ODocument>("select from " + subjectName + " where " + text.substring(pos), this);
    else
      query = new OSQLAsynchQuery<ODocument>("select from " + subjectName, this);

    return this;
  }

  public Object execute(final Map<Object, Object> iArgs) {
    if (subjectName == null)
      throw new OCommandExecutionException("Can't execute the command because it hasn't been parsed yet");

    parameters = iArgs;

    Map<Object, Object> queryArgs = new HashMap<Object, Object>();
    for (int i = parameterCounter; parameters != null && i < parameters.size(); i++) {
      if (parameters.get(i) != null)
        queryArgs.put(i - parameterCounter, parameters.get(i));
    }

    database.query(query, queryArgs);
    return recordCount;
  }

  /**
   * Update current record.
   */
  @SuppressWarnings("unchecked")
  public boolean result(final Object iRecord) {
    final ODocument record = (ODocument) iRecord;

    boolean recordUpdated = false;

    // BIND VALUES TO UPDATE
    Object v;

    if (setEntries.size() > 0) {
      OSQLHelper.bindParameters(record, setEntries, parameters);
      recordUpdated = true;
    }

    // BIND VALUES TO ADD
    Collection<Object> coll;
    Object fieldValue;
    for (Map.Entry<String, Object> entry : addEntries.entrySet()) {
      coll = null;
      if (!record.containsField(entry.getKey())) {
        // GET THE TYPE IF ANY
        if (record.getSchemaClass() != null) {
          OProperty prop = record.getSchemaClass().getProperty(entry.getKey());
          if (prop != null && prop.getType() == OType.LINKSET)
            // SET TYPE
            coll = new HashSet<Object>();
        }

        if (coll == null)
          // IN ALL OTHER CASES USE A LIST
          coll = new ArrayList<Object>();

        record.field(entry.getKey(), coll);
      } else {
        fieldValue = record.field(entry.getKey());

        if (fieldValue instanceof Collection<?>)
          coll = (Collection<Object>) fieldValue;
        else
          continue;
      }

      v = entry.getValue();

      if (v instanceof OSQLFilterItem)
        v = ((OSQLFilterItem) v).getValue(record);
      else if (v instanceof OSQLFunctionRuntime)
        v = ((OSQLFunctionRuntime) v).execute(record);

      coll.add(v);
      recordUpdated = true;
    }

    // BIND VALUES TO PUT (AS MAP)
    Map<String, Object> map;
    OPair<String, Object> pair;
    for (Entry<String, OPair<String, Object>> entry : putEntries.entrySet()) {
      fieldValue = record.field(entry.getKey());

      if (fieldValue == null) {
        if (record.getSchemaClass() != null) {
          final OProperty property = record.getSchemaClass().getProperty(entry.getKey());
          if (property != null
              && (property.getType() != null && (!property.getType().equals(OType.EMBEDDEDMAP) && !property.getType().equals(
                  OType.LINKMAP)))) {
            throw new OCommandExecutionException("field " + entry.getKey() + " is not defined as a map");
          }
        }
        fieldValue = new HashMap();
        record.field(entry.getKey(), fieldValue);
      }

      if (fieldValue instanceof Map<?, ?>) {
        map = (Map<String, Object>) fieldValue;

        pair = entry.getValue();

        if (pair.getValue() instanceof OSQLFilterItem)
          pair.setValue(((OSQLFilterItem) pair.getValue()).getValue(record));
        else if (pair.getValue() instanceof OSQLFunctionRuntime)
          v = ((OSQLFunctionRuntime) pair.getValue()).execute(record);

        map.put(pair.getKey(), pair.getValue());
        recordUpdated = true;
      }
    }

    // REMOVE FIELD IF ANY
    for (Map.Entry<String, Object> entry : removeEntries.entrySet()) {
      v = entry.getValue();
      if (v == EMPTY_VALUE) {
        record.removeField(entry.getKey());
        recordUpdated = true;
      } else {
        fieldValue = record.field(entry.getKey());

        if (fieldValue instanceof Collection<?>) {
          coll = (Collection<Object>) fieldValue;
          if (coll.remove(v))
            recordUpdated = true;
        } else if (fieldValue instanceof Map<?, ?>) {
          map = (Map<String, Object>) fieldValue;
          if (map.remove(v) != null)
            recordUpdated = true;
        }
      }
    }

    if (recordUpdated) {
      record.setDirty();
      record.save();
      recordCount++;
    }

    return true;
  }

  private int parseSetFields(final StringBuilder word, int pos) {
    String fieldName;
    String fieldValue;
    int newPos = pos;

    while (pos != -1 && (setEntries.size() == 0 || word.toString().equals(","))) {
      newPos = OSQLHelper.nextWord(text, textUpperCase, pos, word, false);
      if (newPos == -1)
        throw new OCommandSQLParsingException("Field name expected", text, pos);
      pos = newPos;

      fieldName = word.toString();

      newPos = OStringParser.jumpWhiteSpaces(text, pos);

      if (newPos == -1 || text.charAt(newPos) != '=')
        throw new OCommandSQLParsingException("Character '=' was expected", text, pos);

      pos = newPos;
      newPos = OSQLHelper.nextWord(text, textUpperCase, pos + 1, word, false, " =><");
      if (pos == -1)
        throw new OCommandSQLParsingException("Value expected", text, pos);

      fieldValue = word.toString();

      if (fieldValue.endsWith(",")) {
        pos = newPos - 1;
        fieldValue = fieldValue.substring(0, fieldValue.length() - 1);
      } else
        pos = newPos;

      // INSERT TRANSFORMED FIELD VALUE
      setEntries.put(fieldName, getFieldValueCountingParameters(fieldValue));

      pos = OSQLHelper.nextWord(text, textUpperCase, pos, word, true);
    }

    if (setEntries.size() == 0)
      throw new OCommandSQLParsingException("Entries to set <field> = <value> are missed. Example: name = 'Bill', salary = 300.2",
          text, pos);

    return pos;
  }

  private int parseAddFields(final StringBuilder word, int pos) {
    String fieldName;
    String fieldValue;
    int newPos = pos;

    while (pos != -1 && (setEntries.size() == 0 || word.toString().equals(",")) && !word.toString().equals(KEYWORD_WHERE)) {
      newPos = OSQLHelper.nextWord(text, textUpperCase, pos, word, false);
      if (newPos == -1)
        throw new OCommandSQLParsingException("Field name expected", text, pos);
      pos = newPos;

      fieldName = word.toString();

      newPos = OStringParser.jumpWhiteSpaces(text, pos);

      if (newPos == -1 || text.charAt(newPos) != '=')
        throw new OCommandSQLParsingException("Character '=' was expected", text, pos);

      pos = newPos;
      newPos = OSQLHelper.nextWord(text, textUpperCase, pos + 1, word, false, " =><");
      if (pos == -1)
        throw new OCommandSQLParsingException("Value expected", text, pos);

      fieldValue = word.toString();

      if (fieldValue.endsWith(",")) {
        pos = newPos - 1;
        fieldValue = fieldValue.substring(0, fieldValue.length() - 1);
      } else
        pos = newPos;

      // INSERT TRANSFORMED FIELD VALUE
      addEntries.put(fieldName, getFieldValueCountingParameters(fieldValue));

      pos = OSQLHelper.nextWord(text, textUpperCase, pos, word, true);
    }

    if (addEntries.size() == 0)
      throw new OCommandSQLParsingException("Entries to add <field> = <value> are missed. Example: name = 'Bill', salary = 300.2",
          text, pos);

    return pos;
  }

  private int parsePutFields(final StringBuilder word, int pos) {
    String fieldName;
    String fieldKey;
    String fieldValue;
    int newPos = pos;

    while (pos != -1 && (setEntries.size() == 0 || word.toString().equals(",")) && !word.toString().equals(KEYWORD_WHERE)) {
      newPos = OSQLHelper.nextWord(text, textUpperCase, pos, word, false);
      if (newPos == -1)
        throw new OCommandSQLParsingException("Field name expected", text, pos);
      pos = newPos;

      fieldName = word.toString();

      newPos = OStringParser.jumpWhiteSpaces(text, pos);

      if (newPos == -1 || text.charAt(newPos) != '=')
        throw new OCommandSQLParsingException("Character '=' was expected", text, pos);

      pos = newPos;
      newPos = OSQLHelper.nextWord(text, textUpperCase, pos + 1, word, false, " =><,");
      if (pos == -1)
        throw new OCommandSQLParsingException("Key expected", text, pos);

      fieldKey = word.toString();

      if (fieldKey.endsWith(",")) {
        pos = newPos + 1;
        fieldKey = fieldKey.substring(0, fieldKey.length() - 1);
      } else {
        pos = newPos;

        newPos = OStringParser.jumpWhiteSpaces(text, pos);
        if (newPos == -1 || text.charAt(pos) != ',')
          throw new OCommandSQLParsingException("',' expected", text, pos);

        pos = newPos;
      }

      newPos = OSQLHelper.nextWord(text, textUpperCase, pos + 1, word, false, " =><,");
      if (pos == -1)
        throw new OCommandSQLParsingException("Value expected", text, pos);

      fieldValue = word.toString();

      if (fieldValue.endsWith(",")) {
        pos = newPos - 1;
        fieldValue = fieldValue.substring(0, fieldValue.length() - 1);
      } else
        pos = newPos;

      // INSERT TRANSFORMED FIELD VALUE
      putEntries.put(fieldName, new OPair<String, Object>((String) getFieldValueCountingParameters(fieldKey),
          getFieldValueCountingParameters(fieldValue)));

      pos = OSQLHelper.nextWord(text, textUpperCase, pos, word, true);
    }

    if (putEntries.size() == 0)
      throw new OCommandSQLParsingException("Entries to put <field> = <key>, <value> are missed. Example: name = 'Bill', 30", text,
          pos);

    return pos;
  }

  private int parseRemoveFields(final StringBuilder word, int pos) {
    String fieldName;
    String fieldValue;
    Object value;
    int newPos = pos;

    while (pos != -1 && (removeEntries.size() == 0 || word.toString().equals(",")) && !word.toString().equals(KEYWORD_WHERE)) {
      newPos = OSQLHelper.nextWord(text, textUpperCase, pos, word, false);
      if (newPos == -1)
        throw new OCommandSQLParsingException("Field name expected", text, pos);

      fieldName = word.toString();

      pos = OStringParser.jumpWhiteSpaces(text, newPos);

      if (pos > -1 && text.charAt(pos) == '=') {
        pos = OSQLHelper.nextWord(text, textUpperCase, pos + 1, word, false, " =><,");
        if (pos == -1)
          throw new OCommandSQLParsingException("Value expected", text, pos);

        fieldValue = word.toString();

        if (fieldValue.endsWith(",")) {
          pos = newPos - 1;
          fieldValue = fieldValue.substring(0, fieldValue.length() - 1);
        } else
          pos = newPos;

        value = getFieldValueCountingParameters(fieldValue);

      } else
        value = EMPTY_VALUE;

      // INSERT FIELD NAME TO BE REMOVED
      removeEntries.put(fieldName, value);

      pos = OSQLHelper.nextWord(text, textUpperCase, pos, word, true);
    }

    if (removeEntries.size() == 0)
      throw new OCommandSQLParsingException("Field(s) to remove are missed. Example: name, salary", text, pos);
    return pos;
  }

  private Object getFieldValueCountingParameters(String fieldValue) {
    if (fieldValue.trim().equals("?"))
      parameterCounter++;
    return OSQLHelper.parseValue(database, this, fieldValue);
  }
}
TOP

Related Classes of com.orientechnologies.orient.core.sql.OCommandExecutorSQLUpdate

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.