@abaplint/runtime 2.13.92 → 2.13.94
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/src/builtin/_extremum.d.ts +9 -0
- package/build/src/builtin/_extremum.js +75 -0
- package/build/src/builtin/escape.d.ts +2 -2
- package/build/src/builtin/escape.js +29 -4
- package/build/src/builtin/nmax.d.ts +1 -2
- package/build/src/builtin/nmax.js +3 -28
- package/build/src/builtin/nmin.d.ts +1 -2
- package/build/src/builtin/nmin.js +3 -28
- package/build/src/builtin/round.d.ts +14 -5
- package/build/src/builtin/round.js +69 -21
- package/build/src/compare/eq.js +20 -3
- package/build/src/compare/gt.js +8 -2
- package/build/src/compare/in.d.ts +3 -1
- package/build/src/compare/in.js +35 -18
- package/build/src/expand_in.js +66 -28
- package/build/src/operators/_bit_operations.d.ts +1 -5
- package/build/src/operators/_bit_operations.js +24 -23
- package/build/src/operators/bit-and.js +1 -11
- package/build/src/operators/bit-or.js +1 -11
- package/build/src/operators/bit-xor.js +1 -11
- package/build/src/primary_key.d.ts +2 -0
- package/build/src/primary_key.js +49 -0
- package/build/src/statements/concatenate.js +13 -3
- package/build/src/statements/create_data.js +14 -2
- package/build/src/statements/delete_database.js +15 -0
- package/build/src/statements/delete_internal.d.ts +1 -0
- package/build/src/statements/delete_internal.js +14 -3
- package/build/src/statements/describe.js +17 -1
- package/build/src/statements/insert_database.d.ts +1 -0
- package/build/src/statements/insert_database.js +11 -0
- package/build/src/statements/read_table.js +93 -7
- package/build/src/statements/shift.js +22 -4
- package/build/src/statements/sort.js +22 -0
- package/build/src/statements/write.js +9 -6
- package/build/src/template_formatting.js +18 -4
- package/build/src/types/date.js +6 -0
- package/build/src/types/hex.js +7 -4
- package/build/src/types/integer.js +5 -8
- package/build/src/types/table.js +11 -1
- package/package.json +1 -1
|
@@ -1,29 +1,30 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
let
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const chunkEnd = maxLen - (pass - 1) * 6;
|
|
18
|
-
let leftSlice = leftFull.slice(chunkStart, chunkEnd);
|
|
19
|
-
let rightSlice = rightFull.slice(chunkStart, chunkEnd);
|
|
20
|
-
const chunkLen = leftSlice.length > rightSlice.length ? leftSlice.length : rightSlice.length;
|
|
21
|
-
leftSlice = leftSlice.padEnd(chunkLen, "0");
|
|
22
|
-
rightSlice = rightSlice.padEnd(chunkLen, "0");
|
|
23
|
-
const leftChunk = parseInt(leftSlice, 16);
|
|
24
|
-
const rightChunk = parseInt(rightSlice, 16);
|
|
25
|
-
ret.push({ leftChunk: leftChunk, rightChunk: rightChunk, chunkLen: chunkLen });
|
|
3
|
+
exports.bit_operation = bit_operation;
|
|
4
|
+
/*eslint no-bitwise: ["error", { "allow": [">>>"] }] */
|
|
5
|
+
const types_1 = require("../types");
|
|
6
|
+
// the shorter operand is padded with hex 0 on the right
|
|
7
|
+
function bit_operation(left, right, op) {
|
|
8
|
+
let leftHex = left.get();
|
|
9
|
+
let rightHex = right.get();
|
|
10
|
+
const maxLen = Math.ceil(Math.max(leftHex.length, rightHex.length) / 2) * 2;
|
|
11
|
+
leftHex = leftHex.padEnd(maxLen, "0");
|
|
12
|
+
rightHex = rightHex.padEnd(maxLen, "0");
|
|
13
|
+
let result;
|
|
14
|
+
if (maxLen > 0 && maxLen <= 8) {
|
|
15
|
+
// up to 4 bytes in one 32 bit operation, >>> 0 makes the result unsigned
|
|
16
|
+
result = (op(parseInt(leftHex, 16), parseInt(rightHex, 16)) >>> 0).toString(16).padStart(maxLen, "0");
|
|
26
17
|
}
|
|
18
|
+
else {
|
|
19
|
+
const l = Buffer.from(leftHex, "hex");
|
|
20
|
+
const r = Buffer.from(rightHex, "hex");
|
|
21
|
+
for (let i = 0; i < l.length; i++) {
|
|
22
|
+
l[i] = op(l[i], r[i]);
|
|
23
|
+
}
|
|
24
|
+
result = l.toString("hex");
|
|
25
|
+
}
|
|
26
|
+
const ret = new types_1.XString();
|
|
27
|
+
ret.set(result.toUpperCase());
|
|
27
28
|
return ret;
|
|
28
29
|
}
|
|
29
30
|
//# sourceMappingURL=_bit_operations.js.map
|
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.bitand = bitand;
|
|
4
|
-
/*eslint no-bitwise: ["error", { "allow": ["&"] }] */
|
|
5
|
-
const types_1 = require("../types");
|
|
6
4
|
const _bit_operations_1 = require("./_bit_operations");
|
|
7
5
|
function bitand(left, right) {
|
|
8
|
-
|
|
9
|
-
const chunks = (0, _bit_operations_1.get_bit_operation_chunks)(left, right);
|
|
10
|
-
// eslint-disable-next-line no-cond-assign
|
|
11
|
-
for (let i = 0, chunk; chunk = chunks[i]; i++) {
|
|
12
|
-
and = and + (chunk.leftChunk & chunk.rightChunk).toString(16).toUpperCase().padStart(chunk.chunkLen, "0");
|
|
13
|
-
}
|
|
14
|
-
const ret = new types_1.XString();
|
|
15
|
-
ret.set(and);
|
|
16
|
-
return ret;
|
|
6
|
+
return (0, _bit_operations_1.bit_operation)(left, right, (l, r) => l & r);
|
|
17
7
|
}
|
|
18
8
|
//# sourceMappingURL=bit-and.js.map
|
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.bitor = bitor;
|
|
4
|
-
/*eslint no-bitwise: ["error", { "allow": ["|"] }] */
|
|
5
|
-
const types_1 = require("../types");
|
|
6
4
|
const _bit_operations_1 = require("./_bit_operations");
|
|
7
5
|
function bitor(left, right) {
|
|
8
|
-
|
|
9
|
-
const chunks = (0, _bit_operations_1.get_bit_operation_chunks)(left, right);
|
|
10
|
-
// eslint-disable-next-line no-cond-assign
|
|
11
|
-
for (let i = 0, chunk; chunk = chunks[i]; i++) {
|
|
12
|
-
or = or + (chunk.leftChunk | chunk.rightChunk).toString(16).toUpperCase().padStart(chunk.chunkLen, "0");
|
|
13
|
-
}
|
|
14
|
-
const ret = new types_1.XString();
|
|
15
|
-
ret.set(or);
|
|
16
|
-
return ret;
|
|
6
|
+
return (0, _bit_operations_1.bit_operation)(left, right, (l, r) => l | r);
|
|
17
7
|
}
|
|
18
8
|
//# sourceMappingURL=bit-or.js.map
|
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.bitxor = bitxor;
|
|
4
|
-
/*eslint no-bitwise: ["error", { "allow": ["^"] }] */
|
|
5
|
-
const types_1 = require("../types");
|
|
6
4
|
const _bit_operations_1 = require("./_bit_operations");
|
|
7
5
|
function bitxor(left, right) {
|
|
8
|
-
|
|
9
|
-
const chunks = (0, _bit_operations_1.get_bit_operation_chunks)(left, right);
|
|
10
|
-
// eslint-disable-next-line no-cond-assign
|
|
11
|
-
for (let i = 0, chunk; chunk = chunks[i]; i++) {
|
|
12
|
-
xor = xor + (chunk.leftChunk ^ chunk.rightChunk).toString(16).toUpperCase().padStart(chunk.chunkLen, "0");
|
|
13
|
-
}
|
|
14
|
-
const ret = new types_1.XString();
|
|
15
|
-
ret.set(xor);
|
|
16
|
-
return ret;
|
|
6
|
+
return (0, _bit_operations_1.bit_operation)(left, right, (l, r) => l ^ r);
|
|
17
7
|
}
|
|
18
8
|
//# sourceMappingURL=bit-xor.js.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.primaryKeyValues = primaryKeyValues;
|
|
4
|
+
const types_1 = require("./types");
|
|
5
|
+
// the standard key, all character-like and byte-like components, substructures expanded
|
|
6
|
+
function standardKeyValues(row) {
|
|
7
|
+
if (!(row instanceof types_1.Structure)) {
|
|
8
|
+
return [row];
|
|
9
|
+
}
|
|
10
|
+
const ret = [];
|
|
11
|
+
for (const component of Object.values(row.get())) {
|
|
12
|
+
if (component instanceof types_1.Structure) {
|
|
13
|
+
ret.push(...standardKeyValues(component));
|
|
14
|
+
}
|
|
15
|
+
else if (component instanceof types_1.Character
|
|
16
|
+
|| component instanceof types_1.Numc
|
|
17
|
+
|| component instanceof types_1.Date
|
|
18
|
+
|| component instanceof types_1.Time
|
|
19
|
+
|| component instanceof types_1.String
|
|
20
|
+
|| component instanceof types_1.Hex
|
|
21
|
+
|| component instanceof types_1.HexUInt8
|
|
22
|
+
|| component instanceof types_1.XString) {
|
|
23
|
+
ret.push(component);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return ret;
|
|
27
|
+
}
|
|
28
|
+
// values of the primary key, an empty key gives no values
|
|
29
|
+
function primaryKeyValues(target, row) {
|
|
30
|
+
const options = target.getOptions();
|
|
31
|
+
if (options?.keyType === types_1.TableKeyType.empty) {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
const keyFields = options?.primaryKey?.keyFields ?? [];
|
|
35
|
+
if (keyFields.length === 0) {
|
|
36
|
+
return standardKeyValues(row);
|
|
37
|
+
}
|
|
38
|
+
return keyFields.map(k => {
|
|
39
|
+
if (k.toUpperCase() === "TABLE_LINE") {
|
|
40
|
+
return row;
|
|
41
|
+
}
|
|
42
|
+
let value = row;
|
|
43
|
+
for (const name of k.toLowerCase().split("-")) {
|
|
44
|
+
value = value.get()[name];
|
|
45
|
+
}
|
|
46
|
+
return value;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=primary_key.js.map
|
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.concatenate = concatenate;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
|
+
// sy-subrc 4 when a c target cuts the result, else 0
|
|
6
|
+
function setTarget(target, result) {
|
|
7
|
+
let subrc = 0;
|
|
8
|
+
const pointer = target instanceof types_1.FieldSymbol ? target.getPointer() : target;
|
|
9
|
+
if (pointer instanceof types_1.Character && result.trimEnd().length > pointer.getLength()) {
|
|
10
|
+
subrc = 4;
|
|
11
|
+
}
|
|
12
|
+
target.set(result);
|
|
13
|
+
abap.builtin.sy.get().subrc.set(subrc);
|
|
14
|
+
}
|
|
5
15
|
function concatenate(input) {
|
|
6
16
|
if (input.byteMode === true) {
|
|
7
17
|
concatenateByteMode(input);
|
|
@@ -32,7 +42,7 @@ function concatenate(input) {
|
|
|
32
42
|
result += respectingBlanks === true ? value : value.trimEnd();
|
|
33
43
|
}
|
|
34
44
|
}
|
|
35
|
-
input.target
|
|
45
|
+
setTarget(input.target, result);
|
|
36
46
|
}
|
|
37
47
|
else {
|
|
38
48
|
let result = "";
|
|
@@ -60,7 +70,7 @@ function concatenate(input) {
|
|
|
60
70
|
if (sep.length > 0 && result.length > 0) {
|
|
61
71
|
result = result.slice(0, result.length - sep.length);
|
|
62
72
|
}
|
|
63
|
-
input.target
|
|
73
|
+
setTarget(input.target, result);
|
|
64
74
|
}
|
|
65
75
|
}
|
|
66
76
|
function rawByteValue(source) {
|
|
@@ -99,6 +109,6 @@ function concatenateByteMode(input) {
|
|
|
99
109
|
if (sep.length > 0 && result.length > 0) {
|
|
100
110
|
result = result.slice(0, result.length - sep.length);
|
|
101
111
|
}
|
|
102
|
-
input.target
|
|
112
|
+
setTarget(input.target, result);
|
|
103
113
|
}
|
|
104
114
|
//# sourceMappingURL=concatenate.js.map
|
|
@@ -21,6 +21,18 @@ function createDataRefTo(target, name) {
|
|
|
21
21
|
}
|
|
22
22
|
target.assign(new abap.types.ABAPObject({ qualifiedName: name, RTTIName: name }));
|
|
23
23
|
}
|
|
24
|
+
/** CREATE DATA ... LIKE dobj takes the type of dobj, never its content: the
|
|
25
|
+
* created data object starts initial. A table is created empty right away
|
|
26
|
+
* instead of copying its rows first. */
|
|
27
|
+
function initialLike(like) {
|
|
28
|
+
if (like instanceof types_1.Table || like instanceof types_1.HashedTable) {
|
|
29
|
+
const TableType = like.constructor;
|
|
30
|
+
return new TableType(like.getRowType(), like.getOptions(), like.getQualifiedName());
|
|
31
|
+
}
|
|
32
|
+
const copy = like.clone();
|
|
33
|
+
copy.clear();
|
|
34
|
+
return copy;
|
|
35
|
+
}
|
|
24
36
|
function createData(target, options) {
|
|
25
37
|
// console.dir(options);
|
|
26
38
|
if (target instanceof types_1.FieldSymbol) {
|
|
@@ -208,10 +220,10 @@ function createData(target, options) {
|
|
|
208
220
|
options.like = options.like.getPointer();
|
|
209
221
|
}
|
|
210
222
|
if (options.table === true) {
|
|
211
|
-
target.assign(new abap.types.Table(options.like
|
|
223
|
+
target.assign(new abap.types.Table(initialLike(options.like), tableOptions));
|
|
212
224
|
}
|
|
213
225
|
else {
|
|
214
|
-
target.assign(options.like
|
|
226
|
+
target.assign(initialLike(options.like));
|
|
215
227
|
}
|
|
216
228
|
}
|
|
217
229
|
else {
|
|
@@ -15,14 +15,29 @@ async function deleteDatabase(table, options, context) {
|
|
|
15
15
|
table = table.get().trimEnd();
|
|
16
16
|
}
|
|
17
17
|
if (options.table) {
|
|
18
|
+
// one DELETE per row; sy-subrc is 4 when any row was not found,
|
|
19
|
+
// sy-dbcnt counts the rows deleted
|
|
20
|
+
let subrc = 0;
|
|
21
|
+
let dbcnt = 0;
|
|
18
22
|
for (const row of options.table.array()) {
|
|
19
23
|
await deleteDatabase(table, { from: row }, context);
|
|
24
|
+
if (abap.builtin.sy.get().subrc.get() !== 0) {
|
|
25
|
+
subrc = 4;
|
|
26
|
+
}
|
|
27
|
+
dbcnt += abap.builtin.sy.get().dbcnt.get();
|
|
20
28
|
}
|
|
29
|
+
abap.builtin.sy.get().subrc.set(subrc);
|
|
30
|
+
abap.builtin.sy.get().dbcnt.set(dbcnt);
|
|
21
31
|
}
|
|
22
32
|
else if (options.from) {
|
|
23
33
|
let where = [];
|
|
34
|
+
// the row is found by its primary key, the other fields are not compared
|
|
35
|
+
const keys = abap.DDIC[table.toUpperCase()]?.keyFields;
|
|
24
36
|
const structure = options.from.get();
|
|
25
37
|
for (const k of Object.keys(structure)) {
|
|
38
|
+
if (keys !== undefined && keys.length > 0 && keys.includes(k.toUpperCase()) === false) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
26
41
|
const str = `"${k.toLowerCase()}"` + " = " + (0, insert_database_1.toValue)(structure[k].get());
|
|
27
42
|
where.push(str);
|
|
28
43
|
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.deleteInternal = deleteInternal;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
5
|
const compare_1 = require("../compare");
|
|
6
|
+
const primary_key_1 = require("../primary_key");
|
|
6
7
|
const loop_1 = require("./loop");
|
|
7
8
|
async function deleteInternal(target, options) {
|
|
8
9
|
let index = 0;
|
|
@@ -50,7 +51,12 @@ async function deleteInternal(target, options) {
|
|
|
50
51
|
for (let index = array.length - 1; index > 0; index--) {
|
|
51
52
|
const prev = array[index - 1];
|
|
52
53
|
const i = array[index];
|
|
53
|
-
if (options?.
|
|
54
|
+
if (options?.allFields === true) {
|
|
55
|
+
if ((0, compare_1.eq)(prev, i) === true) {
|
|
56
|
+
target.deleteIndex(index);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else if (options?.comparing) {
|
|
54
60
|
let match = false;
|
|
55
61
|
for (const compareField of options.comparing) {
|
|
56
62
|
match = (0, compare_1.eq)(prev.get()[compareField], i.get()[compareField]);
|
|
@@ -62,8 +68,13 @@ async function deleteInternal(target, options) {
|
|
|
62
68
|
target.deleteIndex(index);
|
|
63
69
|
}
|
|
64
70
|
}
|
|
65
|
-
else
|
|
66
|
-
|
|
71
|
+
else {
|
|
72
|
+
// without COMPARING, rows are compared by the primary key, nothing is deleted if the key is empty
|
|
73
|
+
const prevKey = (0, primary_key_1.primaryKeyValues)(target, prev);
|
|
74
|
+
const key = (0, primary_key_1.primaryKeyValues)(target, i);
|
|
75
|
+
if (key.length > 0 && key.every((value, n) => (0, compare_1.eq)(prevKey[n], value))) {
|
|
76
|
+
target.deleteIndex(index);
|
|
77
|
+
}
|
|
67
78
|
}
|
|
68
79
|
}
|
|
69
80
|
return;
|
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.describe = describe;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
|
+
// a structure is deep when a component is a string, a table or a reference,
|
|
6
|
+
// or a deep structure itself: type kind v, a flat structure is u
|
|
7
|
+
function isDeep(structure) {
|
|
8
|
+
for (const component of Object.values(structure.get())) {
|
|
9
|
+
if (component instanceof types_1.String
|
|
10
|
+
|| component instanceof types_1.XString
|
|
11
|
+
|| component instanceof types_1.Table
|
|
12
|
+
|| component instanceof types_1.HashedTable
|
|
13
|
+
|| component instanceof types_1.DataReference
|
|
14
|
+
|| component instanceof types_1.ABAPObject
|
|
15
|
+
|| (component instanceof types_1.Structure && isDeep(component))) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
5
21
|
function describe(input) {
|
|
6
22
|
// console.dir(input);
|
|
7
23
|
if (input.type) {
|
|
@@ -49,7 +65,7 @@ function describe(input) {
|
|
|
49
65
|
input.type.set("e");
|
|
50
66
|
}
|
|
51
67
|
else if (input.field instanceof types_1.Structure) {
|
|
52
|
-
input.type.set("u");
|
|
68
|
+
input.type.set(isDeep(input.field) ? "v" : "u");
|
|
53
69
|
}
|
|
54
70
|
else if (input.field instanceof types_1.ABAPObject) {
|
|
55
71
|
input.type.set("r");
|
|
@@ -6,5 +6,6 @@ export interface IInsertDatabaseOptions {
|
|
|
6
6
|
values?: Structure;
|
|
7
7
|
table?: Table;
|
|
8
8
|
connection?: string;
|
|
9
|
+
acceptingDuplicateKeys?: boolean;
|
|
9
10
|
}
|
|
10
11
|
export declare function insertDatabase(table: string | ICharacter, options: IInsertDatabaseOptions, context: Context): Promise<number | undefined>;
|
|
@@ -4,6 +4,7 @@ exports.toValue = toValue;
|
|
|
4
4
|
exports.insertDatabase = insertDatabase;
|
|
5
5
|
const prefix_1 = require("../prefix");
|
|
6
6
|
const types_1 = require("../types");
|
|
7
|
+
const throw_error_1 = require("../throw_error");
|
|
7
8
|
function toValue(value) {
|
|
8
9
|
if (typeof value === "string") {
|
|
9
10
|
// postgres requires ' for values
|
|
@@ -21,6 +22,8 @@ async function insertDatabase(table, options, context) {
|
|
|
21
22
|
throw new Error("insertDatabase, wrong input");
|
|
22
23
|
}
|
|
23
24
|
if (options.table !== undefined) {
|
|
25
|
+
const subrcBefore = abap.builtin.sy.get().subrc.get();
|
|
26
|
+
const dbcntBefore = abap.builtin.sy.get().dbcnt.get();
|
|
24
27
|
let subrc = 0;
|
|
25
28
|
let dbcnt = 0;
|
|
26
29
|
for (const row of options.table.array()) {
|
|
@@ -28,6 +31,14 @@ async function insertDatabase(table, options, context) {
|
|
|
28
31
|
subrc = Math.max(subrc, abap.builtin.sy.get().subrc.get());
|
|
29
32
|
dbcnt += abap.builtin.sy.get().dbcnt.get();
|
|
30
33
|
}
|
|
34
|
+
if (subrc !== 0 && options.acceptingDuplicateKeys !== true) {
|
|
35
|
+
// without ACCEPTING DUPLICATE KEYS a row that cannot be inserted raises
|
|
36
|
+
// CX_SY_OPEN_SQL_DB; the other rows stay inserted and sy-subrc and
|
|
37
|
+
// sy-dbcnt keep the values they had before the statement
|
|
38
|
+
abap.builtin.sy.get().subrc.set(subrcBefore);
|
|
39
|
+
abap.builtin.sy.get().dbcnt.set(dbcntBefore);
|
|
40
|
+
await (0, throw_error_1.throwErrorWithParameters)("CX_SY_OPEN_SQL_DB", { sqlmsg: new types_1.String().set(`INSERT ${typeof table === "string" ? table : table.get().trimEnd()} FROM TABLE: a row could not be inserted (duplicate key?)`) });
|
|
41
|
+
}
|
|
31
42
|
abap.builtin.sy.get().subrc.set(subrc);
|
|
32
43
|
abap.builtin.sy.get().dbcnt.set(dbcnt);
|
|
33
44
|
return;
|
|
@@ -90,6 +90,73 @@ async function searchWithKeyPromise(arr, withKey, startIndex = 0, usesTableLine)
|
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
92
|
/////////////////
|
|
93
|
+
function toRow(a, isStructured, usesTableLine) {
|
|
94
|
+
if (usesTableLine === false && isStructured === true) {
|
|
95
|
+
return a.get();
|
|
96
|
+
}
|
|
97
|
+
return isStructured ? { table_line: a, ...a.get() } : { table_line: a };
|
|
98
|
+
}
|
|
99
|
+
/** READ with a key on a SORTED table: binary search over the leading key components that are given,
|
|
100
|
+
* a miss gives sy-subrc 4 and sy-tabix of the row the key would be inserted before,
|
|
101
|
+
* or sy-subrc 8 and sy-tabix lines + 1 when it would be inserted after the last row */
|
|
102
|
+
/** true when every component of the condition is a component of the key */
|
|
103
|
+
function onlyKeyComponents(keyFields, options) {
|
|
104
|
+
const key = keyFields.map(k => k.toLowerCase());
|
|
105
|
+
return Object.keys(options.withKeySimple || {}).every(n => key.includes(n.toLowerCase()));
|
|
106
|
+
}
|
|
107
|
+
function readSortedWithKey(arr, keyFields, options) {
|
|
108
|
+
const names = Object.keys(options.withKeySimple).map(n => n.toLowerCase());
|
|
109
|
+
const prefix = [];
|
|
110
|
+
for (const keyField of keyFields) {
|
|
111
|
+
const index = names.indexOf(keyField.toLowerCase());
|
|
112
|
+
if (index < 0) {
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
prefix.push(options.withKeyValue[index]);
|
|
116
|
+
}
|
|
117
|
+
if (prefix.length === 0) {
|
|
118
|
+
const searchResult = searchWithKey(arr, options.withKey, 0, options.usesTableLine);
|
|
119
|
+
return { found: searchResult.found, foundIndex: searchResult.foundIndex, subrc: undefined };
|
|
120
|
+
}
|
|
121
|
+
const isStructured = arr[0] instanceof types_1.Structure;
|
|
122
|
+
const comparePrefix = (row) => {
|
|
123
|
+
for (const p of prefix) {
|
|
124
|
+
const value = p.key(row);
|
|
125
|
+
// eq first, lt and gt compare a c operand with its trailing blanks against a string
|
|
126
|
+
if ((0, compare_1.eq)(value, p.value)) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
else if ((0, compare_1.lt)(value, p.value)) {
|
|
130
|
+
return -1;
|
|
131
|
+
}
|
|
132
|
+
else if ((0, compare_1.gt)(value, p.value)) {
|
|
133
|
+
return 1;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return 0;
|
|
137
|
+
};
|
|
138
|
+
let left = 0;
|
|
139
|
+
let right = arr.length;
|
|
140
|
+
while (left < right) {
|
|
141
|
+
const middle = Math.floor((left + right) / 2);
|
|
142
|
+
if (comparePrefix(toRow(arr[middle], isStructured, options.usesTableLine)) < 0) {
|
|
143
|
+
left = middle + 1;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
right = middle;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
for (let index = left; index < arr.length; index++) {
|
|
150
|
+
const row = toRow(arr[index], isStructured, options.usesTableLine);
|
|
151
|
+
if (comparePrefix(row) !== 0) {
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
if (options.withKey(row) === true) {
|
|
155
|
+
return { found: arr[index], foundIndex: index + 1, subrc: undefined };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return { found: undefined, foundIndex: left + 1, subrc: left >= arr.length ? 8 : 4 };
|
|
159
|
+
}
|
|
93
160
|
function readTable(table, options) {
|
|
94
161
|
let found = undefined;
|
|
95
162
|
let foundIndex = 0;
|
|
@@ -187,15 +254,34 @@ function readTable(table, options) {
|
|
|
187
254
|
// fallback
|
|
188
255
|
return readTable(table, { ...options, withKeySimple: undefined });
|
|
189
256
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
257
|
+
if (keyInformation?.type === types_1.TableAccessType.sorted
|
|
258
|
+
&& options.withKeyValue
|
|
259
|
+
&& onlyKeyComponents(keyInformation.keyFields, options)) {
|
|
260
|
+
const result = readSortedWithKey(arr, keyInformation.keyFields, options);
|
|
261
|
+
found = result.found;
|
|
262
|
+
foundIndex = result.foundIndex;
|
|
263
|
+
binarySubrc = result.subrc;
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
const startIndex = (0, binary_search_1.binarySearchFrom)(arr, 0, arr.length, firstKeyName.toLowerCase(), firstValue) - 1;
|
|
267
|
+
if (startIndex >= 0) {
|
|
268
|
+
const searchResult = searchWithKeyEarlyExit(arr, options.withKey, startIndex, options.usesTableLine, firstKeyName, firstValue);
|
|
269
|
+
found = searchResult.found;
|
|
270
|
+
foundIndex = searchResult.foundIndex;
|
|
271
|
+
}
|
|
197
272
|
}
|
|
198
273
|
}
|
|
274
|
+
else if (options?.withTableKey === true
|
|
275
|
+
&& options.withKeyValue
|
|
276
|
+
&& options.withKeySimple
|
|
277
|
+
&& options.withKey
|
|
278
|
+
&& table.getOptions().primaryKey?.type === types_1.TableAccessType.sorted
|
|
279
|
+
&& onlyKeyComponents(table.getOptions().primaryKey?.keyFields || [], options)) {
|
|
280
|
+
const result = readSortedWithKey(table.array(), table.getOptions().primaryKey?.keyFields || [], options);
|
|
281
|
+
found = result.found;
|
|
282
|
+
foundIndex = result.foundIndex;
|
|
283
|
+
binarySubrc = result.subrc;
|
|
284
|
+
}
|
|
199
285
|
else if ((options?.binarySearch === true || options?.withTableKey === true)
|
|
200
286
|
&& options.withKeyValue
|
|
201
287
|
&& (options?.binarySearch === true || table.getOptions().primaryKey?.type !== types_1.TableAccessType.standard)
|
|
@@ -37,11 +37,17 @@ function shift_character_mode(target, options) {
|
|
|
37
37
|
else if (options?.places) {
|
|
38
38
|
const p = options.places.get();
|
|
39
39
|
if (options.circular) {
|
|
40
|
-
|
|
40
|
+
if (options.direction === "RIGHT") {
|
|
41
|
+
value = value.substr(value.length - p) + value.substr(0, value.length - p);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
value = value.substr(p) + value.substr(0, p);
|
|
45
|
+
}
|
|
41
46
|
}
|
|
42
47
|
else {
|
|
43
48
|
if (options.direction === "RIGHT") {
|
|
44
|
-
|
|
49
|
+
// set() cuts a fixed length target, a string gets longer
|
|
50
|
+
value = " ".repeat(p) + value;
|
|
45
51
|
}
|
|
46
52
|
else {
|
|
47
53
|
value = value.substr(p);
|
|
@@ -69,6 +75,9 @@ function shift_character_mode(target, options) {
|
|
|
69
75
|
value = value.substr(1) + value.substr(0, 1);
|
|
70
76
|
}
|
|
71
77
|
}
|
|
78
|
+
else if (options?.direction === "RIGHT") {
|
|
79
|
+
value = " " + value;
|
|
80
|
+
}
|
|
72
81
|
else {
|
|
73
82
|
value = value.substr(1);
|
|
74
83
|
}
|
|
@@ -107,7 +116,8 @@ function shift_byte_mode(target, options) {
|
|
|
107
116
|
else {
|
|
108
117
|
const p = options.places.get() * 2;
|
|
109
118
|
if (options.direction === "RIGHT") {
|
|
110
|
-
|
|
119
|
+
// set() cuts a fixed length target, an xstring gets longer
|
|
120
|
+
value = "0".repeat(p) + value;
|
|
111
121
|
}
|
|
112
122
|
else {
|
|
113
123
|
value = value.substr(p);
|
|
@@ -128,7 +138,15 @@ function shift_byte_mode(target, options) {
|
|
|
128
138
|
}
|
|
129
139
|
}
|
|
130
140
|
else if (options?.circular) {
|
|
131
|
-
|
|
141
|
+
if (options.direction === "RIGHT") {
|
|
142
|
+
value = value.substr(value.length - 2) + value.substr(0, value.length - 2);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
value = value.substr(2) + value.substr(0, 2);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (options?.direction === "RIGHT") {
|
|
149
|
+
value = "00" + value;
|
|
132
150
|
}
|
|
133
151
|
else {
|
|
134
152
|
value = value.substr(2);
|
|
@@ -4,6 +4,7 @@ exports.compareRows = compareRows;
|
|
|
4
4
|
exports.sort = sort;
|
|
5
5
|
const types_1 = require("../types");
|
|
6
6
|
const compare_1 = require("../compare");
|
|
7
|
+
const primary_key_1 = require("../primary_key");
|
|
7
8
|
function compare(a, b, input) {
|
|
8
9
|
const componentName = input.component;
|
|
9
10
|
const descending = input.descending;
|
|
@@ -124,6 +125,27 @@ function sort(input, options) {
|
|
|
124
125
|
return 0;
|
|
125
126
|
});
|
|
126
127
|
}
|
|
128
|
+
else if (input instanceof types_1.Table
|
|
129
|
+
&& input.getRowType() instanceof types_1.Structure
|
|
130
|
+
&& input.getOptions()?.keyType !== types_1.TableKeyType.empty) {
|
|
131
|
+
// without BY, rows of a structure are sorted by the primary key
|
|
132
|
+
const descending = options?.descending === true;
|
|
133
|
+
const keys = new Map();
|
|
134
|
+
for (const row of input.array()) {
|
|
135
|
+
keys.set(row, (0, primary_key_1.primaryKeyValues)(input, row));
|
|
136
|
+
}
|
|
137
|
+
input.sort((a, b) => {
|
|
138
|
+
const keyA = keys.get(a);
|
|
139
|
+
const keyB = keys.get(b);
|
|
140
|
+
for (let i = 0; i < keyA.length; i++) {
|
|
141
|
+
const result = compareWholeRows(keyA[i], keyB[i]);
|
|
142
|
+
if (result !== 0) {
|
|
143
|
+
return descending ? -result : result;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return 0;
|
|
147
|
+
});
|
|
148
|
+
}
|
|
127
149
|
else {
|
|
128
150
|
const descending = options?.descending === true;
|
|
129
151
|
input.sort((a, b) => {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.WriteStatement = void 0;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
|
+
const field_symbol_1 = require("../types/field_symbol");
|
|
5
6
|
const NO_DEICMAL_CURRENCIES = ["HUF", "KRW", "JPY"];
|
|
6
7
|
class WriteStatement {
|
|
7
8
|
context;
|
|
@@ -28,19 +29,21 @@ class WriteStatement {
|
|
|
28
29
|
const obj = source.getCharacter();
|
|
29
30
|
this.write(obj, { ...options });
|
|
30
31
|
}
|
|
31
|
-
else if (source instanceof types_1.Float) {
|
|
32
|
+
else if (source instanceof types_1.Float || (source instanceof field_symbol_1.FieldSymbol && source.getPointer() instanceof types_1.Float)) {
|
|
33
|
+
// a float behind a field symbol is formatted the same way
|
|
34
|
+
const float = source instanceof field_symbol_1.FieldSymbol ? source.getPointer() : source;
|
|
32
35
|
if (options?.exponent?.get() === 0) {
|
|
33
|
-
const tens =
|
|
34
|
-
if (options.noSign === true &&
|
|
35
|
-
result =
|
|
36
|
+
const tens = float.getRaw().toFixed(0).length - 1;
|
|
37
|
+
if (options.noSign === true && float.getRaw() < 0) {
|
|
38
|
+
result = float.getRaw().toFixed(17 - tens).replace(".", ",");
|
|
36
39
|
result = result.replace("-", "");
|
|
37
40
|
}
|
|
38
41
|
else {
|
|
39
|
-
result =
|
|
42
|
+
result = float.getRaw().toFixed(16 - tens).replace(".", ",");
|
|
40
43
|
}
|
|
41
44
|
}
|
|
42
45
|
else {
|
|
43
|
-
result =
|
|
46
|
+
result = float.get().toString();
|
|
44
47
|
}
|
|
45
48
|
}
|
|
46
49
|
else if (source instanceof types_1.Packed) {
|