1 /* 2 * Copyright 2015-2018 HuntLabs.cn 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 module hunt.sql.ast.expr.SQLMethodInvokeExpr; 17 18 19 20 import hunt.sql.SQLUtils; 21 import hunt.sql.ast; 22 // import hunt.sql.dialect.oracle.visitor.OracleASTVisitor; 23 import hunt.sql.visitor.SQLASTVisitor; 24 import hunt.sql.util.FnvHash; 25 import hunt.collection; 26 import hunt.sql.ast.expr.SQLIdentifierExpr; 27 import hunt.sql.ast.expr.SQLDateExpr; 28 import hunt.util.StringBuilder; 29 30 public class SQLMethodInvokeExpr : SQLExprImpl , SQLReplaceable//, Serializable 31 { 32 private string name; 33 private SQLExpr owner; 34 private List!SQLExpr parameters; 35 36 private SQLExpr from; 37 private SQLExpr using; 38 private SQLExpr _for; 39 40 private string trimOption; 41 42 private long nameHashCode64; 43 44 public this(){ 45 parameters = new ArrayList!SQLExpr(); 46 } 47 48 public this(string methodName){ 49 this(); 50 this.name = methodName; 51 } 52 53 public this(string methodName, long nameHashCode64){ 54 this(); 55 this.name = methodName; 56 this.nameHashCode64 = nameHashCode64; 57 } 58 59 public this(string methodName, SQLExpr owner){ 60 this(); 61 this.name = methodName; 62 setOwner(owner); 63 } 64 65 public this(string methodName, SQLExpr owner, SQLExpr[] params...){ 66 this(); 67 this.name = methodName; 68 setOwner(owner); 69 foreach (SQLExpr param ; params) { 70 this.addParameter(param); 71 } 72 } 73 74 public long methodNameHashCode64() { 75 if (nameHashCode64 == 0 76 && name !is null) { 77 nameHashCode64 = FnvHash.hashCode64(name); 78 } 79 return nameHashCode64; 80 } 81 82 public string getMethodName() { 83 return this.name; 84 } 85 86 public void setMethodName(string methodName) { 87 this.name = methodName; 88 this.nameHashCode64 = 0L; 89 } 90 91 public SQLExpr getOwner() { 92 return this.owner; 93 } 94 95 public void setOwner(SQLExpr owner) { 96 if (owner !is null) { 97 owner.setParent(this); 98 } 99 this.owner = owner; 100 } 101 102 public SQLExpr getFrom() { 103 return from; 104 } 105 106 public void setFrom(SQLExpr x) { 107 if (x !is null) { 108 x.setParent(this); 109 } 110 this.from = x; 111 } 112 113 public List!SQLExpr getParameters() { 114 return this.parameters; 115 } 116 117 public void addParameter(SQLExpr param) { 118 if (param !is null) { 119 param.setParent(this); 120 } 121 this.parameters.add(param); 122 } 123 124 public void addArgument(SQLExpr arg) { 125 if (arg !is null) { 126 arg.setParent(this); 127 } 128 this.parameters.add(arg); 129 } 130 131 override public void output(StringBuilder buf) { 132 if (this.owner !is null) { 133 this.owner.output(buf); 134 buf.append("."); 135 } 136 137 buf.append(this.name); 138 buf.append("("); 139 for (int i = 0, size = this.parameters.size(); i < size; ++i) { 140 if (i != 0) { 141 buf.append(", "); 142 } 143 144 this.parameters.get(i).output(buf); 145 } 146 buf.append(")"); 147 } 148 149 override protected void accept0(SQLASTVisitor visitor) { 150 if (visitor.visit(this)) { 151 acceptChild(visitor, this.owner); 152 acceptChild!SQLExpr(visitor, this.parameters); 153 acceptChild(visitor, this.from); 154 acceptChild(visitor, this.using); 155 acceptChild(visitor, this._for); 156 } 157 158 visitor.endVisit(this); 159 } 160 161 override public List!SQLObject getChildren() { 162 if (this.owner is null) { 163 return cast(List!SQLObject)this.parameters; 164 } 165 166 List!SQLObject children = new ArrayList!SQLObject(); 167 children.add(owner); 168 children.addAll(cast(List!SQLObject)(this.parameters)); 169 return children; 170 } 171 172 // protected void accept0(OracleASTVisitor visitor) { 173 // if (visitor.visit(this)) { 174 // acceptChild(visitor, this.owner); 175 // acceptChild(visitor, this.parameters); 176 // acceptChild(visitor, this.from); 177 // acceptChild(visitor, this.using); 178 // acceptChild(visitor, this._for); 179 // } 180 181 // visitor.endVisit(this); 182 // } 183 184 override 185 public bool opEquals(Object o) { 186 if (this == o) return true; 187 if (o is null || typeid(this) != typeid(o)) return false; 188 189 SQLMethodInvokeExpr that = cast(SQLMethodInvokeExpr) o; 190 191 if (name !is null ? !(name == that.name) : that.name !is null) return false; 192 if (owner !is null ? !(cast(Object)(owner)).opEquals(cast(Object)(that.owner)) : that.owner !is null) return false; 193 if (parameters !is null ? !(cast(Object)(parameters)).opEquals(cast(Object)(that.parameters)) : that.parameters !is null) return false; 194 return from !is null ? (cast(Object)(from)).opEquals(cast(Object)(that.from)) : that.from is null; 195 196 } 197 198 override 199 public size_t toHash() @trusted nothrow { 200 size_t result = name !is null ? hashOf(name) : 0; 201 result = 31 * result + (owner !is null ? (cast(Object)owner).toHash() : 0); 202 result = 31 * result + (parameters !is null ? (cast(Object)parameters).toHash() : 0); 203 result = 31 * result + (from !is null ? (cast(Object)from).toHash() : 0); 204 return result; 205 } 206 207 override public SQLMethodInvokeExpr clone() { 208 SQLMethodInvokeExpr x = new SQLMethodInvokeExpr(); 209 210 x.name = name; 211 212 if (owner !is null) { 213 x.setOwner(owner.clone()); 214 } 215 216 foreach (SQLExpr param ; parameters) { 217 x.addParameter(param.clone()); 218 } 219 220 if (from !is null) { 221 x.setFrom(from.clone()); 222 } 223 224 if (using !is null) { 225 x.setUsing(using.clone()); 226 } 227 228 return x; 229 } 230 231 override 232 public bool replace(SQLExpr expr, SQLExpr target) { 233 if (target is null) { 234 return false; 235 } 236 237 for (int i = 0; i < parameters.size(); ++i) { 238 if (parameters.get(i) == expr) { 239 parameters.set(i, target); 240 target.setParent(this); 241 return true; 242 } 243 } 244 245 if (from == expr) { 246 setFrom(target); 247 return true; 248 } 249 250 if (using == expr) { 251 setUsing(target); 252 return true; 253 } 254 255 if (_for == expr) { 256 setFor(target); 257 return true; 258 } 259 260 return false; 261 } 262 263 public bool match(string owner, string function_p) { 264 if (function_p is null) { 265 return false; 266 } 267 268 if (!SQLUtils.nameEquals(function_p, name)) { 269 return false; 270 } 271 272 if (owner is null && this.owner is null) { 273 return true; 274 } 275 276 if (owner is null || this.owner is null) { 277 return false; 278 } 279 auto obj = cast(SQLIdentifierExpr) this.owner; 280 if (obj !is null) { 281 return SQLUtils.nameEquals(obj.name, owner); 282 } 283 284 return false; 285 } 286 287 override public SQLDataType computeDataType() { 288 if (SQLUtils.nameEquals("to_date", name) 289 || SQLUtils.nameEquals("add_months", name)) { 290 return SQLDateExpr.DEFAULT_DATA_TYPE; 291 } 292 293 if (parameters.size() == 1) { 294 if (SQLUtils.nameEquals("trunc", name)) { 295 return parameters.get(0).computeDataType(); 296 } 297 } else if (parameters.size() == 2) { 298 SQLExpr param0 = parameters.get(0); 299 SQLExpr param1 = parameters.get(1); 300 if (SQLUtils.nameEquals("nvl", name) || SQLUtils.nameEquals("ifnull", name)) { 301 SQLDataType dataType = param0.computeDataType(); 302 if (dataType !is null) { 303 return dataType; 304 } 305 306 return param1.computeDataType(); 307 } 308 } 309 return null; 310 } 311 312 public SQLExpr getUsing() { 313 return using; 314 } 315 316 public void setUsing(SQLExpr x) { 317 if (x !is null) { 318 x.setParent(this); 319 } 320 this.using = x; 321 } 322 323 public SQLExpr getFor() { 324 return _for; 325 } 326 327 public void setFor(SQLExpr x) { 328 if (x !is null) { 329 x.setParent(this); 330 } 331 this._for = x; 332 } 333 334 public string getTrimOption() { 335 return trimOption; 336 } 337 338 public void setTrimOption(string trimOption) { 339 this.trimOption = trimOption; 340 } 341 }