@@ -147,6 +147,17 @@ ZEND_TSRMLS_CACHE_DEFINE()
147
147
ZEND_GET_MODULE (pgsql )
148
148
#endif
149
149
150
+ struct _pcre_cache_entry {
151
+ pcre2_code * re ;
152
+ /* Pointer is not NULL when there are named captures.
153
+ * Length is equal to capture_count + 1 to account for capture group 0. */
154
+ zend_string * * subpats_table ;
155
+ uint32_t preg_options ;
156
+ uint32_t capture_count ;
157
+ uint32_t compile_options ;
158
+ uint32_t refcount ;
159
+ };
160
+
150
161
static int le_plink ;
151
162
152
163
static zend_class_entry * pgsql_link_ce , * pgsql_result_ce , * pgsql_lob_ce ;
@@ -490,8 +501,51 @@ static PHP_GINIT_FUNCTION(pgsql)
490
501
#if defined(COMPILE_DL_PGSQL ) && defined(ZTS )
491
502
ZEND_TSRMLS_CACHE_UPDATE ();
492
503
#endif
504
+
505
+ size_t i = 0 ;
493
506
memset (pgsql_globals , 0 , sizeof (zend_pgsql_globals ));
494
507
zend_hash_init (& pgsql_globals -> connections , 0 , NULL , NULL , 1 );
508
+
509
+ #define ADD_REGEX (reg ) pgsql_globals->regexes[i ++] = zend_string_init(reg, strlen(reg), true)
510
+ ADD_REGEX ("#^([+-]{0,1}[0-9]+)$#n" );
511
+ ADD_REGEX ("#^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$#n" );
512
+ ADD_REGEX ("#^[+-]{0,1}(inf)(inity){0,1}$#ni" );
513
+ ADD_REGEX ("#^[0-9]+$#n" );
514
+ ADD_REGEX ("#^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])(\\/[0-9]{1,3})?$#n" );
515
+ ADD_REGEX ("#^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(\\/[0-9]{1,3})?$#n" );
516
+ ADD_REGEX ("#^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})(([ \\t]+|T)(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1}(\\.[0-9]+){0,1}([ \\t]*([+-][0-9]{1,4}(:[0-9]{1,2}){0,1}|[-a-zA-Z_/+]{1,50})){0,1})){0,1}$#ni" );
517
+ ADD_REGEX ("#^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})$#ni" );
518
+ ADD_REGEX ("#^(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1}){0,1}$#ni" );
519
+ ADD_REGEX ("#^(@?[ \\t]+)?("
520
+ /* Textual time units and their abbreviations: */
521
+ "(([-+]?[ \\t]+)?"
522
+ "[0-9]+(\\.[0-9]*)?[ \\t]*"
523
+ "(millenniums|millennia|millennium|mil|mils|"
524
+ "centuries|century|cent|c|"
525
+ "decades|decade|dec|decs|"
526
+ "years|year|y|"
527
+ "months|month|mon|"
528
+ "weeks|week|w|"
529
+ "days|day|d|"
530
+ "hours|hour|hr|hrs|h|"
531
+ "minutes|minute|mins|min|m|"
532
+ "seconds|second|secs|sec|s))+|"
533
+ /* Textual time units plus (dd)* hh[:mm[:ss]] */
534
+ "((([-+]?[ \\t]+)?"
535
+ "[0-9]+(\\.[0-9]*)?[ \\t]*"
536
+ "(millenniums|millennia|millennium|mil|mils|"
537
+ "centuries|century|cent|c|"
538
+ "decades|decade|dec|decs|"
539
+ "years|year|y|"
540
+ "months|month|mon|"
541
+ "weeks|week|w|"
542
+ "days|day|d))+"
543
+ "([-+]?[ \\t]+"
544
+ "([0-9]+[ \\t]+)+" /* dd */
545
+ "(([0-9]{1,2}:){0,2}[0-9]{0,2})" /* hh:[mm:[ss]] */
546
+ ")?))"
547
+ "([ \\t]+ago)?$#ni" );
548
+ ADD_REGEX ("#^([0-9a-f]{2,2}:){5,5}[0-9a-f]{2,2}$#ni" );
495
549
}
496
550
497
551
static void php_libpq_version (char * buf , size_t len )
@@ -558,8 +612,12 @@ PHP_MINIT_FUNCTION(pgsql)
558
612
PHP_MSHUTDOWN_FUNCTION (pgsql )
559
613
{
560
614
UNREGISTER_INI_ENTRIES ();
615
+ size_t i ;
561
616
zend_hash_destroy (& PGG (connections ));
562
617
618
+ for (i = 0 ; i < 11 ; i ++ )
619
+ zend_string_release_ex (PGG (regexes [i ]), true);
620
+
563
621
return SUCCESS ;
564
622
}
565
623
@@ -4671,15 +4729,12 @@ static php_pgsql_data_type php_pgsql_get_data_type(const zend_string *type_name)
4671
4729
/* {{{ php_pgsql_convert_match
4672
4730
* test field value with regular expression specified.
4673
4731
*/
4674
- static int php_pgsql_convert_match (const zend_string * str , const char * regex , size_t regex_len , int icase )
4732
+ static int php_pgsql_convert_match (const zend_string * str , zend_string * regex )
4675
4733
{
4676
- pcre2_code * re ;
4677
- PCRE2_SIZE err_offset ;
4678
- int res , errnumber ;
4679
- uint32_t options = PCRE2_NO_AUTO_CAPTURE ;
4734
+ pcre_cache_entry * centry ;
4735
+ int res ;
4680
4736
size_t i ;
4681
4737
pcre2_match_data * match_data ;
4682
- PCRE2_UCHAR err_msg [128 ];
4683
4738
4684
4739
/* Check invalid chars for POSIX regex */
4685
4740
for (i = 0 ; i < ZSTR_LEN (str ); i ++ ) {
@@ -4690,38 +4745,20 @@ static int php_pgsql_convert_match(const zend_string *str, const char *regex , s
4690
4745
}
4691
4746
}
4692
4747
4693
- if (icase ) {
4694
- options |= PCRE2_CASELESS ;
4695
- }
4696
-
4697
- re = pcre2_compile ((PCRE2_SPTR )regex , regex_len , options , & errnumber , & err_offset , php_pcre_cctx ());
4698
- if (NULL == re ) {
4699
- pcre2_get_error_message (errnumber , err_msg , sizeof (err_msg ));
4700
- php_error_docref (NULL , E_WARNING , "Cannot compile regex: '%s'" , err_msg );
4748
+ centry = pcre_get_compiled_regex_cache (regex );
4749
+ if (NULL == centry ) {
4701
4750
return FAILURE ;
4702
4751
}
4703
- #if defined(HAVE_PCRE_JIT_SUPPORT )
4704
- if (PCRE_G (jit )) {
4705
- /*
4706
- * Check if the JIT pass did not work, but the regex had been compiled successfully earlier
4707
- * so let's not end it here.
4708
- */
4709
- if (UNEXPECTED (pcre2_jit_compile (re , PCRE2_JIT_COMPLETE ) != 0 )) {
4710
- pcre2_get_error_message (errnumber , err_msg , sizeof (err_msg ));
4711
- php_error_docref (NULL , E_WARNING , "Cannot use JIT on regex: '%s'" , err_msg );
4712
- }
4713
- }
4714
- #endif
4715
4752
4716
- match_data = php_pcre_create_match_data (0 , re );
4753
+ match_data = php_pcre_create_match_data (0 , centry -> re );
4717
4754
if (NULL == match_data ) {
4718
- pcre2_code_free (re );
4719
4755
php_error_docref (NULL , E_WARNING , "Cannot allocate match data" );
4720
4756
return FAILURE ;
4721
4757
}
4722
- res = pcre2_match (re , (PCRE2_SPTR )ZSTR_VAL (str ), ZSTR_LEN (str ), 0 , 0 , match_data , php_pcre_mctx ());
4758
+ centry -> refcount ++ ;
4759
+ res = pcre2_match (centry -> re , (PCRE2_SPTR )ZSTR_VAL (str ), ZSTR_LEN (str ), 0 , 0 , match_data , php_pcre_mctx ());
4723
4760
php_pcre_free_match_data (match_data );
4724
- pcre2_code_free ( re ) ;
4761
+ centry -> refcount -- ;
4725
4762
4726
4763
if (res == PCRE2_ERROR_NOMATCH ) {
4727
4764
return FAILURE ;
@@ -4902,14 +4939,12 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
4902
4939
}
4903
4940
else {
4904
4941
/* FIXME: better regex must be used */
4905
- #define REGEX0 "^([+-]{0,1}[0-9]+)$"
4906
- if (php_pgsql_convert_match (Z_STR_P (val ), REGEX0 , sizeof (REGEX0 )- 1 , 0 ) == FAILURE ) {
4942
+ if (php_pgsql_convert_match (Z_STR_P (val ), PGG (regexes [0 ])) == FAILURE ) {
4907
4943
err = 1 ;
4908
4944
}
4909
4945
else {
4910
4946
ZVAL_STRINGL (& new_val , Z_STRVAL_P (val ), Z_STRLEN_P (val ));
4911
4947
}
4912
- #undef REGEX0
4913
4948
}
4914
4949
break ;
4915
4950
@@ -4945,11 +4980,9 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
4945
4980
ZVAL_STR (& new_val , ZSTR_KNOWN (ZEND_STR_NULL ));
4946
4981
}
4947
4982
else {
4948
- #define REGEX0 "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$"
4949
- #define REGEX1 "^[+-]{0,1}(inf)(inity){0,1}$"
4950
4983
/* better regex? */
4951
- if (php_pgsql_convert_match (Z_STR_P (val ), REGEX0 , sizeof ( REGEX0 ) - 1 , 0 ) == FAILURE ) {
4952
- if (php_pgsql_convert_match (Z_STR_P (val ), REGEX1 , sizeof ( REGEX1 ) - 1 , 1 ) == FAILURE ) {
4984
+ if (php_pgsql_convert_match (Z_STR_P (val ), PGG ( regexes [ 1 ]) ) == FAILURE ) {
4985
+ if (php_pgsql_convert_match (Z_STR_P (val ), PGG ( regexes [ 2 ]) ) == FAILURE ) {
4953
4986
err = 1 ;
4954
4987
} else {
4955
4988
ZVAL_STR (& new_val , php_pgsql_add_quotes (Z_STR_P (val )));
@@ -4958,8 +4991,6 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
4958
4991
else {
4959
4992
ZVAL_STRING (& new_val , Z_STRVAL_P (val ));
4960
4993
}
4961
- #undef REGEX0
4962
- #undef REGEX1
4963
4994
}
4964
4995
break ;
4965
4996
@@ -5055,7 +5086,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
5055
5086
}
5056
5087
else {
5057
5088
/* better regex? */
5058
- if (php_pgsql_convert_match (Z_STR_P (val ), "^[0-9]+$" , sizeof ( "^[0-9]+$" ) - 1 , 0 ) == FAILURE ) {
5089
+ if (php_pgsql_convert_match (Z_STR_P (val ), PGG ( regexes [ 3 ]) ) == FAILURE ) {
5059
5090
err = 1 ;
5060
5091
}
5061
5092
else {
@@ -5095,20 +5126,16 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
5095
5126
ZVAL_STR (& new_val , ZSTR_KNOWN (ZEND_STR_NULL ));
5096
5127
}
5097
5128
else {
5098
- #define REGEX0 "^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])(\\/[0-9]{1,3})?$"
5099
- #define REGEX1 "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(\\/[0-9]{1,3})?$"
5100
5129
/* The inet type holds an IPv4 or IPv6 host address, and optionally its subnet, all in one field. See more in the doc.
5101
5130
The regex might still be not perfect, but catches the most of IP variants. We might decide to remove the regex
5102
5131
at all though and let the server side to handle it.*/
5103
- if (php_pgsql_convert_match (Z_STR_P (val ), REGEX0 , sizeof ( REGEX0 ) - 1 , 0 ) == FAILURE
5104
- && php_pgsql_convert_match (Z_STR_P (val ), REGEX1 , sizeof ( REGEX1 ) - 1 , 0 ) == FAILURE ) {
5132
+ if (php_pgsql_convert_match (Z_STR_P (val ), PGG ( regexes [ 4 ]) ) == FAILURE
5133
+ && php_pgsql_convert_match (Z_STR_P (val ), PGG ( regexes [ 5 ]) ) == FAILURE ) {
5105
5134
err = 2 ;
5106
5135
}
5107
5136
else {
5108
5137
ZVAL_STR (& new_val , php_pgsql_add_quotes (Z_STR_P (val )));
5109
5138
}
5110
- #undef REGEX0
5111
- #undef REGEX1
5112
5139
}
5113
5140
break ;
5114
5141
@@ -5139,14 +5166,12 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
5139
5166
} else if (zend_string_equals_literal_ci (Z_STR_P (val ), "now()" )) {
5140
5167
ZVAL_STRINGL (& new_val , "NOW()" , sizeof ("NOW()" )- 1 );
5141
5168
} else {
5142
- #define REGEX0 "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})(([ \\t]+|T)(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1}(\\.[0-9]+){0,1}([ \\t]*([+-][0-9]{1,4}(:[0-9]{1,2}){0,1}|[-a-zA-Z_/+]{1,50})){0,1})){0,1}$"
5143
5169
/* better regex? */
5144
- if (php_pgsql_convert_match (Z_STR_P (val ), REGEX0 , sizeof ( REGEX0 ) - 1 , 1 ) == FAILURE ) {
5170
+ if (php_pgsql_convert_match (Z_STR_P (val ), PGG ( regexes [ 6 ]) ) == FAILURE ) {
5145
5171
err = 1 ;
5146
5172
} else {
5147
5173
ZVAL_STR (& new_val , php_pgsql_add_quotes (Z_STR_P (val )));
5148
5174
}
5149
- #undef REGEX0
5150
5175
}
5151
5176
break ;
5152
5177
@@ -5170,15 +5195,13 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
5170
5195
ZVAL_STR (& new_val , ZSTR_KNOWN (ZEND_STR_NULL ));
5171
5196
}
5172
5197
else {
5173
- #define REGEX0 "^([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})$"
5174
5198
/* FIXME: better regex must be used */
5175
- if (php_pgsql_convert_match (Z_STR_P (val ), REGEX0 , sizeof ( REGEX0 ) - 1 , 1 ) == FAILURE ) {
5199
+ if (php_pgsql_convert_match (Z_STR_P (val ), PGG ( regexes [ 7 ]) ) == FAILURE ) {
5176
5200
err = 1 ;
5177
5201
}
5178
5202
else {
5179
5203
ZVAL_STR (& new_val , php_pgsql_add_quotes (Z_STR_P (val )));
5180
5204
}
5181
- #undef REGEX0
5182
5205
}
5183
5206
break ;
5184
5207
@@ -5202,15 +5225,13 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
5202
5225
ZVAL_STR (& new_val , ZSTR_KNOWN (ZEND_STR_NULL ));
5203
5226
}
5204
5227
else {
5205
- #define REGEX0 "^(([0-9]{1,2}:[0-9]{1,2}){1}(:[0-9]{1,2}){0,1}){0,1}$"
5206
5228
/* FIXME: better regex must be used */
5207
- if (php_pgsql_convert_match (Z_STR_P (val ), REGEX0 , sizeof ( REGEX0 ) - 1 , 1 ) == FAILURE ) {
5229
+ if (php_pgsql_convert_match (Z_STR_P (val ), PGG ( regexes [ 8 ]) ) == FAILURE ) {
5208
5230
err = 1 ;
5209
5231
}
5210
5232
else {
5211
5233
ZVAL_STR (& new_val , php_pgsql_add_quotes (Z_STR_P (val )));
5212
5234
}
5213
- #undef REGEX0
5214
5235
}
5215
5236
break ;
5216
5237
@@ -5251,44 +5272,13 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
5251
5272
unit markings. For example, '1 12:59:10' is read the same as '1 day 12 hours 59 min 10
5252
5273
sec'.
5253
5274
*/
5254
- #define REGEX0 \
5255
- "^(@?[ \\t]+)?(" \
5256
- /* Textual time units and their abbreviations: */ \
5257
- "(([-+]?[ \\t]+)?" \
5258
- "[0-9]+(\\.[0-9]*)?[ \\t]*" \
5259
- "(millenniums|millennia|millennium|mil|mils|" \
5260
- "centuries|century|cent|c|" \
5261
- "decades|decade|dec|decs|" \
5262
- "years|year|y|" \
5263
- "months|month|mon|" \
5264
- "weeks|week|w|" \
5265
- "days|day|d|" \
5266
- "hours|hour|hr|hrs|h|" \
5267
- "minutes|minute|mins|min|m|" \
5268
- "seconds|second|secs|sec|s))+|" \
5269
- /* Textual time units plus (dd)* hh[:mm[:ss]] */ \
5270
- "((([-+]?[ \\t]+)?" \
5271
- "[0-9]+(\\.[0-9]*)?[ \\t]*" \
5272
- "(millenniums|millennia|millennium|mil|mils|" \
5273
- "centuries|century|cent|c|" \
5274
- "decades|decade|dec|decs|" \
5275
- "years|year|y|" \
5276
- "months|month|mon|" \
5277
- "weeks|week|w|" \
5278
- "days|day|d))+" \
5279
- "([-+]?[ \\t]+" \
5280
- "([0-9]+[ \\t]+)+" /* dd */ \
5281
- "(([0-9]{1,2}:){0,2}[0-9]{0,2})" /* hh:[mm:[ss]] */ \
5282
- ")?))" \
5283
- "([ \\t]+ago)?$"
5284
-
5285
- if (php_pgsql_convert_match (Z_STR_P (val ), REGEX0 , sizeof (REGEX0 )- 1 , 1 ) == FAILURE ) {
5275
+
5276
+ if (php_pgsql_convert_match (Z_STR_P (val ), PGG (regexes [9 ])) == FAILURE ) {
5286
5277
err = 1 ;
5287
5278
}
5288
5279
else {
5289
5280
ZVAL_STR (& new_val , php_pgsql_add_quotes (Z_STR_P (val )));
5290
5281
}
5291
- #undef REGEX0
5292
5282
}
5293
5283
break ;
5294
5284
@@ -5353,14 +5343,12 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
5353
5343
ZVAL_STR (& new_val , ZSTR_KNOWN (ZEND_STR_NULL ));
5354
5344
}
5355
5345
else {
5356
- #define REGEX0 "^([0-9a-f]{2,2}:){5,5}[0-9a-f]{2,2}$"
5357
- if (php_pgsql_convert_match (Z_STR_P (val ), REGEX0 , sizeof (REGEX0 )- 1 , 1 ) == FAILURE ) {
5346
+ if (php_pgsql_convert_match (Z_STR_P (val ), PGG (regexes [10 ])) == FAILURE ) {
5358
5347
err = 1 ;
5359
5348
}
5360
5349
else {
5361
5350
ZVAL_STR (& new_val , php_pgsql_add_quotes (Z_STR_P (val )));
5362
5351
}
5363
- #undef REGEX0
5364
5352
}
5365
5353
break ;
5366
5354
0 commit comments