@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.
Files changed (40) hide show
  1. package/build/src/builtin/_extremum.d.ts +9 -0
  2. package/build/src/builtin/_extremum.js +75 -0
  3. package/build/src/builtin/escape.d.ts +2 -2
  4. package/build/src/builtin/escape.js +29 -4
  5. package/build/src/builtin/nmax.d.ts +1 -2
  6. package/build/src/builtin/nmax.js +3 -28
  7. package/build/src/builtin/nmin.d.ts +1 -2
  8. package/build/src/builtin/nmin.js +3 -28
  9. package/build/src/builtin/round.d.ts +14 -5
  10. package/build/src/builtin/round.js +69 -21
  11. package/build/src/compare/eq.js +20 -3
  12. package/build/src/compare/gt.js +8 -2
  13. package/build/src/compare/in.d.ts +3 -1
  14. package/build/src/compare/in.js +35 -18
  15. package/build/src/expand_in.js +66 -28
  16. package/build/src/operators/_bit_operations.d.ts +1 -5
  17. package/build/src/operators/_bit_operations.js +24 -23
  18. package/build/src/operators/bit-and.js +1 -11
  19. package/build/src/operators/bit-or.js +1 -11
  20. package/build/src/operators/bit-xor.js +1 -11
  21. package/build/src/primary_key.d.ts +2 -0
  22. package/build/src/primary_key.js +49 -0
  23. package/build/src/statements/concatenate.js +13 -3
  24. package/build/src/statements/create_data.js +14 -2
  25. package/build/src/statements/delete_database.js +15 -0
  26. package/build/src/statements/delete_internal.d.ts +1 -0
  27. package/build/src/statements/delete_internal.js +14 -3
  28. package/build/src/statements/describe.js +17 -1
  29. package/build/src/statements/insert_database.d.ts +1 -0
  30. package/build/src/statements/insert_database.js +11 -0
  31. package/build/src/statements/read_table.js +93 -7
  32. package/build/src/statements/shift.js +22 -4
  33. package/build/src/statements/sort.js +22 -0
  34. package/build/src/statements/write.js +9 -6
  35. package/build/src/template_formatting.js +18 -4
  36. package/build/src/types/date.js +6 -0
  37. package/build/src/types/hex.js +7 -4
  38. package/build/src/types/integer.js +5 -8
  39. package/build/src/types/table.js +11 -1
  40. package/package.json +1 -1
@@ -1,29 +1,30 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.get_bit_operation_chunks = get_bit_operation_chunks;
4
- function get_bit_operation_chunks(left, right) {
5
- const ret = [];
6
- let leftFull = left.get();
7
- const leftLen = leftFull.length;
8
- leftFull = leftFull.padEnd(Math.ceil(leftLen / 2) * 2, "0");
9
- let rightFull = right.get();
10
- const rightLen = rightFull.length;
11
- rightFull = rightFull.padEnd(Math.ceil(rightLen / 2) * 2, "0");
12
- const maxLen = leftFull.length > rightFull.length ? leftFull.length : rightFull.length;
13
- // Using 3-byte chunkgs (6 hex positions) to avoid JavaScript negative values for extreme cases
14
- const chunks = maxLen / 6;
15
- for (let pass = chunks; pass > 0; pass--) {
16
- const chunkStart = maxLen - pass * 6;
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
- let and = "";
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
- let or = "";
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
- let xor = "";
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,2 @@
1
+ import { Table } from "./types";
2
+ export declare function primaryKeyValues(target: Table, row: any): any[];
@@ -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.set(result);
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.set(result);
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.set(result);
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.clone(), tableOptions));
223
+ target.assign(new abap.types.Table(initialLike(options.like), tableOptions));
212
224
  }
213
225
  else {
214
- target.assign(options.like.clone());
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
  }
@@ -5,6 +5,7 @@ export interface IDeleteInternalOptions {
5
5
  index?: INumeric;
6
6
  adjacent?: boolean;
7
7
  comparing?: string[];
8
+ allFields?: boolean;
8
9
  fromValue?: any;
9
10
  from?: any;
10
11
  to?: any;
@@ -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?.comparing) {
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 if ((0, compare_1.eq)(prev, i) === true) {
66
- target.deleteIndex(index);
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
- const startIndex = (0, binary_search_1.binarySearchFrom)(arr, 0, arr.length, firstKeyName.toLowerCase(), firstValue) - 1;
191
- // console.dir("startindex: " + startIndex);
192
- if (startIndex >= 0) {
193
- const searchResult = searchWithKeyEarlyExit(arr, options.withKey, startIndex, options.usesTableLine, firstKeyName, firstValue);
194
- // console.dir(searchResult);
195
- found = searchResult.found;
196
- foundIndex = searchResult.foundIndex;
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
- value = value.substr(p) + value.substr(0, p);
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
- value = " ".repeat(options.places.get()) + value.substring(0, options.places.get());
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
- value = "0".repeat(p) + value.substring(0, p);
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
- value = value.substr(2) + value.substr(0, 2);
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 = source.getRaw().toFixed(0).length - 1;
34
- if (options.noSign === true && source.getRaw() < 0) {
35
- result = source.getRaw().toFixed(17 - tens).replace(".", ",");
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 = source.getRaw().toFixed(16 - tens).replace(".", ",");
42
+ result = float.getRaw().toFixed(16 - tens).replace(".", ",");
40
43
  }
41
44
  }
42
45
  else {
43
- result = source.get().toString();
46
+ result = float.get().toString();
44
47
  }
45
48
  }
46
49
  else if (source instanceof types_1.Packed) {