2014-02-20 2 views
0

그래서 여러 테이블이 있고 각기 다른 사용자가 테이블의 일부에 액세스 할 수 있도록 다른 역할을 만들었습니다.오라클의 절차 - 모든 행을 반환

모든 것을 보려고하는 조정자와 함께 SELECT * FROM yaser.enrol;을 시도 할 때마다 은 employee_no을 쿼리하여 직원 역할을 확인하는 라인을 가리 킵니다.

Theres 총 4 가지 유형의 사용자 : 학생, 교사, 강사, 코디네이터.

편집 ** 모든 코드가 추가되었습니다. 다른 모든 테이블이 기본적으로 동일

CREATE TABLE employee 
(
    emp_no varchar(10), 
    name varchar(100) 
); 

-VARCHARS

어떤 도움 : - 모든 직원

CREATE TABLE course 
(
    course_code varchar(10), 
    course_title varchar(50), 
    course_coord_emp_no varchar(10), 
    primary key (course_code) 
); 

을 그리고 :

-- Create policy function to be called when ‘ENROL’ table is accessed under user Yaser. 
create or replace function f_policy_enrol (schema in varchar2, tab in varchar2) 

return varchar2 
as 
    v_emp_no   varchar2(10); 
    v_student_no  varchar2(10); 
    v_tutor_emp_no  varchar2(10); 
    v_lecturer_emp_no varchar2(10); 
    v_coord_emp_no  varchar2(10); 
    is_tutor   number:=0; 
    is_lecturer   number:=0; 
    is_coordinator  number:=0; 
    is_student   number:=0; 
    is_employee   number:=0; 
    v_program_code  varchar2(10); 
    v_user    varchar2(100); 
    out_string   varchar2(400) default '1=2 '; 
-- The return value will be out_string. '1=2' means 'Nothing to access'. 

