[Developer] #424 use ORDS query handlers for object reads
This commit is contained in:
@@ -20,6 +20,7 @@ SET FEEDBACK ON
|
||||
PROMPT === Creating CB_ORDS handler package ===
|
||||
CREATE OR REPLACE PACKAGE cb_ords_handler_pkg AUTHID DEFINER AS
|
||||
PROCEDURE set_vpd_context(p_authorization IN VARCHAR2);
|
||||
FUNCTION set_vpd_context_sql(p_authorization IN VARCHAR2) RETURN NUMBER;
|
||||
PROCEDURE clear_vpd_context;
|
||||
END;
|
||||
/
|
||||
@@ -45,6 +46,12 @@ CREATE OR REPLACE PACKAGE BODY cb_ords_handler_pkg AS
|
||||
admin.cb_agent_ctx_pkg.set_user_by_bearer(v_bearer_key);
|
||||
END;
|
||||
|
||||
FUNCTION set_vpd_context_sql(p_authorization IN VARCHAR2) RETURN NUMBER AS
|
||||
BEGIN
|
||||
set_vpd_context(p_authorization);
|
||||
RETURN 1;
|
||||
END;
|
||||
|
||||
PROCEDURE clear_vpd_context AS
|
||||
BEGIN
|
||||
admin.cb_agent_ctx_pkg.clear_user;
|
||||
@@ -79,51 +86,21 @@ BEGIN
|
||||
p_module_name => 'cb.agent.security',
|
||||
p_pattern => 'vpd/documents',
|
||||
p_method => 'POST',
|
||||
p_source_type => ORDS.source_type_plsql,
|
||||
p_source_type => ORDS.source_type_query,
|
||||
p_source => q'!
|
||||
DECLARE
|
||||
v_rows_json CLOB;
|
||||
v_offset NUMBER := 1;
|
||||
BEGIN
|
||||
cb_ords_handler_pkg.set_vpd_context(:auth_header);
|
||||
|
||||
SELECT JSON_ARRAYAGG(
|
||||
JSON_OBJECT(
|
||||
'doc_id' VALUE doc_id,
|
||||
'title' VALUE title,
|
||||
'owner_emp_no' VALUE owner_emp_no,
|
||||
'dept_code' VALUE dept_code,
|
||||
'contents' VALUE contents
|
||||
RETURNING VARCHAR2(32767)
|
||||
WITH vpd_ctx AS (
|
||||
SELECT cb_ords_handler_pkg.set_vpd_context_sql(:auth_header) AS applied
|
||||
FROM dual
|
||||
)
|
||||
ORDER BY doc_id
|
||||
RETURNING CLOB
|
||||
)
|
||||
INTO v_rows_json
|
||||
FROM admin.cb_v_search_documents;
|
||||
|
||||
IF v_rows_json IS NULL THEN
|
||||
v_rows_json := '[]';
|
||||
END IF;
|
||||
|
||||
:status_code := 200;
|
||||
OWA_UTIL.MIME_HEADER('application/json', TRUE);
|
||||
HTP.P('{"rows":');
|
||||
WHILE v_offset <= DBMS_LOB.GETLENGTH(v_rows_json) LOOP
|
||||
HTP.P(DBMS_LOB.SUBSTR(v_rows_json, 32767, v_offset));
|
||||
v_offset := v_offset + 32767;
|
||||
END LOOP;
|
||||
HTP.P('}');
|
||||
cb_ords_handler_pkg.clear_vpd_context;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
cb_ords_handler_pkg.clear_vpd_context;
|
||||
:status_code := 403;
|
||||
OWA_UTIL.MIME_HEADER('application/json', TRUE);
|
||||
HTP.P(JSON_OBJECT('error' VALUE SQLERRM RETURNING VARCHAR2(4000)));
|
||||
END;
|
||||
SELECT d.doc_id,
|
||||
d.title,
|
||||
d.owner_emp_no,
|
||||
d.dept_code,
|
||||
d.contents
|
||||
FROM admin.cb_v_search_documents d
|
||||
CROSS JOIN vpd_ctx
|
||||
!',
|
||||
p_items_per_page => 0
|
||||
p_items_per_page => 25
|
||||
);
|
||||
|
||||
ORDS.DEFINE_PARAMETER(
|
||||
|
||||
@@ -99,8 +99,8 @@ public class OrdsMetadataService {
|
||||
throw new AppException("수정할 ORDS Handler를 찾을 수 없습니다.");
|
||||
}
|
||||
String sourceType = handler.sourceType() == null ? "" : handler.sourceType().toLowerCase(Locale.ROOT);
|
||||
if (!sourceType.contains("plsql")) {
|
||||
throw new AppException("현재는 PL/SQL ORDS Handler만 수정할 수 있습니다: " + handler.sourceType());
|
||||
if (!sourceType.contains("plsql") && !sourceType.contains("query")) {
|
||||
throw new AppException("현재는 PL/SQL/SQL Query ORDS Handler만 수정할 수 있습니다: " + handler.sourceType());
|
||||
}
|
||||
String currentUser = jdbcTemplate.queryForObject("SELECT USER FROM dual", String.class);
|
||||
if (currentUser == null || !currentUser.equalsIgnoreCase(handler.parsingSchema())) {
|
||||
@@ -108,18 +108,31 @@ public class OrdsMetadataService {
|
||||
+ currentUser + ", Handler parsing schema: " + handler.parsingSchema());
|
||||
}
|
||||
jdbcTemplate.update("""
|
||||
DECLARE
|
||||
v_source_type VARCHAR2(30);
|
||||
BEGIN
|
||||
IF ? = 'QUERY' THEN
|
||||
v_source_type := ORDS.source_type_query;
|
||||
ELSE
|
||||
v_source_type := ORDS.source_type_plsql;
|
||||
END IF;
|
||||
|
||||
ORDS.DEFINE_HANDLER(
|
||||
p_module_name => ?,
|
||||
p_pattern => ?,
|
||||
p_method => ?,
|
||||
p_source_type => ORDS.source_type_plsql,
|
||||
p_source_type => v_source_type,
|
||||
p_source => ?,
|
||||
p_items_per_page => 0
|
||||
);
|
||||
COMMIT;
|
||||
END;
|
||||
""", handler.moduleName(), handler.template(), handler.method(), command.source());
|
||||
""",
|
||||
handlerSourceTypeCode(handler.sourceType()),
|
||||
handler.moduleName(),
|
||||
handler.template(),
|
||||
handler.method(),
|
||||
command.source());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -163,9 +176,9 @@ public class OrdsMetadataService {
|
||||
p_module_name => ?,
|
||||
p_pattern => ?,
|
||||
p_method => 'POST',
|
||||
p_source_type => ORDS.source_type_plsql,
|
||||
p_source_type => ORDS.source_type_query,
|
||||
p_source => ?,
|
||||
p_items_per_page => 0
|
||||
p_items_per_page => 25
|
||||
);
|
||||
ORDS.DEFINE_PARAMETER(
|
||||
p_module_name => ?,
|
||||
@@ -200,54 +213,28 @@ public class OrdsMetadataService {
|
||||
}
|
||||
|
||||
private String objectQuerySource(ProtectedObject object, List<String> columns) {
|
||||
String jsonEntries = columns.stream()
|
||||
.map(column -> "'" + column.toLowerCase(Locale.ROOT) + "' VALUE " + column)
|
||||
String selectColumns = columns.stream()
|
||||
.map(column -> "o." + column)
|
||||
.reduce((left, right) -> left + ",\n " + right)
|
||||
.orElseThrow();
|
||||
String selectColumns = String.join(", ", columns);
|
||||
return """
|
||||
DECLARE
|
||||
v_limit NUMBER := LEAST(GREATEST(NVL(:row_limit, 50), 1), 500);
|
||||
v_rows_json CLOB;
|
||||
v_offset NUMBER := 1;
|
||||
BEGIN
|
||||
cb_ords_handler_pkg.set_vpd_context(:auth_header);
|
||||
|
||||
SELECT JSON_ARRAYAGG(
|
||||
JSON_OBJECT(
|
||||
%s
|
||||
RETURNING VARCHAR2(32767)
|
||||
WITH vpd_ctx AS (
|
||||
SELECT cb_ords_handler_pkg.set_vpd_context_sql(:auth_header) AS applied
|
||||
FROM dual
|
||||
)
|
||||
RETURNING CLOB
|
||||
)
|
||||
INTO v_rows_json
|
||||
FROM (
|
||||
SELECT %s
|
||||
FROM %s.%s
|
||||
WHERE ROWNUM <= v_limit
|
||||
);
|
||||
FROM %s.%s o
|
||||
CROSS JOIN vpd_ctx
|
||||
WHERE ROWNUM <= LEAST(GREATEST(NVL(:row_limit, 50), 1), 500)
|
||||
""".formatted(selectColumns, object.owner(), object.objectName());
|
||||
}
|
||||
|
||||
IF v_rows_json IS NULL THEN
|
||||
v_rows_json := '[]';
|
||||
END IF;
|
||||
|
||||
:status_code := 200;
|
||||
OWA_UTIL.MIME_HEADER('application/json', TRUE);
|
||||
HTP.P('{"rows":');
|
||||
WHILE v_offset <= DBMS_LOB.GETLENGTH(v_rows_json) LOOP
|
||||
HTP.P(DBMS_LOB.SUBSTR(v_rows_json, 32767, v_offset));
|
||||
v_offset := v_offset + 32767;
|
||||
END LOOP;
|
||||
HTP.P('}');
|
||||
cb_ords_handler_pkg.clear_vpd_context;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
cb_ords_handler_pkg.clear_vpd_context;
|
||||
:status_code := 403;
|
||||
OWA_UTIL.MIME_HEADER('application/json', TRUE);
|
||||
HTP.P(JSON_OBJECT('error' VALUE SQLERRM RETURNING VARCHAR2(4000)));
|
||||
END;
|
||||
""".formatted(jsonEntries, selectColumns, object.owner(), object.objectName());
|
||||
private String handlerSourceTypeCode(String sourceType) {
|
||||
String normalized = sourceType == null ? "" : sourceType.toLowerCase(Locale.ROOT);
|
||||
if (normalized.contains("query")) {
|
||||
return "QUERY";
|
||||
}
|
||||
return "PLSQL";
|
||||
}
|
||||
|
||||
private void requireIdentifier(String value, String label) {
|
||||
|
||||
Reference in New Issue
Block a user