DatabaseProgramming: proc&triggers.sql

File proc&triggers.sql, 23.2 KB (added by 231146, 4 hours ago)
Line 
1
2-- Го откажува летот и ги ажурира сите поврзани билети, boarding passes, arrivals и departures на статус „Cancelled", доколку летот не е веќе во тек или завршен.
3
4CREATE OR REPLACE PROCEDURE CancelFlight(
5 p_FlightId INT
6)
7LANGUAGE plpgsql
8AS $$
9DECLARE
10 v_flight_exists BOOLEAN;
11 v_current_status VARCHAR(20);
12 v_ticket_count INT;
13 v_boarding_count INT;
14 v_arrivals_count INT;
15 v_departures_count INT;
16BEGIN
17 SELECT EXISTS (
18 SELECT 1 FROM Flights WHERE FlightId = p_FlightId
19 ) INTO v_flight_exists;
20
21 IF NOT v_flight_exists THEN
22 RAISE EXCEPTION 'Flight with ID % does not exist.', p_FlightId;
23 END IF;
24
25 SELECT OperatingStatus
26 INTO v_current_status
27 FROM Flights
28 WHERE FlightId = p_FlightId;
29
30 IF v_current_status = 'Cancelled' THEN
31 RAISE EXCEPTION 'Flight with ID % is already cancelled.', p_FlightId;
32 END IF;
33
34 IF v_current_status IN ('Departed', 'En Route', 'Landed', 'Arrived') THEN
35 RAISE EXCEPTION 'Flight with ID % cannot be cancelled because it is in status: %.',
36 p_FlightId, v_current_status;
37 END IF;
38
39 UPDATE Flights
40 SET OperatingStatus = 'Cancelled'
41 WHERE FlightId = p_FlightId;
42
43 GET DIAGNOSTICS v_ticket_count = ROW_COUNT;
44 RAISE NOTICE 'Flights updated: % row(s)', v_ticket_count;
45
46 UPDATE Ticket
47 SET Status = 'Cancelled'
48 WHERE FlightId = p_FlightId
49 AND Status NOT IN ('Cancelled', 'Refunded', 'Used');
50
51 GET DIAGNOSTICS v_ticket_count = ROW_COUNT;
52 RAISE NOTICE 'Tickets cancelled: % row(s)', v_ticket_count;
53
54 UPDATE BoardingPass
55 SET Status = 'Cancelled'
56 WHERE TicketId IN (
57 SELECT TicketId FROM Ticket WHERE FlightId = p_FlightId
58 )
59 AND Status NOT IN ('Cancelled', 'Boarded');
60
61 GET DIAGNOSTICS v_boarding_count = ROW_COUNT;
62 RAISE NOTICE 'Boarding passes cancelled: % row(s)', v_boarding_count;
63
64 UPDATE Arrivals
65 SET Status = 'Cancelled'
66 WHERE FlightId = p_FlightId
67 AND Status NOT IN ('Cancelled', 'Arrived', 'Landed');
68
69 GET DIAGNOSTICS v_arrivals_count = ROW_COUNT;
70 RAISE NOTICE 'Arrivals cancelled: % row(s)', v_arrivals_count;
71
72 UPDATE Departures
73 SET Status = 'Cancelled'
74 WHERE FlightId = p_FlightId
75 AND Status NOT IN ('Cancelled', 'Departed');
76
77 GET DIAGNOSTICS v_departures_count = ROW_COUNT;
78 RAISE NOTICE 'Departures cancelled: % row(s)', v_departures_count;
79
80 RAISE NOTICE 'Flight with ID % has been successfully cancelled.', p_FlightId;
81
82EXCEPTION
83 WHEN OTHERS THEN
84 RAISE EXCEPTION 'Error while cancelling flight %: %', p_FlightId, SQLERRM;
85END;
86$$;
87
88
89-- Го одложува летот за дадени минути со поместување на DepartureTime и ArrivalTime, и го ажурира статусот во „Delayed" во Flights, Arrivals и Departures.
90
91CREATE OR REPLACE PROCEDURE DelayFlight(
92 p_FlightId INT,
93 p_DelayMinutes INT
94)
95LANGUAGE plpgsql
96AS $$
97DECLARE
98 v_flight_exists BOOLEAN;
99 v_current_status VARCHAR(20);
100 v_old_departure TIMESTAMP;
101 v_old_arrival TIMESTAMP;
102 v_new_departure TIMESTAMP;
103 v_new_arrival TIMESTAMP;
104 v_updated_flights INT;
105 v_updated_arrivals INT;
106 v_updated_departures INT;
107BEGIN
108 SELECT EXISTS (
109 SELECT 1 FROM Flights WHERE FlightId = p_FlightId
110 ) INTO v_flight_exists;
111
112 IF NOT v_flight_exists THEN
113 RAISE EXCEPTION 'Flight with ID % does not exist.', p_FlightId;
114 END IF;
115
116 IF p_DelayMinutes <= 0 THEN
117 RAISE EXCEPTION 'Delay time must be greater than 0 minutes. Provided: %',
118 p_DelayMinutes;
119 END IF;
120
121 SELECT OperatingStatus, DepartureTime, ArrivalTime
122 INTO v_current_status, v_old_departure, v_old_arrival
123 FROM Flights
124 WHERE FlightId = p_FlightId;
125
126 IF v_current_status IN ('Cancelled', 'Landed', 'Arrived') THEN
127 RAISE EXCEPTION 'Flight with ID % cannot be delayed because it is in status: %.',
128 p_FlightId, v_current_status;
129 END IF;
130
131 IF v_current_status IN ('Departed', 'En Route') THEN
132 RAISE EXCEPTION 'Flight with ID % is already in the air and cannot be delayed (status: %).',
133 p_FlightId, v_current_status;
134 END IF;
135
136 v_new_departure := v_old_departure + (p_DelayMinutes || ' minutes')::INTERVAL;
137 v_new_arrival := v_old_arrival + (p_DelayMinutes || ' minutes')::INTERVAL;
138
139 RAISE NOTICE 'Old DepartureTime: % -> New: %', v_old_departure, v_new_departure;
140 RAISE NOTICE 'Old ArrivalTime: % -> New: %', v_old_arrival, v_new_arrival;
141
142 UPDATE Flights
143 SET OperatingStatus = 'Delayed',
144 DepartureTime = v_new_departure,
145 ArrivalTime = v_new_arrival
146 WHERE FlightId = p_FlightId;
147
148 GET DIAGNOSTICS v_updated_flights = ROW_COUNT;
149 RAISE NOTICE 'Flights updated: % row(s)', v_updated_flights;
150
151 UPDATE Arrivals
152 SET Status = 'Delayed',
153 ArrivalTime = v_new_arrival
154 WHERE FlightId = p_FlightId
155 AND Status NOT IN ('Cancelled', 'Landed', 'Arrived');
156
157 GET DIAGNOSTICS v_updated_arrivals = ROW_COUNT;
158 RAISE NOTICE 'Arrivals updated: % row(s)', v_updated_arrivals;
159
160 UPDATE Departures
161 SET Status = 'Delayed',
162 DepartureTime = v_new_departure
163 WHERE FlightId = p_FlightId
164 AND Status NOT IN ('Cancelled', 'Departed');
165
166 GET DIAGNOSTICS v_updated_departures = ROW_COUNT;
167 RAISE NOTICE 'Departures updated: % row(s)', v_updated_departures;
168
169 RAISE NOTICE 'Flight with ID % has been successfully delayed by % minutes.', p_FlightId, p_DelayMinutes;
170
171EXCEPTION
172 WHEN OTHERS THEN
173 RAISE EXCEPTION 'Error while delaying flight %: %', p_FlightId, SQLERRM;
174END;
175$$;
176
177
178--Доделува отворен гејт на лет (за arrival или departure) и го менува статусот на гејтот во „Occupied".
179
180CREATE OR REPLACE PROCEDURE AssignGateToFlight(
181 p_FlightId INT,
182 p_GateId INT,
183 p_Direction VARCHAR(20)
184)
185LANGUAGE plpgsql
186AS $$
187DECLARE
188 v_flight_exists BOOLEAN;
189 v_gate_exists BOOLEAN;
190 v_gate_status VARCHAR(20);
191 v_flight_status VARCHAR(20);
192 v_direction_upper VARCHAR(20);
193BEGIN
194 v_direction_upper := UPPER(TRIM(p_Direction));
195
196 IF v_direction_upper NOT IN ('ARRIVAL', 'DEPARTURE') THEN
197 RAISE EXCEPTION 'Invalid direction: %. Use ARRIVAL or DEPARTURE.', p_Direction;
198 END IF;
199
200 SELECT EXISTS (
201 SELECT 1 FROM Flights WHERE FlightId = p_FlightId
202 ) INTO v_flight_exists;
203
204 IF NOT v_flight_exists THEN
205 RAISE EXCEPTION 'Flight with ID % does not exist.', p_FlightId;
206 END IF;
207
208 SELECT OperatingStatus INTO v_flight_status
209 FROM Flights WHERE FlightId = p_FlightId;
210
211 IF v_flight_status IN ('Cancelled', 'Arrived', 'Landed') THEN
212 RAISE EXCEPTION 'Cannot assign a gate to a flight with status: %.', v_flight_status;
213 END IF;
214
215 SELECT EXISTS (
216 SELECT 1 FROM Gate WHERE GateId = p_GateId
217 ) INTO v_gate_exists;
218
219 IF NOT v_gate_exists THEN
220 RAISE EXCEPTION 'Gate with ID % does not exist.', p_GateId;
221 END IF;
222
223 SELECT Status INTO v_gate_status
224 FROM Gate WHERE GateId = p_GateId;
225
226 IF v_gate_status NOT IN ('Open') THEN
227 RAISE EXCEPTION 'Gate with ID % is not available. Current status: %.',
228 p_GateId, v_gate_status;
229 END IF;
230
231 IF v_direction_upper = 'ARRIVAL' THEN
232
233 IF NOT EXISTS (SELECT 1 FROM Arrivals WHERE FlightId = p_FlightId) THEN
234 RAISE EXCEPTION 'No Arrivals record found for flight with ID %.', p_FlightId;
235 END IF;
236
237 UPDATE Arrivals
238 SET GateId = p_GateId
239 WHERE FlightId = p_FlightId;
240
241 RAISE NOTICE 'Gate % assigned to Arrival for flight %.', p_GateId, p_FlightId;
242
243 ELSE
244
245 IF NOT EXISTS (SELECT 1 FROM Departures WHERE FlightId = p_FlightId) THEN
246 RAISE EXCEPTION 'No Departures record found for flight with ID %.', p_FlightId;
247 END IF;
248
249 UPDATE Departures
250 SET GateId = p_GateId
251 WHERE FlightId = p_FlightId;
252
253 RAISE NOTICE 'Gate % assigned to Departure for flight %.', p_GateId, p_FlightId;
254
255 END IF;
256
257 UPDATE Gate
258 SET Status = 'Occupied'
259 WHERE GateId = p_GateId;
260
261 RAISE NOTICE 'Gate % status changed to Occupied.', p_GateId;
262
263EXCEPTION
264 WHEN OTHERS THEN
265 RAISE EXCEPTION 'Error while assigning gate: %', SQLERRM;
266END;
267$$;
268
269
270--Го менува статусот на гејт со валидација на дозволени транзиции (на пример, „Under Maintenance" може да оди само во „Open" или „Closed").
271
272CREATE OR REPLACE PROCEDURE ChangeGateStatus(
273 p_GateId INT,
274 p_NewStatus VARCHAR(20)
275)
276LANGUAGE plpgsql
277AS $$
278DECLARE
279 v_gate_exists BOOLEAN;
280 v_old_status VARCHAR(20);
281BEGIN
282 SELECT EXISTS (
283 SELECT 1 FROM Gate WHERE GateId = p_GateId
284 ) INTO v_gate_exists;
285
286 IF NOT v_gate_exists THEN
287 RAISE EXCEPTION 'Gate with ID % does not exist.', p_GateId;
288 END IF;
289
290 IF p_NewStatus NOT IN ('Open', 'Closed', 'Boarding', 'Occupied', 'Under Maintenance') THEN
291 RAISE EXCEPTION 'Invalid status: %. Allowed values: Open, Closed, Boarding, Occupied, Under Maintenance.',
292 p_NewStatus;
293 END IF;
294
295 SELECT Status INTO v_old_status
296 FROM Gate WHERE GateId = p_GateId;
297
298 IF v_old_status = p_NewStatus THEN
299 RAISE EXCEPTION 'Gate with ID % is already in status: %.', p_GateId, p_NewStatus;
300 END IF;
301
302 IF v_old_status = 'Under Maintenance' AND p_NewStatus NOT IN ('Open', 'Closed') THEN
303 RAISE EXCEPTION 'A gate under maintenance can only transition to Open or Closed.';
304 END IF;
305
306 IF v_old_status = 'Boarding' AND p_NewStatus NOT IN ('Open', 'Closed', 'Occupied') THEN
307 RAISE EXCEPTION 'A gate in Boarding can only transition to Open, Closed or Occupied.';
308 END IF;
309
310 UPDATE Gate
311 SET Status = p_NewStatus
312 WHERE GateId = p_GateId;
313
314 RAISE NOTICE 'Gate % status changed: % -> %.', p_GateId, v_old_status, p_NewStatus;
315
316EXCEPTION
317 WHEN OTHERS THEN
318 RAISE EXCEPTION 'Error while changing gate status: %', SQLERRM;
319END;
320$$;
321
322
323--Доделува слободна писта на лет (arrival или departure), проверувајќи дека пистата припаѓа на точниот аеродром, и го менува статусот на пистата во „Occupied".
324
325CREATE OR REPLACE PROCEDURE AssignRunwayToFlight(
326 p_FlightId INT,
327 p_RunwayId INT,
328 p_Direction VARCHAR(20)
329)
330LANGUAGE plpgsql
331AS $$
332DECLARE
333 v_flight_exists BOOLEAN;
334 v_runway_exists BOOLEAN;
335 v_runway_status VARCHAR(20);
336 v_flight_status VARCHAR(20);
337 v_direction_upper VARCHAR(20);
338 v_runway_airport INT;
339 v_origin_airport INT;
340 v_dest_airport INT;
341BEGIN
342 v_direction_upper := UPPER(TRIM(p_Direction));
343
344 IF v_direction_upper NOT IN ('ARRIVAL', 'DEPARTURE') THEN
345 RAISE EXCEPTION 'Invalid direction: %. Use ARRIVAL or DEPARTURE.', p_Direction;
346 END IF;
347
348 SELECT EXISTS (
349 SELECT 1 FROM Flights WHERE FlightId = p_FlightId
350 ) INTO v_flight_exists;
351
352 IF NOT v_flight_exists THEN
353 RAISE EXCEPTION 'Flight with ID % does not exist.', p_FlightId;
354 END IF;
355
356 SELECT OperatingStatus, OriginAirportId, DestinationAirportId
357 INTO v_flight_status, v_origin_airport, v_dest_airport
358 FROM Flights WHERE FlightId = p_FlightId;
359
360 IF v_flight_status IN ('Cancelled', 'Arrived') THEN
361 RAISE EXCEPTION 'Cannot assign a runway to a flight with status: %.', v_flight_status;
362 END IF;
363
364 SELECT EXISTS (
365 SELECT 1 FROM Runway WHERE RunwayId = p_RunwayId
366 ) INTO v_runway_exists;
367
368 IF NOT v_runway_exists THEN
369 RAISE EXCEPTION 'Runway with ID % does not exist.', p_RunwayId;
370 END IF;
371
372 SELECT Status, AirportId INTO v_runway_status, v_runway_airport
373 FROM Runway WHERE RunwayId = p_RunwayId;
374
375 IF v_runway_status NOT IN ('Open') THEN
376 RAISE EXCEPTION 'Runway with ID % is not available. Current status: %.',
377 p_RunwayId, v_runway_status;
378 END IF;
379
380 IF v_direction_upper = 'ARRIVAL' AND v_runway_airport != v_dest_airport THEN
381 RAISE EXCEPTION 'Runway % does not belong to the destination airport (ID: %).',
382 p_RunwayId, v_dest_airport;
383 END IF;
384
385 IF v_direction_upper = 'DEPARTURE' AND v_runway_airport != v_origin_airport THEN
386 RAISE EXCEPTION 'Runway % does not belong to the origin airport (ID: %).',
387 p_RunwayId, v_origin_airport;
388 END IF;
389
390 IF v_direction_upper = 'ARRIVAL' THEN
391
392 IF NOT EXISTS (SELECT 1 FROM Arrivals WHERE FlightId = p_FlightId) THEN
393 RAISE EXCEPTION 'No Arrivals record found for flight with ID %.', p_FlightId;
394 END IF;
395
396 UPDATE Arrivals
397 SET RunwayId = p_RunwayId
398 WHERE FlightId = p_FlightId;
399
400 RAISE NOTICE 'Runway % assigned to Arrival for flight %.', p_RunwayId, p_FlightId;
401
402 ELSE
403
404 IF NOT EXISTS (SELECT 1 FROM Departures WHERE FlightId = p_FlightId) THEN
405 RAISE EXCEPTION 'No Departures record found for flight with ID %.', p_FlightId;
406 END IF;
407
408 UPDATE Departures
409 SET RunwayId = p_RunwayId
410 WHERE FlightId = p_FlightId;
411
412 RAISE NOTICE 'Runway % assigned to Departure for flight %.', p_RunwayId, p_FlightId;
413
414 END IF;
415
416 UPDATE Runway
417 SET Status = 'Occupied'
418 WHERE RunwayId = p_RunwayId;
419
420 RAISE NOTICE 'Runway % status changed to Occupied.', p_RunwayId;
421
422EXCEPTION
423 WHEN OTHERS THEN
424 RAISE EXCEPTION 'Error while assigning runway: %', SQLERRM;
425END;
426$$;
427
428
429--Го отвора или затвора терминалот заедно со сите негови гејтови, но блокира затворање ако има активни гејтови во статус „Boarding" или „Occupied"
430
431CREATE OR REPLACE PROCEDURE OpenCloseTerminal(
432 p_TerminalId INT,
433 p_Action VARCHAR(10)
434)
435LANGUAGE plpgsql
436AS $$
437DECLARE
438 v_terminal_exists BOOLEAN;
439 v_current_status VARCHAR(20);
440 v_action_upper VARCHAR(10);
441 v_active_flights INT;
442 v_new_status VARCHAR(20);
443BEGIN
444 v_action_upper := UPPER(TRIM(p_Action));
445
446 IF v_action_upper NOT IN ('OPEN', 'CLOSE') THEN
447 RAISE EXCEPTION 'Invalid action: %. Use OPEN or CLOSE.', p_Action;
448 END IF;
449
450 SELECT EXISTS (
451 SELECT 1 FROM Terminal WHERE TerminalId = p_TerminalId
452 ) INTO v_terminal_exists;
453
454 IF NOT v_terminal_exists THEN
455 RAISE EXCEPTION 'Terminal with ID % does not exist.', p_TerminalId;
456 END IF;
457
458 SELECT TerminalStatus INTO v_current_status
459 FROM Terminal WHERE TerminalId = p_TerminalId;
460
461 IF v_current_status = 'Under Maintenance' THEN
462 RAISE EXCEPTION 'Terminal with ID % is under maintenance and cannot be opened or closed directly.',
463 p_TerminalId;
464 END IF;
465
466 IF v_action_upper = 'OPEN' THEN
467 v_new_status := 'Open';
468 ELSE
469 v_new_status := 'Closed';
470 END IF;
471
472 IF v_current_status = v_new_status THEN
473 RAISE EXCEPTION 'Terminal with ID % is already in status: %.', p_TerminalId, v_new_status;
474 END IF;
475
476 IF v_action_upper = 'CLOSE' THEN
477 SELECT COUNT(*) INTO v_active_flights
478 FROM Gate
479 WHERE TerminalId = p_TerminalId
480 AND Status IN ('Boarding', 'Occupied');
481
482 IF v_active_flights > 0 THEN
483 RAISE EXCEPTION 'Terminal cannot be closed. There are % active gate(s) in Boarding/Occupied status.',
484 v_active_flights;
485 END IF;
486
487 UPDATE Gate
488 SET Status = 'Closed'
489 WHERE TerminalId = p_TerminalId
490 AND Status = 'Open';
491
492 RAISE NOTICE 'All open gates in terminal % have been closed.', p_TerminalId;
493 END IF;
494
495 IF v_action_upper = 'OPEN' THEN
496 UPDATE Gate
497 SET Status = 'Open'
498 WHERE TerminalId = p_TerminalId
499 AND Status = 'Closed';
500
501 RAISE NOTICE 'All closed gates in terminal % have been opened.', p_TerminalId;
502 END IF;
503
504 UPDATE Terminal
505 SET TerminalStatus = v_new_status
506 WHERE TerminalId = p_TerminalId;
507
508 RAISE NOTICE 'Terminal % successfully updated: % -> %.', p_TerminalId, v_current_status, v_new_status;
509
510EXCEPTION
511 WHEN OTHERS THEN
512 RAISE EXCEPTION 'Error while changing terminal status: %', SQLERRM;
513END;
514$$;
515
516
517--Закажува одржување на авион со валидација дека авионот нема активни летови, проверка за преклопување на термини, автоматско доделување на слободен хангар и креирање на запис во AircraftMaintenance со поставување на авионот во статус „Under Maintenance".
518
519CREATE OR REPLACE PROCEDURE ScheduleAircraftMaintenance(
520 p_AircraftId INT,
521 p_AirportId INT,
522 p_MaintenanceType VARCHAR(20),
523 p_StartDate TIMESTAMP,
524 p_EndDate TIMESTAMP,
525 p_WorkDescription TEXT DEFAULT NULL,
526 p_MaintenanceCost INT DEFAULT NULL
527)
528LANGUAGE plpgsql
529AS $$
530DECLARE
531 v_aircraft_exists BOOLEAN;
532 v_aircraft_status VARCHAR(20);
533 v_airport_exists BOOLEAN;
534 v_airport_status VARCHAR(20);
535 v_hangar_id INT;
536 v_overlap_count INT;
537 v_duration_minutes INT;
538 v_new_maintenance_id INT;
539BEGIN
540 SELECT EXISTS (
541 SELECT 1 FROM Aircraft WHERE AircraftId = p_AircraftId
542 ) INTO v_aircraft_exists;
543
544 IF NOT v_aircraft_exists THEN
545 RAISE EXCEPTION 'Aircraft with ID % does not exist.', p_AircraftId;
546 END IF;
547
548 SELECT Status INTO v_aircraft_status
549 FROM Aircraft WHERE AircraftId = p_AircraftId;
550
551 IF v_aircraft_status IN ('Retired') THEN
552 RAISE EXCEPTION 'Aircraft with ID % is retired and cannot be scheduled for maintenance.', p_AircraftId;
553 END IF;
554
555 IF v_aircraft_status IN ('Active') THEN
556 IF EXISTS (
557 SELECT 1 FROM Flights
558 WHERE AircraftId = p_AircraftId
559 AND OperatingStatus IN ('Boarding', 'Departed', 'En Route', 'Delayed')
560 ) THEN
561 RAISE EXCEPTION 'Aircraft with ID % has active flights and cannot be scheduled for maintenance.', p_AircraftId;
562 END IF;
563 END IF;
564
565 IF p_StartDate IS NULL THEN
566 RAISE EXCEPTION 'StartDate cannot be null.';
567 END IF;
568
569 IF p_EndDate IS NOT NULL AND p_EndDate <= p_StartDate THEN
570 RAISE EXCEPTION 'EndDate must be after StartDate.';
571 END IF;
572
573 IF p_StartDate < NOW() THEN
574 RAISE EXCEPTION 'StartDate cannot be in the past. Provided: %', p_StartDate;
575 END IF;
576
577 IF p_MaintenanceType NOT IN ('Routine', 'Repair', 'Inspection', 'Overhaul', 'Emergency') THEN
578 RAISE EXCEPTION 'Invalid MaintenanceType: %. Allowed: Routine, Repair, Inspection, Overhaul, Emergency.',
579 p_MaintenanceType;
580 END IF;
581
582 SELECT COUNT(*) INTO v_overlap_count
583 FROM AircraftMaintenance
584 WHERE AircraftId = p_AircraftId
585 AND Status NOT IN ('Completed', 'Cancelled')
586 AND (
587 (p_StartDate BETWEEN StartDate AND COALESCE(EndDate, p_StartDate + INTERVAL '1 day'))
588 OR
589 (COALESCE(p_EndDate, p_StartDate + INTERVAL '1 day') BETWEEN StartDate AND COALESCE(EndDate, p_StartDate + INTERVAL '1 day'))
590 OR
591 (p_StartDate <= StartDate AND COALESCE(p_EndDate, p_StartDate + INTERVAL '1 day') >= COALESCE(EndDate, p_StartDate + INTERVAL '1 day'))
592 );
593
594 IF v_overlap_count > 0 THEN
595 RAISE EXCEPTION 'Aircraft with ID % already has % overlapping maintenance record(s) in that period.',
596 p_AircraftId, v_overlap_count;
597 END IF;
598
599 SELECT EXISTS (
600 SELECT 1 FROM Airport WHERE AirportId = p_AirportId
601 ) INTO v_airport_exists;
602
603 IF NOT v_airport_exists THEN
604 RAISE EXCEPTION 'Airport with ID % does not exist.', p_AirportId;
605 END IF;
606
607 SELECT OperationalStatus INTO v_airport_status
608 FROM Airport WHERE AirportId = p_AirportId;
609
610 IF v_airport_status NOT IN ('Open', 'Restricted') THEN
611 RAISE EXCEPTION 'Airport with ID % is not available for maintenance. Status: %.',
612 p_AirportId, v_airport_status;
613 END IF;
614
615 SELECT h.HangarId INTO v_hangar_id
616 FROM Hangar h
617 WHERE h.AirportId = p_AirportId
618 AND h.Status = 'Open'
619 AND (
620 h.HangarCapacity IS NULL
621 OR (
622 SELECT COUNT(*) FROM StaysAt sa WHERE sa.HangarId = h.HangarId
623 ) < h.HangarCapacity
624 )
625 ORDER BY h.HangarId
626 LIMIT 1;
627
628 IF v_hangar_id IS NULL THEN
629 RAISE NOTICE 'No available hangar found at airport ID %. Maintenance will proceed without hangar assignment.',
630 p_AirportId;
631 ELSE
632 RAISE NOTICE 'Hangar ID % assigned for aircraft ID %.', v_hangar_id, p_AircraftId;
633
634 INSERT INTO StaysAt (HangarId, AircraftId)
635 VALUES (v_hangar_id, p_AircraftId)
636 ON CONFLICT DO NOTHING;
637 END IF;
638
639 IF p_EndDate IS NOT NULL THEN
640 v_duration_minutes := EXTRACT(EPOCH FROM (p_EndDate - p_StartDate))::INT / 60;
641 ELSE
642 v_duration_minutes := NULL;
643 END IF;
644
645 INSERT INTO AircraftMaintenance (
646 AircraftId,
647 MaintenanceType,
648 StartDate,
649 EndDate,
650 DurationMinutes,
651 WorkDescription,
652 Status,
653 MaintenanceCost,
654 AirportId
655 )
656 VALUES (
657 p_AircraftId,
658 p_MaintenanceType,
659 p_StartDate,
660 p_EndDate,
661 v_duration_minutes,
662 p_WorkDescription,
663 'Scheduled',
664 p_MaintenanceCost,
665 p_AirportId
666 )
667 RETURNING MaintenanceId INTO v_new_maintenance_id;
668
669 UPDATE Aircraft
670 SET Status = 'Under Maintenance'
671 WHERE AircraftId = p_AircraftId;
672
673 RAISE NOTICE 'Maintenance ID % successfully scheduled for aircraft ID % at airport ID % from % to %.',
674 v_new_maintenance_id, p_AircraftId, p_AirportId, p_StartDate, COALESCE(p_EndDate::TEXT, 'TBD');
675
676EXCEPTION
677 WHEN OTHERS THEN
678 RAISE EXCEPTION 'Error while scheduling maintenance for aircraft %: %', p_AircraftId, SQLERRM;
679END;
680$$;
681
682
683--Пред INSERT на WorksOn, повикува функција која проверува дали датумите на вработениот се валидни во однос на одржувањето.
684
685CREATE TRIGGER trg_check_workson_dates
686BEFORE INSERT ON WorksOn
687FOR EACH ROW
688EXECUTE FUNCTION check_employee_maintenance_dates();
689
690
691--Исто како претходниот тригер, но се активира пред UPDATE на WorksOn.
692
693CREATE TRIGGER trg_check_workson_dates_update
694BEFORE UPDATE ON WorksOn
695FOR EACH ROW
696EXECUTE FUNCTION check_employee_maintenance_dates();