001: /**
002: * com.mckoi.database.interpret.UpdateTable 14 Sep 2001
003: *
004: * Mckoi SQL Database ( http://www.mckoi.com/database )
005: * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * Version 2 as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License Version 2 for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * Version 2 along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: * Change Log:
021: *
022: *
023: */package com.mckoi.database.interpret;
024:
025: import java.util.*;
026: import com.mckoi.database.*;
027:
028: /**
029: * The instance class that stores all the information about an update
030: * statement for processing.
031: *
032: * @author Tobias Downer
033: */
034:
035: public class UpdateTable extends Statement {
036:
037: /**
038: * The name the table that we are to update.
039: */
040: String table_name;
041:
042: /**
043: * An array of Assignment objects which represent what we are changing.
044: */
045: ArrayList column_sets;
046:
047: /**
048: * If the update statement has a 'where' clause, then this is set here. If
049: * it has no 'where' clause then we apply to the entire table.
050: */
051: SearchExpression where_condition;
052:
053: /**
054: * The limit of the number of rows that are updated by this statement. A
055: * limit of -1 means there is no limit.
056: */
057: int limit = -1;
058:
059: /**
060: * Tables that are relationally linked to the table being inserted into, set
061: * after 'prepare'. This is used to determine the tables we need to read
062: * lock because we need to validate relational constraints on the tables.
063: */
064: private ArrayList relationally_linked_tables;
065:
066: // -----
067:
068: /**
069: * The DataTable we are updating.
070: */
071: private DataTable update_table;
072:
073: /**
074: * The TableName object set during 'prepare'.
075: */
076: private TableName tname;
077:
078: /**
079: * The plan for the set of records we are updating in this query.
080: */
081: private QueryPlanNode plan;
082:
083: // ---------- Implemented from Statement ----------
084:
085: public void prepare() throws DatabaseException {
086:
087: table_name = (String) cmd.getObject("table_name");
088: column_sets = (ArrayList) cmd.getObject("assignments");
089: where_condition = (SearchExpression) cmd
090: .getObject("where_clause");
091: limit = cmd.getInt("limit");
092:
093: // ---
094:
095: // Resolve the TableName object.
096: tname = resolveTableName(table_name, database);
097: // Does the table exist?
098: if (!database.tableExists(tname)) {
099: throw new DatabaseException("Table '" + tname
100: + "' does not exist.");
101: }
102: // Get the table we are updating
103: update_table = database.getTable(tname);
104:
105: // Form a TableSelectExpression that represents the select on the table
106: TableSelectExpression select_expression = new TableSelectExpression();
107: // Create the FROM clause
108: select_expression.from_clause.addTable(table_name);
109: // Set the WHERE clause
110: select_expression.where_clause = where_condition;
111:
112: // Generate the TableExpressionFromSet hierarchy for the expression,
113: TableExpressionFromSet from_set = Planner.generateFromSet(
114: select_expression, database);
115: // Form the plan
116: plan = Planner.formQueryPlan(database, select_expression,
117: from_set, null);
118:
119: // Resolve the variables in the assignments.
120: for (int i = 0; i < column_sets.size(); ++i) {
121: Assignment assignment = (Assignment) column_sets.get(i);
122: Variable orig_var = assignment.getVariable();
123: Variable new_var = from_set.resolveReference(orig_var);
124: if (new_var == null) {
125: throw new StatementException("Reference not found: "
126: + orig_var);
127: }
128: orig_var.set(new_var);
129: assignment.prepareExpressions(from_set
130: .expressionQualifier());
131: }
132:
133: // Resolve all tables linked to this
134: TableName[] linked_tables = database
135: .queryTablesRelationallyLinkedTo(tname);
136: relationally_linked_tables = new ArrayList(linked_tables.length);
137: for (int i = 0; i < linked_tables.length; ++i) {
138: relationally_linked_tables.add(database
139: .getTable(linked_tables[i]));
140: }
141:
142: }
143:
144: public Table evaluate() throws DatabaseException {
145:
146: DatabaseQueryContext context = new DatabaseQueryContext(
147: database);
148:
149: // Generate a list of Variable objects that represent the list of columns
150: // being changed.
151: Variable[] col_var_list = new Variable[column_sets.size()];
152: for (int i = 0; i < col_var_list.length; ++i) {
153: Assignment assign = (Assignment) column_sets.get(i);
154: col_var_list[i] = assign.getVariable();
155: }
156:
157: // Check that this user has privs to update the table.
158: if (!database.getDatabase().canUserUpdateTableObject(context,
159: user, tname, col_var_list)) {
160: throw new UserAccessException(
161: "User not permitted to update table: " + table_name);
162: }
163:
164: // Check the user has select permissions on the tables in the plan.
165: Select.checkUserSelectPermissions(context, user, plan);
166:
167: // Evaluate the plan to find the update set.
168: Table update_set = plan.evaluate(context);
169:
170: // Make an array of assignments
171: Assignment[] assign_list = new Assignment[column_sets.size()];
172: assign_list = (Assignment[]) column_sets.toArray(assign_list);
173: // Update the data table.
174: int update_count = update_table.update(context, update_set,
175: assign_list, limit);
176:
177: // Notify TriggerManager that we've just done an update.
178: if (update_count > 0) {
179: database
180: .notifyTriggerEvent(new TriggerEvent(
181: TriggerEvent.UPDATE, tname.toString(),
182: update_count));
183: }
184:
185: // Return the number of rows we updated.
186: return FunctionTable.resultTable(context, update_count);
187:
188: }
189:
190: }
|