@@ -851,29 +851,38 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
851
851
int32 S = start ; /* start position */
852
852
int32 S1 ; /* adjusted start position */
853
853
int32 L1 ; /* adjusted substring length */
854
+ int32 E ; /* end position */
855
+
856
+ /*
857
+ * SQL99 says S can be zero or negative, but we still must fetch from the
858
+ * start of the string.
859
+ */
860
+ S1 = Max (S , 1 );
854
861
855
862
/* life is easy if the encoding max length is 1 */
856
863
if (eml == 1 )
857
864
{
858
- S1 = Max (S , 1 );
859
-
860
865
if (length_not_specified ) /* special case - get length to end of
861
866
* string */
862
867
L1 = -1 ;
863
- else
868
+ else if (length < 0 )
869
+ {
870
+ /* SQL99 says to throw an error for E < S, i.e., negative length */
871
+ ereport (ERROR ,
872
+ (errcode (ERRCODE_SUBSTRING_ERROR ),
873
+ errmsg ("negative substring length not allowed" )));
874
+ L1 = -1 ; /* silence stupider compilers */
875
+ }
876
+ else if (pg_add_s32_overflow (S , length , & E ))
864
877
{
865
- /* end position */
866
- int E = S + length ;
867
-
868
878
/*
869
- * A negative value for L is the only way for the end position to
870
- * be before the start. SQL99 says to throw an error .
879
+ * L could be large enough for S + L to overflow, in which case
880
+ * the substring must run to end of string .
871
881
*/
872
- if (E < S )
873
- ereport (ERROR ,
874
- (errcode (ERRCODE_SUBSTRING_ERROR ),
875
- errmsg ("negative substring length not allowed" )));
876
-
882
+ L1 = -1 ;
883
+ }
884
+ else
885
+ {
877
886
/*
878
887
* A zero or negative value for the end position can happen if the
879
888
* start was negative or one. SQL99 says to return a zero-length
@@ -887,8 +896,8 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
887
896
888
897
/*
889
898
* If the start position is past the end of the string, SQL99 says to
890
- * return a zero-length string -- PG_GETARG_TEXT_P_SLICE () will do
891
- * that for us. Convert to zero-based starting position
899
+ * return a zero-length string -- DatumGetTextPSlice () will do that
900
+ * for us. We need only convert S1 to zero-based starting position.
892
901
*/
893
902
return DatumGetTextPSlice (str , S1 - 1 , L1 );
894
903
}
@@ -909,12 +918,6 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
909
918
char * s ;
910
919
text * ret ;
911
920
912
- /*
913
- * if S is past the end of the string, the tuple toaster will return a
914
- * zero-length string to us
915
- */
916
- S1 = Max (S , 1 );
917
-
918
921
/*
919
922
* We need to start at position zero because there is no way to know
920
923
* in advance which byte offset corresponds to the supplied start
@@ -925,19 +928,24 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
925
928
if (length_not_specified ) /* special case - get length to end of
926
929
* string */
927
930
slice_size = L1 = -1 ;
928
- else
931
+ else if (length < 0 )
932
+ {
933
+ /* SQL99 says to throw an error for E < S, i.e., negative length */
934
+ ereport (ERROR ,
935
+ (errcode (ERRCODE_SUBSTRING_ERROR ),
936
+ errmsg ("negative substring length not allowed" )));
937
+ slice_size = L1 = -1 ; /* silence stupider compilers */
938
+ }
939
+ else if (pg_add_s32_overflow (S , length , & E ))
929
940
{
930
- int E = S + length ;
931
-
932
941
/*
933
- * A negative value for L is the only way for the end position to
934
- * be before the start. SQL99 says to throw an error .
942
+ * L could be large enough for S + L to overflow, in which case
943
+ * the substring must run to end of string .
935
944
*/
936
- if (E < S )
937
- ereport (ERROR ,
938
- (errcode (ERRCODE_SUBSTRING_ERROR ),
939
- errmsg ("negative substring length not allowed" )));
940
-
945
+ slice_size = L1 = -1 ;
946
+ }
947
+ else
948
+ {
941
949
/*
942
950
* A zero or negative value for the end position can happen if the
943
951
* start was negative or one. SQL99 says to return a zero-length
@@ -955,8 +963,10 @@ text_substring(Datum str, int32 start, int32 length, bool length_not_specified)
955
963
/*
956
964
* Total slice size in bytes can't be any longer than the start
957
965
* position plus substring length times the encoding max length.
966
+ * If that overflows, we can just use -1.
958
967
*/
959
- slice_size = (S1 + L1 ) * eml ;
968
+ if (pg_mul_s32_overflow (E , eml , & slice_size ))
969
+ slice_size = -1 ;
960
970
}
961
971
962
972
/*
@@ -3278,9 +3288,13 @@ bytea_substring(Datum str,
3278
3288
int L ,
3279
3289
bool length_not_specified )
3280
3290
{
3281
- int S1 ; /* adjusted start position */
3282
- int L1 ; /* adjusted substring length */
3291
+ int32 S1 ; /* adjusted start position */
3292
+ int32 L1 ; /* adjusted substring length */
3293
+ int32 E ; /* end position */
3283
3294
3295
+ /*
3296
+ * The logic here should generally match text_substring().
3297
+ */
3284
3298
S1 = Max (S , 1 );
3285
3299
3286
3300
if (length_not_specified )
@@ -3291,20 +3305,24 @@ bytea_substring(Datum str,
3291
3305
*/
3292
3306
L1 = -1 ;
3293
3307
}
3294
- else
3308
+ else if (L < 0 )
3309
+ {
3310
+ /* SQL99 says to throw an error for E < S, i.e., negative length */
3311
+ ereport (ERROR ,
3312
+ (errcode (ERRCODE_SUBSTRING_ERROR ),
3313
+ errmsg ("negative substring length not allowed" )));
3314
+ L1 = -1 ; /* silence stupider compilers */
3315
+ }
3316
+ else if (pg_add_s32_overflow (S , L , & E ))
3295
3317
{
3296
- /* end position */
3297
- int E = S + L ;
3298
-
3299
3318
/*
3300
- * A negative value for L is the only way for the end position to be
3301
- * before the start. SQL99 says to throw an error .
3319
+ * L could be large enough for S + L to overflow, in which case the
3320
+ * substring must run to end of string .
3302
3321
*/
3303
- if (E < S )
3304
- ereport (ERROR ,
3305
- (errcode (ERRCODE_SUBSTRING_ERROR ),
3306
- errmsg ("negative substring length not allowed" )));
3307
-
3322
+ L1 = -1 ;
3323
+ }
3324
+ else
3325
+ {
3308
3326
/*
3309
3327
* A zero or negative value for the end position can happen if the
3310
3328
* start was negative or one. SQL99 says to return a zero-length
@@ -3319,7 +3337,7 @@ bytea_substring(Datum str,
3319
3337
/*
3320
3338
* If the start position is past the end of the string, SQL99 says to
3321
3339
* return a zero-length string -- DatumGetByteaPSlice() will do that for
3322
- * us. Convert to zero-based starting position
3340
+ * us. We need only convert S1 to zero-based starting position.
3323
3341
*/
3324
3342
return DatumGetByteaPSlice (str , S1 - 1 , L1 );
3325
3343
}
0 commit comments