public function sql(ValueBinder $generator)
    {
        if (empty($this->_values) && empty($this->_query)) {
            return '';
        }

        if (!$this->_castedExpressions) {
            $this->_processExpressions();
        }

        $columns = $this->_columnNames();
        $defaults = array_fill_keys($columns, null);
        $placeholders = [];

        $types = [];
        $typeMap = $this->getTypeMap();
        foreach ($defaults as $col => $v) {
            $types[$col] = $typeMap->type($col);
        }

        foreach ($this->_values as $row) {
            $row += $defaults;
            $rowPlaceholders = [];

            foreach ($columns as $column) {
                $value = $row[$column];

                if ($value instanceof ExpressionInterface) {
                    $rowPlaceholders[] = '(' . $value->sql($generator) . ')';
                    continue;
                }

                $placeholder = $generator->placeholder('c');
                $rowPlaceholders[] = $placeholder;
                $generator->bind($placeholder, $value, $types[$column]);
            }

            $placeholders[] = implode(', ', $rowPlaceholders);
        }

        if ($this->getQuery()) {
            return ' ' . $this->getQuery()->sql($generator);
        }

        return sprintf(' VALUES (%s)', implode('), (', $placeholders));
    }