@abaplint/runtime 2.13.92 → 2.13.93
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/escape.d.ts +2 -2
- package/build/src/builtin/escape.js +29 -4
- package/build/src/compare/eq.js +10 -3
- package/build/src/compare/gt.js +8 -2
- 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/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/shift.js +22 -4
- package/build/src/statements/sort.js +22 -0
- package/build/src/statements/write.js +9 -6
- 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/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { String } from "../types";
|
|
1
|
+
import { FieldSymbol, String } from "../types";
|
|
2
2
|
import { ICharacter } from "../types/_character";
|
|
3
3
|
import { INumeric } from "../types/_numeric";
|
|
4
4
|
export declare function escape(input: {
|
|
5
|
-
val: ICharacter | string;
|
|
5
|
+
val: ICharacter | FieldSymbol | string;
|
|
6
6
|
format: INumeric | number;
|
|
7
7
|
}): String;
|
|
@@ -3,8 +3,35 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.escape = escape;
|
|
4
4
|
const types_1 = require("../types");
|
|
5
5
|
const _position_1 = require("./_position");
|
|
6
|
+
const JSON_SHORT = {
|
|
7
|
+
"\\": "\\\\",
|
|
8
|
+
"\"": "\\\"",
|
|
9
|
+
"\b": "\\b",
|
|
10
|
+
"\t": "\\t",
|
|
11
|
+
"\n": "\\n",
|
|
12
|
+
"\f": "\\f",
|
|
13
|
+
"\r": "\\r",
|
|
14
|
+
};
|
|
15
|
+
// backslash, quote, and \b \t \n \f \r by their short forms; the other control
|
|
16
|
+
// characters below U+0020 as \u00XX in upper case hex; U+007F and non-ASCII unchanged
|
|
17
|
+
function escapeJsonCharacter(char) {
|
|
18
|
+
return JSON_SHORT[char] ?? "\\u" + char.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0");
|
|
19
|
+
}
|
|
6
20
|
function escape(input) {
|
|
7
|
-
let
|
|
21
|
+
let source;
|
|
22
|
+
if (input.val instanceof types_1.FieldSymbol) {
|
|
23
|
+
const pointer = input.val.getPointer();
|
|
24
|
+
if (pointer === undefined) {
|
|
25
|
+
throw new Error("GETWA_NOT_ASSIGNED");
|
|
26
|
+
}
|
|
27
|
+
source = pointer;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
source = input.val;
|
|
31
|
+
}
|
|
32
|
+
// a c operand counts without its trailing blanks, as in the other string functions
|
|
33
|
+
let val = typeof source === "string" ? source
|
|
34
|
+
: source instanceof types_1.Character ? source.getTrimEnd() : source.get();
|
|
8
35
|
const format = (0, _position_1.position)(input.format);
|
|
9
36
|
// todo, optimize/cache regexes
|
|
10
37
|
switch (format) {
|
|
@@ -34,9 +61,7 @@ function escape(input) {
|
|
|
34
61
|
val = val.replace(/'/g, "\\'");
|
|
35
62
|
break;
|
|
36
63
|
case 24: // e_json_string
|
|
37
|
-
val = val.replace(
|
|
38
|
-
val = val.replace(/"/g, "\\\"");
|
|
39
|
-
val = val.replace(/\n/g, "\\n");
|
|
64
|
+
val = val.replace(/[\\"\u0000-\u001F]/g, escapeJsonCharacter);
|
|
40
65
|
break;
|
|
41
66
|
default:
|
|
42
67
|
// todo, runtime error
|
package/build/src/compare/eq.js
CHANGED
|
@@ -4,7 +4,6 @@ exports.eq = eq;
|
|
|
4
4
|
/* eslint-disable max-len */
|
|
5
5
|
const types_1 = require("../types");
|
|
6
6
|
const _parse_1 = require("../operators/_parse");
|
|
7
|
-
const initial_1 = require("./initial");
|
|
8
7
|
function compareTables(left, right) {
|
|
9
8
|
const leftArray = left.array();
|
|
10
9
|
const rightArray = right.array();
|
|
@@ -35,6 +34,14 @@ function compareStructures(left, right) {
|
|
|
35
34
|
}
|
|
36
35
|
return true;
|
|
37
36
|
}
|
|
37
|
+
// two x fields of different lengths: the shorter one is padded with 00 on the
|
|
38
|
+
// right, so x'AB' = x'AB00'
|
|
39
|
+
function eqHexPadded(left, right) {
|
|
40
|
+
const l = left.get();
|
|
41
|
+
const r = right.get();
|
|
42
|
+
const length = Math.max(l.length, r.length);
|
|
43
|
+
return l.padEnd(length, "0") === r.padEnd(length, "0");
|
|
44
|
+
}
|
|
38
45
|
// module locals instead of the imported bindings, as the CommonJS re-export
|
|
39
46
|
// getters add overhead on every access in the hot path below
|
|
40
47
|
const IntegerC = types_1.Integer;
|
|
@@ -107,7 +114,7 @@ function eq(left, right) {
|
|
|
107
114
|
}
|
|
108
115
|
else if (leftConstructor === HexC || leftConstructor === HexUInt8C) {
|
|
109
116
|
if (left.getLength() !== right.getLength()) {
|
|
110
|
-
return (
|
|
117
|
+
return eqHexPadded(left, right);
|
|
111
118
|
}
|
|
112
119
|
return left.get() === right.get();
|
|
113
120
|
}
|
|
@@ -211,7 +218,7 @@ function eq(left, right) {
|
|
|
211
218
|
if (left instanceof types_1.Hex || left instanceof types_1.HexUInt8) {
|
|
212
219
|
// @ts-ignore
|
|
213
220
|
if (right.getLength && right.getLength() !== left.getLength()) {
|
|
214
|
-
return (
|
|
221
|
+
return eqHexPadded(left, right);
|
|
215
222
|
}
|
|
216
223
|
return right.get() === left.get();
|
|
217
224
|
}
|
package/build/src/compare/gt.js
CHANGED
|
@@ -112,8 +112,14 @@ function gt(left, right) {
|
|
|
112
112
|
}
|
|
113
113
|
///////////////////////////////////////////////////////////////////
|
|
114
114
|
function gt_with_hex(left, right) {
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
let left_hex = get_hex_from_parameter(left);
|
|
116
|
+
let right_hex = get_hex_from_parameter(right);
|
|
117
|
+
if ((left instanceof types_1.Hex || left instanceof types_1.HexUInt8) && (right instanceof types_1.Hex || right instanceof types_1.HexUInt8)) {
|
|
118
|
+
// two x fields of different lengths: the shorter one is padded with 00 on the right
|
|
119
|
+
const length = Math.max(left_hex.length, right_hex.length);
|
|
120
|
+
left_hex = left_hex.padEnd(length, "0");
|
|
121
|
+
right_hex = right_hex.padEnd(length, "0");
|
|
122
|
+
}
|
|
117
123
|
return left_hex > right_hex;
|
|
118
124
|
}
|
|
119
125
|
function get_hex_from_parameter(comparison_part) {
|
package/build/src/expand_in.js
CHANGED
|
@@ -1,42 +1,80 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.expandIN = expandIN;
|
|
4
|
+
function toSQLValue(value) {
|
|
5
|
+
if (typeof value === "number") {
|
|
6
|
+
return value.toString();
|
|
7
|
+
}
|
|
8
|
+
return `'` + String(value ?? "").replace(/'/g, "''") + "'";
|
|
9
|
+
}
|
|
10
|
+
// one row of a ranges table as a condition that is true when the row matches
|
|
11
|
+
function rowCondition(field, sign, option, low, high) {
|
|
12
|
+
const lowValue = toSQLValue(low);
|
|
13
|
+
switch (option) {
|
|
14
|
+
case "EQ":
|
|
15
|
+
return `${field} = ${lowValue}`;
|
|
16
|
+
case "NE":
|
|
17
|
+
return `${field} <> ${lowValue}`;
|
|
18
|
+
case "GT":
|
|
19
|
+
return `${field} > ${lowValue}`;
|
|
20
|
+
case "GE":
|
|
21
|
+
return `${field} >= ${lowValue}`;
|
|
22
|
+
case "LT":
|
|
23
|
+
return `${field} < ${lowValue}`;
|
|
24
|
+
case "LE":
|
|
25
|
+
return `${field} <= ${lowValue}`;
|
|
26
|
+
case "BT":
|
|
27
|
+
return `(${field} >= ${lowValue} AND ${field} <= ${toSQLValue(high)})`;
|
|
28
|
+
case "NB":
|
|
29
|
+
return `NOT (${field} >= ${lowValue} AND ${field} <= ${toSQLValue(high)})`;
|
|
30
|
+
case "CP":
|
|
31
|
+
case "NP":
|
|
32
|
+
{
|
|
33
|
+
if (sign !== "I" || option !== "CP") {
|
|
34
|
+
// the pattern rules come with a separate change; until then only I CP, as before
|
|
35
|
+
throw new Error(`IN, ${sign} ${option} not supported`);
|
|
36
|
+
}
|
|
37
|
+
const like = `${field} LIKE '` + String(low ?? "").trimEnd().replace(/'/g, "''").replace(/\*/g, "%") + "'";
|
|
38
|
+
return option === "CP" ? like : `NOT ${like}`;
|
|
39
|
+
}
|
|
40
|
+
default:
|
|
41
|
+
throw new Error(`IN, ${sign} ${option} not supported`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
4
44
|
// note: must always return an expression, never return empty string
|
|
5
45
|
// https://www.sqlite.org/lang_select.html
|
|
46
|
+
// The rows with SIGN I are ORed, AND NOT the OR of the rows with SIGN E; a
|
|
47
|
+
// table with E rows only excludes them from everything.
|
|
6
48
|
function expandIN(fieldName, table) {
|
|
7
|
-
let ret = "";
|
|
8
49
|
if (table.array().length === 0) {
|
|
9
50
|
// " NOT IN ()" does not work on postgres
|
|
10
51
|
// LIKE '%' does not work in snowflake with RTRIM collation
|
|
11
|
-
|
|
52
|
+
return `true`;
|
|
12
53
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
else if (row.get().sign?.get() === "I" && row.get().option?.get() === "GE") {
|
|
26
|
-
values.push(`"${fieldName}" >= ` + val);
|
|
27
|
-
}
|
|
28
|
-
else if (row.get().sign?.get() === "I" && row.get().option?.get() === "LE") {
|
|
29
|
-
values.push(`"${fieldName}" <= ` + val);
|
|
30
|
-
}
|
|
31
|
-
else if (row.get().sign?.get() === "I" && row.get().option?.get() === "CP") {
|
|
32
|
-
values.push(`"${fieldName}" LIKE '` + row.get().low?.get().trimEnd().replace(/'/g, "''").replace(/\*/g, "%") + "'");
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
throw new Error(`IN, ${row.get().sign?.get()} ${row.get().option?.get()} not supported`);
|
|
36
|
-
}
|
|
54
|
+
const field = `"${fieldName.replace("~", `"."`)}"`;
|
|
55
|
+
const include = [];
|
|
56
|
+
const exclude = [];
|
|
57
|
+
for (const row of table.array()) {
|
|
58
|
+
const sign = row.get().sign?.get();
|
|
59
|
+
const option = row.get().option?.get();
|
|
60
|
+
if (sign !== "I" && sign !== "E") {
|
|
61
|
+
throw new Error(`IN, ${sign} ${option} not supported`);
|
|
62
|
+
}
|
|
63
|
+
const cond = rowCondition(field, sign, option, row.get().low?.get(), row.get().high?.get());
|
|
64
|
+
if (sign === "I") {
|
|
65
|
+
include.push(cond);
|
|
37
66
|
}
|
|
38
|
-
|
|
67
|
+
else {
|
|
68
|
+
exclude.push(cond);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const parts = [];
|
|
72
|
+
if (include.length > 0) {
|
|
73
|
+
parts.push("(" + include.join(" OR ") + ")");
|
|
74
|
+
}
|
|
75
|
+
if (exclude.length > 0) {
|
|
76
|
+
parts.push("NOT (" + exclude.join(" OR ") + ")");
|
|
39
77
|
}
|
|
40
|
-
return
|
|
78
|
+
return "(" + parts.join(" AND ") + ")";
|
|
41
79
|
}
|
|
42
80
|
//# sourceMappingURL=expand_in.js.map
|
|
@@ -1,6 +1,2 @@
|
|
|
1
1
|
import { XString } from "../types";
|
|
2
|
-
export declare function
|
|
3
|
-
leftChunk: number;
|
|
4
|
-
rightChunk: number;
|
|
5
|
-
chunkLen: number;
|
|
6
|
-
}[];
|
|
2
|
+
export declare function bit_operation(left: XString, right: XString, op: (l: number, r: number) => number): XString;
|
|
@@ -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
|
|
@@ -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;
|
|
@@ -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) {
|
package/build/src/types/date.js
CHANGED
|
@@ -32,7 +32,13 @@ class Date {
|
|
|
32
32
|
else if (value instanceof float_1.Float) {
|
|
33
33
|
this.set(Math.round(value.getRaw()));
|
|
34
34
|
}
|
|
35
|
+
else if (value instanceof string_1.String) {
|
|
36
|
+
// an empty string is the initial date, a shorter one is filled with blanks
|
|
37
|
+
const str = value.get();
|
|
38
|
+
this.value = str === "" ? "00000000" : str;
|
|
39
|
+
}
|
|
35
40
|
else if (typeof value === "string") {
|
|
41
|
+
// raw character results, eg. from CONCATENATE, are filled with blanks
|
|
36
42
|
this.value = value;
|
|
37
43
|
}
|
|
38
44
|
else {
|
package/build/src/types/hex.js
CHANGED
|
@@ -6,7 +6,7 @@ const float_1 = require("./float");
|
|
|
6
6
|
const xstring_1 = require("./xstring");
|
|
7
7
|
const throw_error_1 = require("../throw_error");
|
|
8
8
|
const integer8_1 = require("./integer8");
|
|
9
|
-
const
|
|
9
|
+
const HEX_PREFIX = /^[A-F0-9]*/;
|
|
10
10
|
class Hex {
|
|
11
11
|
value;
|
|
12
12
|
length;
|
|
@@ -73,9 +73,12 @@ class Hex {
|
|
|
73
73
|
return this.set(v);
|
|
74
74
|
}
|
|
75
75
|
else {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
// c -> x: the leading hexadecimal digits, upper case only, and a
|
|
77
|
+
// trailing half byte padded with 0; the first other character ends
|
|
78
|
+
// the conversion, so "ABG1" is AB, "0a1B" is 00
|
|
79
|
+
this.value = HEX_PREFIX.exec(v)[0];
|
|
80
|
+
if (this.value.length % 2 === 1) {
|
|
81
|
+
this.value += "0";
|
|
79
82
|
}
|
|
80
83
|
}
|
|
81
84
|
}
|
|
@@ -93,14 +93,11 @@ class Integer {
|
|
|
93
93
|
this.set(roundHalfAwayFromZero(value.getRaw()));
|
|
94
94
|
}
|
|
95
95
|
else if (value instanceof hex_1.Hex || value instanceof xstring_1.XString || value instanceof hex_uint8_1.HexUInt8) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (hex.length
|
|
100
|
-
|
|
101
|
-
if (num > maxVal / 2 - 1) {
|
|
102
|
-
num = num - maxVal;
|
|
103
|
-
}
|
|
96
|
+
// the last four bytes, 00 on the left, as a signed integer; an empty xstring is 0
|
|
97
|
+
const hex = value.get().slice(-8);
|
|
98
|
+
let num = hex === "" ? 0 : parseInt(hex, 16);
|
|
99
|
+
if (hex.length === 8 && num > 0x7FFFFFFF) {
|
|
100
|
+
num = num - 0x100000000;
|
|
104
101
|
}
|
|
105
102
|
this.set(num);
|
|
106
103
|
}
|