@@ -868,29 +868,38 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
868
868
int32 S = start ; /* start position */
869
869
int32 S1 ; /* adjusted start position */
870
870
int32 L1 ; /* adjusted substring length */
871
+ int32 E ; /* end position */
872
+
873
+ /*
874
+ * SQL99 says S can be zero or negative, but we still must fetch from the
875
+ * start of the string.
876
+ */
877
+ S1 = Max (S , 1 );
871
878
872
879
/* life is easy if the encoding max length is 1 */
873
880
if (eml == 1 )
874
881
{
875
- S1 = Max (S , 1 );
876
-
877
882
if (length_not_specified ) /* special case - get length to end of
878
883
* string */
879
884
L1 = -1 ;
880
- else
885
+ else if (length < 0 )
886
+ {
887
+ /* SQL99 says to throw an error for E < S, i.e., negative length */
888
+ ereport (ERROR ,
889
+ (errcode (ERRCODE_SUBSTRING_ERROR ),
890
+ errmsg ("negative substring length not allowed" )));
891
+ L1 = -1 ; /* silence stupider compilers */
892
+ }
893
+ else if (pg_add_s32_overflow (S , length , & E ))
881
894
{
882
- /* end position */
883
- int E = S + length ;
884
-
885
895
/*
886
- * A negative value for L is the only way for the end position to
887
- * be before the start. SQL99 says to throw an error .
896
+ * L could be large enough for S + L to overflow, in which case
897
+ * the substring must run to end of string .
888
898
*/
889
- if (E < S )
890
- ereport (ERROR ,
891
- (errcode (ERRCODE_SUBSTRING_ERROR ),
892
- errmsg ("negative substring length not allowed" )));
893
-
899
+ L1 = -1 ;
900
+ }
901
+ else
902
+ {
894
903
/*
895
904
* A zero or negative value for the end position can happen if the
896
905
* start was negative or one. SQL99 says to return a zero-length
@@ -904,8 +913,8 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
904
913
905
914
/*
906
915
* If the start position is past the end of the string, SQL99 says to
907
- * return a zero-length string -- PG_GETARG_TEXT_P_SLICE () will do
908
- * that for us. Convert to zero-based starting position
916
+ * return a zero-length string -- DatumGetTextPSlice () will do that
917
+ * for us. We need only convert S1 to zero-based starting position.
909
918
*/
910
919
return DatumGetTextPSlice (str , S1 - 1 , L1 );
911
920
}
@@ -926,12 +935,6 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
926
935
char * s ;
927
936
text * ret ;
928
937
929
- /*
930
- * if S is past the end of the string, the tuple toaster will return a
931
- * zero-length string to us
932
- */
933
- S1 = Max (S , 1 );
934
-
935
938
/*
936
939
* We need to start at position zero because there is no way to know
937
940
* in advance which byte offset corresponds to the supplied start
@@ -942,19 +945,24 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
942
945
if (length_not_specified ) /* special case - get length to end of
943
946
* string */
944
947
slice_size = L1 = -1 ;
945
- else
948
+ else if (length < 0 )
949
+ {
950
+ /* SQL99 says to throw an error for E < S, i.e., negative length */
951
+ ereport (ERROR ,
952
+ (errcode (ERRCODE_SUBSTRING_ERROR ),
953
+ errmsg ("negative substring length not allowed" )));
954
+ slice_size = L1 = -1 ; /* silence stupider compilers */
955
+ }
956
+ else if (pg_add_s32_overflow (S , length , & E ))
946
957
{
947
- int E = S + length ;
948
-
949
958
/*
950
- * A negative value for L is the only way for the end position to
951
- * be before the start. SQL99 says to throw an error .
959
+ * L could be large enough for S + L to overflow, in which case
960
+ * the substring must run to end of string .
952
961
*/
953
- if (E < S )
954
- ereport (ERROR ,
955
- (errcode (ERRCODE_SUBSTRING_ERROR ),
956
- errmsg ("negative substring length not allowed" )));
957
-
962
+ slice_size = L1 = -1 ;
963
+ }
964
+ else
965
+ {
958
966
/*
959
967
* A zero or negative value for the end position can happen if the
960
968
* start was negative or one. SQL99 says to return a zero-length
@@ -972,8 +980,10 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
972
980
/*
973
981
* Total slice size in bytes can't be any longer than the start
974
982
* position plus substring length times the encoding max length.
983
+ * If that overflows, we can just use -1.
975
984
*/
976
- slice_size = (S1 + L1 ) * eml ;
985
+ if (pg_mul_s32_overflow (E , eml , & slice_size ))
986
+ slice_size = -1 ;
977
987
}
978
988
979
989
/*
@@ -3309,9 +3319,13 @@ bytea_substring(Datum str,
3309
3319
int L ,
3310
3320
bool length_not_specified )
3311
3321
{
3312
- int S1 ; /* adjusted start position */
3313
- int L1 ; /* adjusted substring length */
3322
+ int32 S1 ; /* adjusted start position */
3323
+ int32 L1 ; /* adjusted substring length */
3324
+ int32 E ; /* end position */
3314
3325
3326
+ /*
3327
+ * The logic here should generally match text_substring().
3328
+ */
3315
3329
S1 = Max (S , 1 );
3316
3330
3317
3331
if (length_not_specified )
@@ -3322,20 +3336,24 @@ bytea_substring(Datum str,
3322
3336
*/
3323
3337
L1 = -1 ;
3324
3338
}
3325
- else
3339
+ else if (L < 0 )
3340
+ {
3341
+ /* SQL99 says to throw an error for E < S, i.e., negative length */
3342
+ ereport (ERROR ,
3343
+ (errcode (ERRCODE_SUBSTRING_ERROR ),
3344
+ errmsg ("negative substring length not allowed" )));
3345
+ L1 = -1 ; /* silence stupider compilers */
3346
+ }
3347
+ else if (pg_add_s32_overflow (S , L , & E ))
3326
3348
{
3327
- /* end position */
3328
- int E = S + L ;
3329
-
3330
3349
/*
3331
- * A negative value for L is the only way for the end position to be
3332
- * before the start. SQL99 says to throw an error .
3350
+ * L could be large enough for S + L to overflow, in which case the
3351
+ * substring must run to end of string .
3333
3352
*/
3334
- if (E < S )
3335
- ereport (ERROR ,
3336
- (errcode (ERRCODE_SUBSTRING_ERROR ),
3337
- errmsg ("negative substring length not allowed" )));
3338
-
3353
+ L1 = -1 ;
3354
+ }
3355
+ else
3356
+ {
3339
3357
/*
3340
3358
* A zero or negative value for the end position can happen if the
3341
3359
* start was negative or one. SQL99 says to return a zero-length
@@ -3350,7 +3368,7 @@ bytea_substring(Datum str,
3350
3368
/*
3351
3369
* If the start position is past the end of the string, SQL99 says to
3352
3370
* return a zero-length string -- DatumGetByteaPSlice() will do that for
3353
- * us. Convert to zero-based starting position
3371
+ * us. We need only convert S1 to zero-based starting position.
3354
3372
*/
3355
3373
return DatumGetByteaPSlice (str , S1 - 1 , L1 );
3356
3374
}
0 commit comments