limitsdb 0.5.0__py3-none-any.whl
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.
- limitsdb/__init__.py +0 -0
- limitsdb/cli/__init__.py +0 -0
- limitsdb/cli/ldb_crypt.py +44 -0
- limitsdb/cli/ldb_impl.py +207 -0
- limitsdb/cli/ldb_init.py +60 -0
- limitsdb/cli/ldb_run.py +53 -0
- limitsdb/core/__init__.py +0 -0
- limitsdb/core/ldb_config_loader.py +198 -0
- limitsdb/core/ldb_crypto.py +91 -0
- limitsdb/core/ldb_errors.py +30 -0
- limitsdb/core/ldb_ilm_config.py +228 -0
- limitsdb/core/ldb_logger.py +57 -0
- limitsdb/core/ldb_meta.py +31 -0
- limitsdb/core/ldb_params_config.py +459 -0
- limitsdb/core/ldb_runner.py +810 -0
- limitsdb/core/ldb_status.py +8 -0
- limitsdb/core/ldb_utils.py +332 -0
- limitsdb/db/__init__.py +0 -0
- limitsdb/db/ldb_engine_loader.py +16 -0
- limitsdb/db/ldb_engines.py +347 -0
- limitsdb/db/oracle/__init__.py +0 -0
- limitsdb/db/oracle/ldb_conf.sql +151 -0
- limitsdb/db/oracle/ldb_engine_impl.py +1505 -0
- limitsdb/resources/__init__.py +0 -0
- limitsdb/resources/ilm.example.yml +71 -0
- limitsdb-0.5.0.dist-info/METADATA +586 -0
- limitsdb-0.5.0.dist-info/RECORD +32 -0
- limitsdb-0.5.0.dist-info/WHEEL +4 -0
- limitsdb-0.5.0.dist-info/entry_points.txt +6 -0
- limitsdb-0.5.0.dist-info/licenses/LICENSE +118 -0
- limitsdb-0.5.0.dist-info/licenses/LICENSE-DUAL.md +59 -0
- limitsdb-0.5.0.dist-info/licenses/NOTICE +12 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from collections.abc import Mapping, Sequence
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from typing import Any, Literal
|
|
8
|
+
|
|
9
|
+
from limitsdb.core.ldb_params_config import Config
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(frozen=True)
|
|
13
|
+
class ColumnDefinition:
|
|
14
|
+
"""Generic column definition independent from a specific engine."""
|
|
15
|
+
|
|
16
|
+
name: str
|
|
17
|
+
data_type: str
|
|
18
|
+
id: int | None = None
|
|
19
|
+
length: int | None = None
|
|
20
|
+
precision: int | None = None
|
|
21
|
+
scale: int | None = None
|
|
22
|
+
nullable: bool = True
|
|
23
|
+
default: str | None = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
IndexMap = dict[str, dict[str, Any]]
|
|
27
|
+
ColumnMetadata = dict[str, ColumnDefinition]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass(frozen=True)
|
|
31
|
+
class IndexDefinition:
|
|
32
|
+
"""Generic index definition."""
|
|
33
|
+
|
|
34
|
+
name: str
|
|
35
|
+
columns: tuple[str, ...]
|
|
36
|
+
unique: bool = False
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass(frozen=True)
|
|
40
|
+
class TableDefinition:
|
|
41
|
+
"""Generic table definition."""
|
|
42
|
+
|
|
43
|
+
owner: str
|
|
44
|
+
name: str
|
|
45
|
+
columns: tuple[ColumnDefinition, ...]
|
|
46
|
+
primary_key: tuple[str, ...] | None = None
|
|
47
|
+
indexes: tuple[IndexDefinition, ...] = ()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass(frozen=True)
|
|
51
|
+
class SequenceDefinition:
|
|
52
|
+
"""Generic sequence definition."""
|
|
53
|
+
|
|
54
|
+
owner: str
|
|
55
|
+
name: str
|
|
56
|
+
start_with: int = 1
|
|
57
|
+
increment_by: int = 1
|
|
58
|
+
minvalue: int | None = None
|
|
59
|
+
maxvalue: int | None = None
|
|
60
|
+
cycle: bool = False
|
|
61
|
+
cache: int | None = 20
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dataclass(frozen=True)
|
|
65
|
+
class RoleDefinition:
|
|
66
|
+
"""Generic role definition."""
|
|
67
|
+
|
|
68
|
+
name: str
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass(frozen=True)
|
|
72
|
+
class UserDefinition:
|
|
73
|
+
"""Generic user definition."""
|
|
74
|
+
|
|
75
|
+
name: str
|
|
76
|
+
password: str
|
|
77
|
+
default_tablespace: str | None = None
|
|
78
|
+
temporary_tablespace: str | None = None
|
|
79
|
+
roles: tuple[str, ...] = ()
|
|
80
|
+
roles_with_admin_option: tuple[str, ...] = ()
|
|
81
|
+
system_privileges: tuple[str, ...] = ()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@dataclass(frozen=True)
|
|
85
|
+
class DatabaseLinkDefinition:
|
|
86
|
+
"""Generic database link definition."""
|
|
87
|
+
|
|
88
|
+
name: str
|
|
89
|
+
username: str
|
|
90
|
+
password: str
|
|
91
|
+
dsn: str
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class DatabaseEngine(ABC):
|
|
95
|
+
"""Static interface for database engine operations."""
|
|
96
|
+
|
|
97
|
+
@staticmethod
|
|
98
|
+
@abstractmethod
|
|
99
|
+
def get_connection(config: Config, *, admin: bool = False, env: Literal["SOURCE", "HISTORY"] | None = None) -> Any:
|
|
100
|
+
"""Establishes a connection to the database.
|
|
101
|
+
Args:
|
|
102
|
+
config: Configuration object.
|
|
103
|
+
admin: If True, connects with admin credentials.
|
|
104
|
+
Returns:
|
|
105
|
+
An open database connection."""
|
|
106
|
+
pass
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
@abstractmethod
|
|
110
|
+
def close_connection(conn: Any) -> None:
|
|
111
|
+
"""Closes the Oracle connection.
|
|
112
|
+
Args:
|
|
113
|
+
conn: Active Oracle connection."""
|
|
114
|
+
pass
|
|
115
|
+
|
|
116
|
+
@staticmethod
|
|
117
|
+
@abstractmethod
|
|
118
|
+
def get_table_columns(conn: Any, owner: str, table_name: str) -> tuple[list[str], dict[str, ColumnDefinition]]:
|
|
119
|
+
"""Retrieves column names and metadata for a given table.
|
|
120
|
+
Args:
|
|
121
|
+
conn: Active Oracle connection.
|
|
122
|
+
owner: Schema owner of the table.
|
|
123
|
+
table_name: Table name.
|
|
124
|
+
Returns:
|
|
125
|
+
Tuple containing a list of column names and a dict of column metadata."""
|
|
126
|
+
pass
|
|
127
|
+
|
|
128
|
+
@staticmethod
|
|
129
|
+
@abstractmethod
|
|
130
|
+
def get_date_condition(date_expr: str, months_keep_src: int) -> str:
|
|
131
|
+
"""Returns a date condition for the given date expression and months to keep.
|
|
132
|
+
Args:
|
|
133
|
+
date_expr: Date expression to evaluate.
|
|
134
|
+
months_keep_src: Months to keep.
|
|
135
|
+
Returns:
|
|
136
|
+
Date condition as string."""
|
|
137
|
+
pass
|
|
138
|
+
|
|
139
|
+
@staticmethod
|
|
140
|
+
@abstractmethod
|
|
141
|
+
def get_fallback_expression(expression: str, fallback: str) -> str:
|
|
142
|
+
"""Return an expression that uses ``fallback`` when ``expression`` is null."""
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
@staticmethod
|
|
146
|
+
@abstractmethod
|
|
147
|
+
def get_identifiers_from_expression(expression: str) -> set[str]:
|
|
148
|
+
"""Returns a set of @prefixxed identifiers found in the given expression.
|
|
149
|
+
Args:
|
|
150
|
+
expression: The expression string to process.
|
|
151
|
+
Returns:
|
|
152
|
+
A set of identifier strings found in the expression.
|
|
153
|
+
"""
|
|
154
|
+
|
|
155
|
+
@staticmethod
|
|
156
|
+
@abstractmethod
|
|
157
|
+
def rewrite_expression_identifiers(expression: str, replacements: Mapping[str, str], *, qualifier: str) -> str:
|
|
158
|
+
"""Rewrite prefixed identifiers using engine-specific identifier rules.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
expression: Expression containing identifiers prefixed with ``@``.
|
|
162
|
+
replacements: Mapping from normalized source identifiers to persisted identifiers.
|
|
163
|
+
qualifier: SQL qualifier to apply to each replacement.
|
|
164
|
+
Returns:
|
|
165
|
+
The expression with every mapped identifier rendered for the database engine.
|
|
166
|
+
"""
|
|
167
|
+
pass
|
|
168
|
+
|
|
169
|
+
@staticmethod
|
|
170
|
+
@abstractmethod
|
|
171
|
+
def get_column_type(column: ColumnDefinition) -> str:
|
|
172
|
+
"""Returns the database-specific column type definition for the given column.
|
|
173
|
+
Args:
|
|
174
|
+
column: The ColumnDefinition object.
|
|
175
|
+
Returns:
|
|
176
|
+
The database-specific column type as a string.
|
|
177
|
+
"""
|
|
178
|
+
pass
|
|
179
|
+
|
|
180
|
+
@staticmethod
|
|
181
|
+
@abstractmethod
|
|
182
|
+
def generate_sql_block(config: Config, table_cnf: Mapping[str, Any], process_date: str) -> str:
|
|
183
|
+
"""Generates a SQL/PL block to process a given table.
|
|
184
|
+
Args:
|
|
185
|
+
config: Configuration object.
|
|
186
|
+
table_cnf: Processed table configuration object.
|
|
187
|
+
process_date: Process date in 'YYYYMMDD' format.
|
|
188
|
+
Returns:
|
|
189
|
+
The PL/SQL or SQL block to execute."""
|
|
190
|
+
pass
|
|
191
|
+
|
|
192
|
+
@staticmethod
|
|
193
|
+
@abstractmethod
|
|
194
|
+
def get_system_date(conn: Any) -> datetime:
|
|
195
|
+
"""Retrieves the current system date from the database.
|
|
196
|
+
Args:
|
|
197
|
+
conn: Active database connection.
|
|
198
|
+
Returns:
|
|
199
|
+
Current system date."""
|
|
200
|
+
pass
|
|
201
|
+
|
|
202
|
+
@staticmethod
|
|
203
|
+
@abstractmethod
|
|
204
|
+
def sql_block_run(conn: Any, plsql_code: str) -> None:
|
|
205
|
+
"""Executes a PL/SQL or SQL block against the database.
|
|
206
|
+
Args:
|
|
207
|
+
conn: Active database connection.
|
|
208
|
+
plsql_code: The PL/SQL or SQL block to execute."""
|
|
209
|
+
pass
|
|
210
|
+
|
|
211
|
+
@staticmethod
|
|
212
|
+
@abstractmethod
|
|
213
|
+
def get_status(conn: Any, process_date: str) -> list[dict[str, Any]]:
|
|
214
|
+
"""Loads control status rows for a given process date.
|
|
215
|
+
Args:
|
|
216
|
+
conn: Active database connection.
|
|
217
|
+
process_date: The process date in 'YYYYMMDD' format.
|
|
218
|
+
Returns:
|
|
219
|
+
A list of control status rows."""
|
|
220
|
+
pass
|
|
221
|
+
|
|
222
|
+
@staticmethod
|
|
223
|
+
@abstractmethod
|
|
224
|
+
def get_rows_processed(conn: Any, owner: str, table_name: str, process_date: str) -> int:
|
|
225
|
+
"""Returns rows processed for a given table and process date from ldb_ctl.
|
|
226
|
+
Args:
|
|
227
|
+
conn: Active Oracle connection.
|
|
228
|
+
owner: Schema owner of the table.
|
|
229
|
+
table_name: Table name.
|
|
230
|
+
process_date: Target process date in 'YYYYMMDD'.
|
|
231
|
+
Returns:
|
|
232
|
+
Number of rows processed or 0 if none found or mismatched date."""
|
|
233
|
+
pass
|
|
234
|
+
|
|
235
|
+
@staticmethod
|
|
236
|
+
@abstractmethod
|
|
237
|
+
def save_error_status(
|
|
238
|
+
conn: Any,
|
|
239
|
+
config: Config,
|
|
240
|
+
owner: str,
|
|
241
|
+
table_name: str,
|
|
242
|
+
process_date: str,
|
|
243
|
+
process_start: datetime,
|
|
244
|
+
message: str,
|
|
245
|
+
plsql_code: str,
|
|
246
|
+
) -> None:
|
|
247
|
+
"""Saves an error status entry in the control table.
|
|
248
|
+
Args:
|
|
249
|
+
conn: Active database connection.
|
|
250
|
+
config: Configuration object.
|
|
251
|
+
owner: Schema owner.
|
|
252
|
+
table_name: Table name.
|
|
253
|
+
process_date: Date in 'YYYYMMDD' format.
|
|
254
|
+
process_start: Start time of the process.
|
|
255
|
+
message: Error message.
|
|
256
|
+
plsql_code: PL/SQL or SQL block executed."""
|
|
257
|
+
pass
|
|
258
|
+
|
|
259
|
+
@staticmethod
|
|
260
|
+
@abstractmethod
|
|
261
|
+
def all_status_tend(conn: Any, tables_config: dict[tuple[str, str], Any], process_date: str) -> bool:
|
|
262
|
+
"""Checks if all referenced tables have status "Status.TABLE_END" in the control table.
|
|
263
|
+
Args:
|
|
264
|
+
conn: Active database connection.
|
|
265
|
+
tables_config: Dict of (owner, table_name) keys representing configured tables.
|
|
266
|
+
process_date: Processing date in 'YYYYMMDD' format.
|
|
267
|
+
Returns:
|
|
268
|
+
True if all tables have status "Status.TABLE_END" for the given process date, False otherwise."""
|
|
269
|
+
pass
|
|
270
|
+
|
|
271
|
+
@staticmethod
|
|
272
|
+
@abstractmethod
|
|
273
|
+
def get_primary_key_columns(
|
|
274
|
+
conn: Any, owner: str, table_name: str, table_cnf: Mapping[str, Any]
|
|
275
|
+
) -> tuple[str, ...]:
|
|
276
|
+
"""Returns the primary key columns for the specified table."""
|
|
277
|
+
pass
|
|
278
|
+
|
|
279
|
+
@staticmethod
|
|
280
|
+
@abstractmethod
|
|
281
|
+
def ensure_roles(conn: Any, roles: Sequence[RoleDefinition]) -> list[str]:
|
|
282
|
+
"""Ensure that the provided roles exist, returning newly created ones."""
|
|
283
|
+
pass
|
|
284
|
+
|
|
285
|
+
@staticmethod
|
|
286
|
+
@abstractmethod
|
|
287
|
+
def ensure_users(conn: Any, users: Sequence[UserDefinition]) -> list[str]:
|
|
288
|
+
"""Ensure that the provided users exist, returning newly created ones."""
|
|
289
|
+
pass
|
|
290
|
+
|
|
291
|
+
@staticmethod
|
|
292
|
+
@abstractmethod
|
|
293
|
+
def ensure_tables(conn: Any, tables: Sequence[TableDefinition]) -> list[str]:
|
|
294
|
+
"""Ensure that the provided tables exist, returning newly created ones."""
|
|
295
|
+
pass
|
|
296
|
+
|
|
297
|
+
@staticmethod
|
|
298
|
+
@abstractmethod
|
|
299
|
+
def ensure_table_structure(conn: Any, table: TableDefinition, table_cnf: Mapping[str, Any]) -> None:
|
|
300
|
+
"""Ensure that the provided table matches the expected structure."""
|
|
301
|
+
pass
|
|
302
|
+
|
|
303
|
+
@staticmethod
|
|
304
|
+
@abstractmethod
|
|
305
|
+
def ensure_sequences(conn: Any, sequences: Sequence[SequenceDefinition]) -> list[str]:
|
|
306
|
+
"""Ensure that the provided sequences exist, returning newly created ones."""
|
|
307
|
+
pass
|
|
308
|
+
|
|
309
|
+
@staticmethod
|
|
310
|
+
@abstractmethod
|
|
311
|
+
def ensure_database_links(conn: Any, links: Sequence[DatabaseLinkDefinition]) -> list[str]:
|
|
312
|
+
"""Ensure that the provided database links exist, returning newly created ones."""
|
|
313
|
+
pass
|
|
314
|
+
|
|
315
|
+
@staticmethod
|
|
316
|
+
@abstractmethod
|
|
317
|
+
def ensure_table_privileges(
|
|
318
|
+
conn: Any, role: str, tables: Sequence[tuple[str, str]], privileges: Sequence[str]
|
|
319
|
+
) -> list[str]:
|
|
320
|
+
"""Ensure the role has the specified privileges on each table, returning new grants."""
|
|
321
|
+
pass
|
|
322
|
+
|
|
323
|
+
@staticmethod
|
|
324
|
+
@abstractmethod
|
|
325
|
+
def ensure_supporting_objects(conn: Any, owner: str) -> list[str]:
|
|
326
|
+
"""Ensure auxiliary PL/SQL objects required by LimitsDb exist in the schema."""
|
|
327
|
+
pass
|
|
328
|
+
|
|
329
|
+
@staticmethod
|
|
330
|
+
@abstractmethod
|
|
331
|
+
def get_ldb_columns_expressions() -> tuple[str, str]:
|
|
332
|
+
"""Returns the expressions for the LDB process date and insert date columns.
|
|
333
|
+
Returns:
|
|
334
|
+
A tuple containing the process date expression and insert date expression.
|
|
335
|
+
"""
|
|
336
|
+
pass
|
|
337
|
+
|
|
338
|
+
@staticmethod
|
|
339
|
+
@abstractmethod
|
|
340
|
+
def get_identifier_str(identifier: str) -> str:
|
|
341
|
+
"""Returns the identifier string required to query dictionary views.
|
|
342
|
+
Args:
|
|
343
|
+
indentifier: The identifier string to process.
|
|
344
|
+
Returns:
|
|
345
|
+
The identifier string without angle brackets.
|
|
346
|
+
"""
|
|
347
|
+
pass
|
|
File without changes
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
DROP TABLE "LDB"."LDB_CONF";
|
|
2
|
+
--------------------------------------------------------
|
|
3
|
+
-- DDL for Sequence LDB_CNF_ID
|
|
4
|
+
--------------------------------------------------------
|
|
5
|
+
|
|
6
|
+
drop sequence "LDB"."LDB_CNF_ID";
|
|
7
|
+
CREATE SEQUENCE "LDB"."LDB_CNF_ID";
|
|
8
|
+
--------------------------------------------------------
|
|
9
|
+
-- DDL for Table LDB_CONF
|
|
10
|
+
--------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
CREATE TABLE "LDB"."LDB_CONF"
|
|
13
|
+
(
|
|
14
|
+
"CNF_ID" NUMBER,
|
|
15
|
+
"CNF_SOURCE_OWNER" VARCHAR2(50 BYTE),
|
|
16
|
+
"CNF_HISTORY_OWNER" VARCHAR2(50 BYTE),
|
|
17
|
+
"CNF_TABLE" VARCHAR2(50 BYTE),
|
|
18
|
+
"CNF_RETAIN_MONTHS_SOURCE" NUMBER,
|
|
19
|
+
"CNF_RETAIN_MONTHS_HISTORY" NUMBER,
|
|
20
|
+
"CNF_EXEC_DAY" VARCHAR2(10 BYTE),
|
|
21
|
+
"CNF_FRECUENCY" VARCHAR2(10 BYTE),
|
|
22
|
+
"CNF_IS_ACTIVE" CHAR(1 BYTE),
|
|
23
|
+
"CNF_PURGE_DATE_EXPR" VARCHAR2(100 BYTE),
|
|
24
|
+
"CNF_ADDITIONAL_FILTER_EXPR" VARCHAR2(4000 BYTE),
|
|
25
|
+
"CNF_HISTORY_ADDTL_FILTER_EXPR" VARCHAR2(4000 BYTE),
|
|
26
|
+
"CNF_SOURCE_ORPHAN_PURGE" CHAR(1 BYTE),
|
|
27
|
+
"CNF_ORPHAN_CHECK_COLUMN" VARCHAR2(4000 BYTE),
|
|
28
|
+
"CNF_HAS_LOB_COLUMNS" CHAR(1 BYTE),
|
|
29
|
+
"CNF_REFERENCING_TABLES" VARCHAR2(100 BYTE),
|
|
30
|
+
"CNF_JOIN_EXPR" VARCHAR2(4000 BYTE),
|
|
31
|
+
"CNF_HINT_EXPR" VARCHAR2(4000 BYTE),
|
|
32
|
+
"CNF_LONG_COLUMNS" VARCHAR2(4000 BYTE)
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
--------------------------------------------------------
|
|
36
|
+
-- DDL for Index CNF_CONF_PK
|
|
37
|
+
--------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
CREATE UNIQUE INDEX "LDB"."CNF_CONF_PK" ON "LDB"."LDB_CONF" ("CNF_ID");
|
|
40
|
+
|
|
41
|
+
--------------------------------------------------------
|
|
42
|
+
-- DDL for Index CNF_CONF_I1
|
|
43
|
+
--------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
CREATE INDEX "LDB"."CNF_CONF_I1" ON "LDB"."LDB_CONF" ("CNF_SOURCE_OWNER", "CNF_TABLE_NAME");
|
|
46
|
+
|
|
47
|
+
--------------------------------------------------------
|
|
48
|
+
-- Constraints for Table LDB_CONF
|
|
49
|
+
--------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
ALTER TABLE "LDB"."LDB_CONF" ADD CONSTRAINT "CNF_CONF_PK" PRIMARY KEY ("CNF_ID") USING INDEX;
|
|
52
|
+
|
|
53
|
+
--------------------------------------------------------
|
|
54
|
+
-- DDL for Trigger LDB_CNF_ID_CR
|
|
55
|
+
--------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
CREATE OR REPLACE EDITIONABLE TRIGGER "LDB"."LDB_CNF_CR"
|
|
58
|
+
before insert on "LDB_CONF"
|
|
59
|
+
for each row
|
|
60
|
+
begin
|
|
61
|
+
if inserting then
|
|
62
|
+
if :NEW."CNF_ID" is null then
|
|
63
|
+
select LDB_CNF_ID.nextval into :NEW."CNF_ID" from dual;
|
|
64
|
+
end if;
|
|
65
|
+
end if;
|
|
66
|
+
end;
|
|
67
|
+
/
|
|
68
|
+
ALTER TRIGGER "LDB"."LDB_CNF_CR" ENABLE;
|
|
69
|
+
|
|
70
|
+
REM INSERTING into LDB.LDB_CONF
|
|
71
|
+
SET DEFINE OFF;
|
|
72
|
+
Insert into LDB.LDB_CONF (CNF_SOURCE_OWNER,CNF_HISTORY_OWNER,CNF_TABLE,CNF_RETAIN_MONTHS_SOURCE,CNF_RETAIN_MONTHS_HISTORY,CNF_EXEC_DAY,CNF_FRECUENCY,CNF_IS_ACTIVE,CNF_PURGE_DATE_EXPR,CNF_ADDITIONAL_FILTER_EXPR,CNF_HISTORY_ADDTL_FILTER_EXPR,CNF_SOURCE_ORPHAN_PURGE,CNF_ORPHAN_CHECK_COLUMN,CNF_HAS_LOB_COLUMNS,CNF_REFERENCING_TABLES,CNF_JOIN_EXPR,CNF_HINT_EXPR,CNF_LONG_COLUMNS) values ('GL','GLHST','INV_HEAD','3','11',null,'D','Y','INV_DSP_DATE','A.INV_STATUS=''D''',null,null,null,'N',null,null,'full(A)',null);
|
|
73
|
+
Insert into LDB.LDB_CONF (CNF_SOURCE_OWNER,CNF_HISTORY_OWNER,CNF_TABLE,CNF_RETAIN_MONTHS_SOURCE,CNF_RETAIN_MONTHS_HISTORY,CNF_EXEC_DAY,CNF_FRECUENCY,CNF_IS_ACTIVE,CNF_PURGE_DATE_EXPR,CNF_ADDITIONAL_FILTER_EXPR,CNF_HISTORY_ADDTL_FILTER_EXPR,CNF_SOURCE_ORPHAN_PURGE,CNF_ORPHAN_CHECK_COLUMN,CNF_HAS_LOB_COLUMNS,CNF_REFERENCING_TABLES,CNF_JOIN_EXPR,CNF_HINT_EXPR,CNF_LONG_COLUMNS) values ('GL','GLHST','INV_HEAD','1','5',null,'D','Y','INV_DATE','A.INV_STATUS=''A''',null,null,null,'N',null,null,'full(A)',null);
|
|
74
|
+
Insert into LDB.LDB_CONF (CNF_SOURCE_OWNER,CNF_HISTORY_OWNER,CNF_TABLE,CNF_RETAIN_MONTHS_SOURCE,CNF_RETAIN_MONTHS_HISTORY,CNF_EXEC_DAY,CNF_FRECUENCY,CNF_IS_ACTIVE,CNF_PURGE_DATE_EXPR,CNF_ADDITIONAL_FILTER_EXPR,CNF_HISTORY_ADDTL_FILTER_EXPR,CNF_SOURCE_ORPHAN_PURGE,CNF_ORPHAN_CHECK_COLUMN,CNF_HAS_LOB_COLUMNS,CNF_REFERENCING_TABLES,CNF_JOIN_EXPR,CNF_HINT_EXPR,CNF_LONG_COLUMNS) values ('GL','GLHST','INV_DET',null,null,null,null,null,null,null,null,'Y','INV_ID B','N','INV_HEAD','JOIN INV_HEAD ON B.INV_ID=A.INV_ID','full(A) full(B) use_hash(A, B)',null);
|
|
75
|
+
Insert into LDB.LDB_CONF (CNF_SOURCE_OWNER,CNF_HISTORY_OWNER,CNF_TABLE,CNF_RETAIN_MONTHS_SOURCE,CNF_RETAIN_MONTHS_HISTORY,CNF_EXEC_DAY,CNF_FRECUENCY,CNF_IS_ACTIVE,CNF_PURGE_DATE_EXPR,CNF_ADDITIONAL_FILTER_EXPR,CNF_HISTORY_ADDTL_FILTER_EXPR,CNF_SOURCE_ORPHAN_PURGE,CNF_ORPHAN_CHECK_COLUMN,CNF_HAS_LOB_COLUMNS,CNF_REFERENCING_TABLES,CNF_JOIN_EXPR,CNF_HINT_EXPR,CNF_LONG_COLUMNS) values ('GL','GLHST','DSP_HEAD','3','11',null,'D','Y','DSP_DATE','A.DSP_STATUS=''D''',null,null,null,'N',null,null,'full(A)',null);
|
|
76
|
+
Insert into LDB.LDB_CONF (CNF_SOURCE_OWNER,CNF_HISTORY_OWNER,CNF_TABLE,CNF_RETAIN_MONTHS_SOURCE,CNF_RETAIN_MONTHS_HISTORY,CNF_EXEC_DAY,CNF_FRECUENCY,CNF_IS_ACTIVE,CNF_PURGE_DATE_EXPR,CNF_ADDITIONAL_FILTER_EXPR,CNF_HISTORY_ADDTL_FILTER_EXPR,CNF_SOURCE_ORPHAN_PURGE,CNF_ORPHAN_CHECK_COLUMN,CNF_HAS_LOB_COLUMNS,CNF_REFERENCING_TABLES,CNF_JOIN_EXPR,CNF_HINT_EXPR,CNF_LONG_COLUMNS) values ('GL','GLHST','DSP_HEAD','1','5',null,'D','Y','DSP_DATE','A.DSP_STATUS=''A''',null,null,null,'N',null,null,'full(A)',null);
|
|
77
|
+
Insert into LDB.LDB_CONF (CNF_SOURCE_OWNER,CNF_HISTORY_OWNER,CNF_TABLE,CNF_RETAIN_MONTHS_SOURCE,CNF_RETAIN_MONTHS_HISTORY,CNF_EXEC_DAY,CNF_FRECUENCY,CNF_IS_ACTIVE,CNF_PURGE_DATE_EXPR,CNF_ADDITIONAL_FILTER_EXPR,CNF_HISTORY_ADDTL_FILTER_EXPR,CNF_SOURCE_ORPHAN_PURGE,CNF_ORPHAN_CHECK_COLUMN,CNF_HAS_LOB_COLUMNS,CNF_REFERENCING_TABLES,CNF_JOIN_EXPR,CNF_HINT_EXPR,CNF_LONG_COLUMNS) values ('GL','GLHST','DSP_DET',null,null,null,null,null,null,null,null,'Y','B.DSP_ID, C.IND_ID','N','DSP_HEAD, INV_DET','JOIN DSP_HEAD B ON B.DSP_ID=A.DSP_ID JOIN INV_DET C ON C.IND_ID = A.IND_ID','full(A) full(B) full(C) use_hash(A, B, C)',null);
|
|
78
|
+
|
|
79
|
+
commit;
|
|
80
|
+
|
|
81
|
+
create or replace procedure check_save_status(p_owner in varchar2, p_table_name in varchar2, p_process_date in date, p_action in varchar2, p_status in varchar2, p_process_start in date,
|
|
82
|
+
p_chunk_start in date, p_process_end in date, p_message in varchar2, p_rows_processed in varchar2, p_plsql in varchar2, p_sqlcode in out number, p_out_message out varchar2) is
|
|
83
|
+
l_status varchar2(10);
|
|
84
|
+
l_process_start date;
|
|
85
|
+
l_process_date date;
|
|
86
|
+
l_rowid rowid;
|
|
87
|
+
in_use exception;
|
|
88
|
+
pragma exception_init(in_use, -54);
|
|
89
|
+
begin
|
|
90
|
+
if nvl(p_sqlcode,0) not in (-20001, -20002, -20003) then
|
|
91
|
+
begin
|
|
92
|
+
select ctl_status, ctl_process_date, ctl_process_start, rowid into l_status, l_process_date, l_process_start, l_rowid
|
|
93
|
+
from ldb_ctl
|
|
94
|
+
where ctl_owner = p_owner and ctl_table_name = p_table_name
|
|
95
|
+
for update nowait;
|
|
96
|
+
if p_status = 'TSTART' and l_status != 'TEND' and (sysdate - l_process_start)*3600*24 < 5 then
|
|
97
|
+
p_sqlcode := -20002;
|
|
98
|
+
p_out_message := 'Table '||p_table_name||' is currently in process without lock';
|
|
99
|
+
return;
|
|
100
|
+
elsif p_status = 'TSTART' and l_status = 'TEND' and l_process_date = p_process_date then
|
|
101
|
+
rollback;
|
|
102
|
+
p_sqlcode := -20003;
|
|
103
|
+
p_out_message := 'Table '||p_table_name||' is already processed for date '||to_char(p_process_date,'YYYYMMDD');
|
|
104
|
+
return;
|
|
105
|
+
end if;
|
|
106
|
+
update ldb_ctl set ctl_process_date = p_process_date, ctl_action = p_action, ctl_status = p_status,
|
|
107
|
+
ctl_process_start = nvl(p_process_start, ctl_process_start), ctl_process_end = p_process_end,
|
|
108
|
+
ctl_rows_processed = decode(p_status, '{TABLE_START}', 0, ctl_rows_processed) + p_rows_processed, ctl_plsql = nvl(p_plsql, ctl_plsql)
|
|
109
|
+
where rowid = l_rowid;
|
|
110
|
+
exception
|
|
111
|
+
when in_use then
|
|
112
|
+
p_sqlcode := -20001;
|
|
113
|
+
p_out_message := 'Table '||p_table_name||' is currently in process';
|
|
114
|
+
return;
|
|
115
|
+
when no_data_found then
|
|
116
|
+
insert into ldb_ctl (ctl_owner, ctl_table_name, ctl_process_date, ctl_action, ctl_status,
|
|
117
|
+
ctl_process_start, ctl_process_end, ctl_rows_processed, ctl_plsql)
|
|
118
|
+
values (p_owner, p_table_name, p_process_date, p_action, p_status,
|
|
119
|
+
l_process_start, null, 0, p_plsql);
|
|
120
|
+
end;
|
|
121
|
+
end if;
|
|
122
|
+
insert into ldb_log (log_id, log_owner, log_table_name, log_process_date, log_action, log_status,
|
|
123
|
+
log_process_start, log_process_end, log_message, log_rows_processed, log_plsql)
|
|
124
|
+
values (ldb_log_id.nextval, p_owner, p_table_name, p_process_date, p_action, p_status,
|
|
125
|
+
nvl(p_chunk_start, p_process_start), p_process_end, p_message, p_rows_processed, p_plsql);
|
|
126
|
+
end check_save_status;
|
|
127
|
+
/
|
|
128
|
+
|
|
129
|
+
CREATE OR REPLACE TYPE t_referencing_tables AS TABLE OF VARCHAR2(100);
|
|
130
|
+
/
|
|
131
|
+
create or replace procedure check_referencing_tables(p_referencing_tables t_referencing_tables, p_process_date date) is
|
|
132
|
+
l_ref_table varchar2(100);
|
|
133
|
+
l_ref_owner varchar2(100);
|
|
134
|
+
l_ref_table_name varchar2(100);
|
|
135
|
+
l_dummy number;
|
|
136
|
+
begin
|
|
137
|
+
for i in 1..p_referencing_tables.count loop
|
|
138
|
+
l_ref_table := p_referencing_tables(i);
|
|
139
|
+
l_ref_owner := substr(l_ref_table,1,instr(l_ref_table,'.')-1);
|
|
140
|
+
l_ref_table_name := substr(l_ref_table,instr(l_ref_table,'.')+1);
|
|
141
|
+
begin
|
|
142
|
+
select 1 into l_dummy
|
|
143
|
+
from ldb_ctl
|
|
144
|
+
where ctl_owner = l_ref_owner and ctl_table_name = l_ref_table_name and ctl_process_date = p_process_date and ctl_status='TEND';
|
|
145
|
+
exception
|
|
146
|
+
when no_data_found then
|
|
147
|
+
raise_application_error(-20004,'Referencing table '||l_ref_table||' was not fully processed for date '||to_char(p_process_date,'YYYYMMDD'));
|
|
148
|
+
end;
|
|
149
|
+
end loop;
|
|
150
|
+
end check_referencing_tables;
|
|
151
|
+
/
|