columns as $col) { $value = property_exists($row, $col) ? $row->$col : null; if ($value === null) { $out[] = 'NULL'; continue; } if (isset($s->ints[$col])) { $out[] = is_numeric($value) ? (string) $value : "'" . self::escape((string) $value) . "'"; continue; } if (isset($s->bins[$col])) { $hex = strtolower($col) . '__hex'; $out[] = "UNHEX('" . preg_replace('/[^0-9A-Fa-f]/', '', (string) ($row->$hex ?? '')) . "')"; continue; } if (isset($s->bits[$col])) { $bit = strtolower($col) . '__bit'; $out[] = "b'" . decbin((int) ($row->$bit ?? 0)) . "'"; continue; } if (isset($s->points[$col])) { $p = strlen((string) $value) >= 25 ? unpack('x4/corder/Ltype/dlon/dlat', (string) $value) : false; $out[] = is_array($p) && isset($p['lon'], $p['lat']) ? "ST_GeomFromText('POINT(" . self::num($p['lon']) . ' ' . self::num($p['lat']) . ")')" : 'NULL'; continue; } $value = (string) $value; if ($transform !== null) { $value = $transform($col, $value); } $out[] = "'" . self::escape($value) . "'"; } return '(' . implode(',', $out) . ')'; } /** Backslash-escape for MySQL string literals; never leaves a raw newline, CR, NUL or ^Z. */ public static function escape(string $value): string { $value = str_replace('\\', '\\\\', $value); $value = str_replace("'", "\\'", $value); return str_replace(["\x00", "\x0a", "\x0d", "\x1a"], ['\\0', '\\n', '\\r', '\\Z'], $value); } public static function columns(TableSchema $s): string { return '(' . implode(',', array_map([Db::class, 'ident'], $s->columns)) . ')'; } /** Shortest-safe decimal that converts back to the exact same double. */ private static function num(float $f): string { return sprintf('%.17G', $f); } }