From cbc199163c409998368c2c731cbb5cd11618f246 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 11 Aug 2023 15:44:47 -0700 Subject: [PATCH 01/61] Initial commit --- cap/CAPModels.qll | 17 +++++++++++++++++ cap/codeql-pack.lock.yml | 16 ++++++++++++++++ cap/qlpack.yml | 7 +++++++ 3 files changed, 40 insertions(+) create mode 100644 cap/CAPModels.qll create mode 100644 cap/codeql-pack.lock.yml create mode 100644 cap/qlpack.yml diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll new file mode 100644 index 000000000..97d41826f --- /dev/null +++ b/cap/CAPModels.qll @@ -0,0 +1,17 @@ +private import javascript +private import DataFlow + + +predicate isService() { + any() // TODO +} + +predicate isRequest() { + any() // TODO +} + +/** const cds = require('@sap/cds') */ +predicate isCDS() { + any() // TODO +} + diff --git a/cap/codeql-pack.lock.yml b/cap/codeql-pack.lock.yml new file mode 100644 index 000000000..2e92bb9d4 --- /dev/null +++ b/cap/codeql-pack.lock.yml @@ -0,0 +1,16 @@ +--- +lockVersion: 1.0.0 +dependencies: + codeql/javascript-all: + version: 0.7.2 + codeql/mad: + version: 0.1.2 + codeql/regex: + version: 0.1.2 + codeql/tutorial: + version: 0.1.2 + codeql/util: + version: 0.1.2 + codeql/yaml: + version: 0.1.2 +compiled: false diff --git a/cap/qlpack.yml b/cap/qlpack.yml new file mode 100644 index 000000000..b8ace3e7f --- /dev/null +++ b/cap/qlpack.yml @@ -0,0 +1,7 @@ +--- +library: false +warnOnImplicitThis: false +name: advanced-security/cap +version: 0.0.1 +dependencies: + codeql/javascript-all: "*" \ No newline at end of file From 33a987a30a9f12af9850f39337199029538bc6ec Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 11 Aug 2023 16:09:30 -0700 Subject: [PATCH 02/61] Add CDSFacade class --- cap/CAPModels.qll | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index 97d41826f..090f071ab 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -1,17 +1,28 @@ private import javascript private import DataFlow - predicate isService() { - any() // TODO + any() // TODO } predicate isRequest() { - any() // TODO + any() // TODO } -/** const cds = require('@sap/cds') */ -predicate isCDS() { - any() // TODO +private ModuleImportNode isCdsInner(TypeTracker t) { + t.start() and + result.getPath() = "@sap/cds" + or + exists(TypeTracker t2 | result = isCdsInner(t2).track(t2, t)) } +predicate isCds(ModuleImportNode node) { node = isCdsInner(TypeTracker::end()) } + +/** + * ```js + * const cds = require('@sap/cds') + * ``` + */ +class CDSFacade extends ModuleImportNode { + CDSFacade() { isCds(this) } +} From b4559c32abf0b82b98f88d26dc2a53cdd0c3e27d Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 13 Sep 2023 16:42:12 -0700 Subject: [PATCH 03/61] Add scaffolding --- cap/CAPModels.qll | 83 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 6 deletions(-) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index 090f071ab..1df7fefb0 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -1,12 +1,71 @@ private import javascript private import DataFlow -predicate isService() { - any() // TODO +abstract class Service extends ValueNode { } + +class ApplicationService extends Service { + ApplicationService() { + /* 1. Awaiting or directly getting return value of `cds.serve` */ + any() + or + /* 2. From directly using the constructor: `new cds.ApplicationService` */ + any() + or + /* 3. Awaiting or directly getting return value of `cds.connect.to` */ + any() + } } -predicate isRequest() { - any() // TODO +/** Last argument to the service methods `srv.before`, `srv.on`, and `srv.after` */ +private class RequestHandler extends FunctionNode { } + +private class ErrorHandler extends RequestHandler { } + +/** + * Subclassing ApplicationService via `extends`: + * ```js + * class SomeService extends cds.ApplicationService + * ``` + */ +class UserDefinedApplicationService extends ApplicationService, ClassNode { } + +/** + * Subclassing ApplicationService via `cds.service.impl`: + * ```js + * cds.service.impl(() => {...}) + * ``` + */ +class OldStyleApplicationService extends UserDefinedApplicationService, ClassNode { } + +/** + * Parameter of a `srv.with` method call: + * ```js + * cds.serve('./srv/cat-service') .with ((srv) => { + * srv.on ('READ','Books', (req) => req.reply([...])) + * }) + */ +class WithCallParameter extends Service, ParameterNode { } + +class RemoteService extends Service, ClassNode { } + +class MessagingService extends Service, ClassNode { } + +class DatabaseService extends Service, ClassNode { } + +class SqlService extends Service, ClassNode { } + +class Request extends ValueNode, ClassNode { + Request() { + /* + * 1. Parameter of request handler of `srv.on`: + * `srv.on ('READ','Books', (req) => req.reply([...]))` + */ + + any() + or + /* 2. Parameter of `srv.send` */ + any() + } } private ModuleImportNode isCdsInner(TypeTracker t) { @@ -23,6 +82,18 @@ predicate isCds(ModuleImportNode node) { node = isCdsInner(TypeTracker::end()) } * const cds = require('@sap/cds') * ``` */ -class CDSFacade extends ModuleImportNode { - CDSFacade() { isCds(this) } +class CdsFacade extends ModuleImportNode { + CdsFacade() { isCds(this) } } + +abstract class CqlBuilder extends SourceNode { } + +class Select extends CqlBuilder { } + +class Update extends CqlBuilder { } + +class Insert extends CqlBuilder { } + +class Delete extends CqlBuilder { } + +class Upsert extends CqlBuilder { } From b4b2ae57a077c4c4f316df4f137492c4c41af813 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 14 Sep 2023 13:52:32 -0700 Subject: [PATCH 04/61] Add SelectBuilder --- cap/CAPModels.qll | 57 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index 1df7fefb0..f6fb1d0a5 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -68,32 +68,57 @@ class Request extends ValueNode, ClassNode { } } -private ModuleImportNode isCdsInner(TypeTracker t) { - t.start() and - result.getPath() = "@sap/cds" - or - exists(TypeTracker t2 | result = isCdsInner(t2).track(t2, t)) -} - -predicate isCds(ModuleImportNode node) { node = isCdsInner(TypeTracker::end()) } - /** * ```js * const cds = require('@sap/cds') * ``` */ class CdsFacade extends ModuleImportNode { - CdsFacade() { isCds(this) } + CdsFacade() { this = moduleImport("@sap/cds") } } -abstract class CqlBuilder extends SourceNode { } +predicate selectCqlBuilder(TaggedTemplateExpr tagExpr) { + exists(Expr taggingExpr | taggingExpr = tagExpr.getTag() | + /* 1. SELECT `Bar` where SELECT is a local variable */ + taggingExpr.(VarRef).getName() = "SELECT" or + /* 2. SELECT `Bar` where SELECT is a global variable */ + taggingExpr.(GlobalVarAccess).getName() = "SELECT" or + /* 3. SELECT.one `Foo` or SELECT.from `Bar` */ + taggingExpr.(DotExpr).accesses(any(VarRef var | var.getName() = "SELECT"), _) or + selectCqlBuilder(taggingExpr.getAChildExpr()) + ) +} -class Select extends CqlBuilder { } +predicate deleteCqlBuilder(TaggedTemplateExpr tagExpr) { + exists(Expr taggingExpr | taggingExpr = tagExpr.getTag() | + taggingExpr.(VarRef).getName() = "DELETE" or + taggingExpr.(GlobalVarAccess).getName() = "DELETE" or + taggingExpr.(DotExpr).accesses(any(VarRef var | var.getName() = "DELETE"), _) or + deleteCqlBuilder(taggingExpr.getAChildExpr()) + ) +} -class Update extends CqlBuilder { } +abstract class CqlBuilder extends ValueNode { } -class Insert extends CqlBuilder { } +class Select extends CqlBuilder { + Select() { + exists(TaggedTemplateExpr tagExpr | + selectCqlBuilder(tagExpr) and this = tagExpr.flow() + ) + } +} -class Delete extends CqlBuilder { } +class Update extends CqlBuilder { +} + +class Insert extends CqlBuilder { + // Name's INSERT +} -class Upsert extends CqlBuilder { } +class Delete extends CqlBuilder { + // Name's DELETE +} + +class Upsert extends CqlBuilder { + // Name's UPSERT +} From 0ba335edbc6d4c16cfc82ffd66e175e1455c8536 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 18 Sep 2023 16:59:47 -0700 Subject: [PATCH 05/61] Checkpoint: Under construction --- cap/CAPModels.qll | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index f6fb1d0a5..ce092b4dc 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -6,12 +6,23 @@ abstract class Service extends ValueNode { } class ApplicationService extends Service { ApplicationService() { /* 1. Awaiting or directly getting return value of `cds.serve` */ - any() + // either CallExpr or AwaitExpr surrounding it + exists(MethodCallNode cdsServeCall | + any(CdsFacade cds).flowsTo(cdsServeCall.getReceiver()) and + cdsServeCall.getMethodName() = "serve" and + ( + this = cdsServeCall + or + this = any(AwaitExpr await).getOperand().flow() + ) + ) or - /* 2. From directly using the constructor: `new cds.ApplicationService` */ + /* 2. From directly using the constructor: `new cds.ApplicationService` or `new cds.Service` */ + // NewExpr any() or /* 3. Awaiting or directly getting return value of `cds.connect.to` */ + // either CallExpr or AwaitExpr surrounding it any() } } @@ -22,17 +33,18 @@ private class RequestHandler extends FunctionNode { } private class ErrorHandler extends RequestHandler { } /** - * Subclassing ApplicationService via `extends`: - * ```js - * class SomeService extends cds.ApplicationService - * ``` + * Subclassing ApplicationService via `extends`: + * ```js + * class SomeService extends cds.ApplicationService + * ``` */ class UserDefinedApplicationService extends ApplicationService, ClassNode { } /** - * Subclassing ApplicationService via `cds.service.impl`: + * Subclassing ApplicationService via `cds.service.impl`: * ```js - * cds.service.impl(() => {...}) + * const cds = require('@sap/cds') + * module.exports = cds.service.impl (function() { ... }) * ``` */ class OldStyleApplicationService extends UserDefinedApplicationService, ClassNode { } @@ -54,7 +66,7 @@ class DatabaseService extends Service, ClassNode { } class SqlService extends Service, ClassNode { } -class Request extends ValueNode, ClassNode { +class Request extends ValueNode, ParameterNode { Request() { /* * 1. Parameter of request handler of `srv.on`: @@ -102,14 +114,11 @@ abstract class CqlBuilder extends ValueNode { } class Select extends CqlBuilder { Select() { - exists(TaggedTemplateExpr tagExpr | - selectCqlBuilder(tagExpr) and this = tagExpr.flow() - ) + exists(TaggedTemplateExpr tagExpr | selectCqlBuilder(tagExpr) and this = tagExpr.flow()) } } -class Update extends CqlBuilder { -} +class Update extends CqlBuilder { } class Insert extends CqlBuilder { // Name's INSERT From 86bc412a08f534a0c3b404822010c615e7c38ac0 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 18 Sep 2023 17:44:25 -0700 Subject: [PATCH 06/61] Add more --- cap/CAPModels.qll | 72 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index ce092b4dc..c01ad473e 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -18,12 +18,20 @@ class ApplicationService extends Service { ) or /* 2. From directly using the constructor: `new cds.ApplicationService` or `new cds.Service` */ - // NewExpr - any() + exists(MethodCallNode cdsDotService, CdsFacade cds | + this = cdsDotService and + cdsDotService.getReceiver() = cds and + cdsDotService.getMethodName() = ["Service", "ApplicationService"] + ) or /* 3. Awaiting or directly getting return value of `cds.connect.to` */ - // either CallExpr or AwaitExpr surrounding it - any() + // TODO: Can be AwaitExpr surrounding it + exists(CdsFacade cds, PropRef cdsConnect | + this.(CallNode).getCalleeName() = "to" and + this.(CallNode).getReceiver() = cdsConnect and + cdsConnect.getPropertyName() = "connect" and + cdsConnect.getBase() = cds + ) } } @@ -38,16 +46,33 @@ private class ErrorHandler extends RequestHandler { } * class SomeService extends cds.ApplicationService * ``` */ -class UserDefinedApplicationService extends ApplicationService, ClassNode { } +class UserDefinedApplicationService extends ApplicationService, ClassNode { + UserDefinedApplicationService() { + exists(CdsFacade cdsFacade, PropRef cdsApplicationService | + this.getADirectSuperClass() = cdsApplicationService and + cdsApplicationService.getBase() = cdsFacade and + cdsApplicationService.getPropertyName() = "ApplicationService" + ) + } +} /** * Subclassing ApplicationService via `cds.service.impl`: * ```js * const cds = require('@sap/cds') - * module.exports = cds.service.impl (function() { ... }) + * module.exports = cds.service.impl (function() { ... }) * ``` */ -class OldStyleApplicationService extends UserDefinedApplicationService, ClassNode { } +class OldStyleApplicationService extends UserDefinedApplicationService, MethodCallNode { + OldStyleApplicationService() { + exists(PropRef cdsService, CdsFacade cds | + this.getMethodName() = "impl" and + this.getReceiver() = cdsService and + cdsService.getPropertyName() = "service" and + cdsService.getBase() = cds + ) + } +} /** * Parameter of a `srv.with` method call: @@ -56,7 +81,17 @@ class OldStyleApplicationService extends UserDefinedApplicationService, ClassNod * srv.on ('READ','Books', (req) => req.reply([...])) * }) */ -class WithCallParameter extends Service, ParameterNode { } +class WithCallParameter extends Service, ParameterNode { + WithCallParameter() { + exists(MethodCallNode withCall, MethodCallNode serveCall, CdsFacade cds | + withCall.getArgument(0) = this and + withCall.getMethodName() = "with" and + withCall.getReceiver() = serveCall and + serveCall.getMethodName() = "serve" and + serveCall.getReceiver() = cds + ) + } +} class RemoteService extends Service, ClassNode { } @@ -66,17 +101,20 @@ class DatabaseService extends Service, ClassNode { } class SqlService extends Service, ClassNode { } +/** + * Parameter of request handler of `srv.on`: + * ```js + * srv.on ('READ','Books', (req) => req.reply([...])) + * ``` + */ class Request extends ValueNode, ParameterNode { Request() { - /* - * 1. Parameter of request handler of `srv.on`: - * `srv.on ('READ','Books', (req) => req.reply([...]))` - */ - - any() - or - /* 2. Parameter of `srv.send` */ - any() + exists(MethodCallNode srvOn, Service srv, FunctionNode handler | + srvOn.getMethodName() = "on" and + srvOn.getReceiver() = srv and + srvOn.getLastArgument() = handler and + handler.getLastParameter() = this + ) } } From 340af897e29d4e0088c111e6bcf77c53ce70fb08 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 25 Sep 2023 17:12:33 -0700 Subject: [PATCH 07/61] Add some test cases --- cap/cql_test.js | 72 +++++++++++++++++++++++++++++++++++++++++++++ cap/service_test.js | 0 2 files changed, 72 insertions(+) create mode 100644 cap/cql_test.js create mode 100644 cap/service_test.js diff --git a/cap/cql_test.js b/cap/cql_test.js new file mode 100644 index 000000000..8fe1b7114 --- /dev/null +++ b/cap/cql_test.js @@ -0,0 +1,72 @@ +/* Simplest SELECTs without property accesses or method calls */ +var select = SELECT`Table`; + +/* SELECTs with property accesses */ +var select = SELECT.one.from`Table`; +var select = SELECT.one.from(Table); +var select = SELECT.distinct.from`Table`; +var select = SELECT.distinct.from(Table); + +/* SELECTs with method calls */ +// .columns() +var select = SELECT.from`Table`.columns`col1, col2`; +var select = SELECT.from`Table`.columns((data) => { + data.col1, data.col2; +}); +var select = SELECT.from`Table`.columns`{ col1, col2 as column }`; +var select = SELECT.from`Table`.columns("col1", "col2 as column"); +var select = SELECT.from`Table`.columns([ + "col1", + { ref: ["col2", "prop"], as: "property" }, +]); +var select = SELECT.from`Table`.columns("col1", { + ref: ["col2", "prop"], + as: "property", +}); + +// .where() +var select = SELECT.from`Table`.where(); + +/* SELECTS with property access and method calls */ + +/* + - Property: .one + - const one = await SELECT.one.from (Authors) + - const [one] = await SELECT.from (Authors) + - Property: .distinct + - SELECT.distinct.from (Authors) + - Method: .columns() + - SELECT.from `Books` .columns (b => { b.title, b.author.name.as('author') }) + - SELECT.from `Books` .columns `{ title, author.name as author }` + - SELECT.from `Books` .columns `title, author.name as author` + - SELECT.from `Books` .columns ( 'title', 'author.name as author') + - SELECT.from `Books` .columns ( 'title', {ref:['author','name'],as:'author'} ) + - SELECT.from `Books` .columns (['title', {ref:['author','name'],as:'author'} ]) + - Method: .from() + - SELECT.from (Books,201) + - SELECT.from (Books,201, b => { b.ID, b.title }) + - SELECT.one.from (Books) .where ({ID:201}) + - SELECT.one.from (Books) .where ({ID:201}) .columns (b => { b.ID, b.title }) + - Method: .alias() + - SELECT.from ('Authors').alias('a').where({ exists: SELECT.from('Books').where('author_ID = a.ID')}) + - Method: .where() + - Method: .having() + - Method: .groupBy() + - Method: .orderBy() + - Method: .limit() + - Method: forUpdate() + - Method: forShareLock() + */ + +/* CQL tagged function */ +CQL`SELECT col1, col2, col3 from Table`; + +/* JSON literal queries */ + +var select = { + SELECT: { + one: true, + columns: [{ ref: ["Foo"] }, { ref: ["Boo"] }, { ref: ["Moo"] }], + from: { ref: ["Bar"] }, + }, +}; diff --git a/cap/service_test.js b/cap/service_test.js new file mode 100644 index 000000000..e69de29bb From 302b3292700ad06a517838d2ef04d7080abf1c5f Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 25 Sep 2023 17:51:51 -0700 Subject: [PATCH 08/61] Add `groupBy` and `having` --- cap/cql_test.js | 182 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 152 insertions(+), 30 deletions(-) diff --git a/cap/cql_test.js b/cap/cql_test.js index 8fe1b7114..7ac6ab3af 100644 --- a/cap/cql_test.js +++ b/cap/cql_test.js @@ -24,39 +24,161 @@ var select = SELECT.from`Table`.columns("col1", { as: "property", }); +var select = SELECT.from(Table).columns`col1, col2`; +var select = SELECT.from(Table).columns((data) => { + data.col1, data.col2; +}); +var select = SELECT.from(Table).columns`{ col1, col2 as column }`; +var select = SELECT.from(Table).columns("col1", "col2 as column"); +var select = SELECT.from(Table).columns([ + "col1", + { ref: ["col2", "prop"], as: "property" }, +]); +var select = SELECT.from(Table).columns("col1", { + ref: ["col2", "prop"], + as: "property", +}); + // .where() -var select = SELECT.from`Table`.where(); +var select = SELECT.from`Table`.where({ col1: "*" }); +var select = SELECT.from`Table`.where("col1='*'"); +var select = SELECT.from`Table`.where`"col1='*'"`; +var select = SELECT.from`Table`.where("col1=", "*"); +var select = SELECT.from`Table`.where`col = ${"*"}`; +var select = SELECT.from`Table`.where("col1 in ('*', 10)"); +var select = SELECT.from`Table`.where`col1 in ${[("*", 10)]}`; +var select = SELECT.from`Table`.where({ col1: 10, and: { col2: 11 } }); -/* SELECTS with property access and method calls */ +// .groupBy() +var select = SELECT.from`Table`.groupBy("col1", "col2"); +var select = SELECT.from`Table`.groupBy`col1, col2`; +var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2"); +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`; +var select = SELECT.from`Table`.groupBy( + { ref: ["col1", "prop1"] }, + { ref: ["col2", "prop2"] } +); + +// .having() +var select = SELECT.from`Table`.having({ col1: "*" }); +var select = SELECT.from`Table`.having("col1='*'"); +var select = SELECT.from`Table`.having`"col1='*'"`; +var select = SELECT.from`Table`.having("col1=", "*"); +var select = SELECT.from`Table`.having`col = ${"*"}`; +var select = SELECT.from`Table`.having("col1 in ('*', 10)"); +var select = SELECT.from`Table`.having`col1 in ${[("*", 10)]}`; +var select = SELECT.from`Table`.having({ col1: 10, and: { col2: 11 } }); -/* - - Property: .one - - const one = await SELECT.one.from (Authors) - - const [one] = await SELECT.from (Authors) - - Property: .distinct - - SELECT.distinct.from (Authors) - - Method: .columns() - - SELECT.from `Books` .columns (b => { b.title, b.author.name.as('author') }) - - SELECT.from `Books` .columns `{ title, author.name as author }` - - SELECT.from `Books` .columns `title, author.name as author` - - SELECT.from `Books` .columns ( 'title', 'author.name as author') - - SELECT.from `Books` .columns ( 'title', {ref:['author','name'],as:'author'} ) - - SELECT.from `Books` .columns (['title', {ref:['author','name'],as:'author'} ]) - - Method: .from() - - SELECT.from (Books,201) - - SELECT.from (Books,201, b => { b.ID, b.title }) - - SELECT.one.from (Books) .where ({ID:201}) - - SELECT.one.from (Books) .where ({ID:201}) .columns (b => { b.ID, b.title }) - - Method: .alias() - - SELECT.from ('Authors').alias('a').where({ exists: SELECT.from('Books').where('author_ID = a.ID')}) - - Method: .where() - - Method: .having() - - Method: .groupBy() - - Method: .orderBy() - - Method: .limit() - - Method: forUpdate() - - Method: forShareLock() - */ +var select = SELECT.from`Table`.groupBy("col1", "col2").having({ col1: "*" }); +var select = SELECT.from`Table`.groupBy("col1", "col2").having("col1='*'"); +var select = SELECT.from`Table`.groupBy("col1", "col2").having`"col1='*'"`; +var select = SELECT.from`Table`.groupBy("col1", "col2").having("col1=", "*"); +var select = SELECT.from`Table`.groupBy("col1", "col2").having`col = ${"*"}`; +var select = SELECT.from`Table` + .groupBy("col1", "col2") + .having("col1 in ('*', 10)"); +var select = SELECT.from`Table`.groupBy("col1", "col2").having`col1 in ${[ + ("*", 10), +]}`; +var select = SELECT.from`Table` + .groupBy("col1", "col2") + .having({ col1: 10, and: { col2: 11 } }); + +var select = SELECT.from`Table`.groupBy`col1, col2`.having({ col1: "*" }); +var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1='*'"); +var select = SELECT.from`Table`.groupBy`col1, col2`.having`"col1='*'"`; +var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1=", "*"); +var select = SELECT.from`Table`.groupBy`col1, col2`.having`col = ${"*"}`; +var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1 in ('*', 10)"); +var select = SELECT.from`Table`.groupBy`col1, col2`.having`col1 in ${[ + ("*", 10), +]}`; +var select = SELECT.from`Table`.groupBy`col1, col2`.having({ + col1: 10, + and: { col2: 11 }, +}); + +var select = SELECT.from`Table` + .groupBy("col1.prop1", "col2.prop2") + .having({ col1: "*" }); +var select = SELECT.from`Table` + .groupBy("col1.prop1", "col2.prop2") + .having("col1='*'"); +var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") + .having`"col1='*'"`; +var select = SELECT.from`Table` + .groupBy("col1.prop1", "col2.prop2") + .having("col1=", "*"); +var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") + .having`col = ${"*"}`; +var select = SELECT.from`Table` + .groupBy("col1.prop1", "col2.prop2") + .having("col1 in ('*', 10)"); +var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") + .having`col1 in ${[("*", 10)]}`; +var select = SELECT.from`Table` + .groupBy("col1.prop1", "col2.prop2") + .having({ col1: 10, and: { col2: 11 } }); + +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having({ + col1: "*", +}); +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( + "col1='*'" +); +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` + .having`"col1='*'"`; +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( + "col1=", + "*" +); +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` + .having`col = ${"*"}`; +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( + "col1 in ('*', 10)" +); +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` + .having`col1 in ${[("*", 10)]}`; +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having({ + col1: 10, + and: { col2: 11 }, +}); + +var select = SELECT.from`Table` + .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) + .having({ col1: "*" }); +var select = SELECT.from`Table` + .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) + .having("col1='*'"); +var select = SELECT.from`Table`.groupBy( + { ref: ["col1", "prop1"] }, + { ref: ["col2", "prop2"] } +).having`"col1='*'"`; +var select = SELECT.from`Table` + .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) + .having("col1=", "*"); +var select = SELECT.from`Table`.groupBy( + { ref: ["col1", "prop1"] }, + { ref: ["col2", "prop2"] } +).having`col = ${"*"}`; +var select = SELECT.from`Table` + .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) + .having("col1 in ('*', 10)"); +var select = SELECT.from`Table`.groupBy( + { ref: ["col1", "prop1"] }, + { ref: ["col2", "prop2"] } +).having`col1 in ${[("*", 10)]}`; +var select = SELECT.from`Table` + .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) + .having({ col1: 10, and: { col2: 11 } }); + +// .orderBy() +// .limit() +// .forUpdate() +// .forShareLock() + +/* SELECTS with property access and method calls */ +TODO; /* CQL tagged function */ CQL`SELECT col1, col2, col3 from Table`; From ebb110ea11b44ace72f86f49e6cc8e0711a383f7 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 26 Sep 2023 12:24:48 -0700 Subject: [PATCH 09/61] Finalize SELECT draft except CQN and CQL obj --- cap/cql_test.js | 52 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/cap/cql_test.js b/cap/cql_test.js index 7ac6ab3af..ccff4cdcd 100644 --- a/cap/cql_test.js +++ b/cap/cql_test.js @@ -1,20 +1,20 @@ /* Simplest SELECTs without property accesses or method calls */ var select = SELECT`Table`; -/* SELECTs with property accesses */ +/* ========== SELECTs with property accesses ========== */ var select = SELECT.one.from`Table`; var select = SELECT.one.from(Table); var select = SELECT.distinct.from`Table`; var select = SELECT.distinct.from(Table); -/* SELECTs with method calls */ +/* ========== SELECTs with method calls ========== */ // .columns() var select = SELECT.from`Table`.columns`col1, col2`; var select = SELECT.from`Table`.columns((data) => { data.col1, data.col2; }); -var select = SELECT.from`Table`.columns`{ col1, col2 as column }`; -var select = SELECT.from`Table`.columns("col1", "col2 as column"); +var select = SELECT.from`Table`.columns`{ col1, col2 as col2Alias }`; +var select = SELECT.from`Table`.columns("col1", "col2 as col2Alias"); var select = SELECT.from`Table`.columns([ "col1", { ref: ["col2", "prop"], as: "property" }, @@ -28,8 +28,8 @@ var select = SELECT.from(Table).columns`col1, col2`; var select = SELECT.from(Table).columns((data) => { data.col1, data.col2; }); -var select = SELECT.from(Table).columns`{ col1, col2 as column }`; -var select = SELECT.from(Table).columns("col1", "col2 as column"); +var select = SELECT.from(Table).columns`{ col1, col2 as col2Alias }`; +var select = SELECT.from(Table).columns("col1", "col2 as col2Alias"); var select = SELECT.from(Table).columns([ "col1", { ref: ["col2", "prop"], as: "property" }, @@ -173,17 +173,47 @@ var select = SELECT.from`Table` .having({ col1: 10, and: { col2: 11 } }); // .orderBy() +var select = SELECT.from`Table`.orderBy`col1.prop1, col2.prop2`; +var select = SELECT.from`Table`.orderBy`col1 asc, col2.prop2`; +var select = SELECT.from`Table`.orderBy`col1.prop1, col2 asc`; +var select = SELECT.from`Table`.orderBy`col1 asc col2 asc`; +var select = SELECT.from`Table`.orderBy`col1.prop1, col2.prop2`; +var select = SELECT.from`Table`.orderBy`col1 desc, col2.prop2`; +var select = SELECT.from`Table`.orderBy`col1.prop1, col2 desc`; +var select = SELECT.from`Table`.orderBy`col1 desc col2 desc`; + // .limit() +var select = SELECT.from`Table`.limit(10); +var select = SELECT.from`Table`.limit(10, 20); +var select = SELECT.from`Table`.limit({ val: 10 }); +var select = SELECT.from`Table`.limit({ val: 10 }, { val: 20 }); +var select = SELECT.from`Table`.limit({ ref: ["limitVal"] }); +var select = SELECT.from`Table`.limit({ + ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], +}); + // .forUpdate() -// .forShareLock() +var select = SELECT.from`Table`.groupBy`col1, col2` + .having`col = ${"*"}`.forUpdate(); -/* SELECTS with property access and method calls */ -TODO; +// .forShareLock() +var select = SELECT.from`Table`.groupBy`col1, col2` + .having`col = ${"*"}`.forShareLock(); -/* CQL tagged function */ +/* ========== SELECTS with property access and method calls ========== */ +var select = SELECT.distinct.from`Table`.where`col1 in ${[("*", 10)]}`.groupBy( + "col1", + "col2" +).having`col1 in ${[("*", 10)]}` + .limit({ + ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], + }) + .forShareLock(); + +/* ========== CQL tagged function ========== */ CQL`SELECT col1, col2, col3 from Table`; -/* JSON literal queries */ +/* ========== JSON literal queries ========== */ var select = { SELECT: { From c1e0b9b56d605ddcfd1bb11b20c8d523b3ec30de Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 26 Sep 2023 12:30:27 -0700 Subject: [PATCH 10/61] Add orderBy to SELECT with propaccess and methodcall --- cap/cql_test.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cap/cql_test.js b/cap/cql_test.js index ccff4cdcd..49021e6a2 100644 --- a/cap/cql_test.js +++ b/cap/cql_test.js @@ -204,11 +204,9 @@ var select = SELECT.from`Table`.groupBy`col1, col2` var select = SELECT.distinct.from`Table`.where`col1 in ${[("*", 10)]}`.groupBy( "col1", "col2" -).having`col1 in ${[("*", 10)]}` - .limit({ - ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], - }) - .forShareLock(); +).having`col1 in ${[("*", 10)]}`.limit({ + ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], +}).orderBy`col1 desc, col2.prop2`.forShareLock(); /* ========== CQL tagged function ========== */ CQL`SELECT col1, col2, col3 from Table`; From a1005b9b1fed5d4ce14ab9ecd29196dea029aa93 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 26 Sep 2023 13:13:37 -0700 Subject: [PATCH 11/61] Add parsed CQL object cases --- cap/cql_test.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/cap/cql_test.js b/cap/cql_test.js index 49021e6a2..eadf53ca5 100644 --- a/cap/cql_test.js +++ b/cap/cql_test.js @@ -213,6 +213,12 @@ CQL`SELECT col1, col2, col3 from Table`; /* ========== JSON literal queries ========== */ +var select = { + SELECT: { + from: { ref: ["Bar"] }, + }, +}; + var select = { SELECT: { one: true, @@ -220,3 +226,16 @@ var select = { from: { ref: ["Bar"] }, }, }; + +var select = { + SELECT: { + distinct: true, + columns: [{ ref: ["Foo"] }, { ref: ["Boo"] }, { ref: ["Moo"] }], + from: { ref: ["Bar"] }, + limit: { + rows: { val: 7 }, + }, + where: [{ ref: ["col1"] }, ">", { val: 2 }], + groupBy: [{ ref: ["col1"] }, { ref: ["col2", "prop2"] }], + }, +}; From f251685748407aef5255ffb4799170da42f8491d Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 26 Sep 2023 13:19:01 -0700 Subject: [PATCH 12/61] Rename cql_test to select and nest folders --- cap/{cql_test.js => test/cql/select.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cap/{cql_test.js => test/cql/select.js} (100%) diff --git a/cap/cql_test.js b/cap/test/cql/select.js similarity index 100% rename from cap/cql_test.js rename to cap/test/cql/select.js From 71dc61b67ac9eb11dafa0b11caf6f6d2c55a2f20 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 26 Sep 2023 15:23:32 -0700 Subject: [PATCH 13/61] Add test for Select --- cap/CAPModels.qll | 22 ++++-- cap/codeql-pack.lock.yml | 12 ++-- cap/qlpack.yml | 4 +- cap/test/codeql-pack.lock.yml | 20 ++++++ cap/test/cql/select.expected | 128 ++++++++++++++++++++++++++++++++++ cap/test/cql/select.ql | 4 ++ cap/test/qlpack.yml | 8 +++ 7 files changed, 185 insertions(+), 13 deletions(-) create mode 100644 cap/test/codeql-pack.lock.yml create mode 100644 cap/test/cql/select.expected create mode 100644 cap/test/cql/select.ql create mode 100644 cap/test/qlpack.yml diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index c01ad473e..2b0da2624 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -156,16 +156,30 @@ class Select extends CqlBuilder { } } -class Update extends CqlBuilder { } +class Update extends CqlBuilder { + Update() { + // TODO + exists(TaggedTemplateExpr tagExpr | selectCqlBuilder(tagExpr) and this = tagExpr.flow()) + } +} class Insert extends CqlBuilder { - // Name's INSERT + Insert() { + // TODO + exists(TaggedTemplateExpr tagExpr | selectCqlBuilder(tagExpr) and this = tagExpr.flow()) + } } class Delete extends CqlBuilder { - // Name's DELETE + Delete() { + // TODO + exists(TaggedTemplateExpr tagExpr | selectCqlBuilder(tagExpr) and this = tagExpr.flow()) + } } class Upsert extends CqlBuilder { - // Name's UPSERT + Upsert() { + // TODO + exists(TaggedTemplateExpr tagExpr | selectCqlBuilder(tagExpr) and this = tagExpr.flow()) + } } diff --git a/cap/codeql-pack.lock.yml b/cap/codeql-pack.lock.yml index 2e92bb9d4..f8b362092 100644 --- a/cap/codeql-pack.lock.yml +++ b/cap/codeql-pack.lock.yml @@ -2,15 +2,13 @@ lockVersion: 1.0.0 dependencies: codeql/javascript-all: - version: 0.7.2 - codeql/mad: - version: 0.1.2 + version: 0.6.4 codeql/regex: - version: 0.1.2 + version: 0.0.15 codeql/tutorial: - version: 0.1.2 + version: 0.0.12 codeql/util: - version: 0.1.2 + version: 0.0.12 codeql/yaml: - version: 0.1.2 + version: 0.0.4 compiled: false diff --git a/cap/qlpack.yml b/cap/qlpack.yml index b8ace3e7f..0289ede45 100644 --- a/cap/qlpack.yml +++ b/cap/qlpack.yml @@ -1,7 +1,7 @@ --- library: false warnOnImplicitThis: false -name: advanced-security/cap +name: advanced-security/javascript-sap-cap-models version: 0.0.1 dependencies: - codeql/javascript-all: "*" \ No newline at end of file + codeql/javascript-all: "^0.6.3" \ No newline at end of file diff --git a/cap/test/codeql-pack.lock.yml b/cap/test/codeql-pack.lock.yml new file mode 100644 index 000000000..79d3aa8c2 --- /dev/null +++ b/cap/test/codeql-pack.lock.yml @@ -0,0 +1,20 @@ +--- +lockVersion: 1.0.0 +dependencies: + codeql/javascript-all: + version: 0.6.4 + codeql/javascript-queries: + version: 0.6.4 + codeql/regex: + version: 0.0.15 + codeql/suite-helpers: + version: 0.5.4 + codeql/tutorial: + version: 0.0.12 + codeql/typos: + version: 0.0.19 + codeql/util: + version: 0.0.12 + codeql/yaml: + version: 0.0.4 +compiled: false diff --git a/cap/test/cql/select.expected b/cap/test/cql/select.expected new file mode 100644 index 000000000..01ef7236a --- /dev/null +++ b/cap/test/cql/select.expected @@ -0,0 +1,128 @@ +| select.js:2:14:2:26 | SELECT`Table` | +| select.js:12:14:12:31 | SELECT.from`Table` | +| select.js:12:14:12:51 | SELECT. ... , col2` | +| select.js:13:14:13:31 | SELECT.from`Table` | +| select.js:16:14:16:31 | SELECT.from`Table` | +| select.js:16:14:16:68 | SELECT. ... lias }` | +| select.js:17:14:17:31 | SELECT.from`Table` | +| select.js:18:14:18:31 | SELECT.from`Table` | +| select.js:22:14:22:31 | SELECT.from`Table` | +| select.js:43:14:43:31 | SELECT.from`Table` | +| select.js:44:14:44:31 | SELECT.from`Table` | +| select.js:45:14:45:31 | SELECT.from`Table` | +| select.js:45:14:45:49 | SELECT. ... 1='*'"` | +| select.js:46:14:46:31 | SELECT.from`Table` | +| select.js:47:14:47:31 | SELECT.from`Table` | +| select.js:47:14:47:51 | SELECT. ... ${"*"}` | +| select.js:48:14:48:31 | SELECT.from`Table` | +| select.js:49:14:49:31 | SELECT.from`Table` | +| select.js:49:14:49:61 | SELECT. ... 10)]}` | +| select.js:50:14:50:31 | SELECT.from`Table` | +| select.js:53:14:53:31 | SELECT.from`Table` | +| select.js:54:14:54:31 | SELECT.from`Table` | +| select.js:54:14:54:51 | SELECT. ... , col2` | +| select.js:55:14:55:31 | SELECT.from`Table` | +| select.js:56:14:56:31 | SELECT.from`Table` | +| select.js:56:14:56:63 | SELECT. ... .prop2` | +| select.js:57:14:57:31 | SELECT.from`Table` | +| select.js:63:14:63:31 | SELECT.from`Table` | +| select.js:64:14:64:31 | SELECT.from`Table` | +| select.js:65:14:65:31 | SELECT.from`Table` | +| select.js:65:14:65:50 | SELECT. ... 1='*'"` | +| select.js:66:14:66:31 | SELECT.from`Table` | +| select.js:67:14:67:31 | SELECT.from`Table` | +| select.js:67:14:67:52 | SELECT. ... ${"*"}` | +| select.js:68:14:68:31 | SELECT.from`Table` | +| select.js:69:14:69:31 | SELECT.from`Table` | +| select.js:69:14:69:62 | SELECT. ... 10)]}` | +| select.js:70:14:70:31 | SELECT.from`Table` | +| select.js:72:14:72:31 | SELECT.from`Table` | +| select.js:73:14:73:31 | SELECT.from`Table` | +| select.js:74:14:74:31 | SELECT.from`Table` | +| select.js:75:14:75:31 | SELECT.from`Table` | +| select.js:76:14:76:31 | SELECT.from`Table` | +| select.js:77:14:77:31 | SELECT.from`Table` | +| select.js:80:14:80:31 | SELECT.from`Table` | +| select.js:83:14:83:31 | SELECT.from`Table` | +| select.js:87:14:87:31 | SELECT.from`Table` | +| select.js:87:14:87:51 | SELECT. ... , col2` | +| select.js:88:14:88:31 | SELECT.from`Table` | +| select.js:88:14:88:51 | SELECT. ... , col2` | +| select.js:89:14:89:31 | SELECT.from`Table` | +| select.js:89:14:89:51 | SELECT. ... , col2` | +| select.js:89:14:89:70 | SELECT. ... 1='*'"` | +| select.js:90:14:90:31 | SELECT.from`Table` | +| select.js:90:14:90:51 | SELECT. ... , col2` | +| select.js:91:14:91:31 | SELECT.from`Table` | +| select.js:91:14:91:51 | SELECT. ... , col2` | +| select.js:91:14:91:72 | SELECT. ... ${"*"}` | +| select.js:92:14:92:31 | SELECT.from`Table` | +| select.js:92:14:92:51 | SELECT. ... , col2` | +| select.js:93:14:93:31 | SELECT.from`Table` | +| select.js:93:14:93:51 | SELECT. ... , col2` | +| select.js:93:14:95:3 | SELECT. ... 0),\\n]}` | +| select.js:96:14:96:31 | SELECT.from`Table` | +| select.js:96:14:96:51 | SELECT. ... , col2` | +| select.js:101:14:101:31 | SELECT.from`Table` | +| select.js:104:14:104:31 | SELECT.from`Table` | +| select.js:107:14:107:31 | SELECT.from`Table` | +| select.js:109:14:109:31 | SELECT.from`Table` | +| select.js:112:14:112:31 | SELECT.from`Table` | +| select.js:114:14:114:31 | SELECT.from`Table` | +| select.js:117:14:117:31 | SELECT.from`Table` | +| select.js:119:14:119:31 | SELECT.from`Table` | +| select.js:123:14:123:31 | SELECT.from`Table` | +| select.js:123:14:123:63 | SELECT. ... .prop2` | +| select.js:126:14:126:31 | SELECT.from`Table` | +| select.js:126:14:126:63 | SELECT. ... .prop2` | +| select.js:129:14:129:31 | SELECT.from`Table` | +| select.js:129:14:129:63 | SELECT. ... .prop2` | +| select.js:129:14:130:21 | SELECT. ... 1='*'"` | +| select.js:131:14:131:31 | SELECT.from`Table` | +| select.js:131:14:131:63 | SELECT. ... .prop2` | +| select.js:135:14:135:31 | SELECT.from`Table` | +| select.js:135:14:135:63 | SELECT. ... .prop2` | +| select.js:135:14:136:23 | SELECT. ... ${"*"}` | +| select.js:137:14:137:31 | SELECT.from`Table` | +| select.js:137:14:137:63 | SELECT. ... .prop2` | +| select.js:140:14:140:31 | SELECT.from`Table` | +| select.js:140:14:140:63 | SELECT. ... .prop2` | +| select.js:140:14:141:33 | SELECT. ... 10)]}` | +| select.js:142:14:142:31 | SELECT.from`Table` | +| select.js:142:14:142:63 | SELECT. ... .prop2` | +| select.js:147:14:147:31 | SELECT.from`Table` | +| select.js:150:14:150:31 | SELECT.from`Table` | +| select.js:153:14:153:31 | SELECT.from`Table` | +| select.js:157:14:157:31 | SELECT.from`Table` | +| select.js:160:14:160:31 | SELECT.from`Table` | +| select.js:164:14:164:31 | SELECT.from`Table` | +| select.js:167:14:167:31 | SELECT.from`Table` | +| select.js:171:14:171:31 | SELECT.from`Table` | +| select.js:176:14:176:31 | SELECT.from`Table` | +| select.js:176:14:176:63 | SELECT. ... .prop2` | +| select.js:177:14:177:31 | SELECT.from`Table` | +| select.js:177:14:177:61 | SELECT. ... .prop2` | +| select.js:178:14:178:31 | SELECT.from`Table` | +| select.js:178:14:178:61 | SELECT. ... l2 asc` | +| select.js:179:14:179:31 | SELECT.from`Table` | +| select.js:179:14:179:58 | SELECT. ... l2 asc` | +| select.js:180:14:180:31 | SELECT.from`Table` | +| select.js:180:14:180:63 | SELECT. ... .prop2` | +| select.js:181:14:181:31 | SELECT.from`Table` | +| select.js:181:14:181:62 | SELECT. ... .prop2` | +| select.js:182:14:182:31 | SELECT.from`Table` | +| select.js:182:14:182:62 | SELECT. ... 2 desc` | +| select.js:183:14:183:31 | SELECT.from`Table` | +| select.js:183:14:183:60 | SELECT. ... 2 desc` | +| select.js:186:14:186:31 | SELECT.from`Table` | +| select.js:187:14:187:31 | SELECT.from`Table` | +| select.js:188:14:188:31 | SELECT.from`Table` | +| select.js:189:14:189:31 | SELECT.from`Table` | +| select.js:190:14:190:31 | SELECT.from`Table` | +| select.js:191:14:191:31 | SELECT.from`Table` | +| select.js:196:14:196:31 | SELECT.from`Table` | +| select.js:196:14:196:51 | SELECT. ... , col2` | +| select.js:196:14:197:23 | SELECT. ... ${"*"}` | +| select.js:200:14:200:31 | SELECT.from`Table` | +| select.js:200:14:200:51 | SELECT. ... , col2` | +| select.js:200:14:201:23 | SELECT. ... ${"*"}` | diff --git a/cap/test/cql/select.ql b/cap/test/cql/select.ql new file mode 100644 index 000000000..da95f7305 --- /dev/null +++ b/cap/test/cql/select.ql @@ -0,0 +1,4 @@ +import javascript +import CAPModels + +select any(Select s) \ No newline at end of file diff --git a/cap/test/qlpack.yml b/cap/test/qlpack.yml new file mode 100644 index 000000000..973a4c08b --- /dev/null +++ b/cap/test/qlpack.yml @@ -0,0 +1,8 @@ +name: advanced-security/javascript-sap-cap-models-tests +version: 0.0.1 +extractor: javascript +dependencies: + codeql/javascript-all: "^0.6.3" + codeql/javascript-queries: "^0.6.3" + advanced-security/javascript-sap-cap-models: "^0.0.1" + # advanced-security/javascript-sap-cap-extensions: "^0.0.1" From 66a72b0f0a25752e2c1f79608a1f43f33b028b7a Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 26 Sep 2023 15:48:56 -0700 Subject: [PATCH 14/61] Capture `SELECT.one.from` syntax --- cap/CAPModels.qll | 11 +++++++---- cap/test/cql/select.expected | 4 ++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index 2b0da2624..085baa285 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -129,16 +129,19 @@ class CdsFacade extends ModuleImportNode { predicate selectCqlBuilder(TaggedTemplateExpr tagExpr) { exists(Expr taggingExpr | taggingExpr = tagExpr.getTag() | - /* 1. SELECT `Bar` where SELECT is a local variable */ + /* SELECT `Bar` */ taggingExpr.(VarRef).getName() = "SELECT" or - /* 2. SELECT `Bar` where SELECT is a global variable */ - taggingExpr.(GlobalVarAccess).getName() = "SELECT" or - /* 3. SELECT.one `Foo` or SELECT.from `Bar` */ + /* SELECT.one `Foo`, SELECT.from `Bar` */ taggingExpr.(DotExpr).accesses(any(VarRef var | var.getName() = "SELECT"), _) or + taggingExpr + .(DotExpr) + .accesses(any(DotExpr var | var.accesses(any(VarRef var_ | var_.getName() = "SELECT"), _)), + _) or selectCqlBuilder(taggingExpr.getAChildExpr()) ) } +// SELECT.one.from`Table` predicate deleteCqlBuilder(TaggedTemplateExpr tagExpr) { exists(Expr taggingExpr | taggingExpr = tagExpr.getTag() | taggingExpr.(VarRef).getName() = "DELETE" or diff --git a/cap/test/cql/select.expected b/cap/test/cql/select.expected index 01ef7236a..e0138ea78 100644 --- a/cap/test/cql/select.expected +++ b/cap/test/cql/select.expected @@ -1,4 +1,6 @@ | select.js:2:14:2:26 | SELECT`Table` | +| select.js:5:14:5:35 | SELECT. ... `Table` | +| select.js:7:14:7:40 | SELECT. ... `Table` | | select.js:12:14:12:31 | SELECT.from`Table` | | select.js:12:14:12:51 | SELECT. ... , col2` | | select.js:13:14:13:31 | SELECT.from`Table` | @@ -126,3 +128,5 @@ | select.js:200:14:200:31 | SELECT.from`Table` | | select.js:200:14:200:51 | SELECT. ... , col2` | | select.js:200:14:201:23 | SELECT. ... ${"*"}` | +| select.js:204:14:204:40 | SELECT. ... `Table` | +| select.js:204:14:204:70 | SELECT. ... 10)]}` | From b03babb2b74f192e860734437ac2c096606daf6a Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 27 Sep 2023 14:58:35 -0700 Subject: [PATCH 15/61] Turn more tests to green --- cap/CAPModels.qll | 28 +++++++++++++++++++++++++++- cap/test/cql/select.js | 2 ++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index 085baa285..031277946 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -133,6 +133,7 @@ predicate selectCqlBuilder(TaggedTemplateExpr tagExpr) { taggingExpr.(VarRef).getName() = "SELECT" or /* SELECT.one `Foo`, SELECT.from `Bar` */ taggingExpr.(DotExpr).accesses(any(VarRef var | var.getName() = "SELECT"), _) or + /* SELECT.one.from`Table` */ taggingExpr .(DotExpr) .accesses(any(DotExpr var | var.accesses(any(VarRef var_ | var_.getName() = "SELECT"), _)), @@ -141,7 +142,32 @@ predicate selectCqlBuilder(TaggedTemplateExpr tagExpr) { ) } -// SELECT.one.from`Table` +private predicate accessesSelect(DotExpr dot) { + dot.accesses(any(VarRef var | var.getName() = "SELECT"), _) + or + accessesSelect(dot.getAChildExpr()) +} + +/** Tagged SELECTs with property accesses */ +predicate accessesSelectTagged(TaggedTemplateExpr tagExpr) { accessesSelect(tagExpr.getTag()) } + +/** Nested Tagged SELECTs (includes accessesSelectTagged: Tagged SELECTs with property accesses) */ +predicate nestedSelectTaggedTemplate(TaggedTemplateExpr tagExpr) { + // tagExpr = SELECT.from`Table`.columns`col1, col2` + exists(Expr taggingExpr | taggingExpr = tagExpr.getTag() | + // taggingExpr = SELECT.from`Table`.columns + // base + accessesSelect(taggingExpr) + or + // recursive + exists(TaggedTemplateExpr nestedTaggingExpr | + taggingExpr.(DotExpr).accesses(nestedTaggingExpr, _) + | + nestedSelectTaggedTemplate(nestedTaggingExpr) + ) + ) +} + predicate deleteCqlBuilder(TaggedTemplateExpr tagExpr) { exists(Expr taggingExpr | taggingExpr = tagExpr.getTag() | taggingExpr.(VarRef).getName() = "DELETE" or diff --git a/cap/test/cql/select.js b/cap/test/cql/select.js index eadf53ca5..912d977f2 100644 --- a/cap/test/cql/select.js +++ b/cap/test/cql/select.js @@ -6,6 +6,8 @@ var select = SELECT.one.from`Table`; var select = SELECT.one.from(Table); var select = SELECT.distinct.from`Table`; var select = SELECT.distinct.from(Table); +var select = SELECT.one.two.three.distinct.from(Table); +var select = SELECT.one.two.three.distinct.from`Table`; /* ========== SELECTs with method calls ========== */ // .columns() From 8d3ea62f1287399a7c62ffa29bd15a1d9c3d182a Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 28 Sep 2023 15:02:27 -0700 Subject: [PATCH 16/61] Add variants which uses TaggedTemplate instead of MethodCall and vice versa --- cap/test/cql/select.js | 76 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/cap/test/cql/select.js b/cap/test/cql/select.js index 912d977f2..37196f687 100644 --- a/cap/test/cql/select.js +++ b/cap/test/cql/select.js @@ -51,6 +51,15 @@ var select = SELECT.from`Table`.where("col1 in ('*', 10)"); var select = SELECT.from`Table`.where`col1 in ${[("*", 10)]}`; var select = SELECT.from`Table`.where({ col1: 10, and: { col2: 11 } }); +var select = SELECT.from(Table).where({ col1: "*" }); +var select = SELECT.from(Table).where("col1='*'"); +var select = SELECT.from(Table).where`"col1='*'"`; +var select = SELECT.from(Table).where("col1=", "*"); +var select = SELECT.from(Table).where`col = ${"*"}`; +var select = SELECT.from(Table).where("col1 in ('*', 10)"); +var select = SELECT.from(Table).where`col1 in ${[("*", 10)]}`; +var select = SELECT.from(Table).where({ col1: 10, and: { col2: 11 } }); + // .groupBy() var select = SELECT.from`Table`.groupBy("col1", "col2"); var select = SELECT.from`Table`.groupBy`col1, col2`; @@ -61,6 +70,15 @@ var select = SELECT.from`Table`.groupBy( { ref: ["col2", "prop2"] } ); +var select = SELECT.from(Table).groupBy("col1", "col2"); +var select = SELECT.from(Table).groupBy`col1, col2`; +var select = SELECT.from(Table).groupBy("col1.prop1", "col2.prop2"); +var select = SELECT.from(Table).groupBy`col1.prop1, col2.prop2`; +var select = SELECT.from(Table).groupBy( + { ref: ["col1", "prop1"] }, + { ref: ["col2", "prop2"] } +); + // .having() var select = SELECT.from`Table`.having({ col1: "*" }); var select = SELECT.from`Table`.having("col1='*'"); @@ -71,6 +89,15 @@ var select = SELECT.from`Table`.having("col1 in ('*', 10)"); var select = SELECT.from`Table`.having`col1 in ${[("*", 10)]}`; var select = SELECT.from`Table`.having({ col1: 10, and: { col2: 11 } }); +var select = SELECT.from(Table).having({ col1: "*" }); +var select = SELECT.from(Table).having("col1='*'"); +var select = SELECT.from(Table).having`"col1='*'"`; +var select = SELECT.from(Table).having("col1=", "*"); +var select = SELECT.from(Table).having`col = ${"*"}`; +var select = SELECT.from(Table).having("col1 in ('*', 10)"); +var select = SELECT.from(Table).having`col1 in ${[("*", 10)]}`; +var select = SELECT.from(Table).having({ col1: 10, and: { col2: 11 } }); + var select = SELECT.from`Table`.groupBy("col1", "col2").having({ col1: "*" }); var select = SELECT.from`Table`.groupBy("col1", "col2").having("col1='*'"); var select = SELECT.from`Table`.groupBy("col1", "col2").having`"col1='*'"`; @@ -86,6 +113,21 @@ var select = SELECT.from`Table` .groupBy("col1", "col2") .having({ col1: 10, and: { col2: 11 } }); +var select = SELECT.from(Table).groupBy("col1", "col2").having({ col1: "*" }); +var select = SELECT.from(Table).groupBy("col1", "col2").having("col1='*'"); +var select = SELECT.from(Table).groupBy("col1", "col2").having`"col1='*'"`; +var select = SELECT.from(Table).groupBy("col1", "col2").having("col1=", "*"); +var select = SELECT.from(Table).groupBy("col1", "col2").having`col = ${"*"}`; +var select = SELECT.from(Table) + .groupBy("col1", "col2") + .having("col1 in ('*', 10)"); +var select = SELECT.from(Table).groupBy("col1", "col2").having`col1 in ${[ + ("*", 10), +]}`; +var select = SELECT.from(Table) + .groupBy("col1", "col2") + .having({ col1: 10, and: { col2: 11 } }); + var select = SELECT.from`Table`.groupBy`col1, col2`.having({ col1: "*" }); var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1='*'"); var select = SELECT.from`Table`.groupBy`col1, col2`.having`"col1='*'"`; @@ -100,6 +142,20 @@ var select = SELECT.from`Table`.groupBy`col1, col2`.having({ and: { col2: 11 }, }); +var select = SELECT.from`Table`.groupBy(col1, col2).having({ col1: "*" }); +var select = SELECT.from`Table`.groupBy(col1, col2).having("col1='*'"); +var select = SELECT.from`Table`.groupBy(col1, col2).having`"col1='*'"`; +var select = SELECT.from`Table`.groupBy(col1, col2).having("col1=", "*"); +var select = SELECT.from`Table`.groupBy(col1, col2).having`col = ${"*"}`; +var select = SELECT.from`Table`.groupBy(col1, col2).having("col1 in ('*', 10)"); +var select = SELECT.from`Table`.groupBy(col1, col2).having`col1 in ${[ + ("*", 10), +]}`; +var select = SELECT.from`Table`.groupBy(col1, col2).having({ + col1: 10, + and: { col2: 11 }, +}); + var select = SELECT.from`Table` .groupBy("col1.prop1", "col2.prop2") .having({ col1: "*" }); @@ -184,8 +240,18 @@ var select = SELECT.from`Table`.orderBy`col1 desc, col2.prop2`; var select = SELECT.from`Table`.orderBy`col1.prop1, col2 desc`; var select = SELECT.from`Table`.orderBy`col1 desc col2 desc`; +var select = SELECT.from(Table).orderBy`col1.prop1, col2.prop2`; +var select = SELECT.from(Table).orderBy`col1 asc, col2.prop2`; +var select = SELECT.from(Table).orderBy`col1.prop1, col2 asc`; +var select = SELECT.from(Table).orderBy`col1 asc col2 asc`; +var select = SELECT.from(Table).orderBy`col1.prop1, col2.prop2`; +var select = SELECT.from(Table).orderBy`col1 desc, col2.prop2`; +var select = SELECT.from(Table).orderBy`col1.prop1, col2 desc`; +var select = SELECT.from(Table).orderBy`col1 desc col2 desc`; + // .limit() var select = SELECT.from`Table`.limit(10); +var select = SELECT.from`Table`.limit`${10}`; var select = SELECT.from`Table`.limit(10, 20); var select = SELECT.from`Table`.limit({ val: 10 }); var select = SELECT.from`Table`.limit({ val: 10 }, { val: 20 }); @@ -194,6 +260,16 @@ var select = SELECT.from`Table`.limit({ ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], }); +var select = SELECT.from(Table).limit(10); +var select = SELECT.from(Table).limit`${10}`; +var select = SELECT.from(Table).limit(10, 20); +var select = SELECT.from(Table).limit({ val: 10 }); +var select = SELECT.from(Table).limit({ val: 10 }, { val: 20 }); +var select = SELECT.from(Table).limit({ ref: ["limitVal"] }); +var select = SELECT.from(Table).limit({ + ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], +}); + // .forUpdate() var select = SELECT.from`Table`.groupBy`col1, col2` .having`col = ${"*"}`.forUpdate(); From cf6bf1a93832db4abe87e4f6c5246bd59c54c0dd Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 28 Sep 2023 16:00:40 -0700 Subject: [PATCH 17/61] Add `isTaggedTemplateSelect` and `isMethodCallSelect` --- cap/CAPModels.qll | 92 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 26 deletions(-) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index 031277946..b6fceffad 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -127,43 +127,66 @@ class CdsFacade extends ModuleImportNode { CdsFacade() { this = moduleImport("@sap/cds") } } -predicate selectCqlBuilder(TaggedTemplateExpr tagExpr) { - exists(Expr taggingExpr | taggingExpr = tagExpr.getTag() | - /* SELECT `Bar` */ - taggingExpr.(VarRef).getName() = "SELECT" or - /* SELECT.one `Foo`, SELECT.from `Bar` */ - taggingExpr.(DotExpr).accesses(any(VarRef var | var.getName() = "SELECT"), _) or - /* SELECT.one.from`Table` */ - taggingExpr - .(DotExpr) - .accesses(any(DotExpr var | var.accesses(any(VarRef var_ | var_.getName() = "SELECT"), _)), - _) or - selectCqlBuilder(taggingExpr.getAChildExpr()) +/** + * Holds if a `DotExpr` ultimately accesses a `SELECT` variable, e.g. + * ```js + * SELECT.from + * SELECT.one.from + * SELECT.distinct.from + * ``` + */ +private predicate accessesSelect(DotExpr dot) { + exists(DotExpr descendant | descendant = dot.getAChildExpr*() | + descendant.accesses(any(VarRef var | var.getName() = "SELECT"), _) ) } -private predicate accessesSelect(DotExpr dot) { - dot.accesses(any(VarRef var | var.getName() = "SELECT"), _) - or - accessesSelect(dot.getAChildExpr()) +/** + * Method call `SELECT` CQL query expressions, e.g. + * ```js + * SELECT.from(Table) + * SELECT.distinct.from(Table); + * SELECT.from`Table`.where("col1='*'"); + * SELECT.from(Table).having("col1='*'"); + * ``` + */ +predicate isMethodCallSelect(MethodCallExpr callExpr) { + exists(Expr receiver | receiver = callExpr.getCallee() | + accessesSelect(receiver) + or + exists(TaggedTemplateExpr nestedTaggingExpr | + receiver.(DotExpr).accesses(nestedTaggingExpr, _) + | + isTaggedTemplateSelect(nestedTaggingExpr) + ) + or + exists(MethodCallExpr nestedCallExpr | receiver.(DotExpr).accesses(nestedCallExpr, _) | + isMethodCallSelect(nestedCallExpr) + ) + ) } -/** Tagged SELECTs with property accesses */ -predicate accessesSelectTagged(TaggedTemplateExpr tagExpr) { accessesSelect(tagExpr.getTag()) } - -/** Nested Tagged SELECTs (includes accessesSelectTagged: Tagged SELECTs with property accesses) */ -predicate nestedSelectTaggedTemplate(TaggedTemplateExpr tagExpr) { - // tagExpr = SELECT.from`Table`.columns`col1, col2` +/** + * Tagged `SELECT` CQL query expressions, e.g. + * ```js + * SELECT.from`Table` + * SELECT.distinct.from`Table`; + * SELECT.from(Table).where`"col1='*'"`; + * SELECT.from`Table`.having`"col1='*'"`; + * ``` + */ +predicate isTaggedTemplateSelect(TaggedTemplateExpr tagExpr) { exists(Expr taggingExpr | taggingExpr = tagExpr.getTag() | - // taggingExpr = SELECT.from`Table`.columns - // base accessesSelect(taggingExpr) or - // recursive exists(TaggedTemplateExpr nestedTaggingExpr | taggingExpr.(DotExpr).accesses(nestedTaggingExpr, _) | - nestedSelectTaggedTemplate(nestedTaggingExpr) + isTaggedTemplateSelect(nestedTaggingExpr) + ) + or + exists(MethodCallExpr nestedCallExpr | taggingExpr.(DotExpr).accesses(nestedCallExpr, _) | + isMethodCallSelect(nestedCallExpr) ) ) } @@ -179,6 +202,23 @@ predicate deleteCqlBuilder(TaggedTemplateExpr tagExpr) { abstract class CqlBuilder extends ValueNode { } +newtype TCQLSelect = + TaggedTemplateSelect(TaggedTemplateExpr tagExpr) or + MethodCallSelect(MethodCallExpr callExpr) + +class CQLSelect extends TCQLSelect { + TaggedTemplateExpr asTaggedTemplate() { this = TaggedTemplateSelect(result) } + + MethodCallExpr asMethodCall() { this = MethodCallSelect(result) } + + string toString() { + result = this.asTaggedTemplate().toString() or + result = this.asMethodCall().toString() + } +} + +deprecated predicate selectCqlBuilder(TaggedTemplateExpr tagExpr) { any() } + class Select extends CqlBuilder { Select() { exists(TaggedTemplateExpr tagExpr | selectCqlBuilder(tagExpr) and this = tagExpr.flow()) From 7cd3d016778abc3bae98ef9f7ac099de5a738554 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 28 Sep 2023 16:08:28 -0700 Subject: [PATCH 18/61] Add comments to each branch --- cap/CAPModels.qll | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index b6fceffad..cc3100e21 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -152,14 +152,29 @@ private predicate accessesSelect(DotExpr dot) { */ predicate isMethodCallSelect(MethodCallExpr callExpr) { exists(Expr receiver | receiver = callExpr.getCallee() | + /* + * Only property accesses are left up to SELECT, e.g. + * SELECT.x.y. ...z`cond` + */ + accessesSelect(receiver) or + /* + * The immediate prefix is a TaggedTemplateExpr: + * SELECT.x. ... .z`cond1`.w`cond2` + */ + exists(TaggedTemplateExpr nestedTaggingExpr | receiver.(DotExpr).accesses(nestedTaggingExpr, _) | isTaggedTemplateSelect(nestedTaggingExpr) ) or + /* + * The immediate prefix is a MethodCallExpr: + * SELECT.x. ... .z(cond1).w`cond2` + */ + exists(MethodCallExpr nestedCallExpr | receiver.(DotExpr).accesses(nestedCallExpr, _) | isMethodCallSelect(nestedCallExpr) ) @@ -177,14 +192,29 @@ predicate isMethodCallSelect(MethodCallExpr callExpr) { */ predicate isTaggedTemplateSelect(TaggedTemplateExpr tagExpr) { exists(Expr taggingExpr | taggingExpr = tagExpr.getTag() | + /* + * Only property accesses are left up to SELECT, e.g. + * SELECT.x.y. ...z`cond` + */ + accessesSelect(taggingExpr) or + /* + * The immediate prefix is a TaggedTemplateExpr: + * SELECT.x. ... .z`cond1`.w`cond2` + */ + exists(TaggedTemplateExpr nestedTaggingExpr | taggingExpr.(DotExpr).accesses(nestedTaggingExpr, _) | isTaggedTemplateSelect(nestedTaggingExpr) ) or + /* + * The immediate prefix is a MethodCallExpr: + * SELECT.x. ... .z(cond1).w`cond2` + */ + exists(MethodCallExpr nestedCallExpr | taggingExpr.(DotExpr).accesses(nestedCallExpr, _) | isMethodCallSelect(nestedCallExpr) ) From 6e8fbc372e1f47fb1c60bb38667408215dfc3722 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 28 Sep 2023 16:22:48 -0700 Subject: [PATCH 19/61] Establish CqlExpression hierarchy --- cap/CAPModels.qll | 72 ++++++++++++++++------------------------------- 1 file changed, 24 insertions(+), 48 deletions(-) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index cc3100e21..09e5c7b4f 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -221,22 +221,18 @@ predicate isTaggedTemplateSelect(TaggedTemplateExpr tagExpr) { ) } -predicate deleteCqlBuilder(TaggedTemplateExpr tagExpr) { - exists(Expr taggingExpr | taggingExpr = tagExpr.getTag() | - taggingExpr.(VarRef).getName() = "DELETE" or - taggingExpr.(GlobalVarAccess).getName() = "DELETE" or - taggingExpr.(DotExpr).accesses(any(VarRef var | var.getName() = "DELETE"), _) or - deleteCqlBuilder(taggingExpr.getAChildExpr()) - ) -} - -abstract class CqlBuilder extends ValueNode { } - -newtype TCQLSelect = - TaggedTemplateSelect(TaggedTemplateExpr tagExpr) or - MethodCallSelect(MethodCallExpr callExpr) - -class CQLSelect extends TCQLSelect { +newtype TCqlExpr = + TCqlSelectExpr(TCqlSelect cqlSelect) or + TCqlInsertExpr(TCqlInsert cqlInsert) or + TCqlUpdateExpr(TCqlUpdate cqlUpdate) or + TCqlDeleteExpr(TCqlDelete cqlDelete) or + TCqlUpsertExpr(TCqlUpsert cqlUpsert) + +newtype TCqlSelect = + TaggedTemplateSelect(TaggedTemplateExpr tagExpr) { isTaggedTemplateSelect(tagExpr) } or + MethodCallSelect(MethodCallExpr callExpr) { isMethodCallSelect(callExpr) } + +class Select extends TCqlSelect { TaggedTemplateExpr asTaggedTemplate() { this = TaggedTemplateSelect(result) } MethodCallExpr asMethodCall() { this = MethodCallSelect(result) } @@ -247,38 +243,18 @@ class CQLSelect extends TCQLSelect { } } -deprecated predicate selectCqlBuilder(TaggedTemplateExpr tagExpr) { any() } - -class Select extends CqlBuilder { - Select() { - exists(TaggedTemplateExpr tagExpr | selectCqlBuilder(tagExpr) and this = tagExpr.flow()) - } -} - -class Update extends CqlBuilder { - Update() { - // TODO - exists(TaggedTemplateExpr tagExpr | selectCqlBuilder(tagExpr) and this = tagExpr.flow()) - } -} +newtype TCqlInsert = + TaggedTemplateInsert(TaggedTemplateExpr tagExpr) or + MethodCallInsert(MethodCallExpr callExpr) -class Insert extends CqlBuilder { - Insert() { - // TODO - exists(TaggedTemplateExpr tagExpr | selectCqlBuilder(tagExpr) and this = tagExpr.flow()) - } -} +newtype TCqlUpdate = + TaggedTemplateUpdate(TaggedTemplateExpr tagExpr) or + MethodCallUpdate(MethodCallExpr callExpr) -class Delete extends CqlBuilder { - Delete() { - // TODO - exists(TaggedTemplateExpr tagExpr | selectCqlBuilder(tagExpr) and this = tagExpr.flow()) - } -} +newtype TCqlDelete = + TaggedTemplateDelete(TaggedTemplateExpr tagExpr) or + MethodCallDelete(MethodCallExpr callExpr) -class Upsert extends CqlBuilder { - Upsert() { - // TODO - exists(TaggedTemplateExpr tagExpr | selectCqlBuilder(tagExpr) and this = tagExpr.flow()) - } -} +newtype TCqlUpsert = + TaggedTemplateUpsert(TaggedTemplateExpr tagExpr) or + MethodCallUpsert(MethodCallExpr callExpr) From 71536fcd248a35009563bcd881e9640474daa29e Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 28 Sep 2023 16:23:53 -0700 Subject: [PATCH 20/61] Make isMethodCallSelect and isTaggedTemplateSelect private --- cap/CAPModels.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index 09e5c7b4f..3b2ff6ad4 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -150,7 +150,7 @@ private predicate accessesSelect(DotExpr dot) { * SELECT.from(Table).having("col1='*'"); * ``` */ -predicate isMethodCallSelect(MethodCallExpr callExpr) { +private predicate isMethodCallSelect(MethodCallExpr callExpr) { exists(Expr receiver | receiver = callExpr.getCallee() | /* * Only property accesses are left up to SELECT, e.g. @@ -190,7 +190,7 @@ predicate isMethodCallSelect(MethodCallExpr callExpr) { * SELECT.from`Table`.having`"col1='*'"`; * ``` */ -predicate isTaggedTemplateSelect(TaggedTemplateExpr tagExpr) { +private predicate isTaggedTemplateSelect(TaggedTemplateExpr tagExpr) { exists(Expr taggingExpr | taggingExpr = tagExpr.getTag() | /* * Only property accesses are left up to SELECT, e.g. From 390b8fb082204537a7047ff39193c7ff71894359 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 28 Sep 2023 16:27:37 -0700 Subject: [PATCH 21/61] Fix a minor error in explaining comment --- cap/CAPModels.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index 3b2ff6ad4..6b56d3f07 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -161,7 +161,7 @@ private predicate isMethodCallSelect(MethodCallExpr callExpr) { or /* * The immediate prefix is a TaggedTemplateExpr: - * SELECT.x. ... .z`cond1`.w`cond2` + * SELECT.x. ... .z`cond1`.w(cond2) */ exists(TaggedTemplateExpr nestedTaggingExpr | @@ -172,7 +172,7 @@ private predicate isMethodCallSelect(MethodCallExpr callExpr) { or /* * The immediate prefix is a MethodCallExpr: - * SELECT.x. ... .z(cond1).w`cond2` + * SELECT.x. ... .z(cond1).w(cond2) */ exists(MethodCallExpr nestedCallExpr | receiver.(DotExpr).accesses(nestedCallExpr, _) | From 8b9c54b041425982748c9067b6f1bf7d20da5188 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 28 Sep 2023 16:27:59 -0700 Subject: [PATCH 22/61] Fix another minor error in comment --- cap/CAPModels.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index 6b56d3f07..586638612 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -154,7 +154,7 @@ private predicate isMethodCallSelect(MethodCallExpr callExpr) { exists(Expr receiver | receiver = callExpr.getCallee() | /* * Only property accesses are left up to SELECT, e.g. - * SELECT.x.y. ...z`cond` + * SELECT.x.y. ...z(cond) */ accessesSelect(receiver) From 536b3c83d197a4672246640cdb981b59abe9a83f Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 28 Sep 2023 16:32:27 -0700 Subject: [PATCH 23/61] Add `getLocation` for clickable results --- cap/CAPModels.qll | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index 586638612..1cc5905f2 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -241,6 +241,11 @@ class Select extends TCqlSelect { result = this.asTaggedTemplate().toString() or result = this.asMethodCall().toString() } + + Location getLocation() { + result = this.asTaggedTemplate().getLocation() or + result = this.asMethodCall().getLocation() + } } newtype TCqlInsert = From e44abc1bbcf0609bed5ca12923090943ea273afa Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 29 Sep 2023 11:28:52 -0700 Subject: [PATCH 24/61] Factor out shared member predicates to a class --- cap/CAPModels.qll | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index 1cc5905f2..5e9070193 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -222,20 +222,13 @@ private predicate isTaggedTemplateSelect(TaggedTemplateExpr tagExpr) { } newtype TCqlExpr = - TCqlSelectExpr(TCqlSelect cqlSelect) or - TCqlInsertExpr(TCqlInsert cqlInsert) or - TCqlUpdateExpr(TCqlUpdate cqlUpdate) or - TCqlDeleteExpr(TCqlDelete cqlDelete) or - TCqlUpsertExpr(TCqlUpsert cqlUpsert) + TaggedTemplate(TaggedTemplateExpr tagExpr) or + MethodCall(MethodCallExpr callExpr) -newtype TCqlSelect = - TaggedTemplateSelect(TaggedTemplateExpr tagExpr) { isTaggedTemplateSelect(tagExpr) } or - MethodCallSelect(MethodCallExpr callExpr) { isMethodCallSelect(callExpr) } +class CqlExpr extends TCqlExpr { + TaggedTemplateExpr asTaggedTemplate() { this = TaggedTemplate(result) } -class Select extends TCqlSelect { - TaggedTemplateExpr asTaggedTemplate() { this = TaggedTemplateSelect(result) } - - MethodCallExpr asMethodCall() { this = MethodCallSelect(result) } + MethodCallExpr asMethodCall() { this = MethodCall(result) } string toString() { result = this.asTaggedTemplate().toString() or @@ -248,18 +241,24 @@ class Select extends TCqlSelect { } } -newtype TCqlInsert = - TaggedTemplateInsert(TaggedTemplateExpr tagExpr) or - MethodCallInsert(MethodCallExpr callExpr) +class CqlSelect extends CqlExpr { + CqlSelect() { + isMethodCallSelect(this.asMethodCall()) or isTaggedTemplateSelect(this.asTaggedTemplate()) + } +} + +class CqlInsert extends CqlExpr { + CqlInsert() { any() } +} -newtype TCqlUpdate = - TaggedTemplateUpdate(TaggedTemplateExpr tagExpr) or - MethodCallUpdate(MethodCallExpr callExpr) +class CqlDelete extends CqlExpr { + CqlDelete() { any() } +} -newtype TCqlDelete = - TaggedTemplateDelete(TaggedTemplateExpr tagExpr) or - MethodCallDelete(MethodCallExpr callExpr) +class CqlUpdate extends CqlExpr { + CqlUpdate() { any() } +} -newtype TCqlUpsert = - TaggedTemplateUpsert(TaggedTemplateExpr tagExpr) or - MethodCallUpsert(MethodCallExpr callExpr) +class CqlUpsert extends CqlExpr { + CqlUpsert() { any() } +} From 9dfccb75ff2843a284ae456369cf2a1c0f383faf Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 29 Sep 2023 12:13:13 -0700 Subject: [PATCH 25/61] Match on property names and method names --- cap/CAPModels.qll | 56 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index 5e9070193..3212803c3 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -136,9 +136,18 @@ class CdsFacade extends ModuleImportNode { * ``` */ private predicate accessesSelect(DotExpr dot) { - exists(DotExpr descendant | descendant = dot.getAChildExpr*() | - descendant.accesses(any(VarRef var | var.getName() = "SELECT"), _) - ) + dot.accesses(any(VarRef var | var.getName() = "SELECT"), + [ + "one", "distinct", "columns", "from", "alias", "where", "having", "groupBy", "orderBy", + "limit", "forUpdate", "forShareLock" + ]) + or + dot.getPropertyName() = + [ + "one", "distinct", "columns", "from", "alias", "where", "having", "groupBy", "orderBy", + "limit", "forUpdate", "forShareLock" + ] and + accessesSelect(dot.getAChildExpr()) } /** @@ -151,6 +160,11 @@ private predicate accessesSelect(DotExpr dot) { * ``` */ private predicate isMethodCallSelect(MethodCallExpr callExpr) { + callExpr.getCalleeName() = + [ + "columns", "from", "alias", "where", "having", "groupBy", "orderBy", "limit", "forUpdate", + "forShareLock" + ] and exists(Expr receiver | receiver = callExpr.getCallee() | /* * Only property accesses are left up to SELECT, e.g. @@ -191,7 +205,14 @@ private predicate isMethodCallSelect(MethodCallExpr callExpr) { * ``` */ private predicate isTaggedTemplateSelect(TaggedTemplateExpr tagExpr) { - exists(Expr taggingExpr | taggingExpr = tagExpr.getTag() | + exists(Expr taggingExpr | + taggingExpr = tagExpr.getTag() and + taggingExpr.(DotExpr).getPropertyName() = + [ + "columns", "from", "alias", "where", "having", "groupBy", "orderBy", "limit", "forUpdate", + "forShareLock" + ] + | /* * Only property accesses are left up to SELECT, e.g. * SELECT.x.y. ...z`cond` @@ -241,24 +262,31 @@ class CqlExpr extends TCqlExpr { } } -class CqlSelect extends CqlExpr { - CqlSelect() { +class CqlSelectExpr extends CqlExpr { + CqlSelectExpr() { isMethodCallSelect(this.asMethodCall()) or isTaggedTemplateSelect(this.asTaggedTemplate()) } + + /* TODO */ + predicate selectWhere() { any() } + + /* TODO */ + predicate selectFrom() { any() } + // TODO: propname validation } -class CqlInsert extends CqlExpr { - CqlInsert() { any() } +class CqlInsertExpr extends CqlExpr { + CqlInsertExpr() { any() } } -class CqlDelete extends CqlExpr { - CqlDelete() { any() } +class CqlDeleteExpr extends CqlExpr { + CqlDeleteExpr() { any() } } -class CqlUpdate extends CqlExpr { - CqlUpdate() { any() } +class CqlUpdateExpr extends CqlExpr { + CqlUpdateExpr() { any() } } -class CqlUpsert extends CqlExpr { - CqlUpsert() { any() } +class CqlUpsertExpr extends CqlExpr { + CqlUpsertExpr() { any() } } From 8c3661d4ba049de2402aac7884d1eba7493a1194 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 29 Sep 2023 15:18:34 -0700 Subject: [PATCH 26/61] Move CQL models to separate file --- cap/CAPModels.qll | 166 +-------------------------------------------- cap/CQL.qll | 169 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+), 165 deletions(-) create mode 100644 cap/CQL.qll diff --git a/cap/CAPModels.qll b/cap/CAPModels.qll index 3212803c3..6e94d9ace 100644 --- a/cap/CAPModels.qll +++ b/cap/CAPModels.qll @@ -125,168 +125,4 @@ class Request extends ValueNode, ParameterNode { */ class CdsFacade extends ModuleImportNode { CdsFacade() { this = moduleImport("@sap/cds") } -} - -/** - * Holds if a `DotExpr` ultimately accesses a `SELECT` variable, e.g. - * ```js - * SELECT.from - * SELECT.one.from - * SELECT.distinct.from - * ``` - */ -private predicate accessesSelect(DotExpr dot) { - dot.accesses(any(VarRef var | var.getName() = "SELECT"), - [ - "one", "distinct", "columns", "from", "alias", "where", "having", "groupBy", "orderBy", - "limit", "forUpdate", "forShareLock" - ]) - or - dot.getPropertyName() = - [ - "one", "distinct", "columns", "from", "alias", "where", "having", "groupBy", "orderBy", - "limit", "forUpdate", "forShareLock" - ] and - accessesSelect(dot.getAChildExpr()) -} - -/** - * Method call `SELECT` CQL query expressions, e.g. - * ```js - * SELECT.from(Table) - * SELECT.distinct.from(Table); - * SELECT.from`Table`.where("col1='*'"); - * SELECT.from(Table).having("col1='*'"); - * ``` - */ -private predicate isMethodCallSelect(MethodCallExpr callExpr) { - callExpr.getCalleeName() = - [ - "columns", "from", "alias", "where", "having", "groupBy", "orderBy", "limit", "forUpdate", - "forShareLock" - ] and - exists(Expr receiver | receiver = callExpr.getCallee() | - /* - * Only property accesses are left up to SELECT, e.g. - * SELECT.x.y. ...z(cond) - */ - - accessesSelect(receiver) - or - /* - * The immediate prefix is a TaggedTemplateExpr: - * SELECT.x. ... .z`cond1`.w(cond2) - */ - - exists(TaggedTemplateExpr nestedTaggingExpr | - receiver.(DotExpr).accesses(nestedTaggingExpr, _) - | - isTaggedTemplateSelect(nestedTaggingExpr) - ) - or - /* - * The immediate prefix is a MethodCallExpr: - * SELECT.x. ... .z(cond1).w(cond2) - */ - - exists(MethodCallExpr nestedCallExpr | receiver.(DotExpr).accesses(nestedCallExpr, _) | - isMethodCallSelect(nestedCallExpr) - ) - ) -} - -/** - * Tagged `SELECT` CQL query expressions, e.g. - * ```js - * SELECT.from`Table` - * SELECT.distinct.from`Table`; - * SELECT.from(Table).where`"col1='*'"`; - * SELECT.from`Table`.having`"col1='*'"`; - * ``` - */ -private predicate isTaggedTemplateSelect(TaggedTemplateExpr tagExpr) { - exists(Expr taggingExpr | - taggingExpr = tagExpr.getTag() and - taggingExpr.(DotExpr).getPropertyName() = - [ - "columns", "from", "alias", "where", "having", "groupBy", "orderBy", "limit", "forUpdate", - "forShareLock" - ] - | - /* - * Only property accesses are left up to SELECT, e.g. - * SELECT.x.y. ...z`cond` - */ - - accessesSelect(taggingExpr) - or - /* - * The immediate prefix is a TaggedTemplateExpr: - * SELECT.x. ... .z`cond1`.w`cond2` - */ - - exists(TaggedTemplateExpr nestedTaggingExpr | - taggingExpr.(DotExpr).accesses(nestedTaggingExpr, _) - | - isTaggedTemplateSelect(nestedTaggingExpr) - ) - or - /* - * The immediate prefix is a MethodCallExpr: - * SELECT.x. ... .z(cond1).w`cond2` - */ - - exists(MethodCallExpr nestedCallExpr | taggingExpr.(DotExpr).accesses(nestedCallExpr, _) | - isMethodCallSelect(nestedCallExpr) - ) - ) -} - -newtype TCqlExpr = - TaggedTemplate(TaggedTemplateExpr tagExpr) or - MethodCall(MethodCallExpr callExpr) - -class CqlExpr extends TCqlExpr { - TaggedTemplateExpr asTaggedTemplate() { this = TaggedTemplate(result) } - - MethodCallExpr asMethodCall() { this = MethodCall(result) } - - string toString() { - result = this.asTaggedTemplate().toString() or - result = this.asMethodCall().toString() - } - - Location getLocation() { - result = this.asTaggedTemplate().getLocation() or - result = this.asMethodCall().getLocation() - } -} - -class CqlSelectExpr extends CqlExpr { - CqlSelectExpr() { - isMethodCallSelect(this.asMethodCall()) or isTaggedTemplateSelect(this.asTaggedTemplate()) - } - - /* TODO */ - predicate selectWhere() { any() } - - /* TODO */ - predicate selectFrom() { any() } - // TODO: propname validation -} - -class CqlInsertExpr extends CqlExpr { - CqlInsertExpr() { any() } -} - -class CqlDeleteExpr extends CqlExpr { - CqlDeleteExpr() { any() } -} - -class CqlUpdateExpr extends CqlExpr { - CqlUpdateExpr() { any() } -} - -class CqlUpsertExpr extends CqlExpr { - CqlUpsertExpr() { any() } -} +} \ No newline at end of file diff --git a/cap/CQL.qll b/cap/CQL.qll new file mode 100644 index 000000000..3881311ca --- /dev/null +++ b/cap/CQL.qll @@ -0,0 +1,169 @@ +private import javascript +private import DataFlow + +/** + * Holds if a `DotExpr` ultimately accesses a `SELECT` variable, e.g. + * ```js + * SELECT.from + * SELECT.one.from + * SELECT.distinct.from + * ``` + */ +private predicate accessesSelect(DotExpr dot) { + dot.accesses(any(VarRef var | var.getName() = "SELECT"), + [ + "one", "distinct", "columns", "from", "alias", "where", "having", "groupBy", "orderBy", + "limit", "forUpdate", "forShareLock" + ]) + or + dot.getPropertyName() = + [ + "one", "distinct", "columns", "from", "alias", "where", "having", "groupBy", "orderBy", + "limit", "forUpdate", "forShareLock" + ] and + accessesSelect(dot.getAChildExpr()) +} + +/** + * Method call `SELECT` CQL query expressions, e.g. + * ```js + * SELECT.from(Table) + * SELECT.distinct.from(Table); + * SELECT.from`Table`.where("col1='*'"); + * SELECT.from(Table).having("col1='*'"); + * ``` + */ +private predicate isMethodCallSelect(MethodCallExpr callExpr) { + callExpr.getCalleeName() = + [ + "columns", "from", "alias", "where", "having", "groupBy", "orderBy", "limit", "forUpdate", + "forShareLock" + ] and + exists(Expr receiver | receiver = callExpr.getCallee() | + /* + * Only property accesses are left up to SELECT, e.g. + * SELECT.x.y. ...z(cond) + */ + + accessesSelect(receiver) + or + /* + * The immediate prefix is a TaggedTemplateExpr: + * SELECT.x. ... .z`cond1`.w(cond2) + */ + + exists(TaggedTemplateExpr nestedTaggingExpr | + receiver.(DotExpr).accesses(nestedTaggingExpr, _) + | + isTaggedTemplateSelect(nestedTaggingExpr) + ) + or + /* + * The immediate prefix is a MethodCallExpr: + * SELECT.x. ... .z(cond1).w(cond2) + */ + + exists(MethodCallExpr nestedCallExpr | receiver.(DotExpr).accesses(nestedCallExpr, _) | + isMethodCallSelect(nestedCallExpr) + ) + ) +} + +/** + * Tagged `SELECT` CQL query expressions, e.g. + * ```js + * SELECT.from`Table` + * SELECT.distinct.from`Table`; + * SELECT.from(Table).where`"col1='*'"`; + * SELECT.from`Table`.having`"col1='*'"`; + * ``` + */ +private predicate isTaggedTemplateSelect(TaggedTemplateExpr tagExpr) { + exists(Expr taggingExpr | + taggingExpr = tagExpr.getTag() and + taggingExpr.(DotExpr).getPropertyName() = + [ + "columns", "from", "alias", "where", "having", "groupBy", "orderBy", "limit", "forUpdate", + "forShareLock" + ] + | + /* + * Only property accesses are left up to SELECT, e.g. + * SELECT.x.y. ...z`cond` + */ + + accessesSelect(taggingExpr) + or + /* + * The immediate prefix is a TaggedTemplateExpr: + * SELECT.x. ... .z`cond1`.w`cond2` + */ + + exists(TaggedTemplateExpr nestedTaggingExpr | + taggingExpr.(DotExpr).accesses(nestedTaggingExpr, _) + | + isTaggedTemplateSelect(nestedTaggingExpr) + ) + or + /* + * The immediate prefix is a MethodCallExpr: + * SELECT.x. ... .z(cond1).w`cond2` + */ + + exists(MethodCallExpr nestedCallExpr | taggingExpr.(DotExpr).accesses(nestedCallExpr, _) | + isMethodCallSelect(nestedCallExpr) + ) + ) +} + +newtype TCqlExpr = + TaggedTemplate(TaggedTemplateExpr tagExpr) or + MethodCall(MethodCallExpr callExpr) + +class CqlExpr extends TCqlExpr { + TaggedTemplateExpr asTaggedTemplate() { this = TaggedTemplate(result) } + + MethodCallExpr asMethodCall() { this = MethodCall(result) } + + string toString() { + result = this.asTaggedTemplate().toString() or + result = this.asMethodCall().toString() + } + + Location getLocation() { + result = this.asTaggedTemplate().getLocation() or + result = this.asMethodCall().getLocation() + } +} + +class CqlSelectExpr extends CqlExpr { + CqlSelectExpr() { + isMethodCallSelect(this.asMethodCall()) or isTaggedTemplateSelect(this.asTaggedTemplate()) + } + + predicate selectWhere() { + this.asMethodCall().getMethodName() = "where" or + this.asTaggedTemplate().getTag().(DotExpr).getPropertyName() = "where" + } + + predicate selectFrom() { + this.asMethodCall().getMethodName() = "from" or + this.asTaggedTemplate().getTag().(DotExpr).getPropertyName() = "from" + } +} + +class CqlInsertExpr extends CqlExpr { + CqlInsertExpr() { any() } +} + +class CqlDeleteExpr extends CqlExpr { + CqlDeleteExpr() { any() } +} + +class CqlUpdateExpr extends CqlExpr { + CqlUpdateExpr() { any() } +} + +class CqlUpsertExpr extends CqlExpr { + CqlUpsertExpr() { any() } +} From c17958bf57c99ab26b0a42d497c7451ae5049b7c Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 29 Sep 2023 15:22:34 -0700 Subject: [PATCH 27/61] Fix syntactical mistakes on unit tests for SELECT --- cap/test/cql/select.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cap/test/cql/select.js b/cap/test/cql/select.js index 37196f687..9701d98fd 100644 --- a/cap/test/cql/select.js +++ b/cap/test/cql/select.js @@ -44,7 +44,7 @@ var select = SELECT.from(Table).columns("col1", { // .where() var select = SELECT.from`Table`.where({ col1: "*" }); var select = SELECT.from`Table`.where("col1='*'"); -var select = SELECT.from`Table`.where`"col1='*'"`; +var select = SELECT.from`Table`.where`col1=${"*"}`; var select = SELECT.from`Table`.where("col1=", "*"); var select = SELECT.from`Table`.where`col = ${"*"}`; var select = SELECT.from`Table`.where("col1 in ('*', 10)"); @@ -53,7 +53,7 @@ var select = SELECT.from`Table`.where({ col1: 10, and: { col2: 11 } }); var select = SELECT.from(Table).where({ col1: "*" }); var select = SELECT.from(Table).where("col1='*'"); -var select = SELECT.from(Table).where`"col1='*'"`; +var select = SELECT.from(Table).where`col1=${"*"}`; var select = SELECT.from(Table).where("col1=", "*"); var select = SELECT.from(Table).where`col = ${"*"}`; var select = SELECT.from(Table).where("col1 in ('*', 10)"); @@ -82,7 +82,7 @@ var select = SELECT.from(Table).groupBy( // .having() var select = SELECT.from`Table`.having({ col1: "*" }); var select = SELECT.from`Table`.having("col1='*'"); -var select = SELECT.from`Table`.having`"col1='*'"`; +var select = SELECT.from`Table`.having`col1=${"*"}`; var select = SELECT.from`Table`.having("col1=", "*"); var select = SELECT.from`Table`.having`col = ${"*"}`; var select = SELECT.from`Table`.having("col1 in ('*', 10)"); @@ -91,7 +91,7 @@ var select = SELECT.from`Table`.having({ col1: 10, and: { col2: 11 } }); var select = SELECT.from(Table).having({ col1: "*" }); var select = SELECT.from(Table).having("col1='*'"); -var select = SELECT.from(Table).having`"col1='*'"`; +var select = SELECT.from(Table).having`col1=${"*"}`; var select = SELECT.from(Table).having("col1=", "*"); var select = SELECT.from(Table).having`col = ${"*"}`; var select = SELECT.from(Table).having("col1 in ('*', 10)"); @@ -100,7 +100,7 @@ var select = SELECT.from(Table).having({ col1: 10, and: { col2: 11 } }); var select = SELECT.from`Table`.groupBy("col1", "col2").having({ col1: "*" }); var select = SELECT.from`Table`.groupBy("col1", "col2").having("col1='*'"); -var select = SELECT.from`Table`.groupBy("col1", "col2").having`"col1='*'"`; +var select = SELECT.from`Table`.groupBy("col1", "col2").having`col1=${"*"}`; var select = SELECT.from`Table`.groupBy("col1", "col2").having("col1=", "*"); var select = SELECT.from`Table`.groupBy("col1", "col2").having`col = ${"*"}`; var select = SELECT.from`Table` @@ -115,7 +115,7 @@ var select = SELECT.from`Table` var select = SELECT.from(Table).groupBy("col1", "col2").having({ col1: "*" }); var select = SELECT.from(Table).groupBy("col1", "col2").having("col1='*'"); -var select = SELECT.from(Table).groupBy("col1", "col2").having`"col1='*'"`; +var select = SELECT.from(Table).groupBy("col1", "col2").having`col1=${"*"}`; var select = SELECT.from(Table).groupBy("col1", "col2").having("col1=", "*"); var select = SELECT.from(Table).groupBy("col1", "col2").having`col = ${"*"}`; var select = SELECT.from(Table) @@ -130,7 +130,7 @@ var select = SELECT.from(Table) var select = SELECT.from`Table`.groupBy`col1, col2`.having({ col1: "*" }); var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1='*'"); -var select = SELECT.from`Table`.groupBy`col1, col2`.having`"col1='*'"`; +var select = SELECT.from`Table`.groupBy`col1, col2`.having`col1=${"*"}`; var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1=", "*"); var select = SELECT.from`Table`.groupBy`col1, col2`.having`col = ${"*"}`; var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1 in ('*', 10)"); @@ -144,7 +144,7 @@ var select = SELECT.from`Table`.groupBy`col1, col2`.having({ var select = SELECT.from`Table`.groupBy(col1, col2).having({ col1: "*" }); var select = SELECT.from`Table`.groupBy(col1, col2).having("col1='*'"); -var select = SELECT.from`Table`.groupBy(col1, col2).having`"col1='*'"`; +var select = SELECT.from`Table`.groupBy(col1, col2).having`col1=${"*"}`; var select = SELECT.from`Table`.groupBy(col1, col2).having("col1=", "*"); var select = SELECT.from`Table`.groupBy(col1, col2).having`col = ${"*"}`; var select = SELECT.from`Table`.groupBy(col1, col2).having("col1 in ('*', 10)"); @@ -163,7 +163,7 @@ var select = SELECT.from`Table` .groupBy("col1.prop1", "col2.prop2") .having("col1='*'"); var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") - .having`"col1='*'"`; + .having`col1=${"*"}`; var select = SELECT.from`Table` .groupBy("col1.prop1", "col2.prop2") .having("col1=", "*"); @@ -185,7 +185,7 @@ var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( "col1='*'" ); var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` - .having`"col1='*'"`; + .having`col1=${"*"}`; var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( "col1=", "*" @@ -211,7 +211,7 @@ var select = SELECT.from`Table` var select = SELECT.from`Table`.groupBy( { ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] } -).having`"col1='*'"`; +).having`col1=${"*"}`; var select = SELECT.from`Table` .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) .having("col1=", "*"); From 80f7223bf645ba225643b759bec509be907b1c1e Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 29 Sep 2023 15:23:05 -0700 Subject: [PATCH 28/61] Add test for INSERT CQL query expressions --- cap/test/cql/insert.js | 67 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 cap/test/cql/insert.js diff --git a/cap/test/cql/insert.js b/cap/test/cql/insert.js new file mode 100644 index 000000000..e140dbea9 --- /dev/null +++ b/cap/test/cql/insert.js @@ -0,0 +1,67 @@ +/* ========== into ========== */ +var insert = INSERT.into(Table, [ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]); + +/* ========== into, entries ========== */ +var insert = INSERT.into(Table).entries( + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" } +); +var insert = INSERT.into("Table").entries( + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" } +); +var insert = INSERT.into`Table`.entries( + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" } +); + +/* ========== into, columns, values ========== */ +var insert = INSERT.into(Table) + .columns("col1", "col2") + .values("val11", "val12"); +var insert = INSERT.into("Table") + .columns("col1", "col2") + .values("val11", "val12"); +var insert = INSERT.into`Table` + .columns("col1", "col2") + .values("val11", "val12"); + +/* ========== into, columns, rows ========== */ +var insert = INSERT.into(Table) + .columns("col1", "col2") + .rows([ + ["val11", "val12"], + ["val21", "val22"], + ]); +var insert = INSERT.into("Table") + .columns("col1", "col2") + .rows([ + ["val11", "val12"], + ["val21", "val22"], + ]); +var insert = INSERT.into`Table`.columns("col1", "col2").rows([ + ["val11", "val12"], + ["val21", "val22"], +]); + +/* ========== into, as ========== */ +var insert = INSERT.into(Table).as(SELECT.from`Table`.columns`col1, col2`); +var insert = INSERT.into(Table).as(SELECT.from`Table`.where`col1=${"*"}`); +var insert = INSERT.into(Table).as( + SELECT.from`Table`.groupBy("col1", "col2").having`col1=${"*"}` +); + +var insert = INSERT.into("Table").as(SELECT.from`Table`.columns`col1, col2`); +var insert = INSERT.into("Table").as(SELECT.from`Table`.where`col1=${"*"}`); +var insert = INSERT.into("Table").as( + SELECT.from`Table`.groupBy("col1", "col2").having`col1=${"*"}` +); + +var insert = INSERT.into`Table`.as(SELECT.from`Table`.columns`col1, col2`); +var insert = INSERT.into`Table`.as(SELECT.from`Table`.where`col1=${"*"}`); +var insert = INSERT.into`Table`.as( + SELECT.from`Table`.groupBy("col1", "col2").having`col1=${"*"}` +); From d09b1c079f8887c29f9ef404a106b9aa96053d9e Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 29 Sep 2023 17:14:23 -0700 Subject: [PATCH 29/61] Update tests for SELECT --- cap/test/cql/select.expected | 133 +---------------------------------- cap/test/cql/select.ql | 5 +- 2 files changed, 4 insertions(+), 134 deletions(-) diff --git a/cap/test/cql/select.expected b/cap/test/cql/select.expected index e0138ea78..3459bed94 100644 --- a/cap/test/cql/select.expected +++ b/cap/test/cql/select.expected @@ -1,132 +1 @@ -| select.js:2:14:2:26 | SELECT`Table` | -| select.js:5:14:5:35 | SELECT. ... `Table` | -| select.js:7:14:7:40 | SELECT. ... `Table` | -| select.js:12:14:12:31 | SELECT.from`Table` | -| select.js:12:14:12:51 | SELECT. ... , col2` | -| select.js:13:14:13:31 | SELECT.from`Table` | -| select.js:16:14:16:31 | SELECT.from`Table` | -| select.js:16:14:16:68 | SELECT. ... lias }` | -| select.js:17:14:17:31 | SELECT.from`Table` | -| select.js:18:14:18:31 | SELECT.from`Table` | -| select.js:22:14:22:31 | SELECT.from`Table` | -| select.js:43:14:43:31 | SELECT.from`Table` | -| select.js:44:14:44:31 | SELECT.from`Table` | -| select.js:45:14:45:31 | SELECT.from`Table` | -| select.js:45:14:45:49 | SELECT. ... 1='*'"` | -| select.js:46:14:46:31 | SELECT.from`Table` | -| select.js:47:14:47:31 | SELECT.from`Table` | -| select.js:47:14:47:51 | SELECT. ... ${"*"}` | -| select.js:48:14:48:31 | SELECT.from`Table` | -| select.js:49:14:49:31 | SELECT.from`Table` | -| select.js:49:14:49:61 | SELECT. ... 10)]}` | -| select.js:50:14:50:31 | SELECT.from`Table` | -| select.js:53:14:53:31 | SELECT.from`Table` | -| select.js:54:14:54:31 | SELECT.from`Table` | -| select.js:54:14:54:51 | SELECT. ... , col2` | -| select.js:55:14:55:31 | SELECT.from`Table` | -| select.js:56:14:56:31 | SELECT.from`Table` | -| select.js:56:14:56:63 | SELECT. ... .prop2` | -| select.js:57:14:57:31 | SELECT.from`Table` | -| select.js:63:14:63:31 | SELECT.from`Table` | -| select.js:64:14:64:31 | SELECT.from`Table` | -| select.js:65:14:65:31 | SELECT.from`Table` | -| select.js:65:14:65:50 | SELECT. ... 1='*'"` | -| select.js:66:14:66:31 | SELECT.from`Table` | -| select.js:67:14:67:31 | SELECT.from`Table` | -| select.js:67:14:67:52 | SELECT. ... ${"*"}` | -| select.js:68:14:68:31 | SELECT.from`Table` | -| select.js:69:14:69:31 | SELECT.from`Table` | -| select.js:69:14:69:62 | SELECT. ... 10)]}` | -| select.js:70:14:70:31 | SELECT.from`Table` | -| select.js:72:14:72:31 | SELECT.from`Table` | -| select.js:73:14:73:31 | SELECT.from`Table` | -| select.js:74:14:74:31 | SELECT.from`Table` | -| select.js:75:14:75:31 | SELECT.from`Table` | -| select.js:76:14:76:31 | SELECT.from`Table` | -| select.js:77:14:77:31 | SELECT.from`Table` | -| select.js:80:14:80:31 | SELECT.from`Table` | -| select.js:83:14:83:31 | SELECT.from`Table` | -| select.js:87:14:87:31 | SELECT.from`Table` | -| select.js:87:14:87:51 | SELECT. ... , col2` | -| select.js:88:14:88:31 | SELECT.from`Table` | -| select.js:88:14:88:51 | SELECT. ... , col2` | -| select.js:89:14:89:31 | SELECT.from`Table` | -| select.js:89:14:89:51 | SELECT. ... , col2` | -| select.js:89:14:89:70 | SELECT. ... 1='*'"` | -| select.js:90:14:90:31 | SELECT.from`Table` | -| select.js:90:14:90:51 | SELECT. ... , col2` | -| select.js:91:14:91:31 | SELECT.from`Table` | -| select.js:91:14:91:51 | SELECT. ... , col2` | -| select.js:91:14:91:72 | SELECT. ... ${"*"}` | -| select.js:92:14:92:31 | SELECT.from`Table` | -| select.js:92:14:92:51 | SELECT. ... , col2` | -| select.js:93:14:93:31 | SELECT.from`Table` | -| select.js:93:14:93:51 | SELECT. ... , col2` | -| select.js:93:14:95:3 | SELECT. ... 0),\\n]}` | -| select.js:96:14:96:31 | SELECT.from`Table` | -| select.js:96:14:96:51 | SELECT. ... , col2` | -| select.js:101:14:101:31 | SELECT.from`Table` | -| select.js:104:14:104:31 | SELECT.from`Table` | -| select.js:107:14:107:31 | SELECT.from`Table` | -| select.js:109:14:109:31 | SELECT.from`Table` | -| select.js:112:14:112:31 | SELECT.from`Table` | -| select.js:114:14:114:31 | SELECT.from`Table` | -| select.js:117:14:117:31 | SELECT.from`Table` | -| select.js:119:14:119:31 | SELECT.from`Table` | -| select.js:123:14:123:31 | SELECT.from`Table` | -| select.js:123:14:123:63 | SELECT. ... .prop2` | -| select.js:126:14:126:31 | SELECT.from`Table` | -| select.js:126:14:126:63 | SELECT. ... .prop2` | -| select.js:129:14:129:31 | SELECT.from`Table` | -| select.js:129:14:129:63 | SELECT. ... .prop2` | -| select.js:129:14:130:21 | SELECT. ... 1='*'"` | -| select.js:131:14:131:31 | SELECT.from`Table` | -| select.js:131:14:131:63 | SELECT. ... .prop2` | -| select.js:135:14:135:31 | SELECT.from`Table` | -| select.js:135:14:135:63 | SELECT. ... .prop2` | -| select.js:135:14:136:23 | SELECT. ... ${"*"}` | -| select.js:137:14:137:31 | SELECT.from`Table` | -| select.js:137:14:137:63 | SELECT. ... .prop2` | -| select.js:140:14:140:31 | SELECT.from`Table` | -| select.js:140:14:140:63 | SELECT. ... .prop2` | -| select.js:140:14:141:33 | SELECT. ... 10)]}` | -| select.js:142:14:142:31 | SELECT.from`Table` | -| select.js:142:14:142:63 | SELECT. ... .prop2` | -| select.js:147:14:147:31 | SELECT.from`Table` | -| select.js:150:14:150:31 | SELECT.from`Table` | -| select.js:153:14:153:31 | SELECT.from`Table` | -| select.js:157:14:157:31 | SELECT.from`Table` | -| select.js:160:14:160:31 | SELECT.from`Table` | -| select.js:164:14:164:31 | SELECT.from`Table` | -| select.js:167:14:167:31 | SELECT.from`Table` | -| select.js:171:14:171:31 | SELECT.from`Table` | -| select.js:176:14:176:31 | SELECT.from`Table` | -| select.js:176:14:176:63 | SELECT. ... .prop2` | -| select.js:177:14:177:31 | SELECT.from`Table` | -| select.js:177:14:177:61 | SELECT. ... .prop2` | -| select.js:178:14:178:31 | SELECT.from`Table` | -| select.js:178:14:178:61 | SELECT. ... l2 asc` | -| select.js:179:14:179:31 | SELECT.from`Table` | -| select.js:179:14:179:58 | SELECT. ... l2 asc` | -| select.js:180:14:180:31 | SELECT.from`Table` | -| select.js:180:14:180:63 | SELECT. ... .prop2` | -| select.js:181:14:181:31 | SELECT.from`Table` | -| select.js:181:14:181:62 | SELECT. ... .prop2` | -| select.js:182:14:182:31 | SELECT.from`Table` | -| select.js:182:14:182:62 | SELECT. ... 2 desc` | -| select.js:183:14:183:31 | SELECT.from`Table` | -| select.js:183:14:183:60 | SELECT. ... 2 desc` | -| select.js:186:14:186:31 | SELECT.from`Table` | -| select.js:187:14:187:31 | SELECT.from`Table` | -| select.js:188:14:188:31 | SELECT.from`Table` | -| select.js:189:14:189:31 | SELECT.from`Table` | -| select.js:190:14:190:31 | SELECT.from`Table` | -| select.js:191:14:191:31 | SELECT.from`Table` | -| select.js:196:14:196:31 | SELECT.from`Table` | -| select.js:196:14:196:51 | SELECT. ... , col2` | -| select.js:196:14:197:23 | SELECT. ... ${"*"}` | -| select.js:200:14:200:31 | SELECT.from`Table` | -| select.js:200:14:200:51 | SELECT. ... , col2` | -| select.js:200:14:201:23 | SELECT. ... ${"*"}` | -| select.js:204:14:204:40 | SELECT. ... `Table` | -| select.js:204:14:204:70 | SELECT. ... 10)]}` | +| hihi | diff --git a/cap/test/cql/select.ql b/cap/test/cql/select.ql index da95f7305..77ee0f12b 100644 --- a/cap/test/cql/select.ql +++ b/cap/test/cql/select.ql @@ -1,4 +1,5 @@ import javascript -import CAPModels +import CQL -select any(Select s) \ No newline at end of file +// select any(CqlSelectExpr s) +select "hihi" \ No newline at end of file From f046ab5d6b30bebf437eed27e301b5fa82d76a6b Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 29 Sep 2023 17:14:42 -0700 Subject: [PATCH 30/61] Implement classes for INSERT and add tests --- cap/CQL.qll | 65 ++++++++++++++++++++++++++++++------ cap/test/cql/insert.expected | 1 + cap/test/cql/insert.ql | 5 +++ 3 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 cap/test/cql/insert.expected create mode 100644 cap/test/cql/insert.ql diff --git a/cap/CQL.qll b/cap/CQL.qll index 3881311ca..ecc8f0079 100644 --- a/cap/CQL.qll +++ b/cap/CQL.qll @@ -1,6 +1,7 @@ private import javascript private import DataFlow +/* TODO: Query bases */ /** * Holds if a `DotExpr` ultimately accesses a `SELECT` variable, e.g. * ```js @@ -116,6 +117,50 @@ private predicate isTaggedTemplateSelect(TaggedTemplateExpr tagExpr) { ) } +private predicate accessesInsert(DotExpr dot) { + dot.accesses(any(VarRef var | var.getName() = "INSERT"), + ["into", "entries", "values", "rows", "as"]) + or + dot.getPropertyName() = ["into", "entries", "values", "rows", "as"] and + accessesInsert(dot.getAChildExpr()) +} + +private predicate isMethodCallInsert(MethodCallExpr callExpr) { + callExpr.getCalleeName() = ["into", "entries", "values", "rows", "as"] and + exists(Expr receiver | receiver = callExpr.getCallee() | + accessesInsert(receiver) + or + exists(TaggedTemplateExpr nestedTaggingExpr | + receiver.(DotExpr).accesses(nestedTaggingExpr, _) + | + isTaggedTemplateInsert(nestedTaggingExpr) + ) + or + exists(MethodCallExpr nestedCallExpr | receiver.(DotExpr).accesses(nestedCallExpr, _) | + isMethodCallInsert(nestedCallExpr) + ) + ) +} + +private predicate isTaggedTemplateInsert(TaggedTemplateExpr tagExpr) { + exists(Expr taggingExpr | + taggingExpr = tagExpr.getTag() and + taggingExpr.(DotExpr).getPropertyName() = ["into", "entries", "values", "rows", "as"] + | + accessesInsert(taggingExpr) + or + exists(TaggedTemplateExpr nestedTaggingExpr | + taggingExpr.(DotExpr).accesses(nestedTaggingExpr, _) + | + isTaggedTemplateInsert(nestedTaggingExpr) + ) + or + exists(MethodCallExpr nestedCallExpr | taggingExpr.(DotExpr).accesses(nestedCallExpr, _) | + isMethodCallInsert(nestedCallExpr) + ) + ) +} + newtype TCqlExpr = TaggedTemplate(TaggedTemplateExpr tagExpr) or MethodCall(MethodCallExpr callExpr) @@ -153,17 +198,17 @@ class CqlSelectExpr extends CqlExpr { } class CqlInsertExpr extends CqlExpr { - CqlInsertExpr() { any() } + CqlInsertExpr() { isMethodCallInsert(this.asMethodCall()) } } -class CqlDeleteExpr extends CqlExpr { - CqlDeleteExpr() { any() } -} +// class CqlDeleteExpr extends CqlExpr { +// CqlDeleteExpr() { any() } +// } -class CqlUpdateExpr extends CqlExpr { - CqlUpdateExpr() { any() } -} +// class CqlUpdateExpr extends CqlExpr { +// CqlUpdateExpr() { any() } +// } -class CqlUpsertExpr extends CqlExpr { - CqlUpsertExpr() { any() } -} +// class CqlUpsertExpr extends CqlExpr { +// CqlUpsertExpr() { any() } +// } diff --git a/cap/test/cql/insert.expected b/cap/test/cql/insert.expected new file mode 100644 index 000000000..3459bed94 --- /dev/null +++ b/cap/test/cql/insert.expected @@ -0,0 +1 @@ +| hihi | diff --git a/cap/test/cql/insert.ql b/cap/test/cql/insert.ql new file mode 100644 index 000000000..becd7e236 --- /dev/null +++ b/cap/test/cql/insert.ql @@ -0,0 +1,5 @@ +import javascript +import CQL + +// select any(CqlInsertExpr s) +select "hihi" From aed2d87a7527dbb821c21c9c00dc833d3da20725 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 2 Oct 2023 17:30:56 -0700 Subject: [PATCH 31/61] Refactor class hierarchy --- cap/CQL.qll | 81 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/cap/CQL.qll b/cap/CQL.qll index ecc8f0079..a479108c8 100644 --- a/cap/CQL.qll +++ b/cap/CQL.qll @@ -1,7 +1,32 @@ private import javascript private import DataFlow +private import CAPModels + +class CqlQueryBase extends VarRef { + CqlQueryBase() { + /* Made available as a global variable */ + exists(GlobalVariable queryBase | + queryBase.getName() = ["SELECT", "INSERT", "DELETE", "UPDATE", "UPSERT"] + | + this = queryBase.getAReference() + ) + or + /* Imported from `cds.ql` */ + exists(CdsFacade cds, PropRef cdsDotQl | + this.flow().getALocalSource() = cdsDotQl and + cdsDotQl.getBase() = cds + ) + } +} + +class CqlSelectBase extends CqlQueryBase { + CqlSelectBase() { this.getName() = "SELECT" } +} + +class CqlInsertBase extends CqlQueryBase { + CqlInsertBase() { this.getName() = "INSERT" } +} -/* TODO: Query bases */ /** * Holds if a `DotExpr` ultimately accesses a `SELECT` variable, e.g. * ```js @@ -76,7 +101,12 @@ private predicate isMethodCallSelect(MethodCallExpr callExpr) { * SELECT.from`Table` * SELECT.distinct.from`Table`; * SELECT.from(Table).where`"col1='*'"`; - * SELECT.from`Table`.having`"col1='*'"`; + * SELECT.from`Table`.having`"col1='*'"`; ==> "Select having call" + * + * + * SELECT.having`"col1='*'".`from`Table`; ==> "Select from call", if we omit `having` from consideration? getLocation() + * + * * ``` */ private predicate isTaggedTemplateSelect(TaggedTemplateExpr tagExpr) { @@ -161,9 +191,25 @@ private predicate isTaggedTemplateInsert(TaggedTemplateExpr tagExpr) { ) } +Expr getRootReceiver(Expr e) { + result = e and e instanceof VarRef + or + result = getRootReceiver(e.(DotExpr).getBase()) + or + result = getRootReceiver(e.(MethodCallExpr).getReceiver()) + or + result = getRootReceiver(e.(PropAccess).getBase()) + or + result = getRootReceiver(e.(TaggedTemplateExpr).getTag()) +} + newtype TCqlExpr = - TaggedTemplate(TaggedTemplateExpr tagExpr) or - MethodCall(MethodCallExpr callExpr) + TaggedTemplate(TaggedTemplateExpr tagExpr) { + exists(CqlQueryBase base | base = getRootReceiver(tagExpr)) + } or + MethodCall(MethodCallExpr callExpr) { + exists(CqlQueryBase base | base = getRootReceiver(callExpr)) + } class CqlExpr extends TCqlExpr { TaggedTemplateExpr asTaggedTemplate() { this = TaggedTemplate(result) } @@ -179,11 +225,31 @@ class CqlExpr extends TCqlExpr { result = this.asTaggedTemplate().getLocation() or result = this.asMethodCall().getLocation() } + + CqlQueryBase getCqlBase() { + result = getRootReceiver(this.asTaggedTemplate()) or + result = getRootReceiver(this.asMethodCall()) + } + + Expr getReceiver() { + result = this.asMethodCall().getReceiver() + or + result = this.asTaggedTemplate().getTag().(DotExpr).getBase() + } + + Expr getParent() { + result = this.asMethodCall().getParent() or + result = this.asTaggedTemplate().getParent() + } } class CqlSelectExpr extends CqlExpr { CqlSelectExpr() { - isMethodCallSelect(this.asMethodCall()) or isTaggedTemplateSelect(this.asTaggedTemplate()) + exists(CqlSelectBase cqlSelect | + this.getCqlBase() = cqlSelect and + not this.getParent() instanceof TaggedTemplateExpr and + not this.getParent() instanceof MethodCallExpr + ) } predicate selectWhere() { @@ -198,17 +264,14 @@ class CqlSelectExpr extends CqlExpr { } class CqlInsertExpr extends CqlExpr { - CqlInsertExpr() { isMethodCallInsert(this.asMethodCall()) } + CqlInsertExpr() { exists(CqlInsertBase cqlInsert | this.getCqlBase() = cqlInsert) } } - // class CqlDeleteExpr extends CqlExpr { // CqlDeleteExpr() { any() } // } - // class CqlUpdateExpr extends CqlExpr { // CqlUpdateExpr() { any() } // } - // class CqlUpsertExpr extends CqlExpr { // CqlUpsertExpr() { any() } // } From bb0030a8f359568361c7c38cc4aa1b16c38b2824 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 3 Oct 2023 15:58:39 -0700 Subject: [PATCH 32/61] Loosen definitions and add modeling of `DELETE`, `UPDATE` and `UPSERT` --- cap/CQL.qll | 288 ++++++++++++++++++++-------------------------------- 1 file changed, 108 insertions(+), 180 deletions(-) diff --git a/cap/CQL.qll b/cap/CQL.qll index a479108c8..d9995028f 100644 --- a/cap/CQL.qll +++ b/cap/CQL.qll @@ -27,168 +27,16 @@ class CqlInsertBase extends CqlQueryBase { CqlInsertBase() { this.getName() = "INSERT" } } -/** - * Holds if a `DotExpr` ultimately accesses a `SELECT` variable, e.g. - * ```js - * SELECT.from - * SELECT.one.from - * SELECT.distinct.from - * ``` - */ -private predicate accessesSelect(DotExpr dot) { - dot.accesses(any(VarRef var | var.getName() = "SELECT"), - [ - "one", "distinct", "columns", "from", "alias", "where", "having", "groupBy", "orderBy", - "limit", "forUpdate", "forShareLock" - ]) - or - dot.getPropertyName() = - [ - "one", "distinct", "columns", "from", "alias", "where", "having", "groupBy", "orderBy", - "limit", "forUpdate", "forShareLock" - ] and - accessesSelect(dot.getAChildExpr()) +class CqlDeleteBase extends CqlQueryBase { + CqlDeleteBase() { this.getName() = "DELETE" } } -/** - * Method call `SELECT` CQL query expressions, e.g. - * ```js - * SELECT.from(Table) - * SELECT.distinct.from(Table); - * SELECT.from`Table`.where("col1='*'"); - * SELECT.from(Table).having("col1='*'"); - * ``` - */ -private predicate isMethodCallSelect(MethodCallExpr callExpr) { - callExpr.getCalleeName() = - [ - "columns", "from", "alias", "where", "having", "groupBy", "orderBy", "limit", "forUpdate", - "forShareLock" - ] and - exists(Expr receiver | receiver = callExpr.getCallee() | - /* - * Only property accesses are left up to SELECT, e.g. - * SELECT.x.y. ...z(cond) - */ - - accessesSelect(receiver) - or - /* - * The immediate prefix is a TaggedTemplateExpr: - * SELECT.x. ... .z`cond1`.w(cond2) - */ - - exists(TaggedTemplateExpr nestedTaggingExpr | - receiver.(DotExpr).accesses(nestedTaggingExpr, _) - | - isTaggedTemplateSelect(nestedTaggingExpr) - ) - or - /* - * The immediate prefix is a MethodCallExpr: - * SELECT.x. ... .z(cond1).w(cond2) - */ - - exists(MethodCallExpr nestedCallExpr | receiver.(DotExpr).accesses(nestedCallExpr, _) | - isMethodCallSelect(nestedCallExpr) - ) - ) +class CqlUpdateBase extends CqlQueryBase { + CqlUpdateBase() { this.getName() = "UPDATE" } } -/** - * Tagged `SELECT` CQL query expressions, e.g. - * ```js - * SELECT.from`Table` - * SELECT.distinct.from`Table`; - * SELECT.from(Table).where`"col1='*'"`; - * SELECT.from`Table`.having`"col1='*'"`; ==> "Select having call" - * - * - * SELECT.having`"col1='*'".`from`Table`; ==> "Select from call", if we omit `having` from consideration? getLocation() - * - * - * ``` - */ -private predicate isTaggedTemplateSelect(TaggedTemplateExpr tagExpr) { - exists(Expr taggingExpr | - taggingExpr = tagExpr.getTag() and - taggingExpr.(DotExpr).getPropertyName() = - [ - "columns", "from", "alias", "where", "having", "groupBy", "orderBy", "limit", "forUpdate", - "forShareLock" - ] - | - /* - * Only property accesses are left up to SELECT, e.g. - * SELECT.x.y. ...z`cond` - */ - - accessesSelect(taggingExpr) - or - /* - * The immediate prefix is a TaggedTemplateExpr: - * SELECT.x. ... .z`cond1`.w`cond2` - */ - - exists(TaggedTemplateExpr nestedTaggingExpr | - taggingExpr.(DotExpr).accesses(nestedTaggingExpr, _) - | - isTaggedTemplateSelect(nestedTaggingExpr) - ) - or - /* - * The immediate prefix is a MethodCallExpr: - * SELECT.x. ... .z(cond1).w`cond2` - */ - - exists(MethodCallExpr nestedCallExpr | taggingExpr.(DotExpr).accesses(nestedCallExpr, _) | - isMethodCallSelect(nestedCallExpr) - ) - ) -} - -private predicate accessesInsert(DotExpr dot) { - dot.accesses(any(VarRef var | var.getName() = "INSERT"), - ["into", "entries", "values", "rows", "as"]) - or - dot.getPropertyName() = ["into", "entries", "values", "rows", "as"] and - accessesInsert(dot.getAChildExpr()) -} - -private predicate isMethodCallInsert(MethodCallExpr callExpr) { - callExpr.getCalleeName() = ["into", "entries", "values", "rows", "as"] and - exists(Expr receiver | receiver = callExpr.getCallee() | - accessesInsert(receiver) - or - exists(TaggedTemplateExpr nestedTaggingExpr | - receiver.(DotExpr).accesses(nestedTaggingExpr, _) - | - isTaggedTemplateInsert(nestedTaggingExpr) - ) - or - exists(MethodCallExpr nestedCallExpr | receiver.(DotExpr).accesses(nestedCallExpr, _) | - isMethodCallInsert(nestedCallExpr) - ) - ) -} - -private predicate isTaggedTemplateInsert(TaggedTemplateExpr tagExpr) { - exists(Expr taggingExpr | - taggingExpr = tagExpr.getTag() and - taggingExpr.(DotExpr).getPropertyName() = ["into", "entries", "values", "rows", "as"] - | - accessesInsert(taggingExpr) - or - exists(TaggedTemplateExpr nestedTaggingExpr | - taggingExpr.(DotExpr).accesses(nestedTaggingExpr, _) - | - isTaggedTemplateInsert(nestedTaggingExpr) - ) - or - exists(MethodCallExpr nestedCallExpr | taggingExpr.(DotExpr).accesses(nestedCallExpr, _) | - isMethodCallInsert(nestedCallExpr) - ) - ) +class CqlUpsertBase extends CqlQueryBase { + CqlUpsertBase() { this.getName() = "UPSERT" } } Expr getRootReceiver(Expr e) { @@ -216,6 +64,19 @@ class CqlExpr extends TCqlExpr { MethodCallExpr asMethodCall() { this = MethodCall(result) } + /** + * Convert this `CqlExpr` into a `DotExpr`, i.e. + * Get SELECT.from`Table` when given SELECT.from`Table`.where`cond`, + * Get SELECT.from(table) when given SELECT.from(table).where`cond`, + * Get SELECT.from`Table` when given SELECT.from`Table`.where(cond), + * Get SELECT.from(table) when given SELECT.from(table).where(cond). + */ + DotExpr asDotExpr() { + result = this.asTaggedTemplate().getTag().(DotExpr) + or + result = this.asMethodCall().getCallee().(DotExpr) + } + string toString() { result = this.asTaggedTemplate().toString() or result = this.asMethodCall().toString() @@ -237,9 +98,40 @@ class CqlExpr extends TCqlExpr { result = this.asTaggedTemplate().getTag().(DotExpr).getBase() } - Expr getParent() { - result = this.asMethodCall().getParent() or - result = this.asTaggedTemplate().getParent() + Expr getParentExpr() { + result = this.asMethodCall().getParentExpr() or + result = this.asTaggedTemplate().getParentExpr() + } + + Expr getAChildExpr() { + result = this.asMethodCall().getAChildExpr() or + result = this.asTaggedTemplate().getAChildExpr() + } + + Expr getAnAncestorExpr() { + result = this.asMethodCall().getParentExpr+() or + result = this.asTaggedTemplate().getParentExpr+() + } + + CqlExpr getAnAncestorCqlExpr() { + result.asTaggedTemplate() = this.getAnAncestorExpr() or + result.asMethodCall() = this.getAnAncestorExpr() + } + + CqlExpr getAChildCqlExpr() { + result.asTaggedTemplate() = this.asMethodCall().getAChildExpr() or + result.asMethodCall() = this.asTaggedTemplate().getAChildExpr() + } + + /** + * Matches the given CqlExpr to its method/property name, nested at arbitrary depth. + */ + string getAnAPIName() { + /* Base case */ + this.asDotExpr().accesses(_, result) + or + /* Inductive case */ + result = this.getAChildCqlExpr().getAnAPIName() } } @@ -247,31 +139,67 @@ class CqlSelectExpr extends CqlExpr { CqlSelectExpr() { exists(CqlSelectBase cqlSelect | this.getCqlBase() = cqlSelect and - not this.getParent() instanceof TaggedTemplateExpr and - not this.getParent() instanceof MethodCallExpr + not exists( + any(CqlExpr ancestorSelect | + ancestorSelect = this.getAnAncestorCqlExpr() and ancestorSelect.getCqlBase() = cqlSelect + ) + ) ) } - predicate selectWhere() { - this.asMethodCall().getMethodName() = "where" or - this.asTaggedTemplate().getTag().(DotExpr).getPropertyName() = "where" + predicate selectWhere() { this.getAnAPIName() = "where" } + + predicate selectFrom() { this.getAnAPIName() = "from" } +} + +class CqlInsertExpr extends CqlExpr { + CqlInsertExpr() { + exists(CqlInsertBase cqlInsert | + this.getCqlBase() = cqlInsert and + not exists( + any(CqlExpr ancestorInsert | + ancestorInsert = this.getAnAncestorCqlExpr() and ancestorInsert.getCqlBase() = cqlInsert + ) + ) + ) } +} - predicate selectFrom() { - this.asMethodCall().getMethodName() = "from" or - this.asTaggedTemplate().getTag().(DotExpr).getPropertyName() = "from" +class CqlDeleteExpr extends CqlExpr { + CqlDeleteExpr() { + exists(CqlDeleteBase cqlDelete | + this.getCqlBase() = cqlDelete and + not exists( + any(CqlExpr ancestorDelete | + ancestorDelete = this.getAnAncestorCqlExpr() and ancestorDelete.getCqlBase() = cqlDelete + ) + ) + ) } } -class CqlInsertExpr extends CqlExpr { - CqlInsertExpr() { exists(CqlInsertBase cqlInsert | this.getCqlBase() = cqlInsert) } +class CqlUpdateExpr extends CqlExpr { + CqlUpdateExpr() { + exists(CqlUpdateBase cqlUpdate | + this.getCqlBase() = cqlUpdate and + not exists( + any(CqlExpr ancestorUpdate | + ancestorUpdate = this.getAnAncestorCqlExpr() and ancestorUpdate.getCqlBase() = cqlUpdate + ) + ) + ) + } +} + +class CqlUpsertExpr extends CqlExpr { + CqlUpsertExpr() { + exists(CqlUpsertBase cqlUpsert | + this.getCqlBase() = cqlUpsert and + not exists( + any(CqlExpr ancestorUpsert | + ancestorUpsert = this.getAnAncestorCqlExpr() and ancestorUpsert.getCqlBase() = cqlUpsert + ) + ) + ) + } } -// class CqlDeleteExpr extends CqlExpr { -// CqlDeleteExpr() { any() } -// } -// class CqlUpdateExpr extends CqlExpr { -// CqlUpdateExpr() { any() } -// } -// class CqlUpsertExpr extends CqlExpr { -// CqlUpsertExpr() { any() } -// } From 3c8c76d415c71a2cdd0f968e83687142486ea43b Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 3 Oct 2023 16:48:33 -0700 Subject: [PATCH 33/61] Debug `getAnAPIName/0` --- cap/CQL.qll | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/cap/CQL.qll b/cap/CQL.qll index d9995028f..b1bf6453b 100644 --- a/cap/CQL.qll +++ b/cap/CQL.qll @@ -108,6 +108,11 @@ class CqlExpr extends TCqlExpr { result = this.asTaggedTemplate().getAChildExpr() } + Expr getADescendantExpr() { + result = this.asMethodCall().getAChildExpr+() or + result = this.asTaggedTemplate().getAChildExpr+() + } + Expr getAnAncestorExpr() { result = this.asMethodCall().getParentExpr+() or result = this.asTaggedTemplate().getParentExpr+() @@ -123,15 +128,17 @@ class CqlExpr extends TCqlExpr { result.asMethodCall() = this.asTaggedTemplate().getAChildExpr() } + CqlExpr getADescendantCqlExpr() { + result.asTaggedTemplate() = this.getADescendantExpr() or + result.asMethodCall() = this.getADescendantExpr() + } + /** * Matches the given CqlExpr to its method/property name, nested at arbitrary depth. */ string getAnAPIName() { - /* Base case */ - this.asDotExpr().accesses(_, result) - or - /* Inductive case */ - result = this.getAChildCqlExpr().getAnAPIName() + result = this.asDotExpr().getPropertyName() or + result = this.getADescendantCqlExpr().getAnAPIName() } } From d8ae9f15f8f82df59dc2b9db5a75fd9bdf543528 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 3 Oct 2023 16:53:10 -0700 Subject: [PATCH 34/61] Make similar member predicates close to each other --- cap/CQL.qll | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/cap/CQL.qll b/cap/CQL.qll index b1bf6453b..a1aa9425f 100644 --- a/cap/CQL.qll +++ b/cap/CQL.qll @@ -103,14 +103,9 @@ class CqlExpr extends TCqlExpr { result = this.asTaggedTemplate().getParentExpr() } - Expr getAChildExpr() { - result = this.asMethodCall().getAChildExpr() or - result = this.asTaggedTemplate().getAChildExpr() - } - - Expr getADescendantExpr() { - result = this.asMethodCall().getAChildExpr+() or - result = this.asTaggedTemplate().getAChildExpr+() + CqlExpr getCqlParentExpr() { + result.asTaggedTemplate() = this.asMethodCall().getParentExpr() or + result.asMethodCall() = this.asTaggedTemplate().getParentExpr() } Expr getAnAncestorExpr() { @@ -123,11 +118,21 @@ class CqlExpr extends TCqlExpr { result.asMethodCall() = this.getAnAncestorExpr() } + Expr getAChildExpr() { + result = this.asMethodCall().getAChildExpr() or + result = this.asTaggedTemplate().getAChildExpr() + } + CqlExpr getAChildCqlExpr() { result.asTaggedTemplate() = this.asMethodCall().getAChildExpr() or result.asMethodCall() = this.asTaggedTemplate().getAChildExpr() } + Expr getADescendantExpr() { + result = this.asMethodCall().getAChildExpr+() or + result = this.asTaggedTemplate().getAChildExpr+() + } + CqlExpr getADescendantCqlExpr() { result.asTaggedTemplate() = this.getADescendantExpr() or result.asMethodCall() = this.getADescendantExpr() From b5f0bebe883bad85af5038455c713723c544256c Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 4 Oct 2023 16:38:30 -0700 Subject: [PATCH 35/61] Add tests for `UPDATE` --- cap/test/cql/update.js | 260 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 cap/test/cql/update.js diff --git a/cap/test/cql/update.js b/cap/test/cql/update.js new file mode 100644 index 000000000..1199db6aa --- /dev/null +++ b/cap/test/cql/update.js @@ -0,0 +1,260 @@ +// TaggedTemplate: UPDATE, entity, set, with, where + +let diff = 1; +let val = 2; + +/* ========== UPDATE (entity), set ========== */ + +/* Without `entity` */ +var update = UPDATE`Table`.set`col1 = col1 - ${diff}`; +var update = UPDATE`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }); // CQN +var update = UPDATE`Table`.set({ col1: diff }); // QBE + +/* With `entity` */ +var update = UPDATE.entity(Table).set`col1 = col1 - ${diff}`; +var update = UPDATE.entity(Table).set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }); // CQN +var update = UPDATE.entity(Table).set({ col1: diff }); // QBE + +var update = UPDATE.entity("Table").set`col1 = col1 - ${diff}`; +var update = UPDATE.entity("Table").set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }); // CQN +var update = UPDATE.entity("Table").set({ col1: diff }); // QBE + +var update = UPDATE.entity`Table`.set`col1 = col1 - ${diff}`; +var update = UPDATE.entity`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }); // CQN +var update = UPDATE.entity`Table`.set({ col1: diff }); // QBE + +/* ========== UPDATE (entity), with ========== */ + +/* Without `entity` */ +var update = UPDATE`Table`.with`col1 = col1 - ${diff}`; +var update = UPDATE`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }); // CQN +var update = UPDATE`Table`.with({ col1: diff }); // QBE + +/* With `entity` */ +var update = UPDATE.entity`Table`.with`col1 = col1 - ${diff}`; +var update = UPDATE.entity`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }); // CQN +var update = UPDATE.entity`Table`.with({ col1: diff }); // QBE + +/* ========== UPDATE (entity), set, where ========== */ + +/* Without `entity` */ +var update = UPDATE`Table`.set`col1 = col1 - ${diff}`.where({ col1: "*" }); +var update = UPDATE`Table`.set`col1 = col1 - ${diff}`.where("col1='*'"); +var update = UPDATE`Table`.set`col1 = col1 - ${diff}`.where`col1=${"*"}`; +var update = UPDATE`Table`.set`col1 = col1 - ${diff}`.where("col1=", "*"); +var update = UPDATE`Table`.set`col1 = col1 - ${diff}`.where`col = ${"*"}`; +var update = UPDATE`Table`.set`col1 = col1 - ${diff}`.where("col1 in ('*', 10)"); +var update = UPDATE`Table`.set`col1 = col1 - ${diff}`.where`col1 in ${[ ("*", 10), ]}`; +var update = UPDATE`Table`.set`col1 = col1 - ${diff}`.where({ col1: 10, and: { col2: 11 }, }); + +var update = UPDATE`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: "*" }); +var update = UPDATE`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1='*'"); +var update = UPDATE`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1=${"*"}`; +var update = UPDATE`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1=", "*"); +var update = UPDATE`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col = ${"*"}`; +var update = UPDATE`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1 in ('*', 10)"); +var update = UPDATE`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: 10, and: { col2: 11 } }); + +var update = UPDATE`Table`.set({ col1: diff }).where({ col1: "*" }); +var update = UPDATE`Table`.set({ col1: diff }).where("col1='*'"); +var update = UPDATE`Table`.set({ col1: diff }).where`col1=${"*"}`; +var update = UPDATE`Table`.set({ col1: diff }).where("col1=", "*"); +var update = UPDATE`Table`.set({ col1: diff }).where`col = ${"*"}`; +var update = UPDATE`Table`.set({ col1: diff }).where("col1 in ('*', 10)"); +var update = UPDATE`Table`.set({ col1: diff }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE`Table`.set({ col1: diff }).where({ col1: 10, and: { col2: 11 } }); + +/* With `entity` */ +var update = UPDATE.entity`Table`.set`col1 = col1 - ${diff}`.where({ col1: "*" }); +var update = UPDATE.entity`Table`.set`col1 = col1 - ${diff}`.where("col1='*'"); +var update = UPDATE.entity`Table`.set`col1 = col1 - ${diff}`.where`col1=${"*"}`; +var update = UPDATE.entity`Table`.set`col1 = col1 - ${diff}`.where("col1=", "*"); +var update = UPDATE.entity`Table`.set`col1 = col1 - ${diff}`.where`col = ${"*"}`; +var update = UPDATE.entity`Table`.set`col1 = col1 - ${diff}`.where("col1 in ('*', 10)"); +var update = UPDATE.entity`Table`.set`col1 = col1 - ${diff}`.where`col1 in ${[ ("*", 10), ]}`; +var update = UPDATE.entity`Table`.set`col1 = col1 - ${diff}`.where({ col1: 10, and: { col2: 11 }, }); + +var update = UPDATE.entity`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: "*" }); +var update = UPDATE.entity`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1='*'"); +var update = UPDATE.entity`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1=${"*"}`; +var update = UPDATE.entity`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1=", "*"); +var update = UPDATE.entity`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col = ${"*"}`; +var update = UPDATE.entity`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1 in ('*', 10)"); +var update = UPDATE.entity`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE.entity`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: 10, and: { col2: 11 } }); + +var update = UPDATE.entity`Table`.set({ col1: diff }).where({ col1: "*" }); +var update = UPDATE.entity`Table`.set({ col1: diff }).where("col1='*'"); +var update = UPDATE.entity`Table`.set({ col1: diff }).where`col1=${"*"}`; +var update = UPDATE.entity`Table`.set({ col1: diff }).where("col1=", "*"); +var update = UPDATE.entity`Table`.set({ col1: diff }).where`col = ${"*"}`; +var update = UPDATE.entity`Table`.set({ col1: diff }).where("col1 in ('*', 10)"); +var update = UPDATE.entity`Table`.set({ col1: diff }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE.entity`Table`.set({ col1: diff }).where({ col1: 10, and: { col2: 11 } }); + +var update = UPDATE.entity(Table).set`col1 = col1 - ${diff}`.where({ col1: "*" }); +var update = UPDATE.entity(Table).set`col1 = col1 - ${diff}`.where("col1='*'"); +var update = UPDATE.entity(Table).set`col1 = col1 - ${diff}`.where`col1=${"*"}`; +var update = UPDATE.entity(Table).set`col1 = col1 - ${diff}`.where("col1=", "*"); +var update = UPDATE.entity(Table).set`col1 = col1 - ${diff}`.where`col = ${"*"}`; +var update = UPDATE.entity(Table).set`col1 = col1 - ${diff}`.where("col1 in ('*', 10)"); +var update = UPDATE.entity(Table).set`col1 = col1 - ${diff}`.where`col1 in ${[ ("*", 10), ]}`; +var update = UPDATE.entity(Table).set`col1 = col1 - ${diff}`.where({ col1: 10, and: { col2: 11 }, }); + +var update = UPDATE.entity(Table).set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: "*" }); +var update = UPDATE.entity(Table).set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1='*'"); +var update = UPDATE.entity(Table).set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1=${"*"}`; +var update = UPDATE.entity(Table).set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1=", "*"); +var update = UPDATE.entity(Table).set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col = ${"*"}`; +var update = UPDATE.entity(Table).set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1 in ('*', 10)"); +var update = UPDATE.entity(Table).set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE.entity(Table).set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: 10, and: { col2: 11 } }); + +var update = UPDATE.entity(Table).set({ col1: diff }).where({ col1: "*" }); +var update = UPDATE.entity(Table).set({ col1: diff }).where("col1='*'"); +var update = UPDATE.entity(Table).set({ col1: diff }).where`col1=${"*"}`; +var update = UPDATE.entity(Table).set({ col1: diff }).where("col1=", "*"); +var update = UPDATE.entity(Table).set({ col1: diff }).where`col = ${"*"}`; +var update = UPDATE.entity(Table).set({ col1: diff }).where("col1 in ('*', 10)"); +var update = UPDATE.entity(Table).set({ col1: diff }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE.entity(Table).set({ col1: diff }).where({ col1: 10, and: { col2: 11 } }); + +var update = UPDATE.entity("Table").set`col1 = col1 - ${diff}`.where({ col1: "*" }); +var update = UPDATE.entity("Table").set`col1 = col1 - ${diff}`.where("col1='*'"); +var update = UPDATE.entity("Table").set`col1 = col1 - ${diff}`.where`col1=${"*"}`; +var update = UPDATE.entity("Table").set`col1 = col1 - ${diff}`.where("col1=", "*"); +var update = UPDATE.entity("Table").set`col1 = col1 - ${diff}`.where`col = ${"*"}`; +var update = UPDATE.entity("Table").set`col1 = col1 - ${diff}`.where("col1 in ('*', 10)"); +var update = UPDATE.entity("Table").set`col1 = col1 - ${diff}`.where`col1 in ${[ ("*", 10), ]}`; +var update = UPDATE.entity("Table").set`col1 = col1 - ${diff}`.where({ col1: 10, and: { col2: 11 }, }); + +var update = UPDATE.entity("Table").set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: "*" }); +var update = UPDATE.entity("Table").set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1='*'"); +var update = UPDATE.entity("Table").set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1=${"*"}`; +var update = UPDATE.entity("Table").set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1=", "*"); +var update = UPDATE.entity("Table").set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col = ${"*"}`; +var update = UPDATE.entity("Table").set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1 in ('*', 10)"); +var update = UPDATE.entity("Table").set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE.entity("Table").set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: 10, and: { col2: 11 } }); + +var update = UPDATE.entity("Table").set({ col1: diff }).where({ col1: "*" }); +var update = UPDATE.entity("Table").set({ col1: diff }).where("col1='*'"); +var update = UPDATE.entity("Table").set({ col1: diff }).where`col1=${"*"}`; +var update = UPDATE.entity("Table").set({ col1: diff }).where("col1=", "*"); +var update = UPDATE.entity("Table").set({ col1: diff }).where`col = ${"*"}`; +var update = UPDATE.entity("Table").set({ col1: diff }).where("col1 in ('*', 10)"); +var update = UPDATE.entity("Table").set({ col1: diff }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE.entity("Table").set({ col1: diff }).where({ col1: 10, and: { col2: 11 } }); + +/* ========== UPDATE (entity), with, where ========== */ + +/* Without `entity` */ +var update = UPDATE`Table`.with`col1 = col1 - ${diff}`.where({ col1: "*" }); +var update = UPDATE`Table`.with`col1 = col1 - ${diff}`.where("col1='*'"); +var update = UPDATE`Table`.with`col1 = col1 - ${diff}`.where`col1=${"*"}`; +var update = UPDATE`Table`.with`col1 = col1 - ${diff}`.where("col1=", "*"); +var update = UPDATE`Table`.with`col1 = col1 - ${diff}`.where`col = ${"*"}`; +var update = UPDATE`Table`.with`col1 = col1 - ${diff}`.where("col1 in ('*', 10)"); +var update = UPDATE`Table`.with`col1 = col1 - ${diff}`.where`col1 in ${[ ("*", 10), ]}`; +var update = UPDATE`Table`.with`col1 = col1 - ${diff}`.where({ col1: 10, and: { col2: 11 }, }); + +var update = UPDATE`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: "*" }); +var update = UPDATE`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1='*'"); +var update = UPDATE`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1=${"*"}`; +var update = UPDATE`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1=", "*"); +var update = UPDATE`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col = ${"*"}`; +var update = UPDATE`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1 in ('*', 10)"); +var update = UPDATE`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: 10, and: { col2: 11 } }); + +var update = UPDATE`Table`.with({ col1: diff }).where({ col1: "*" }); +var update = UPDATE`Table`.with({ col1: diff }).where("col1='*'"); +var update = UPDATE`Table`.with({ col1: diff }).where`col1=${"*"}`; +var update = UPDATE`Table`.with({ col1: diff }).where("col1=", "*"); +var update = UPDATE`Table`.with({ col1: diff }).where`col = ${"*"}`; +var update = UPDATE`Table`.with({ col1: diff }).where("col1 in ('*', 10)"); +var update = UPDATE`Table`.with({ col1: diff }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE`Table`.with({ col1: diff }).where({ col1: 10, and: { col2: 11 } }); + +/* With `entity` */ +var update = UPDATE.entity`Table`.with`col1 = col1 - ${diff}`.where({ col1: "*" }); +var update = UPDATE.entity`Table`.with`col1 = col1 - ${diff}`.where("col1='*'"); +var update = UPDATE.entity`Table`.with`col1 = col1 - ${diff}`.where`col1=${"*"}`; +var update = UPDATE.entity`Table`.with`col1 = col1 - ${diff}`.where("col1=", "*"); +var update = UPDATE.entity`Table`.with`col1 = col1 - ${diff}`.where`col = ${"*"}`; +var update = UPDATE.entity`Table`.with`col1 = col1 - ${diff}`.where("col1 in ('*', 10)"); +var update = UPDATE.entity`Table`.with`col1 = col1 - ${diff}`.where`col1 in ${[ ("*", 10), ]}`; +var update = UPDATE.entity`Table`.with`col1 = col1 - ${diff}`.where({ col1: 10, and: { col2: 11 }, }); + +var update = UPDATE.entity`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: "*" }); +var update = UPDATE.entity`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1='*'"); +var update = UPDATE.entity`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1=${"*"}`; +var update = UPDATE.entity`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1=", "*"); +var update = UPDATE.entity`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col = ${"*"}`; +var update = UPDATE.entity`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1 in ('*', 10)"); +var update = UPDATE.entity`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE.entity`Table`.with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: 10, and: { col2: 11 } }); + +var update = UPDATE.entity`Table`.with({ col1: diff }).where({ col1: "*" }); +var update = UPDATE.entity`Table`.with({ col1: diff }).where("col1='*'"); +var update = UPDATE.entity`Table`.with({ col1: diff }).where`col1=${"*"}`; +var update = UPDATE.entity`Table`.with({ col1: diff }).where("col1=", "*"); +var update = UPDATE.entity`Table`.with({ col1: diff }).where`col = ${"*"}`; +var update = UPDATE.entity`Table`.with({ col1: diff }).where("col1 in ('*', 10)"); +var update = UPDATE.entity`Table`.with({ col1: diff }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE.entity`Table`.with({ col1: diff }).where({ col1: 10, and: { col2: 11 } }); + +var update = UPDATE.entity(Table).with`col1 = col1 - ${diff}`.where({ col1: "*" }); +var update = UPDATE.entity(Table).with`col1 = col1 - ${diff}`.where("col1='*'"); +var update = UPDATE.entity(Table).with`col1 = col1 - ${diff}`.where`col1=${"*"}`; +var update = UPDATE.entity(Table).with`col1 = col1 - ${diff}`.where("col1=", "*"); +var update = UPDATE.entity(Table).with`col1 = col1 - ${diff}`.where`col = ${"*"}`; +var update = UPDATE.entity(Table).with`col1 = col1 - ${diff}`.where("col1 in ('*', 10)"); +var update = UPDATE.entity(Table).with`col1 = col1 - ${diff}`.where`col1 in ${[ ("*", 10), ]}`; +var update = UPDATE.entity(Table).with`col1 = col1 - ${diff}`.where({ col1: 10, and: { col2: 11 }, }); + +var update = UPDATE.entity(Table).with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: "*" }); +var update = UPDATE.entity(Table).with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1='*'"); +var update = UPDATE.entity(Table).with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1=${"*"}`; +var update = UPDATE.entity(Table).with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1=", "*"); +var update = UPDATE.entity(Table).with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col = ${"*"}`; +var update = UPDATE.entity(Table).with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1 in ('*', 10)"); +var update = UPDATE.entity(Table).with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE.entity(Table).with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: 10, and: { col2: 11 } }); + +var update = UPDATE.entity(Table).with({ col1: diff }).where({ col1: "*" }); +var update = UPDATE.entity(Table).with({ col1: diff }).where("col1='*'"); +var update = UPDATE.entity(Table).with({ col1: diff }).where`col1=${"*"}`; +var update = UPDATE.entity(Table).with({ col1: diff }).where("col1=", "*"); +var update = UPDATE.entity(Table).with({ col1: diff }).where`col = ${"*"}`; +var update = UPDATE.entity(Table).with({ col1: diff }).where("col1 in ('*', 10)"); +var update = UPDATE.entity(Table).with({ col1: diff }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE.entity(Table).with({ col1: diff }).where({ col1: 10, and: { col2: 11 } }); + +var update = UPDATE.entity("Table").with`col1 = col1 - ${diff}`.where({ col1: "*" }); +var update = UPDATE.entity("Table").with`col1 = col1 - ${diff}`.where("col1='*'"); +var update = UPDATE.entity("Table").with`col1 = col1 - ${diff}`.where`col1=${"*"}`; +var update = UPDATE.entity("Table").with`col1 = col1 - ${diff}`.where("col1=", "*"); +var update = UPDATE.entity("Table").with`col1 = col1 - ${diff}`.where`col = ${"*"}`; +var update = UPDATE.entity("Table").with`col1 = col1 - ${diff}`.where("col1 in ('*', 10)"); +var update = UPDATE.entity("Table").with`col1 = col1 - ${diff}`.where`col1 in ${[ ("*", 10), ]}`; +var update = UPDATE.entity("Table").with`col1 = col1 - ${diff}`.where({ col1: 10, and: { col2: 11 }, }); + +var update = UPDATE.entity("Table").with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: "*" }); +var update = UPDATE.entity("Table").with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1='*'"); +var update = UPDATE.entity("Table").with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1=${"*"}`; +var update = UPDATE.entity("Table").with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1=", "*"); +var update = UPDATE.entity("Table").with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col = ${"*"}`; +var update = UPDATE.entity("Table").with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where("col1 in ('*', 10)"); +var update = UPDATE.entity("Table").with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE.entity("Table").with({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] } }).where({ col1: 10, and: { col2: 11 } }); + +var update = UPDATE.entity("Table").with({ col1: diff }).where({ col1: "*" }); +var update = UPDATE.entity("Table").with({ col1: diff }).where("col1='*'"); +var update = UPDATE.entity("Table").with({ col1: diff }).where`col1=${"*"}`; +var update = UPDATE.entity("Table").with({ col1: diff }).where("col1=", "*"); +var update = UPDATE.entity("Table").with({ col1: diff }).where`col = ${"*"}`; +var update = UPDATE.entity("Table").with({ col1: diff }).where("col1 in ('*', 10)"); +var update = UPDATE.entity("Table").with({ col1: diff }).where`col1 in ${[("*", 10)]}`; +var update = UPDATE.entity("Table").with({ col1: diff }).where({ col1: 10, and: { col2: 11 } }); From 71ae19e2def73bcb28e5f867abede677a88c6755 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 4 Oct 2023 16:38:55 -0700 Subject: [PATCH 36/61] Add a single case for `INSERT` --- cap/test/cql/insert.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cap/test/cql/insert.js b/cap/test/cql/insert.js index e140dbea9..bc69b244b 100644 --- a/cap/test/cql/insert.js +++ b/cap/test/cql/insert.js @@ -3,6 +3,10 @@ var insert = INSERT.into(Table, [ { col1: "val11", col2: "val12" }, { col1: "val21", col2: "val22" }, ]); +var insert = INSERT.into("Table", [ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]); /* ========== into, entries ========== */ var insert = INSERT.into(Table).entries( From 2d6620b30eb4d3fd2e1eaee5c28dfa340cce8846 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 4 Oct 2023 16:39:13 -0700 Subject: [PATCH 37/61] Add minor delimiting comments --- cap/CQL.qll | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cap/CQL.qll b/cap/CQL.qll index a1aa9425f..03ffc989f 100644 --- a/cap/CQL.qll +++ b/cap/CQL.qll @@ -98,6 +98,8 @@ class CqlExpr extends TCqlExpr { result = this.asTaggedTemplate().getTag().(DotExpr).getBase() } + /* ========== Parent relationships ========== */ + Expr getParentExpr() { result = this.asMethodCall().getParentExpr() or result = this.asTaggedTemplate().getParentExpr() @@ -118,6 +120,8 @@ class CqlExpr extends TCqlExpr { result.asMethodCall() = this.getAnAncestorExpr() } + /* ========== Children relationships ========== */ + Expr getAChildExpr() { result = this.asMethodCall().getAChildExpr() or result = this.asTaggedTemplate().getAChildExpr() From 4731166a879721308d74f042c96fd764a8553a0e Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 4 Oct 2023 16:40:10 -0700 Subject: [PATCH 38/61] Remove unnecessary comment --- cap/test/cql/update.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/cap/test/cql/update.js b/cap/test/cql/update.js index 1199db6aa..186a440cd 100644 --- a/cap/test/cql/update.js +++ b/cap/test/cql/update.js @@ -1,5 +1,3 @@ -// TaggedTemplate: UPDATE, entity, set, with, where - let diff = 1; let val = 2; From 4310fa503d1fd4c93a9ac3da43fd6995594c786d Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 4 Oct 2023 16:48:56 -0700 Subject: [PATCH 39/61] Add unit tests for `DELETE` --- cap/test/cql/delete.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 cap/test/cql/delete.js diff --git a/cap/test/cql/delete.js b/cap/test/cql/delete.js new file mode 100644 index 000000000..4ae15ae94 --- /dev/null +++ b/cap/test/cql/delete.js @@ -0,0 +1,17 @@ +var delete_ = DELETE.from`Table`.where({ col1: "*" }); +var delete_ = DELETE.from`Table`.where("col1='*'"); +var delete_ = DELETE.from`Table`.where`col1=${"*"}`; +var delete_ = DELETE.from`Table`.where("col1=", "*"); +var delete_ = DELETE.from`Table`.where`col = ${"*"}`; +var delete_ = DELETE.from`Table`.where("col1 in ('*', 10)"); +var delete_ = DELETE.from`Table`.where`col1 in ${[("*", 10)]}`; +var delete_ = DELETE.from`Table`.where({ col1: 10, and: { col2: 11 } }); + +var delete_ = DELETE.from(Table).where({ col1: "*" }); +var delete_ = DELETE.from(Table).where("col1='*'"); +var delete_ = DELETE.from(Table).where`col1=${"*"}`; +var delete_ = DELETE.from(Table).where("col1=", "*"); +var delete_ = DELETE.from(Table).where`col = ${"*"}`; +var delete_ = DELETE.from(Table).where("col1 in ('*', 10)"); +var delete_ = DELETE.from(Table).where`col1 in ${[("*", 10)]}`; +var delete_ = DELETE.from(Table).where({ col1: 10, and: { col2: 11 } }); \ No newline at end of file From 66eccc5caaade43346f664c5516c5570af9bf9dd Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 4 Oct 2023 16:50:24 -0700 Subject: [PATCH 40/61] Add delete.expected and correct other unit test drivers --- cap/test/cql/delete.expected | 0 cap/test/cql/delete.ql | 5 +++++ cap/test/cql/insert.ql | 3 +-- cap/test/cql/select.ql | 3 +-- 4 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 cap/test/cql/delete.expected create mode 100644 cap/test/cql/delete.ql diff --git a/cap/test/cql/delete.expected b/cap/test/cql/delete.expected new file mode 100644 index 000000000..e69de29bb diff --git a/cap/test/cql/delete.ql b/cap/test/cql/delete.ql new file mode 100644 index 000000000..4942d70d2 --- /dev/null +++ b/cap/test/cql/delete.ql @@ -0,0 +1,5 @@ +import javascript +import CQL + +select any(CqlDeleteExpr s) + diff --git a/cap/test/cql/insert.ql b/cap/test/cql/insert.ql index becd7e236..1e8d9faf4 100644 --- a/cap/test/cql/insert.ql +++ b/cap/test/cql/insert.ql @@ -1,5 +1,4 @@ import javascript import CQL -// select any(CqlInsertExpr s) -select "hihi" +select any(CqlInsertExpr s) diff --git a/cap/test/cql/select.ql b/cap/test/cql/select.ql index 77ee0f12b..cd96c0834 100644 --- a/cap/test/cql/select.ql +++ b/cap/test/cql/select.ql @@ -1,5 +1,4 @@ import javascript import CQL -// select any(CqlSelectExpr s) -select "hihi" \ No newline at end of file +select any(CqlSelectExpr s) \ No newline at end of file From 7a1a52be1cc581feb6f7249531c7bc770174bfe2 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 4 Oct 2023 17:06:44 -0700 Subject: [PATCH 41/61] Add cases for INSERT where INSERT is a shortcut for INSERT.entries and .entries() takes an array --- cap/test/cql/insert.js | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/cap/test/cql/insert.js b/cap/test/cql/insert.js index bc69b244b..7be1090e1 100644 --- a/cap/test/cql/insert.js +++ b/cap/test/cql/insert.js @@ -1,4 +1,13 @@ /* ========== into ========== */ +var insert = INSERT([ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]).into(Table); +var insert = INSERT([ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]).into("Table"); + var insert = INSERT.into(Table, [ { col1: "val11", col2: "val12" }, { col1: "val21", col2: "val22" }, @@ -13,14 +22,26 @@ var insert = INSERT.into(Table).entries( { col1: "val11", col2: "val12" }, { col1: "val21", col2: "val22" } ); -var insert = INSERT.into("Table").entries( +var insert = INSERT.into(Table).entries([ { col1: "val11", col2: "val12" }, - { col1: "val21", col2: "val22" } -); -var insert = INSERT.into`Table`.entries( + { col1: "val21", col2: "val22" }, +]); +var insert = INSERT.into("Table").entries([ { col1: "val11", col2: "val12" }, - { col1: "val21", col2: "val22" } -); + { col1: "val21", col2: "val22" }, +]); +var insert = INSERT.into("Table").entries([ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]); +var insert = INSERT.into`Table`.entries([ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]); +var insert = INSERT.into`Table`.entries([ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]); /* ========== into, columns, values ========== */ var insert = INSERT.into(Table) From 7619b952a4a9b7cf36044cbc49e669c9ce8326ed Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 4 Oct 2023 17:08:42 -0700 Subject: [PATCH 42/61] Add tests for upsert and add `.expected` --- cap/test/cql/update.expected | 0 cap/test/cql/update.ql | 5 ++++ cap/test/cql/upsert.expected | 0 cap/test/cql/upsert.js | 44 ++++++++++++++++++++++++++++++++++++ cap/test/cql/upsert.ql | 5 ++++ 5 files changed, 54 insertions(+) create mode 100644 cap/test/cql/update.expected create mode 100644 cap/test/cql/update.ql create mode 100644 cap/test/cql/upsert.expected create mode 100644 cap/test/cql/upsert.js create mode 100644 cap/test/cql/upsert.ql diff --git a/cap/test/cql/update.expected b/cap/test/cql/update.expected new file mode 100644 index 000000000..e69de29bb diff --git a/cap/test/cql/update.ql b/cap/test/cql/update.ql new file mode 100644 index 000000000..0d4b9e72d --- /dev/null +++ b/cap/test/cql/update.ql @@ -0,0 +1,5 @@ +import javascript +import CQL + +select any(CqlUpdateExpr s) + diff --git a/cap/test/cql/upsert.expected b/cap/test/cql/upsert.expected new file mode 100644 index 000000000..e69de29bb diff --git a/cap/test/cql/upsert.js b/cap/test/cql/upsert.js new file mode 100644 index 000000000..78d0100ab --- /dev/null +++ b/cap/test/cql/upsert.js @@ -0,0 +1,44 @@ +/* ========== into ========== */ +var upsert = UPSERT([ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]).into(Table); +var upsert = UPSERT([ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]).into("Table"); + +var upsert = UPSERT.into(Table, [ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]); +var upsert = UPSERT.into("Table", [ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]); + +/* ========== into, entries ========== */ +var upsert = UPSERT.into(Table).entries( + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" } +); +var upsert = UPSERT.into(Table).entries([ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]); +var upsert = UPSERT.into("Table").entries([ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]); +var upsert = UPSERT.into("Table").entries([ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]); +var upsert = UPSERT.into`Table`.entries([ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]); +var upsert = UPSERT.into`Table`.entries([ + { col1: "val11", col2: "val12" }, + { col1: "val21", col2: "val22" }, +]); diff --git a/cap/test/cql/upsert.ql b/cap/test/cql/upsert.ql new file mode 100644 index 000000000..151471f8a --- /dev/null +++ b/cap/test/cql/upsert.ql @@ -0,0 +1,5 @@ +import javascript +import CQL + +select any(CqlUpsertExpr s) + From 1d96665ec05b225d05f6c0b748250ccf274cc1b8 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 5 Oct 2023 16:52:42 -0700 Subject: [PATCH 43/61] Move contents of cap/ according to new repository structure --- cap/codeql-pack.lock.yml | 14 ------------- cap/qlpack.yml | 7 ------- cap/service_test.js | 0 cap/test/codeql-pack.lock.yml | 20 ------------------- cap/test/qlpack.yml | 8 -------- javascript/frameworks/cap/ext/qlpack.yml | 9 +++++++++ .../frameworks/cap/lib/CDS.qll | 0 .../frameworks/cap/lib}/CQL.qll | 0 javascript/frameworks/cap/lib/qlpack.yml | 9 +++++++++ javascript/frameworks/cap/src/qlpack.yml | 10 ++++++++++ .../cap/test/models}/cql/delete.expected | 0 .../frameworks/cap/test/models}/cql/delete.js | 0 .../frameworks/cap/test/models}/cql/delete.ql | 0 .../cap/test/models}/cql/insert.expected | 0 .../frameworks/cap/test/models}/cql/insert.js | 0 .../frameworks/cap/test/models}/cql/insert.ql | 0 .../cap/test/models}/cql/select.expected | 0 .../frameworks/cap/test/models}/cql/select.js | 0 .../frameworks/cap/test/models}/cql/select.ql | 0 .../cap/test/models}/cql/update.expected | 0 .../frameworks/cap/test/models}/cql/update.js | 0 .../frameworks/cap/test/models}/cql/update.ql | 0 .../cap/test/models}/cql/upsert.expected | 0 .../frameworks/cap/test/models}/cql/upsert.js | 0 .../frameworks/cap/test/models}/cql/upsert.ql | 0 javascript/frameworks/cap/test/qlpack.yml | 10 ++++++++++ 26 files changed, 38 insertions(+), 49 deletions(-) delete mode 100644 cap/codeql-pack.lock.yml delete mode 100644 cap/qlpack.yml delete mode 100644 cap/service_test.js delete mode 100644 cap/test/codeql-pack.lock.yml delete mode 100644 cap/test/qlpack.yml create mode 100644 javascript/frameworks/cap/ext/qlpack.yml rename cap/CAPModels.qll => javascript/frameworks/cap/lib/CDS.qll (100%) rename {cap => javascript/frameworks/cap/lib}/CQL.qll (100%) create mode 100644 javascript/frameworks/cap/lib/qlpack.yml create mode 100644 javascript/frameworks/cap/src/qlpack.yml rename {cap/test => javascript/frameworks/cap/test/models}/cql/delete.expected (100%) rename {cap/test => javascript/frameworks/cap/test/models}/cql/delete.js (100%) rename {cap/test => javascript/frameworks/cap/test/models}/cql/delete.ql (100%) rename {cap/test => javascript/frameworks/cap/test/models}/cql/insert.expected (100%) rename {cap/test => javascript/frameworks/cap/test/models}/cql/insert.js (100%) rename {cap/test => javascript/frameworks/cap/test/models}/cql/insert.ql (100%) rename {cap/test => javascript/frameworks/cap/test/models}/cql/select.expected (100%) rename {cap/test => javascript/frameworks/cap/test/models}/cql/select.js (100%) rename {cap/test => javascript/frameworks/cap/test/models}/cql/select.ql (100%) rename {cap/test => javascript/frameworks/cap/test/models}/cql/update.expected (100%) rename {cap/test => javascript/frameworks/cap/test/models}/cql/update.js (100%) rename {cap/test => javascript/frameworks/cap/test/models}/cql/update.ql (100%) rename {cap/test => javascript/frameworks/cap/test/models}/cql/upsert.expected (100%) rename {cap/test => javascript/frameworks/cap/test/models}/cql/upsert.js (100%) rename {cap/test => javascript/frameworks/cap/test/models}/cql/upsert.ql (100%) create mode 100644 javascript/frameworks/cap/test/qlpack.yml diff --git a/cap/codeql-pack.lock.yml b/cap/codeql-pack.lock.yml deleted file mode 100644 index f8b362092..000000000 --- a/cap/codeql-pack.lock.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- -lockVersion: 1.0.0 -dependencies: - codeql/javascript-all: - version: 0.6.4 - codeql/regex: - version: 0.0.15 - codeql/tutorial: - version: 0.0.12 - codeql/util: - version: 0.0.12 - codeql/yaml: - version: 0.0.4 -compiled: false diff --git a/cap/qlpack.yml b/cap/qlpack.yml deleted file mode 100644 index 0289ede45..000000000 --- a/cap/qlpack.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -library: false -warnOnImplicitThis: false -name: advanced-security/javascript-sap-cap-models -version: 0.0.1 -dependencies: - codeql/javascript-all: "^0.6.3" \ No newline at end of file diff --git a/cap/service_test.js b/cap/service_test.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/cap/test/codeql-pack.lock.yml b/cap/test/codeql-pack.lock.yml deleted file mode 100644 index 79d3aa8c2..000000000 --- a/cap/test/codeql-pack.lock.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- -lockVersion: 1.0.0 -dependencies: - codeql/javascript-all: - version: 0.6.4 - codeql/javascript-queries: - version: 0.6.4 - codeql/regex: - version: 0.0.15 - codeql/suite-helpers: - version: 0.5.4 - codeql/tutorial: - version: 0.0.12 - codeql/typos: - version: 0.0.19 - codeql/util: - version: 0.0.12 - codeql/yaml: - version: 0.0.4 -compiled: false diff --git a/cap/test/qlpack.yml b/cap/test/qlpack.yml deleted file mode 100644 index 973a4c08b..000000000 --- a/cap/test/qlpack.yml +++ /dev/null @@ -1,8 +0,0 @@ -name: advanced-security/javascript-sap-cap-models-tests -version: 0.0.1 -extractor: javascript -dependencies: - codeql/javascript-all: "^0.6.3" - codeql/javascript-queries: "^0.6.3" - advanced-security/javascript-sap-cap-models: "^0.0.1" - # advanced-security/javascript-sap-cap-extensions: "^0.0.1" diff --git a/javascript/frameworks/cap/ext/qlpack.yml b/javascript/frameworks/cap/ext/qlpack.yml new file mode 100644 index 000000000..365426211 --- /dev/null +++ b/javascript/frameworks/cap/ext/qlpack.yml @@ -0,0 +1,9 @@ +--- +library: true +name: advanced-security/javascript-sap-cap-models +version: 0.2.0 +extensionTargets: + codeql/javascript-all: "^0.6.3" + codeql/javascript-queries: "^0.6.3" +dataExtensions: + - "*.model.yml" \ No newline at end of file diff --git a/cap/CAPModels.qll b/javascript/frameworks/cap/lib/CDS.qll similarity index 100% rename from cap/CAPModels.qll rename to javascript/frameworks/cap/lib/CDS.qll diff --git a/cap/CQL.qll b/javascript/frameworks/cap/lib/CQL.qll similarity index 100% rename from cap/CQL.qll rename to javascript/frameworks/cap/lib/CQL.qll diff --git a/javascript/frameworks/cap/lib/qlpack.yml b/javascript/frameworks/cap/lib/qlpack.yml new file mode 100644 index 000000000..737b1cb2b --- /dev/null +++ b/javascript/frameworks/cap/lib/qlpack.yml @@ -0,0 +1,9 @@ +--- +library: true +name: advanced-security/javascript-sap-cap-all +version: 0.0.1 +suites: codeql-suites +extractor: javascript +dependencies: + codeql/javascript-all: "^0.6.3" + advanced-security/javascript-sap-cap-models: "^0.2.0" diff --git a/javascript/frameworks/cap/src/qlpack.yml b/javascript/frameworks/cap/src/qlpack.yml new file mode 100644 index 000000000..a102e570f --- /dev/null +++ b/javascript/frameworks/cap/src/qlpack.yml @@ -0,0 +1,10 @@ +--- +library: false +name: advanced-security/javascript-sap-cap-queries +version: 0.2.0 +suites: codeql-suites +extractor: javascript +dependencies: + codeql/javascript-all: "^0.6.3" + advanced-security/javascript-sap-cap-models: "^0.2.0" + advanced-security/javascript-sap-cap-all: "^0.2.0" \ No newline at end of file diff --git a/cap/test/cql/delete.expected b/javascript/frameworks/cap/test/models/cql/delete.expected similarity index 100% rename from cap/test/cql/delete.expected rename to javascript/frameworks/cap/test/models/cql/delete.expected diff --git a/cap/test/cql/delete.js b/javascript/frameworks/cap/test/models/cql/delete.js similarity index 100% rename from cap/test/cql/delete.js rename to javascript/frameworks/cap/test/models/cql/delete.js diff --git a/cap/test/cql/delete.ql b/javascript/frameworks/cap/test/models/cql/delete.ql similarity index 100% rename from cap/test/cql/delete.ql rename to javascript/frameworks/cap/test/models/cql/delete.ql diff --git a/cap/test/cql/insert.expected b/javascript/frameworks/cap/test/models/cql/insert.expected similarity index 100% rename from cap/test/cql/insert.expected rename to javascript/frameworks/cap/test/models/cql/insert.expected diff --git a/cap/test/cql/insert.js b/javascript/frameworks/cap/test/models/cql/insert.js similarity index 100% rename from cap/test/cql/insert.js rename to javascript/frameworks/cap/test/models/cql/insert.js diff --git a/cap/test/cql/insert.ql b/javascript/frameworks/cap/test/models/cql/insert.ql similarity index 100% rename from cap/test/cql/insert.ql rename to javascript/frameworks/cap/test/models/cql/insert.ql diff --git a/cap/test/cql/select.expected b/javascript/frameworks/cap/test/models/cql/select.expected similarity index 100% rename from cap/test/cql/select.expected rename to javascript/frameworks/cap/test/models/cql/select.expected diff --git a/cap/test/cql/select.js b/javascript/frameworks/cap/test/models/cql/select.js similarity index 100% rename from cap/test/cql/select.js rename to javascript/frameworks/cap/test/models/cql/select.js diff --git a/cap/test/cql/select.ql b/javascript/frameworks/cap/test/models/cql/select.ql similarity index 100% rename from cap/test/cql/select.ql rename to javascript/frameworks/cap/test/models/cql/select.ql diff --git a/cap/test/cql/update.expected b/javascript/frameworks/cap/test/models/cql/update.expected similarity index 100% rename from cap/test/cql/update.expected rename to javascript/frameworks/cap/test/models/cql/update.expected diff --git a/cap/test/cql/update.js b/javascript/frameworks/cap/test/models/cql/update.js similarity index 100% rename from cap/test/cql/update.js rename to javascript/frameworks/cap/test/models/cql/update.js diff --git a/cap/test/cql/update.ql b/javascript/frameworks/cap/test/models/cql/update.ql similarity index 100% rename from cap/test/cql/update.ql rename to javascript/frameworks/cap/test/models/cql/update.ql diff --git a/cap/test/cql/upsert.expected b/javascript/frameworks/cap/test/models/cql/upsert.expected similarity index 100% rename from cap/test/cql/upsert.expected rename to javascript/frameworks/cap/test/models/cql/upsert.expected diff --git a/cap/test/cql/upsert.js b/javascript/frameworks/cap/test/models/cql/upsert.js similarity index 100% rename from cap/test/cql/upsert.js rename to javascript/frameworks/cap/test/models/cql/upsert.js diff --git a/cap/test/cql/upsert.ql b/javascript/frameworks/cap/test/models/cql/upsert.ql similarity index 100% rename from cap/test/cql/upsert.ql rename to javascript/frameworks/cap/test/models/cql/upsert.ql diff --git a/javascript/frameworks/cap/test/qlpack.yml b/javascript/frameworks/cap/test/qlpack.yml new file mode 100644 index 000000000..264055b76 --- /dev/null +++ b/javascript/frameworks/cap/test/qlpack.yml @@ -0,0 +1,10 @@ +--- +name: advanced-security/javascript-sap-cap-queries-tests +version: 0.2.0 +extractor: javascript +dependencies: + codeql/javascript-all: "^0.6.3" + codeql/javascript-queries: "^0.6.3" + advanced-security/javascript-sap-cap-queries: "^0.2.0" + advanced-security/javascript-sap-cap-models: "^0.2.0" + advanced-security/javascript-sap-cap-all: "^0.2.0" \ No newline at end of file From a12839674ea68ddd734d3821356cc8a4e10d52ac Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 5 Oct 2023 16:57:30 -0700 Subject: [PATCH 44/61] Add lock files for dependency versions --- .../frameworks/cap/ext/codeql-pack.lock.yml | 4 ++++ .../frameworks/cap/lib/codeql-pack.lock.yml | 14 +++++++++++++ .../frameworks/cap/src/codeql-pack.lock.yml | 14 +++++++++++++ .../frameworks/cap/test/codeql-pack.lock.yml | 20 +++++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 javascript/frameworks/cap/ext/codeql-pack.lock.yml create mode 100644 javascript/frameworks/cap/lib/codeql-pack.lock.yml create mode 100644 javascript/frameworks/cap/src/codeql-pack.lock.yml create mode 100644 javascript/frameworks/cap/test/codeql-pack.lock.yml diff --git a/javascript/frameworks/cap/ext/codeql-pack.lock.yml b/javascript/frameworks/cap/ext/codeql-pack.lock.yml new file mode 100644 index 000000000..530042745 --- /dev/null +++ b/javascript/frameworks/cap/ext/codeql-pack.lock.yml @@ -0,0 +1,4 @@ +--- +lockVersion: 1.0.0 +dependencies: {} +compiled: false diff --git a/javascript/frameworks/cap/lib/codeql-pack.lock.yml b/javascript/frameworks/cap/lib/codeql-pack.lock.yml new file mode 100644 index 000000000..f8b362092 --- /dev/null +++ b/javascript/frameworks/cap/lib/codeql-pack.lock.yml @@ -0,0 +1,14 @@ +--- +lockVersion: 1.0.0 +dependencies: + codeql/javascript-all: + version: 0.6.4 + codeql/regex: + version: 0.0.15 + codeql/tutorial: + version: 0.0.12 + codeql/util: + version: 0.0.12 + codeql/yaml: + version: 0.0.4 +compiled: false diff --git a/javascript/frameworks/cap/src/codeql-pack.lock.yml b/javascript/frameworks/cap/src/codeql-pack.lock.yml new file mode 100644 index 000000000..f8b362092 --- /dev/null +++ b/javascript/frameworks/cap/src/codeql-pack.lock.yml @@ -0,0 +1,14 @@ +--- +lockVersion: 1.0.0 +dependencies: + codeql/javascript-all: + version: 0.6.4 + codeql/regex: + version: 0.0.15 + codeql/tutorial: + version: 0.0.12 + codeql/util: + version: 0.0.12 + codeql/yaml: + version: 0.0.4 +compiled: false diff --git a/javascript/frameworks/cap/test/codeql-pack.lock.yml b/javascript/frameworks/cap/test/codeql-pack.lock.yml new file mode 100644 index 000000000..79d3aa8c2 --- /dev/null +++ b/javascript/frameworks/cap/test/codeql-pack.lock.yml @@ -0,0 +1,20 @@ +--- +lockVersion: 1.0.0 +dependencies: + codeql/javascript-all: + version: 0.6.4 + codeql/javascript-queries: + version: 0.6.4 + codeql/regex: + version: 0.0.15 + codeql/suite-helpers: + version: 0.5.4 + codeql/tutorial: + version: 0.0.12 + codeql/typos: + version: 0.0.19 + codeql/util: + version: 0.0.12 + codeql/yaml: + version: 0.0.4 +compiled: false From 5e124b57a107d4939a895f6e140db78c445f7898 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 5 Oct 2023 16:59:58 -0700 Subject: [PATCH 45/61] Add subfolders for correct import paths --- .../{ => advanced_security/javascript/frameworks/cap}/CDS.qll | 0 .../{ => advanced_security/javascript/frameworks/cap}/CQL.qll | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename javascript/frameworks/cap/lib/{ => advanced_security/javascript/frameworks/cap}/CDS.qll (100%) rename javascript/frameworks/cap/lib/{ => advanced_security/javascript/frameworks/cap}/CQL.qll (99%) diff --git a/javascript/frameworks/cap/lib/CDS.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll similarity index 100% rename from javascript/frameworks/cap/lib/CDS.qll rename to javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll diff --git a/javascript/frameworks/cap/lib/CQL.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll similarity index 99% rename from javascript/frameworks/cap/lib/CQL.qll rename to javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll index 03ffc989f..8656dabba 100644 --- a/javascript/frameworks/cap/lib/CQL.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll @@ -1,6 +1,6 @@ private import javascript private import DataFlow -private import CAPModels +private import CDS class CqlQueryBase extends VarRef { CqlQueryBase() { From 3bfc433ad0ddb7e1aa1a93f6e6cab5b2fe347c88 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 9 Oct 2023 15:41:08 -0700 Subject: [PATCH 46/61] Update import path for unit tests --- javascript/frameworks/cap/test/models/cql/delete.ql | 5 +++-- javascript/frameworks/cap/test/models/cql/insert.ql | 5 +++-- javascript/frameworks/cap/test/models/cql/select.ql | 5 +++-- javascript/frameworks/cap/test/models/cql/update.ql | 5 +++-- javascript/frameworks/cap/test/models/cql/upsert.ql | 5 +++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/javascript/frameworks/cap/test/models/cql/delete.ql b/javascript/frameworks/cap/test/models/cql/delete.ql index 4942d70d2..636bad4f1 100644 --- a/javascript/frameworks/cap/test/models/cql/delete.ql +++ b/javascript/frameworks/cap/test/models/cql/delete.ql @@ -1,5 +1,6 @@ import javascript -import CQL +import advanced_security.javascript.frameworks.cap.CQL -select any(CqlDeleteExpr s) +from CqlDeleteExpr s +select s.getLocation(), s diff --git a/javascript/frameworks/cap/test/models/cql/insert.ql b/javascript/frameworks/cap/test/models/cql/insert.ql index 1e8d9faf4..bb73473d2 100644 --- a/javascript/frameworks/cap/test/models/cql/insert.ql +++ b/javascript/frameworks/cap/test/models/cql/insert.ql @@ -1,4 +1,5 @@ import javascript -import CQL +import advanced_security.javascript.frameworks.cap.CQL -select any(CqlInsertExpr s) +from CqlInsertExpr s +select s.getLocation(), s diff --git a/javascript/frameworks/cap/test/models/cql/select.ql b/javascript/frameworks/cap/test/models/cql/select.ql index cd96c0834..78d704526 100644 --- a/javascript/frameworks/cap/test/models/cql/select.ql +++ b/javascript/frameworks/cap/test/models/cql/select.ql @@ -1,4 +1,5 @@ import javascript -import CQL +import advanced_security.javascript.frameworks.cap.CQL -select any(CqlSelectExpr s) \ No newline at end of file +from CqlSelectExpr s +select s.getLocation(), s \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cql/update.ql b/javascript/frameworks/cap/test/models/cql/update.ql index 0d4b9e72d..8f61fff44 100644 --- a/javascript/frameworks/cap/test/models/cql/update.ql +++ b/javascript/frameworks/cap/test/models/cql/update.ql @@ -1,5 +1,6 @@ import javascript -import CQL +import advanced_security.javascript.frameworks.cap.CQL -select any(CqlUpdateExpr s) +from CqlUpdateExpr s +select s.getLocation(), s diff --git a/javascript/frameworks/cap/test/models/cql/upsert.ql b/javascript/frameworks/cap/test/models/cql/upsert.ql index 151471f8a..19b6cd1ce 100644 --- a/javascript/frameworks/cap/test/models/cql/upsert.ql +++ b/javascript/frameworks/cap/test/models/cql/upsert.ql @@ -1,5 +1,6 @@ import javascript -import CQL +import advanced_security.javascript.frameworks.cap.CQL -select any(CqlUpsertExpr s) +from CqlUpsertExpr s +select s.getLocation(), s From f3a9594bc0e1ab3a9bc28337fc52ae6b0b17a62d Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 9 Oct 2023 15:41:26 -0700 Subject: [PATCH 47/61] Cover cases where the base obj acts as shortcut --- .../javascript/frameworks/cap/CQL.qll | 115 +++++++++++++++--- 1 file changed, 99 insertions(+), 16 deletions(-) diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll index 8656dabba..47042f9a5 100644 --- a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll @@ -39,8 +39,37 @@ class CqlUpsertBase extends CqlQueryBase { CqlUpsertBase() { this.getName() = "UPSERT" } } +abstract class CqlQueryBaseCall extends CallExpr { + // TODO: Express "It's a global function or a local function imported from cds.ql" +} + +class CqlSelectBaseCall extends CqlQueryBaseCall { + CqlSelectBaseCall() { this.getCalleeName() = "SELECT" } +} + +class CqlInsertBaseCall extends CqlQueryBaseCall { + CqlInsertBaseCall() { this.getCalleeName() = "INSERT" } +} + +class CqlDeleteBaseCall extends CqlQueryBaseCall { + CqlDeleteBaseCall() { this.getCalleeName() = "DELETE" } +} + +class CqlUpdateBaseCall extends CqlQueryBaseCall { + CqlUpdateBaseCall() { this.getCalleeName() = "UPDATE" } +} + +class CqlUpsertBaseCall extends CqlQueryBaseCall { + CqlUpsertBaseCall() { this.getCalleeName() = "UPSERT" } +} + Expr getRootReceiver(Expr e) { - result = e and e instanceof VarRef + result = e and + ( + e instanceof VarRef + or + e instanceof CallExpr and not exists(e.(CallExpr).getReceiver()) + ) or result = getRootReceiver(e.(DotExpr).getBase()) or @@ -53,17 +82,22 @@ Expr getRootReceiver(Expr e) { newtype TCqlExpr = TaggedTemplate(TaggedTemplateExpr tagExpr) { - exists(CqlQueryBase base | base = getRootReceiver(tagExpr)) + exists(CqlQueryBase base | base = getRootReceiver(tagExpr)) or + exists(CqlQueryBaseCall call | call = getRootReceiver(tagExpr)) } or MethodCall(MethodCallExpr callExpr) { - exists(CqlQueryBase base | base = getRootReceiver(callExpr)) - } + exists(CqlQueryBase base | base = getRootReceiver(callExpr)) or + exists(CqlQueryBaseCall call | call = getRootReceiver(callExpr)) + } or + ShortcutCall(CqlQueryBaseCall callExpr) class CqlExpr extends TCqlExpr { TaggedTemplateExpr asTaggedTemplate() { this = TaggedTemplate(result) } MethodCallExpr asMethodCall() { this = MethodCall(result) } + CallExpr asShortcutCall() { this = ShortcutCall(result) } + /** * Convert this `CqlExpr` into a `DotExpr`, i.e. * Get SELECT.from`Table` when given SELECT.from`Table`.where`cond`, @@ -79,12 +113,14 @@ class CqlExpr extends TCqlExpr { string toString() { result = this.asTaggedTemplate().toString() or - result = this.asMethodCall().toString() + result = this.asMethodCall().toString() or + result = this.asShortcutCall().toString() } Location getLocation() { result = this.asTaggedTemplate().getLocation() or - result = this.asMethodCall().getLocation() + result = this.asMethodCall().getLocation() or + result = this.asShortcutCall().getLocation() } CqlQueryBase getCqlBase() { @@ -92,6 +128,11 @@ class CqlExpr extends TCqlExpr { result = getRootReceiver(this.asMethodCall()) } + CqlQueryBaseCall getCqlBaseCall() { + result = getRootReceiver(this.asTaggedTemplate()).(CqlQueryBaseCall) or + result = getRootReceiver(this.asMethodCall()).(CqlQueryBaseCall) + } + Expr getReceiver() { result = this.asMethodCall().getReceiver() or @@ -99,47 +140,53 @@ class CqlExpr extends TCqlExpr { } /* ========== Parent relationships ========== */ - Expr getParentExpr() { result = this.asMethodCall().getParentExpr() or - result = this.asTaggedTemplate().getParentExpr() + result = this.asTaggedTemplate().getParentExpr() or + result = this.asShortcutCall().getParentExpr() } CqlExpr getCqlParentExpr() { result.asTaggedTemplate() = this.asMethodCall().getParentExpr() or - result.asMethodCall() = this.asTaggedTemplate().getParentExpr() + result.asMethodCall() = this.asTaggedTemplate().getParentExpr() or + result.asShortcutCall() = this.asShortcutCall().getParentExpr() } Expr getAnAncestorExpr() { result = this.asMethodCall().getParentExpr+() or - result = this.asTaggedTemplate().getParentExpr+() + result = this.asTaggedTemplate().getParentExpr+() or + result = this.asShortcutCall().getParentExpr+() } CqlExpr getAnAncestorCqlExpr() { result.asTaggedTemplate() = this.getAnAncestorExpr() or - result.asMethodCall() = this.getAnAncestorExpr() + result.asMethodCall() = this.getAnAncestorExpr() or + result.asShortcutCall() = this.getAnAncestorExpr() } /* ========== Children relationships ========== */ - Expr getAChildExpr() { result = this.asMethodCall().getAChildExpr() or - result = this.asTaggedTemplate().getAChildExpr() + result = this.asTaggedTemplate().getAChildExpr() or + result = this.asShortcutCall().getAChildExpr() } CqlExpr getAChildCqlExpr() { result.asTaggedTemplate() = this.asMethodCall().getAChildExpr() or - result.asMethodCall() = this.asTaggedTemplate().getAChildExpr() + result.asMethodCall() = this.asTaggedTemplate().getAChildExpr() or + result.asShortcutCall() = this.asShortcutCall().getAChildExpr() } Expr getADescendantExpr() { result = this.asMethodCall().getAChildExpr+() or - result = this.asTaggedTemplate().getAChildExpr+() + result = this.asTaggedTemplate().getAChildExpr+() or + result = this.asShortcutCall().getAChildExpr+() } CqlExpr getADescendantCqlExpr() { result.asTaggedTemplate() = this.getADescendantExpr() or - result.asMethodCall() = this.getADescendantExpr() + result.asMethodCall() = this.getADescendantExpr() or + result.asShortcutCall() = this.getADescendantExpr() } /** @@ -161,11 +208,20 @@ class CqlSelectExpr extends CqlExpr { ) ) ) + or + this.getCqlBaseCall() instanceof CqlSelectBaseCall } predicate selectWhere() { this.getAnAPIName() = "where" } predicate selectFrom() { this.getAnAPIName() = "from" } + + predicate selectColumns() { + this.getAnAPIName() = "columns" + or + /* SELECT itself is a shortcut of SELECT.columns */ + this.getCqlBaseCall() instanceof CqlSelectBaseCall + } } class CqlInsertExpr extends CqlExpr { @@ -178,6 +234,15 @@ class CqlInsertExpr extends CqlExpr { ) ) ) + or + this.getCqlBaseCall() instanceof CqlInsertBaseCall + } + + predicate insertEntries() { + this.getAnAPIName() = "entries" + or + /* INSERT itself is a shortcut of INSERT.entries */ + this.getCqlBaseCall() instanceof CqlInsertBaseCall } } @@ -204,6 +269,15 @@ class CqlUpdateExpr extends CqlExpr { ) ) ) + or + this.getCqlBaseCall() instanceof CqlUpdateBaseCall + } + + predicate updateEntity() { + this.getAnAPIName() = "entity" + or + /* UPDATE itself is a shortcut of UPDATE.entity */ + this.getCqlBaseCall() instanceof CqlUpdateBaseCall } } @@ -217,5 +291,14 @@ class CqlUpsertExpr extends CqlExpr { ) ) ) + or + this.getCqlBaseCall() instanceof CqlUpsertBaseCall + } + + predicate upsertEntries() { + this.getAnAPIName() = "entries" + or + /* UPSERT itself is a shortcut of UPSERT.entries */ + this.getCqlBaseCall() instanceof CqlUpsertBaseCall } } From 588581fa33f96292df1183b299e328a4bfb26d57 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 9 Oct 2023 16:04:14 -0700 Subject: [PATCH 48/61] Add cases where SELECT and UPDATE act as shortcut calls --- javascript/frameworks/cap/test/models/cql/select.js | 9 +++++++-- javascript/frameworks/cap/test/models/cql/update.js | 10 +++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/javascript/frameworks/cap/test/models/cql/select.js b/javascript/frameworks/cap/test/models/cql/select.js index 9701d98fd..02d9bb9f2 100644 --- a/javascript/frameworks/cap/test/models/cql/select.js +++ b/javascript/frameworks/cap/test/models/cql/select.js @@ -1,5 +1,10 @@ -/* Simplest SELECTs without property accesses or method calls */ -var select = SELECT`Table`; +/* ========== SELECT acting as shortcut to SELECT.columns ========== */ +var select = SELECT`col1, col2`.from`Table`; +var select = SELECT`col1, col2`.from(Table); +var select = SELECT`col1, col2`.from("Table"); +var select = SELECT("col1, col2").from`Table`; +var select = SELECT("col1, col2").from(Table); +var select = SELECT("col1, col2").from("Table"); /* ========== SELECTs with property accesses ========== */ var select = SELECT.one.from`Table`; diff --git a/javascript/frameworks/cap/test/models/cql/update.js b/javascript/frameworks/cap/test/models/cql/update.js index 186a440cd..2f9c49a9e 100644 --- a/javascript/frameworks/cap/test/models/cql/update.js +++ b/javascript/frameworks/cap/test/models/cql/update.js @@ -3,11 +3,19 @@ let val = 2; /* ========== UPDATE (entity), set ========== */ -/* Without `entity` */ +/* UPDATE acting as shortcut to UPDATE.entity */ var update = UPDATE`Table`.set`col1 = col1 - ${diff}`; var update = UPDATE`Table`.set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }); // CQN var update = UPDATE`Table`.set({ col1: diff }); // QBE +var update = UPDATE(Table).set`col1 = col1 - ${diff}`; +var update = UPDATE(Table).set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }); // CQN +var update = UPDATE(Table).set({ col1: diff }); // QBE + +var update = UPDATE("Table").set`col1 = col1 - ${diff}`; +var update = UPDATE("Table").set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }); // CQN +var update = UPDATE("Table").set({ col1: diff }); // QBE + /* With `entity` */ var update = UPDATE.entity(Table).set`col1 = col1 - ${diff}`; var update = UPDATE.entity(Table).set({ col1: { xpr: [{ ref: ["col1"] }, "-", { ref: ["diff"] }] }, }); // CQN From ddf12235f8f13d8727ee1ab1a6ec01c87fb06e2f Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 9 Oct 2023 16:04:30 -0700 Subject: [PATCH 49/61] Update .expected and remove unneeded code in update.js --- .../cap/test/models/cql/delete.expected | 16 ++ .../cap/test/models/cql/insert.expected | 26 ++- .../cap/test/models/cql/select.expected | 165 ++++++++++++- .../cap/test/models/cql/update.expected | 216 ++++++++++++++++++ .../frameworks/cap/test/models/cql/update.js | 3 - .../cap/test/models/cql/upsert.expected | 10 + 6 files changed, 431 insertions(+), 5 deletions(-) diff --git a/javascript/frameworks/cap/test/models/cql/delete.expected b/javascript/frameworks/cap/test/models/cql/delete.expected index e69de29bb..99e49e121 100644 --- a/javascript/frameworks/cap/test/models/cql/delete.expected +++ b/javascript/frameworks/cap/test/models/cql/delete.expected @@ -0,0 +1,16 @@ +| delete.js:1:15:1:53 | delete.js:1 | delete.js:1:15:1:53 | DELETE. ... "*" }) | +| delete.js:2:15:2:50 | delete.js:2 | delete.js:2:15:2:50 | DELETE. ... 1='*'") | +| delete.js:3:15:3:51 | delete.js:3 | delete.js:3:15:3:51 | DELETE. ... ${"*"}` | +| delete.js:4:15:4:52 | delete.js:4 | delete.js:4:15:4:52 | DELETE. ... ", "*") | +| delete.js:5:15:5:52 | delete.js:5 | delete.js:5:15:5:52 | DELETE. ... ${"*"}` | +| delete.js:6:15:6:59 | delete.js:6 | delete.js:6:15:6:59 | DELETE. ... , 10)") | +| delete.js:7:15:7:62 | delete.js:7 | delete.js:7:15:7:62 | DELETE. ... 10)]}` | +| delete.js:8:15:8:71 | delete.js:8 | delete.js:8:15:8:71 | DELETE. ... 11 } }) | +| delete.js:10:15:10:53 | delete.js:10 | delete.js:10:15:10:53 | DELETE. ... "*" }) | +| delete.js:11:15:11:50 | delete.js:11 | delete.js:11:15:11:50 | DELETE. ... 1='*'") | +| delete.js:12:15:12:51 | delete.js:12 | delete.js:12:15:12:51 | DELETE. ... ${"*"}` | +| delete.js:13:15:13:52 | delete.js:13 | delete.js:13:15:13:52 | DELETE. ... ", "*") | +| delete.js:14:15:14:52 | delete.js:14 | delete.js:14:15:14:52 | DELETE. ... ${"*"}` | +| delete.js:15:15:15:59 | delete.js:15 | delete.js:15:15:15:59 | DELETE. ... , 10)") | +| delete.js:16:15:16:62 | delete.js:16 | delete.js:16:15:16:62 | DELETE. ... 10)]}` | +| delete.js:17:15:17:71 | delete.js:17 | delete.js:17:15:17:71 | DELETE. ... 11 } }) | diff --git a/javascript/frameworks/cap/test/models/cql/insert.expected b/javascript/frameworks/cap/test/models/cql/insert.expected index 3459bed94..e4af5d7a9 100644 --- a/javascript/frameworks/cap/test/models/cql/insert.expected +++ b/javascript/frameworks/cap/test/models/cql/insert.expected @@ -1 +1,25 @@ -| hihi | +| insert.js:2:14:5:14 | insert.js:2 | insert.js:2:14:5:14 | INSERT( ... (Table) | +| insert.js:6:14:9:16 | insert.js:6 | insert.js:6:14:9:16 | INSERT( ... Table") | +| insert.js:11:14:14:2 | insert.js:11 | insert.js:11:14:14:2 | INSERT. ... " },\\n]) | +| insert.js:15:14:18:2 | insert.js:15 | insert.js:15:14:18:2 | INSERT. ... " },\\n]) | +| insert.js:21:14:24:1 | insert.js:21 | insert.js:21:14:24:1 | INSERT. ... 22" }\\n) | +| insert.js:25:14:28:2 | insert.js:25 | insert.js:25:14:28:2 | INSERT. ... " },\\n]) | +| insert.js:29:14:32:2 | insert.js:29 | insert.js:29:14:32:2 | INSERT. ... " },\\n]) | +| insert.js:33:14:36:2 | insert.js:33 | insert.js:33:14:36:2 | INSERT. ... " },\\n]) | +| insert.js:37:14:40:2 | insert.js:37 | insert.js:37:14:40:2 | INSERT. ... " },\\n]) | +| insert.js:41:14:44:2 | insert.js:41 | insert.js:41:14:44:2 | INSERT. ... " },\\n]) | +| insert.js:47:14:49:27 | insert.js:47 | insert.js:47:14:49:27 | INSERT. ... val12") | +| insert.js:50:14:52:27 | insert.js:50 | insert.js:50:14:52:27 | INSERT. ... val12") | +| insert.js:53:14:55:27 | insert.js:53 | insert.js:53:14:55:27 | INSERT. ... val12") | +| insert.js:58:14:63:4 | insert.js:58 | insert.js:58:14:63:4 | INSERT. ... ],\\n ]) | +| insert.js:64:14:69:4 | insert.js:64 | insert.js:64:14:69:4 | INSERT. ... ],\\n ]) | +| insert.js:70:14:73:2 | insert.js:70 | insert.js:70:14:73:2 | INSERT. ... 2"],\\n]) | +| insert.js:76:14:76:74 | insert.js:76 | insert.js:76:14:76:74 | INSERT. ... col2`) | +| insert.js:77:14:77:73 | insert.js:77 | insert.js:77:14:77:73 | INSERT. ... {"*"}`) | +| insert.js:78:14:80:1 | insert.js:78 | insert.js:78:14:80:1 | INSERT. ... "*"}`\\n) | +| insert.js:82:14:82:76 | insert.js:82 | insert.js:82:14:82:76 | INSERT. ... col2`) | +| insert.js:83:14:83:75 | insert.js:83 | insert.js:83:14:83:75 | INSERT. ... {"*"}`) | +| insert.js:84:14:86:1 | insert.js:84 | insert.js:84:14:86:1 | INSERT. ... "*"}`\\n) | +| insert.js:88:14:88:74 | insert.js:88 | insert.js:88:14:88:74 | INSERT. ... col2`) | +| insert.js:89:14:89:73 | insert.js:89 | insert.js:89:14:89:73 | INSERT. ... {"*"}`) | +| insert.js:90:14:92:1 | insert.js:90 | insert.js:90:14:92:1 | INSERT. ... "*"}`\\n) | diff --git a/javascript/frameworks/cap/test/models/cql/select.expected b/javascript/frameworks/cap/test/models/cql/select.expected index 3459bed94..9a7ec4963 100644 --- a/javascript/frameworks/cap/test/models/cql/select.expected +++ b/javascript/frameworks/cap/test/models/cql/select.expected @@ -1 +1,164 @@ -| hihi | +| insert.js:76:36:76:73 | insert.js:76 | insert.js:76:36:76:73 | SELECT. ... , col2` | +| insert.js:77:36:77:72 | insert.js:77 | insert.js:77:36:77:72 | SELECT. ... ${"*"}` | +| insert.js:79:3:79:64 | insert.js:79 | insert.js:79:3:79:64 | SELECT. ... ${"*"}` | +| insert.js:82:38:82:75 | insert.js:82 | insert.js:82:38:82:75 | SELECT. ... , col2` | +| insert.js:83:38:83:74 | insert.js:83 | insert.js:83:38:83:74 | SELECT. ... ${"*"}` | +| insert.js:85:3:85:64 | insert.js:85 | insert.js:85:3:85:64 | SELECT. ... ${"*"}` | +| insert.js:88:36:88:73 | insert.js:88 | insert.js:88:36:88:73 | SELECT. ... , col2` | +| insert.js:89:36:89:72 | insert.js:89 | insert.js:89:36:89:72 | SELECT. ... ${"*"}` | +| insert.js:91:3:91:64 | insert.js:91 | insert.js:91:3:91:64 | SELECT. ... ${"*"}` | +| select.js:2:14:2:43 | select.js:2 | select.js:2:14:2:43 | SELECT` ... `Table` | +| select.js:3:14:3:43 | select.js:3 | select.js:3:14:3:43 | SELECT` ... (Table) | +| select.js:4:14:4:45 | select.js:4 | select.js:4:14:4:45 | SELECT` ... Table") | +| select.js:5:14:5:45 | select.js:5 | select.js:5:14:5:45 | SELECT( ... `Table` | +| select.js:6:14:6:45 | select.js:6 | select.js:6:14:6:45 | SELECT( ... (Table) | +| select.js:7:14:7:47 | select.js:7 | select.js:7:14:7:47 | SELECT( ... Table") | +| select.js:10:14:10:35 | select.js:10 | select.js:10:14:10:35 | SELECT. ... `Table` | +| select.js:11:14:11:35 | select.js:11 | select.js:11:14:11:35 | SELECT. ... (Table) | +| select.js:12:14:12:40 | select.js:12 | select.js:12:14:12:40 | SELECT. ... `Table` | +| select.js:13:14:13:40 | select.js:13 | select.js:13:14:13:40 | SELECT. ... (Table) | +| select.js:14:14:14:54 | select.js:14 | select.js:14:14:14:54 | SELECT. ... (Table) | +| select.js:15:14:15:54 | select.js:15 | select.js:15:14:15:54 | SELECT. ... `Table` | +| select.js:19:14:19:51 | select.js:19 | select.js:19:14:19:51 | SELECT. ... , col2` | +| select.js:20:14:22:2 | select.js:20 | select.js:20:14:22:2 | SELECT. ... ol2;\\n}) | +| select.js:23:14:23:68 | select.js:23 | select.js:23:14:23:68 | SELECT. ... lias }` | +| select.js:24:14:24:68 | select.js:24 | select.js:24:14:24:68 | SELECT. ... Alias") | +| select.js:25:14:28:2 | select.js:25 | select.js:25:14:28:2 | SELECT. ... " },\\n]) | +| select.js:29:14:32:2 | select.js:29 | select.js:29:14:32:2 | SELECT. ... ty",\\n}) | +| select.js:34:14:34:51 | select.js:34 | select.js:34:14:34:51 | SELECT. ... , col2` | +| select.js:35:14:37:2 | select.js:35 | select.js:35:14:37:2 | SELECT. ... ol2;\\n}) | +| select.js:38:14:38:68 | select.js:38 | select.js:38:14:38:68 | SELECT. ... lias }` | +| select.js:39:14:39:68 | select.js:39 | select.js:39:14:39:68 | SELECT. ... Alias") | +| select.js:40:14:43:2 | select.js:40 | select.js:40:14:43:2 | SELECT. ... " },\\n]) | +| select.js:44:14:47:2 | select.js:44 | select.js:44:14:47:2 | SELECT. ... ty",\\n}) | +| select.js:50:14:50:52 | select.js:50 | select.js:50:14:50:52 | SELECT. ... "*" }) | +| select.js:51:14:51:49 | select.js:51 | select.js:51:14:51:49 | SELECT. ... 1='*'") | +| select.js:52:14:52:50 | select.js:52 | select.js:52:14:52:50 | SELECT. ... ${"*"}` | +| select.js:53:14:53:51 | select.js:53 | select.js:53:14:53:51 | SELECT. ... ", "*") | +| select.js:54:14:54:51 | select.js:54 | select.js:54:14:54:51 | SELECT. ... ${"*"}` | +| select.js:55:14:55:58 | select.js:55 | select.js:55:14:55:58 | SELECT. ... , 10)") | +| select.js:56:14:56:61 | select.js:56 | select.js:56:14:56:61 | SELECT. ... 10)]}` | +| select.js:57:14:57:70 | select.js:57 | select.js:57:14:57:70 | SELECT. ... 11 } }) | +| select.js:59:14:59:52 | select.js:59 | select.js:59:14:59:52 | SELECT. ... "*" }) | +| select.js:60:14:60:49 | select.js:60 | select.js:60:14:60:49 | SELECT. ... 1='*'") | +| select.js:61:14:61:50 | select.js:61 | select.js:61:14:61:50 | SELECT. ... ${"*"}` | +| select.js:62:14:62:51 | select.js:62 | select.js:62:14:62:51 | SELECT. ... ", "*") | +| select.js:63:14:63:51 | select.js:63 | select.js:63:14:63:51 | SELECT. ... ${"*"}` | +| select.js:64:14:64:58 | select.js:64 | select.js:64:14:64:58 | SELECT. ... , 10)") | +| select.js:65:14:65:61 | select.js:65 | select.js:65:14:65:61 | SELECT. ... 10)]}` | +| select.js:66:14:66:70 | select.js:66 | select.js:66:14:66:70 | SELECT. ... 11 } }) | +| select.js:69:14:69:55 | select.js:69 | select.js:69:14:69:55 | SELECT. ... "col2") | +| select.js:70:14:70:51 | select.js:70 | select.js:70:14:70:51 | SELECT. ... , col2` | +| select.js:71:14:71:67 | select.js:71 | select.js:71:14:71:67 | SELECT. ... prop2") | +| select.js:72:14:72:63 | select.js:72 | select.js:72:14:72:63 | SELECT. ... .prop2` | +| select.js:73:14:76:1 | select.js:73 | select.js:73:14:76:1 | SELECT. ... 2"] }\\n) | +| select.js:78:14:78:55 | select.js:78 | select.js:78:14:78:55 | SELECT. ... "col2") | +| select.js:79:14:79:51 | select.js:79 | select.js:79:14:79:51 | SELECT. ... , col2` | +| select.js:80:14:80:67 | select.js:80 | select.js:80:14:80:67 | SELECT. ... prop2") | +| select.js:81:14:81:63 | select.js:81 | select.js:81:14:81:63 | SELECT. ... .prop2` | +| select.js:82:14:85:1 | select.js:82 | select.js:82:14:85:1 | SELECT. ... 2"] }\\n) | +| select.js:88:14:88:53 | select.js:88 | select.js:88:14:88:53 | SELECT. ... "*" }) | +| select.js:89:14:89:50 | select.js:89 | select.js:89:14:89:50 | SELECT. ... 1='*'") | +| select.js:90:14:90:51 | select.js:90 | select.js:90:14:90:51 | SELECT. ... ${"*"}` | +| select.js:91:14:91:52 | select.js:91 | select.js:91:14:91:52 | SELECT. ... ", "*") | +| select.js:92:14:92:52 | select.js:92 | select.js:92:14:92:52 | SELECT. ... ${"*"}` | +| select.js:93:14:93:59 | select.js:93 | select.js:93:14:93:59 | SELECT. ... , 10)") | +| select.js:94:14:94:62 | select.js:94 | select.js:94:14:94:62 | SELECT. ... 10)]}` | +| select.js:95:14:95:71 | select.js:95 | select.js:95:14:95:71 | SELECT. ... 11 } }) | +| select.js:97:14:97:53 | select.js:97 | select.js:97:14:97:53 | SELECT. ... "*" }) | +| select.js:98:14:98:50 | select.js:98 | select.js:98:14:98:50 | SELECT. ... 1='*'") | +| select.js:99:14:99:51 | select.js:99 | select.js:99:14:99:51 | SELECT. ... ${"*"}` | +| select.js:100:14:100:52 | select.js:100 | select.js:100:14:100:52 | SELECT. ... ", "*") | +| select.js:101:14:101:52 | select.js:101 | select.js:101:14:101:52 | SELECT. ... ${"*"}` | +| select.js:102:14:102:59 | select.js:102 | select.js:102:14:102:59 | SELECT. ... , 10)") | +| select.js:103:14:103:62 | select.js:103 | select.js:103:14:103:62 | SELECT. ... 10)]}` | +| select.js:104:14:104:71 | select.js:104 | select.js:104:14:104:71 | SELECT. ... 11 } }) | +| select.js:106:14:106:77 | select.js:106 | select.js:106:14:106:77 | SELECT. ... "*" }) | +| select.js:107:14:107:74 | select.js:107 | select.js:107:14:107:74 | SELECT. ... 1='*'") | +| select.js:108:14:108:75 | select.js:108 | select.js:108:14:108:75 | SELECT. ... ${"*"}` | +| select.js:109:14:109:76 | select.js:109 | select.js:109:14:109:76 | SELECT. ... ", "*") | +| select.js:110:14:110:76 | select.js:110 | select.js:110:14:110:76 | SELECT. ... ${"*"}` | +| select.js:111:14:113:30 | select.js:111 | select.js:111:14:113:30 | SELECT. ... , 10)") | +| select.js:114:14:116:3 | select.js:114 | select.js:114:14:116:3 | SELECT. ... 0),\\n]}` | +| select.js:117:14:119:42 | select.js:117 | select.js:117:14:119:42 | SELECT. ... 11 } }) | +| select.js:121:14:121:77 | select.js:121 | select.js:121:14:121:77 | SELECT. ... "*" }) | +| select.js:122:14:122:74 | select.js:122 | select.js:122:14:122:74 | SELECT. ... 1='*'") | +| select.js:123:14:123:75 | select.js:123 | select.js:123:14:123:75 | SELECT. ... ${"*"}` | +| select.js:124:14:124:76 | select.js:124 | select.js:124:14:124:76 | SELECT. ... ", "*") | +| select.js:125:14:125:76 | select.js:125 | select.js:125:14:125:76 | SELECT. ... ${"*"}` | +| select.js:126:14:128:30 | select.js:126 | select.js:126:14:128:30 | SELECT. ... , 10)") | +| select.js:129:14:131:3 | select.js:129 | select.js:129:14:131:3 | SELECT. ... 0),\\n]}` | +| select.js:132:14:134:42 | select.js:132 | select.js:132:14:134:42 | SELECT. ... 11 } }) | +| select.js:136:14:136:73 | select.js:136 | select.js:136:14:136:73 | SELECT. ... "*" }) | +| select.js:137:14:137:70 | select.js:137 | select.js:137:14:137:70 | SELECT. ... 1='*'") | +| select.js:138:14:138:71 | select.js:138 | select.js:138:14:138:71 | SELECT. ... ${"*"}` | +| select.js:139:14:139:72 | select.js:139 | select.js:139:14:139:72 | SELECT. ... ", "*") | +| select.js:140:14:140:72 | select.js:140 | select.js:140:14:140:72 | SELECT. ... ${"*"}` | +| select.js:141:14:141:79 | select.js:141 | select.js:141:14:141:79 | SELECT. ... , 10)") | +| select.js:142:14:144:3 | select.js:142 | select.js:142:14:144:3 | SELECT. ... 0),\\n]}` | +| select.js:145:14:148:2 | select.js:145 | select.js:145:14:148:2 | SELECT. ... 1 },\\n}) | +| select.js:150:14:150:73 | select.js:150 | select.js:150:14:150:73 | SELECT. ... "*" }) | +| select.js:151:14:151:70 | select.js:151 | select.js:151:14:151:70 | SELECT. ... 1='*'") | +| select.js:152:14:152:71 | select.js:152 | select.js:152:14:152:71 | SELECT. ... ${"*"}` | +| select.js:153:14:153:72 | select.js:153 | select.js:153:14:153:72 | SELECT. ... ", "*") | +| select.js:154:14:154:72 | select.js:154 | select.js:154:14:154:72 | SELECT. ... ${"*"}` | +| select.js:155:14:155:79 | select.js:155 | select.js:155:14:155:79 | SELECT. ... , 10)") | +| select.js:156:14:158:3 | select.js:156 | select.js:156:14:158:3 | SELECT. ... 0),\\n]}` | +| select.js:159:14:162:2 | select.js:159 | select.js:159:14:162:2 | SELECT. ... 1 },\\n}) | +| select.js:164:14:166:24 | select.js:164 | select.js:164:14:166:24 | SELECT. ... "*" }) | +| select.js:167:14:169:21 | select.js:167 | select.js:167:14:169:21 | SELECT. ... 1='*'") | +| select.js:170:14:171:22 | select.js:170 | select.js:170:14:171:22 | SELECT. ... ${"*"}` | +| select.js:172:14:174:23 | select.js:172 | select.js:172:14:174:23 | SELECT. ... ", "*") | +| select.js:175:14:176:23 | select.js:175 | select.js:175:14:176:23 | SELECT. ... ${"*"}` | +| select.js:177:14:179:30 | select.js:177 | select.js:177:14:179:30 | SELECT. ... , 10)") | +| select.js:180:14:181:33 | select.js:180 | select.js:180:14:181:33 | SELECT. ... 10)]}` | +| select.js:182:14:184:42 | select.js:182 | select.js:182:14:184:42 | SELECT. ... 11 } }) | +| select.js:186:14:188:2 | select.js:186 | select.js:186:14:188:2 | SELECT. ... "*",\\n}) | +| select.js:189:14:191:1 | select.js:189 | select.js:189:14:191:1 | SELECT. ... ='*'"\\n) | +| select.js:192:14:193:22 | select.js:192 | select.js:192:14:193:22 | SELECT. ... ${"*"}` | +| select.js:194:14:197:1 | select.js:194 | select.js:194:14:197:1 | SELECT. ... "*"\\n) | +| select.js:198:14:199:23 | select.js:198 | select.js:198:14:199:23 | SELECT. ... ${"*"}` | +| select.js:200:14:202:1 | select.js:200 | select.js:200:14:202:1 | SELECT. ... 10)"\\n) | +| select.js:203:14:204:33 | select.js:203 | select.js:203:14:204:33 | SELECT. ... 10)]}` | +| select.js:205:14:208:2 | select.js:205 | select.js:205:14:208:2 | SELECT. ... 1 },\\n}) | +| select.js:210:14:212:24 | select.js:210 | select.js:210:14:212:24 | SELECT. ... "*" }) | +| select.js:213:14:215:21 | select.js:213 | select.js:213:14:215:21 | SELECT. ... 1='*'") | +| select.js:216:14:219:21 | select.js:216 | select.js:216:14:219:21 | SELECT. ... ${"*"}` | +| select.js:220:14:222:23 | select.js:220 | select.js:220:14:222:23 | SELECT. ... ", "*") | +| select.js:223:14:226:22 | select.js:223 | select.js:223:14:226:22 | SELECT. ... ${"*"}` | +| select.js:227:14:229:30 | select.js:227 | select.js:227:14:229:30 | SELECT. ... , 10)") | +| select.js:230:14:233:32 | select.js:230 | select.js:230:14:233:32 | SELECT. ... 10)]}` | +| select.js:234:14:236:42 | select.js:234 | select.js:234:14:236:42 | SELECT. ... 11 } }) | +| select.js:239:14:239:63 | select.js:239 | select.js:239:14:239:63 | SELECT. ... .prop2` | +| select.js:240:14:240:61 | select.js:240 | select.js:240:14:240:61 | SELECT. ... .prop2` | +| select.js:241:14:241:61 | select.js:241 | select.js:241:14:241:61 | SELECT. ... l2 asc` | +| select.js:242:14:242:58 | select.js:242 | select.js:242:14:242:58 | SELECT. ... l2 asc` | +| select.js:243:14:243:63 | select.js:243 | select.js:243:14:243:63 | SELECT. ... .prop2` | +| select.js:244:14:244:62 | select.js:244 | select.js:244:14:244:62 | SELECT. ... .prop2` | +| select.js:245:14:245:62 | select.js:245 | select.js:245:14:245:62 | SELECT. ... 2 desc` | +| select.js:246:14:246:60 | select.js:246 | select.js:246:14:246:60 | SELECT. ... 2 desc` | +| select.js:248:14:248:63 | select.js:248 | select.js:248:14:248:63 | SELECT. ... .prop2` | +| select.js:249:14:249:61 | select.js:249 | select.js:249:14:249:61 | SELECT. ... .prop2` | +| select.js:250:14:250:61 | select.js:250 | select.js:250:14:250:61 | SELECT. ... l2 asc` | +| select.js:251:14:251:58 | select.js:251 | select.js:251:14:251:58 | SELECT. ... l2 asc` | +| select.js:252:14:252:63 | select.js:252 | select.js:252:14:252:63 | SELECT. ... .prop2` | +| select.js:253:14:253:62 | select.js:253 | select.js:253:14:253:62 | SELECT. ... .prop2` | +| select.js:254:14:254:62 | select.js:254 | select.js:254:14:254:62 | SELECT. ... 2 desc` | +| select.js:255:14:255:60 | select.js:255 | select.js:255:14:255:60 | SELECT. ... 2 desc` | +| select.js:258:14:258:41 | select.js:258 | select.js:258:14:258:41 | SELECT. ... mit(10) | +| select.js:259:14:259:44 | select.js:259 | select.js:259:14:259:44 | SELECT. ... `${10}` | +| select.js:260:14:260:45 | select.js:260 | select.js:260:14:260:45 | SELECT. ... 10, 20) | +| select.js:261:14:261:50 | select.js:261 | select.js:261:14:261:50 | SELECT. ... : 10 }) | +| select.js:262:14:262:63 | select.js:262 | select.js:262:14:262:63 | SELECT. ... : 20 }) | +| select.js:263:14:263:60 | select.js:263 | select.js:263:14:263:60 | SELECT. ... al"] }) | +| select.js:264:14:266:2 | select.js:264 | select.js:264:14:266:2 | SELECT. ... }],\\n}) | +| select.js:268:14:268:41 | select.js:268 | select.js:268:14:268:41 | SELECT. ... mit(10) | +| select.js:269:14:269:44 | select.js:269 | select.js:269:14:269:44 | SELECT. ... `${10}` | +| select.js:270:14:270:45 | select.js:270 | select.js:270:14:270:45 | SELECT. ... 10, 20) | +| select.js:271:14:271:50 | select.js:271 | select.js:271:14:271:50 | SELECT. ... : 10 }) | +| select.js:272:14:272:63 | select.js:272 | select.js:272:14:272:63 | SELECT. ... : 20 }) | +| select.js:273:14:273:60 | select.js:273 | select.js:273:14:273:60 | SELECT. ... al"] }) | +| select.js:274:14:276:2 | select.js:274 | select.js:274:14:276:2 | SELECT. ... }],\\n}) | +| select.js:279:14:280:35 | select.js:279 | select.js:279:14:280:35 | SELECT. ... pdate() | +| select.js:283:14:284:38 | select.js:283 | select.js:283:14:284:38 | SELECT. ... eLock() | +| select.js:287:14:292:48 | select.js:287 | select.js:287:14:292:48 | SELECT. ... eLock() | diff --git a/javascript/frameworks/cap/test/models/cql/update.expected b/javascript/frameworks/cap/test/models/cql/update.expected index e69de29bb..fd18594a2 100644 --- a/javascript/frameworks/cap/test/models/cql/update.expected +++ b/javascript/frameworks/cap/test/models/cql/update.expected @@ -0,0 +1,216 @@ +| update.js:4:14:4:53 | update.js:4 | update.js:4:14:4:53 | UPDATE` ... {diff}` | +| update.js:5:14:5:95 | update.js:5 | update.js:5:14:5:95 | UPDATE` ... ] }, }) | +| update.js:6:14:6:46 | update.js:6 | update.js:6:14:6:46 | UPDATE` ... diff }) | +| update.js:8:14:8:53 | update.js:8 | update.js:8:14:8:53 | UPDATE( ... {diff}` | +| update.js:9:14:9:95 | update.js:9 | update.js:9:14:9:95 | UPDATE( ... ] }, }) | +| update.js:10:14:10:46 | update.js:10 | update.js:10:14:10:46 | UPDATE( ... diff }) | +| update.js:12:14:12:55 | update.js:12 | update.js:12:14:12:55 | UPDATE( ... {diff}` | +| update.js:13:14:13:97 | update.js:13 | update.js:13:14:13:97 | UPDATE( ... ] }, }) | +| update.js:14:14:14:48 | update.js:14 | update.js:14:14:14:48 | UPDATE( ... diff }) | +| update.js:17:14:17:60 | update.js:17 | update.js:17:14:17:60 | UPDATE. ... {diff}` | +| update.js:18:14:18:102 | update.js:18 | update.js:18:14:18:102 | UPDATE. ... ] }, }) | +| update.js:19:14:19:53 | update.js:19 | update.js:19:14:19:53 | UPDATE. ... diff }) | +| update.js:21:14:21:62 | update.js:21 | update.js:21:14:21:62 | UPDATE. ... {diff}` | +| update.js:22:14:22:104 | update.js:22 | update.js:22:14:22:104 | UPDATE. ... ] }, }) | +| update.js:23:14:23:55 | update.js:23 | update.js:23:14:23:55 | UPDATE. ... diff }) | +| update.js:25:14:25:60 | update.js:25 | update.js:25:14:25:60 | UPDATE. ... {diff}` | +| update.js:26:14:26:102 | update.js:26 | update.js:26:14:26:102 | UPDATE. ... ] }, }) | +| update.js:27:14:27:53 | update.js:27 | update.js:27:14:27:53 | UPDATE. ... diff }) | +| update.js:32:14:32:54 | update.js:32 | update.js:32:14:32:54 | UPDATE` ... {diff}` | +| update.js:33:14:33:96 | update.js:33 | update.js:33:14:33:96 | UPDATE` ... ] }, }) | +| update.js:34:14:34:47 | update.js:34 | update.js:34:14:34:47 | UPDATE` ... diff }) | +| update.js:37:14:37:61 | update.js:37 | update.js:37:14:37:61 | UPDATE. ... {diff}` | +| update.js:38:14:38:103 | update.js:38 | update.js:38:14:38:103 | UPDATE. ... ] }, }) | +| update.js:39:14:39:54 | update.js:39 | update.js:39:14:39:54 | UPDATE. ... diff }) | +| update.js:44:14:44:74 | update.js:44 | update.js:44:14:44:74 | UPDATE` ... "*" }) | +| update.js:45:14:45:71 | update.js:45 | update.js:45:14:45:71 | UPDATE` ... 1='*'") | +| update.js:46:14:46:72 | update.js:46 | update.js:46:14:46:72 | UPDATE` ... ${"*"}` | +| update.js:47:14:47:73 | update.js:47 | update.js:47:14:47:73 | UPDATE` ... ", "*") | +| update.js:48:14:48:73 | update.js:48 | update.js:48:14:48:73 | UPDATE` ... ${"*"}` | +| update.js:49:14:49:80 | update.js:49 | update.js:49:14:49:80 | UPDATE` ... , 10)") | +| update.js:50:14:50:86 | update.js:50 | update.js:50:14:50:86 | UPDATE` ... 0), ]}` | +| update.js:51:14:51:93 | update.js:51 | update.js:51:14:51:93 | UPDATE` ... 1 }, }) | +| update.js:53:14:53:115 | update.js:53 | update.js:53:14:53:115 | UPDATE` ... "*" }) | +| update.js:54:14:54:112 | update.js:54 | update.js:54:14:54:112 | UPDATE` ... 1='*'") | +| update.js:55:14:55:114 | update.js:55 | update.js:55:14:55:114 | UPDATE` ... ${"*"}` | +| update.js:56:14:56:114 | update.js:56 | update.js:56:14:56:114 | UPDATE` ... ", "*") | +| update.js:57:14:57:115 | update.js:57 | update.js:57:14:57:115 | UPDATE` ... ${"*"}` | +| update.js:58:14:58:121 | update.js:58 | update.js:58:14:58:121 | UPDATE` ... , 10)") | +| update.js:59:14:59:125 | update.js:59 | update.js:59:14:59:125 | UPDATE` ... 10)]}` | +| update.js:60:14:60:133 | update.js:60 | update.js:60:14:60:133 | UPDATE` ... 11 } }) | +| update.js:62:14:62:67 | update.js:62 | update.js:62:14:62:67 | UPDATE` ... "*" }) | +| update.js:63:14:63:64 | update.js:63 | update.js:63:14:63:64 | UPDATE` ... 1='*'") | +| update.js:64:14:64:65 | update.js:64 | update.js:64:14:64:65 | UPDATE` ... ${"*"}` | +| update.js:65:14:65:66 | update.js:65 | update.js:65:14:65:66 | UPDATE` ... ", "*") | +| update.js:66:14:66:66 | update.js:66 | update.js:66:14:66:66 | UPDATE` ... ${"*"}` | +| update.js:67:14:67:73 | update.js:67 | update.js:67:14:67:73 | UPDATE` ... , 10)") | +| update.js:68:14:68:76 | update.js:68 | update.js:68:14:68:76 | UPDATE` ... 10)]}` | +| update.js:69:14:69:85 | update.js:69 | update.js:69:14:69:85 | UPDATE` ... 11 } }) | +| update.js:72:14:72:81 | update.js:72 | update.js:72:14:72:81 | UPDATE. ... "*" }) | +| update.js:73:14:73:78 | update.js:73 | update.js:73:14:73:78 | UPDATE. ... 1='*'") | +| update.js:74:14:74:79 | update.js:74 | update.js:74:14:74:79 | UPDATE. ... ${"*"}` | +| update.js:75:14:75:80 | update.js:75 | update.js:75:14:75:80 | UPDATE. ... ", "*") | +| update.js:76:14:76:80 | update.js:76 | update.js:76:14:76:80 | UPDATE. ... ${"*"}` | +| update.js:77:14:77:87 | update.js:77 | update.js:77:14:77:87 | UPDATE. ... , 10)") | +| update.js:78:14:78:93 | update.js:78 | update.js:78:14:78:93 | UPDATE. ... 0), ]}` | +| update.js:79:14:79:100 | update.js:79 | update.js:79:14:79:100 | UPDATE. ... 1 }, }) | +| update.js:81:14:81:122 | update.js:81 | update.js:81:14:81:122 | UPDATE. ... "*" }) | +| update.js:82:14:82:119 | update.js:82 | update.js:82:14:82:119 | UPDATE. ... 1='*'") | +| update.js:83:14:83:121 | update.js:83 | update.js:83:14:83:121 | UPDATE. ... ${"*"}` | +| update.js:84:14:84:121 | update.js:84 | update.js:84:14:84:121 | UPDATE. ... ", "*") | +| update.js:85:14:85:122 | update.js:85 | update.js:85:14:85:122 | UPDATE. ... ${"*"}` | +| update.js:86:14:86:128 | update.js:86 | update.js:86:14:86:128 | UPDATE. ... , 10)") | +| update.js:87:14:87:132 | update.js:87 | update.js:87:14:87:132 | UPDATE. ... 10)]}` | +| update.js:88:14:88:140 | update.js:88 | update.js:88:14:88:140 | UPDATE. ... 11 } }) | +| update.js:90:14:90:74 | update.js:90 | update.js:90:14:90:74 | UPDATE. ... "*" }) | +| update.js:91:14:91:71 | update.js:91 | update.js:91:14:91:71 | UPDATE. ... 1='*'") | +| update.js:92:14:92:72 | update.js:92 | update.js:92:14:92:72 | UPDATE. ... ${"*"}` | +| update.js:93:14:93:73 | update.js:93 | update.js:93:14:93:73 | UPDATE. ... ", "*") | +| update.js:94:14:94:73 | update.js:94 | update.js:94:14:94:73 | UPDATE. ... ${"*"}` | +| update.js:95:14:95:80 | update.js:95 | update.js:95:14:95:80 | UPDATE. ... , 10)") | +| update.js:96:14:96:83 | update.js:96 | update.js:96:14:96:83 | UPDATE. ... 10)]}` | +| update.js:97:14:97:92 | update.js:97 | update.js:97:14:97:92 | UPDATE. ... 11 } }) | +| update.js:99:14:99:81 | update.js:99 | update.js:99:14:99:81 | UPDATE. ... "*" }) | +| update.js:100:14:100:78 | update.js:100 | update.js:100:14:100:78 | UPDATE. ... 1='*'") | +| update.js:101:14:101:79 | update.js:101 | update.js:101:14:101:79 | UPDATE. ... ${"*"}` | +| update.js:102:14:102:80 | update.js:102 | update.js:102:14:102:80 | UPDATE. ... ", "*") | +| update.js:103:14:103:80 | update.js:103 | update.js:103:14:103:80 | UPDATE. ... ${"*"}` | +| update.js:104:14:104:87 | update.js:104 | update.js:104:14:104:87 | UPDATE. ... , 10)") | +| update.js:105:14:105:93 | update.js:105 | update.js:105:14:105:93 | UPDATE. ... 0), ]}` | +| update.js:106:14:106:100 | update.js:106 | update.js:106:14:106:100 | UPDATE. ... 1 }, }) | +| update.js:108:14:108:122 | update.js:108 | update.js:108:14:108:122 | UPDATE. ... "*" }) | +| update.js:109:14:109:119 | update.js:109 | update.js:109:14:109:119 | UPDATE. ... 1='*'") | +| update.js:110:14:110:121 | update.js:110 | update.js:110:14:110:121 | UPDATE. ... ${"*"}` | +| update.js:111:14:111:121 | update.js:111 | update.js:111:14:111:121 | UPDATE. ... ", "*") | +| update.js:112:14:112:122 | update.js:112 | update.js:112:14:112:122 | UPDATE. ... ${"*"}` | +| update.js:113:14:113:128 | update.js:113 | update.js:113:14:113:128 | UPDATE. ... , 10)") | +| update.js:114:14:114:132 | update.js:114 | update.js:114:14:114:132 | UPDATE. ... 10)]}` | +| update.js:115:14:115:140 | update.js:115 | update.js:115:14:115:140 | UPDATE. ... 11 } }) | +| update.js:117:14:117:74 | update.js:117 | update.js:117:14:117:74 | UPDATE. ... "*" }) | +| update.js:118:14:118:71 | update.js:118 | update.js:118:14:118:71 | UPDATE. ... 1='*'") | +| update.js:119:14:119:72 | update.js:119 | update.js:119:14:119:72 | UPDATE. ... ${"*"}` | +| update.js:120:14:120:73 | update.js:120 | update.js:120:14:120:73 | UPDATE. ... ", "*") | +| update.js:121:14:121:73 | update.js:121 | update.js:121:14:121:73 | UPDATE. ... ${"*"}` | +| update.js:122:14:122:80 | update.js:122 | update.js:122:14:122:80 | UPDATE. ... , 10)") | +| update.js:123:14:123:83 | update.js:123 | update.js:123:14:123:83 | UPDATE. ... 10)]}` | +| update.js:124:14:124:92 | update.js:124 | update.js:124:14:124:92 | UPDATE. ... 11 } }) | +| update.js:126:14:126:83 | update.js:126 | update.js:126:14:126:83 | UPDATE. ... "*" }) | +| update.js:127:14:127:80 | update.js:127 | update.js:127:14:127:80 | UPDATE. ... 1='*'") | +| update.js:128:14:128:81 | update.js:128 | update.js:128:14:128:81 | UPDATE. ... ${"*"}` | +| update.js:129:14:129:82 | update.js:129 | update.js:129:14:129:82 | UPDATE. ... ", "*") | +| update.js:130:14:130:82 | update.js:130 | update.js:130:14:130:82 | UPDATE. ... ${"*"}` | +| update.js:131:14:131:89 | update.js:131 | update.js:131:14:131:89 | UPDATE. ... , 10)") | +| update.js:132:14:132:95 | update.js:132 | update.js:132:14:132:95 | UPDATE. ... 0), ]}` | +| update.js:133:14:133:102 | update.js:133 | update.js:133:14:133:102 | UPDATE. ... 1 }, }) | +| update.js:135:14:135:124 | update.js:135 | update.js:135:14:135:124 | UPDATE. ... "*" }) | +| update.js:136:14:136:121 | update.js:136 | update.js:136:14:136:121 | UPDATE. ... 1='*'") | +| update.js:137:14:137:123 | update.js:137 | update.js:137:14:137:123 | UPDATE. ... ${"*"}` | +| update.js:138:14:138:123 | update.js:138 | update.js:138:14:138:123 | UPDATE. ... ", "*") | +| update.js:139:14:139:124 | update.js:139 | update.js:139:14:139:124 | UPDATE. ... ${"*"}` | +| update.js:140:14:140:130 | update.js:140 | update.js:140:14:140:130 | UPDATE. ... , 10)") | +| update.js:141:14:141:134 | update.js:141 | update.js:141:14:141:134 | UPDATE. ... 10)]}` | +| update.js:142:14:142:142 | update.js:142 | update.js:142:14:142:142 | UPDATE. ... 11 } }) | +| update.js:144:14:144:76 | update.js:144 | update.js:144:14:144:76 | UPDATE. ... "*" }) | +| update.js:145:14:145:73 | update.js:145 | update.js:145:14:145:73 | UPDATE. ... 1='*'") | +| update.js:146:14:146:74 | update.js:146 | update.js:146:14:146:74 | UPDATE. ... ${"*"}` | +| update.js:147:14:147:75 | update.js:147 | update.js:147:14:147:75 | UPDATE. ... ", "*") | +| update.js:148:14:148:75 | update.js:148 | update.js:148:14:148:75 | UPDATE. ... ${"*"}` | +| update.js:149:14:149:82 | update.js:149 | update.js:149:14:149:82 | UPDATE. ... , 10)") | +| update.js:150:14:150:85 | update.js:150 | update.js:150:14:150:85 | UPDATE. ... 10)]}` | +| update.js:151:14:151:94 | update.js:151 | update.js:151:14:151:94 | UPDATE. ... 11 } }) | +| update.js:156:14:156:75 | update.js:156 | update.js:156:14:156:75 | UPDATE` ... "*" }) | +| update.js:157:14:157:72 | update.js:157 | update.js:157:14:157:72 | UPDATE` ... 1='*'") | +| update.js:158:14:158:73 | update.js:158 | update.js:158:14:158:73 | UPDATE` ... ${"*"}` | +| update.js:159:14:159:74 | update.js:159 | update.js:159:14:159:74 | UPDATE` ... ", "*") | +| update.js:160:14:160:74 | update.js:160 | update.js:160:14:160:74 | UPDATE` ... ${"*"}` | +| update.js:161:14:161:81 | update.js:161 | update.js:161:14:161:81 | UPDATE` ... , 10)") | +| update.js:162:14:162:87 | update.js:162 | update.js:162:14:162:87 | UPDATE` ... 0), ]}` | +| update.js:163:14:163:94 | update.js:163 | update.js:163:14:163:94 | UPDATE` ... 1 }, }) | +| update.js:165:14:165:116 | update.js:165 | update.js:165:14:165:116 | UPDATE` ... "*" }) | +| update.js:166:14:166:113 | update.js:166 | update.js:166:14:166:113 | UPDATE` ... 1='*'") | +| update.js:167:14:167:115 | update.js:167 | update.js:167:14:167:115 | UPDATE` ... ${"*"}` | +| update.js:168:14:168:115 | update.js:168 | update.js:168:14:168:115 | UPDATE` ... ", "*") | +| update.js:169:14:169:116 | update.js:169 | update.js:169:14:169:116 | UPDATE` ... ${"*"}` | +| update.js:170:14:170:122 | update.js:170 | update.js:170:14:170:122 | UPDATE` ... , 10)") | +| update.js:171:14:171:126 | update.js:171 | update.js:171:14:171:126 | UPDATE` ... 10)]}` | +| update.js:172:14:172:134 | update.js:172 | update.js:172:14:172:134 | UPDATE` ... 11 } }) | +| update.js:174:14:174:68 | update.js:174 | update.js:174:14:174:68 | UPDATE` ... "*" }) | +| update.js:175:14:175:65 | update.js:175 | update.js:175:14:175:65 | UPDATE` ... 1='*'") | +| update.js:176:14:176:66 | update.js:176 | update.js:176:14:176:66 | UPDATE` ... ${"*"}` | +| update.js:177:14:177:67 | update.js:177 | update.js:177:14:177:67 | UPDATE` ... ", "*") | +| update.js:178:14:178:67 | update.js:178 | update.js:178:14:178:67 | UPDATE` ... ${"*"}` | +| update.js:179:14:179:74 | update.js:179 | update.js:179:14:179:74 | UPDATE` ... , 10)") | +| update.js:180:14:180:77 | update.js:180 | update.js:180:14:180:77 | UPDATE` ... 10)]}` | +| update.js:181:14:181:86 | update.js:181 | update.js:181:14:181:86 | UPDATE` ... 11 } }) | +| update.js:184:14:184:82 | update.js:184 | update.js:184:14:184:82 | UPDATE. ... "*" }) | +| update.js:185:14:185:79 | update.js:185 | update.js:185:14:185:79 | UPDATE. ... 1='*'") | +| update.js:186:14:186:80 | update.js:186 | update.js:186:14:186:80 | UPDATE. ... ${"*"}` | +| update.js:187:14:187:81 | update.js:187 | update.js:187:14:187:81 | UPDATE. ... ", "*") | +| update.js:188:14:188:81 | update.js:188 | update.js:188:14:188:81 | UPDATE. ... ${"*"}` | +| update.js:189:14:189:88 | update.js:189 | update.js:189:14:189:88 | UPDATE. ... , 10)") | +| update.js:190:14:190:94 | update.js:190 | update.js:190:14:190:94 | UPDATE. ... 0), ]}` | +| update.js:191:14:191:101 | update.js:191 | update.js:191:14:191:101 | UPDATE. ... 1 }, }) | +| update.js:193:14:193:123 | update.js:193 | update.js:193:14:193:123 | UPDATE. ... "*" }) | +| update.js:194:14:194:120 | update.js:194 | update.js:194:14:194:120 | UPDATE. ... 1='*'") | +| update.js:195:14:195:122 | update.js:195 | update.js:195:14:195:122 | UPDATE. ... ${"*"}` | +| update.js:196:14:196:122 | update.js:196 | update.js:196:14:196:122 | UPDATE. ... ", "*") | +| update.js:197:14:197:123 | update.js:197 | update.js:197:14:197:123 | UPDATE. ... ${"*"}` | +| update.js:198:14:198:129 | update.js:198 | update.js:198:14:198:129 | UPDATE. ... , 10)") | +| update.js:199:14:199:133 | update.js:199 | update.js:199:14:199:133 | UPDATE. ... 10)]}` | +| update.js:200:14:200:141 | update.js:200 | update.js:200:14:200:141 | UPDATE. ... 11 } }) | +| update.js:202:14:202:75 | update.js:202 | update.js:202:14:202:75 | UPDATE. ... "*" }) | +| update.js:203:14:203:72 | update.js:203 | update.js:203:14:203:72 | UPDATE. ... 1='*'") | +| update.js:204:14:204:73 | update.js:204 | update.js:204:14:204:73 | UPDATE. ... ${"*"}` | +| update.js:205:14:205:74 | update.js:205 | update.js:205:14:205:74 | UPDATE. ... ", "*") | +| update.js:206:14:206:74 | update.js:206 | update.js:206:14:206:74 | UPDATE. ... ${"*"}` | +| update.js:207:14:207:81 | update.js:207 | update.js:207:14:207:81 | UPDATE. ... , 10)") | +| update.js:208:14:208:84 | update.js:208 | update.js:208:14:208:84 | UPDATE. ... 10)]}` | +| update.js:209:14:209:93 | update.js:209 | update.js:209:14:209:93 | UPDATE. ... 11 } }) | +| update.js:211:14:211:82 | update.js:211 | update.js:211:14:211:82 | UPDATE. ... "*" }) | +| update.js:212:14:212:79 | update.js:212 | update.js:212:14:212:79 | UPDATE. ... 1='*'") | +| update.js:213:14:213:80 | update.js:213 | update.js:213:14:213:80 | UPDATE. ... ${"*"}` | +| update.js:214:14:214:81 | update.js:214 | update.js:214:14:214:81 | UPDATE. ... ", "*") | +| update.js:215:14:215:81 | update.js:215 | update.js:215:14:215:81 | UPDATE. ... ${"*"}` | +| update.js:216:14:216:88 | update.js:216 | update.js:216:14:216:88 | UPDATE. ... , 10)") | +| update.js:217:14:217:94 | update.js:217 | update.js:217:14:217:94 | UPDATE. ... 0), ]}` | +| update.js:218:14:218:101 | update.js:218 | update.js:218:14:218:101 | UPDATE. ... 1 }, }) | +| update.js:220:14:220:123 | update.js:220 | update.js:220:14:220:123 | UPDATE. ... "*" }) | +| update.js:221:14:221:120 | update.js:221 | update.js:221:14:221:120 | UPDATE. ... 1='*'") | +| update.js:222:14:222:122 | update.js:222 | update.js:222:14:222:122 | UPDATE. ... ${"*"}` | +| update.js:223:14:223:122 | update.js:223 | update.js:223:14:223:122 | UPDATE. ... ", "*") | +| update.js:224:14:224:123 | update.js:224 | update.js:224:14:224:123 | UPDATE. ... ${"*"}` | +| update.js:225:14:225:129 | update.js:225 | update.js:225:14:225:129 | UPDATE. ... , 10)") | +| update.js:226:14:226:133 | update.js:226 | update.js:226:14:226:133 | UPDATE. ... 10)]}` | +| update.js:227:14:227:141 | update.js:227 | update.js:227:14:227:141 | UPDATE. ... 11 } }) | +| update.js:229:14:229:75 | update.js:229 | update.js:229:14:229:75 | UPDATE. ... "*" }) | +| update.js:230:14:230:72 | update.js:230 | update.js:230:14:230:72 | UPDATE. ... 1='*'") | +| update.js:231:14:231:73 | update.js:231 | update.js:231:14:231:73 | UPDATE. ... ${"*"}` | +| update.js:232:14:232:74 | update.js:232 | update.js:232:14:232:74 | UPDATE. ... ", "*") | +| update.js:233:14:233:74 | update.js:233 | update.js:233:14:233:74 | UPDATE. ... ${"*"}` | +| update.js:234:14:234:81 | update.js:234 | update.js:234:14:234:81 | UPDATE. ... , 10)") | +| update.js:235:14:235:84 | update.js:235 | update.js:235:14:235:84 | UPDATE. ... 10)]}` | +| update.js:236:14:236:93 | update.js:236 | update.js:236:14:236:93 | UPDATE. ... 11 } }) | +| update.js:238:14:238:84 | update.js:238 | update.js:238:14:238:84 | UPDATE. ... "*" }) | +| update.js:239:14:239:81 | update.js:239 | update.js:239:14:239:81 | UPDATE. ... 1='*'") | +| update.js:240:14:240:82 | update.js:240 | update.js:240:14:240:82 | UPDATE. ... ${"*"}` | +| update.js:241:14:241:83 | update.js:241 | update.js:241:14:241:83 | UPDATE. ... ", "*") | +| update.js:242:14:242:83 | update.js:242 | update.js:242:14:242:83 | UPDATE. ... ${"*"}` | +| update.js:243:14:243:90 | update.js:243 | update.js:243:14:243:90 | UPDATE. ... , 10)") | +| update.js:244:14:244:96 | update.js:244 | update.js:244:14:244:96 | UPDATE. ... 0), ]}` | +| update.js:245:14:245:103 | update.js:245 | update.js:245:14:245:103 | UPDATE. ... 1 }, }) | +| update.js:247:14:247:125 | update.js:247 | update.js:247:14:247:125 | UPDATE. ... "*" }) | +| update.js:248:14:248:122 | update.js:248 | update.js:248:14:248:122 | UPDATE. ... 1='*'") | +| update.js:249:14:249:124 | update.js:249 | update.js:249:14:249:124 | UPDATE. ... ${"*"}` | +| update.js:250:14:250:124 | update.js:250 | update.js:250:14:250:124 | UPDATE. ... ", "*") | +| update.js:251:14:251:125 | update.js:251 | update.js:251:14:251:125 | UPDATE. ... ${"*"}` | +| update.js:252:14:252:131 | update.js:252 | update.js:252:14:252:131 | UPDATE. ... , 10)") | +| update.js:253:14:253:135 | update.js:253 | update.js:253:14:253:135 | UPDATE. ... 10)]}` | +| update.js:254:14:254:143 | update.js:254 | update.js:254:14:254:143 | UPDATE. ... 11 } }) | +| update.js:256:14:256:77 | update.js:256 | update.js:256:14:256:77 | UPDATE. ... "*" }) | +| update.js:257:14:257:74 | update.js:257 | update.js:257:14:257:74 | UPDATE. ... 1='*'") | +| update.js:258:14:258:75 | update.js:258 | update.js:258:14:258:75 | UPDATE. ... ${"*"}` | +| update.js:259:14:259:76 | update.js:259 | update.js:259:14:259:76 | UPDATE. ... ", "*") | +| update.js:260:14:260:76 | update.js:260 | update.js:260:14:260:76 | UPDATE. ... ${"*"}` | +| update.js:261:14:261:83 | update.js:261 | update.js:261:14:261:83 | UPDATE. ... , 10)") | +| update.js:262:14:262:86 | update.js:262 | update.js:262:14:262:86 | UPDATE. ... 10)]}` | +| update.js:263:14:263:95 | update.js:263 | update.js:263:14:263:95 | UPDATE. ... 11 } }) | diff --git a/javascript/frameworks/cap/test/models/cql/update.js b/javascript/frameworks/cap/test/models/cql/update.js index 2f9c49a9e..e5c4c8a57 100644 --- a/javascript/frameworks/cap/test/models/cql/update.js +++ b/javascript/frameworks/cap/test/models/cql/update.js @@ -1,6 +1,3 @@ -let diff = 1; -let val = 2; - /* ========== UPDATE (entity), set ========== */ /* UPDATE acting as shortcut to UPDATE.entity */ diff --git a/javascript/frameworks/cap/test/models/cql/upsert.expected b/javascript/frameworks/cap/test/models/cql/upsert.expected index e69de29bb..69a2e7bb7 100644 --- a/javascript/frameworks/cap/test/models/cql/upsert.expected +++ b/javascript/frameworks/cap/test/models/cql/upsert.expected @@ -0,0 +1,10 @@ +| upsert.js:2:14:5:14 | upsert.js:2 | upsert.js:2:14:5:14 | UPSERT( ... (Table) | +| upsert.js:6:14:9:16 | upsert.js:6 | upsert.js:6:14:9:16 | UPSERT( ... Table") | +| upsert.js:11:14:14:2 | upsert.js:11 | upsert.js:11:14:14:2 | UPSERT. ... " },\\n]) | +| upsert.js:15:14:18:2 | upsert.js:15 | upsert.js:15:14:18:2 | UPSERT. ... " },\\n]) | +| upsert.js:21:14:24:1 | upsert.js:21 | upsert.js:21:14:24:1 | UPSERT. ... 22" }\\n) | +| upsert.js:25:14:28:2 | upsert.js:25 | upsert.js:25:14:28:2 | UPSERT. ... " },\\n]) | +| upsert.js:29:14:32:2 | upsert.js:29 | upsert.js:29:14:32:2 | UPSERT. ... " },\\n]) | +| upsert.js:33:14:36:2 | upsert.js:33 | upsert.js:33:14:36:2 | UPSERT. ... " },\\n]) | +| upsert.js:37:14:40:2 | upsert.js:37 | upsert.js:37:14:40:2 | UPSERT. ... " },\\n]) | +| upsert.js:41:14:44:2 | upsert.js:41 | upsert.js:41:14:44:2 | UPSERT. ... " },\\n]) | From c3c949b973b305be87b1e77804701aa1fcfc176a Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 20 Dec 2023 16:17:03 -0500 Subject: [PATCH 50/61] Upgrade CodeQL dependencies and bump pack versions --- javascript/frameworks/cap/ext/qlpack.yml | 6 +++--- .../frameworks/cap/lib/codeql-pack.lock.yml | 12 +++++++----- javascript/frameworks/cap/lib/qlpack.yml | 6 +++--- .../frameworks/cap/src/codeql-pack.lock.yml | 12 +++++++----- javascript/frameworks/cap/src/qlpack.yml | 8 ++++---- .../frameworks/cap/test/codeql-pack.lock.yml | 18 ++++++++++-------- javascript/frameworks/cap/test/qlpack.yml | 12 ++++++------ 7 files changed, 40 insertions(+), 34 deletions(-) diff --git a/javascript/frameworks/cap/ext/qlpack.yml b/javascript/frameworks/cap/ext/qlpack.yml index 365426211..ba988c804 100644 --- a/javascript/frameworks/cap/ext/qlpack.yml +++ b/javascript/frameworks/cap/ext/qlpack.yml @@ -1,9 +1,9 @@ --- library: true name: advanced-security/javascript-sap-cap-models -version: 0.2.0 +version: 0.3.0 extensionTargets: - codeql/javascript-all: "^0.6.3" - codeql/javascript-queries: "^0.6.3" + codeql/javascript-all: "^0.8.1" + codeql/javascript-queries: "^0.8.1" dataExtensions: - "*.model.yml" \ No newline at end of file diff --git a/javascript/frameworks/cap/lib/codeql-pack.lock.yml b/javascript/frameworks/cap/lib/codeql-pack.lock.yml index f8b362092..fad4fb67b 100644 --- a/javascript/frameworks/cap/lib/codeql-pack.lock.yml +++ b/javascript/frameworks/cap/lib/codeql-pack.lock.yml @@ -2,13 +2,15 @@ lockVersion: 1.0.0 dependencies: codeql/javascript-all: - version: 0.6.4 + version: 0.8.5 + codeql/mad: + version: 0.2.5 codeql/regex: - version: 0.0.15 + version: 0.2.5 codeql/tutorial: - version: 0.0.12 + version: 0.2.5 codeql/util: - version: 0.0.12 + version: 0.2.5 codeql/yaml: - version: 0.0.4 + version: 0.2.5 compiled: false diff --git a/javascript/frameworks/cap/lib/qlpack.yml b/javascript/frameworks/cap/lib/qlpack.yml index 737b1cb2b..7c18b0734 100644 --- a/javascript/frameworks/cap/lib/qlpack.yml +++ b/javascript/frameworks/cap/lib/qlpack.yml @@ -1,9 +1,9 @@ --- library: true name: advanced-security/javascript-sap-cap-all -version: 0.0.1 +version: 0.1.1 suites: codeql-suites extractor: javascript dependencies: - codeql/javascript-all: "^0.6.3" - advanced-security/javascript-sap-cap-models: "^0.2.0" + codeql/javascript-all: "^0.8.1" + advanced-security/javascript-sap-cap-models: "^0.3.0" diff --git a/javascript/frameworks/cap/src/codeql-pack.lock.yml b/javascript/frameworks/cap/src/codeql-pack.lock.yml index f8b362092..fad4fb67b 100644 --- a/javascript/frameworks/cap/src/codeql-pack.lock.yml +++ b/javascript/frameworks/cap/src/codeql-pack.lock.yml @@ -2,13 +2,15 @@ lockVersion: 1.0.0 dependencies: codeql/javascript-all: - version: 0.6.4 + version: 0.8.5 + codeql/mad: + version: 0.2.5 codeql/regex: - version: 0.0.15 + version: 0.2.5 codeql/tutorial: - version: 0.0.12 + version: 0.2.5 codeql/util: - version: 0.0.12 + version: 0.2.5 codeql/yaml: - version: 0.0.4 + version: 0.2.5 compiled: false diff --git a/javascript/frameworks/cap/src/qlpack.yml b/javascript/frameworks/cap/src/qlpack.yml index a102e570f..112b503ba 100644 --- a/javascript/frameworks/cap/src/qlpack.yml +++ b/javascript/frameworks/cap/src/qlpack.yml @@ -1,10 +1,10 @@ --- library: false name: advanced-security/javascript-sap-cap-queries -version: 0.2.0 +version: 0.3.0 suites: codeql-suites extractor: javascript dependencies: - codeql/javascript-all: "^0.6.3" - advanced-security/javascript-sap-cap-models: "^0.2.0" - advanced-security/javascript-sap-cap-all: "^0.2.0" \ No newline at end of file + codeql/javascript-all: "^0.8.1" + advanced-security/javascript-sap-cap-models: "^0.3.0" + advanced-security/javascript-sap-cap-all: "^0.1.1" \ No newline at end of file diff --git a/javascript/frameworks/cap/test/codeql-pack.lock.yml b/javascript/frameworks/cap/test/codeql-pack.lock.yml index 79d3aa8c2..b731a4d91 100644 --- a/javascript/frameworks/cap/test/codeql-pack.lock.yml +++ b/javascript/frameworks/cap/test/codeql-pack.lock.yml @@ -2,19 +2,21 @@ lockVersion: 1.0.0 dependencies: codeql/javascript-all: - version: 0.6.4 + version: 0.8.5 codeql/javascript-queries: - version: 0.6.4 + version: 0.8.5 + codeql/mad: + version: 0.2.5 codeql/regex: - version: 0.0.15 + version: 0.2.5 codeql/suite-helpers: - version: 0.5.4 + version: 0.7.5 codeql/tutorial: - version: 0.0.12 + version: 0.2.5 codeql/typos: - version: 0.0.19 + version: 0.2.5 codeql/util: - version: 0.0.12 + version: 0.2.5 codeql/yaml: - version: 0.0.4 + version: 0.2.5 compiled: false diff --git a/javascript/frameworks/cap/test/qlpack.yml b/javascript/frameworks/cap/test/qlpack.yml index 264055b76..96c3a8232 100644 --- a/javascript/frameworks/cap/test/qlpack.yml +++ b/javascript/frameworks/cap/test/qlpack.yml @@ -1,10 +1,10 @@ --- name: advanced-security/javascript-sap-cap-queries-tests -version: 0.2.0 +version: 0.3.0 extractor: javascript dependencies: - codeql/javascript-all: "^0.6.3" - codeql/javascript-queries: "^0.6.3" - advanced-security/javascript-sap-cap-queries: "^0.2.0" - advanced-security/javascript-sap-cap-models: "^0.2.0" - advanced-security/javascript-sap-cap-all: "^0.2.0" \ No newline at end of file + codeql/javascript-all: "^0.8.1" + codeql/javascript-queries: "^0.8.1" + advanced-security/javascript-sap-cap-queries: "^0.3.0" + advanced-security/javascript-sap-cap-models: "^0.3.0" + advanced-security/javascript-sap-cap-all: "^0.1.1" \ No newline at end of file From 4eef0034aebf2362e8c30e8211353fa6bed99b0b Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 20 Dec 2023 16:44:12 -0500 Subject: [PATCH 51/61] Minor additions comment style modules addition --- .../javascript/frameworks/cap/CDS.qll | 12 ++++--- .../javascript/frameworks/cap/CQL.qll | 31 +++++++++---------- .../frameworks/cap/test/models/cql/delete.ql | 2 +- .../frameworks/cap/test/models/cql/insert.ql | 2 +- .../frameworks/cap/test/models/cql/select.ql | 2 +- .../frameworks/cap/test/models/cql/update.ql | 2 +- .../frameworks/cap/test/models/cql/upsert.ql | 2 +- 7 files changed, 27 insertions(+), 26 deletions(-) diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll index 6e94d9ace..81adeefd2 100644 --- a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll @@ -1,11 +1,12 @@ -private import javascript -private import DataFlow +import javascript +import DataFlow +module CDS { abstract class Service extends ValueNode { } class ApplicationService extends Service { ApplicationService() { - /* 1. Awaiting or directly getting return value of `cds.serve` */ + // 1. Awaiting or directly getting return value of `cds.serve` // either CallExpr or AwaitExpr surrounding it exists(MethodCallNode cdsServeCall | any(CdsFacade cds).flowsTo(cdsServeCall.getReceiver()) and @@ -17,14 +18,14 @@ class ApplicationService extends Service { ) ) or - /* 2. From directly using the constructor: `new cds.ApplicationService` or `new cds.Service` */ + // 2. From directly using the constructor: `new cds.ApplicationService` or `new cds.Service` exists(MethodCallNode cdsDotService, CdsFacade cds | this = cdsDotService and cdsDotService.getReceiver() = cds and cdsDotService.getMethodName() = ["Service", "ApplicationService"] ) or - /* 3. Awaiting or directly getting return value of `cds.connect.to` */ + // 3. Awaiting or directly getting return value of `cds.connect.to` // TODO: Can be AwaitExpr surrounding it exists(CdsFacade cds, PropRef cdsConnect | this.(CallNode).getCalleeName() = "to" and @@ -125,4 +126,5 @@ class Request extends ValueNode, ParameterNode { */ class CdsFacade extends ModuleImportNode { CdsFacade() { this = moduleImport("@sap/cds") } +} } \ No newline at end of file diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll index 47042f9a5..d1e4ee2f5 100644 --- a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll @@ -1,17 +1,18 @@ -private import javascript -private import DataFlow -private import CDS +import javascript +import DataFlow +import CDS::CDS +module CQL { class CqlQueryBase extends VarRef { CqlQueryBase() { - /* Made available as a global variable */ + // Made available as a global variable exists(GlobalVariable queryBase | queryBase.getName() = ["SELECT", "INSERT", "DELETE", "UPDATE", "UPSERT"] | this = queryBase.getAReference() ) or - /* Imported from `cds.ql` */ + // Imported from `cds.ql` */ exists(CdsFacade cds, PropRef cdsDotQl | this.flow().getALocalSource() = cdsDotQl and cdsDotQl.getBase() = cds @@ -100,10 +101,7 @@ class CqlExpr extends TCqlExpr { /** * Convert this `CqlExpr` into a `DotExpr`, i.e. - * Get SELECT.from`Table` when given SELECT.from`Table`.where`cond`, - * Get SELECT.from(table) when given SELECT.from(table).where`cond`, - * Get SELECT.from`Table` when given SELECT.from`Table`.where(cond), - * Get SELECT.from(table) when given SELECT.from(table).where(cond). + * `Get SELECT.from'Table' when given SELECT.from'Table'.wherecond`, */ DotExpr asDotExpr() { result = this.asTaggedTemplate().getTag().(DotExpr) @@ -139,7 +137,7 @@ class CqlExpr extends TCqlExpr { result = this.asTaggedTemplate().getTag().(DotExpr).getBase() } - /* ========== Parent relationships ========== */ + /** ========== Parent relationships ========== */ Expr getParentExpr() { result = this.asMethodCall().getParentExpr() or result = this.asTaggedTemplate().getParentExpr() or @@ -164,7 +162,7 @@ class CqlExpr extends TCqlExpr { result.asShortcutCall() = this.getAnAncestorExpr() } - /* ========== Children relationships ========== */ + /** ========== Children relationships ========== */ Expr getAChildExpr() { result = this.asMethodCall().getAChildExpr() or result = this.asTaggedTemplate().getAChildExpr() or @@ -190,7 +188,7 @@ class CqlExpr extends TCqlExpr { } /** - * Matches the given CqlExpr to its method/property name, nested at arbitrary depth. + * Matches the given `CqlExpr` to its method/property name, nested at arbitrary depth. */ string getAnAPIName() { result = this.asDotExpr().getPropertyName() or @@ -219,7 +217,7 @@ class CqlSelectExpr extends CqlExpr { predicate selectColumns() { this.getAnAPIName() = "columns" or - /* SELECT itself is a shortcut of SELECT.columns */ + // SELECT itself is a shortcut of SELECT.columns this.getCqlBaseCall() instanceof CqlSelectBaseCall } } @@ -241,7 +239,7 @@ class CqlInsertExpr extends CqlExpr { predicate insertEntries() { this.getAnAPIName() = "entries" or - /* INSERT itself is a shortcut of INSERT.entries */ + // INSERT itself is a shortcut of INSERT.entries this.getCqlBaseCall() instanceof CqlInsertBaseCall } } @@ -276,7 +274,7 @@ class CqlUpdateExpr extends CqlExpr { predicate updateEntity() { this.getAnAPIName() = "entity" or - /* UPDATE itself is a shortcut of UPDATE.entity */ + // UPDATE itself is a shortcut of UPDATE.entity this.getCqlBaseCall() instanceof CqlUpdateBaseCall } } @@ -298,7 +296,8 @@ class CqlUpsertExpr extends CqlExpr { predicate upsertEntries() { this.getAnAPIName() = "entries" or - /* UPSERT itself is a shortcut of UPSERT.entries */ + // UPSERT itself is a shortcut of UPSERT.entries this.getCqlBaseCall() instanceof CqlUpsertBaseCall } } +} \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cql/delete.ql b/javascript/frameworks/cap/test/models/cql/delete.ql index 636bad4f1..f602eeba4 100644 --- a/javascript/frameworks/cap/test/models/cql/delete.ql +++ b/javascript/frameworks/cap/test/models/cql/delete.ql @@ -1,6 +1,6 @@ import javascript import advanced_security.javascript.frameworks.cap.CQL -from CqlDeleteExpr s +from CQL::CqlDeleteExpr s select s.getLocation(), s diff --git a/javascript/frameworks/cap/test/models/cql/insert.ql b/javascript/frameworks/cap/test/models/cql/insert.ql index bb73473d2..fddd3890c 100644 --- a/javascript/frameworks/cap/test/models/cql/insert.ql +++ b/javascript/frameworks/cap/test/models/cql/insert.ql @@ -1,5 +1,5 @@ import javascript import advanced_security.javascript.frameworks.cap.CQL -from CqlInsertExpr s +from CQL::CqlInsertExpr s select s.getLocation(), s diff --git a/javascript/frameworks/cap/test/models/cql/select.ql b/javascript/frameworks/cap/test/models/cql/select.ql index 78d704526..9f9d0d1fd 100644 --- a/javascript/frameworks/cap/test/models/cql/select.ql +++ b/javascript/frameworks/cap/test/models/cql/select.ql @@ -1,5 +1,5 @@ import javascript import advanced_security.javascript.frameworks.cap.CQL -from CqlSelectExpr s +from CQL::CqlSelectExpr s select s.getLocation(), s \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cql/update.ql b/javascript/frameworks/cap/test/models/cql/update.ql index 8f61fff44..88e3ea481 100644 --- a/javascript/frameworks/cap/test/models/cql/update.ql +++ b/javascript/frameworks/cap/test/models/cql/update.ql @@ -1,6 +1,6 @@ import javascript import advanced_security.javascript.frameworks.cap.CQL -from CqlUpdateExpr s +from CQL::CqlUpdateExpr s select s.getLocation(), s diff --git a/javascript/frameworks/cap/test/models/cql/upsert.ql b/javascript/frameworks/cap/test/models/cql/upsert.ql index 19b6cd1ce..156736ca7 100644 --- a/javascript/frameworks/cap/test/models/cql/upsert.ql +++ b/javascript/frameworks/cap/test/models/cql/upsert.ql @@ -1,6 +1,6 @@ import javascript import advanced_security.javascript.frameworks.cap.CQL -from CqlUpsertExpr s +from CQL::CqlUpsertExpr s select s.getLocation(), s From cf2b390657d6c8bec8de6b10d19ea646466e6c1b Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Fri, 22 Dec 2023 00:34:41 -0500 Subject: [PATCH 52/61] Refactor CDS add tests simplify models --- .../javascript/frameworks/cap/CDS.qll | 132 +++++++++--------- .../javascript/frameworks/cap/CQL.qll | 2 +- .../applicationserviceinstance.expected | 6 + .../applicationserviceinstance.js | 7 + .../applicationserviceinstance.ql | 5 + .../oldstyleuserdefined.expected | 1 + .../oldstyleuserdefined.js | 3 + .../oldstyleuserdefined.ql | 5 + .../requesthandler/requesthandler.expected | 2 + .../cds/requesthandler/requesthandler.js | 17 +++ .../cds/requesthandler/requesthandler.ql | 5 + .../userdefinedservice.expected | 1 + .../userdefinedservice/userdefinedservice.js | 8 ++ .../userdefinedservice/userdefinedservice.ql | 5 + 14 files changed, 133 insertions(+), 66 deletions(-) create mode 100644 javascript/frameworks/cap/test/models/cds/applicationserviceinstance/applicationserviceinstance.expected create mode 100644 javascript/frameworks/cap/test/models/cds/applicationserviceinstance/applicationserviceinstance.js create mode 100644 javascript/frameworks/cap/test/models/cds/applicationserviceinstance/applicationserviceinstance.ql create mode 100644 javascript/frameworks/cap/test/models/cds/oldstyleuserdefined/oldstyleuserdefined.expected create mode 100644 javascript/frameworks/cap/test/models/cds/oldstyleuserdefined/oldstyleuserdefined.js create mode 100644 javascript/frameworks/cap/test/models/cds/oldstyleuserdefined/oldstyleuserdefined.ql create mode 100644 javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.expected create mode 100644 javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.js create mode 100644 javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.ql create mode 100644 javascript/frameworks/cap/test/models/cds/userdefinedservice/userdefinedservice.expected create mode 100644 javascript/frameworks/cap/test/models/cds/userdefinedservice/userdefinedservice.js create mode 100644 javascript/frameworks/cap/test/models/cds/userdefinedservice/userdefinedservice.ql diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll index 81adeefd2..fd5d9fc79 100644 --- a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll @@ -2,37 +2,34 @@ import javascript import DataFlow module CDS { -abstract class Service extends ValueNode { } + // TODO: should this base type be more specific? +abstract class ServiceInstance extends DataFlow::Node { } -class ApplicationService extends Service { - ApplicationService() { - // 1. Awaiting or directly getting return value of `cds.serve` - // either CallExpr or AwaitExpr surrounding it - exists(MethodCallNode cdsServeCall | - any(CdsFacade cds).flowsTo(cdsServeCall.getReceiver()) and - cdsServeCall.getMethodName() = "serve" and - ( - this = cdsServeCall - or - this = any(AwaitExpr await).getOperand().flow() - ) - ) - or - // 2. From directly using the constructor: `new cds.ApplicationService` or `new cds.Service` - exists(MethodCallNode cdsDotService, CdsFacade cds | - this = cdsDotService and - cdsDotService.getReceiver() = cds and - cdsDotService.getMethodName() = ["Service", "ApplicationService"] - ) - or - // 3. Awaiting or directly getting return value of `cds.connect.to` - // TODO: Can be AwaitExpr surrounding it - exists(CdsFacade cds, PropRef cdsConnect | - this.(CallNode).getCalleeName() = "to" and - this.(CallNode).getReceiver() = cdsConnect and - cdsConnect.getPropertyName() = "connect" and - cdsConnect.getBase() = cds - ) +/** + * Call to`cds.serve` + */ +class CdsServeCall extends ServiceInstance { + CdsServeCall(){ + this = any(CdsFacade cds).getMember("serve").getACall() + } +} + +/** + * call to: + * `new cds.ApplicationService` or `new cds.Service` + */ +class ServiceConstructor extends ServiceInstance { + ServiceConstructor(){ + this = any(ApplicationService cds).getAnInstantiation() + } +} + +/** + * return value of `cds.connect.to` + */ +class ConnectTo extends ServiceInstance { + ConnectTo(){ + this = any(CdsFacade cds).getMember("connect").getMember("to").getACall() } } @@ -47,12 +44,10 @@ private class ErrorHandler extends RequestHandler { } * class SomeService extends cds.ApplicationService * ``` */ -class UserDefinedApplicationService extends ApplicationService, ClassNode { +class UserDefinedApplicationService extends ClassNode { UserDefinedApplicationService() { - exists(CdsFacade cdsFacade, PropRef cdsApplicationService | - this.getADirectSuperClass() = cdsApplicationService and - cdsApplicationService.getBase() = cdsFacade and - cdsApplicationService.getPropertyName() = "ApplicationService" + exists( ApplicationService cdsApplicationService | + this.getASuperClassNode() = cdsApplicationService.asSource() ) } } @@ -64,13 +59,10 @@ class UserDefinedApplicationService extends ApplicationService, ClassNode { * module.exports = cds.service.impl (function() { ... }) * ``` */ -class OldStyleApplicationService extends UserDefinedApplicationService, MethodCallNode { - OldStyleApplicationService() { - exists(PropRef cdsService, CdsFacade cds | - this.getMethodName() = "impl" and - this.getReceiver() = cdsService and - cdsService.getPropertyName() = "service" and - cdsService.getBase() = cds +class OldStyleUserDefinedApplicationService extends MethodCallNode { + OldStyleUserDefinedApplicationService() { + exists(CdsFacade cds | + this = cds.getMember("service").getMember("impl").getACall() ) } } @@ -81,42 +73,52 @@ class OldStyleApplicationService extends UserDefinedApplicationService, MethodCa * cds.serve('./srv/cat-service') .with ((srv) => { * srv.on ('READ','Books', (req) => req.reply([...])) * }) + * ``` + * + * TODO expand this to capture request handlers registered inside the function */ -class WithCallParameter extends Service, ParameterNode { +class WithCallParameter extends Node { WithCallParameter() { - exists(MethodCallNode withCall, MethodCallNode serveCall, CdsFacade cds | + exists(MethodCallNode withCall, ServiceInstance svc | withCall.getArgument(0) = this and withCall.getMethodName() = "with" and - withCall.getReceiver() = serveCall and - serveCall.getMethodName() = "serve" and - serveCall.getReceiver() = cds + withCall.getReceiver() = svc ) } } -class RemoteService extends Service, ClassNode { } - -class MessagingService extends Service, ClassNode { } - -class DatabaseService extends Service, ClassNode { } - -class SqlService extends Service, ClassNode { } - /** * Parameter of request handler of `srv.on`: * ```js - * srv.on ('READ','Books', (req) => req.reply([...])) + * this.on ('READ','Books', (req) => req.reply([...])) * ``` + * **this currently only describes event handlers registered in custom service definitions** + * not sure how else to know which service is registering the handler */ -class Request extends ValueNode, ParameterNode { - Request() { - exists(MethodCallNode srvOn, Service srv, FunctionNode handler | - srvOn.getMethodName() = "on" and - srvOn.getReceiver() = srv and - srvOn.getLastArgument() = handler and - handler.getLastParameter() = this +class RequestSource extends ValueNode, ParameterNode { + UserDefinedApplicationService svc; + RequestSource() { + // TODO : consider - do we need to actually ever know which service the handler is associated to? + exists(MethodCallNode on, FunctionNode init, FunctionNode handler | + svc.getAnInstanceMember() = init and + init.getName() = "init" + and on.getMethodName() = "on" + and on.getEnclosingFunction() = init.getAstNode() + and on.getLastArgument() = handler + and handler.getLastParameter() = this ) } + UserDefinedApplicationService getDefiningService(){ + result = svc + } + +} + + +class ApplicationService extends API::Node { + ApplicationService(){ + exists(CdsFacade c | this = c.getMember("ApplicationService")) + } } /** @@ -124,7 +126,7 @@ class Request extends ValueNode, ParameterNode { * const cds = require('@sap/cds') * ``` */ -class CdsFacade extends ModuleImportNode { - CdsFacade() { this = moduleImport("@sap/cds") } +class CdsFacade extends API::Node { + CdsFacade() { this = API::moduleImport("@sap/cds") } } } \ No newline at end of file diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll index d1e4ee2f5..7f44b768d 100644 --- a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll @@ -15,7 +15,7 @@ class CqlQueryBase extends VarRef { // Imported from `cds.ql` */ exists(CdsFacade cds, PropRef cdsDotQl | this.flow().getALocalSource() = cdsDotQl and - cdsDotQl.getBase() = cds + cdsDotQl.getBase() = cds.getInducingNode() ) } } diff --git a/javascript/frameworks/cap/test/models/cds/applicationserviceinstance/applicationserviceinstance.expected b/javascript/frameworks/cap/test/models/cds/applicationserviceinstance/applicationserviceinstance.expected new file mode 100644 index 000000000..c79d16090 --- /dev/null +++ b/javascript/frameworks/cap/test/models/cds/applicationserviceinstance/applicationserviceinstance.expected @@ -0,0 +1,6 @@ +| applicationserviceinstance.js:2:11:2:61 | new cds ... ptions) | +| applicationserviceinstance.js:3:18:3:68 | new cds ... ptions) | +| applicationserviceinstance.js:4:14:4:44 | cds.con ... rvice') | +| applicationserviceinstance.js:5:20:5:50 | cds.con ... rvice') | +| applicationserviceinstance.js:6:18:6:43 | cds.ser ... rvice') | +| applicationserviceinstance.js:7:24:7:49 | cds.ser ... rvice') | diff --git a/javascript/frameworks/cap/test/models/cds/applicationserviceinstance/applicationserviceinstance.js b/javascript/frameworks/cap/test/models/cds/applicationserviceinstance/applicationserviceinstance.js new file mode 100644 index 000000000..07e86d7bc --- /dev/null +++ b/javascript/frameworks/cap/test/models/cds/applicationserviceinstance/applicationserviceinstance.js @@ -0,0 +1,7 @@ +const cds = require("@sap/cds"); +let svc = new cds.ApplicationService ("", cds.model, options) +let svc1 = await new cds.ApplicationService ("", cds.model, options) +const svc2 = cds.connect.to ('some-service') +const svc3 = await cds.connect.to ('some-service') +const { svc5 } = cds.serve ('some-service') +const { svc4 } = await cds.serve ('some-service') diff --git a/javascript/frameworks/cap/test/models/cds/applicationserviceinstance/applicationserviceinstance.ql b/javascript/frameworks/cap/test/models/cds/applicationserviceinstance/applicationserviceinstance.ql new file mode 100644 index 000000000..ae7c7152f --- /dev/null +++ b/javascript/frameworks/cap/test/models/cds/applicationserviceinstance/applicationserviceinstance.ql @@ -0,0 +1,5 @@ +import javascript +import advanced_security.javascript.frameworks.cap.CDS + +from CDS::ServiceInstance svc +select svc \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cds/oldstyleuserdefined/oldstyleuserdefined.expected b/javascript/frameworks/cap/test/models/cds/oldstyleuserdefined/oldstyleuserdefined.expected new file mode 100644 index 000000000..f849b37d9 --- /dev/null +++ b/javascript/frameworks/cap/test/models/cds/oldstyleuserdefined/oldstyleuserdefined.expected @@ -0,0 +1 @@ +| oldstyleuserdefined.js:3:18:3:49 | cds.ser ... n(){ }) | diff --git a/javascript/frameworks/cap/test/models/cds/oldstyleuserdefined/oldstyleuserdefined.js b/javascript/frameworks/cap/test/models/cds/oldstyleuserdefined/oldstyleuserdefined.js new file mode 100644 index 000000000..f27d66ba0 --- /dev/null +++ b/javascript/frameworks/cap/test/models/cds/oldstyleuserdefined/oldstyleuserdefined.js @@ -0,0 +1,3 @@ +const cds = require("@sap/cds"); + +module.exports = cds.service.impl (function(){ }) \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cds/oldstyleuserdefined/oldstyleuserdefined.ql b/javascript/frameworks/cap/test/models/cds/oldstyleuserdefined/oldstyleuserdefined.ql new file mode 100644 index 000000000..9d3229dcb --- /dev/null +++ b/javascript/frameworks/cap/test/models/cds/oldstyleuserdefined/oldstyleuserdefined.ql @@ -0,0 +1,5 @@ +import javascript +import advanced_security.javascript.frameworks.cap.CDS + +from CDS::OldStyleUserDefinedApplicationService svc +select svc \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.expected b/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.expected new file mode 100644 index 000000000..27c8400bd --- /dev/null +++ b/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.expected @@ -0,0 +1,2 @@ +| requesthandler.js:5:42:5:44 | req | +| requesthandler.js:6:34:6:36 | req | diff --git a/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.js b/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.js new file mode 100644 index 000000000..14be37f7d --- /dev/null +++ b/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.js @@ -0,0 +1,17 @@ +const cds = require("@sap/cds"); +class BooksService extends cds.ApplicationService { + init(){ + const { Books, Authors } = this.entities + this.on ('READ',[Books,Authors], req => req.target.data) + this.on ('UPDATE',Books, req => { + let [ ID ] = req.params + return Object.assign (Books.data[ID], req.data) + }) + return super.init() + } +} +module.exports = BooksService + +cds.serve('./test-service') .with ((srv) => { + srv.on ('READ','Books', (req) => req.reply([])) //currently this handler is not detected + }) \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.ql b/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.ql new file mode 100644 index 000000000..2b9e269f9 --- /dev/null +++ b/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.ql @@ -0,0 +1,5 @@ +import javascript +import advanced_security.javascript.frameworks.cap.CDS + +from CDS::RequestSource src +select src \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cds/userdefinedservice/userdefinedservice.expected b/javascript/frameworks/cap/test/models/cds/userdefinedservice/userdefinedservice.expected new file mode 100644 index 000000000..f4f448a52 --- /dev/null +++ b/javascript/frameworks/cap/test/models/cds/userdefinedservice/userdefinedservice.expected @@ -0,0 +1 @@ +| userdefinedservice.js:3:1:7:1 | class B ... )\\n }\\n} | diff --git a/javascript/frameworks/cap/test/models/cds/userdefinedservice/userdefinedservice.js b/javascript/frameworks/cap/test/models/cds/userdefinedservice/userdefinedservice.js new file mode 100644 index 000000000..684351cf1 --- /dev/null +++ b/javascript/frameworks/cap/test/models/cds/userdefinedservice/userdefinedservice.js @@ -0,0 +1,8 @@ +const cds = require("@sap/cds"); + +class BooksService extends cds.ApplicationService { + init() { + return super.init() + } +} +module.exports = BooksService \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cds/userdefinedservice/userdefinedservice.ql b/javascript/frameworks/cap/test/models/cds/userdefinedservice/userdefinedservice.ql new file mode 100644 index 000000000..0a3adf59d --- /dev/null +++ b/javascript/frameworks/cap/test/models/cds/userdefinedservice/userdefinedservice.ql @@ -0,0 +1,5 @@ +import javascript +import advanced_security.javascript.frameworks.cap.CDS + +from CDS::UserDefinedApplicationService svc +select svc \ No newline at end of file From fa7a6bb362172a1ed93edd2774724c0805fce918 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 3 Jan 2024 12:02:56 -0500 Subject: [PATCH 53/61] Improve cds request handler model --- .../javascript/frameworks/cap/CDS.qll | 42 ++++++++++++------- .../requesthandler/requesthandler.expected | 1 + .../cds/requesthandler/requesthandler.js | 4 +- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll index fd5d9fc79..2538674b6 100644 --- a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll @@ -77,7 +77,7 @@ class OldStyleUserDefinedApplicationService extends MethodCallNode { * * TODO expand this to capture request handlers registered inside the function */ -class WithCallParameter extends Node { +class WithCallParameter extends RequestHandler { WithCallParameter() { exists(MethodCallNode withCall, ServiceInstance svc | withCall.getArgument(0) = this and @@ -87,34 +87,48 @@ class WithCallParameter extends Node { } } +/** + * Parameter of request handler of `_.on`: + * ```js + * _.on ('READ','Books', (req) => req.reply([...])) + * ``` + */ +class OnNodeParam extends ValueNode, ParameterNode { + MethodCallNode on; + OnNodeParam() { + exists(FunctionNode handler | + on.getMethodName() = "on" + and on.getLastArgument() = handler + and handler.getLastParameter() = this + ) + } + MethodCallNode getOnNode(){ + result = on + } + +} + /** * Parameter of request handler of `srv.on`: * ```js * this.on ('READ','Books', (req) => req.reply([...])) * ``` - * **this currently only describes event handlers registered in custom service definitions** * not sure how else to know which service is registering the handler */ -class RequestSource extends ValueNode, ParameterNode { - UserDefinedApplicationService svc; +class RequestSource extends OnNodeParam { RequestSource() { // TODO : consider - do we need to actually ever know which service the handler is associated to? - exists(MethodCallNode on, FunctionNode init, FunctionNode handler | + exists(UserDefinedApplicationService svc, FunctionNode init | svc.getAnInstanceMember() = init and init.getName() = "init" - and on.getMethodName() = "on" - and on.getEnclosingFunction() = init.getAstNode() - and on.getLastArgument() = handler - and handler.getLastParameter() = this + and this.getOnNode().getEnclosingFunction() = init.getAstNode() ) + or + exists(WithCallParameter pa | + this.getOnNode().getEnclosingFunction() = pa.getFunction()) } - UserDefinedApplicationService getDefiningService(){ - result = svc - } - } - class ApplicationService extends API::Node { ApplicationService(){ exists(CdsFacade c | this = c.getMember("ApplicationService")) diff --git a/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.expected b/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.expected index 27c8400bd..04bc1e540 100644 --- a/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.expected +++ b/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.expected @@ -1,2 +1,3 @@ | requesthandler.js:5:42:5:44 | req | | requesthandler.js:6:34:6:36 | req | +| requesthandler.js:16:34:16:36 | req | diff --git a/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.js b/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.js index 14be37f7d..369878a17 100644 --- a/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.js +++ b/javascript/frameworks/cap/test/models/cds/requesthandler/requesthandler.js @@ -12,6 +12,6 @@ class BooksService extends cds.ApplicationService { } module.exports = BooksService -cds.serve('./test-service') .with ((srv) => { - srv.on ('READ','Books', (req) => req.reply([])) //currently this handler is not detected +cds.serve('./test-service').with ((srv) => { + srv.on ('READ','Books', (req) => req.reply([])) }) \ No newline at end of file From eead8db9c9dc0356f73c7a1686d4d1cd2c1c620b Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Fri, 5 Jan 2024 14:17:54 -0500 Subject: [PATCH 54/61] Refactor cql test locations isolate each test type --- .../models/cql/{ => delete}/delete.expected | 0 .../test/models/cql/{ => delete}/delete.js | 0 .../test/models/cql/{ => delete}/delete.ql | 0 .../models/cql/{ => insert}/insert.expected | 0 .../test/models/cql/{ => insert}/insert.js | 0 .../test/models/cql/{ => insert}/insert.ql | 0 .../frameworks/cap/test/models/cql/select.js | 324 ----------------- .../frameworks/cap/test/models/cql/select.ql | 5 - .../models/cql/{ => select}/select.expected | 0 .../cap/test/models/cql/select/select.js | 328 ++++++++++++++++++ .../cap/test/models/cql/select/select.ql | 23 ++ .../cap/test/models/cql/select/select2.js | 4 + .../models/cql/{ => update}/update.expected | 0 .../test/models/cql/{ => update}/update.js | 0 .../test/models/cql/{ => update}/update.ql | 0 .../models/cql/{ => upsert}/upsert.expected | 0 .../test/models/cql/{ => upsert}/upsert.js | 0 .../test/models/cql/{ => upsert}/upsert.ql | 0 18 files changed, 355 insertions(+), 329 deletions(-) rename javascript/frameworks/cap/test/models/cql/{ => delete}/delete.expected (100%) rename javascript/frameworks/cap/test/models/cql/{ => delete}/delete.js (100%) rename javascript/frameworks/cap/test/models/cql/{ => delete}/delete.ql (100%) rename javascript/frameworks/cap/test/models/cql/{ => insert}/insert.expected (100%) rename javascript/frameworks/cap/test/models/cql/{ => insert}/insert.js (100%) rename javascript/frameworks/cap/test/models/cql/{ => insert}/insert.ql (100%) delete mode 100644 javascript/frameworks/cap/test/models/cql/select.js delete mode 100644 javascript/frameworks/cap/test/models/cql/select.ql rename javascript/frameworks/cap/test/models/cql/{ => select}/select.expected (100%) create mode 100644 javascript/frameworks/cap/test/models/cql/select/select.js create mode 100644 javascript/frameworks/cap/test/models/cql/select/select.ql create mode 100644 javascript/frameworks/cap/test/models/cql/select/select2.js rename javascript/frameworks/cap/test/models/cql/{ => update}/update.expected (100%) rename javascript/frameworks/cap/test/models/cql/{ => update}/update.js (100%) rename javascript/frameworks/cap/test/models/cql/{ => update}/update.ql (100%) rename javascript/frameworks/cap/test/models/cql/{ => upsert}/upsert.expected (100%) rename javascript/frameworks/cap/test/models/cql/{ => upsert}/upsert.js (100%) rename javascript/frameworks/cap/test/models/cql/{ => upsert}/upsert.ql (100%) diff --git a/javascript/frameworks/cap/test/models/cql/delete.expected b/javascript/frameworks/cap/test/models/cql/delete/delete.expected similarity index 100% rename from javascript/frameworks/cap/test/models/cql/delete.expected rename to javascript/frameworks/cap/test/models/cql/delete/delete.expected diff --git a/javascript/frameworks/cap/test/models/cql/delete.js b/javascript/frameworks/cap/test/models/cql/delete/delete.js similarity index 100% rename from javascript/frameworks/cap/test/models/cql/delete.js rename to javascript/frameworks/cap/test/models/cql/delete/delete.js diff --git a/javascript/frameworks/cap/test/models/cql/delete.ql b/javascript/frameworks/cap/test/models/cql/delete/delete.ql similarity index 100% rename from javascript/frameworks/cap/test/models/cql/delete.ql rename to javascript/frameworks/cap/test/models/cql/delete/delete.ql diff --git a/javascript/frameworks/cap/test/models/cql/insert.expected b/javascript/frameworks/cap/test/models/cql/insert/insert.expected similarity index 100% rename from javascript/frameworks/cap/test/models/cql/insert.expected rename to javascript/frameworks/cap/test/models/cql/insert/insert.expected diff --git a/javascript/frameworks/cap/test/models/cql/insert.js b/javascript/frameworks/cap/test/models/cql/insert/insert.js similarity index 100% rename from javascript/frameworks/cap/test/models/cql/insert.js rename to javascript/frameworks/cap/test/models/cql/insert/insert.js diff --git a/javascript/frameworks/cap/test/models/cql/insert.ql b/javascript/frameworks/cap/test/models/cql/insert/insert.ql similarity index 100% rename from javascript/frameworks/cap/test/models/cql/insert.ql rename to javascript/frameworks/cap/test/models/cql/insert/insert.ql diff --git a/javascript/frameworks/cap/test/models/cql/select.js b/javascript/frameworks/cap/test/models/cql/select.js deleted file mode 100644 index 02d9bb9f2..000000000 --- a/javascript/frameworks/cap/test/models/cql/select.js +++ /dev/null @@ -1,324 +0,0 @@ -/* ========== SELECT acting as shortcut to SELECT.columns ========== */ -var select = SELECT`col1, col2`.from`Table`; -var select = SELECT`col1, col2`.from(Table); -var select = SELECT`col1, col2`.from("Table"); -var select = SELECT("col1, col2").from`Table`; -var select = SELECT("col1, col2").from(Table); -var select = SELECT("col1, col2").from("Table"); - -/* ========== SELECTs with property accesses ========== */ -var select = SELECT.one.from`Table`; -var select = SELECT.one.from(Table); -var select = SELECT.distinct.from`Table`; -var select = SELECT.distinct.from(Table); -var select = SELECT.one.two.three.distinct.from(Table); -var select = SELECT.one.two.three.distinct.from`Table`; - -/* ========== SELECTs with method calls ========== */ -// .columns() -var select = SELECT.from`Table`.columns`col1, col2`; -var select = SELECT.from`Table`.columns((data) => { - data.col1, data.col2; -}); -var select = SELECT.from`Table`.columns`{ col1, col2 as col2Alias }`; -var select = SELECT.from`Table`.columns("col1", "col2 as col2Alias"); -var select = SELECT.from`Table`.columns([ - "col1", - { ref: ["col2", "prop"], as: "property" }, -]); -var select = SELECT.from`Table`.columns("col1", { - ref: ["col2", "prop"], - as: "property", -}); - -var select = SELECT.from(Table).columns`col1, col2`; -var select = SELECT.from(Table).columns((data) => { - data.col1, data.col2; -}); -var select = SELECT.from(Table).columns`{ col1, col2 as col2Alias }`; -var select = SELECT.from(Table).columns("col1", "col2 as col2Alias"); -var select = SELECT.from(Table).columns([ - "col1", - { ref: ["col2", "prop"], as: "property" }, -]); -var select = SELECT.from(Table).columns("col1", { - ref: ["col2", "prop"], - as: "property", -}); - -// .where() -var select = SELECT.from`Table`.where({ col1: "*" }); -var select = SELECT.from`Table`.where("col1='*'"); -var select = SELECT.from`Table`.where`col1=${"*"}`; -var select = SELECT.from`Table`.where("col1=", "*"); -var select = SELECT.from`Table`.where`col = ${"*"}`; -var select = SELECT.from`Table`.where("col1 in ('*', 10)"); -var select = SELECT.from`Table`.where`col1 in ${[("*", 10)]}`; -var select = SELECT.from`Table`.where({ col1: 10, and: { col2: 11 } }); - -var select = SELECT.from(Table).where({ col1: "*" }); -var select = SELECT.from(Table).where("col1='*'"); -var select = SELECT.from(Table).where`col1=${"*"}`; -var select = SELECT.from(Table).where("col1=", "*"); -var select = SELECT.from(Table).where`col = ${"*"}`; -var select = SELECT.from(Table).where("col1 in ('*', 10)"); -var select = SELECT.from(Table).where`col1 in ${[("*", 10)]}`; -var select = SELECT.from(Table).where({ col1: 10, and: { col2: 11 } }); - -// .groupBy() -var select = SELECT.from`Table`.groupBy("col1", "col2"); -var select = SELECT.from`Table`.groupBy`col1, col2`; -var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2"); -var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`; -var select = SELECT.from`Table`.groupBy( - { ref: ["col1", "prop1"] }, - { ref: ["col2", "prop2"] } -); - -var select = SELECT.from(Table).groupBy("col1", "col2"); -var select = SELECT.from(Table).groupBy`col1, col2`; -var select = SELECT.from(Table).groupBy("col1.prop1", "col2.prop2"); -var select = SELECT.from(Table).groupBy`col1.prop1, col2.prop2`; -var select = SELECT.from(Table).groupBy( - { ref: ["col1", "prop1"] }, - { ref: ["col2", "prop2"] } -); - -// .having() -var select = SELECT.from`Table`.having({ col1: "*" }); -var select = SELECT.from`Table`.having("col1='*'"); -var select = SELECT.from`Table`.having`col1=${"*"}`; -var select = SELECT.from`Table`.having("col1=", "*"); -var select = SELECT.from`Table`.having`col = ${"*"}`; -var select = SELECT.from`Table`.having("col1 in ('*', 10)"); -var select = SELECT.from`Table`.having`col1 in ${[("*", 10)]}`; -var select = SELECT.from`Table`.having({ col1: 10, and: { col2: 11 } }); - -var select = SELECT.from(Table).having({ col1: "*" }); -var select = SELECT.from(Table).having("col1='*'"); -var select = SELECT.from(Table).having`col1=${"*"}`; -var select = SELECT.from(Table).having("col1=", "*"); -var select = SELECT.from(Table).having`col = ${"*"}`; -var select = SELECT.from(Table).having("col1 in ('*', 10)"); -var select = SELECT.from(Table).having`col1 in ${[("*", 10)]}`; -var select = SELECT.from(Table).having({ col1: 10, and: { col2: 11 } }); - -var select = SELECT.from`Table`.groupBy("col1", "col2").having({ col1: "*" }); -var select = SELECT.from`Table`.groupBy("col1", "col2").having("col1='*'"); -var select = SELECT.from`Table`.groupBy("col1", "col2").having`col1=${"*"}`; -var select = SELECT.from`Table`.groupBy("col1", "col2").having("col1=", "*"); -var select = SELECT.from`Table`.groupBy("col1", "col2").having`col = ${"*"}`; -var select = SELECT.from`Table` - .groupBy("col1", "col2") - .having("col1 in ('*', 10)"); -var select = SELECT.from`Table`.groupBy("col1", "col2").having`col1 in ${[ - ("*", 10), -]}`; -var select = SELECT.from`Table` - .groupBy("col1", "col2") - .having({ col1: 10, and: { col2: 11 } }); - -var select = SELECT.from(Table).groupBy("col1", "col2").having({ col1: "*" }); -var select = SELECT.from(Table).groupBy("col1", "col2").having("col1='*'"); -var select = SELECT.from(Table).groupBy("col1", "col2").having`col1=${"*"}`; -var select = SELECT.from(Table).groupBy("col1", "col2").having("col1=", "*"); -var select = SELECT.from(Table).groupBy("col1", "col2").having`col = ${"*"}`; -var select = SELECT.from(Table) - .groupBy("col1", "col2") - .having("col1 in ('*', 10)"); -var select = SELECT.from(Table).groupBy("col1", "col2").having`col1 in ${[ - ("*", 10), -]}`; -var select = SELECT.from(Table) - .groupBy("col1", "col2") - .having({ col1: 10, and: { col2: 11 } }); - -var select = SELECT.from`Table`.groupBy`col1, col2`.having({ col1: "*" }); -var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1='*'"); -var select = SELECT.from`Table`.groupBy`col1, col2`.having`col1=${"*"}`; -var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1=", "*"); -var select = SELECT.from`Table`.groupBy`col1, col2`.having`col = ${"*"}`; -var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1 in ('*', 10)"); -var select = SELECT.from`Table`.groupBy`col1, col2`.having`col1 in ${[ - ("*", 10), -]}`; -var select = SELECT.from`Table`.groupBy`col1, col2`.having({ - col1: 10, - and: { col2: 11 }, -}); - -var select = SELECT.from`Table`.groupBy(col1, col2).having({ col1: "*" }); -var select = SELECT.from`Table`.groupBy(col1, col2).having("col1='*'"); -var select = SELECT.from`Table`.groupBy(col1, col2).having`col1=${"*"}`; -var select = SELECT.from`Table`.groupBy(col1, col2).having("col1=", "*"); -var select = SELECT.from`Table`.groupBy(col1, col2).having`col = ${"*"}`; -var select = SELECT.from`Table`.groupBy(col1, col2).having("col1 in ('*', 10)"); -var select = SELECT.from`Table`.groupBy(col1, col2).having`col1 in ${[ - ("*", 10), -]}`; -var select = SELECT.from`Table`.groupBy(col1, col2).having({ - col1: 10, - and: { col2: 11 }, -}); - -var select = SELECT.from`Table` - .groupBy("col1.prop1", "col2.prop2") - .having({ col1: "*" }); -var select = SELECT.from`Table` - .groupBy("col1.prop1", "col2.prop2") - .having("col1='*'"); -var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") - .having`col1=${"*"}`; -var select = SELECT.from`Table` - .groupBy("col1.prop1", "col2.prop2") - .having("col1=", "*"); -var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") - .having`col = ${"*"}`; -var select = SELECT.from`Table` - .groupBy("col1.prop1", "col2.prop2") - .having("col1 in ('*', 10)"); -var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") - .having`col1 in ${[("*", 10)]}`; -var select = SELECT.from`Table` - .groupBy("col1.prop1", "col2.prop2") - .having({ col1: 10, and: { col2: 11 } }); - -var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having({ - col1: "*", -}); -var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( - "col1='*'" -); -var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` - .having`col1=${"*"}`; -var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( - "col1=", - "*" -); -var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` - .having`col = ${"*"}`; -var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( - "col1 in ('*', 10)" -); -var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` - .having`col1 in ${[("*", 10)]}`; -var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having({ - col1: 10, - and: { col2: 11 }, -}); - -var select = SELECT.from`Table` - .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) - .having({ col1: "*" }); -var select = SELECT.from`Table` - .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) - .having("col1='*'"); -var select = SELECT.from`Table`.groupBy( - { ref: ["col1", "prop1"] }, - { ref: ["col2", "prop2"] } -).having`col1=${"*"}`; -var select = SELECT.from`Table` - .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) - .having("col1=", "*"); -var select = SELECT.from`Table`.groupBy( - { ref: ["col1", "prop1"] }, - { ref: ["col2", "prop2"] } -).having`col = ${"*"}`; -var select = SELECT.from`Table` - .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) - .having("col1 in ('*', 10)"); -var select = SELECT.from`Table`.groupBy( - { ref: ["col1", "prop1"] }, - { ref: ["col2", "prop2"] } -).having`col1 in ${[("*", 10)]}`; -var select = SELECT.from`Table` - .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) - .having({ col1: 10, and: { col2: 11 } }); - -// .orderBy() -var select = SELECT.from`Table`.orderBy`col1.prop1, col2.prop2`; -var select = SELECT.from`Table`.orderBy`col1 asc, col2.prop2`; -var select = SELECT.from`Table`.orderBy`col1.prop1, col2 asc`; -var select = SELECT.from`Table`.orderBy`col1 asc col2 asc`; -var select = SELECT.from`Table`.orderBy`col1.prop1, col2.prop2`; -var select = SELECT.from`Table`.orderBy`col1 desc, col2.prop2`; -var select = SELECT.from`Table`.orderBy`col1.prop1, col2 desc`; -var select = SELECT.from`Table`.orderBy`col1 desc col2 desc`; - -var select = SELECT.from(Table).orderBy`col1.prop1, col2.prop2`; -var select = SELECT.from(Table).orderBy`col1 asc, col2.prop2`; -var select = SELECT.from(Table).orderBy`col1.prop1, col2 asc`; -var select = SELECT.from(Table).orderBy`col1 asc col2 asc`; -var select = SELECT.from(Table).orderBy`col1.prop1, col2.prop2`; -var select = SELECT.from(Table).orderBy`col1 desc, col2.prop2`; -var select = SELECT.from(Table).orderBy`col1.prop1, col2 desc`; -var select = SELECT.from(Table).orderBy`col1 desc col2 desc`; - -// .limit() -var select = SELECT.from`Table`.limit(10); -var select = SELECT.from`Table`.limit`${10}`; -var select = SELECT.from`Table`.limit(10, 20); -var select = SELECT.from`Table`.limit({ val: 10 }); -var select = SELECT.from`Table`.limit({ val: 10 }, { val: 20 }); -var select = SELECT.from`Table`.limit({ ref: ["limitVal"] }); -var select = SELECT.from`Table`.limit({ - ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], -}); - -var select = SELECT.from(Table).limit(10); -var select = SELECT.from(Table).limit`${10}`; -var select = SELECT.from(Table).limit(10, 20); -var select = SELECT.from(Table).limit({ val: 10 }); -var select = SELECT.from(Table).limit({ val: 10 }, { val: 20 }); -var select = SELECT.from(Table).limit({ ref: ["limitVal"] }); -var select = SELECT.from(Table).limit({ - ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], -}); - -// .forUpdate() -var select = SELECT.from`Table`.groupBy`col1, col2` - .having`col = ${"*"}`.forUpdate(); - -// .forShareLock() -var select = SELECT.from`Table`.groupBy`col1, col2` - .having`col = ${"*"}`.forShareLock(); - -/* ========== SELECTS with property access and method calls ========== */ -var select = SELECT.distinct.from`Table`.where`col1 in ${[("*", 10)]}`.groupBy( - "col1", - "col2" -).having`col1 in ${[("*", 10)]}`.limit({ - ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], -}).orderBy`col1 desc, col2.prop2`.forShareLock(); - -/* ========== CQL tagged function ========== */ -CQL`SELECT col1, col2, col3 from Table`; - -/* ========== JSON literal queries ========== */ - -var select = { - SELECT: { - from: { ref: ["Bar"] }, - }, -}; - -var select = { - SELECT: { - one: true, - columns: [{ ref: ["Foo"] }, { ref: ["Boo"] }, { ref: ["Moo"] }], - from: { ref: ["Bar"] }, - }, -}; - -var select = { - SELECT: { - distinct: true, - columns: [{ ref: ["Foo"] }, { ref: ["Boo"] }, { ref: ["Moo"] }], - from: { ref: ["Bar"] }, - limit: { - rows: { val: 7 }, - }, - where: [{ ref: ["col1"] }, ">", { val: 2 }], - groupBy: [{ ref: ["col1"] }, { ref: ["col2", "prop2"] }], - }, -}; diff --git a/javascript/frameworks/cap/test/models/cql/select.ql b/javascript/frameworks/cap/test/models/cql/select.ql deleted file mode 100644 index 9f9d0d1fd..000000000 --- a/javascript/frameworks/cap/test/models/cql/select.ql +++ /dev/null @@ -1,5 +0,0 @@ -import javascript -import advanced_security.javascript.frameworks.cap.CQL - -from CQL::CqlSelectExpr s -select s.getLocation(), s \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cql/select.expected b/javascript/frameworks/cap/test/models/cql/select/select.expected similarity index 100% rename from javascript/frameworks/cap/test/models/cql/select.expected rename to javascript/frameworks/cap/test/models/cql/select/select.expected diff --git a/javascript/frameworks/cap/test/models/cql/select/select.js b/javascript/frameworks/cap/test/models/cql/select/select.js new file mode 100644 index 000000000..b2cfcc99e --- /dev/null +++ b/javascript/frameworks/cap/test/models/cql/select/select.js @@ -0,0 +1,328 @@ +// /* ========== SELECT acting as shortcut to SELECT.columns ========== */ +// var select = SELECT`col1, col2`.from`Table`; +// var select = SELECT`col1, col2`.from(Table); +// var select = SELECT`col1, col2`.from("Table"); +// var select = SELECT("col1, col2").from`Table`; +// var select = SELECT("col1, col2").from(Table); +// var select = SELECT("col1, col2").from("Table"); + +// /* ========== SELECTs with property accesses ========== */ +// var select = SELECT.one.from`Table`; +// var select = SELECT.one.from(Table); +// var select = SELECT.distinct.from`Table`; +// var select = SELECT.distinct.from(Table); +// var select = SELECT.one.two.three.distinct.from(Table); +// var select = SELECT.one.two.three.distinct.from`Table`; + +// /* ========== SELECTs with method calls ========== */ +// // .columns() +// var select = SELECT.from`Table`.columns`col1, col2`; +// var select = SELECT.from`Table`.columns((data) => { +// data.col1, data.col2; +// }); +// var select = SELECT.from`Table`.columns`{ col1, col2 as col2Alias }`; +// var select = SELECT.from`Table`.columns("col1", "col2 as col2Alias"); +// var select = SELECT.from`Table`.columns([ +// "col1", +// { ref: ["col2", "prop"], as: "property" }, +// ]); +// var select = SELECT.from`Table`.columns("col1", { +// ref: ["col2", "prop"], +// as: "property", +// }); + +// var select = SELECT.from(Table).columns`col1, col2`; +// var select = SELECT.from(Table).columns((data) => { +// data.col1, data.col2; +// }); +// var select = SELECT.from(Table).columns`{ col1, col2 as col2Alias }`; +// var select = SELECT.from(Table).columns("col1", "col2 as col2Alias"); +// var select = SELECT.from(Table).columns([ +// "col1", +// { ref: ["col2", "prop"], as: "property" }, +// ]); +// var select = SELECT.from(Table).columns("col1", { +// ref: ["col2", "prop"], +// as: "property", +// }); + +// // .where() +// var select = SELECT.from`Table`.where({ col1: "*" }); +// var select = SELECT.from`Table`.where("col1='*'"); +// var select = SELECT.from`Table`.where`col1=${"*"}`; +// var select = SELECT.from`Table`.where("col1=", "*"); +// var select = SELECT.from`Table`.where`col = ${"*"}`; +// var select = SELECT.from`Table`.where("col1 in ('*', 10)"); +// var select = SELECT.from`Table`.where`col1 in ${[("*", 10)]}`; +// var select = SELECT.from`Table`.where({ col1: 10, and: { col2: 11 } }); + +// var select = SELECT.from(Table).where({ col1: "*" }); +// var select = SELECT.from(Table).where("col1='*'"); +// var select = SELECT.from(Table).where`col1=${"*"}`; +// var select = SELECT.from(Table).where("col1=", "*"); +// var select = SELECT.from(Table).where`col = ${"*"}`; +// var select = SELECT.from(Table).where("col1 in ('*', 10)"); +// var select = SELECT.from(Table).where`col1 in ${[("*", 10)]}`; +// var select = SELECT.from(Table).where({ col1: 10, and: { col2: 11 } }); + +// // .groupBy() +// var select = SELECT.from`Table`.groupBy("col1", "col2"); +// var select = SELECT.from`Table`.groupBy`col1, col2`; +// var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2"); +// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`; +// var select = SELECT.from`Table`.groupBy( +// { ref: ["col1", "prop1"] }, +// { ref: ["col2", "prop2"] } +// ); + +// var select = SELECT.from(Table).groupBy("col1", "col2"); +// var select = SELECT.from(Table).groupBy`col1, col2`; +// var select = SELECT.from(Table).groupBy("col1.prop1", "col2.prop2"); +// var select = SELECT.from(Table).groupBy`col1.prop1, col2.prop2`; +// var select = SELECT.from(Table).groupBy( +// { ref: ["col1", "prop1"] }, +// { ref: ["col2", "prop2"] } +// ); + +// // .having() +// var select = SELECT.from`Table`.having({ col1: "*" }); +// var select = SELECT.from`Table`.having("col1='*'"); +// var select = SELECT.from`Table`.having`col1=${"*"}`; +// var select = SELECT.from`Table`.having("col1=", "*"); +// var select = SELECT.from`Table`.having`col = ${"*"}`; +// var select = SELECT.from`Table`.having("col1 in ('*', 10)"); +// var select = SELECT.from`Table`.having`col1 in ${[("*", 10)]}`; +// var select = SELECT.from`Table`.having({ col1: 10, and: { col2: 11 } }); + +// var select = SELECT.from(Table).having({ col1: "*" }); +// var select = SELECT.from(Table).having("col1='*'"); +// var select = SELECT.from(Table).having`col1=${"*"}`; +// var select = SELECT.from(Table).having("col1=", "*"); +// var select = SELECT.from(Table).having`col = ${"*"}`; +// var select = SELECT.from(Table).having("col1 in ('*', 10)"); +// var select = SELECT.from(Table).having`col1 in ${[("*", 10)]}`; +// var select = SELECT.from(Table).having({ col1: 10, and: { col2: 11 } }); + +// var select = SELECT.from`Table`.groupBy("col1", "col2").having({ col1: "*" }); +// var select = SELECT.from`Table`.groupBy("col1", "col2").having("col1='*'"); +// var select = SELECT.from`Table`.groupBy("col1", "col2").having`col1=${"*"}`; +// var select = SELECT.from`Table`.groupBy("col1", "col2").having("col1=", "*"); +// var select = SELECT.from`Table`.groupBy("col1", "col2").having`col = ${"*"}`; +// var select = SELECT.from`Table` +// .groupBy("col1", "col2") +// .having("col1 in ('*', 10)"); +// var select = SELECT.from`Table`.groupBy("col1", "col2").having`col1 in ${[ +// ("*", 10), +// ]}`; +// var select = SELECT.from`Table` +// .groupBy("col1", "col2") +// .having({ col1: 10, and: { col2: 11 } }); + +// var select = SELECT.from(Table).groupBy("col1", "col2").having({ col1: "*" }); +// var select = SELECT.from(Table).groupBy("col1", "col2").having("col1='*'"); +// var select = SELECT.from(Table).groupBy("col1", "col2").having`col1=${"*"}`; +// var select = SELECT.from(Table).groupBy("col1", "col2").having("col1=", "*"); +// var select = SELECT.from(Table).groupBy("col1", "col2").having`col = ${"*"}`; +// var select = SELECT.from(Table) +// .groupBy("col1", "col2") +// .having("col1 in ('*', 10)"); +// var select = SELECT.from(Table).groupBy("col1", "col2").having`col1 in ${[ +// ("*", 10), +// ]}`; +// var select = SELECT.from(Table) +// .groupBy("col1", "col2") +// .having({ col1: 10, and: { col2: 11 } }); + +// var select = SELECT.from`Table`.groupBy`col1, col2`.having({ col1: "*" }); +// var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1='*'"); +// var select = SELECT.from`Table`.groupBy`col1, col2`.having`col1=${"*"}`; +// var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1=", "*"); +// var select = SELECT.from`Table`.groupBy`col1, col2`.having`col = ${"*"}`; +// var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1 in ('*', 10)"); +// var select = SELECT.from`Table`.groupBy`col1, col2`.having`col1 in ${[ +// ("*", 10), +// ]}`; +// var select = SELECT.from`Table`.groupBy`col1, col2`.having({ +// col1: 10, +// and: { col2: 11 }, +// }); + +// var select = SELECT.from`Table`.groupBy(col1, col2).having({ col1: "*" }); +// var select = SELECT.from`Table`.groupBy(col1, col2).having("col1='*'"); +// var select = SELECT.from`Table`.groupBy(col1, col2).having`col1=${"*"}`; +// var select = SELECT.from`Table`.groupBy(col1, col2).having("col1=", "*"); +// var select = SELECT.from`Table`.groupBy(col1, col2).having`col = ${"*"}`; +// var select = SELECT.from`Table`.groupBy(col1, col2).having("col1 in ('*', 10)"); +// var select = SELECT.from`Table`.groupBy(col1, col2).having`col1 in ${[ +// ("*", 10), +// ]}`; +// var select = SELECT.from`Table`.groupBy(col1, col2).having({ +// col1: 10, +// and: { col2: 11 }, +// }); + +// var select = SELECT.from`Table` +// .groupBy("col1.prop1", "col2.prop2") +// .having({ col1: "*" }); +// var select = SELECT.from`Table` +// .groupBy("col1.prop1", "col2.prop2") +// .having("col1='*'"); +// var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") +// .having`col1=${"*"}`; +// var select = SELECT.from`Table` +// .groupBy("col1.prop1", "col2.prop2") +// .having("col1=", "*"); +// var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") +// .having`col = ${"*"}`; +// var select = SELECT.from`Table` +// .groupBy("col1.prop1", "col2.prop2") +// .having("col1 in ('*', 10)"); +// var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") +// .having`col1 in ${[("*", 10)]}`; +// var select = SELECT.from`Table` +// .groupBy("col1.prop1", "col2.prop2") +// .having({ col1: 10, and: { col2: 11 } }); + +// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having({ +// col1: "*", +// }); +// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( +// "col1='*'" +// ); +// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` +// .having`col1=${"*"}`; +// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( +// "col1=", +// "*" +// ); +// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` +// .having`col = ${"*"}`; +// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( +// "col1 in ('*', 10)" +// ); +// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` +// .having`col1 in ${[("*", 10)]}`; +// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having({ +// col1: 10, +// and: { col2: 11 }, +// }); + +// var select = SELECT.from`Table` +// .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) +// .having({ col1: "*" }); +// var select = SELECT.from`Table` +// .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) +// .having("col1='*'"); +// var select = SELECT.from`Table`.groupBy( +// { ref: ["col1", "prop1"] }, +// { ref: ["col2", "prop2"] } +// ).having`col1=${"*"}`; +// var select = SELECT.from`Table` +// .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) +// .having("col1=", "*"); +// var select = SELECT.from`Table`.groupBy( +// { ref: ["col1", "prop1"] }, +// { ref: ["col2", "prop2"] } +// ).having`col = ${"*"}`; +// var select = SELECT.from`Table` +// .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) +// .having("col1 in ('*', 10)"); +// var select = SELECT.from`Table`.groupBy( +// { ref: ["col1", "prop1"] }, +// { ref: ["col2", "prop2"] } +// ).having`col1 in ${[("*", 10)]}`; +// var select = SELECT.from`Table` +// .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) +// .having({ col1: 10, and: { col2: 11 } }); + +// // .orderBy() +// var select = SELECT.from`Table`.orderBy`col1.prop1, col2.prop2`; +// var select = SELECT.from`Table`.orderBy`col1 asc, col2.prop2`; +// var select = SELECT.from`Table`.orderBy`col1.prop1, col2 asc`; +// var select = SELECT.from`Table`.orderBy`col1 asc col2 asc`; +// var select = SELECT.from`Table`.orderBy`col1.prop1, col2.prop2`; +// var select = SELECT.from`Table`.orderBy`col1 desc, col2.prop2`; +// var select = SELECT.from`Table`.orderBy`col1.prop1, col2 desc`; +// var select = SELECT.from`Table`.orderBy`col1 desc col2 desc`; + +// var select = SELECT.from(Table).orderBy`col1.prop1, col2.prop2`; +// var select = SELECT.from(Table).orderBy`col1 asc, col2.prop2`; +// var select = SELECT.from(Table).orderBy`col1.prop1, col2 asc`; +// var select = SELECT.from(Table).orderBy`col1 asc col2 asc`; +// var select = SELECT.from(Table).orderBy`col1.prop1, col2.prop2`; +// var select = SELECT.from(Table).orderBy`col1 desc, col2.prop2`; +// var select = SELECT.from(Table).orderBy`col1.prop1, col2 desc`; +// var select = SELECT.from(Table).orderBy`col1 desc col2 desc`; + +// // .limit() +// var select = SELECT.from`Table`.limit(10); +// var select = SELECT.from`Table`.limit`${10}`; +// var select = SELECT.from`Table`.limit(10, 20); +// var select = SELECT.from`Table`.limit({ val: 10 }); +// var select = SELECT.from`Table`.limit({ val: 10 }, { val: 20 }); +// var select = SELECT.from`Table`.limit({ ref: ["limitVal"] }); +// var select = SELECT.from`Table`.limit({ +// ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], +// }); + +// var select = SELECT.from(Table).limit(10); +// var select = SELECT.from(Table).limit`${10}`; +// var select = SELECT.from(Table).limit(10, 20); +// var select = SELECT.from(Table).limit({ val: 10 }); +// var select = SELECT.from(Table).limit({ val: 10 }, { val: 20 }); +// var select = SELECT.from(Table).limit({ ref: ["limitVal"] }); +// var select = SELECT.from(Table).limit({ +// ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], +// }); + +// // .forUpdate() +// var select = SELECT.from`Table`.groupBy`col1, col2` +// .having`col = ${"*"}`.forUpdate(); + +// // .forShareLock() +// var select = SELECT.from`Table`.groupBy`col1, col2` +// .having`col = ${"*"}`.forShareLock(); + +// /* ========== SELECTS with property access and method calls ========== */ +// var select = SELECT.distinct.from`Table`.where`col1 in ${[("*", 10)]}`.groupBy( +// "col1", +// "col2" +// ).having`col1 in ${[("*", 10)]}`.limit({ +// ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], +// }).orderBy`col1 desc, col2.prop2`.forShareLock(); + +// /* ========== CQL tagged function ========== */ +// CQL`SELECT col1, col2, col3 from Table`; + +// /* ========== JSON literal queries ========== */ + +// var select = { +// SELECT: { +// from: { ref: ["Bar"] }, +// }, +// }; + +// var select = { +// SELECT: { +// one: true, +// columns: [{ ref: ["Foo"] }, { ref: ["Boo"] }, { ref: ["Moo"] }], +// from: { ref: ["Bar"] }, +// }, +// }; + +// var select = { +// SELECT: { +// distinct: true, +// columns: [{ ref: ["Foo"] }, { ref: ["Boo"] }, { ref: ["Moo"] }], +// from: { ref: ["Bar"] }, +// limit: { +// rows: { val: 7 }, +// }, +// where: [{ ref: ["col1"] }, ">", { val: 2 }], +// groupBy: [{ ref: ["col1"] }, { ref: ["col2", "prop2"] }], +// }, +// }; + +// /* ========== reflected definitions ========== */ +// const { Books } = cds.entities; +// let q1 = SELECT.from (Books) .where `ID=${201}`; \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cql/select/select.ql b/javascript/frameworks/cap/test/models/cql/select/select.ql new file mode 100644 index 000000000..fe3d87909 --- /dev/null +++ b/javascript/frameworks/cap/test/models/cql/select/select.ql @@ -0,0 +1,23 @@ +import javascript +import advanced_security.javascript.frameworks.cap.CQL +import advanced_security.javascript.frameworks.cap.CDS + +// from CQL::CqlSelectExpr s +// select s.getLocation(), s +from API::Node cds, PropRef cdsDotQL, Node v , VarRef var +where +cds = API::moduleImport("@sap/cds") and + cds.getMember("ql").asSource() = cdsDotQL + and cdsDotQL.(DataFlow::SourceNode).flowsTo+(v) + //and var.getADeclaration().getFirstControlFlowNode() = v.getAstNode().getAChild().getFirstControlFlowNode() + and var.getName() = "SELECT" + and v.getAstNode().getAChild() = var + select v, + v.getAstNode().getAChild(), + //v.getAstNode().getAChild().getFirstControlFlowNode(), + // v.getAstNode().getAChild().getAQlClass(), + var, var.getVariable()//.getADeclaration().getAQlClass(), var.getADeclaration().getFirstControlFlowNode() + +// from Variable v +// where v.getName() = "SELECT" +// select v, v.getADeclaration(), v.getADeclaration().getAQlClass() \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cql/select/select2.js b/javascript/frameworks/cap/test/models/cql/select/select2.js new file mode 100644 index 000000000..04fb9f7db --- /dev/null +++ b/javascript/frameworks/cap/test/models/cql/select/select2.js @@ -0,0 +1,4 @@ +/* ========== obtained through module ========== */ +const cds = require('@sap/cds'); +const { SELECT, INSERT, UPDATE, DELETE } = cds.ql; +var select = SELECT.one.from(Table); \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cql/update.expected b/javascript/frameworks/cap/test/models/cql/update/update.expected similarity index 100% rename from javascript/frameworks/cap/test/models/cql/update.expected rename to javascript/frameworks/cap/test/models/cql/update/update.expected diff --git a/javascript/frameworks/cap/test/models/cql/update.js b/javascript/frameworks/cap/test/models/cql/update/update.js similarity index 100% rename from javascript/frameworks/cap/test/models/cql/update.js rename to javascript/frameworks/cap/test/models/cql/update/update.js diff --git a/javascript/frameworks/cap/test/models/cql/update.ql b/javascript/frameworks/cap/test/models/cql/update/update.ql similarity index 100% rename from javascript/frameworks/cap/test/models/cql/update.ql rename to javascript/frameworks/cap/test/models/cql/update/update.ql diff --git a/javascript/frameworks/cap/test/models/cql/upsert.expected b/javascript/frameworks/cap/test/models/cql/upsert/upsert.expected similarity index 100% rename from javascript/frameworks/cap/test/models/cql/upsert.expected rename to javascript/frameworks/cap/test/models/cql/upsert/upsert.expected diff --git a/javascript/frameworks/cap/test/models/cql/upsert.js b/javascript/frameworks/cap/test/models/cql/upsert/upsert.js similarity index 100% rename from javascript/frameworks/cap/test/models/cql/upsert.js rename to javascript/frameworks/cap/test/models/cql/upsert/upsert.js diff --git a/javascript/frameworks/cap/test/models/cql/upsert.ql b/javascript/frameworks/cap/test/models/cql/upsert/upsert.ql similarity index 100% rename from javascript/frameworks/cap/test/models/cql/upsert.ql rename to javascript/frameworks/cap/test/models/cql/upsert/upsert.ql From 09334a5a1ceeaa7afaadd5e22e98200a5a52874f Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Fri, 5 Jan 2024 16:24:45 -0500 Subject: [PATCH 55/61] Fix cql query base representations for case when objects are obtained through ql member of cds module --- .../javascript/frameworks/cap/CQL.qll | 21 +- .../test/models/cql/select/select.expected | 11 +- .../cap/test/models/cql/select/select.js | 598 +++++++++--------- .../cap/test/models/cql/select/select.ql | 21 +- .../cap/test/models/cql/select/select2.js | 6 +- 5 files changed, 318 insertions(+), 339 deletions(-) diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll index 7f44b768d..2fa5202ea 100644 --- a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll @@ -5,17 +5,18 @@ import CDS::CDS module CQL { class CqlQueryBase extends VarRef { CqlQueryBase() { + exists(string name | + this.getName() = name and + name in ["SELECT", "INSERT", "DELETE", "UPDATE", "UPSERT"] and // Made available as a global variable exists(GlobalVariable queryBase | - queryBase.getName() = ["SELECT", "INSERT", "DELETE", "UPDATE", "UPSERT"] - | this = queryBase.getAReference() ) or // Imported from `cds.ql` */ - exists(CdsFacade cds, PropRef cdsDotQl | - this.flow().getALocalSource() = cdsDotQl and - cdsDotQl.getBase() = cds.getInducingNode() + exists(CdsFacade cds | + cds.getMember("ql").getMember(name).getAValueReachableFromSource().asExpr() = this + ) ) } } @@ -81,7 +82,7 @@ Expr getRootReceiver(Expr e) { result = getRootReceiver(e.(TaggedTemplateExpr).getTag()) } -newtype TCqlExpr = +newtype TCqlExprClause = TaggedTemplate(TaggedTemplateExpr tagExpr) { exists(CqlQueryBase base | base = getRootReceiver(tagExpr)) or exists(CqlQueryBaseCall call | call = getRootReceiver(tagExpr)) @@ -92,7 +93,7 @@ newtype TCqlExpr = } or ShortcutCall(CqlQueryBaseCall callExpr) -class CqlExpr extends TCqlExpr { +class CqlExpr extends TCqlExprClause { TaggedTemplateExpr asTaggedTemplate() { this = TaggedTemplate(result) } MethodCallExpr asMethodCall() { this = MethodCall(result) } @@ -201,9 +202,8 @@ class CqlSelectExpr extends CqlExpr { exists(CqlSelectBase cqlSelect | this.getCqlBase() = cqlSelect and not exists( - any(CqlExpr ancestorSelect | + CqlExpr ancestorSelect | ancestorSelect = this.getAnAncestorCqlExpr() and ancestorSelect.getCqlBase() = cqlSelect - ) ) ) or @@ -227,9 +227,8 @@ class CqlInsertExpr extends CqlExpr { exists(CqlInsertBase cqlInsert | this.getCqlBase() = cqlInsert and not exists( - any(CqlExpr ancestorInsert | + CqlExpr ancestorInsert | ancestorInsert = this.getAnAncestorCqlExpr() and ancestorInsert.getCqlBase() = cqlInsert - ) ) ) or diff --git a/javascript/frameworks/cap/test/models/cql/select/select.expected b/javascript/frameworks/cap/test/models/cql/select/select.expected index 9a7ec4963..e648ab53d 100644 --- a/javascript/frameworks/cap/test/models/cql/select/select.expected +++ b/javascript/frameworks/cap/test/models/cql/select/select.expected @@ -1,12 +1,4 @@ -| insert.js:76:36:76:73 | insert.js:76 | insert.js:76:36:76:73 | SELECT. ... , col2` | -| insert.js:77:36:77:72 | insert.js:77 | insert.js:77:36:77:72 | SELECT. ... ${"*"}` | -| insert.js:79:3:79:64 | insert.js:79 | insert.js:79:3:79:64 | SELECT. ... ${"*"}` | -| insert.js:82:38:82:75 | insert.js:82 | insert.js:82:38:82:75 | SELECT. ... , col2` | -| insert.js:83:38:83:74 | insert.js:83 | insert.js:83:38:83:74 | SELECT. ... ${"*"}` | -| insert.js:85:3:85:64 | insert.js:85 | insert.js:85:3:85:64 | SELECT. ... ${"*"}` | -| insert.js:88:36:88:73 | insert.js:88 | insert.js:88:36:88:73 | SELECT. ... , col2` | -| insert.js:89:36:89:72 | insert.js:89 | insert.js:89:36:89:72 | SELECT. ... ${"*"}` | -| insert.js:91:3:91:64 | insert.js:91 | insert.js:91:3:91:64 | SELECT. ... ${"*"}` | +| select2.js:4:14:4:35 | select2.js:4 | select2.js:4:14:4:35 | SELECT. ... (Table) | | select.js:2:14:2:43 | select.js:2 | select.js:2:14:2:43 | SELECT` ... `Table` | | select.js:3:14:3:43 | select.js:3 | select.js:3:14:3:43 | SELECT` ... (Table) | | select.js:4:14:4:45 | select.js:4 | select.js:4:14:4:45 | SELECT` ... Table") | @@ -162,3 +154,4 @@ | select.js:279:14:280:35 | select.js:279 | select.js:279:14:280:35 | SELECT. ... pdate() | | select.js:283:14:284:38 | select.js:283 | select.js:283:14:284:38 | SELECT. ... eLock() | | select.js:287:14:292:48 | select.js:287 | select.js:287:14:292:48 | SELECT. ... eLock() | +| select.js:328:10:328:47 | select.js:328 | select.js:328:10:328:47 | SELECT. ... ${201}` | diff --git a/javascript/frameworks/cap/test/models/cql/select/select.js b/javascript/frameworks/cap/test/models/cql/select/select.js index b2cfcc99e..33c5eff98 100644 --- a/javascript/frameworks/cap/test/models/cql/select/select.js +++ b/javascript/frameworks/cap/test/models/cql/select/select.js @@ -1,328 +1,328 @@ -// /* ========== SELECT acting as shortcut to SELECT.columns ========== */ -// var select = SELECT`col1, col2`.from`Table`; -// var select = SELECT`col1, col2`.from(Table); -// var select = SELECT`col1, col2`.from("Table"); -// var select = SELECT("col1, col2").from`Table`; -// var select = SELECT("col1, col2").from(Table); -// var select = SELECT("col1, col2").from("Table"); +/* ========== SELECT acting as shortcut to SELECT.columns ========== */ +var select = SELECT`col1, col2`.from`Table`; +var select = SELECT`col1, col2`.from(Table); +var select = SELECT`col1, col2`.from("Table"); +var select = SELECT("col1, col2").from`Table`; +var select = SELECT("col1, col2").from(Table); +var select = SELECT("col1, col2").from("Table"); -// /* ========== SELECTs with property accesses ========== */ -// var select = SELECT.one.from`Table`; -// var select = SELECT.one.from(Table); -// var select = SELECT.distinct.from`Table`; -// var select = SELECT.distinct.from(Table); -// var select = SELECT.one.two.three.distinct.from(Table); -// var select = SELECT.one.two.three.distinct.from`Table`; +/* ========== SELECTs with property accesses ========== */ +var select = SELECT.one.from`Table`; +var select = SELECT.one.from(Table); +var select = SELECT.distinct.from`Table`; +var select = SELECT.distinct.from(Table); +var select = SELECT.one.two.three.distinct.from(Table); +var select = SELECT.one.two.three.distinct.from`Table`; -// /* ========== SELECTs with method calls ========== */ -// // .columns() -// var select = SELECT.from`Table`.columns`col1, col2`; -// var select = SELECT.from`Table`.columns((data) => { -// data.col1, data.col2; -// }); -// var select = SELECT.from`Table`.columns`{ col1, col2 as col2Alias }`; -// var select = SELECT.from`Table`.columns("col1", "col2 as col2Alias"); -// var select = SELECT.from`Table`.columns([ -// "col1", -// { ref: ["col2", "prop"], as: "property" }, -// ]); -// var select = SELECT.from`Table`.columns("col1", { -// ref: ["col2", "prop"], -// as: "property", -// }); +/* ========== SELECTs with method calls ========== */ +// .columns() +var select = SELECT.from`Table`.columns`col1, col2`; +var select = SELECT.from`Table`.columns((data) => { + data.col1, data.col2; +}); +var select = SELECT.from`Table`.columns`{ col1, col2 as col2Alias }`; +var select = SELECT.from`Table`.columns("col1", "col2 as col2Alias"); +var select = SELECT.from`Table`.columns([ + "col1", + { ref: ["col2", "prop"], as: "property" }, +]); +var select = SELECT.from`Table`.columns("col1", { + ref: ["col2", "prop"], + as: "property", +}); -// var select = SELECT.from(Table).columns`col1, col2`; -// var select = SELECT.from(Table).columns((data) => { -// data.col1, data.col2; -// }); -// var select = SELECT.from(Table).columns`{ col1, col2 as col2Alias }`; -// var select = SELECT.from(Table).columns("col1", "col2 as col2Alias"); -// var select = SELECT.from(Table).columns([ -// "col1", -// { ref: ["col2", "prop"], as: "property" }, -// ]); -// var select = SELECT.from(Table).columns("col1", { -// ref: ["col2", "prop"], -// as: "property", -// }); +var select = SELECT.from(Table).columns`col1, col2`; +var select = SELECT.from(Table).columns((data) => { + data.col1, data.col2; +}); +var select = SELECT.from(Table).columns`{ col1, col2 as col2Alias }`; +var select = SELECT.from(Table).columns("col1", "col2 as col2Alias"); +var select = SELECT.from(Table).columns([ + "col1", + { ref: ["col2", "prop"], as: "property" }, +]); +var select = SELECT.from(Table).columns("col1", { + ref: ["col2", "prop"], + as: "property", +}); -// // .where() -// var select = SELECT.from`Table`.where({ col1: "*" }); -// var select = SELECT.from`Table`.where("col1='*'"); -// var select = SELECT.from`Table`.where`col1=${"*"}`; -// var select = SELECT.from`Table`.where("col1=", "*"); -// var select = SELECT.from`Table`.where`col = ${"*"}`; -// var select = SELECT.from`Table`.where("col1 in ('*', 10)"); -// var select = SELECT.from`Table`.where`col1 in ${[("*", 10)]}`; -// var select = SELECT.from`Table`.where({ col1: 10, and: { col2: 11 } }); +// .where() +var select = SELECT.from`Table`.where({ col1: "*" }); +var select = SELECT.from`Table`.where("col1='*'"); +var select = SELECT.from`Table`.where`col1=${"*"}`; +var select = SELECT.from`Table`.where("col1=", "*"); +var select = SELECT.from`Table`.where`col = ${"*"}`; +var select = SELECT.from`Table`.where("col1 in ('*', 10)"); +var select = SELECT.from`Table`.where`col1 in ${[("*", 10)]}`; +var select = SELECT.from`Table`.where({ col1: 10, and: { col2: 11 } }); -// var select = SELECT.from(Table).where({ col1: "*" }); -// var select = SELECT.from(Table).where("col1='*'"); -// var select = SELECT.from(Table).where`col1=${"*"}`; -// var select = SELECT.from(Table).where("col1=", "*"); -// var select = SELECT.from(Table).where`col = ${"*"}`; -// var select = SELECT.from(Table).where("col1 in ('*', 10)"); -// var select = SELECT.from(Table).where`col1 in ${[("*", 10)]}`; -// var select = SELECT.from(Table).where({ col1: 10, and: { col2: 11 } }); +var select = SELECT.from(Table).where({ col1: "*" }); +var select = SELECT.from(Table).where("col1='*'"); +var select = SELECT.from(Table).where`col1=${"*"}`; +var select = SELECT.from(Table).where("col1=", "*"); +var select = SELECT.from(Table).where`col = ${"*"}`; +var select = SELECT.from(Table).where("col1 in ('*', 10)"); +var select = SELECT.from(Table).where`col1 in ${[("*", 10)]}`; +var select = SELECT.from(Table).where({ col1: 10, and: { col2: 11 } }); -// // .groupBy() -// var select = SELECT.from`Table`.groupBy("col1", "col2"); -// var select = SELECT.from`Table`.groupBy`col1, col2`; -// var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2"); -// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`; -// var select = SELECT.from`Table`.groupBy( -// { ref: ["col1", "prop1"] }, -// { ref: ["col2", "prop2"] } -// ); +// .groupBy() +var select = SELECT.from`Table`.groupBy("col1", "col2"); +var select = SELECT.from`Table`.groupBy`col1, col2`; +var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2"); +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`; +var select = SELECT.from`Table`.groupBy( + { ref: ["col1", "prop1"] }, + { ref: ["col2", "prop2"] } +); -// var select = SELECT.from(Table).groupBy("col1", "col2"); -// var select = SELECT.from(Table).groupBy`col1, col2`; -// var select = SELECT.from(Table).groupBy("col1.prop1", "col2.prop2"); -// var select = SELECT.from(Table).groupBy`col1.prop1, col2.prop2`; -// var select = SELECT.from(Table).groupBy( -// { ref: ["col1", "prop1"] }, -// { ref: ["col2", "prop2"] } -// ); +var select = SELECT.from(Table).groupBy("col1", "col2"); +var select = SELECT.from(Table).groupBy`col1, col2`; +var select = SELECT.from(Table).groupBy("col1.prop1", "col2.prop2"); +var select = SELECT.from(Table).groupBy`col1.prop1, col2.prop2`; +var select = SELECT.from(Table).groupBy( + { ref: ["col1", "prop1"] }, + { ref: ["col2", "prop2"] } +); -// // .having() -// var select = SELECT.from`Table`.having({ col1: "*" }); -// var select = SELECT.from`Table`.having("col1='*'"); -// var select = SELECT.from`Table`.having`col1=${"*"}`; -// var select = SELECT.from`Table`.having("col1=", "*"); -// var select = SELECT.from`Table`.having`col = ${"*"}`; -// var select = SELECT.from`Table`.having("col1 in ('*', 10)"); -// var select = SELECT.from`Table`.having`col1 in ${[("*", 10)]}`; -// var select = SELECT.from`Table`.having({ col1: 10, and: { col2: 11 } }); +// .having() +var select = SELECT.from`Table`.having({ col1: "*" }); +var select = SELECT.from`Table`.having("col1='*'"); +var select = SELECT.from`Table`.having`col1=${"*"}`; +var select = SELECT.from`Table`.having("col1=", "*"); +var select = SELECT.from`Table`.having`col = ${"*"}`; +var select = SELECT.from`Table`.having("col1 in ('*', 10)"); +var select = SELECT.from`Table`.having`col1 in ${[("*", 10)]}`; +var select = SELECT.from`Table`.having({ col1: 10, and: { col2: 11 } }); -// var select = SELECT.from(Table).having({ col1: "*" }); -// var select = SELECT.from(Table).having("col1='*'"); -// var select = SELECT.from(Table).having`col1=${"*"}`; -// var select = SELECT.from(Table).having("col1=", "*"); -// var select = SELECT.from(Table).having`col = ${"*"}`; -// var select = SELECT.from(Table).having("col1 in ('*', 10)"); -// var select = SELECT.from(Table).having`col1 in ${[("*", 10)]}`; -// var select = SELECT.from(Table).having({ col1: 10, and: { col2: 11 } }); +var select = SELECT.from(Table).having({ col1: "*" }); +var select = SELECT.from(Table).having("col1='*'"); +var select = SELECT.from(Table).having`col1=${"*"}`; +var select = SELECT.from(Table).having("col1=", "*"); +var select = SELECT.from(Table).having`col = ${"*"}`; +var select = SELECT.from(Table).having("col1 in ('*', 10)"); +var select = SELECT.from(Table).having`col1 in ${[("*", 10)]}`; +var select = SELECT.from(Table).having({ col1: 10, and: { col2: 11 } }); -// var select = SELECT.from`Table`.groupBy("col1", "col2").having({ col1: "*" }); -// var select = SELECT.from`Table`.groupBy("col1", "col2").having("col1='*'"); -// var select = SELECT.from`Table`.groupBy("col1", "col2").having`col1=${"*"}`; -// var select = SELECT.from`Table`.groupBy("col1", "col2").having("col1=", "*"); -// var select = SELECT.from`Table`.groupBy("col1", "col2").having`col = ${"*"}`; -// var select = SELECT.from`Table` -// .groupBy("col1", "col2") -// .having("col1 in ('*', 10)"); -// var select = SELECT.from`Table`.groupBy("col1", "col2").having`col1 in ${[ -// ("*", 10), -// ]}`; -// var select = SELECT.from`Table` -// .groupBy("col1", "col2") -// .having({ col1: 10, and: { col2: 11 } }); +var select = SELECT.from`Table`.groupBy("col1", "col2").having({ col1: "*" }); +var select = SELECT.from`Table`.groupBy("col1", "col2").having("col1='*'"); +var select = SELECT.from`Table`.groupBy("col1", "col2").having`col1=${"*"}`; +var select = SELECT.from`Table`.groupBy("col1", "col2").having("col1=", "*"); +var select = SELECT.from`Table`.groupBy("col1", "col2").having`col = ${"*"}`; +var select = SELECT.from`Table` + .groupBy("col1", "col2") + .having("col1 in ('*', 10)"); +var select = SELECT.from`Table`.groupBy("col1", "col2").having`col1 in ${[ + ("*", 10), +]}`; +var select = SELECT.from`Table` + .groupBy("col1", "col2") + .having({ col1: 10, and: { col2: 11 } }); -// var select = SELECT.from(Table).groupBy("col1", "col2").having({ col1: "*" }); -// var select = SELECT.from(Table).groupBy("col1", "col2").having("col1='*'"); -// var select = SELECT.from(Table).groupBy("col1", "col2").having`col1=${"*"}`; -// var select = SELECT.from(Table).groupBy("col1", "col2").having("col1=", "*"); -// var select = SELECT.from(Table).groupBy("col1", "col2").having`col = ${"*"}`; -// var select = SELECT.from(Table) -// .groupBy("col1", "col2") -// .having("col1 in ('*', 10)"); -// var select = SELECT.from(Table).groupBy("col1", "col2").having`col1 in ${[ -// ("*", 10), -// ]}`; -// var select = SELECT.from(Table) -// .groupBy("col1", "col2") -// .having({ col1: 10, and: { col2: 11 } }); +var select = SELECT.from(Table).groupBy("col1", "col2").having({ col1: "*" }); +var select = SELECT.from(Table).groupBy("col1", "col2").having("col1='*'"); +var select = SELECT.from(Table).groupBy("col1", "col2").having`col1=${"*"}`; +var select = SELECT.from(Table).groupBy("col1", "col2").having("col1=", "*"); +var select = SELECT.from(Table).groupBy("col1", "col2").having`col = ${"*"}`; +var select = SELECT.from(Table) + .groupBy("col1", "col2") + .having("col1 in ('*', 10)"); +var select = SELECT.from(Table).groupBy("col1", "col2").having`col1 in ${[ + ("*", 10), +]}`; +var select = SELECT.from(Table) + .groupBy("col1", "col2") + .having({ col1: 10, and: { col2: 11 } }); -// var select = SELECT.from`Table`.groupBy`col1, col2`.having({ col1: "*" }); -// var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1='*'"); -// var select = SELECT.from`Table`.groupBy`col1, col2`.having`col1=${"*"}`; -// var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1=", "*"); -// var select = SELECT.from`Table`.groupBy`col1, col2`.having`col = ${"*"}`; -// var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1 in ('*', 10)"); -// var select = SELECT.from`Table`.groupBy`col1, col2`.having`col1 in ${[ -// ("*", 10), -// ]}`; -// var select = SELECT.from`Table`.groupBy`col1, col2`.having({ -// col1: 10, -// and: { col2: 11 }, -// }); +var select = SELECT.from`Table`.groupBy`col1, col2`.having({ col1: "*" }); +var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1='*'"); +var select = SELECT.from`Table`.groupBy`col1, col2`.having`col1=${"*"}`; +var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1=", "*"); +var select = SELECT.from`Table`.groupBy`col1, col2`.having`col = ${"*"}`; +var select = SELECT.from`Table`.groupBy`col1, col2`.having("col1 in ('*', 10)"); +var select = SELECT.from`Table`.groupBy`col1, col2`.having`col1 in ${[ + ("*", 10), +]}`; +var select = SELECT.from`Table`.groupBy`col1, col2`.having({ + col1: 10, + and: { col2: 11 }, +}); -// var select = SELECT.from`Table`.groupBy(col1, col2).having({ col1: "*" }); -// var select = SELECT.from`Table`.groupBy(col1, col2).having("col1='*'"); -// var select = SELECT.from`Table`.groupBy(col1, col2).having`col1=${"*"}`; -// var select = SELECT.from`Table`.groupBy(col1, col2).having("col1=", "*"); -// var select = SELECT.from`Table`.groupBy(col1, col2).having`col = ${"*"}`; -// var select = SELECT.from`Table`.groupBy(col1, col2).having("col1 in ('*', 10)"); -// var select = SELECT.from`Table`.groupBy(col1, col2).having`col1 in ${[ -// ("*", 10), -// ]}`; -// var select = SELECT.from`Table`.groupBy(col1, col2).having({ -// col1: 10, -// and: { col2: 11 }, -// }); +var select = SELECT.from`Table`.groupBy(col1, col2).having({ col1: "*" }); +var select = SELECT.from`Table`.groupBy(col1, col2).having("col1='*'"); +var select = SELECT.from`Table`.groupBy(col1, col2).having`col1=${"*"}`; +var select = SELECT.from`Table`.groupBy(col1, col2).having("col1=", "*"); +var select = SELECT.from`Table`.groupBy(col1, col2).having`col = ${"*"}`; +var select = SELECT.from`Table`.groupBy(col1, col2).having("col1 in ('*', 10)"); +var select = SELECT.from`Table`.groupBy(col1, col2).having`col1 in ${[ + ("*", 10), +]}`; +var select = SELECT.from`Table`.groupBy(col1, col2).having({ + col1: 10, + and: { col2: 11 }, +}); -// var select = SELECT.from`Table` -// .groupBy("col1.prop1", "col2.prop2") -// .having({ col1: "*" }); -// var select = SELECT.from`Table` -// .groupBy("col1.prop1", "col2.prop2") -// .having("col1='*'"); -// var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") -// .having`col1=${"*"}`; -// var select = SELECT.from`Table` -// .groupBy("col1.prop1", "col2.prop2") -// .having("col1=", "*"); -// var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") -// .having`col = ${"*"}`; -// var select = SELECT.from`Table` -// .groupBy("col1.prop1", "col2.prop2") -// .having("col1 in ('*', 10)"); -// var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") -// .having`col1 in ${[("*", 10)]}`; -// var select = SELECT.from`Table` -// .groupBy("col1.prop1", "col2.prop2") -// .having({ col1: 10, and: { col2: 11 } }); +var select = SELECT.from`Table` + .groupBy("col1.prop1", "col2.prop2") + .having({ col1: "*" }); +var select = SELECT.from`Table` + .groupBy("col1.prop1", "col2.prop2") + .having("col1='*'"); +var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") + .having`col1=${"*"}`; +var select = SELECT.from`Table` + .groupBy("col1.prop1", "col2.prop2") + .having("col1=", "*"); +var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") + .having`col = ${"*"}`; +var select = SELECT.from`Table` + .groupBy("col1.prop1", "col2.prop2") + .having("col1 in ('*', 10)"); +var select = SELECT.from`Table`.groupBy("col1.prop1", "col2.prop2") + .having`col1 in ${[("*", 10)]}`; +var select = SELECT.from`Table` + .groupBy("col1.prop1", "col2.prop2") + .having({ col1: 10, and: { col2: 11 } }); -// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having({ -// col1: "*", -// }); -// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( -// "col1='*'" -// ); -// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` -// .having`col1=${"*"}`; -// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( -// "col1=", -// "*" -// ); -// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` -// .having`col = ${"*"}`; -// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( -// "col1 in ('*', 10)" -// ); -// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` -// .having`col1 in ${[("*", 10)]}`; -// var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having({ -// col1: 10, -// and: { col2: 11 }, -// }); +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having({ + col1: "*", +}); +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( + "col1='*'" +); +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` + .having`col1=${"*"}`; +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( + "col1=", + "*" +); +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` + .having`col = ${"*"}`; +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having( + "col1 in ('*', 10)" +); +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2` + .having`col1 in ${[("*", 10)]}`; +var select = SELECT.from`Table`.groupBy`col1.prop1, col2.prop2`.having({ + col1: 10, + and: { col2: 11 }, +}); -// var select = SELECT.from`Table` -// .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) -// .having({ col1: "*" }); -// var select = SELECT.from`Table` -// .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) -// .having("col1='*'"); -// var select = SELECT.from`Table`.groupBy( -// { ref: ["col1", "prop1"] }, -// { ref: ["col2", "prop2"] } -// ).having`col1=${"*"}`; -// var select = SELECT.from`Table` -// .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) -// .having("col1=", "*"); -// var select = SELECT.from`Table`.groupBy( -// { ref: ["col1", "prop1"] }, -// { ref: ["col2", "prop2"] } -// ).having`col = ${"*"}`; -// var select = SELECT.from`Table` -// .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) -// .having("col1 in ('*', 10)"); -// var select = SELECT.from`Table`.groupBy( -// { ref: ["col1", "prop1"] }, -// { ref: ["col2", "prop2"] } -// ).having`col1 in ${[("*", 10)]}`; -// var select = SELECT.from`Table` -// .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) -// .having({ col1: 10, and: { col2: 11 } }); +var select = SELECT.from`Table` + .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) + .having({ col1: "*" }); +var select = SELECT.from`Table` + .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) + .having("col1='*'"); +var select = SELECT.from`Table`.groupBy( + { ref: ["col1", "prop1"] }, + { ref: ["col2", "prop2"] } +).having`col1=${"*"}`; +var select = SELECT.from`Table` + .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) + .having("col1=", "*"); +var select = SELECT.from`Table`.groupBy( + { ref: ["col1", "prop1"] }, + { ref: ["col2", "prop2"] } +).having`col = ${"*"}`; +var select = SELECT.from`Table` + .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) + .having("col1 in ('*', 10)"); +var select = SELECT.from`Table`.groupBy( + { ref: ["col1", "prop1"] }, + { ref: ["col2", "prop2"] } +).having`col1 in ${[("*", 10)]}`; +var select = SELECT.from`Table` + .groupBy({ ref: ["col1", "prop1"] }, { ref: ["col2", "prop2"] }) + .having({ col1: 10, and: { col2: 11 } }); -// // .orderBy() -// var select = SELECT.from`Table`.orderBy`col1.prop1, col2.prop2`; -// var select = SELECT.from`Table`.orderBy`col1 asc, col2.prop2`; -// var select = SELECT.from`Table`.orderBy`col1.prop1, col2 asc`; -// var select = SELECT.from`Table`.orderBy`col1 asc col2 asc`; -// var select = SELECT.from`Table`.orderBy`col1.prop1, col2.prop2`; -// var select = SELECT.from`Table`.orderBy`col1 desc, col2.prop2`; -// var select = SELECT.from`Table`.orderBy`col1.prop1, col2 desc`; -// var select = SELECT.from`Table`.orderBy`col1 desc col2 desc`; +// .orderBy() +var select = SELECT.from`Table`.orderBy`col1.prop1, col2.prop2`; +var select = SELECT.from`Table`.orderBy`col1 asc, col2.prop2`; +var select = SELECT.from`Table`.orderBy`col1.prop1, col2 asc`; +var select = SELECT.from`Table`.orderBy`col1 asc col2 asc`; +var select = SELECT.from`Table`.orderBy`col1.prop1, col2.prop2`; +var select = SELECT.from`Table`.orderBy`col1 desc, col2.prop2`; +var select = SELECT.from`Table`.orderBy`col1.prop1, col2 desc`; +var select = SELECT.from`Table`.orderBy`col1 desc col2 desc`; -// var select = SELECT.from(Table).orderBy`col1.prop1, col2.prop2`; -// var select = SELECT.from(Table).orderBy`col1 asc, col2.prop2`; -// var select = SELECT.from(Table).orderBy`col1.prop1, col2 asc`; -// var select = SELECT.from(Table).orderBy`col1 asc col2 asc`; -// var select = SELECT.from(Table).orderBy`col1.prop1, col2.prop2`; -// var select = SELECT.from(Table).orderBy`col1 desc, col2.prop2`; -// var select = SELECT.from(Table).orderBy`col1.prop1, col2 desc`; -// var select = SELECT.from(Table).orderBy`col1 desc col2 desc`; +var select = SELECT.from(Table).orderBy`col1.prop1, col2.prop2`; +var select = SELECT.from(Table).orderBy`col1 asc, col2.prop2`; +var select = SELECT.from(Table).orderBy`col1.prop1, col2 asc`; +var select = SELECT.from(Table).orderBy`col1 asc col2 asc`; +var select = SELECT.from(Table).orderBy`col1.prop1, col2.prop2`; +var select = SELECT.from(Table).orderBy`col1 desc, col2.prop2`; +var select = SELECT.from(Table).orderBy`col1.prop1, col2 desc`; +var select = SELECT.from(Table).orderBy`col1 desc col2 desc`; -// // .limit() -// var select = SELECT.from`Table`.limit(10); -// var select = SELECT.from`Table`.limit`${10}`; -// var select = SELECT.from`Table`.limit(10, 20); -// var select = SELECT.from`Table`.limit({ val: 10 }); -// var select = SELECT.from`Table`.limit({ val: 10 }, { val: 20 }); -// var select = SELECT.from`Table`.limit({ ref: ["limitVal"] }); -// var select = SELECT.from`Table`.limit({ -// ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], -// }); +// .limit() +var select = SELECT.from`Table`.limit(10); +var select = SELECT.from`Table`.limit`${10}`; +var select = SELECT.from`Table`.limit(10, 20); +var select = SELECT.from`Table`.limit({ val: 10 }); +var select = SELECT.from`Table`.limit({ val: 10 }, { val: 20 }); +var select = SELECT.from`Table`.limit({ ref: ["limitVal"] }); +var select = SELECT.from`Table`.limit({ + ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], +}); -// var select = SELECT.from(Table).limit(10); -// var select = SELECT.from(Table).limit`${10}`; -// var select = SELECT.from(Table).limit(10, 20); -// var select = SELECT.from(Table).limit({ val: 10 }); -// var select = SELECT.from(Table).limit({ val: 10 }, { val: 20 }); -// var select = SELECT.from(Table).limit({ ref: ["limitVal"] }); -// var select = SELECT.from(Table).limit({ -// ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], -// }); +var select = SELECT.from(Table).limit(10); +var select = SELECT.from(Table).limit`${10}`; +var select = SELECT.from(Table).limit(10, 20); +var select = SELECT.from(Table).limit({ val: 10 }); +var select = SELECT.from(Table).limit({ val: 10 }, { val: 20 }); +var select = SELECT.from(Table).limit({ ref: ["limitVal"] }); +var select = SELECT.from(Table).limit({ + ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], +}); -// // .forUpdate() -// var select = SELECT.from`Table`.groupBy`col1, col2` -// .having`col = ${"*"}`.forUpdate(); +// .forUpdate() +var select = SELECT.from`Table`.groupBy`col1, col2` + .having`col = ${"*"}`.forUpdate(); -// // .forShareLock() -// var select = SELECT.from`Table`.groupBy`col1, col2` -// .having`col = ${"*"}`.forShareLock(); +// .forShareLock() +var select = SELECT.from`Table`.groupBy`col1, col2` + .having`col = ${"*"}`.forShareLock(); -// /* ========== SELECTS with property access and method calls ========== */ -// var select = SELECT.distinct.from`Table`.where`col1 in ${[("*", 10)]}`.groupBy( -// "col1", -// "col2" -// ).having`col1 in ${[("*", 10)]}`.limit({ -// ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], -// }).orderBy`col1 desc, col2.prop2`.forShareLock(); +/* ========== SELECTS with property access and method calls ========== */ +var select = SELECT.distinct.from`Table`.where`col1 in ${[("*", 10)]}`.groupBy( + "col1", + "col2" +).having`col1 in ${[("*", 10)]}`.limit({ + ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], +}).orderBy`col1 desc, col2.prop2`.forShareLock(); -// /* ========== CQL tagged function ========== */ -// CQL`SELECT col1, col2, col3 from Table`; +/* ========== CQL tagged function ========== */ +CQL`SELECT col1, col2, col3 from Table`; -// /* ========== JSON literal queries ========== */ +/* ========== JSON literal queries ========== */ -// var select = { -// SELECT: { -// from: { ref: ["Bar"] }, -// }, -// }; +var select = { + SELECT: { + from: { ref: ["Bar"] }, + }, +}; -// var select = { -// SELECT: { -// one: true, -// columns: [{ ref: ["Foo"] }, { ref: ["Boo"] }, { ref: ["Moo"] }], -// from: { ref: ["Bar"] }, -// }, -// }; +var select = { + SELECT: { + one: true, + columns: [{ ref: ["Foo"] }, { ref: ["Boo"] }, { ref: ["Moo"] }], + from: { ref: ["Bar"] }, + }, +}; -// var select = { -// SELECT: { -// distinct: true, -// columns: [{ ref: ["Foo"] }, { ref: ["Boo"] }, { ref: ["Moo"] }], -// from: { ref: ["Bar"] }, -// limit: { -// rows: { val: 7 }, -// }, -// where: [{ ref: ["col1"] }, ">", { val: 2 }], -// groupBy: [{ ref: ["col1"] }, { ref: ["col2", "prop2"] }], -// }, -// }; +var select = { + SELECT: { + distinct: true, + columns: [{ ref: ["Foo"] }, { ref: ["Boo"] }, { ref: ["Moo"] }], + from: { ref: ["Bar"] }, + limit: { + rows: { val: 7 }, + }, + where: [{ ref: ["col1"] }, ">", { val: 2 }], + groupBy: [{ ref: ["col1"] }, { ref: ["col2", "prop2"] }], + }, +}; -// /* ========== reflected definitions ========== */ -// const { Books } = cds.entities; -// let q1 = SELECT.from (Books) .where `ID=${201}`; \ No newline at end of file +/* ========== reflected definitions ========== */ +const { Books } = cds.entities; +let q1 = SELECT.from (Books) .where `ID=${201}`; \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cql/select/select.ql b/javascript/frameworks/cap/test/models/cql/select/select.ql index fe3d87909..4d0999490 100644 --- a/javascript/frameworks/cap/test/models/cql/select/select.ql +++ b/javascript/frameworks/cap/test/models/cql/select/select.ql @@ -2,22 +2,5 @@ import javascript import advanced_security.javascript.frameworks.cap.CQL import advanced_security.javascript.frameworks.cap.CDS -// from CQL::CqlSelectExpr s -// select s.getLocation(), s -from API::Node cds, PropRef cdsDotQL, Node v , VarRef var -where -cds = API::moduleImport("@sap/cds") and - cds.getMember("ql").asSource() = cdsDotQL - and cdsDotQL.(DataFlow::SourceNode).flowsTo+(v) - //and var.getADeclaration().getFirstControlFlowNode() = v.getAstNode().getAChild().getFirstControlFlowNode() - and var.getName() = "SELECT" - and v.getAstNode().getAChild() = var - select v, - v.getAstNode().getAChild(), - //v.getAstNode().getAChild().getFirstControlFlowNode(), - // v.getAstNode().getAChild().getAQlClass(), - var, var.getVariable()//.getADeclaration().getAQlClass(), var.getADeclaration().getFirstControlFlowNode() - -// from Variable v -// where v.getName() = "SELECT" -// select v, v.getADeclaration(), v.getADeclaration().getAQlClass() \ No newline at end of file +from CQL::CqlSelectExpr s +select s.getLocation(), s \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cql/select/select2.js b/javascript/frameworks/cap/test/models/cql/select/select2.js index 04fb9f7db..51aec5cc7 100644 --- a/javascript/frameworks/cap/test/models/cql/select/select2.js +++ b/javascript/frameworks/cap/test/models/cql/select/select2.js @@ -1,4 +1,8 @@ /* ========== obtained through module ========== */ const cds = require('@sap/cds'); const { SELECT, INSERT, UPDATE, DELETE } = cds.ql; -var select = SELECT.one.from(Table); \ No newline at end of file +var select = SELECT.one.from(Table); + +/* ========== not a use of the API ========== */ +foo.SELECT +require("SELECT")() \ No newline at end of file From 17e99e4c73373ffa63fc7684cc1ad5eff00707bc Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 10 Jan 2024 19:40:03 -0500 Subject: [PATCH 56/61] Update CQL models and add basic sql injection query and test for sql injection query --- .../javascript/frameworks/cap/CQL.qll | 207 ++++-------- .../cap/src/sqlinjection/SqlInjection.ql | 33 ++ .../test/models/cql/delete/delete.expected | 14 +- .../cap/test/models/cql/delete/delete.ql | 2 +- .../test/models/cql/insert/insert.expected | 25 ++ .../cap/test/models/cql/insert/insert.ql | 2 +- .../test/models/cql/select/select.expected | 162 +++++---- .../cap/test/models/cql/select/select.ql | 3 +- .../cap/test/models/cql/select/select2.js | 14 +- .../test/models/cql/update/update.expected | 316 +++++++++++++----- .../cap/test/models/cql/update/update.ql | 2 +- .../test/models/cql/upsert/upsert.expected | 6 + .../cap/test/models/cql/upsert/upsert.ql | 2 +- .../test/models/queries/sqlinjection.expected | 2 + .../cap/test/models/queries/sqlinjection.js | 23 ++ .../test/models/queries/sqlinjection.qlref | 1 + 16 files changed, 507 insertions(+), 307 deletions(-) create mode 100644 javascript/frameworks/cap/src/sqlinjection/SqlInjection.ql create mode 100644 javascript/frameworks/cap/test/models/queries/sqlinjection.expected create mode 100644 javascript/frameworks/cap/test/models/queries/sqlinjection.js create mode 100644 javascript/frameworks/cap/test/models/queries/sqlinjection.qlref diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll index 2fa5202ea..2a861354d 100644 --- a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll @@ -41,6 +41,9 @@ class CqlUpsertBase extends CqlQueryBase { CqlUpsertBase() { this.getName() = "UPSERT" } } +/** + * The cds-ql docs do not mention DELETE being a function acting as a shortcut to any underlying clause + */ abstract class CqlQueryBaseCall extends CallExpr { // TODO: Express "It's a global function or a local function imported from cds.ql" } @@ -53,10 +56,6 @@ class CqlInsertBaseCall extends CqlQueryBaseCall { CqlInsertBaseCall() { this.getCalleeName() = "INSERT" } } -class CqlDeleteBaseCall extends CqlQueryBaseCall { - CqlDeleteBaseCall() { this.getCalleeName() = "DELETE" } -} - class CqlUpdateBaseCall extends CqlQueryBaseCall { CqlUpdateBaseCall() { this.getCalleeName() = "UPDATE" } } @@ -82,83 +81,100 @@ Expr getRootReceiver(Expr e) { result = getRootReceiver(e.(TaggedTemplateExpr).getTag()) } -newtype TCqlExprClause = - TaggedTemplate(TaggedTemplateExpr tagExpr) { - exists(CqlQueryBase base | base = getRootReceiver(tagExpr)) or - exists(CqlQueryBaseCall call | call = getRootReceiver(tagExpr)) - } or +newtype TCqlClause = MethodCall(MethodCallExpr callExpr) { exists(CqlQueryBase base | base = getRootReceiver(callExpr)) or exists(CqlQueryBaseCall call | call = getRootReceiver(callExpr)) } or ShortcutCall(CqlQueryBaseCall callExpr) -class CqlExpr extends TCqlExprClause { - TaggedTemplateExpr asTaggedTemplate() { this = TaggedTemplate(result) } +class CqlClause extends TCqlClause { + + Expr asExpr(){ + result = this.asMethodCall() + or + result = this.asShortcutCall() + } + + Expr getArgument(){ + result = this.asMethodCall().getAnArgument() + or + result = this.asShortcutCall().getAnArgument() + } + + string getClauseName(){ + result = this.asMethodCall().getMethodName() + or + (this.asShortcutCall().getCalleeName() = "SELECT" and + result = "columns") + or + (this.asShortcutCall().getCalleeName() in ["INSERT", "UPSERT"] and + result = "entries") + or + (this.asShortcutCall().getCalleeName() = "UPDATE" and + result = "entity") + } MethodCallExpr asMethodCall() { this = MethodCall(result) } CallExpr asShortcutCall() { this = ShortcutCall(result) } /** - * Convert this `CqlExpr` into a `DotExpr`, i.e. + * Convert this `CqlClause` into a `DotExpr`, i.e. * `Get SELECT.from'Table' when given SELECT.from'Table'.wherecond`, */ DotExpr asDotExpr() { - result = this.asTaggedTemplate().getTag().(DotExpr) - or result = this.asMethodCall().getCallee().(DotExpr) } string toString() { - result = this.asTaggedTemplate().toString() or result = this.asMethodCall().toString() or result = this.asShortcutCall().toString() } Location getLocation() { - result = this.asTaggedTemplate().getLocation() or result = this.asMethodCall().getLocation() or result = this.asShortcutCall().getLocation() } CqlQueryBase getCqlBase() { - result = getRootReceiver(this.asTaggedTemplate()) or result = getRootReceiver(this.asMethodCall()) } CqlQueryBaseCall getCqlBaseCall() { - result = getRootReceiver(this.asTaggedTemplate()).(CqlQueryBaseCall) or result = getRootReceiver(this.asMethodCall()).(CqlQueryBaseCall) } - Expr getReceiver() { - result = this.asMethodCall().getReceiver() - or - result = this.asTaggedTemplate().getTag().(DotExpr).getBase() - } - /** ========== Parent relationships ========== */ Expr getParentExpr() { result = this.asMethodCall().getParentExpr() or - result = this.asTaggedTemplate().getParentExpr() or result = this.asShortcutCall().getParentExpr() } - CqlExpr getCqlParentExpr() { - result.asTaggedTemplate() = this.asMethodCall().getParentExpr() or - result.asMethodCall() = this.asTaggedTemplate().getParentExpr() or - result.asShortcutCall() = this.asShortcutCall().getParentExpr() + /** + * Possible cases for constructing a chain of clauses: + * + * (looking at the terminal clause and its possible parent types as tuples: (this, parent)) + * 1) MethodCall.MethodCall + * - example `(SELECT.from(Table), SELECT.from(Table).where("col1='*'"))` + * 2) ShortcutCall.MethodCall + * - example `(SELECT("col1, col2"), SELECT("col1, col2").from("Table"))` + * + * ShortcutCalls cannot be added to any clause chain other than the first position + * example - `SELECT("col1, col2").INSERT(col2)` is not valid + */ + CqlClause getCqlParentExpr() { + result.asMethodCall() = this.asMethodCall().getParentExpr().getParentExpr() + or + result.asMethodCall() = this.asShortcutCall().getParentExpr().getParentExpr() } Expr getAnAncestorExpr() { result = this.asMethodCall().getParentExpr+() or - result = this.asTaggedTemplate().getParentExpr+() or result = this.asShortcutCall().getParentExpr+() } - CqlExpr getAnAncestorCqlExpr() { - result.asTaggedTemplate() = this.getAnAncestorExpr() or + CqlClause getAnAncestorCqlClause() { result.asMethodCall() = this.getAnAncestorExpr() or result.asShortcutCall() = this.getAnAncestorExpr() } @@ -166,137 +182,44 @@ class CqlExpr extends TCqlExprClause { /** ========== Children relationships ========== */ Expr getAChildExpr() { result = this.asMethodCall().getAChildExpr() or - result = this.asTaggedTemplate().getAChildExpr() or result = this.asShortcutCall().getAChildExpr() } - CqlExpr getAChildCqlExpr() { - result.asTaggedTemplate() = this.asMethodCall().getAChildExpr() or - result.asMethodCall() = this.asTaggedTemplate().getAChildExpr() or - result.asShortcutCall() = this.asShortcutCall().getAChildExpr() + /** + * the same chain order logic as `getCqlParentExpr` but reversed + */ + CqlClause getAChildCqlClause() { + result.asMethodCall() = this.asMethodCall().getAChildExpr().getAChildExpr() or + result.asShortcutCall() = this.asMethodCall().getAChildExpr().getAChildExpr() } Expr getADescendantExpr() { result = this.asMethodCall().getAChildExpr+() or - result = this.asTaggedTemplate().getAChildExpr+() or result = this.asShortcutCall().getAChildExpr+() } - CqlExpr getADescendantCqlExpr() { - result.asTaggedTemplate() = this.getADescendantExpr() or + CqlClause getADescendantCqlClause() { result.asMethodCall() = this.getADescendantExpr() or result.asShortcutCall() = this.getADescendantExpr() } /** - * Matches the given `CqlExpr` to its method/property name, nested at arbitrary depth. + * Matches the given `CqlClause` to its method/property name, nested at arbitrary depth. */ string getAnAPIName() { result = this.asDotExpr().getPropertyName() or - result = this.getADescendantCqlExpr().getAnAPIName() + result = this.getADescendantCqlClause().getAnAPIName() } } -class CqlSelectExpr extends CqlExpr { - CqlSelectExpr() { - exists(CqlSelectBase cqlSelect | - this.getCqlBase() = cqlSelect and - not exists( - CqlExpr ancestorSelect | - ancestorSelect = this.getAnAncestorCqlExpr() and ancestorSelect.getCqlBase() = cqlSelect - ) - ) - or - this.getCqlBaseCall() instanceof CqlSelectBaseCall - } - - predicate selectWhere() { this.getAnAPIName() = "where" } - - predicate selectFrom() { this.getAnAPIName() = "from" } - - predicate selectColumns() { - this.getAnAPIName() = "columns" - or - // SELECT itself is a shortcut of SELECT.columns - this.getCqlBaseCall() instanceof CqlSelectBaseCall - } -} - -class CqlInsertExpr extends CqlExpr { - CqlInsertExpr() { - exists(CqlInsertBase cqlInsert | - this.getCqlBase() = cqlInsert and - not exists( - CqlExpr ancestorInsert | - ancestorInsert = this.getAnAncestorCqlExpr() and ancestorInsert.getCqlBase() = cqlInsert - ) - ) - or - this.getCqlBaseCall() instanceof CqlInsertBaseCall - } - - predicate insertEntries() { - this.getAnAPIName() = "entries" - or - // INSERT itself is a shortcut of INSERT.entries - this.getCqlBaseCall() instanceof CqlInsertBaseCall - } -} - -class CqlDeleteExpr extends CqlExpr { - CqlDeleteExpr() { - exists(CqlDeleteBase cqlDelete | - this.getCqlBase() = cqlDelete and - not exists( - any(CqlExpr ancestorDelete | - ancestorDelete = this.getAnAncestorCqlExpr() and ancestorDelete.getCqlBase() = cqlDelete - ) - ) - ) - } -} - -class CqlUpdateExpr extends CqlExpr { - CqlUpdateExpr() { - exists(CqlUpdateBase cqlUpdate | - this.getCqlBase() = cqlUpdate and - not exists( - any(CqlExpr ancestorUpdate | - ancestorUpdate = this.getAnAncestorCqlExpr() and ancestorUpdate.getCqlBase() = cqlUpdate - ) - ) - ) - or - this.getCqlBaseCall() instanceof CqlUpdateBaseCall - } - - predicate updateEntity() { - this.getAnAPIName() = "entity" - or - // UPDATE itself is a shortcut of UPDATE.entity - this.getCqlBaseCall() instanceof CqlUpdateBaseCall - } -} - -class CqlUpsertExpr extends CqlExpr { - CqlUpsertExpr() { - exists(CqlUpsertBase cqlUpsert | - this.getCqlBase() = cqlUpsert and - not exists( - any(CqlExpr ancestorUpsert | - ancestorUpsert = this.getAnAncestorCqlExpr() and ancestorUpsert.getCqlBase() = cqlUpsert - ) - ) - ) - or - this.getCqlBaseCall() instanceof CqlUpsertBaseCall - } - - predicate upsertEntries() { - this.getAnAPIName() = "entries" - or - // UPSERT itself is a shortcut of UPSERT.entries - this.getCqlBaseCall() instanceof CqlUpsertBaseCall +/** + * Call to`cds.db.run` + */ +//TODO: add awaits around SQLClauses +class CQLSink extends DataFlow::Node { + CQLSink(){ + this = any(CdsFacade cds).getMember("db").getMember("run").getACall().getAnArgument() } + } } \ No newline at end of file diff --git a/javascript/frameworks/cap/src/sqlinjection/SqlInjection.ql b/javascript/frameworks/cap/src/sqlinjection/SqlInjection.ql new file mode 100644 index 000000000..66eef62b6 --- /dev/null +++ b/javascript/frameworks/cap/src/sqlinjection/SqlInjection.ql @@ -0,0 +1,33 @@ +import javascript +import advanced_security.javascript.frameworks.cap.CDS +import advanced_security.javascript.frameworks.cap.CQL +import semmle.javascript.StringConcatenation + +class SqlInjectionConfiguration extends TaintTracking::Configuration { + SqlInjectionConfiguration(){ + this = "" + } + override predicate isSource(DataFlow::Node source) { + exists(CDS::RequestSource src | + source = src ) + } + + override predicate isSink(DataFlow::Node sink) { + exists(CQL::CQLSink snk | + sink = snk ) + } + + override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { + //string concatenation in a clause arg taints the clause + exists(CQL::CqlClause clause | + clause.getArgument() = pred.asExpr() + and clause.asExpr() = succ.asExpr() + and + exists(StringConcatenation::getAnOperand(pred)) + ) + } +} + +from SqlInjectionConfiguration sql , DataFlow::Node source, DataFlow::Node sink +where sql.hasFlow(source, sink) +select sink, "Injection vulnerability found." \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cql/delete/delete.expected b/javascript/frameworks/cap/test/models/cql/delete/delete.expected index 99e49e121..c879ee912 100644 --- a/javascript/frameworks/cap/test/models/cql/delete/delete.expected +++ b/javascript/frameworks/cap/test/models/cql/delete/delete.expected @@ -1,16 +1,18 @@ | delete.js:1:15:1:53 | delete.js:1 | delete.js:1:15:1:53 | DELETE. ... "*" }) | | delete.js:2:15:2:50 | delete.js:2 | delete.js:2:15:2:50 | DELETE. ... 1='*'") | -| delete.js:3:15:3:51 | delete.js:3 | delete.js:3:15:3:51 | DELETE. ... ${"*"}` | | delete.js:4:15:4:52 | delete.js:4 | delete.js:4:15:4:52 | DELETE. ... ", "*") | -| delete.js:5:15:5:52 | delete.js:5 | delete.js:5:15:5:52 | DELETE. ... ${"*"}` | | delete.js:6:15:6:59 | delete.js:6 | delete.js:6:15:6:59 | DELETE. ... , 10)") | -| delete.js:7:15:7:62 | delete.js:7 | delete.js:7:15:7:62 | DELETE. ... 10)]}` | | delete.js:8:15:8:71 | delete.js:8 | delete.js:8:15:8:71 | DELETE. ... 11 } }) | +| delete.js:10:15:10:32 | delete.js:10 | delete.js:10:15:10:32 | DELETE.from(Table) | | delete.js:10:15:10:53 | delete.js:10 | delete.js:10:15:10:53 | DELETE. ... "*" }) | +| delete.js:11:15:11:32 | delete.js:11 | delete.js:11:15:11:32 | DELETE.from(Table) | | delete.js:11:15:11:50 | delete.js:11 | delete.js:11:15:11:50 | DELETE. ... 1='*'") | -| delete.js:12:15:12:51 | delete.js:12 | delete.js:12:15:12:51 | DELETE. ... ${"*"}` | +| delete.js:12:15:12:32 | delete.js:12 | delete.js:12:15:12:32 | DELETE.from(Table) | +| delete.js:13:15:13:32 | delete.js:13 | delete.js:13:15:13:32 | DELETE.from(Table) | | delete.js:13:15:13:52 | delete.js:13 | delete.js:13:15:13:52 | DELETE. ... ", "*") | -| delete.js:14:15:14:52 | delete.js:14 | delete.js:14:15:14:52 | DELETE. ... ${"*"}` | +| delete.js:14:15:14:32 | delete.js:14 | delete.js:14:15:14:32 | DELETE.from(Table) | +| delete.js:15:15:15:32 | delete.js:15 | delete.js:15:15:15:32 | DELETE.from(Table) | | delete.js:15:15:15:59 | delete.js:15 | delete.js:15:15:15:59 | DELETE. ... , 10)") | -| delete.js:16:15:16:62 | delete.js:16 | delete.js:16:15:16:62 | DELETE. ... 10)]}` | +| delete.js:16:15:16:32 | delete.js:16 | delete.js:16:15:16:32 | DELETE.from(Table) | +| delete.js:17:15:17:32 | delete.js:17 | delete.js:17:15:17:32 | DELETE.from(Table) | | delete.js:17:15:17:71 | delete.js:17 | delete.js:17:15:17:71 | DELETE. ... 11 } }) | diff --git a/javascript/frameworks/cap/test/models/cql/delete/delete.ql b/javascript/frameworks/cap/test/models/cql/delete/delete.ql index f602eeba4..2c7551107 100644 --- a/javascript/frameworks/cap/test/models/cql/delete/delete.ql +++ b/javascript/frameworks/cap/test/models/cql/delete/delete.ql @@ -1,6 +1,6 @@ import javascript import advanced_security.javascript.frameworks.cap.CQL -from CQL::CqlDeleteExpr s +from CQL::CqlClause s select s.getLocation(), s diff --git a/javascript/frameworks/cap/test/models/cql/insert/insert.expected b/javascript/frameworks/cap/test/models/cql/insert/insert.expected index e4af5d7a9..d82dfe113 100644 --- a/javascript/frameworks/cap/test/models/cql/insert/insert.expected +++ b/javascript/frameworks/cap/test/models/cql/insert/insert.expected @@ -1,25 +1,50 @@ +| insert.js:2:14:5:2 | insert.js:2 | insert.js:2:14:5:2 | INSERT( ... " },\\n]) | | insert.js:2:14:5:14 | insert.js:2 | insert.js:2:14:5:14 | INSERT( ... (Table) | +| insert.js:6:14:9:2 | insert.js:6 | insert.js:6:14:9:2 | INSERT( ... " },\\n]) | | insert.js:6:14:9:16 | insert.js:6 | insert.js:6:14:9:16 | INSERT( ... Table") | | insert.js:11:14:14:2 | insert.js:11 | insert.js:11:14:14:2 | INSERT. ... " },\\n]) | | insert.js:15:14:18:2 | insert.js:15 | insert.js:15:14:18:2 | INSERT. ... " },\\n]) | +| insert.js:21:14:21:31 | insert.js:21 | insert.js:21:14:21:31 | INSERT.into(Table) | | insert.js:21:14:24:1 | insert.js:21 | insert.js:21:14:24:1 | INSERT. ... 22" }\\n) | +| insert.js:25:14:25:31 | insert.js:25 | insert.js:25:14:25:31 | INSERT.into(Table) | | insert.js:25:14:28:2 | insert.js:25 | insert.js:25:14:28:2 | INSERT. ... " },\\n]) | +| insert.js:29:14:29:33 | insert.js:29 | insert.js:29:14:29:33 | INSERT.into("Table") | | insert.js:29:14:32:2 | insert.js:29 | insert.js:29:14:32:2 | INSERT. ... " },\\n]) | +| insert.js:33:14:33:33 | insert.js:33 | insert.js:33:14:33:33 | INSERT.into("Table") | | insert.js:33:14:36:2 | insert.js:33 | insert.js:33:14:36:2 | INSERT. ... " },\\n]) | | insert.js:37:14:40:2 | insert.js:37 | insert.js:37:14:40:2 | INSERT. ... " },\\n]) | | insert.js:41:14:44:2 | insert.js:41 | insert.js:41:14:44:2 | INSERT. ... " },\\n]) | +| insert.js:47:14:47:31 | insert.js:47 | insert.js:47:14:47:31 | INSERT.into(Table) | +| insert.js:47:14:48:26 | insert.js:47 | insert.js:47:14:48:26 | INSERT. ... "col2") | | insert.js:47:14:49:27 | insert.js:47 | insert.js:47:14:49:27 | INSERT. ... val12") | +| insert.js:50:14:50:33 | insert.js:50 | insert.js:50:14:50:33 | INSERT.into("Table") | +| insert.js:50:14:51:26 | insert.js:50 | insert.js:50:14:51:26 | INSERT. ... "col2") | | insert.js:50:14:52:27 | insert.js:50 | insert.js:50:14:52:27 | INSERT. ... val12") | +| insert.js:53:14:54:26 | insert.js:53 | insert.js:53:14:54:26 | INSERT. ... "col2") | | insert.js:53:14:55:27 | insert.js:53 | insert.js:53:14:55:27 | INSERT. ... val12") | +| insert.js:58:14:58:31 | insert.js:58 | insert.js:58:14:58:31 | INSERT.into(Table) | +| insert.js:58:14:59:26 | insert.js:58 | insert.js:58:14:59:26 | INSERT. ... "col2") | | insert.js:58:14:63:4 | insert.js:58 | insert.js:58:14:63:4 | INSERT. ... ],\\n ]) | +| insert.js:64:14:64:33 | insert.js:64 | insert.js:64:14:64:33 | INSERT.into("Table") | +| insert.js:64:14:65:26 | insert.js:64 | insert.js:64:14:65:26 | INSERT. ... "col2") | | insert.js:64:14:69:4 | insert.js:64 | insert.js:64:14:69:4 | INSERT. ... ],\\n ]) | +| insert.js:70:14:70:55 | insert.js:70 | insert.js:70:14:70:55 | INSERT. ... "col2") | | insert.js:70:14:73:2 | insert.js:70 | insert.js:70:14:73:2 | INSERT. ... 2"],\\n]) | +| insert.js:76:14:76:31 | insert.js:76 | insert.js:76:14:76:31 | INSERT.into(Table) | | insert.js:76:14:76:74 | insert.js:76 | insert.js:76:14:76:74 | INSERT. ... col2`) | +| insert.js:77:14:77:31 | insert.js:77 | insert.js:77:14:77:31 | INSERT.into(Table) | | insert.js:77:14:77:73 | insert.js:77 | insert.js:77:14:77:73 | INSERT. ... {"*"}`) | +| insert.js:78:14:78:31 | insert.js:78 | insert.js:78:14:78:31 | INSERT.into(Table) | | insert.js:78:14:80:1 | insert.js:78 | insert.js:78:14:80:1 | INSERT. ... "*"}`\\n) | +| insert.js:79:3:79:44 | insert.js:79 | insert.js:79:3:79:44 | SELECT. ... "col2") | +| insert.js:82:14:82:33 | insert.js:82 | insert.js:82:14:82:33 | INSERT.into("Table") | | insert.js:82:14:82:76 | insert.js:82 | insert.js:82:14:82:76 | INSERT. ... col2`) | +| insert.js:83:14:83:33 | insert.js:83 | insert.js:83:14:83:33 | INSERT.into("Table") | | insert.js:83:14:83:75 | insert.js:83 | insert.js:83:14:83:75 | INSERT. ... {"*"}`) | +| insert.js:84:14:84:33 | insert.js:84 | insert.js:84:14:84:33 | INSERT.into("Table") | | insert.js:84:14:86:1 | insert.js:84 | insert.js:84:14:86:1 | INSERT. ... "*"}`\\n) | +| insert.js:85:3:85:44 | insert.js:85 | insert.js:85:3:85:44 | SELECT. ... "col2") | | insert.js:88:14:88:74 | insert.js:88 | insert.js:88:14:88:74 | INSERT. ... col2`) | | insert.js:89:14:89:73 | insert.js:89 | insert.js:89:14:89:73 | INSERT. ... {"*"}`) | | insert.js:90:14:92:1 | insert.js:90 | insert.js:90:14:92:1 | INSERT. ... "*"}`\\n) | +| insert.js:91:3:91:44 | insert.js:91 | insert.js:91:3:91:44 | SELECT. ... "col2") | diff --git a/javascript/frameworks/cap/test/models/cql/insert/insert.ql b/javascript/frameworks/cap/test/models/cql/insert/insert.ql index fddd3890c..3f53113e1 100644 --- a/javascript/frameworks/cap/test/models/cql/insert/insert.ql +++ b/javascript/frameworks/cap/test/models/cql/insert/insert.ql @@ -1,5 +1,5 @@ import javascript import advanced_security.javascript.frameworks.cap.CQL -from CQL::CqlInsertExpr s +from CQL::CqlClause s select s.getLocation(), s diff --git a/javascript/frameworks/cap/test/models/cql/select/select.expected b/javascript/frameworks/cap/test/models/cql/select/select.expected index e648ab53d..de09ede2a 100644 --- a/javascript/frameworks/cap/test/models/cql/select/select.expected +++ b/javascript/frameworks/cap/test/models/cql/select/select.expected @@ -1,157 +1,187 @@ -| select2.js:4:14:4:35 | select2.js:4 | select2.js:4:14:4:35 | SELECT. ... (Table) | -| select.js:2:14:2:43 | select.js:2 | select.js:2:14:2:43 | SELECT` ... `Table` | | select.js:3:14:3:43 | select.js:3 | select.js:3:14:3:43 | SELECT` ... (Table) | | select.js:4:14:4:45 | select.js:4 | select.js:4:14:4:45 | SELECT` ... Table") | -| select.js:5:14:5:45 | select.js:5 | select.js:5:14:5:45 | SELECT( ... `Table` | +| select.js:5:14:5:33 | select.js:5 | select.js:5:14:5:33 | SELECT("col1, col2") | +| select.js:6:14:6:33 | select.js:6 | select.js:6:14:6:33 | SELECT("col1, col2") | | select.js:6:14:6:45 | select.js:6 | select.js:6:14:6:45 | SELECT( ... (Table) | +| select.js:7:14:7:33 | select.js:7 | select.js:7:14:7:33 | SELECT("col1, col2") | | select.js:7:14:7:47 | select.js:7 | select.js:7:14:7:47 | SELECT( ... Table") | -| select.js:10:14:10:35 | select.js:10 | select.js:10:14:10:35 | SELECT. ... `Table` | | select.js:11:14:11:35 | select.js:11 | select.js:11:14:11:35 | SELECT. ... (Table) | -| select.js:12:14:12:40 | select.js:12 | select.js:12:14:12:40 | SELECT. ... `Table` | | select.js:13:14:13:40 | select.js:13 | select.js:13:14:13:40 | SELECT. ... (Table) | | select.js:14:14:14:54 | select.js:14 | select.js:14:14:14:54 | SELECT. ... (Table) | -| select.js:15:14:15:54 | select.js:15 | select.js:15:14:15:54 | SELECT. ... `Table` | -| select.js:19:14:19:51 | select.js:19 | select.js:19:14:19:51 | SELECT. ... , col2` | | select.js:20:14:22:2 | select.js:20 | select.js:20:14:22:2 | SELECT. ... ol2;\\n}) | -| select.js:23:14:23:68 | select.js:23 | select.js:23:14:23:68 | SELECT. ... lias }` | | select.js:24:14:24:68 | select.js:24 | select.js:24:14:24:68 | SELECT. ... Alias") | | select.js:25:14:28:2 | select.js:25 | select.js:25:14:28:2 | SELECT. ... " },\\n]) | | select.js:29:14:32:2 | select.js:29 | select.js:29:14:32:2 | SELECT. ... ty",\\n}) | -| select.js:34:14:34:51 | select.js:34 | select.js:34:14:34:51 | SELECT. ... , col2` | +| select.js:34:14:34:31 | select.js:34 | select.js:34:14:34:31 | SELECT.from(Table) | +| select.js:35:14:35:31 | select.js:35 | select.js:35:14:35:31 | SELECT.from(Table) | | select.js:35:14:37:2 | select.js:35 | select.js:35:14:37:2 | SELECT. ... ol2;\\n}) | -| select.js:38:14:38:68 | select.js:38 | select.js:38:14:38:68 | SELECT. ... lias }` | +| select.js:38:14:38:31 | select.js:38 | select.js:38:14:38:31 | SELECT.from(Table) | +| select.js:39:14:39:31 | select.js:39 | select.js:39:14:39:31 | SELECT.from(Table) | | select.js:39:14:39:68 | select.js:39 | select.js:39:14:39:68 | SELECT. ... Alias") | +| select.js:40:14:40:31 | select.js:40 | select.js:40:14:40:31 | SELECT.from(Table) | | select.js:40:14:43:2 | select.js:40 | select.js:40:14:43:2 | SELECT. ... " },\\n]) | +| select.js:44:14:44:31 | select.js:44 | select.js:44:14:44:31 | SELECT.from(Table) | | select.js:44:14:47:2 | select.js:44 | select.js:44:14:47:2 | SELECT. ... ty",\\n}) | | select.js:50:14:50:52 | select.js:50 | select.js:50:14:50:52 | SELECT. ... "*" }) | | select.js:51:14:51:49 | select.js:51 | select.js:51:14:51:49 | SELECT. ... 1='*'") | -| select.js:52:14:52:50 | select.js:52 | select.js:52:14:52:50 | SELECT. ... ${"*"}` | | select.js:53:14:53:51 | select.js:53 | select.js:53:14:53:51 | SELECT. ... ", "*") | -| select.js:54:14:54:51 | select.js:54 | select.js:54:14:54:51 | SELECT. ... ${"*"}` | | select.js:55:14:55:58 | select.js:55 | select.js:55:14:55:58 | SELECT. ... , 10)") | -| select.js:56:14:56:61 | select.js:56 | select.js:56:14:56:61 | SELECT. ... 10)]}` | | select.js:57:14:57:70 | select.js:57 | select.js:57:14:57:70 | SELECT. ... 11 } }) | +| select.js:59:14:59:31 | select.js:59 | select.js:59:14:59:31 | SELECT.from(Table) | | select.js:59:14:59:52 | select.js:59 | select.js:59:14:59:52 | SELECT. ... "*" }) | +| select.js:60:14:60:31 | select.js:60 | select.js:60:14:60:31 | SELECT.from(Table) | | select.js:60:14:60:49 | select.js:60 | select.js:60:14:60:49 | SELECT. ... 1='*'") | -| select.js:61:14:61:50 | select.js:61 | select.js:61:14:61:50 | SELECT. ... ${"*"}` | +| select.js:61:14:61:31 | select.js:61 | select.js:61:14:61:31 | SELECT.from(Table) | +| select.js:62:14:62:31 | select.js:62 | select.js:62:14:62:31 | SELECT.from(Table) | | select.js:62:14:62:51 | select.js:62 | select.js:62:14:62:51 | SELECT. ... ", "*") | -| select.js:63:14:63:51 | select.js:63 | select.js:63:14:63:51 | SELECT. ... ${"*"}` | +| select.js:63:14:63:31 | select.js:63 | select.js:63:14:63:31 | SELECT.from(Table) | +| select.js:64:14:64:31 | select.js:64 | select.js:64:14:64:31 | SELECT.from(Table) | | select.js:64:14:64:58 | select.js:64 | select.js:64:14:64:58 | SELECT. ... , 10)") | -| select.js:65:14:65:61 | select.js:65 | select.js:65:14:65:61 | SELECT. ... 10)]}` | +| select.js:65:14:65:31 | select.js:65 | select.js:65:14:65:31 | SELECT.from(Table) | +| select.js:66:14:66:31 | select.js:66 | select.js:66:14:66:31 | SELECT.from(Table) | | select.js:66:14:66:70 | select.js:66 | select.js:66:14:66:70 | SELECT. ... 11 } }) | | select.js:69:14:69:55 | select.js:69 | select.js:69:14:69:55 | SELECT. ... "col2") | -| select.js:70:14:70:51 | select.js:70 | select.js:70:14:70:51 | SELECT. ... , col2` | | select.js:71:14:71:67 | select.js:71 | select.js:71:14:71:67 | SELECT. ... prop2") | -| select.js:72:14:72:63 | select.js:72 | select.js:72:14:72:63 | SELECT. ... .prop2` | | select.js:73:14:76:1 | select.js:73 | select.js:73:14:76:1 | SELECT. ... 2"] }\\n) | +| select.js:78:14:78:31 | select.js:78 | select.js:78:14:78:31 | SELECT.from(Table) | | select.js:78:14:78:55 | select.js:78 | select.js:78:14:78:55 | SELECT. ... "col2") | -| select.js:79:14:79:51 | select.js:79 | select.js:79:14:79:51 | SELECT. ... , col2` | +| select.js:79:14:79:31 | select.js:79 | select.js:79:14:79:31 | SELECT.from(Table) | +| select.js:80:14:80:31 | select.js:80 | select.js:80:14:80:31 | SELECT.from(Table) | | select.js:80:14:80:67 | select.js:80 | select.js:80:14:80:67 | SELECT. ... prop2") | -| select.js:81:14:81:63 | select.js:81 | select.js:81:14:81:63 | SELECT. ... .prop2` | +| select.js:81:14:81:31 | select.js:81 | select.js:81:14:81:31 | SELECT.from(Table) | +| select.js:82:14:82:31 | select.js:82 | select.js:82:14:82:31 | SELECT.from(Table) | | select.js:82:14:85:1 | select.js:82 | select.js:82:14:85:1 | SELECT. ... 2"] }\\n) | | select.js:88:14:88:53 | select.js:88 | select.js:88:14:88:53 | SELECT. ... "*" }) | | select.js:89:14:89:50 | select.js:89 | select.js:89:14:89:50 | SELECT. ... 1='*'") | -| select.js:90:14:90:51 | select.js:90 | select.js:90:14:90:51 | SELECT. ... ${"*"}` | | select.js:91:14:91:52 | select.js:91 | select.js:91:14:91:52 | SELECT. ... ", "*") | -| select.js:92:14:92:52 | select.js:92 | select.js:92:14:92:52 | SELECT. ... ${"*"}` | | select.js:93:14:93:59 | select.js:93 | select.js:93:14:93:59 | SELECT. ... , 10)") | -| select.js:94:14:94:62 | select.js:94 | select.js:94:14:94:62 | SELECT. ... 10)]}` | | select.js:95:14:95:71 | select.js:95 | select.js:95:14:95:71 | SELECT. ... 11 } }) | +| select.js:97:14:97:31 | select.js:97 | select.js:97:14:97:31 | SELECT.from(Table) | | select.js:97:14:97:53 | select.js:97 | select.js:97:14:97:53 | SELECT. ... "*" }) | +| select.js:98:14:98:31 | select.js:98 | select.js:98:14:98:31 | SELECT.from(Table) | | select.js:98:14:98:50 | select.js:98 | select.js:98:14:98:50 | SELECT. ... 1='*'") | -| select.js:99:14:99:51 | select.js:99 | select.js:99:14:99:51 | SELECT. ... ${"*"}` | +| select.js:99:14:99:31 | select.js:99 | select.js:99:14:99:31 | SELECT.from(Table) | +| select.js:100:14:100:31 | select.js:100 | select.js:100:14:100:31 | SELECT.from(Table) | | select.js:100:14:100:52 | select.js:100 | select.js:100:14:100:52 | SELECT. ... ", "*") | -| select.js:101:14:101:52 | select.js:101 | select.js:101:14:101:52 | SELECT. ... ${"*"}` | +| select.js:101:14:101:31 | select.js:101 | select.js:101:14:101:31 | SELECT.from(Table) | +| select.js:102:14:102:31 | select.js:102 | select.js:102:14:102:31 | SELECT.from(Table) | | select.js:102:14:102:59 | select.js:102 | select.js:102:14:102:59 | SELECT. ... , 10)") | -| select.js:103:14:103:62 | select.js:103 | select.js:103:14:103:62 | SELECT. ... 10)]}` | +| select.js:103:14:103:31 | select.js:103 | select.js:103:14:103:31 | SELECT.from(Table) | +| select.js:104:14:104:31 | select.js:104 | select.js:104:14:104:31 | SELECT.from(Table) | | select.js:104:14:104:71 | select.js:104 | select.js:104:14:104:71 | SELECT. ... 11 } }) | +| select.js:106:14:106:55 | select.js:106 | select.js:106:14:106:55 | SELECT. ... "col2") | | select.js:106:14:106:77 | select.js:106 | select.js:106:14:106:77 | SELECT. ... "*" }) | +| select.js:107:14:107:55 | select.js:107 | select.js:107:14:107:55 | SELECT. ... "col2") | | select.js:107:14:107:74 | select.js:107 | select.js:107:14:107:74 | SELECT. ... 1='*'") | -| select.js:108:14:108:75 | select.js:108 | select.js:108:14:108:75 | SELECT. ... ${"*"}` | +| select.js:108:14:108:55 | select.js:108 | select.js:108:14:108:55 | SELECT. ... "col2") | +| select.js:109:14:109:55 | select.js:109 | select.js:109:14:109:55 | SELECT. ... "col2") | | select.js:109:14:109:76 | select.js:109 | select.js:109:14:109:76 | SELECT. ... ", "*") | -| select.js:110:14:110:76 | select.js:110 | select.js:110:14:110:76 | SELECT. ... ${"*"}` | +| select.js:110:14:110:55 | select.js:110 | select.js:110:14:110:55 | SELECT. ... "col2") | +| select.js:111:14:112:26 | select.js:111 | select.js:111:14:112:26 | SELECT. ... "col2") | | select.js:111:14:113:30 | select.js:111 | select.js:111:14:113:30 | SELECT. ... , 10)") | -| select.js:114:14:116:3 | select.js:114 | select.js:114:14:116:3 | SELECT. ... 0),\\n]}` | +| select.js:114:14:114:55 | select.js:114 | select.js:114:14:114:55 | SELECT. ... "col2") | +| select.js:117:14:118:26 | select.js:117 | select.js:117:14:118:26 | SELECT. ... "col2") | | select.js:117:14:119:42 | select.js:117 | select.js:117:14:119:42 | SELECT. ... 11 } }) | +| select.js:121:14:121:31 | select.js:121 | select.js:121:14:121:31 | SELECT.from(Table) | +| select.js:121:14:121:55 | select.js:121 | select.js:121:14:121:55 | SELECT. ... "col2") | | select.js:121:14:121:77 | select.js:121 | select.js:121:14:121:77 | SELECT. ... "*" }) | +| select.js:122:14:122:31 | select.js:122 | select.js:122:14:122:31 | SELECT.from(Table) | +| select.js:122:14:122:55 | select.js:122 | select.js:122:14:122:55 | SELECT. ... "col2") | | select.js:122:14:122:74 | select.js:122 | select.js:122:14:122:74 | SELECT. ... 1='*'") | -| select.js:123:14:123:75 | select.js:123 | select.js:123:14:123:75 | SELECT. ... ${"*"}` | +| select.js:123:14:123:31 | select.js:123 | select.js:123:14:123:31 | SELECT.from(Table) | +| select.js:123:14:123:55 | select.js:123 | select.js:123:14:123:55 | SELECT. ... "col2") | +| select.js:124:14:124:31 | select.js:124 | select.js:124:14:124:31 | SELECT.from(Table) | +| select.js:124:14:124:55 | select.js:124 | select.js:124:14:124:55 | SELECT. ... "col2") | | select.js:124:14:124:76 | select.js:124 | select.js:124:14:124:76 | SELECT. ... ", "*") | -| select.js:125:14:125:76 | select.js:125 | select.js:125:14:125:76 | SELECT. ... ${"*"}` | +| select.js:125:14:125:31 | select.js:125 | select.js:125:14:125:31 | SELECT.from(Table) | +| select.js:125:14:125:55 | select.js:125 | select.js:125:14:125:55 | SELECT. ... "col2") | +| select.js:126:14:126:31 | select.js:126 | select.js:126:14:126:31 | SELECT.from(Table) | +| select.js:126:14:127:26 | select.js:126 | select.js:126:14:127:26 | SELECT. ... "col2") | | select.js:126:14:128:30 | select.js:126 | select.js:126:14:128:30 | SELECT. ... , 10)") | -| select.js:129:14:131:3 | select.js:129 | select.js:129:14:131:3 | SELECT. ... 0),\\n]}` | +| select.js:129:14:129:31 | select.js:129 | select.js:129:14:129:31 | SELECT.from(Table) | +| select.js:129:14:129:55 | select.js:129 | select.js:129:14:129:55 | SELECT. ... "col2") | +| select.js:132:14:132:31 | select.js:132 | select.js:132:14:132:31 | SELECT.from(Table) | +| select.js:132:14:133:26 | select.js:132 | select.js:132:14:133:26 | SELECT. ... "col2") | | select.js:132:14:134:42 | select.js:132 | select.js:132:14:134:42 | SELECT. ... 11 } }) | | select.js:136:14:136:73 | select.js:136 | select.js:136:14:136:73 | SELECT. ... "*" }) | | select.js:137:14:137:70 | select.js:137 | select.js:137:14:137:70 | SELECT. ... 1='*'") | -| select.js:138:14:138:71 | select.js:138 | select.js:138:14:138:71 | SELECT. ... ${"*"}` | | select.js:139:14:139:72 | select.js:139 | select.js:139:14:139:72 | SELECT. ... ", "*") | -| select.js:140:14:140:72 | select.js:140 | select.js:140:14:140:72 | SELECT. ... ${"*"}` | | select.js:141:14:141:79 | select.js:141 | select.js:141:14:141:79 | SELECT. ... , 10)") | -| select.js:142:14:144:3 | select.js:142 | select.js:142:14:144:3 | SELECT. ... 0),\\n]}` | | select.js:145:14:148:2 | select.js:145 | select.js:145:14:148:2 | SELECT. ... 1 },\\n}) | +| select.js:150:14:150:51 | select.js:150 | select.js:150:14:150:51 | SELECT. ... , col2) | | select.js:150:14:150:73 | select.js:150 | select.js:150:14:150:73 | SELECT. ... "*" }) | +| select.js:151:14:151:51 | select.js:151 | select.js:151:14:151:51 | SELECT. ... , col2) | | select.js:151:14:151:70 | select.js:151 | select.js:151:14:151:70 | SELECT. ... 1='*'") | -| select.js:152:14:152:71 | select.js:152 | select.js:152:14:152:71 | SELECT. ... ${"*"}` | +| select.js:152:14:152:51 | select.js:152 | select.js:152:14:152:51 | SELECT. ... , col2) | +| select.js:153:14:153:51 | select.js:153 | select.js:153:14:153:51 | SELECT. ... , col2) | | select.js:153:14:153:72 | select.js:153 | select.js:153:14:153:72 | SELECT. ... ", "*") | -| select.js:154:14:154:72 | select.js:154 | select.js:154:14:154:72 | SELECT. ... ${"*"}` | +| select.js:154:14:154:51 | select.js:154 | select.js:154:14:154:51 | SELECT. ... , col2) | +| select.js:155:14:155:51 | select.js:155 | select.js:155:14:155:51 | SELECT. ... , col2) | | select.js:155:14:155:79 | select.js:155 | select.js:155:14:155:79 | SELECT. ... , 10)") | -| select.js:156:14:158:3 | select.js:156 | select.js:156:14:158:3 | SELECT. ... 0),\\n]}` | +| select.js:156:14:156:51 | select.js:156 | select.js:156:14:156:51 | SELECT. ... , col2) | +| select.js:159:14:159:51 | select.js:159 | select.js:159:14:159:51 | SELECT. ... , col2) | | select.js:159:14:162:2 | select.js:159 | select.js:159:14:162:2 | SELECT. ... 1 },\\n}) | +| select.js:164:14:165:38 | select.js:164 | select.js:164:14:165:38 | SELECT. ... prop2") | | select.js:164:14:166:24 | select.js:164 | select.js:164:14:166:24 | SELECT. ... "*" }) | +| select.js:167:14:168:38 | select.js:167 | select.js:167:14:168:38 | SELECT. ... prop2") | | select.js:167:14:169:21 | select.js:167 | select.js:167:14:169:21 | SELECT. ... 1='*'") | -| select.js:170:14:171:22 | select.js:170 | select.js:170:14:171:22 | SELECT. ... ${"*"}` | +| select.js:170:14:170:67 | select.js:170 | select.js:170:14:170:67 | SELECT. ... prop2") | +| select.js:172:14:173:38 | select.js:172 | select.js:172:14:173:38 | SELECT. ... prop2") | | select.js:172:14:174:23 | select.js:172 | select.js:172:14:174:23 | SELECT. ... ", "*") | -| select.js:175:14:176:23 | select.js:175 | select.js:175:14:176:23 | SELECT. ... ${"*"}` | +| select.js:175:14:175:67 | select.js:175 | select.js:175:14:175:67 | SELECT. ... prop2") | +| select.js:177:14:178:38 | select.js:177 | select.js:177:14:178:38 | SELECT. ... prop2") | | select.js:177:14:179:30 | select.js:177 | select.js:177:14:179:30 | SELECT. ... , 10)") | -| select.js:180:14:181:33 | select.js:180 | select.js:180:14:181:33 | SELECT. ... 10)]}` | +| select.js:180:14:180:67 | select.js:180 | select.js:180:14:180:67 | SELECT. ... prop2") | +| select.js:182:14:183:38 | select.js:182 | select.js:182:14:183:38 | SELECT. ... prop2") | | select.js:182:14:184:42 | select.js:182 | select.js:182:14:184:42 | SELECT. ... 11 } }) | | select.js:186:14:188:2 | select.js:186 | select.js:186:14:188:2 | SELECT. ... "*",\\n}) | | select.js:189:14:191:1 | select.js:189 | select.js:189:14:191:1 | SELECT. ... ='*'"\\n) | -| select.js:192:14:193:22 | select.js:192 | select.js:192:14:193:22 | SELECT. ... ${"*"}` | | select.js:194:14:197:1 | select.js:194 | select.js:194:14:197:1 | SELECT. ... "*"\\n) | -| select.js:198:14:199:23 | select.js:198 | select.js:198:14:199:23 | SELECT. ... ${"*"}` | | select.js:200:14:202:1 | select.js:200 | select.js:200:14:202:1 | SELECT. ... 10)"\\n) | -| select.js:203:14:204:33 | select.js:203 | select.js:203:14:204:33 | SELECT. ... 10)]}` | | select.js:205:14:208:2 | select.js:205 | select.js:205:14:208:2 | SELECT. ... 1 },\\n}) | +| select.js:210:14:211:66 | select.js:210 | select.js:210:14:211:66 | SELECT. ... p2"] }) | | select.js:210:14:212:24 | select.js:210 | select.js:210:14:212:24 | SELECT. ... "*" }) | +| select.js:213:14:214:66 | select.js:213 | select.js:213:14:214:66 | SELECT. ... p2"] }) | | select.js:213:14:215:21 | select.js:213 | select.js:213:14:215:21 | SELECT. ... 1='*'") | -| select.js:216:14:219:21 | select.js:216 | select.js:216:14:219:21 | SELECT. ... ${"*"}` | +| select.js:216:14:219:1 | select.js:216 | select.js:216:14:219:1 | SELECT. ... 2"] }\\n) | +| select.js:220:14:221:66 | select.js:220 | select.js:220:14:221:66 | SELECT. ... p2"] }) | | select.js:220:14:222:23 | select.js:220 | select.js:220:14:222:23 | SELECT. ... ", "*") | -| select.js:223:14:226:22 | select.js:223 | select.js:223:14:226:22 | SELECT. ... ${"*"}` | +| select.js:223:14:226:1 | select.js:223 | select.js:223:14:226:1 | SELECT. ... 2"] }\\n) | +| select.js:227:14:228:66 | select.js:227 | select.js:227:14:228:66 | SELECT. ... p2"] }) | | select.js:227:14:229:30 | select.js:227 | select.js:227:14:229:30 | SELECT. ... , 10)") | -| select.js:230:14:233:32 | select.js:230 | select.js:230:14:233:32 | SELECT. ... 10)]}` | +| select.js:230:14:233:1 | select.js:230 | select.js:230:14:233:1 | SELECT. ... 2"] }\\n) | +| select.js:234:14:235:66 | select.js:234 | select.js:234:14:235:66 | SELECT. ... p2"] }) | | select.js:234:14:236:42 | select.js:234 | select.js:234:14:236:42 | SELECT. ... 11 } }) | -| select.js:239:14:239:63 | select.js:239 | select.js:239:14:239:63 | SELECT. ... .prop2` | -| select.js:240:14:240:61 | select.js:240 | select.js:240:14:240:61 | SELECT. ... .prop2` | -| select.js:241:14:241:61 | select.js:241 | select.js:241:14:241:61 | SELECT. ... l2 asc` | -| select.js:242:14:242:58 | select.js:242 | select.js:242:14:242:58 | SELECT. ... l2 asc` | -| select.js:243:14:243:63 | select.js:243 | select.js:243:14:243:63 | SELECT. ... .prop2` | -| select.js:244:14:244:62 | select.js:244 | select.js:244:14:244:62 | SELECT. ... .prop2` | -| select.js:245:14:245:62 | select.js:245 | select.js:245:14:245:62 | SELECT. ... 2 desc` | -| select.js:246:14:246:60 | select.js:246 | select.js:246:14:246:60 | SELECT. ... 2 desc` | -| select.js:248:14:248:63 | select.js:248 | select.js:248:14:248:63 | SELECT. ... .prop2` | -| select.js:249:14:249:61 | select.js:249 | select.js:249:14:249:61 | SELECT. ... .prop2` | -| select.js:250:14:250:61 | select.js:250 | select.js:250:14:250:61 | SELECT. ... l2 asc` | -| select.js:251:14:251:58 | select.js:251 | select.js:251:14:251:58 | SELECT. ... l2 asc` | -| select.js:252:14:252:63 | select.js:252 | select.js:252:14:252:63 | SELECT. ... .prop2` | -| select.js:253:14:253:62 | select.js:253 | select.js:253:14:253:62 | SELECT. ... .prop2` | -| select.js:254:14:254:62 | select.js:254 | select.js:254:14:254:62 | SELECT. ... 2 desc` | -| select.js:255:14:255:60 | select.js:255 | select.js:255:14:255:60 | SELECT. ... 2 desc` | +| select.js:248:14:248:31 | select.js:248 | select.js:248:14:248:31 | SELECT.from(Table) | +| select.js:249:14:249:31 | select.js:249 | select.js:249:14:249:31 | SELECT.from(Table) | +| select.js:250:14:250:31 | select.js:250 | select.js:250:14:250:31 | SELECT.from(Table) | +| select.js:251:14:251:31 | select.js:251 | select.js:251:14:251:31 | SELECT.from(Table) | +| select.js:252:14:252:31 | select.js:252 | select.js:252:14:252:31 | SELECT.from(Table) | +| select.js:253:14:253:31 | select.js:253 | select.js:253:14:253:31 | SELECT.from(Table) | +| select.js:254:14:254:31 | select.js:254 | select.js:254:14:254:31 | SELECT.from(Table) | +| select.js:255:14:255:31 | select.js:255 | select.js:255:14:255:31 | SELECT.from(Table) | | select.js:258:14:258:41 | select.js:258 | select.js:258:14:258:41 | SELECT. ... mit(10) | -| select.js:259:14:259:44 | select.js:259 | select.js:259:14:259:44 | SELECT. ... `${10}` | | select.js:260:14:260:45 | select.js:260 | select.js:260:14:260:45 | SELECT. ... 10, 20) | | select.js:261:14:261:50 | select.js:261 | select.js:261:14:261:50 | SELECT. ... : 10 }) | | select.js:262:14:262:63 | select.js:262 | select.js:262:14:262:63 | SELECT. ... : 20 }) | | select.js:263:14:263:60 | select.js:263 | select.js:263:14:263:60 | SELECT. ... al"] }) | | select.js:264:14:266:2 | select.js:264 | select.js:264:14:266:2 | SELECT. ... }],\\n}) | +| select.js:268:14:268:31 | select.js:268 | select.js:268:14:268:31 | SELECT.from(Table) | | select.js:268:14:268:41 | select.js:268 | select.js:268:14:268:41 | SELECT. ... mit(10) | -| select.js:269:14:269:44 | select.js:269 | select.js:269:14:269:44 | SELECT. ... `${10}` | +| select.js:269:14:269:31 | select.js:269 | select.js:269:14:269:31 | SELECT.from(Table) | +| select.js:270:14:270:31 | select.js:270 | select.js:270:14:270:31 | SELECT.from(Table) | | select.js:270:14:270:45 | select.js:270 | select.js:270:14:270:45 | SELECT. ... 10, 20) | +| select.js:271:14:271:31 | select.js:271 | select.js:271:14:271:31 | SELECT.from(Table) | | select.js:271:14:271:50 | select.js:271 | select.js:271:14:271:50 | SELECT. ... : 10 }) | +| select.js:272:14:272:31 | select.js:272 | select.js:272:14:272:31 | SELECT.from(Table) | | select.js:272:14:272:63 | select.js:272 | select.js:272:14:272:63 | SELECT. ... : 20 }) | +| select.js:273:14:273:31 | select.js:273 | select.js:273:14:273:31 | SELECT.from(Table) | | select.js:273:14:273:60 | select.js:273 | select.js:273:14:273:60 | SELECT. ... al"] }) | +| select.js:274:14:274:31 | select.js:274 | select.js:274:14:274:31 | SELECT.from(Table) | | select.js:274:14:276:2 | select.js:274 | select.js:274:14:276:2 | SELECT. ... }],\\n}) | | select.js:279:14:280:35 | select.js:279 | select.js:279:14:280:35 | SELECT. ... pdate() | | select.js:283:14:284:38 | select.js:283 | select.js:283:14:284:38 | SELECT. ... eLock() | +| select.js:287:14:290:1 | select.js:287 | select.js:287:14:290:1 | SELECT. ... col2"\\n) | +| select.js:287:14:292:2 | select.js:287 | select.js:287:14:292:2 | SELECT. ... }],\\n}) | | select.js:287:14:292:48 | select.js:287 | select.js:287:14:292:48 | SELECT. ... eLock() | -| select.js:328:10:328:47 | select.js:328 | select.js:328:10:328:47 | SELECT. ... ${201}` | +| select.js:328:10:328:28 | select.js:328 | select.js:328:10:328:28 | SELECT.from (Books) | diff --git a/javascript/frameworks/cap/test/models/cql/select/select.ql b/javascript/frameworks/cap/test/models/cql/select/select.ql index 4d0999490..d2961efff 100644 --- a/javascript/frameworks/cap/test/models/cql/select/select.ql +++ b/javascript/frameworks/cap/test/models/cql/select/select.ql @@ -1,6 +1,5 @@ import javascript import advanced_security.javascript.frameworks.cap.CQL -import advanced_security.javascript.frameworks.cap.CDS -from CQL::CqlSelectExpr s +from CQL::CqlClause s select s.getLocation(), s \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cql/select/select2.js b/javascript/frameworks/cap/test/models/cql/select/select2.js index 51aec5cc7..78d6c7e31 100644 --- a/javascript/frameworks/cap/test/models/cql/select/select2.js +++ b/javascript/frameworks/cap/test/models/cql/select/select2.js @@ -1,8 +1,8 @@ -/* ========== obtained through module ========== */ -const cds = require('@sap/cds'); -const { SELECT, INSERT, UPDATE, DELETE } = cds.ql; -var select = SELECT.one.from(Table); +// /* ========== obtained through module ========== */ +// const cds = require('@sap/cds'); +// const { SELECT, INSERT, UPDATE, DELETE } = cds.ql; +// var select = SELECT.one.from(Table); -/* ========== not a use of the API ========== */ -foo.SELECT -require("SELECT")() \ No newline at end of file +// /* ========== not a use of the API ========== */ +// foo.SELECT +// require("SELECT")() \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cql/update/update.expected b/javascript/frameworks/cap/test/models/cql/update/update.expected index fd18594a2..9b1218b8f 100644 --- a/javascript/frameworks/cap/test/models/cql/update/update.expected +++ b/javascript/frameworks/cap/test/models/cql/update/update.expected @@ -1,216 +1,372 @@ -| update.js:4:14:4:53 | update.js:4 | update.js:4:14:4:53 | UPDATE` ... {diff}` | | update.js:5:14:5:95 | update.js:5 | update.js:5:14:5:95 | UPDATE` ... ] }, }) | | update.js:6:14:6:46 | update.js:6 | update.js:6:14:6:46 | UPDATE` ... diff }) | -| update.js:8:14:8:53 | update.js:8 | update.js:8:14:8:53 | UPDATE( ... {diff}` | +| update.js:8:14:8:26 | update.js:8 | update.js:8:14:8:26 | UPDATE(Table) | +| update.js:9:14:9:26 | update.js:9 | update.js:9:14:9:26 | UPDATE(Table) | | update.js:9:14:9:95 | update.js:9 | update.js:9:14:9:95 | UPDATE( ... ] }, }) | +| update.js:10:14:10:26 | update.js:10 | update.js:10:14:10:26 | UPDATE(Table) | | update.js:10:14:10:46 | update.js:10 | update.js:10:14:10:46 | UPDATE( ... diff }) | -| update.js:12:14:12:55 | update.js:12 | update.js:12:14:12:55 | UPDATE( ... {diff}` | +| update.js:12:14:12:28 | update.js:12 | update.js:12:14:12:28 | UPDATE("Table") | +| update.js:13:14:13:28 | update.js:13 | update.js:13:14:13:28 | UPDATE("Table") | | update.js:13:14:13:97 | update.js:13 | update.js:13:14:13:97 | UPDATE( ... ] }, }) | +| update.js:14:14:14:28 | update.js:14 | update.js:14:14:14:28 | UPDATE("Table") | | update.js:14:14:14:48 | update.js:14 | update.js:14:14:14:48 | UPDATE( ... diff }) | -| update.js:17:14:17:60 | update.js:17 | update.js:17:14:17:60 | UPDATE. ... {diff}` | +| update.js:17:14:17:33 | update.js:17 | update.js:17:14:17:33 | UPDATE.entity(Table) | +| update.js:18:14:18:33 | update.js:18 | update.js:18:14:18:33 | UPDATE.entity(Table) | | update.js:18:14:18:102 | update.js:18 | update.js:18:14:18:102 | UPDATE. ... ] }, }) | +| update.js:19:14:19:33 | update.js:19 | update.js:19:14:19:33 | UPDATE.entity(Table) | | update.js:19:14:19:53 | update.js:19 | update.js:19:14:19:53 | UPDATE. ... diff }) | -| update.js:21:14:21:62 | update.js:21 | update.js:21:14:21:62 | UPDATE. ... {diff}` | +| update.js:21:14:21:35 | update.js:21 | update.js:21:14:21:35 | UPDATE. ... Table") | +| update.js:22:14:22:35 | update.js:22 | update.js:22:14:22:35 | UPDATE. ... Table") | | update.js:22:14:22:104 | update.js:22 | update.js:22:14:22:104 | UPDATE. ... ] }, }) | +| update.js:23:14:23:35 | update.js:23 | update.js:23:14:23:35 | UPDATE. ... Table") | | update.js:23:14:23:55 | update.js:23 | update.js:23:14:23:55 | UPDATE. ... diff }) | -| update.js:25:14:25:60 | update.js:25 | update.js:25:14:25:60 | UPDATE. ... {diff}` | | update.js:26:14:26:102 | update.js:26 | update.js:26:14:26:102 | UPDATE. ... ] }, }) | | update.js:27:14:27:53 | update.js:27 | update.js:27:14:27:53 | UPDATE. ... diff }) | -| update.js:32:14:32:54 | update.js:32 | update.js:32:14:32:54 | UPDATE` ... {diff}` | | update.js:33:14:33:96 | update.js:33 | update.js:33:14:33:96 | UPDATE` ... ] }, }) | | update.js:34:14:34:47 | update.js:34 | update.js:34:14:34:47 | UPDATE` ... diff }) | -| update.js:37:14:37:61 | update.js:37 | update.js:37:14:37:61 | UPDATE. ... {diff}` | | update.js:38:14:38:103 | update.js:38 | update.js:38:14:38:103 | UPDATE. ... ] }, }) | | update.js:39:14:39:54 | update.js:39 | update.js:39:14:39:54 | UPDATE. ... diff }) | | update.js:44:14:44:74 | update.js:44 | update.js:44:14:44:74 | UPDATE` ... "*" }) | | update.js:45:14:45:71 | update.js:45 | update.js:45:14:45:71 | UPDATE` ... 1='*'") | -| update.js:46:14:46:72 | update.js:46 | update.js:46:14:46:72 | UPDATE` ... ${"*"}` | | update.js:47:14:47:73 | update.js:47 | update.js:47:14:47:73 | UPDATE` ... ", "*") | -| update.js:48:14:48:73 | update.js:48 | update.js:48:14:48:73 | UPDATE` ... ${"*"}` | | update.js:49:14:49:80 | update.js:49 | update.js:49:14:49:80 | UPDATE` ... , 10)") | -| update.js:50:14:50:86 | update.js:50 | update.js:50:14:50:86 | UPDATE` ... 0), ]}` | | update.js:51:14:51:93 | update.js:51 | update.js:51:14:51:93 | UPDATE` ... 1 }, }) | +| update.js:53:14:53:94 | update.js:53 | update.js:53:14:53:94 | UPDATE` ... }] } }) | | update.js:53:14:53:115 | update.js:53 | update.js:53:14:53:115 | UPDATE` ... "*" }) | +| update.js:54:14:54:94 | update.js:54 | update.js:54:14:54:94 | UPDATE` ... }] } }) | | update.js:54:14:54:112 | update.js:54 | update.js:54:14:54:112 | UPDATE` ... 1='*'") | -| update.js:55:14:55:114 | update.js:55 | update.js:55:14:55:114 | UPDATE` ... ${"*"}` | +| update.js:55:14:55:95 | update.js:55 | update.js:55:14:55:95 | UPDATE` ... ] }, }) | +| update.js:56:14:56:94 | update.js:56 | update.js:56:14:56:94 | UPDATE` ... }] } }) | | update.js:56:14:56:114 | update.js:56 | update.js:56:14:56:114 | UPDATE` ... ", "*") | -| update.js:57:14:57:115 | update.js:57 | update.js:57:14:57:115 | UPDATE` ... ${"*"}` | +| update.js:57:14:57:95 | update.js:57 | update.js:57:14:57:95 | UPDATE` ... ] }, }) | +| update.js:58:14:58:94 | update.js:58 | update.js:58:14:58:94 | UPDATE` ... }] } }) | | update.js:58:14:58:121 | update.js:58 | update.js:58:14:58:121 | UPDATE` ... , 10)") | -| update.js:59:14:59:125 | update.js:59 | update.js:59:14:59:125 | UPDATE` ... 10)]}` | +| update.js:59:14:59:95 | update.js:59 | update.js:59:14:59:95 | UPDATE` ... ] }, }) | +| update.js:60:14:60:94 | update.js:60 | update.js:60:14:60:94 | UPDATE` ... }] } }) | | update.js:60:14:60:133 | update.js:60 | update.js:60:14:60:133 | UPDATE` ... 11 } }) | +| update.js:62:14:62:46 | update.js:62 | update.js:62:14:62:46 | UPDATE` ... diff }) | | update.js:62:14:62:67 | update.js:62 | update.js:62:14:62:67 | UPDATE` ... "*" }) | +| update.js:63:14:63:46 | update.js:63 | update.js:63:14:63:46 | UPDATE` ... diff }) | | update.js:63:14:63:64 | update.js:63 | update.js:63:14:63:64 | UPDATE` ... 1='*'") | -| update.js:64:14:64:65 | update.js:64 | update.js:64:14:64:65 | UPDATE` ... ${"*"}` | +| update.js:64:14:64:46 | update.js:64 | update.js:64:14:64:46 | UPDATE` ... diff }) | +| update.js:65:14:65:46 | update.js:65 | update.js:65:14:65:46 | UPDATE` ... diff }) | | update.js:65:14:65:66 | update.js:65 | update.js:65:14:65:66 | UPDATE` ... ", "*") | -| update.js:66:14:66:66 | update.js:66 | update.js:66:14:66:66 | UPDATE` ... ${"*"}` | +| update.js:66:14:66:46 | update.js:66 | update.js:66:14:66:46 | UPDATE` ... diff }) | +| update.js:67:14:67:46 | update.js:67 | update.js:67:14:67:46 | UPDATE` ... diff }) | | update.js:67:14:67:73 | update.js:67 | update.js:67:14:67:73 | UPDATE` ... , 10)") | -| update.js:68:14:68:76 | update.js:68 | update.js:68:14:68:76 | UPDATE` ... 10)]}` | +| update.js:68:14:68:46 | update.js:68 | update.js:68:14:68:46 | UPDATE` ... diff }) | +| update.js:69:14:69:46 | update.js:69 | update.js:69:14:69:46 | UPDATE` ... diff }) | | update.js:69:14:69:85 | update.js:69 | update.js:69:14:69:85 | UPDATE` ... 11 } }) | | update.js:72:14:72:81 | update.js:72 | update.js:72:14:72:81 | UPDATE. ... "*" }) | | update.js:73:14:73:78 | update.js:73 | update.js:73:14:73:78 | UPDATE. ... 1='*'") | -| update.js:74:14:74:79 | update.js:74 | update.js:74:14:74:79 | UPDATE. ... ${"*"}` | | update.js:75:14:75:80 | update.js:75 | update.js:75:14:75:80 | UPDATE. ... ", "*") | -| update.js:76:14:76:80 | update.js:76 | update.js:76:14:76:80 | UPDATE. ... ${"*"}` | | update.js:77:14:77:87 | update.js:77 | update.js:77:14:77:87 | UPDATE. ... , 10)") | -| update.js:78:14:78:93 | update.js:78 | update.js:78:14:78:93 | UPDATE. ... 0), ]}` | | update.js:79:14:79:100 | update.js:79 | update.js:79:14:79:100 | UPDATE. ... 1 }, }) | +| update.js:81:14:81:101 | update.js:81 | update.js:81:14:81:101 | UPDATE. ... }] } }) | | update.js:81:14:81:122 | update.js:81 | update.js:81:14:81:122 | UPDATE. ... "*" }) | +| update.js:82:14:82:101 | update.js:82 | update.js:82:14:82:101 | UPDATE. ... }] } }) | | update.js:82:14:82:119 | update.js:82 | update.js:82:14:82:119 | UPDATE. ... 1='*'") | -| update.js:83:14:83:121 | update.js:83 | update.js:83:14:83:121 | UPDATE. ... ${"*"}` | +| update.js:83:14:83:102 | update.js:83 | update.js:83:14:83:102 | UPDATE. ... ] }, }) | +| update.js:84:14:84:101 | update.js:84 | update.js:84:14:84:101 | UPDATE. ... }] } }) | | update.js:84:14:84:121 | update.js:84 | update.js:84:14:84:121 | UPDATE. ... ", "*") | -| update.js:85:14:85:122 | update.js:85 | update.js:85:14:85:122 | UPDATE. ... ${"*"}` | +| update.js:85:14:85:102 | update.js:85 | update.js:85:14:85:102 | UPDATE. ... ] }, }) | +| update.js:86:14:86:101 | update.js:86 | update.js:86:14:86:101 | UPDATE. ... }] } }) | | update.js:86:14:86:128 | update.js:86 | update.js:86:14:86:128 | UPDATE. ... , 10)") | -| update.js:87:14:87:132 | update.js:87 | update.js:87:14:87:132 | UPDATE. ... 10)]}` | +| update.js:87:14:87:102 | update.js:87 | update.js:87:14:87:102 | UPDATE. ... ] }, }) | +| update.js:88:14:88:101 | update.js:88 | update.js:88:14:88:101 | UPDATE. ... }] } }) | | update.js:88:14:88:140 | update.js:88 | update.js:88:14:88:140 | UPDATE. ... 11 } }) | +| update.js:90:14:90:53 | update.js:90 | update.js:90:14:90:53 | UPDATE. ... diff }) | | update.js:90:14:90:74 | update.js:90 | update.js:90:14:90:74 | UPDATE. ... "*" }) | +| update.js:91:14:91:53 | update.js:91 | update.js:91:14:91:53 | UPDATE. ... diff }) | | update.js:91:14:91:71 | update.js:91 | update.js:91:14:91:71 | UPDATE. ... 1='*'") | -| update.js:92:14:92:72 | update.js:92 | update.js:92:14:92:72 | UPDATE. ... ${"*"}` | +| update.js:92:14:92:53 | update.js:92 | update.js:92:14:92:53 | UPDATE. ... diff }) | +| update.js:93:14:93:53 | update.js:93 | update.js:93:14:93:53 | UPDATE. ... diff }) | | update.js:93:14:93:73 | update.js:93 | update.js:93:14:93:73 | UPDATE. ... ", "*") | -| update.js:94:14:94:73 | update.js:94 | update.js:94:14:94:73 | UPDATE. ... ${"*"}` | +| update.js:94:14:94:53 | update.js:94 | update.js:94:14:94:53 | UPDATE. ... diff }) | +| update.js:95:14:95:53 | update.js:95 | update.js:95:14:95:53 | UPDATE. ... diff }) | | update.js:95:14:95:80 | update.js:95 | update.js:95:14:95:80 | UPDATE. ... , 10)") | -| update.js:96:14:96:83 | update.js:96 | update.js:96:14:96:83 | UPDATE. ... 10)]}` | +| update.js:96:14:96:53 | update.js:96 | update.js:96:14:96:53 | UPDATE. ... diff }) | +| update.js:97:14:97:53 | update.js:97 | update.js:97:14:97:53 | UPDATE. ... diff }) | | update.js:97:14:97:92 | update.js:97 | update.js:97:14:97:92 | UPDATE. ... 11 } }) | +| update.js:99:14:99:33 | update.js:99 | update.js:99:14:99:33 | UPDATE.entity(Table) | | update.js:99:14:99:81 | update.js:99 | update.js:99:14:99:81 | UPDATE. ... "*" }) | +| update.js:100:14:100:33 | update.js:100 | update.js:100:14:100:33 | UPDATE.entity(Table) | | update.js:100:14:100:78 | update.js:100 | update.js:100:14:100:78 | UPDATE. ... 1='*'") | -| update.js:101:14:101:79 | update.js:101 | update.js:101:14:101:79 | UPDATE. ... ${"*"}` | +| update.js:101:14:101:33 | update.js:101 | update.js:101:14:101:33 | UPDATE.entity(Table) | +| update.js:102:14:102:33 | update.js:102 | update.js:102:14:102:33 | UPDATE.entity(Table) | | update.js:102:14:102:80 | update.js:102 | update.js:102:14:102:80 | UPDATE. ... ", "*") | -| update.js:103:14:103:80 | update.js:103 | update.js:103:14:103:80 | UPDATE. ... ${"*"}` | +| update.js:103:14:103:33 | update.js:103 | update.js:103:14:103:33 | UPDATE.entity(Table) | +| update.js:104:14:104:33 | update.js:104 | update.js:104:14:104:33 | UPDATE.entity(Table) | | update.js:104:14:104:87 | update.js:104 | update.js:104:14:104:87 | UPDATE. ... , 10)") | -| update.js:105:14:105:93 | update.js:105 | update.js:105:14:105:93 | UPDATE. ... 0), ]}` | +| update.js:105:14:105:33 | update.js:105 | update.js:105:14:105:33 | UPDATE.entity(Table) | +| update.js:106:14:106:33 | update.js:106 | update.js:106:14:106:33 | UPDATE.entity(Table) | | update.js:106:14:106:100 | update.js:106 | update.js:106:14:106:100 | UPDATE. ... 1 }, }) | +| update.js:108:14:108:33 | update.js:108 | update.js:108:14:108:33 | UPDATE.entity(Table) | +| update.js:108:14:108:101 | update.js:108 | update.js:108:14:108:101 | UPDATE. ... }] } }) | | update.js:108:14:108:122 | update.js:108 | update.js:108:14:108:122 | UPDATE. ... "*" }) | +| update.js:109:14:109:33 | update.js:109 | update.js:109:14:109:33 | UPDATE.entity(Table) | +| update.js:109:14:109:101 | update.js:109 | update.js:109:14:109:101 | UPDATE. ... }] } }) | | update.js:109:14:109:119 | update.js:109 | update.js:109:14:109:119 | UPDATE. ... 1='*'") | -| update.js:110:14:110:121 | update.js:110 | update.js:110:14:110:121 | UPDATE. ... ${"*"}` | +| update.js:110:14:110:33 | update.js:110 | update.js:110:14:110:33 | UPDATE.entity(Table) | +| update.js:110:14:110:102 | update.js:110 | update.js:110:14:110:102 | UPDATE. ... ] }, }) | +| update.js:111:14:111:33 | update.js:111 | update.js:111:14:111:33 | UPDATE.entity(Table) | +| update.js:111:14:111:101 | update.js:111 | update.js:111:14:111:101 | UPDATE. ... }] } }) | | update.js:111:14:111:121 | update.js:111 | update.js:111:14:111:121 | UPDATE. ... ", "*") | -| update.js:112:14:112:122 | update.js:112 | update.js:112:14:112:122 | UPDATE. ... ${"*"}` | +| update.js:112:14:112:33 | update.js:112 | update.js:112:14:112:33 | UPDATE.entity(Table) | +| update.js:112:14:112:102 | update.js:112 | update.js:112:14:112:102 | UPDATE. ... ] }, }) | +| update.js:113:14:113:33 | update.js:113 | update.js:113:14:113:33 | UPDATE.entity(Table) | +| update.js:113:14:113:101 | update.js:113 | update.js:113:14:113:101 | UPDATE. ... }] } }) | | update.js:113:14:113:128 | update.js:113 | update.js:113:14:113:128 | UPDATE. ... , 10)") | -| update.js:114:14:114:132 | update.js:114 | update.js:114:14:114:132 | UPDATE. ... 10)]}` | +| update.js:114:14:114:33 | update.js:114 | update.js:114:14:114:33 | UPDATE.entity(Table) | +| update.js:114:14:114:102 | update.js:114 | update.js:114:14:114:102 | UPDATE. ... ] }, }) | +| update.js:115:14:115:33 | update.js:115 | update.js:115:14:115:33 | UPDATE.entity(Table) | +| update.js:115:14:115:101 | update.js:115 | update.js:115:14:115:101 | UPDATE. ... }] } }) | | update.js:115:14:115:140 | update.js:115 | update.js:115:14:115:140 | UPDATE. ... 11 } }) | +| update.js:117:14:117:33 | update.js:117 | update.js:117:14:117:33 | UPDATE.entity(Table) | +| update.js:117:14:117:53 | update.js:117 | update.js:117:14:117:53 | UPDATE. ... diff }) | | update.js:117:14:117:74 | update.js:117 | update.js:117:14:117:74 | UPDATE. ... "*" }) | +| update.js:118:14:118:33 | update.js:118 | update.js:118:14:118:33 | UPDATE.entity(Table) | +| update.js:118:14:118:53 | update.js:118 | update.js:118:14:118:53 | UPDATE. ... diff }) | | update.js:118:14:118:71 | update.js:118 | update.js:118:14:118:71 | UPDATE. ... 1='*'") | -| update.js:119:14:119:72 | update.js:119 | update.js:119:14:119:72 | UPDATE. ... ${"*"}` | +| update.js:119:14:119:33 | update.js:119 | update.js:119:14:119:33 | UPDATE.entity(Table) | +| update.js:119:14:119:53 | update.js:119 | update.js:119:14:119:53 | UPDATE. ... diff }) | +| update.js:120:14:120:33 | update.js:120 | update.js:120:14:120:33 | UPDATE.entity(Table) | +| update.js:120:14:120:53 | update.js:120 | update.js:120:14:120:53 | UPDATE. ... diff }) | | update.js:120:14:120:73 | update.js:120 | update.js:120:14:120:73 | UPDATE. ... ", "*") | -| update.js:121:14:121:73 | update.js:121 | update.js:121:14:121:73 | UPDATE. ... ${"*"}` | +| update.js:121:14:121:33 | update.js:121 | update.js:121:14:121:33 | UPDATE.entity(Table) | +| update.js:121:14:121:53 | update.js:121 | update.js:121:14:121:53 | UPDATE. ... diff }) | +| update.js:122:14:122:33 | update.js:122 | update.js:122:14:122:33 | UPDATE.entity(Table) | +| update.js:122:14:122:53 | update.js:122 | update.js:122:14:122:53 | UPDATE. ... diff }) | | update.js:122:14:122:80 | update.js:122 | update.js:122:14:122:80 | UPDATE. ... , 10)") | -| update.js:123:14:123:83 | update.js:123 | update.js:123:14:123:83 | UPDATE. ... 10)]}` | +| update.js:123:14:123:33 | update.js:123 | update.js:123:14:123:33 | UPDATE.entity(Table) | +| update.js:123:14:123:53 | update.js:123 | update.js:123:14:123:53 | UPDATE. ... diff }) | +| update.js:124:14:124:33 | update.js:124 | update.js:124:14:124:33 | UPDATE.entity(Table) | +| update.js:124:14:124:53 | update.js:124 | update.js:124:14:124:53 | UPDATE. ... diff }) | | update.js:124:14:124:92 | update.js:124 | update.js:124:14:124:92 | UPDATE. ... 11 } }) | +| update.js:126:14:126:35 | update.js:126 | update.js:126:14:126:35 | UPDATE. ... Table") | | update.js:126:14:126:83 | update.js:126 | update.js:126:14:126:83 | UPDATE. ... "*" }) | +| update.js:127:14:127:35 | update.js:127 | update.js:127:14:127:35 | UPDATE. ... Table") | | update.js:127:14:127:80 | update.js:127 | update.js:127:14:127:80 | UPDATE. ... 1='*'") | -| update.js:128:14:128:81 | update.js:128 | update.js:128:14:128:81 | UPDATE. ... ${"*"}` | +| update.js:128:14:128:35 | update.js:128 | update.js:128:14:128:35 | UPDATE. ... Table") | +| update.js:129:14:129:35 | update.js:129 | update.js:129:14:129:35 | UPDATE. ... Table") | | update.js:129:14:129:82 | update.js:129 | update.js:129:14:129:82 | UPDATE. ... ", "*") | -| update.js:130:14:130:82 | update.js:130 | update.js:130:14:130:82 | UPDATE. ... ${"*"}` | +| update.js:130:14:130:35 | update.js:130 | update.js:130:14:130:35 | UPDATE. ... Table") | +| update.js:131:14:131:35 | update.js:131 | update.js:131:14:131:35 | UPDATE. ... Table") | | update.js:131:14:131:89 | update.js:131 | update.js:131:14:131:89 | UPDATE. ... , 10)") | -| update.js:132:14:132:95 | update.js:132 | update.js:132:14:132:95 | UPDATE. ... 0), ]}` | +| update.js:132:14:132:35 | update.js:132 | update.js:132:14:132:35 | UPDATE. ... Table") | +| update.js:133:14:133:35 | update.js:133 | update.js:133:14:133:35 | UPDATE. ... Table") | | update.js:133:14:133:102 | update.js:133 | update.js:133:14:133:102 | UPDATE. ... 1 }, }) | +| update.js:135:14:135:35 | update.js:135 | update.js:135:14:135:35 | UPDATE. ... Table") | +| update.js:135:14:135:103 | update.js:135 | update.js:135:14:135:103 | UPDATE. ... }] } }) | | update.js:135:14:135:124 | update.js:135 | update.js:135:14:135:124 | UPDATE. ... "*" }) | +| update.js:136:14:136:35 | update.js:136 | update.js:136:14:136:35 | UPDATE. ... Table") | +| update.js:136:14:136:103 | update.js:136 | update.js:136:14:136:103 | UPDATE. ... }] } }) | | update.js:136:14:136:121 | update.js:136 | update.js:136:14:136:121 | UPDATE. ... 1='*'") | -| update.js:137:14:137:123 | update.js:137 | update.js:137:14:137:123 | UPDATE. ... ${"*"}` | +| update.js:137:14:137:35 | update.js:137 | update.js:137:14:137:35 | UPDATE. ... Table") | +| update.js:137:14:137:104 | update.js:137 | update.js:137:14:137:104 | UPDATE. ... ] }, }) | +| update.js:138:14:138:35 | update.js:138 | update.js:138:14:138:35 | UPDATE. ... Table") | +| update.js:138:14:138:103 | update.js:138 | update.js:138:14:138:103 | UPDATE. ... }] } }) | | update.js:138:14:138:123 | update.js:138 | update.js:138:14:138:123 | UPDATE. ... ", "*") | -| update.js:139:14:139:124 | update.js:139 | update.js:139:14:139:124 | UPDATE. ... ${"*"}` | +| update.js:139:14:139:35 | update.js:139 | update.js:139:14:139:35 | UPDATE. ... Table") | +| update.js:139:14:139:104 | update.js:139 | update.js:139:14:139:104 | UPDATE. ... ] }, }) | +| update.js:140:14:140:35 | update.js:140 | update.js:140:14:140:35 | UPDATE. ... Table") | +| update.js:140:14:140:103 | update.js:140 | update.js:140:14:140:103 | UPDATE. ... }] } }) | | update.js:140:14:140:130 | update.js:140 | update.js:140:14:140:130 | UPDATE. ... , 10)") | -| update.js:141:14:141:134 | update.js:141 | update.js:141:14:141:134 | UPDATE. ... 10)]}` | +| update.js:141:14:141:35 | update.js:141 | update.js:141:14:141:35 | UPDATE. ... Table") | +| update.js:141:14:141:104 | update.js:141 | update.js:141:14:141:104 | UPDATE. ... ] }, }) | +| update.js:142:14:142:35 | update.js:142 | update.js:142:14:142:35 | UPDATE. ... Table") | +| update.js:142:14:142:103 | update.js:142 | update.js:142:14:142:103 | UPDATE. ... }] } }) | | update.js:142:14:142:142 | update.js:142 | update.js:142:14:142:142 | UPDATE. ... 11 } }) | +| update.js:144:14:144:35 | update.js:144 | update.js:144:14:144:35 | UPDATE. ... Table") | +| update.js:144:14:144:55 | update.js:144 | update.js:144:14:144:55 | UPDATE. ... diff }) | | update.js:144:14:144:76 | update.js:144 | update.js:144:14:144:76 | UPDATE. ... "*" }) | +| update.js:145:14:145:35 | update.js:145 | update.js:145:14:145:35 | UPDATE. ... Table") | +| update.js:145:14:145:55 | update.js:145 | update.js:145:14:145:55 | UPDATE. ... diff }) | | update.js:145:14:145:73 | update.js:145 | update.js:145:14:145:73 | UPDATE. ... 1='*'") | -| update.js:146:14:146:74 | update.js:146 | update.js:146:14:146:74 | UPDATE. ... ${"*"}` | +| update.js:146:14:146:35 | update.js:146 | update.js:146:14:146:35 | UPDATE. ... Table") | +| update.js:146:14:146:55 | update.js:146 | update.js:146:14:146:55 | UPDATE. ... diff }) | +| update.js:147:14:147:35 | update.js:147 | update.js:147:14:147:35 | UPDATE. ... Table") | +| update.js:147:14:147:55 | update.js:147 | update.js:147:14:147:55 | UPDATE. ... diff }) | | update.js:147:14:147:75 | update.js:147 | update.js:147:14:147:75 | UPDATE. ... ", "*") | -| update.js:148:14:148:75 | update.js:148 | update.js:148:14:148:75 | UPDATE. ... ${"*"}` | +| update.js:148:14:148:35 | update.js:148 | update.js:148:14:148:35 | UPDATE. ... Table") | +| update.js:148:14:148:55 | update.js:148 | update.js:148:14:148:55 | UPDATE. ... diff }) | +| update.js:149:14:149:35 | update.js:149 | update.js:149:14:149:35 | UPDATE. ... Table") | +| update.js:149:14:149:55 | update.js:149 | update.js:149:14:149:55 | UPDATE. ... diff }) | | update.js:149:14:149:82 | update.js:149 | update.js:149:14:149:82 | UPDATE. ... , 10)") | -| update.js:150:14:150:85 | update.js:150 | update.js:150:14:150:85 | UPDATE. ... 10)]}` | +| update.js:150:14:150:35 | update.js:150 | update.js:150:14:150:35 | UPDATE. ... Table") | +| update.js:150:14:150:55 | update.js:150 | update.js:150:14:150:55 | UPDATE. ... diff }) | +| update.js:151:14:151:35 | update.js:151 | update.js:151:14:151:35 | UPDATE. ... Table") | +| update.js:151:14:151:55 | update.js:151 | update.js:151:14:151:55 | UPDATE. ... diff }) | | update.js:151:14:151:94 | update.js:151 | update.js:151:14:151:94 | UPDATE. ... 11 } }) | | update.js:156:14:156:75 | update.js:156 | update.js:156:14:156:75 | UPDATE` ... "*" }) | | update.js:157:14:157:72 | update.js:157 | update.js:157:14:157:72 | UPDATE` ... 1='*'") | -| update.js:158:14:158:73 | update.js:158 | update.js:158:14:158:73 | UPDATE` ... ${"*"}` | | update.js:159:14:159:74 | update.js:159 | update.js:159:14:159:74 | UPDATE` ... ", "*") | -| update.js:160:14:160:74 | update.js:160 | update.js:160:14:160:74 | UPDATE` ... ${"*"}` | | update.js:161:14:161:81 | update.js:161 | update.js:161:14:161:81 | UPDATE` ... , 10)") | -| update.js:162:14:162:87 | update.js:162 | update.js:162:14:162:87 | UPDATE` ... 0), ]}` | | update.js:163:14:163:94 | update.js:163 | update.js:163:14:163:94 | UPDATE` ... 1 }, }) | +| update.js:165:14:165:95 | update.js:165 | update.js:165:14:165:95 | UPDATE` ... }] } }) | | update.js:165:14:165:116 | update.js:165 | update.js:165:14:165:116 | UPDATE` ... "*" }) | +| update.js:166:14:166:95 | update.js:166 | update.js:166:14:166:95 | UPDATE` ... }] } }) | | update.js:166:14:166:113 | update.js:166 | update.js:166:14:166:113 | UPDATE` ... 1='*'") | -| update.js:167:14:167:115 | update.js:167 | update.js:167:14:167:115 | UPDATE` ... ${"*"}` | +| update.js:167:14:167:96 | update.js:167 | update.js:167:14:167:96 | UPDATE` ... ] }, }) | +| update.js:168:14:168:95 | update.js:168 | update.js:168:14:168:95 | UPDATE` ... }] } }) | | update.js:168:14:168:115 | update.js:168 | update.js:168:14:168:115 | UPDATE` ... ", "*") | -| update.js:169:14:169:116 | update.js:169 | update.js:169:14:169:116 | UPDATE` ... ${"*"}` | +| update.js:169:14:169:96 | update.js:169 | update.js:169:14:169:96 | UPDATE` ... ] }, }) | +| update.js:170:14:170:95 | update.js:170 | update.js:170:14:170:95 | UPDATE` ... }] } }) | | update.js:170:14:170:122 | update.js:170 | update.js:170:14:170:122 | UPDATE` ... , 10)") | -| update.js:171:14:171:126 | update.js:171 | update.js:171:14:171:126 | UPDATE` ... 10)]}` | +| update.js:171:14:171:96 | update.js:171 | update.js:171:14:171:96 | UPDATE` ... ] }, }) | +| update.js:172:14:172:95 | update.js:172 | update.js:172:14:172:95 | UPDATE` ... }] } }) | | update.js:172:14:172:134 | update.js:172 | update.js:172:14:172:134 | UPDATE` ... 11 } }) | +| update.js:174:14:174:47 | update.js:174 | update.js:174:14:174:47 | UPDATE` ... diff }) | | update.js:174:14:174:68 | update.js:174 | update.js:174:14:174:68 | UPDATE` ... "*" }) | +| update.js:175:14:175:47 | update.js:175 | update.js:175:14:175:47 | UPDATE` ... diff }) | | update.js:175:14:175:65 | update.js:175 | update.js:175:14:175:65 | UPDATE` ... 1='*'") | -| update.js:176:14:176:66 | update.js:176 | update.js:176:14:176:66 | UPDATE` ... ${"*"}` | +| update.js:176:14:176:47 | update.js:176 | update.js:176:14:176:47 | UPDATE` ... diff }) | +| update.js:177:14:177:47 | update.js:177 | update.js:177:14:177:47 | UPDATE` ... diff }) | | update.js:177:14:177:67 | update.js:177 | update.js:177:14:177:67 | UPDATE` ... ", "*") | -| update.js:178:14:178:67 | update.js:178 | update.js:178:14:178:67 | UPDATE` ... ${"*"}` | +| update.js:178:14:178:47 | update.js:178 | update.js:178:14:178:47 | UPDATE` ... diff }) | +| update.js:179:14:179:47 | update.js:179 | update.js:179:14:179:47 | UPDATE` ... diff }) | | update.js:179:14:179:74 | update.js:179 | update.js:179:14:179:74 | UPDATE` ... , 10)") | -| update.js:180:14:180:77 | update.js:180 | update.js:180:14:180:77 | UPDATE` ... 10)]}` | +| update.js:180:14:180:47 | update.js:180 | update.js:180:14:180:47 | UPDATE` ... diff }) | +| update.js:181:14:181:47 | update.js:181 | update.js:181:14:181:47 | UPDATE` ... diff }) | | update.js:181:14:181:86 | update.js:181 | update.js:181:14:181:86 | UPDATE` ... 11 } }) | | update.js:184:14:184:82 | update.js:184 | update.js:184:14:184:82 | UPDATE. ... "*" }) | | update.js:185:14:185:79 | update.js:185 | update.js:185:14:185:79 | UPDATE. ... 1='*'") | -| update.js:186:14:186:80 | update.js:186 | update.js:186:14:186:80 | UPDATE. ... ${"*"}` | | update.js:187:14:187:81 | update.js:187 | update.js:187:14:187:81 | UPDATE. ... ", "*") | -| update.js:188:14:188:81 | update.js:188 | update.js:188:14:188:81 | UPDATE. ... ${"*"}` | | update.js:189:14:189:88 | update.js:189 | update.js:189:14:189:88 | UPDATE. ... , 10)") | -| update.js:190:14:190:94 | update.js:190 | update.js:190:14:190:94 | UPDATE. ... 0), ]}` | | update.js:191:14:191:101 | update.js:191 | update.js:191:14:191:101 | UPDATE. ... 1 }, }) | +| update.js:193:14:193:102 | update.js:193 | update.js:193:14:193:102 | UPDATE. ... }] } }) | | update.js:193:14:193:123 | update.js:193 | update.js:193:14:193:123 | UPDATE. ... "*" }) | +| update.js:194:14:194:102 | update.js:194 | update.js:194:14:194:102 | UPDATE. ... }] } }) | | update.js:194:14:194:120 | update.js:194 | update.js:194:14:194:120 | UPDATE. ... 1='*'") | -| update.js:195:14:195:122 | update.js:195 | update.js:195:14:195:122 | UPDATE. ... ${"*"}` | +| update.js:195:14:195:103 | update.js:195 | update.js:195:14:195:103 | UPDATE. ... ] }, }) | +| update.js:196:14:196:102 | update.js:196 | update.js:196:14:196:102 | UPDATE. ... }] } }) | | update.js:196:14:196:122 | update.js:196 | update.js:196:14:196:122 | UPDATE. ... ", "*") | -| update.js:197:14:197:123 | update.js:197 | update.js:197:14:197:123 | UPDATE. ... ${"*"}` | +| update.js:197:14:197:103 | update.js:197 | update.js:197:14:197:103 | UPDATE. ... ] }, }) | +| update.js:198:14:198:102 | update.js:198 | update.js:198:14:198:102 | UPDATE. ... }] } }) | | update.js:198:14:198:129 | update.js:198 | update.js:198:14:198:129 | UPDATE. ... , 10)") | -| update.js:199:14:199:133 | update.js:199 | update.js:199:14:199:133 | UPDATE. ... 10)]}` | +| update.js:199:14:199:103 | update.js:199 | update.js:199:14:199:103 | UPDATE. ... ] }, }) | +| update.js:200:14:200:102 | update.js:200 | update.js:200:14:200:102 | UPDATE. ... }] } }) | | update.js:200:14:200:141 | update.js:200 | update.js:200:14:200:141 | UPDATE. ... 11 } }) | +| update.js:202:14:202:54 | update.js:202 | update.js:202:14:202:54 | UPDATE. ... diff }) | | update.js:202:14:202:75 | update.js:202 | update.js:202:14:202:75 | UPDATE. ... "*" }) | +| update.js:203:14:203:54 | update.js:203 | update.js:203:14:203:54 | UPDATE. ... diff }) | | update.js:203:14:203:72 | update.js:203 | update.js:203:14:203:72 | UPDATE. ... 1='*'") | -| update.js:204:14:204:73 | update.js:204 | update.js:204:14:204:73 | UPDATE. ... ${"*"}` | +| update.js:204:14:204:54 | update.js:204 | update.js:204:14:204:54 | UPDATE. ... diff }) | +| update.js:205:14:205:54 | update.js:205 | update.js:205:14:205:54 | UPDATE. ... diff }) | | update.js:205:14:205:74 | update.js:205 | update.js:205:14:205:74 | UPDATE. ... ", "*") | -| update.js:206:14:206:74 | update.js:206 | update.js:206:14:206:74 | UPDATE. ... ${"*"}` | +| update.js:206:14:206:54 | update.js:206 | update.js:206:14:206:54 | UPDATE. ... diff }) | +| update.js:207:14:207:54 | update.js:207 | update.js:207:14:207:54 | UPDATE. ... diff }) | | update.js:207:14:207:81 | update.js:207 | update.js:207:14:207:81 | UPDATE. ... , 10)") | -| update.js:208:14:208:84 | update.js:208 | update.js:208:14:208:84 | UPDATE. ... 10)]}` | +| update.js:208:14:208:54 | update.js:208 | update.js:208:14:208:54 | UPDATE. ... diff }) | +| update.js:209:14:209:54 | update.js:209 | update.js:209:14:209:54 | UPDATE. ... diff }) | | update.js:209:14:209:93 | update.js:209 | update.js:209:14:209:93 | UPDATE. ... 11 } }) | +| update.js:211:14:211:33 | update.js:211 | update.js:211:14:211:33 | UPDATE.entity(Table) | | update.js:211:14:211:82 | update.js:211 | update.js:211:14:211:82 | UPDATE. ... "*" }) | +| update.js:212:14:212:33 | update.js:212 | update.js:212:14:212:33 | UPDATE.entity(Table) | | update.js:212:14:212:79 | update.js:212 | update.js:212:14:212:79 | UPDATE. ... 1='*'") | -| update.js:213:14:213:80 | update.js:213 | update.js:213:14:213:80 | UPDATE. ... ${"*"}` | +| update.js:213:14:213:33 | update.js:213 | update.js:213:14:213:33 | UPDATE.entity(Table) | +| update.js:214:14:214:33 | update.js:214 | update.js:214:14:214:33 | UPDATE.entity(Table) | | update.js:214:14:214:81 | update.js:214 | update.js:214:14:214:81 | UPDATE. ... ", "*") | -| update.js:215:14:215:81 | update.js:215 | update.js:215:14:215:81 | UPDATE. ... ${"*"}` | +| update.js:215:14:215:33 | update.js:215 | update.js:215:14:215:33 | UPDATE.entity(Table) | +| update.js:216:14:216:33 | update.js:216 | update.js:216:14:216:33 | UPDATE.entity(Table) | | update.js:216:14:216:88 | update.js:216 | update.js:216:14:216:88 | UPDATE. ... , 10)") | -| update.js:217:14:217:94 | update.js:217 | update.js:217:14:217:94 | UPDATE. ... 0), ]}` | +| update.js:217:14:217:33 | update.js:217 | update.js:217:14:217:33 | UPDATE.entity(Table) | +| update.js:218:14:218:33 | update.js:218 | update.js:218:14:218:33 | UPDATE.entity(Table) | | update.js:218:14:218:101 | update.js:218 | update.js:218:14:218:101 | UPDATE. ... 1 }, }) | +| update.js:220:14:220:33 | update.js:220 | update.js:220:14:220:33 | UPDATE.entity(Table) | +| update.js:220:14:220:102 | update.js:220 | update.js:220:14:220:102 | UPDATE. ... }] } }) | | update.js:220:14:220:123 | update.js:220 | update.js:220:14:220:123 | UPDATE. ... "*" }) | +| update.js:221:14:221:33 | update.js:221 | update.js:221:14:221:33 | UPDATE.entity(Table) | +| update.js:221:14:221:102 | update.js:221 | update.js:221:14:221:102 | UPDATE. ... }] } }) | | update.js:221:14:221:120 | update.js:221 | update.js:221:14:221:120 | UPDATE. ... 1='*'") | -| update.js:222:14:222:122 | update.js:222 | update.js:222:14:222:122 | UPDATE. ... ${"*"}` | +| update.js:222:14:222:33 | update.js:222 | update.js:222:14:222:33 | UPDATE.entity(Table) | +| update.js:222:14:222:103 | update.js:222 | update.js:222:14:222:103 | UPDATE. ... ] }, }) | +| update.js:223:14:223:33 | update.js:223 | update.js:223:14:223:33 | UPDATE.entity(Table) | +| update.js:223:14:223:102 | update.js:223 | update.js:223:14:223:102 | UPDATE. ... }] } }) | | update.js:223:14:223:122 | update.js:223 | update.js:223:14:223:122 | UPDATE. ... ", "*") | -| update.js:224:14:224:123 | update.js:224 | update.js:224:14:224:123 | UPDATE. ... ${"*"}` | +| update.js:224:14:224:33 | update.js:224 | update.js:224:14:224:33 | UPDATE.entity(Table) | +| update.js:224:14:224:103 | update.js:224 | update.js:224:14:224:103 | UPDATE. ... ] }, }) | +| update.js:225:14:225:33 | update.js:225 | update.js:225:14:225:33 | UPDATE.entity(Table) | +| update.js:225:14:225:102 | update.js:225 | update.js:225:14:225:102 | UPDATE. ... }] } }) | | update.js:225:14:225:129 | update.js:225 | update.js:225:14:225:129 | UPDATE. ... , 10)") | -| update.js:226:14:226:133 | update.js:226 | update.js:226:14:226:133 | UPDATE. ... 10)]}` | +| update.js:226:14:226:33 | update.js:226 | update.js:226:14:226:33 | UPDATE.entity(Table) | +| update.js:226:14:226:103 | update.js:226 | update.js:226:14:226:103 | UPDATE. ... ] }, }) | +| update.js:227:14:227:33 | update.js:227 | update.js:227:14:227:33 | UPDATE.entity(Table) | +| update.js:227:14:227:102 | update.js:227 | update.js:227:14:227:102 | UPDATE. ... }] } }) | | update.js:227:14:227:141 | update.js:227 | update.js:227:14:227:141 | UPDATE. ... 11 } }) | +| update.js:229:14:229:33 | update.js:229 | update.js:229:14:229:33 | UPDATE.entity(Table) | +| update.js:229:14:229:54 | update.js:229 | update.js:229:14:229:54 | UPDATE. ... diff }) | | update.js:229:14:229:75 | update.js:229 | update.js:229:14:229:75 | UPDATE. ... "*" }) | +| update.js:230:14:230:33 | update.js:230 | update.js:230:14:230:33 | UPDATE.entity(Table) | +| update.js:230:14:230:54 | update.js:230 | update.js:230:14:230:54 | UPDATE. ... diff }) | | update.js:230:14:230:72 | update.js:230 | update.js:230:14:230:72 | UPDATE. ... 1='*'") | -| update.js:231:14:231:73 | update.js:231 | update.js:231:14:231:73 | UPDATE. ... ${"*"}` | +| update.js:231:14:231:33 | update.js:231 | update.js:231:14:231:33 | UPDATE.entity(Table) | +| update.js:231:14:231:54 | update.js:231 | update.js:231:14:231:54 | UPDATE. ... diff }) | +| update.js:232:14:232:33 | update.js:232 | update.js:232:14:232:33 | UPDATE.entity(Table) | +| update.js:232:14:232:54 | update.js:232 | update.js:232:14:232:54 | UPDATE. ... diff }) | | update.js:232:14:232:74 | update.js:232 | update.js:232:14:232:74 | UPDATE. ... ", "*") | -| update.js:233:14:233:74 | update.js:233 | update.js:233:14:233:74 | UPDATE. ... ${"*"}` | +| update.js:233:14:233:33 | update.js:233 | update.js:233:14:233:33 | UPDATE.entity(Table) | +| update.js:233:14:233:54 | update.js:233 | update.js:233:14:233:54 | UPDATE. ... diff }) | +| update.js:234:14:234:33 | update.js:234 | update.js:234:14:234:33 | UPDATE.entity(Table) | +| update.js:234:14:234:54 | update.js:234 | update.js:234:14:234:54 | UPDATE. ... diff }) | | update.js:234:14:234:81 | update.js:234 | update.js:234:14:234:81 | UPDATE. ... , 10)") | -| update.js:235:14:235:84 | update.js:235 | update.js:235:14:235:84 | UPDATE. ... 10)]}` | +| update.js:235:14:235:33 | update.js:235 | update.js:235:14:235:33 | UPDATE.entity(Table) | +| update.js:235:14:235:54 | update.js:235 | update.js:235:14:235:54 | UPDATE. ... diff }) | +| update.js:236:14:236:33 | update.js:236 | update.js:236:14:236:33 | UPDATE.entity(Table) | +| update.js:236:14:236:54 | update.js:236 | update.js:236:14:236:54 | UPDATE. ... diff }) | | update.js:236:14:236:93 | update.js:236 | update.js:236:14:236:93 | UPDATE. ... 11 } }) | +| update.js:238:14:238:35 | update.js:238 | update.js:238:14:238:35 | UPDATE. ... Table") | | update.js:238:14:238:84 | update.js:238 | update.js:238:14:238:84 | UPDATE. ... "*" }) | +| update.js:239:14:239:35 | update.js:239 | update.js:239:14:239:35 | UPDATE. ... Table") | | update.js:239:14:239:81 | update.js:239 | update.js:239:14:239:81 | UPDATE. ... 1='*'") | -| update.js:240:14:240:82 | update.js:240 | update.js:240:14:240:82 | UPDATE. ... ${"*"}` | +| update.js:240:14:240:35 | update.js:240 | update.js:240:14:240:35 | UPDATE. ... Table") | +| update.js:241:14:241:35 | update.js:241 | update.js:241:14:241:35 | UPDATE. ... Table") | | update.js:241:14:241:83 | update.js:241 | update.js:241:14:241:83 | UPDATE. ... ", "*") | -| update.js:242:14:242:83 | update.js:242 | update.js:242:14:242:83 | UPDATE. ... ${"*"}` | +| update.js:242:14:242:35 | update.js:242 | update.js:242:14:242:35 | UPDATE. ... Table") | +| update.js:243:14:243:35 | update.js:243 | update.js:243:14:243:35 | UPDATE. ... Table") | | update.js:243:14:243:90 | update.js:243 | update.js:243:14:243:90 | UPDATE. ... , 10)") | -| update.js:244:14:244:96 | update.js:244 | update.js:244:14:244:96 | UPDATE. ... 0), ]}` | +| update.js:244:14:244:35 | update.js:244 | update.js:244:14:244:35 | UPDATE. ... Table") | +| update.js:245:14:245:35 | update.js:245 | update.js:245:14:245:35 | UPDATE. ... Table") | | update.js:245:14:245:103 | update.js:245 | update.js:245:14:245:103 | UPDATE. ... 1 }, }) | +| update.js:247:14:247:35 | update.js:247 | update.js:247:14:247:35 | UPDATE. ... Table") | +| update.js:247:14:247:104 | update.js:247 | update.js:247:14:247:104 | UPDATE. ... }] } }) | | update.js:247:14:247:125 | update.js:247 | update.js:247:14:247:125 | UPDATE. ... "*" }) | +| update.js:248:14:248:35 | update.js:248 | update.js:248:14:248:35 | UPDATE. ... Table") | +| update.js:248:14:248:104 | update.js:248 | update.js:248:14:248:104 | UPDATE. ... }] } }) | | update.js:248:14:248:122 | update.js:248 | update.js:248:14:248:122 | UPDATE. ... 1='*'") | -| update.js:249:14:249:124 | update.js:249 | update.js:249:14:249:124 | UPDATE. ... ${"*"}` | +| update.js:249:14:249:35 | update.js:249 | update.js:249:14:249:35 | UPDATE. ... Table") | +| update.js:249:14:249:105 | update.js:249 | update.js:249:14:249:105 | UPDATE. ... ] }, }) | +| update.js:250:14:250:35 | update.js:250 | update.js:250:14:250:35 | UPDATE. ... Table") | +| update.js:250:14:250:104 | update.js:250 | update.js:250:14:250:104 | UPDATE. ... }] } }) | | update.js:250:14:250:124 | update.js:250 | update.js:250:14:250:124 | UPDATE. ... ", "*") | -| update.js:251:14:251:125 | update.js:251 | update.js:251:14:251:125 | UPDATE. ... ${"*"}` | +| update.js:251:14:251:35 | update.js:251 | update.js:251:14:251:35 | UPDATE. ... Table") | +| update.js:251:14:251:105 | update.js:251 | update.js:251:14:251:105 | UPDATE. ... ] }, }) | +| update.js:252:14:252:35 | update.js:252 | update.js:252:14:252:35 | UPDATE. ... Table") | +| update.js:252:14:252:104 | update.js:252 | update.js:252:14:252:104 | UPDATE. ... }] } }) | | update.js:252:14:252:131 | update.js:252 | update.js:252:14:252:131 | UPDATE. ... , 10)") | -| update.js:253:14:253:135 | update.js:253 | update.js:253:14:253:135 | UPDATE. ... 10)]}` | +| update.js:253:14:253:35 | update.js:253 | update.js:253:14:253:35 | UPDATE. ... Table") | +| update.js:253:14:253:105 | update.js:253 | update.js:253:14:253:105 | UPDATE. ... ] }, }) | +| update.js:254:14:254:35 | update.js:254 | update.js:254:14:254:35 | UPDATE. ... Table") | +| update.js:254:14:254:104 | update.js:254 | update.js:254:14:254:104 | UPDATE. ... }] } }) | | update.js:254:14:254:143 | update.js:254 | update.js:254:14:254:143 | UPDATE. ... 11 } }) | +| update.js:256:14:256:35 | update.js:256 | update.js:256:14:256:35 | UPDATE. ... Table") | +| update.js:256:14:256:56 | update.js:256 | update.js:256:14:256:56 | UPDATE. ... diff }) | | update.js:256:14:256:77 | update.js:256 | update.js:256:14:256:77 | UPDATE. ... "*" }) | +| update.js:257:14:257:35 | update.js:257 | update.js:257:14:257:35 | UPDATE. ... Table") | +| update.js:257:14:257:56 | update.js:257 | update.js:257:14:257:56 | UPDATE. ... diff }) | | update.js:257:14:257:74 | update.js:257 | update.js:257:14:257:74 | UPDATE. ... 1='*'") | -| update.js:258:14:258:75 | update.js:258 | update.js:258:14:258:75 | UPDATE. ... ${"*"}` | +| update.js:258:14:258:35 | update.js:258 | update.js:258:14:258:35 | UPDATE. ... Table") | +| update.js:258:14:258:56 | update.js:258 | update.js:258:14:258:56 | UPDATE. ... diff }) | +| update.js:259:14:259:35 | update.js:259 | update.js:259:14:259:35 | UPDATE. ... Table") | +| update.js:259:14:259:56 | update.js:259 | update.js:259:14:259:56 | UPDATE. ... diff }) | | update.js:259:14:259:76 | update.js:259 | update.js:259:14:259:76 | UPDATE. ... ", "*") | -| update.js:260:14:260:76 | update.js:260 | update.js:260:14:260:76 | UPDATE. ... ${"*"}` | +| update.js:260:14:260:35 | update.js:260 | update.js:260:14:260:35 | UPDATE. ... Table") | +| update.js:260:14:260:56 | update.js:260 | update.js:260:14:260:56 | UPDATE. ... diff }) | +| update.js:261:14:261:35 | update.js:261 | update.js:261:14:261:35 | UPDATE. ... Table") | +| update.js:261:14:261:56 | update.js:261 | update.js:261:14:261:56 | UPDATE. ... diff }) | | update.js:261:14:261:83 | update.js:261 | update.js:261:14:261:83 | UPDATE. ... , 10)") | -| update.js:262:14:262:86 | update.js:262 | update.js:262:14:262:86 | UPDATE. ... 10)]}` | +| update.js:262:14:262:35 | update.js:262 | update.js:262:14:262:35 | UPDATE. ... Table") | +| update.js:262:14:262:56 | update.js:262 | update.js:262:14:262:56 | UPDATE. ... diff }) | +| update.js:263:14:263:35 | update.js:263 | update.js:263:14:263:35 | UPDATE. ... Table") | +| update.js:263:14:263:56 | update.js:263 | update.js:263:14:263:56 | UPDATE. ... diff }) | | update.js:263:14:263:95 | update.js:263 | update.js:263:14:263:95 | UPDATE. ... 11 } }) | diff --git a/javascript/frameworks/cap/test/models/cql/update/update.ql b/javascript/frameworks/cap/test/models/cql/update/update.ql index 88e3ea481..2c7551107 100644 --- a/javascript/frameworks/cap/test/models/cql/update/update.ql +++ b/javascript/frameworks/cap/test/models/cql/update/update.ql @@ -1,6 +1,6 @@ import javascript import advanced_security.javascript.frameworks.cap.CQL -from CQL::CqlUpdateExpr s +from CQL::CqlClause s select s.getLocation(), s diff --git a/javascript/frameworks/cap/test/models/cql/upsert/upsert.expected b/javascript/frameworks/cap/test/models/cql/upsert/upsert.expected index 69a2e7bb7..39a552845 100644 --- a/javascript/frameworks/cap/test/models/cql/upsert/upsert.expected +++ b/javascript/frameworks/cap/test/models/cql/upsert/upsert.expected @@ -1,10 +1,16 @@ +| upsert.js:2:14:5:2 | upsert.js:2 | upsert.js:2:14:5:2 | UPSERT( ... " },\\n]) | | upsert.js:2:14:5:14 | upsert.js:2 | upsert.js:2:14:5:14 | UPSERT( ... (Table) | +| upsert.js:6:14:9:2 | upsert.js:6 | upsert.js:6:14:9:2 | UPSERT( ... " },\\n]) | | upsert.js:6:14:9:16 | upsert.js:6 | upsert.js:6:14:9:16 | UPSERT( ... Table") | | upsert.js:11:14:14:2 | upsert.js:11 | upsert.js:11:14:14:2 | UPSERT. ... " },\\n]) | | upsert.js:15:14:18:2 | upsert.js:15 | upsert.js:15:14:18:2 | UPSERT. ... " },\\n]) | +| upsert.js:21:14:21:31 | upsert.js:21 | upsert.js:21:14:21:31 | UPSERT.into(Table) | | upsert.js:21:14:24:1 | upsert.js:21 | upsert.js:21:14:24:1 | UPSERT. ... 22" }\\n) | +| upsert.js:25:14:25:31 | upsert.js:25 | upsert.js:25:14:25:31 | UPSERT.into(Table) | | upsert.js:25:14:28:2 | upsert.js:25 | upsert.js:25:14:28:2 | UPSERT. ... " },\\n]) | +| upsert.js:29:14:29:33 | upsert.js:29 | upsert.js:29:14:29:33 | UPSERT.into("Table") | | upsert.js:29:14:32:2 | upsert.js:29 | upsert.js:29:14:32:2 | UPSERT. ... " },\\n]) | +| upsert.js:33:14:33:33 | upsert.js:33 | upsert.js:33:14:33:33 | UPSERT.into("Table") | | upsert.js:33:14:36:2 | upsert.js:33 | upsert.js:33:14:36:2 | UPSERT. ... " },\\n]) | | upsert.js:37:14:40:2 | upsert.js:37 | upsert.js:37:14:40:2 | UPSERT. ... " },\\n]) | | upsert.js:41:14:44:2 | upsert.js:41 | upsert.js:41:14:44:2 | UPSERT. ... " },\\n]) | diff --git a/javascript/frameworks/cap/test/models/cql/upsert/upsert.ql b/javascript/frameworks/cap/test/models/cql/upsert/upsert.ql index 156736ca7..2c7551107 100644 --- a/javascript/frameworks/cap/test/models/cql/upsert/upsert.ql +++ b/javascript/frameworks/cap/test/models/cql/upsert/upsert.ql @@ -1,6 +1,6 @@ import javascript import advanced_security.javascript.frameworks.cap.CQL -from CQL::CqlUpsertExpr s +from CQL::CqlClause s select s.getLocation(), s diff --git a/javascript/frameworks/cap/test/models/queries/sqlinjection.expected b/javascript/frameworks/cap/test/models/queries/sqlinjection.expected new file mode 100644 index 000000000..1126707f9 --- /dev/null +++ b/javascript/frameworks/cap/test/models/queries/sqlinjection.expected @@ -0,0 +1,2 @@ +| sqlinjection.js:13:35:13:39 | query | Injection vulnerability found. | +| sqlinjection.js:16:36:16:41 | query2 | Injection vulnerability found. | diff --git a/javascript/frameworks/cap/test/models/queries/sqlinjection.js b/javascript/frameworks/cap/test/models/queries/sqlinjection.js new file mode 100644 index 000000000..0f0e4211f --- /dev/null +++ b/javascript/frameworks/cap/test/models/queries/sqlinjection.js @@ -0,0 +1,23 @@ +import cds from '@sap/cds' +const { Books } = cds.entities ('sap.capire.bookshop') + +class SampleVulnService extends cds.ApplicationService { init(){ + + // contains a sample sql injection + this.on ('submitOrder', async req => { + const {book,quantity} = req.data + + let {stock} = await SELECT `stock` .from (Books,book) //alert? + + let query = SELECT.from `Books` .where (`ID=${book}`) + let books = await cds.db.run (query) //alert + + let query2 = SELECT.from `Books` .where ('ID='+book) + let books2 = await cds.db.run (query2) //alert + + let books3 = await SELECT.from `Books` .where `ID=${book}` //safe + }) + + return super.init() +}} +export { SampleVulnService } diff --git a/javascript/frameworks/cap/test/models/queries/sqlinjection.qlref b/javascript/frameworks/cap/test/models/queries/sqlinjection.qlref new file mode 100644 index 000000000..915158d38 --- /dev/null +++ b/javascript/frameworks/cap/test/models/queries/sqlinjection.qlref @@ -0,0 +1 @@ +sqlinjection/Sqlinjection.ql \ No newline at end of file From f774013a719d066c5dec878b3016028d1fa1f7fb Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Sun, 14 Jan 2024 21:32:30 -0500 Subject: [PATCH 57/61] Improve cap sql model add extra sink for await on sql stmt and improve test for that also add metadata to query --- .../javascript/frameworks/cap/CQL.qll | 5 ++++- .../frameworks/cap/src/sqlinjection/SqlInjection.ql | 12 ++++++++++++ .../cap/test/models/queries/sqlinjection.js | 4 ++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll index 2a861354d..3c184d1e2 100644 --- a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll @@ -214,11 +214,14 @@ class CqlClause extends TCqlClause { /** * Call to`cds.db.run` + * or + * an await surrounding a sql statement */ -//TODO: add awaits around SQLClauses class CQLSink extends DataFlow::Node { CQLSink(){ this = any(CdsFacade cds).getMember("db").getMember("run").getACall().getAnArgument() + or + exists(AwaitExpr a, CQL::CqlClause clause | a.getAChildExpr() = clause.asExpr() and this.asExpr() = clause.asExpr()) } } diff --git a/javascript/frameworks/cap/src/sqlinjection/SqlInjection.ql b/javascript/frameworks/cap/src/sqlinjection/SqlInjection.ql index 66eef62b6..174ddcda1 100644 --- a/javascript/frameworks/cap/src/sqlinjection/SqlInjection.ql +++ b/javascript/frameworks/cap/src/sqlinjection/SqlInjection.ql @@ -1,3 +1,15 @@ +/** + * @name Uncontrolled data in SQL query + * @description Including user-supplied data in a SQL query without + * neutralizing special elements can make code vulnerable + * to SQL Injection. + * @kind problem + * @problem.severity error + * @id javascript/sql-injection-custom + * @tags security + * external/cwe/cwe-089 + */ + import javascript import advanced_security.javascript.frameworks.cap.CDS import advanced_security.javascript.frameworks.cap.CQL diff --git a/javascript/frameworks/cap/test/models/queries/sqlinjection.js b/javascript/frameworks/cap/test/models/queries/sqlinjection.js index 0f0e4211f..acc2f7357 100644 --- a/javascript/frameworks/cap/test/models/queries/sqlinjection.js +++ b/javascript/frameworks/cap/test/models/queries/sqlinjection.js @@ -12,9 +12,13 @@ class SampleVulnService extends cds.ApplicationService { init(){ let query = SELECT.from `Books` .where (`ID=${book}`) let books = await cds.db.run (query) //alert + let books11 = await SELECT.from `Books` .where (`ID=${book}`) //alert + let query2 = SELECT.from `Books` .where ('ID='+book) let books2 = await cds.db.run (query2) //alert + let books22 = await SELECT.from `Books` .where ('ID='+book) //alert + let books3 = await SELECT.from `Books` .where `ID=${book}` //safe }) From baae66b7df76a11e955cef8b4133980f59ac6820 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Mon, 15 Jan 2024 22:18:30 -0500 Subject: [PATCH 58/61] Improve cap cql taint steps and testing --- .../javascript/frameworks/cap/CQL.qll | 31 ++++++++++++++++++- .../cap/src/sqlinjection/SqlInjection.ql | 11 ++++--- .../test/models/cql/select/select.expected | 3 +- .../cap/test/models/cql/select/select.js | 3 -- .../cap/test/models/cql/select/select2.js | 14 ++++----- .../cql/taintedclause/taintedclause.expected | 1 + .../models/cql/taintedclause/taintedclause.js | 5 +++ .../models/cql/taintedclause/taintedclause.ql | 5 +++ .../test/models/queries/sqlinjection.expected | 6 +++- .../cap/test/models/queries/sqlinjection.js | 9 ++++++ 10 files changed, 71 insertions(+), 17 deletions(-) create mode 100644 javascript/frameworks/cap/test/models/cql/taintedclause/taintedclause.expected create mode 100644 javascript/frameworks/cap/test/models/cql/taintedclause/taintedclause.js create mode 100644 javascript/frameworks/cap/test/models/cql/taintedclause/taintedclause.ql diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll index 3c184d1e2..da0340496 100644 --- a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll @@ -212,6 +212,17 @@ class CqlClause extends TCqlClause { } } +/** + * A possibly tainted clause + * any clause with a string concatenation in it + * regardless of where that operand came from + */ +class TaintedClause extends CqlClause { + TaintedClause(){ + exists(StringConcatenation::getAnOperand(this.getArgument().flow())) + } +} + /** * Call to`cds.db.run` * or @@ -222,7 +233,25 @@ class CQLSink extends DataFlow::Node { this = any(CdsFacade cds).getMember("db").getMember("run").getACall().getAnArgument() or exists(AwaitExpr a, CQL::CqlClause clause | a.getAChildExpr() = clause.asExpr() and this.asExpr() = clause.asExpr()) + } +} + +/** + * a more heurisitic based taint step + * captures one of the alternative ways to construct query strings: + * `cds.parse.cql(`string`+userInput)` + * and considers them tainted if they've been concatenated against + * in any manner + */ +class ParseCQLTaintedClause extends CallNode { + ParseCQLTaintedClause(){ + this = any(CdsFacade cds).getMember("parse").getMember("cql").getACall() and + exists(DataFlow::Node n | n = StringConcatenation::getAnOperand(this.getAnArgument()) + //omit the fact that the arg of cds.parse.cql (`SELECT * from Foo`) + //is technically a string concat + and not n.asExpr() instanceof TemplateElement + ) } - } + } \ No newline at end of file diff --git a/javascript/frameworks/cap/src/sqlinjection/SqlInjection.ql b/javascript/frameworks/cap/src/sqlinjection/SqlInjection.ql index 174ddcda1..3ca9c8cc6 100644 --- a/javascript/frameworks/cap/src/sqlinjection/SqlInjection.ql +++ b/javascript/frameworks/cap/src/sqlinjection/SqlInjection.ql @@ -13,7 +13,6 @@ import javascript import advanced_security.javascript.frameworks.cap.CDS import advanced_security.javascript.frameworks.cap.CQL -import semmle.javascript.StringConcatenation class SqlInjectionConfiguration extends TaintTracking::Configuration { SqlInjectionConfiguration(){ @@ -31,11 +30,15 @@ class SqlInjectionConfiguration extends TaintTracking::Configuration { override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { //string concatenation in a clause arg taints the clause - exists(CQL::CqlClause clause | + exists(CQL::TaintedClause clause | clause.getArgument() = pred.asExpr() and clause.asExpr() = succ.asExpr() - and - exists(StringConcatenation::getAnOperand(pred)) + ) + or + //less precise, any concat in the alternative sql stmt construction techniques + exists(CQL::ParseCQLTaintedClause parse | + parse.getAnArgument() = pred + and parse = succ ) } } diff --git a/javascript/frameworks/cap/test/models/cql/select/select.expected b/javascript/frameworks/cap/test/models/cql/select/select.expected index de09ede2a..2b04cdd57 100644 --- a/javascript/frameworks/cap/test/models/cql/select/select.expected +++ b/javascript/frameworks/cap/test/models/cql/select/select.expected @@ -1,3 +1,4 @@ +| select2.js:4:14:4:35 | select2.js:4 | select2.js:4:14:4:35 | SELECT. ... (Table) | | select.js:3:14:3:43 | select.js:3 | select.js:3:14:3:43 | SELECT` ... (Table) | | select.js:4:14:4:45 | select.js:4 | select.js:4:14:4:45 | SELECT` ... Table") | | select.js:5:14:5:33 | select.js:5 | select.js:5:14:5:33 | SELECT("col1, col2") | @@ -184,4 +185,4 @@ | select.js:287:14:290:1 | select.js:287 | select.js:287:14:290:1 | SELECT. ... col2"\\n) | | select.js:287:14:292:2 | select.js:287 | select.js:287:14:292:2 | SELECT. ... }],\\n}) | | select.js:287:14:292:48 | select.js:287 | select.js:287:14:292:48 | SELECT. ... eLock() | -| select.js:328:10:328:28 | select.js:328 | select.js:328:10:328:28 | SELECT.from (Books) | +| select.js:325:10:325:28 | select.js:325 | select.js:325:10:325:28 | SELECT.from (Books) | diff --git a/javascript/frameworks/cap/test/models/cql/select/select.js b/javascript/frameworks/cap/test/models/cql/select/select.js index 33c5eff98..6be706f4d 100644 --- a/javascript/frameworks/cap/test/models/cql/select/select.js +++ b/javascript/frameworks/cap/test/models/cql/select/select.js @@ -291,9 +291,6 @@ var select = SELECT.distinct.from`Table`.where`col1 in ${[("*", 10)]}`.groupBy( ref: [{ id: "function", args: { p: { ref: ["arg1"] } } }], }).orderBy`col1 desc, col2.prop2`.forShareLock(); -/* ========== CQL tagged function ========== */ -CQL`SELECT col1, col2, col3 from Table`; - /* ========== JSON literal queries ========== */ var select = { diff --git a/javascript/frameworks/cap/test/models/cql/select/select2.js b/javascript/frameworks/cap/test/models/cql/select/select2.js index 78d6c7e31..51aec5cc7 100644 --- a/javascript/frameworks/cap/test/models/cql/select/select2.js +++ b/javascript/frameworks/cap/test/models/cql/select/select2.js @@ -1,8 +1,8 @@ -// /* ========== obtained through module ========== */ -// const cds = require('@sap/cds'); -// const { SELECT, INSERT, UPDATE, DELETE } = cds.ql; -// var select = SELECT.one.from(Table); +/* ========== obtained through module ========== */ +const cds = require('@sap/cds'); +const { SELECT, INSERT, UPDATE, DELETE } = cds.ql; +var select = SELECT.one.from(Table); -// /* ========== not a use of the API ========== */ -// foo.SELECT -// require("SELECT")() \ No newline at end of file +/* ========== not a use of the API ========== */ +foo.SELECT +require("SELECT")() \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/cql/taintedclause/taintedclause.expected b/javascript/frameworks/cap/test/models/cql/taintedclause/taintedclause.expected new file mode 100644 index 000000000..698109cb3 --- /dev/null +++ b/javascript/frameworks/cap/test/models/cql/taintedclause/taintedclause.expected @@ -0,0 +1 @@ +| taintedclause.js:4:12:4:57 | cds.par ... rInput) | diff --git a/javascript/frameworks/cap/test/models/cql/taintedclause/taintedclause.js b/javascript/frameworks/cap/test/models/cql/taintedclause/taintedclause.js new file mode 100644 index 000000000..d9f124912 --- /dev/null +++ b/javascript/frameworks/cap/test/models/cql/taintedclause/taintedclause.js @@ -0,0 +1,5 @@ +/* ========== CQL parse usages ========== */ +const cds = require('@sap/cds'); +let cqn = CQL`SELECT col1, col2, col3 from Table` + userInput //this is actually already captured by taint steps by default +let cqn1 = cds.parse.cql (`SELECT * from Foo`+ userInput) +let cqn2 = cds.parse.cql (`SELECT * from Foo`) + userInput //not valid diff --git a/javascript/frameworks/cap/test/models/cql/taintedclause/taintedclause.ql b/javascript/frameworks/cap/test/models/cql/taintedclause/taintedclause.ql new file mode 100644 index 000000000..1fc1dd1bc --- /dev/null +++ b/javascript/frameworks/cap/test/models/cql/taintedclause/taintedclause.ql @@ -0,0 +1,5 @@ +import javascript +import advanced_security.javascript.frameworks.cap.CQL + +from CQL::ParseCQLTaintedClause clause +select clause \ No newline at end of file diff --git a/javascript/frameworks/cap/test/models/queries/sqlinjection.expected b/javascript/frameworks/cap/test/models/queries/sqlinjection.expected index 1126707f9..933e1888e 100644 --- a/javascript/frameworks/cap/test/models/queries/sqlinjection.expected +++ b/javascript/frameworks/cap/test/models/queries/sqlinjection.expected @@ -1,2 +1,6 @@ | sqlinjection.js:13:35:13:39 | query | Injection vulnerability found. | -| sqlinjection.js:16:36:16:41 | query2 | Injection vulnerability found. | +| sqlinjection.js:15:25:15:65 | SELECT. ... book}`) | Injection vulnerability found. | +| sqlinjection.js:18:36:18:41 | query2 | Injection vulnerability found. | +| sqlinjection.js:20:25:20:63 | SELECT. ... '+book) | Injection vulnerability found. | +| sqlinjection.js:28:38:28:40 | cqn | Injection vulnerability found. | +| sqlinjection.js:31:38:31:41 | cqn1 | Injection vulnerability found. | diff --git a/javascript/frameworks/cap/test/models/queries/sqlinjection.js b/javascript/frameworks/cap/test/models/queries/sqlinjection.js index acc2f7357..5cc820090 100644 --- a/javascript/frameworks/cap/test/models/queries/sqlinjection.js +++ b/javascript/frameworks/cap/test/models/queries/sqlinjection.js @@ -20,6 +20,15 @@ class SampleVulnService extends cds.ApplicationService { init(){ let books22 = await SELECT.from `Books` .where ('ID='+book) //alert let books3 = await SELECT.from `Books` .where `ID=${book}` //safe + + let id=2 + let books33 = await SELECT.from `Books` .where ('ID='+id) //safe + + let cqn = CQL`SELECT col1, col2, col3 from Books` + book + let books222 = await cds.db.run (cqn) //alert + + let cqn1 = cds.parse.cql (`SELECT * from Books`+ book) + let books111 = await cds.db.run (cqn1) //alert }) return super.init() From 3246352a1d6c53204c322e235d662fd2ddd3c404 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Thu, 18 Jan 2024 12:11:08 -0500 Subject: [PATCH 59/61] Add comments and query format to CDS and CQL library --- .../javascript/frameworks/cap/CDS.qll | 226 +++++---- .../javascript/frameworks/cap/CQL.qll | 428 +++++++++--------- 2 files changed, 323 insertions(+), 331 deletions(-) diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll index 2538674b6..d1e3a0d11 100644 --- a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CDS.qll @@ -3,144 +3,132 @@ import DataFlow module CDS { // TODO: should this base type be more specific? -abstract class ServiceInstance extends DataFlow::Node { } + abstract class ServiceInstance extends DataFlow::Node { } -/** - * Call to`cds.serve` - */ -class CdsServeCall extends ServiceInstance { - CdsServeCall(){ - this = any(CdsFacade cds).getMember("serve").getACall() + /** + * Call to`cds.serve` + */ + class CdsServeCall extends ServiceInstance { + CdsServeCall() { this = any(CdsFacade cds).getMember("serve").getACall() } } -} -/** - * call to: - * `new cds.ApplicationService` or `new cds.Service` - */ -class ServiceConstructor extends ServiceInstance { - ServiceConstructor(){ - this = any(ApplicationService cds).getAnInstantiation() + /** + * call to: + * `new cds.ApplicationService` or `new cds.Service` + */ + class ServiceConstructor extends ServiceInstance { + ServiceConstructor() { this = any(ApplicationService cds).getAnInstantiation() } } -} -/** - * return value of `cds.connect.to` - */ -class ConnectTo extends ServiceInstance { - ConnectTo(){ - this = any(CdsFacade cds).getMember("connect").getMember("to").getACall() + /** + * return value of `cds.connect.to` + */ + class ConnectTo extends ServiceInstance { + ConnectTo() { this = any(CdsFacade cds).getMember("connect").getMember("to").getACall() } } -} -/** Last argument to the service methods `srv.before`, `srv.on`, and `srv.after` */ -private class RequestHandler extends FunctionNode { } + /** Last argument to the service methods `srv.before`, `srv.on`, and `srv.after` */ + private class RequestHandler extends FunctionNode { } -private class ErrorHandler extends RequestHandler { } + private class ErrorHandler extends RequestHandler { } -/** - * Subclassing ApplicationService via `extends`: - * ```js - * class SomeService extends cds.ApplicationService - * ``` - */ -class UserDefinedApplicationService extends ClassNode { - UserDefinedApplicationService() { - exists( ApplicationService cdsApplicationService | - this.getASuperClassNode() = cdsApplicationService.asSource() - ) + /** + * Subclassing ApplicationService via `extends`: + * ```js + * class SomeService extends cds.ApplicationService + * ``` + */ + class UserDefinedApplicationService extends ClassNode { + UserDefinedApplicationService() { + exists(ApplicationService cdsApplicationService | + this.getASuperClassNode() = cdsApplicationService.asSource() + ) + } } -} -/** - * Subclassing ApplicationService via `cds.service.impl`: - * ```js - * const cds = require('@sap/cds') - * module.exports = cds.service.impl (function() { ... }) - * ``` - */ -class OldStyleUserDefinedApplicationService extends MethodCallNode { - OldStyleUserDefinedApplicationService() { - exists(CdsFacade cds | - this = cds.getMember("service").getMember("impl").getACall() - ) + /** + * Subclassing ApplicationService via `cds.service.impl`: + * ```js + * const cds = require('@sap/cds') + * module.exports = cds.service.impl (function() { ... }) + * ``` + */ + class OldStyleUserDefinedApplicationService extends MethodCallNode { + OldStyleUserDefinedApplicationService() { + exists(CdsFacade cds | this = cds.getMember("service").getMember("impl").getACall()) + } } -} -/** - * Parameter of a `srv.with` method call: - * ```js - * cds.serve('./srv/cat-service') .with ((srv) => { - * srv.on ('READ','Books', (req) => req.reply([...])) - * }) - * ``` - * - * TODO expand this to capture request handlers registered inside the function - */ -class WithCallParameter extends RequestHandler { - WithCallParameter() { - exists(MethodCallNode withCall, ServiceInstance svc | - withCall.getArgument(0) = this and - withCall.getMethodName() = "with" and - withCall.getReceiver() = svc - ) + /** + * Parameter of a `srv.with` method call: + * ```js + * cds.serve('./srv/cat-service') .with ((srv) => { + * srv.on ('READ','Books', (req) => req.reply([...])) + * }) + * ``` + * + * TODO expand this to capture request handlers registered inside the function + */ + class WithCallParameter extends RequestHandler { + WithCallParameter() { + exists(MethodCallNode withCall, ServiceInstance svc | + withCall.getArgument(0) = this and + withCall.getMethodName() = "with" and + withCall.getReceiver() = svc + ) + } } -} -/** - * Parameter of request handler of `_.on`: - * ```js - * _.on ('READ','Books', (req) => req.reply([...])) - * ``` - */ -class OnNodeParam extends ValueNode, ParameterNode { - MethodCallNode on; - OnNodeParam() { - exists(FunctionNode handler | - on.getMethodName() = "on" - and on.getLastArgument() = handler - and handler.getLastParameter() = this - ) - } - MethodCallNode getOnNode(){ - result = on - } + /** + * Parameter of request handler of `_.on`: + * ```js + * _.on ('READ','Books', (req) => req.reply([...])) + * ``` + */ + class OnNodeParam extends ValueNode, ParameterNode { + MethodCallNode on; -} + OnNodeParam() { + exists(FunctionNode handler | + on.getMethodName() = "on" and + on.getLastArgument() = handler and + handler.getLastParameter() = this + ) + } -/** - * Parameter of request handler of `srv.on`: - * ```js - * this.on ('READ','Books', (req) => req.reply([...])) - * ``` - * not sure how else to know which service is registering the handler - */ -class RequestSource extends OnNodeParam { - RequestSource() { - // TODO : consider - do we need to actually ever know which service the handler is associated to? - exists(UserDefinedApplicationService svc, FunctionNode init | - svc.getAnInstanceMember() = init and - init.getName() = "init" - and this.getOnNode().getEnclosingFunction() = init.getAstNode() - ) - or - exists(WithCallParameter pa | - this.getOnNode().getEnclosingFunction() = pa.getFunction()) + MethodCallNode getOnNode() { result = on } } -} -class ApplicationService extends API::Node { - ApplicationService(){ - exists(CdsFacade c | this = c.getMember("ApplicationService")) + /** + * Parameter of request handler of `srv.on`: + * ```js + * this.on ('READ','Books', (req) => req.reply([...])) + * ``` + * not sure how else to know which service is registering the handler + */ + class RequestSource extends OnNodeParam { + RequestSource() { + // TODO : consider - do we need to actually ever know which service the handler is associated to? + exists(UserDefinedApplicationService svc, FunctionNode init | + svc.getAnInstanceMember() = init and + init.getName() = "init" and + this.getOnNode().getEnclosingFunction() = init.getAstNode() + ) + or + exists(WithCallParameter pa | this.getOnNode().getEnclosingFunction() = pa.getFunction()) + } } -} -/** - * ```js - * const cds = require('@sap/cds') - * ``` - */ -class CdsFacade extends API::Node { - CdsFacade() { this = API::moduleImport("@sap/cds") } + class ApplicationService extends API::Node { + ApplicationService() { exists(CdsFacade c | this = c.getMember("ApplicationService")) } + } + + /** + * ```js + * const cds = require('@sap/cds') + * ``` + */ + class CdsFacade extends API::Node { + CdsFacade() { this = API::moduleImport("@sap/cds") } + } } -} \ No newline at end of file diff --git a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll index da0340496..1dde91599 100644 --- a/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll +++ b/javascript/frameworks/cap/lib/advanced_security/javascript/frameworks/cap/CQL.qll @@ -3,255 +3,259 @@ import DataFlow import CDS::CDS module CQL { -class CqlQueryBase extends VarRef { - CqlQueryBase() { - exists(string name | - this.getName() = name and - name in ["SELECT", "INSERT", "DELETE", "UPDATE", "UPSERT"] and - // Made available as a global variable - exists(GlobalVariable queryBase | - this = queryBase.getAReference() - ) - or - // Imported from `cds.ql` */ - exists(CdsFacade cds | - cds.getMember("ql").getMember(name).getAValueReachableFromSource().asExpr() = this - ) - ) + /** + * Objects from the SQL-like fluent API + * this is the set of clauses that acts as the base of a statement + */ + class CqlQueryBase extends VarRef { + CqlQueryBase() { + exists(string name | + this.getName() = name and + name in ["SELECT", "INSERT", "DELETE", "UPDATE", "UPSERT"] and + // Made available as a global variable + exists(GlobalVariable queryBase | this = queryBase.getAReference()) + or + // Imported from `cds.ql` */ + exists(CdsFacade cds | + cds.getMember("ql").getMember(name).getAValueReachableFromSource().asExpr() = this + ) + ) + } } -} - -class CqlSelectBase extends CqlQueryBase { - CqlSelectBase() { this.getName() = "SELECT" } -} - -class CqlInsertBase extends CqlQueryBase { - CqlInsertBase() { this.getName() = "INSERT" } -} - -class CqlDeleteBase extends CqlQueryBase { - CqlDeleteBase() { this.getName() = "DELETE" } -} - -class CqlUpdateBase extends CqlQueryBase { - CqlUpdateBase() { this.getName() = "UPDATE" } -} - -class CqlUpsertBase extends CqlQueryBase { - CqlUpsertBase() { this.getName() = "UPSERT" } -} - -/** - * The cds-ql docs do not mention DELETE being a function acting as a shortcut to any underlying clause - */ -abstract class CqlQueryBaseCall extends CallExpr { - // TODO: Express "It's a global function or a local function imported from cds.ql" -} - -class CqlSelectBaseCall extends CqlQueryBaseCall { - CqlSelectBaseCall() { this.getCalleeName() = "SELECT" } -} - -class CqlInsertBaseCall extends CqlQueryBaseCall { - CqlInsertBaseCall() { this.getCalleeName() = "INSERT" } -} - -class CqlUpdateBaseCall extends CqlQueryBaseCall { - CqlUpdateBaseCall() { this.getCalleeName() = "UPDATE" } -} - -class CqlUpsertBaseCall extends CqlQueryBaseCall { - CqlUpsertBaseCall() { this.getCalleeName() = "UPSERT" } -} - -Expr getRootReceiver(Expr e) { - result = e and - ( - e instanceof VarRef - or - e instanceof CallExpr and not exists(e.(CallExpr).getReceiver()) - ) - or - result = getRootReceiver(e.(DotExpr).getBase()) - or - result = getRootReceiver(e.(MethodCallExpr).getReceiver()) - or - result = getRootReceiver(e.(PropAccess).getBase()) - or - result = getRootReceiver(e.(TaggedTemplateExpr).getTag()) -} -newtype TCqlClause = - MethodCall(MethodCallExpr callExpr) { - exists(CqlQueryBase base | base = getRootReceiver(callExpr)) or - exists(CqlQueryBaseCall call | call = getRootReceiver(callExpr)) - } or - ShortcutCall(CqlQueryBaseCall callExpr) - -class CqlClause extends TCqlClause { - - Expr asExpr(){ - result = this.asMethodCall() - or - result = this.asShortcutCall() + class CqlSelectBase extends CqlQueryBase { + CqlSelectBase() { this.getName() = "SELECT" } } - Expr getArgument(){ - result = this.asMethodCall().getAnArgument() - or - result = this.asShortcutCall().getAnArgument() + class CqlInsertBase extends CqlQueryBase { + CqlInsertBase() { this.getName() = "INSERT" } } - string getClauseName(){ - result = this.asMethodCall().getMethodName() - or - (this.asShortcutCall().getCalleeName() = "SELECT" and - result = "columns") - or - (this.asShortcutCall().getCalleeName() in ["INSERT", "UPSERT"] and - result = "entries") - or - (this.asShortcutCall().getCalleeName() = "UPDATE" and - result = "entity") + class CqlDeleteBase extends CqlQueryBase { + CqlDeleteBase() { this.getName() = "DELETE" } } - MethodCallExpr asMethodCall() { this = MethodCall(result) } + class CqlUpdateBase extends CqlQueryBase { + CqlUpdateBase() { this.getName() = "UPDATE" } + } - CallExpr asShortcutCall() { this = ShortcutCall(result) } + class CqlUpsertBase extends CqlQueryBase { + CqlUpsertBase() { this.getName() = "UPSERT" } + } /** - * Convert this `CqlClause` into a `DotExpr`, i.e. - * `Get SELECT.from'Table' when given SELECT.from'Table'.wherecond`, + * The cds-ql docs do not mention DELETE being a function acting as a shortcut to any underlying clause */ - DotExpr asDotExpr() { - result = this.asMethodCall().getCallee().(DotExpr) + abstract class CqlQueryBaseCall extends CallExpr { + // TODO: Express "It's a global function or a local function imported from cds.ql" } - string toString() { - result = this.asMethodCall().toString() or - result = this.asShortcutCall().toString() + class CqlSelectBaseCall extends CqlQueryBaseCall { + CqlSelectBaseCall() { this.getCalleeName() = "SELECT" } } - Location getLocation() { - result = this.asMethodCall().getLocation() or - result = this.asShortcutCall().getLocation() + class CqlInsertBaseCall extends CqlQueryBaseCall { + CqlInsertBaseCall() { this.getCalleeName() = "INSERT" } } - CqlQueryBase getCqlBase() { - result = getRootReceiver(this.asMethodCall()) + class CqlUpdateBaseCall extends CqlQueryBaseCall { + CqlUpdateBaseCall() { this.getCalleeName() = "UPDATE" } } - CqlQueryBaseCall getCqlBaseCall() { - result = getRootReceiver(this.asMethodCall()).(CqlQueryBaseCall) - } - - /** ========== Parent relationships ========== */ - Expr getParentExpr() { - result = this.asMethodCall().getParentExpr() or - result = this.asShortcutCall().getParentExpr() + class CqlUpsertBaseCall extends CqlQueryBaseCall { + CqlUpsertBaseCall() { this.getCalleeName() = "UPSERT" } } /** - * Possible cases for constructing a chain of clauses: - * - * (looking at the terminal clause and its possible parent types as tuples: (this, parent)) - * 1) MethodCall.MethodCall - * - example `(SELECT.from(Table), SELECT.from(Table).where("col1='*'"))` - * 2) ShortcutCall.MethodCall - * - example `(SELECT("col1, col2"), SELECT("col1, col2").from("Table"))` - * - * ShortcutCalls cannot be added to any clause chain other than the first position - * example - `SELECT("col1, col2").INSERT(col2)` is not valid + * Obtains the receiver across a variety of types of accesses */ - CqlClause getCqlParentExpr() { - result.asMethodCall() = this.asMethodCall().getParentExpr().getParentExpr() + Expr getRootReceiver(Expr e) { + result = e and + ( + e instanceof VarRef + or + e instanceof CallExpr and not exists(e.(CallExpr).getReceiver()) + ) or - result.asMethodCall() = this.asShortcutCall().getParentExpr().getParentExpr() - } - - Expr getAnAncestorExpr() { - result = this.asMethodCall().getParentExpr+() or - result = this.asShortcutCall().getParentExpr+() - } - - CqlClause getAnAncestorCqlClause() { - result.asMethodCall() = this.getAnAncestorExpr() or - result.asShortcutCall() = this.getAnAncestorExpr() - } - - /** ========== Children relationships ========== */ - Expr getAChildExpr() { - result = this.asMethodCall().getAChildExpr() or - result = this.asShortcutCall().getAChildExpr() + result = getRootReceiver(e.(DotExpr).getBase()) + or + result = getRootReceiver(e.(MethodCallExpr).getReceiver()) + or + result = getRootReceiver(e.(PropAccess).getBase()) + or + result = getRootReceiver(e.(TaggedTemplateExpr).getTag()) } /** - * the same chain order logic as `getCqlParentExpr` but reversed + * An aggregation type for the two ways to access the fluent API + * provided by the module cds.ql */ - CqlClause getAChildCqlClause() { - result.asMethodCall() = this.asMethodCall().getAChildExpr().getAChildExpr() or - result.asShortcutCall() = this.asMethodCall().getAChildExpr().getAChildExpr() - } - - Expr getADescendantExpr() { - result = this.asMethodCall().getAChildExpr+() or - result = this.asShortcutCall().getAChildExpr+() - } - - CqlClause getADescendantCqlClause() { - result.asMethodCall() = this.getADescendantExpr() or - result.asShortcutCall() = this.getADescendantExpr() + newtype TCqlClause = + MethodCall(MethodCallExpr callExpr) { + exists(CqlQueryBase base | base = getRootReceiver(callExpr)) or + exists(CqlQueryBaseCall call | call = getRootReceiver(callExpr)) + } or + ShortcutCall(CqlQueryBaseCall callExpr) + + class CqlClause extends TCqlClause { + Expr asExpr() { + result = this.asMethodCall() + or + result = this.asShortcutCall() + } + + Expr getArgument() { + result = this.asMethodCall().getAnArgument() + or + result = this.asShortcutCall().getAnArgument() + } + + string getClauseName() { + result = this.asMethodCall().getMethodName() + or + this.asShortcutCall().getCalleeName() = "SELECT" and + result = "columns" + or + this.asShortcutCall().getCalleeName() in ["INSERT", "UPSERT"] and + result = "entries" + or + this.asShortcutCall().getCalleeName() = "UPDATE" and + result = "entity" + } + + MethodCallExpr asMethodCall() { this = MethodCall(result) } + + CallExpr asShortcutCall() { this = ShortcutCall(result) } + + /** + * Convert this `CqlClause` into a `DotExpr`, i.e. + * `Get SELECT.from'Table' when given SELECT.from'Table'.wherecond`, + */ + DotExpr asDotExpr() { result = this.asMethodCall().getCallee().(DotExpr) } + + string toString() { + result = this.asMethodCall().toString() or + result = this.asShortcutCall().toString() + } + + Location getLocation() { + result = this.asMethodCall().getLocation() or + result = this.asShortcutCall().getLocation() + } + + CqlQueryBase getCqlBase() { result = getRootReceiver(this.asMethodCall()) } + + CqlQueryBaseCall getCqlBaseCall() { + result = getRootReceiver(this.asMethodCall()).(CqlQueryBaseCall) + } + + /** Describes a parent expression relation */ + Expr getParentExpr() { + result = this.asMethodCall().getParentExpr() or + result = this.asShortcutCall().getParentExpr() + } + + /** + * Possible cases for constructing a chain of clauses: + * + * (looking at the terminal clause and its possible parent types as tuples: (this, parent)) + * 1) MethodCall.MethodCall + * - example `(SELECT.from(Table), SELECT.from(Table).where("col1='*'"))` + * 2) ShortcutCall.MethodCall + * - example `(SELECT("col1, col2"), SELECT("col1, col2").from("Table"))` + * + * ShortcutCalls cannot be added to any clause chain other than the first position + * example - `SELECT("col1, col2").INSERT(col2)` is not valid + */ + CqlClause getCqlParentExpr() { + result.asMethodCall() = this.asMethodCall().getParentExpr().getParentExpr() + or + result.asMethodCall() = this.asShortcutCall().getParentExpr().getParentExpr() + } + + Expr getAnAncestorExpr() { + result = this.asMethodCall().getParentExpr+() or + result = this.asShortcutCall().getParentExpr+() + } + + CqlClause getAnAncestorCqlClause() { + result.asMethodCall() = this.getAnAncestorExpr() or + result.asShortcutCall() = this.getAnAncestorExpr() + } + + /** Describes a child expression relation */ + Expr getAChildExpr() { + result = this.asMethodCall().getAChildExpr() or + result = this.asShortcutCall().getAChildExpr() + } + + /** + * the same chain order logic as `getCqlParentExpr` but reversed + */ + CqlClause getAChildCqlClause() { + result.asMethodCall() = this.asMethodCall().getAChildExpr().getAChildExpr() or + result.asShortcutCall() = this.asMethodCall().getAChildExpr().getAChildExpr() + } + + Expr getADescendantExpr() { + result = this.asMethodCall().getAChildExpr+() or + result = this.asShortcutCall().getAChildExpr+() + } + + CqlClause getADescendantCqlClause() { + result.asMethodCall() = this.getADescendantExpr() or + result.asShortcutCall() = this.getADescendantExpr() + } + + /** + * Matches the given `CqlClause` to its method/property name, nested at arbitrary depth. + */ + string getAnAPIName() { + result = this.asDotExpr().getPropertyName() or + result = this.getADescendantCqlClause().getAnAPIName() + } } /** - * Matches the given `CqlClause` to its method/property name, nested at arbitrary depth. + * A possibly tainted clause + * any clause with a string concatenation in it + * regardless of where that operand came from */ - string getAnAPIName() { - result = this.asDotExpr().getPropertyName() or - result = this.getADescendantCqlClause().getAnAPIName() + class TaintedClause extends CqlClause { + TaintedClause() { exists(StringConcatenation::getAnOperand(this.getArgument().flow())) } } -} -/** - * A possibly tainted clause - * any clause with a string concatenation in it - * regardless of where that operand came from - */ -class TaintedClause extends CqlClause { - TaintedClause(){ - exists(StringConcatenation::getAnOperand(this.getArgument().flow())) + /** + * Call to`cds.db.run` + * or + * an await surrounding a sql statement + */ + class CQLSink extends DataFlow::Node { + CQLSink() { + this = any(CdsFacade cds).getMember("db").getMember("run").getACall().getAnArgument() + or + exists(AwaitExpr a, CQL::CqlClause clause | + a.getAChildExpr() = clause.asExpr() and this.asExpr() = clause.asExpr() + ) + } } -} - -/** - * Call to`cds.db.run` - * or - * an await surrounding a sql statement - */ -class CQLSink extends DataFlow::Node { - CQLSink(){ - this = any(CdsFacade cds).getMember("db").getMember("run").getACall().getAnArgument() - or - exists(AwaitExpr a, CQL::CqlClause clause | a.getAChildExpr() = clause.asExpr() and this.asExpr() = clause.asExpr()) - } -} -/** - * a more heurisitic based taint step - * captures one of the alternative ways to construct query strings: - * `cds.parse.cql(`string`+userInput)` - * and considers them tainted if they've been concatenated against - * in any manner - */ -class ParseCQLTaintedClause extends CallNode { - ParseCQLTaintedClause(){ - this = any(CdsFacade cds).getMember("parse").getMember("cql").getACall() and - exists(DataFlow::Node n | n = StringConcatenation::getAnOperand(this.getAnArgument()) - //omit the fact that the arg of cds.parse.cql (`SELECT * from Foo`) - //is technically a string concat - and not n.asExpr() instanceof TemplateElement + /** + * a more heurisitic based taint step + * captures one of the alternative ways to construct query strings: + * `cds.parse.cql(`string`+userInput)` + * and considers them tainted if they've been concatenated against + * in any manner + */ + class ParseCQLTaintedClause extends CallNode { + ParseCQLTaintedClause() { + this = any(CdsFacade cds).getMember("parse").getMember("cql").getACall() and + exists(DataFlow::Node n | + n = StringConcatenation::getAnOperand(this.getAnArgument()) and + //omit the fact that the arg of cds.parse.cql (`SELECT * from Foo`) + //is technically a string concat + not n.asExpr() instanceof TemplateElement ) + } } } - -} \ No newline at end of file From beb10fb4fa55415438241818ede463e583255dcc Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Fri, 19 Jan 2024 13:34:58 -0500 Subject: [PATCH 60/61] Fix cap query test location --- .../cap/test/{models => }/queries/sqlinjection.expected | 0 .../frameworks/cap/test/{models => }/queries/sqlinjection.js | 0 .../frameworks/cap/test/{models => }/queries/sqlinjection.qlref | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename javascript/frameworks/cap/test/{models => }/queries/sqlinjection.expected (100%) rename javascript/frameworks/cap/test/{models => }/queries/sqlinjection.js (100%) rename javascript/frameworks/cap/test/{models => }/queries/sqlinjection.qlref (100%) diff --git a/javascript/frameworks/cap/test/models/queries/sqlinjection.expected b/javascript/frameworks/cap/test/queries/sqlinjection.expected similarity index 100% rename from javascript/frameworks/cap/test/models/queries/sqlinjection.expected rename to javascript/frameworks/cap/test/queries/sqlinjection.expected diff --git a/javascript/frameworks/cap/test/models/queries/sqlinjection.js b/javascript/frameworks/cap/test/queries/sqlinjection.js similarity index 100% rename from javascript/frameworks/cap/test/models/queries/sqlinjection.js rename to javascript/frameworks/cap/test/queries/sqlinjection.js diff --git a/javascript/frameworks/cap/test/models/queries/sqlinjection.qlref b/javascript/frameworks/cap/test/queries/sqlinjection.qlref similarity index 100% rename from javascript/frameworks/cap/test/models/queries/sqlinjection.qlref rename to javascript/frameworks/cap/test/queries/sqlinjection.qlref From 1288c81c5124b3f3723e9495151d9b4fc768a116 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Fri, 19 Jan 2024 14:41:53 -0500 Subject: [PATCH 61/61] Fix naming in cap query qlref file --- javascript/frameworks/cap/test/queries/sqlinjection.qlref | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/frameworks/cap/test/queries/sqlinjection.qlref b/javascript/frameworks/cap/test/queries/sqlinjection.qlref index 915158d38..0401f5b18 100644 --- a/javascript/frameworks/cap/test/queries/sqlinjection.qlref +++ b/javascript/frameworks/cap/test/queries/sqlinjection.qlref @@ -1 +1 @@ -sqlinjection/Sqlinjection.ql \ No newline at end of file +sqlinjection/SqlInjection.ql \ No newline at end of file