| @@ -64,8 +64,67 @@ | ||
| 64 | 64 | return implode( ',', $values ); |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | 67 | /** |
| 68 | + * Split a list of values into chunks whose rendered `IN ()` comma separated list | |
| 69 | + * stays under a character budget. This prevents hosts (e.g. WP Engine) that kill | |
| 70 | + * overly long SQL queries from failing on unbounded `IN ()` lists. | |
| 71 | + * | |
| 72 | + * @since 2.4 | |
| 73 | + * | |
| 74 | + * @param array $values An array of values (integers or strings). | |
| 75 | + * @param int $sql_budget Maximum character length (rendered, comma separated) allowed per chunk. | |
| 76 | + * @return array An array of chunks. Each chunk is an array of values (same type as input). | |
| 77 | + */ | |
| 78 | + public static function chunk_in_values( array $values, int $sql_budget = 8000 ): array { | |
| 79 | + if ( ! $values ) { | |
| 80 | + return []; | |
| 81 | + } | |
| 82 | + | |
| 83 | + /** | |
| 84 | + * Filter the SQL character budget used to chunk `IN ()` value lists. | |
| 85 | + * | |
| 86 | + * @since 2.4 | |
| 87 | + * | |
| 88 | + * @param int $sql_budget The character budget. | |
| 89 | + */ | |
| 90 | + $given_sql_budget = $sql_budget; | |
| 91 | + $sql_budget = (int) apply_filters( 'imagify_db_in_clause_sql_budget', $sql_budget ); | |
| 92 | + | |
| 93 | + if ( $sql_budget < 1 ) { | |
| 94 | + // Fall back to the caller's own value if it was valid, otherwise the hardcoded default. | |
| 95 | + $sql_budget = ( $given_sql_budget >= 1 ) ? $given_sql_budget : 8000; | |
| 96 | + } | |
| 97 | + | |
| 98 | + $chunks = []; | |
| 99 | + $current_chunk = []; | |
| 100 | + $current_len = 0; | |
| 101 | + | |
| 102 | + foreach ( array_values( $values ) as $value ) { | |
| 103 | + $rendered_len = strlen( self::quote_string( esc_sql( $value ) ) ); | |
| 104 | + // +1 for the comma separator, except for the first value in a chunk. | |
| 105 | + $added_len = $current_chunk ? $rendered_len + 1 : $rendered_len; | |
| 106 | + | |
| 107 | + if ( $current_chunk && ( $current_len + $added_len ) > $sql_budget ) { | |
| 108 | + // Start a new chunk. | |
| 109 | + $chunks[] = $current_chunk; | |
| 110 | + $current_chunk = []; | |
| 111 | + $current_len = 0; | |
| 112 | + $added_len = $rendered_len; | |
| 113 | + } | |
| 114 | + | |
| 115 | + $current_chunk[] = $value; | |
| 116 | + $current_len += $added_len; | |
| 117 | + } | |
| 118 | + | |
| 119 | + if ( $current_chunk ) { | |
| 120 | + $chunks[] = $current_chunk; | |
| 121 | + } | |
| 122 | + | |
| 123 | + return $chunks; | |
| 124 | + } | |
| 125 | + | |
| 126 | + /** | |
| 68 | 127 | * Wrap a value in quotes, unless it's an integer. |
| 69 | 128 | * |
| 70 | 129 | * @since 1.6.13 |
| 71 | 130 | * @access public |