1 30 31 32 package org.hsqldb; 33 34 import org.hsqldb.HsqlNameManager.HsqlName; 35 import org.hsqldb.lib.HsqlDeque; 36 import org.hsqldb.lib.StringConverter; 37 import org.hsqldb.lib.StringUtil; 38 39 46 60 class TriggerDef extends Thread { 61 62 65 static final int NUM_TRIGGER_OPS = 3; static final int NUM_TRIGS = NUM_TRIGGER_OPS * 2 * 2; 68 HsqlName name; 70 String when; 71 String operation; 72 boolean forEachRow; 73 boolean nowait; int maxRowsQueued; 76 83 public static int getDefaultQueueSize() { 84 return defaultQueueSize; 85 } 86 87 protected static int defaultQueueSize = 1024; 88 Table table; 89 Trigger trigger; 90 String triggerClassName; 91 int vectorIndex; 93 protected HsqlDeque pendingQueue; protected int rowsQueued; protected boolean valid = true; protected volatile boolean keepGoing = true; 98 99 128 public TriggerDef(HsqlNameManager.HsqlName name, String when, 129 String operation, boolean forEach, Table table, 130 String triggerClassName, boolean noWait, int queueSize, 131 ClassLoader loader) throws HsqlException { 132 133 this.name = name; 134 this.when = when; 135 this.operation = operation; 136 this.forEachRow = forEach; 137 this.nowait = noWait; 138 this.maxRowsQueued = queueSize; 139 this.table = table; 140 vectorIndex = SqlToIndex(); 141 this.triggerClassName = triggerClassName; 142 rowsQueued = 0; 143 pendingQueue = new HsqlDeque(); 144 145 if (vectorIndex < 0) { 146 throw Trace.error(Trace.UNEXPECTED_TOKEN, 147 Trace.CREATE_TRIGGER_COMMAND_1); 148 } 149 150 Class cl; 151 152 try { 153 cl = loader == null ? Class.forName(triggerClassName) 154 : loader.loadClass(triggerClassName); 155 } catch (ClassNotFoundException e) { 156 valid = false; 157 cl = DefaultTrigger.class; 158 } 159 160 try { 161 162 trigger = (Trigger) cl.newInstance(); 164 } catch (Exception e) { 165 valid = false; 166 cl = DefaultTrigger.class; 167 } 168 } 169 170 177 public StringBuffer getDDL() { 178 179 StringBuffer a = new StringBuffer (256); 180 181 a.append(Token.T_CREATE).append(' '); 182 a.append(Token.T_TRIGGER).append(' '); 183 a.append(name.statementName).append(' '); 184 a.append(when).append(' '); 185 a.append(operation).append(' '); 186 a.append(Token.T_ON).append(' '); 187 a.append(table.getName().statementName).append(' '); 188 189 if (forEachRow) { 190 a.append(Token.T_FOR).append(' '); 191 a.append(Token.T_EACH).append(' '); 192 a.append(Token.T_ROW).append(' '); 193 } 194 195 if (nowait) { 196 a.append(Token.T_NOWAIT).append(' '); 197 } 198 199 if (maxRowsQueued != getDefaultQueueSize()) { 200 a.append(Token.T_QUEUE).append(' '); 201 a.append(maxRowsQueued).append(' '); 202 } 203 204 a.append(Token.T_CALL).append(' '); 205 a.append(StringConverter.toQuotedString(triggerClassName, '"', 206 false)); 207 208 return a; 209 } 210 211 219 public int SqlToIndex() { 220 221 int indx; 222 223 if (operation.equals(Token.T_INSERT)) { 224 indx = Trigger.INSERT_AFTER; 225 } else if (operation.equals(Token.T_DELETE)) { 226 indx = Trigger.DELETE_AFTER; 227 } else if (operation.equals(Token.T_UPDATE)) { 228 indx = Trigger.UPDATE_AFTER; 229 } else { 230 return -1; 231 } 232 233 if (when.equals(Token.T_BEFORE)) { 234 indx += NUM_TRIGGER_OPS; } else if (!when.equals(Token.T_AFTER)) { 236 return -1; 237 } 238 239 if (forEachRow) { 240 indx += 2 * NUM_TRIGGER_OPS; 241 } 242 243 return indx; 244 } 245 246 public static int indexToRight(int idx) { 247 248 switch (idx) { 249 250 case Trigger.DELETE_AFTER : 251 case Trigger.DELETE_AFTER_ROW : 252 case Trigger.DELETE_BEFORE : 253 case Trigger.DELETE_BEFORE_ROW : 254 return UserManager.DELETE; 255 256 case Trigger.INSERT_AFTER : 257 case Trigger.INSERT_AFTER_ROW : 258 case Trigger.INSERT_BEFORE : 259 case Trigger.INSERT_BEFORE_ROW : 260 return UserManager.INSERT; 261 262 case Trigger.UPDATE_AFTER : 263 case Trigger.UPDATE_AFTER_ROW : 264 case Trigger.UPDATE_BEFORE : 265 case Trigger.UPDATE_BEFORE_ROW : 266 return UserManager.UPDATE; 267 268 default : 269 return 0; 270 } 271 } 272 273 280 public void run() { 281 282 while (keepGoing) { 283 TriggerData triggerData = popPair(); 284 285 if (triggerData != null) { 286 if (triggerData.username != null) { 287 trigger.fire(this.vectorIndex, name.name, 288 table.getName().name, triggerData.oldRow, 289 triggerData.newRow); 290 } 291 } 292 } 293 } 294 295 298 public synchronized void start() { 299 300 if (maxRowsQueued != 0) { 301 super.start(); 302 } 303 } 304 305 308 public synchronized void terminate() { 309 310 keepGoing = false; 311 312 notify(); 313 } 314 315 325 synchronized TriggerData popPair() { 326 327 if (rowsQueued == 0) { 328 try { 329 wait(); } catch (InterruptedException e) { 331 332 333 } 334 } 335 336 rowsQueued--; 337 338 notify(); 340 if (pendingQueue.size() == 0) { 341 return null; 342 } else { 343 return (TriggerData) pendingQueue.removeFirst(); 344 } 345 } 346 347 356 synchronized void pushPair(Session session, Object [] row1, 357 Object [] row2) { 358 359 if (maxRowsQueued == 0) { 360 trigger.fire(vectorIndex, name.name, table.getName().name, row1, 361 row2); 362 363 return; 364 } 365 366 if (rowsQueued >= maxRowsQueued) { 367 if (nowait) { 368 pendingQueue.removeLast(); } else { 370 try { 371 wait(); 372 } catch (InterruptedException e) { 373 374 375 } 376 377 rowsQueued++; 378 } 379 } else { 380 rowsQueued++; 381 } 382 383 pendingQueue.add(new TriggerData(session, row1, row2)); 384 notify(); } 386 387 392 public boolean isBusy() { 393 return rowsQueued != 0; 394 } 395 396 401 public boolean isValid() { 402 return valid; 403 } 404 405 410 class TriggerData { 411 412 public Object [] oldRow; 413 public Object [] newRow; 414 public String username; 415 416 public TriggerData(Session session, Object [] oldRow, 417 Object [] newRow) { 418 419 this.oldRow = oldRow; 420 this.newRow = newRow; 421 this.username = session.getUsername(); 422 } 423 } 424 425 static class DefaultTrigger implements org.hsqldb.Trigger { 426 427 public void fire(int i, String name, String table, Object [] row1, 428 Object [] row2) { 429 throw new RuntimeException ("Missing Trigger class!"); 430 } 431 } 432 } 433 | Popular Tags |