db = $db; $this->cap = max( 1024, (int) $cap ); } /** * SQL literal for a value. * * @param string|null $value Raw value from mysqli (strings or null). * @param array $column Column info (binary, numeric). */ public function literal( $value, array $column ) { if ( null === $value ) { return 'NULL'; } $value = (string) $value; if ( ! empty( $column['binary'] ) ) { return '' === $value ? "''" : '0x' . bin2hex( $value ); } if ( ! empty( $column['numeric'] ) && preg_match( '/^-?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/', $value ) ) { // "-0" as a bare literal is integer zero; the float form keeps negative zero. return ( '-0' === $value && ! empty( $column['float'] ) ) ? '-0e0' : $value; } return Connection::literal( $value ); } /** * One row as a tuple "(a,b,c)". * * @param array $row Values in column order. * @param array $columns Column info in the same order. */ public function tuple( array $row, array $columns ) { $parts = array(); foreach ( $columns as $i => $column ) { $parts[] = $this->literal( $row[ $i ], $column ); } return '(' . implode( ',', $parts ) . ')'; } /** * Groups tuples into INSERT statements no larger than the cap (a single oversized row * gets a statement of its own). * * @param string $table Table name. * @param array $columns Column info. * @param string[] $tuples Tuples. * @return string Statements, one per line. */ public function inserts( $table, array $columns, array $tuples ) { if ( ! $tuples ) { return ''; } $names = array(); foreach ( $columns as $column ) { $names[] = Connection::ident( $column['name'] ); } $head = 'INSERT INTO ' . Connection::ident( $table ) . ' (' . implode( ',', $names ) . ') VALUES '; $out = ''; $batch = array(); $size = strlen( $head ); foreach ( $tuples as $tuple ) { $len = strlen( $tuple ) + 1; if ( $batch && $size + $len > $this->cap ) { $out .= $head . implode( ',', $batch ) . ";\n"; $batch = array(); $size = strlen( $head ); } $batch[] = $tuple; $size += $len; } $out .= $head . implode( ',', $batch ) . ";\n"; return $out; } }