begin 
    -- get session user 
    v_user := lower(sys_context('userenv','session_user')); 

    -- Is the user a student? 
    begin 
    SELECT student_no INTO v_student_no FROM student WHERE lower(student_no) = v_user; 
    is_student:=1; 
    exception 
    when no_data_found then 
    v_student_no := 0; 
    end; 

    -- Is the user an employee? 
    begin 
    SELECT emp_no INTO v_emp_no FROM employee WHERE lower(emp_no) = v_user; 
    is_employee:=1; 
    exception 
    when no_data_found then 
    v_emp_no := 0; 
    end; 

    -- Query the employee number to determine role. 
    -- If Tutor. 
    SELECT MAX(tutor_emp_no) INTO v_tutor_emp_no FROM tutorial WHERE lower(tutor_emp_no) = v_user; 
    -- If Lecturer. 
    SELECT MAX(course_coord_emp_no) INTO v_lecturer_emp_no FROM course WHERE lower(course_coord_emp_no) = v_user; 
    -- If Coordinator. 
    SELECT MAX(prog_coord_emp_no) into v_coord_emp_no FROM program WHERE lower(prog_coord_emp_no) = v_user; 

    -- Get role of the employee if the user is an employee. 
    if v_emp_no != 0 and v_tutor_emp_no is NOT NULL then 
    -- Employee is a Tutor. 
    is_tutor := 1; 
    elsif v_emp_no != 0 and v_lecturer_emp_no is NOT NULL then 
    -- Employee is Lecturer. 
    is_lecturer := 1; 
    elsif v_emp_no != 0 and v_coord_emp_no is NOT NULL then 
    -- Employee is Coordinator. 
    is_coordinator := 1; 
    end if; 

    -- Create the string to be used as the WHERE clause. 
    if is_student = 1 then 
    -- Students are allowed to see their orders only. 
    out_string := out_string||'or student_no = '''||v_student_no||''' '; 
    end if; 

    if is_tutor = 1 then 
    -- Tutors are allowed to see enrolments of students that they tutor. 
----  out_string := out_string||'or student_no in (select student_no from tutorial where tutor_emp_no = '||v_tutor_emp_no||') '; 
---- NOT WORKING. 
    out_string := out_string||'or student_no in (select student_no from tutorial where lower(tutor_emp_no) = v_tutor_emp_no) '; 

    end if; 

    if is_coordinator = 1 then 
    -- The coordinator is allowed to see all records in ENROL (WHERE 1=1 or anything) means all rows. 
    out_string := out_string||'or 1=1 '; 
    end if; 

    return out_string; 
end; 
/

이는 내가 참조하고있어 테이블은 좋은 것입니다! :) Yaser

+2

전체 절차 및 입력 및 오류를 표시하십시오. – kevinsky

+0

'오류입니다'는 올바른 오류 메시지가 아닙니다.코드를 보여주십시오. 아마도 당신은'out_string'을 동적 SQL로 실행하고, 아마도 참조 커서를 여는 것일까? 작은 비트를 바탕으로 내 생각 엔 'or'또는 '1 = 1''앞에 공간이 필요하다는 것을 알았습니다. 또는 괄호 문제가 있음을 나타냅니다. 그러나 괜찮은 대답을 줄 수있는 방법은 여기에 있습니다. –

+0

@AlexPoole, 죄송합니다. 처음 게시물을 편집하십시오! –

답변

1

이 문제는 많은 진화하고이 답변의 대부분은 실제 코드와 관련이 아니었다 누락 end if에 대해이었다. 전혀 차이가 없습니다 - 사실로 or 1=1를 사용하여, 다시 원래 질문에 이동 이동하려면 포괄는 if 경우 비교 문자열의 다른 분기에도 OK입니다.

'or ''x''=''x'' ' 

... 또는

'or v_user=v_user ' 

을하지만 주석에 표시하는 것 당신은 빈 문자열을 비교할 수 없습니다 : 당신이 정말로 문자열을 비교하려면 않은 경우 당신은 같은 일을 할 수 있습니다. 빈 문자열 ''은 오라클의 null과 동일하며 어떤 경우도 null과 동일시 할 수 없습니다. (동일한 이유로 v_usernull 인 경우 이전 검사가 실패합니다. 그래서 또 다른 가능성은 다음과 같습니다 여기에 비교기는 is하지 =입니다

'or null is null ' 

하는 것으로. 당신이 VPD 오류가 왜 그 모두가 정말 동일로

없음으로는, 주소 - 그들은 모두 항상 true로 평가 그것을 당신이 사용하는 중요하지 않습니다. 실제로 or true으로 끝나는 것은 똑같이 작동합니다. 오라클 SQL이 그런 부울을 이해하지 못한다는 것은 부끄러운 일입니다. 다른 절에서 비교되는 데이터 유형은이 절과 관련이 없습니다.

당신은, 함수가 실제로 두 경우 모두 반환하는 것을 볼 당신이 기대하는 무엇을 확인하고 당신이 VPD 직접 반대하는 테이블을 조회 할 때 제한으로 작동하는지 확인해야합니다.

+0

고마워하지만 괜찮아요, 문제는 내가 코드를 가지고'out_string : = out_string || '또는 1 = 1';'varchars를 사용하는 반면 반환하는 숫자를 사용하는 예제입니다. varchars에 더 적합하도록 ''또는 1 = 1 ''을 (를) 변경해야합니까? –

+0

또한 작은 따옴표로 복사 할 때 사용합니다. 머리를 주셔서 감사합니다 :) –

+0

당신은 그 조항에서 두 개의 숫자를 비교하고 있습니다 - '1 = 1'. 다른 절이 문자열을 비교하는 것은 중요하지 않습니다. 따옴표를 확인하기위한 메모도 추가했습니다. 게시 한 코드가 유효하지 않습니다. 그리고 너는 어떻게 부르며 이것을 사용 하는가? 실행되고 있는지 확인하기 위해 독립 실행 형으로 실행할 가치가 있습니다. 'tab'이 사용되지 않는 것처럼''f_policy_enrol (user, 'x') from dual'을 선택하십시오. –