|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.53 2000/12/03 14:51:01 thomas Exp $ |
| 11 | + * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.54 2000/12/07 18:38:59 tgl Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
@@ -529,37 +529,122 @@ time_smaller(PG_FUNCTION_ARGS)
|
529 | 529 | PG_RETURN_TIMEADT((time1 < time2) ? time1 : time2);
|
530 | 530 | }
|
531 | 531 |
|
532 |
| -/* overlaps_time() |
533 |
| - * Implements the SQL92 OVERLAPS operator. |
534 |
| - * Algorithm from Date and Darwen, 1997 |
| 532 | +/* overlaps_time() --- implements the SQL92 OVERLAPS operator. |
| 533 | + * |
| 534 | + * Algorithm is per SQL92 spec. This is much harder than you'd think |
| 535 | + * because the spec requires us to deliver a non-null answer in some cases |
| 536 | + * where some of the inputs are null. |
535 | 537 | */
|
536 | 538 | Datum
|
537 | 539 | overlaps_time(PG_FUNCTION_ARGS)
|
538 | 540 | {
|
539 |
| - TimeADT ts1 = PG_GETARG_TIMEADT(0); |
540 |
| - TimeADT te1 = PG_GETARG_TIMEADT(1); |
541 |
| - TimeADT ts2 = PG_GETARG_TIMEADT(2); |
542 |
| - TimeADT te2 = PG_GETARG_TIMEADT(3); |
| 541 | + /* The arguments are TimeADT, but we leave them as generic Datums |
| 542 | + * to avoid dereferencing nulls (TimeADT is pass-by-reference!) |
| 543 | + */ |
| 544 | + Datum ts1 = PG_GETARG_DATUM(0); |
| 545 | + Datum te1 = PG_GETARG_DATUM(1); |
| 546 | + Datum ts2 = PG_GETARG_DATUM(2); |
| 547 | + Datum te2 = PG_GETARG_DATUM(3); |
| 548 | + bool ts1IsNull = PG_ARGISNULL(0); |
| 549 | + bool te1IsNull = PG_ARGISNULL(1); |
| 550 | + bool ts2IsNull = PG_ARGISNULL(2); |
| 551 | + bool te2IsNull = PG_ARGISNULL(3); |
543 | 552 |
|
544 |
| - /* Make sure we have ordered pairs... */ |
545 |
| - if (ts1 > te1) |
546 |
| - { |
547 |
| - TimeADT tt = ts1; |
| 553 | +#define TIMEADT_GT(t1,t2) \ |
| 554 | + (DatumGetTimeADT(t1) > DatumGetTimeADT(t2)) |
| 555 | +#define TIMEADT_LT(t1,t2) \ |
| 556 | + (DatumGetTimeADT(t1) < DatumGetTimeADT(t2)) |
548 | 557 |
|
| 558 | + /* |
| 559 | + * If both endpoints of interval 1 are null, the result is null (unknown). |
| 560 | + * If just one endpoint is null, take ts1 as the non-null one. |
| 561 | + * Otherwise, take ts1 as the lesser endpoint. |
| 562 | + */ |
| 563 | + if (ts1IsNull) |
| 564 | + { |
| 565 | + if (te1IsNull) |
| 566 | + PG_RETURN_NULL(); |
| 567 | + /* swap null for non-null */ |
549 | 568 | ts1 = te1;
|
550 |
| - te1 = tt; |
| 569 | + te1IsNull = true; |
551 | 570 | }
|
552 |
| - if (ts2 > te2) |
| 571 | + else if (!te1IsNull) |
553 | 572 | {
|
554 |
| - TimeADT tt = ts2; |
| 573 | + if (TIMEADT_GT(ts1, te1)) |
| 574 | + { |
| 575 | + Datum tt = ts1; |
| 576 | + |
| 577 | + ts1 = te1; |
| 578 | + te1 = tt; |
| 579 | + } |
| 580 | + } |
555 | 581 |
|
| 582 | + /* Likewise for interval 2. */ |
| 583 | + if (ts2IsNull) |
| 584 | + { |
| 585 | + if (te2IsNull) |
| 586 | + PG_RETURN_NULL(); |
| 587 | + /* swap null for non-null */ |
556 | 588 | ts2 = te2;
|
557 |
| - te2 = tt; |
| 589 | + te2IsNull = true; |
| 590 | + } |
| 591 | + else if (!te2IsNull) |
| 592 | + { |
| 593 | + if (TIMEADT_GT(ts2, te2)) |
| 594 | + { |
| 595 | + Datum tt = ts2; |
| 596 | + |
| 597 | + ts2 = te2; |
| 598 | + te2 = tt; |
| 599 | + } |
558 | 600 | }
|
559 | 601 |
|
560 |
| - PG_RETURN_BOOL((ts1 > ts2 && (ts1 < te2 || te1 < te2)) || |
561 |
| - (ts1 < ts2 && (ts2 < te1 || te2 < te1)) || |
562 |
| - (ts1 == ts2)); |
| 602 | + /* |
| 603 | + * At this point neither ts1 nor ts2 is null, so we can consider three |
| 604 | + * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2 |
| 605 | + */ |
| 606 | + if (TIMEADT_GT(ts1, ts2)) |
| 607 | + { |
| 608 | + /* This case is ts1 < te2 OR te1 < te2, which may look redundant |
| 609 | + * but in the presence of nulls it's not quite completely so. |
| 610 | + */ |
| 611 | + if (te2IsNull) |
| 612 | + PG_RETURN_NULL(); |
| 613 | + if (TIMEADT_LT(ts1, te2)) |
| 614 | + PG_RETURN_BOOL(true); |
| 615 | + if (te1IsNull) |
| 616 | + PG_RETURN_NULL(); |
| 617 | + /* If te1 is not null then we had ts1 <= te1 above, and we just |
| 618 | + * found ts1 >= te2, hence te1 >= te2. |
| 619 | + */ |
| 620 | + PG_RETURN_BOOL(false); |
| 621 | + } |
| 622 | + else if (TIMEADT_LT(ts1, ts2)) |
| 623 | + { |
| 624 | + /* This case is ts2 < te1 OR te2 < te1 */ |
| 625 | + if (te1IsNull) |
| 626 | + PG_RETURN_NULL(); |
| 627 | + if (TIMEADT_LT(ts2, te1)) |
| 628 | + PG_RETURN_BOOL(true); |
| 629 | + if (te2IsNull) |
| 630 | + PG_RETURN_NULL(); |
| 631 | + /* If te2 is not null then we had ts2 <= te2 above, and we just |
| 632 | + * found ts2 >= te1, hence te2 >= te1. |
| 633 | + */ |
| 634 | + PG_RETURN_BOOL(false); |
| 635 | + } |
| 636 | + else |
| 637 | + { |
| 638 | + /* For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a |
| 639 | + * rather silly way of saying "true if both are nonnull, else null". |
| 640 | + */ |
| 641 | + if (te1IsNull || te2IsNull) |
| 642 | + PG_RETURN_NULL(); |
| 643 | + PG_RETURN_BOOL(true); |
| 644 | + } |
| 645 | + |
| 646 | +#undef TIMEADT_GT |
| 647 | +#undef TIMEADT_LT |
563 | 648 | }
|
564 | 649 |
|
565 | 650 | /* timestamp_time()
|
@@ -964,53 +1049,122 @@ timetz_mi_interval(PG_FUNCTION_ARGS)
|
964 | 1049 | PG_RETURN_TIMETZADT_P(result);
|
965 | 1050 | }
|
966 | 1051 |
|
967 |
| -/* overlaps_timetz() |
968 |
| - * Implements the SQL92 OVERLAPS operator. |
969 |
| - * Algorithm from Date and Darwen, 1997 |
| 1052 | +/* overlaps_timetz() --- implements the SQL92 OVERLAPS operator. |
| 1053 | + * |
| 1054 | + * Algorithm is per SQL92 spec. This is much harder than you'd think |
| 1055 | + * because the spec requires us to deliver a non-null answer in some cases |
| 1056 | + * where some of the inputs are null. |
970 | 1057 | */
|
971 | 1058 | Datum
|
972 | 1059 | overlaps_timetz(PG_FUNCTION_ARGS)
|
973 | 1060 | {
|
974 | 1061 | /* The arguments are TimeTzADT *, but we leave them as generic Datums
|
975 |
| - * for convenience of notation. |
| 1062 | + * for convenience of notation --- and to avoid dereferencing nulls. |
976 | 1063 | */
|
977 | 1064 | Datum ts1 = PG_GETARG_DATUM(0);
|
978 | 1065 | Datum te1 = PG_GETARG_DATUM(1);
|
979 | 1066 | Datum ts2 = PG_GETARG_DATUM(2);
|
980 | 1067 | Datum te2 = PG_GETARG_DATUM(3);
|
| 1068 | + bool ts1IsNull = PG_ARGISNULL(0); |
| 1069 | + bool te1IsNull = PG_ARGISNULL(1); |
| 1070 | + bool ts2IsNull = PG_ARGISNULL(2); |
| 1071 | + bool te2IsNull = PG_ARGISNULL(3); |
981 | 1072 |
|
982 | 1073 | #define TIMETZ_GT(t1,t2) \
|
983 | 1074 | DatumGetBool(DirectFunctionCall2(timetz_gt,t1,t2))
|
984 | 1075 | #define TIMETZ_LT(t1,t2) \
|
985 | 1076 | DatumGetBool(DirectFunctionCall2(timetz_lt,t1,t2))
|
986 |
| -#define TIMETZ_EQ(t1,t2) \ |
987 |
| - DatumGetBool(DirectFunctionCall2(timetz_eq,t1,t2)) |
988 | 1077 |
|
989 |
| - /* Make sure we have ordered pairs... */ |
990 |
| - if (TIMETZ_GT(ts1, te1)) |
| 1078 | + /* |
| 1079 | + * If both endpoints of interval 1 are null, the result is null (unknown). |
| 1080 | + * If just one endpoint is null, take ts1 as the non-null one. |
| 1081 | + * Otherwise, take ts1 as the lesser endpoint. |
| 1082 | + */ |
| 1083 | + if (ts1IsNull) |
991 | 1084 | {
|
992 |
| - Datum tt = ts1; |
993 |
| - |
| 1085 | + if (te1IsNull) |
| 1086 | + PG_RETURN_NULL(); |
| 1087 | + /* swap null for non-null */ |
994 | 1088 | ts1 = te1;
|
995 |
| - te1 = tt; |
| 1089 | + te1IsNull = true; |
996 | 1090 | }
|
997 |
| - if (TIMETZ_GT(ts2, te2)) |
| 1091 | + else if (!te1IsNull) |
998 | 1092 | {
|
999 |
| - Datum tt = ts2; |
| 1093 | + if (TIMETZ_GT(ts1, te1)) |
| 1094 | + { |
| 1095 | + Datum tt = ts1; |
| 1096 | + |
| 1097 | + ts1 = te1; |
| 1098 | + te1 = tt; |
| 1099 | + } |
| 1100 | + } |
1000 | 1101 |
|
| 1102 | + /* Likewise for interval 2. */ |
| 1103 | + if (ts2IsNull) |
| 1104 | + { |
| 1105 | + if (te2IsNull) |
| 1106 | + PG_RETURN_NULL(); |
| 1107 | + /* swap null for non-null */ |
1001 | 1108 | ts2 = te2;
|
1002 |
| - te2 = tt; |
| 1109 | + te2IsNull = true; |
| 1110 | + } |
| 1111 | + else if (!te2IsNull) |
| 1112 | + { |
| 1113 | + if (TIMETZ_GT(ts2, te2)) |
| 1114 | + { |
| 1115 | + Datum tt = ts2; |
| 1116 | + |
| 1117 | + ts2 = te2; |
| 1118 | + te2 = tt; |
| 1119 | + } |
1003 | 1120 | }
|
1004 | 1121 |
|
1005 |
| - PG_RETURN_BOOL((TIMETZ_GT(ts1, ts2) && |
1006 |
| - (TIMETZ_LT(ts1, te2) || TIMETZ_LT(te1, te2))) || |
1007 |
| - (TIMETZ_GT(ts2, ts1) && |
1008 |
| - (TIMETZ_LT(ts2, te1) || TIMETZ_LT(te2, te1))) || |
1009 |
| - TIMETZ_EQ(ts1, ts2)); |
| 1122 | + /* |
| 1123 | + * At this point neither ts1 nor ts2 is null, so we can consider three |
| 1124 | + * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2 |
| 1125 | + */ |
| 1126 | + if (TIMETZ_GT(ts1, ts2)) |
| 1127 | + { |
| 1128 | + /* This case is ts1 < te2 OR te1 < te2, which may look redundant |
| 1129 | + * but in the presence of nulls it's not quite completely so. |
| 1130 | + */ |
| 1131 | + if (te2IsNull) |
| 1132 | + PG_RETURN_NULL(); |
| 1133 | + if (TIMETZ_LT(ts1, te2)) |
| 1134 | + PG_RETURN_BOOL(true); |
| 1135 | + if (te1IsNull) |
| 1136 | + PG_RETURN_NULL(); |
| 1137 | + /* If te1 is not null then we had ts1 <= te1 above, and we just |
| 1138 | + * found ts1 >= te2, hence te1 >= te2. |
| 1139 | + */ |
| 1140 | + PG_RETURN_BOOL(false); |
| 1141 | + } |
| 1142 | + else if (TIMETZ_LT(ts1, ts2)) |
| 1143 | + { |
| 1144 | + /* This case is ts2 < te1 OR te2 < te1 */ |
| 1145 | + if (te1IsNull) |
| 1146 | + PG_RETURN_NULL(); |
| 1147 | + if (TIMETZ_LT(ts2, te1)) |
| 1148 | + PG_RETURN_BOOL(true); |
| 1149 | + if (te2IsNull) |
| 1150 | + PG_RETURN_NULL(); |
| 1151 | + /* If te2 is not null then we had ts2 <= te2 above, and we just |
| 1152 | + * found ts2 >= te1, hence te2 >= te1. |
| 1153 | + */ |
| 1154 | + PG_RETURN_BOOL(false); |
| 1155 | + } |
| 1156 | + else |
| 1157 | + { |
| 1158 | + /* For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a |
| 1159 | + * rather silly way of saying "true if both are nonnull, else null". |
| 1160 | + */ |
| 1161 | + if (te1IsNull || te2IsNull) |
| 1162 | + PG_RETURN_NULL(); |
| 1163 | + PG_RETURN_BOOL(true); |
| 1164 | + } |
1010 | 1165 |
|
1011 | 1166 | #undef TIMETZ_GT
|
1012 | 1167 | #undef TIMETZ_LT
|
1013 |
| -#undef TIMETZ_EQ |
1014 | 1168 | }
|
1015 | 1169 |
|
1016 | 1170 | /* timestamp_timetz()
|
|
0 commit comments