@abaplint/core 2.96.2 → 2.97.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/abaplint.d.ts +9 -1
- package/build/src/abap/5_syntax/_builtin.js +2 -2
- package/build/src/abap/5_syntax/_procedural.js +2 -2
- package/build/src/abap/5_syntax/basic_types.js +21 -15
- package/build/src/abap/5_syntax/statements/controls.js +1 -1
- package/build/src/abap/5_syntax/statements/find.js +2 -2
- package/build/src/abap/5_syntax/statements/ranges.js +1 -1
- package/build/src/abap/5_syntax/statements/selectoption.js +1 -1
- package/build/src/abap/5_syntax/statements/split.js +1 -1
- package/build/src/abap/5_syntax/structures/data.js +2 -2
- package/build/src/abap/5_syntax/structures/statics.js +2 -2
- package/build/src/abap/types/basic/table_type.js +8 -1
- package/build/src/abap/types/form_definition.js +2 -2
- package/build/src/ddic.js +1 -1
- package/build/src/objects/table_type.js +1 -0
- package/build/src/registry.js +1 -1
- package/build/src/rules/constant_classes.js +1 -1
- package/build/src/rules/downport.js +2 -2
- package/build/src/rules/index.js +1 -0
- package/build/src/rules/sql_escape_host_variables.js +1 -1
- package/build/src/rules/strict_sql.js +71 -0
- package/package.json +1 -1
package/build/abaplint.d.ts
CHANGED
|
@@ -401,6 +401,7 @@ declare namespace BasicTypes {
|
|
|
401
401
|
IStructureComponent,
|
|
402
402
|
StructureType,
|
|
403
403
|
TableAccessType,
|
|
404
|
+
TableKeyType,
|
|
404
405
|
ITableKey,
|
|
405
406
|
ITableOptions,
|
|
406
407
|
TableType_2 as TableType,
|
|
@@ -3626,13 +3627,14 @@ declare interface ISyntaxSettings {
|
|
|
3626
3627
|
|
|
3627
3628
|
declare type ITableKey = {
|
|
3628
3629
|
name: string;
|
|
3629
|
-
type
|
|
3630
|
+
type: TableAccessType;
|
|
3630
3631
|
keyFields: string[];
|
|
3631
3632
|
isUnique: boolean;
|
|
3632
3633
|
};
|
|
3633
3634
|
|
|
3634
3635
|
declare type ITableOptions = {
|
|
3635
3636
|
withHeader: boolean;
|
|
3637
|
+
keyType: TableKeyType;
|
|
3636
3638
|
primaryKey?: ITableKey;
|
|
3637
3639
|
secondary?: ITableKey[];
|
|
3638
3640
|
};
|
|
@@ -5959,6 +5961,12 @@ declare class TableExpression extends Expression {
|
|
|
5959
5961
|
getRunnable(): IStatementRunnable;
|
|
5960
5962
|
}
|
|
5961
5963
|
|
|
5964
|
+
declare enum TableKeyType {
|
|
5965
|
+
default = "DEFAULT",
|
|
5966
|
+
user = "USER",
|
|
5967
|
+
empty = "EMPTY"
|
|
5968
|
+
}
|
|
5969
|
+
|
|
5962
5970
|
declare class Tables implements IStatement {
|
|
5963
5971
|
getMatcher(): IStatementRunnable;
|
|
5964
5972
|
}
|
|
@@ -388,7 +388,7 @@ BuiltIn.methods = [
|
|
|
388
388
|
{
|
|
389
389
|
name: "CONCAT_LINES_OF",
|
|
390
390
|
mandatory: {
|
|
391
|
-
"table": new basic_1.TableType(new basic_1.AnyType(), { withHeader: false }),
|
|
391
|
+
"table": new basic_1.TableType(new basic_1.AnyType(), { withHeader: false, keyType: basic_1.TableKeyType.default }),
|
|
392
392
|
},
|
|
393
393
|
optional: {
|
|
394
394
|
"sep": new basic_1.StringType(),
|
|
@@ -684,7 +684,7 @@ BuiltIn.methods = [
|
|
|
684
684
|
{
|
|
685
685
|
name: "LINES",
|
|
686
686
|
mandatory: {
|
|
687
|
-
"val": new basic_1.TableType(new basic_1.AnyType(), { withHeader: false }),
|
|
687
|
+
"val": new basic_1.TableType(new basic_1.AnyType(), { withHeader: false, keyType: basic_1.TableKeyType.default }),
|
|
688
688
|
},
|
|
689
689
|
return: new basic_1.IntegerType(),
|
|
690
690
|
},
|
|
@@ -90,10 +90,10 @@ class Procedural {
|
|
|
90
90
|
}
|
|
91
91
|
if (param.direction === types_1.FunctionModuleParameterDirection.tables) {
|
|
92
92
|
if (found instanceof basic_1.TableType) {
|
|
93
|
-
found = new basic_1.TableType(found.getRowType(), { withHeader: true });
|
|
93
|
+
found = new basic_1.TableType(found.getRowType(), { withHeader: true, keyType: basic_1.TableKeyType.default });
|
|
94
94
|
}
|
|
95
95
|
else {
|
|
96
|
-
found = new basic_1.TableType(found, { withHeader: true });
|
|
96
|
+
found = new basic_1.TableType(found, { withHeader: true, keyType: basic_1.TableKeyType.default });
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
if ((found instanceof basic_1.UnknownType || found instanceof basic_1.VoidType) && ((_a = param.type) === null || _a === void 0 ? void 0 : _a.includes("-"))) {
|
|
@@ -143,7 +143,7 @@ class BasicTypes {
|
|
|
143
143
|
}
|
|
144
144
|
else if (child.concatTokens() === "[]") {
|
|
145
145
|
if (type instanceof Types.TableType) {
|
|
146
|
-
type = new basic_1.TableType(type.getRowType(), { withHeader: false });
|
|
146
|
+
type = new basic_1.TableType(type.getRowType(), { withHeader: false, keyType: Types.TableKeyType.default });
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
else { // field name
|
|
@@ -269,7 +269,7 @@ class BasicTypes {
|
|
|
269
269
|
return undefined;
|
|
270
270
|
}
|
|
271
271
|
parseTable(node, name) {
|
|
272
|
-
var _a, _b, _c;
|
|
272
|
+
var _a, _b, _c, _d;
|
|
273
273
|
const typename = node.findFirstExpression(Expressions.TypeName);
|
|
274
274
|
const text = (_a = node.findFirstExpression(Expressions.TypeTable)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
|
|
275
275
|
if (text === undefined) {
|
|
@@ -292,10 +292,11 @@ class BasicTypes {
|
|
|
292
292
|
}
|
|
293
293
|
const typeTableKeys = node.findAllExpressions(expressions_1.TypeTableKey);
|
|
294
294
|
const firstKey = typeTableKeys[0];
|
|
295
|
-
const isNamed = (firstKey === null || firstKey === void 0 ? void 0 : firstKey.findDirectExpression(expressions_1.Field)) !== undefined
|
|
295
|
+
const isNamed = (firstKey === null || firstKey === void 0 ? void 0 : firstKey.findDirectExpression(expressions_1.Field)) !== undefined
|
|
296
|
+
&& ((_b = firstKey === null || firstKey === void 0 ? void 0 : firstKey.findDirectExpression(expressions_1.Field)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase()) !== "PRIMARY_KEY";
|
|
296
297
|
const primaryKey = {
|
|
297
298
|
name: "primary_key",
|
|
298
|
-
type: type,
|
|
299
|
+
type: type || basic_1.TableAccessType.standard,
|
|
299
300
|
isUnique: isNamed ? false : (firstKey === null || firstKey === void 0 ? void 0 : firstKey.concatTokens().toUpperCase().includes("WITH UNIQUE ")) === true,
|
|
300
301
|
keyFields: [],
|
|
301
302
|
};
|
|
@@ -304,9 +305,6 @@ class BasicTypes {
|
|
|
304
305
|
for (const k of (firstKey === null || firstKey === void 0 ? void 0 : firstKey.findDirectExpressions(expressions_1.FieldSub)) || []) {
|
|
305
306
|
primaryKey.keyFields.push(k.concatTokens().toUpperCase());
|
|
306
307
|
}
|
|
307
|
-
if (primaryKey.keyFields.length === 0 && text.includes(" DEFAULT KEY")) {
|
|
308
|
-
primaryKey.keyFields.push("TABLE_LINE");
|
|
309
|
-
}
|
|
310
308
|
}
|
|
311
309
|
else {
|
|
312
310
|
start = 0;
|
|
@@ -314,7 +312,7 @@ class BasicTypes {
|
|
|
314
312
|
const secondaryKeys = [];
|
|
315
313
|
for (let i = start; i < typeTableKeys.length; i++) {
|
|
316
314
|
const row = typeTableKeys[i];
|
|
317
|
-
const name = (
|
|
315
|
+
const name = (_c = row.findDirectExpression(expressions_1.Field)) === null || _c === void 0 ? void 0 : _c.concatTokens();
|
|
318
316
|
if (name === undefined) {
|
|
319
317
|
continue;
|
|
320
318
|
}
|
|
@@ -329,8 +327,16 @@ class BasicTypes {
|
|
|
329
327
|
}
|
|
330
328
|
secondaryKeys.push(secondary);
|
|
331
329
|
}
|
|
330
|
+
let keyType = Types.TableKeyType.user;
|
|
331
|
+
if (text.includes(" EMPTY KEY")) {
|
|
332
|
+
keyType = Types.TableKeyType.empty;
|
|
333
|
+
}
|
|
334
|
+
else if (text.includes(" DEFAULT KEY")) {
|
|
335
|
+
keyType = Types.TableKeyType.default;
|
|
336
|
+
}
|
|
332
337
|
const options = {
|
|
333
338
|
withHeader: text.includes(" WITH HEADER LINE"),
|
|
339
|
+
keyType: keyType,
|
|
334
340
|
primaryKey: primaryKey,
|
|
335
341
|
secondary: secondaryKeys,
|
|
336
342
|
};
|
|
@@ -402,7 +408,7 @@ class BasicTypes {
|
|
|
402
408
|
else if (typename && (text.startsWith("TYPE TABLE FOR CREATE ")
|
|
403
409
|
|| text.startsWith("TYPE TABLE FOR UPDATE "))) {
|
|
404
410
|
const name = typename.concatTokens();
|
|
405
|
-
const type = (
|
|
411
|
+
const type = (_d = this.scope.getDDIC().lookupDDLS(name)) === null || _d === void 0 ? void 0 : _d.type;
|
|
406
412
|
if (type) {
|
|
407
413
|
return new Types.TableType(new basic_1.VoidType("RapTodo"), options);
|
|
408
414
|
}
|
|
@@ -477,7 +483,7 @@ class BasicTypes {
|
|
|
477
483
|
|| text === "TYPE HASHED TABLE"
|
|
478
484
|
|| text === "TYPE INDEX TABLE"
|
|
479
485
|
|| text === "TYPE ANY TABLE") {
|
|
480
|
-
return new Types.TableType(new Types.AnyType(), { withHeader: node.concatTokens().toUpperCase().includes("WITH HEADER LINE") });
|
|
486
|
+
return new Types.TableType(new Types.AnyType(), { withHeader: node.concatTokens().toUpperCase().includes("WITH HEADER LINE"), keyType: Types.TableKeyType.default });
|
|
481
487
|
}
|
|
482
488
|
else if (text.startsWith("LIKE ")) {
|
|
483
489
|
let sub = node.findFirstExpression(Expressions.Type);
|
|
@@ -495,7 +501,7 @@ class BasicTypes {
|
|
|
495
501
|
}
|
|
496
502
|
found = this.resolveLikeName(sub);
|
|
497
503
|
if (found && this.isOccurs(node)) {
|
|
498
|
-
found = new Types.TableType(found, { withHeader: text.includes("WITH HEADER LINE") }, qualifiedName);
|
|
504
|
+
found = new Types.TableType(found, { withHeader: text.includes("WITH HEADER LINE"), keyType: Types.TableKeyType.default }, qualifiedName);
|
|
499
505
|
}
|
|
500
506
|
}
|
|
501
507
|
else if (text.startsWith("TYPE LINE OF ")) {
|
|
@@ -524,17 +530,17 @@ class BasicTypes {
|
|
|
524
530
|
found = this.resolveTypeName(typeName, this.findLength(node), this.findDecimals(node), qualifiedName);
|
|
525
531
|
const concat = node.concatTokens().toUpperCase();
|
|
526
532
|
if (found && this.isOccurs(node)) {
|
|
527
|
-
found = new Types.TableType(found, { withHeader: concat.includes(" WITH HEADER LINE") }, qualifiedName);
|
|
533
|
+
found = new Types.TableType(found, { withHeader: concat.includes(" WITH HEADER LINE"), keyType: Types.TableKeyType.default }, qualifiedName);
|
|
528
534
|
}
|
|
529
535
|
else if (found && concat.includes(" WITH HEADER LINE")) {
|
|
530
536
|
if (found instanceof Types.VoidType) {
|
|
531
|
-
found = new Types.TableType(found, { withHeader: true });
|
|
537
|
+
found = new Types.TableType(found, { withHeader: true, keyType: Types.TableKeyType.default });
|
|
532
538
|
}
|
|
533
539
|
else if (!(found instanceof Types.TableType)) {
|
|
534
540
|
throw new Error("WITH HEADER LINE can only be used with internal table");
|
|
535
541
|
}
|
|
536
542
|
else {
|
|
537
|
-
found = new Types.TableType(found.getRowType(), { withHeader: true });
|
|
543
|
+
found = new Types.TableType(found.getRowType(), { withHeader: true, keyType: Types.TableKeyType.default });
|
|
538
544
|
}
|
|
539
545
|
}
|
|
540
546
|
if (found === undefined && typeName === undefined) {
|
|
@@ -548,7 +554,7 @@ class BasicTypes {
|
|
|
548
554
|
}
|
|
549
555
|
found = new Types.CharacterType(length, { qualifiedName: qualifiedName }); // fallback
|
|
550
556
|
if (this.isOccurs(node)) {
|
|
551
|
-
found = new Types.TableType(found, { withHeader: concat.includes(" WITH HEADER LINE") }, qualifiedName);
|
|
557
|
+
found = new Types.TableType(found, { withHeader: concat.includes(" WITH HEADER LINE"), keyType: Types.TableKeyType.default }, qualifiedName);
|
|
552
558
|
}
|
|
553
559
|
}
|
|
554
560
|
}
|
|
@@ -32,7 +32,7 @@ class Controls {
|
|
|
32
32
|
{ name: "LINE_SELECTOR", type: new basic_1.CharacterType(1) },
|
|
33
33
|
{ name: "H_GRID", type: new basic_1.CharacterType(1) },
|
|
34
34
|
{ name: "V_GRID", type: new basic_1.CharacterType(1) },
|
|
35
|
-
{ name: "COLS", type: new basic_1.TableType(cols, { withHeader: false }) },
|
|
35
|
+
{ name: "COLS", type: new basic_1.TableType(cols, { withHeader: false, keyType: basic_1.TableKeyType.default }) },
|
|
36
36
|
{ name: "INVISIBLE", type: new basic_1.CharacterType(1) },
|
|
37
37
|
]);
|
|
38
38
|
const id = new _typed_identifier_1.TypedIdentifier(token, filename, type);
|
|
@@ -21,13 +21,13 @@ class Find {
|
|
|
21
21
|
{ name: "LINE", type: new basic_1.IntegerType() },
|
|
22
22
|
{ name: "OFFSET", type: new basic_1.IntegerType() },
|
|
23
23
|
{ name: "LENGTH", type: new basic_1.IntegerType() },
|
|
24
|
-
{ name: "SUBMATCHES", type: new basic_1.TableType(sub, { withHeader: false }) },
|
|
24
|
+
{ name: "SUBMATCHES", type: new basic_1.TableType(sub, { withHeader: false, keyType: basic_1.TableKeyType.default }) },
|
|
25
25
|
], "MATCH_RESULT", "MATCH_RESULT");
|
|
26
26
|
if (node.concatTokens().toUpperCase().startsWith("FIND FIRST")) {
|
|
27
27
|
this.inline(rfound, scope, filename, type);
|
|
28
28
|
}
|
|
29
29
|
else {
|
|
30
|
-
this.inline(rfound, scope, filename, new basic_1.TableType(type, { withHeader: false }, "MATCH_RESULT_TAB"));
|
|
30
|
+
this.inline(rfound, scope, filename, new basic_1.TableType(type, { withHeader: false, keyType: basic_1.TableKeyType.default }, "MATCH_RESULT_TAB"));
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
const ofound = node.findExpressionsAfterToken("OFFSET");
|
|
@@ -21,7 +21,7 @@ class Ranges {
|
|
|
21
21
|
{ name: "low", type: found },
|
|
22
22
|
{ name: "high", type: found },
|
|
23
23
|
]);
|
|
24
|
-
const type = new basic_1.TableType(structure, { withHeader: true });
|
|
24
|
+
const type = new basic_1.TableType(structure, { withHeader: true, keyType: basic_1.TableKeyType.default });
|
|
25
25
|
const id = new _typed_identifier_1.TypedIdentifier(nameToken, filename, type);
|
|
26
26
|
scope.addIdentifier(id);
|
|
27
27
|
}
|
|
@@ -39,7 +39,7 @@ class SelectOption {
|
|
|
39
39
|
{ name: "LOW", type: found },
|
|
40
40
|
{ name: "HIGH", type: found },
|
|
41
41
|
]);
|
|
42
|
-
scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(nameToken, filename, new basic_1.TableType(stru, { withHeader: true })));
|
|
42
|
+
scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(nameToken, filename, new basic_1.TableType(stru, { withHeader: true, keyType: basic_1.TableKeyType.default })));
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
45
|
if (nameToken) {
|
|
@@ -10,7 +10,7 @@ const _type_utils_1 = require("../_type_utils");
|
|
|
10
10
|
class Split {
|
|
11
11
|
runSyntax(node, scope, filename) {
|
|
12
12
|
const intoTable = node.findTokenSequencePosition("INTO", "TABLE") !== undefined;
|
|
13
|
-
const type = intoTable ? new basic_1.TableType(new basic_1.StringType(), { withHeader: false }) : new basic_1.StringType();
|
|
13
|
+
const type = intoTable ? new basic_1.TableType(new basic_1.StringType(), { withHeader: false, keyType: basic_1.TableKeyType.default }) : new basic_1.StringType();
|
|
14
14
|
for (const target of node.findAllExpressions(Expressions.Target)) {
|
|
15
15
|
const inline = target.findDirectExpression(Expressions.InlineData);
|
|
16
16
|
if (inline) {
|
|
@@ -58,7 +58,7 @@ class Data {
|
|
|
58
58
|
}
|
|
59
59
|
if (found instanceof Basic.VoidType) {
|
|
60
60
|
if (table === true) {
|
|
61
|
-
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(found, { withHeader: true }));
|
|
61
|
+
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(found, { withHeader: true, keyType: Basic.TableKeyType.default }));
|
|
62
62
|
}
|
|
63
63
|
else {
|
|
64
64
|
return new _typed_identifier_1.TypedIdentifier(name, filename, found);
|
|
@@ -76,7 +76,7 @@ class Data {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
if (table === true) {
|
|
79
|
-
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(new Basic.StructureType(components), { withHeader: true }));
|
|
79
|
+
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(new Basic.StructureType(components), { withHeader: true, keyType: Basic.TableKeyType.default }));
|
|
80
80
|
}
|
|
81
81
|
else {
|
|
82
82
|
const val = Object.keys(values).length > 0 ? values : undefined;
|
|
@@ -49,7 +49,7 @@ class Statics {
|
|
|
49
49
|
}
|
|
50
50
|
if (found instanceof Basic.VoidType) {
|
|
51
51
|
if (table === true) {
|
|
52
|
-
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(found, { withHeader: true }));
|
|
52
|
+
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(found, { withHeader: true, keyType: Basic.TableKeyType.default }));
|
|
53
53
|
}
|
|
54
54
|
else {
|
|
55
55
|
return new _typed_identifier_1.TypedIdentifier(name, filename, found);
|
|
@@ -67,7 +67,7 @@ class Statics {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
if (table === true) {
|
|
70
|
-
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(new Basic.StructureType(components), { withHeader: true }));
|
|
70
|
+
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(new Basic.StructureType(components), { withHeader: true, keyType: Basic.TableKeyType.default }));
|
|
71
71
|
}
|
|
72
72
|
else {
|
|
73
73
|
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.StructureType(components));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TableType = exports.TableAccessType = void 0;
|
|
3
|
+
exports.TableType = exports.TableKeyType = exports.TableAccessType = void 0;
|
|
4
4
|
const _abstract_type_1 = require("./_abstract_type");
|
|
5
5
|
var TableAccessType;
|
|
6
6
|
(function (TableAccessType) {
|
|
@@ -10,6 +10,12 @@ var TableAccessType;
|
|
|
10
10
|
TableAccessType["index"] = "INDEX";
|
|
11
11
|
TableAccessType["any"] = "ANY";
|
|
12
12
|
})(TableAccessType = exports.TableAccessType || (exports.TableAccessType = {}));
|
|
13
|
+
var TableKeyType;
|
|
14
|
+
(function (TableKeyType) {
|
|
15
|
+
TableKeyType["default"] = "DEFAULT";
|
|
16
|
+
TableKeyType["user"] = "USER";
|
|
17
|
+
TableKeyType["empty"] = "EMPTY";
|
|
18
|
+
})(TableKeyType = exports.TableKeyType || (exports.TableKeyType = {}));
|
|
13
19
|
class TableType extends _abstract_type_1.AbstractType {
|
|
14
20
|
constructor(rowType, options, qualifiedName) {
|
|
15
21
|
var _a;
|
|
@@ -49,6 +55,7 @@ class TableType extends _abstract_type_1.AbstractType {
|
|
|
49
55
|
isGeneric() {
|
|
50
56
|
var _a, _b;
|
|
51
57
|
if (((_a = this.options.primaryKey) === null || _a === void 0 ? void 0 : _a.type) !== TableAccessType.standard
|
|
58
|
+
&& this.options.keyType === TableKeyType.user
|
|
52
59
|
&& ((_b = this.options.primaryKey) === null || _b === void 0 ? void 0 : _b.keyFields.length) === 0) {
|
|
53
60
|
return true;
|
|
54
61
|
}
|
|
@@ -49,10 +49,10 @@ class FormDefinition extends _identifier_1.Identifier {
|
|
|
49
49
|
let type = p.getType();
|
|
50
50
|
const isStructure = param.findDirectTokenByText("STRUCTURE") !== undefined;
|
|
51
51
|
if (isStructure) {
|
|
52
|
-
type = new basic_1.TableType(type, { withHeader: true });
|
|
52
|
+
type = new basic_1.TableType(type, { withHeader: true, keyType: basic_1.TableKeyType.default });
|
|
53
53
|
}
|
|
54
54
|
if (type instanceof basic_1.TableType) {
|
|
55
|
-
type = new basic_1.TableType(type.getRowType(), { withHeader: true });
|
|
55
|
+
type = new basic_1.TableType(type.getRowType(), { withHeader: true, keyType: basic_1.TableKeyType.default });
|
|
56
56
|
}
|
|
57
57
|
else if (!(type instanceof basic_1.UnknownType) && !(type instanceof basic_1.VoidType)) {
|
|
58
58
|
type = new basic_1.UnknownType("FORM TABLES type must be table type");
|
package/build/src/ddic.js
CHANGED
|
@@ -66,7 +66,7 @@ class DDIC {
|
|
|
66
66
|
case "%_C_POINTER":
|
|
67
67
|
return new Types.HexType(8, qualifiedName);
|
|
68
68
|
case "TABLE":
|
|
69
|
-
return new Types.TableType(new Types.AnyType(), { withHeader: false });
|
|
69
|
+
return new Types.TableType(new Types.AnyType(), { withHeader: false, keyType: Types.TableKeyType.default });
|
|
70
70
|
case "DATA":
|
|
71
71
|
return new Types.AnyType({ qualifiedName: qualifiedName });
|
|
72
72
|
case "NUMERIC":
|
|
@@ -32,6 +32,7 @@ class TableType extends _abstract_object_1.AbstractObject {
|
|
|
32
32
|
var _a, _b, _c;
|
|
33
33
|
const tableOptions = {
|
|
34
34
|
withHeader: false,
|
|
35
|
+
keyType: Types.TableKeyType.user,
|
|
35
36
|
secondary: [],
|
|
36
37
|
};
|
|
37
38
|
for (const k of ((_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.dd43v) || []) {
|
package/build/src/registry.js
CHANGED
|
@@ -24,7 +24,7 @@ class ConstantClasses {
|
|
|
24
24
|
title: "Validate constant classes",
|
|
25
25
|
shortDescription: `Checks that a class contains exactly the constants corresponding to a domain's fixed values.`,
|
|
26
26
|
extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#prefer-enumeration-classes-to-constants-interfaces`,
|
|
27
|
-
tags: [_irule_1.RuleTag.Styleguide
|
|
27
|
+
tags: [_irule_1.RuleTag.Styleguide],
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
initialize(reg) {
|
|
@@ -122,7 +122,7 @@ class Downport {
|
|
|
122
122
|
return {
|
|
123
123
|
key: "downport",
|
|
124
124
|
title: "Downport statement",
|
|
125
|
-
shortDescription: `
|
|
125
|
+
shortDescription: `Downport functionality`,
|
|
126
126
|
extendedInformation: `Much like the 'commented_code' rule this rule loops through unknown statements and tries parsing with
|
|
127
127
|
a higher level language version. If successful, various rules are applied to downport the statement.
|
|
128
128
|
Target downport version is always v702, thus rule is only enabled if target version is v702.
|
|
@@ -155,7 +155,7 @@ Current rules:
|
|
|
155
155
|
* MESSAGE with non simple source
|
|
156
156
|
|
|
157
157
|
Only one transformation is applied to a statement at a time, so multiple steps might be required to do the full downport.`,
|
|
158
|
-
tags: [_irule_1.RuleTag.
|
|
158
|
+
tags: [_irule_1.RuleTag.Downport, _irule_1.RuleTag.Quickfix],
|
|
159
159
|
};
|
|
160
160
|
}
|
|
161
161
|
getConfig() {
|
package/build/src/rules/index.js
CHANGED
|
@@ -142,6 +142,7 @@ __exportStar(require("./space_before_dot"), exports);
|
|
|
142
142
|
__exportStar(require("./sql_escape_host_variables"), exports);
|
|
143
143
|
__exportStar(require("./start_at_tab"), exports);
|
|
144
144
|
__exportStar(require("./static_call_via_instance"), exports);
|
|
145
|
+
__exportStar(require("./strict_sql"), exports);
|
|
145
146
|
__exportStar(require("./superclass_final"), exports);
|
|
146
147
|
__exportStar(require("./superfluous_value"), exports);
|
|
147
148
|
__exportStar(require("./sy_modification"), exports);
|
|
@@ -23,7 +23,7 @@ class SQLEscapeHostVariables extends _abap_rule_1.ABAPRule {
|
|
|
23
23
|
title: "Escape SQL host variables",
|
|
24
24
|
shortDescription: `Escape SQL host variables, from 740sp05`,
|
|
25
25
|
extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#avoid-obsolete-language-elements`,
|
|
26
|
-
tags: [_irule_1.RuleTag.Upport, _irule_1.RuleTag.Styleguide, _irule_1.RuleTag.Quickfix],
|
|
26
|
+
tags: [_irule_1.RuleTag.Upport, _irule_1.RuleTag.Styleguide, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.Syntax],
|
|
27
27
|
badExample: `SELECT * FROM tab INTO TABLE res WHERE field = val.`,
|
|
28
28
|
goodExample: `SELECT * FROM tab INTO TABLE @res WHERE field = @val.`,
|
|
29
29
|
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StrictSQL = exports.StrictSQLConf = void 0;
|
|
4
|
+
const Statements = require("../abap/2_statements/statements");
|
|
5
|
+
const Expressions = require("../abap/2_statements/expressions");
|
|
6
|
+
const issue_1 = require("../issue");
|
|
7
|
+
const _abap_rule_1 = require("./_abap_rule");
|
|
8
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
9
|
+
const version_1 = require("../version");
|
|
10
|
+
const _irule_1 = require("./_irule");
|
|
11
|
+
class StrictSQLConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
12
|
+
}
|
|
13
|
+
exports.StrictSQLConf = StrictSQLConf;
|
|
14
|
+
class StrictSQL extends _abap_rule_1.ABAPRule {
|
|
15
|
+
constructor() {
|
|
16
|
+
super(...arguments);
|
|
17
|
+
this.conf = new StrictSQLConf();
|
|
18
|
+
}
|
|
19
|
+
getMetadata() {
|
|
20
|
+
return {
|
|
21
|
+
key: "strict_sql",
|
|
22
|
+
title: "Strict SQL",
|
|
23
|
+
shortDescription: `Strict SQL`,
|
|
24
|
+
extendedInformation: `https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-US/abapinto_clause.htm
|
|
25
|
+
|
|
26
|
+
https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-us/abenopensql_strict_mode_750.htm
|
|
27
|
+
|
|
28
|
+
Also see separate rule sql_escape_host_variables`,
|
|
29
|
+
tags: [_irule_1.RuleTag.Upport, _irule_1.RuleTag.Syntax],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
getConfig() {
|
|
33
|
+
return this.conf;
|
|
34
|
+
}
|
|
35
|
+
setConfig(conf) {
|
|
36
|
+
this.conf = conf;
|
|
37
|
+
}
|
|
38
|
+
runParsed(file, obj) {
|
|
39
|
+
const issues = [];
|
|
40
|
+
const type = obj.getType();
|
|
41
|
+
if (type === "INTF" || type === "TYPE") {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
if (this.reg.getConfig().getVersion() < version_1.Version.v740sp02
|
|
45
|
+
&& this.reg.getConfig().getVersion() !== version_1.Version.Cloud) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
for (const s of file.getStatements()) {
|
|
49
|
+
if (s.get() instanceof Statements.Select
|
|
50
|
+
|| s.get() instanceof Statements.SelectLoop) {
|
|
51
|
+
const expr = s.findDirectExpression(Expressions.Select);
|
|
52
|
+
const where = expr === null || expr === void 0 ? void 0 : expr.findDirectExpression(Expressions.SQLCond);
|
|
53
|
+
const into = (expr === null || expr === void 0 ? void 0 : expr.findDirectExpression(Expressions.SQLIntoStructure))
|
|
54
|
+
|| (expr === null || expr === void 0 ? void 0 : expr.findDirectExpression(Expressions.SQLIntoTable));
|
|
55
|
+
if (into === undefined || where === undefined) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (where.getFirstToken().getStart().isBefore(into.getFirstToken().getStart())) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const message = "INTO/APPENDING must be last in strict SQL";
|
|
62
|
+
const issue = issue_1.Issue.atToken(file, s.getFirstToken(), message, this.getMetadata().key, this.conf.severity);
|
|
63
|
+
issues.push(issue);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return issues;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.StrictSQL = StrictSQL;
|
|
71
|
+
//# sourceMappingURL=strict_sql.js.map
|