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.
@@ -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
+ /