|
294 | 294 | var s; |
295 | 295 | let refs = []; |
296 | 296 | let op = this.op; |
| 297 | + let skipNullCheck = false; // Flag to skip null checking for deterministic empty set operations |
297 | 298 | let _this = this; |
298 | 299 | let ref = function (expr) { |
299 | 300 | if (expr.toJS) { |
|
375 | 376 | const uncachedLookup = `(alasql.utils.flatArray(this.queriesfn[${this.queriesidx}](params, null, ${context})).indexOf(alasql.utils.getValueOf(${leftJS()})) > -1)`; |
376 | 377 | s = `(${checkCorrelated} ? ${uncachedLookup} : ${cachedLookup})`; |
377 | 378 | } else if (Array.isArray(this.right)) { |
378 | | - if (!alasql.options.cache || this.right.some(value => value instanceof yy.ParamValue)) { |
| 379 | + // Empty array: nothing is IN an empty set, always false |
| 380 | + if (this.right.length === 0) { |
| 381 | + // Must call leftJS() to populate the refs array for the declareRefs statement, |
| 382 | + // even though the result is not used in the final expression |
| 383 | + leftJS(); |
| 384 | + s = 'false'; |
| 385 | + skipNullCheck = true; // Result is deterministic even with null operands |
| 386 | + } else if ( |
| 387 | + !alasql.options.cache || |
| 388 | + this.right.some(value => value instanceof yy.ParamValue) |
| 389 | + ) { |
379 | 390 | // Leverage JS Set for faster lookups than arrays |
380 | 391 | s = `(new Set([${this.right.map(ref).join(',')}]).has(alasql.utils.getValueOf(${leftJS()})))`; |
381 | 392 | } else { |
|
399 | 410 | const uncachedLookup = `(alasql.utils.flatArray(this.queriesfn[${this.queriesidx}](params, null, ${context})).indexOf(alasql.utils.getValueOf(${leftJS()})) < 0)`; |
400 | 411 | s = `(${checkCorrelated} ? ${uncachedLookup} : ${cachedLookup})`; |
401 | 412 | } else if (Array.isArray(this.right)) { |
402 | | - if (!alasql.options.cache || this.right.some(value => value instanceof yy.ParamValue)) { |
| 413 | + // Empty array: everything is NOT IN an empty set, always true |
| 414 | + if (this.right.length === 0) { |
| 415 | + // Must call leftJS() to populate the refs array for the declareRefs statement, |
| 416 | + // even though the result is not used in the final expression |
| 417 | + leftJS(); |
| 418 | + s = 'true'; |
| 419 | + skipNullCheck = true; // Result is deterministic even with null operands |
| 420 | + } else if ( |
| 421 | + !alasql.options.cache || |
| 422 | + this.right.some(value => value instanceof yy.ParamValue) |
| 423 | + ) { |
403 | 424 | // Leverage JS Set for faster lookups than arrays |
404 | 425 | s = `(!(new Set([${this.right.map(ref).join(',')}]).has(alasql.utils.getValueOf(${leftJS()}))))`; |
405 | 426 | } else { |
|
475 | 496 | var expr = s || '(' + leftJS() + op + rightJS() + ')'; |
476 | 497 |
|
477 | 498 | var declareRefs = 'y=[(' + refs.join('), (') + ')]'; |
478 | | - if (op === '&&' || op === '||' || op === 'IS' || op === 'IS NULL' || op === 'IS NOT NULL') { |
| 499 | + if ( |
| 500 | + skipNullCheck || |
| 501 | + op === '&&' || |
| 502 | + op === '||' || |
| 503 | + op === 'IS' || |
| 504 | + op === 'IS NULL' || |
| 505 | + op === 'IS NOT NULL' |
| 506 | + ) { |
479 | 507 | return '(' + declareRefs + ', ' + expr + ')'; |
480 | 508 | } |
481 | 509 |
|
|
0 commit comments