JavaScript Python PHP
import * as __biblioteca0 from "yaml";
function executar(input = '[{"codigo":"00123"}]', table = 'dados', schema = '') {
const parseDocument = __biblioteca0["parseDocument"];
const visit = __biblioteca0["visit"];
const isScalar = __biblioteca0["isScalar"];
const { parseJsonCompatible: parseJsonCompatible } = (() => {
const LineCounter = __biblioteca0["LineCounter"];
const parseDocument = __biblioteca0["parseDocument"];
const isAlias = __biblioteca0["isAlias"];
const isScalar = __biblioteca0["isScalar"];
const isSeq = __biblioteca0["isSeq"];
const isMap = __biblioteca0["isMap"];
const SAFE_TAGS = new Set(['str', 'bool', 'null', 'int', 'float', 'map', 'seq'].map(tag => `tag:yaml.org,2002:${tag}`));
function parseJsonCompatible(input, format, onObjectKeys) {
if (!input.trim())
throw new Error(`Informe um documento ${format}.`);
if (input.length > 1000000)
throw new Error('A entrada excede o limite de 1 milhão de caracteres.');
if (format === 'JSON') {
// Syntax check only: do not use the rounded numeric values from JSON.parse.
try {
JSON.parse(input);
}
catch (cause) {
throw new Error(`JSON inválido: ${cause instanceof Error ? cause.message : 'erro de sintaxe'}`);
}
}
const lines = new LineCounter();
const doc = parseDocument(input, { version: '1.2', schema: format === 'JSON' ? 'json' : 'core', intAsBigInt: true, uniqueKeys: true, lineCounter: lines, prettyErrors: true, resolveKnownTags: false });
const issue = doc.errors[0] ?? doc.warnings[0];
if (issue)
throw new Error(`${format} inválido (${issue.code}): ${issue.message}`);
if (doc.directives?.yaml.version !== '1.2')
throw new Error('Somente YAML 1.2 é aceito para preservar os tipos de JSON.');
let count = 0;
function fail(message, node) {
const offset = node?.range?.[0];
const position = offset === undefined ? '' : (() => { const { line, col } = lines.linePos(offset); return ` (linha ${line}, coluna ${col})`; })();
throw new Error(message + position);
}
function convert(node, depth = 0) {
if (++count > 100000 || depth > 100)
fail('Documento muito complexo: limite de 100 níveis ou 100 mil nós.', node);
if (!node)
return null;
if (isAlias(node))
fail('Aliases YAML não são aceitos: JSON não preserva referências ou ciclos.', node);
if (node.tag && !SAFE_TAGS.has(node.tag))
fail(`Tag não permitida: ${node.tag}.`, node);
if (isScalar(node)) {
const value = node.value;
if (typeof value === 'bigint') {
if (value === BigInt(0) && node.source?.startsWith('-'))
fail('JSON de saída não preserva o sinal de zero negativo. Use 0 ou uma string.', node);
if (value > BigInt(Number.MAX_SAFE_INTEGER) || value < BigInt(Number.MIN_SAFE_INTEGER))
fail('Inteiro fora do intervalo seguro de JSON/JavaScript. Use uma string entre aspas para preservar todos os dígitos.', node);
return Number(value);
}
if (typeof value === 'number') {
if (!Number.isFinite(value))
fail('JSON não representa NaN ou infinito.', node);
if (Number.isInteger(value) && !Number.isSafeInteger(value))
fail('Número inteiro fora do intervalo seguro. Use uma string entre aspas para preservar a precisão.', node);
if (value === 0 && /[1-9]/.test((node.source ?? '').split(/[eE]/)[0]))
fail('Número pequeno demais para a precisão de JavaScript. Use uma string entre aspas.', node);
if (Object.is(value, -0))
fail('JSON de saída não preserva o sinal de zero negativo. Use 0 ou uma string.', node);
return value;
}
if (value === null || typeof value === 'string' || typeof value === 'boolean')
return value;
fail('Valor não representável em JSON.', node);
}
if (isSeq(node))
return node.items.map(item => convert(item, depth + 1));
if (isMap(node)) {
const result = Object.create(null);
const keys = [];
for (const pair of node.items) {
if (!isScalar(pair.key) || typeof pair.key.value !== 'string')
fail('Chaves de objetos devem ser strings; chaves numéricas, booleanas ou complexas não são preservadas em JSON.', pair.key);
const key = pair.key.value;
if (format === 'YAML' && key === '<<' && pair.key.type === 'PLAIN')
fail('Chaves de merge YAML (<<) não são aceitas.', pair.key);
if (Object.hasOwn(result, key))
fail(`Chave duplicada: ${key}.`, pair.key);
keys.push(key);
result[key] = convert(pair.value, depth + 1);
}
onObjectKeys?.(result, keys);
return result;
}
fail('Estrutura não representável em JSON.', node);
}
if (!doc.contents)
throw new Error('Informe um documento com um valor; use null para um valor nulo.');
return convert(doc.contents);
}
return { parseJsonCompatible: parseJsonCompatible };
})();
function textCheck(value) {
if (value.includes('\0') || /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/.test(value))
throw new Error('NUL e surrogates isolados não são suportados pelo subconjunto PostgreSQL UTF-8.');
}
function identifier(value) {
textCheck(value);
if (!value || new TextEncoder().encode(value).length > 63)
throw new Error('Identificador deve ter de 1 a 63 bytes UTF-8, sem truncamento.');
return '"' + value.replace(/"/g, '""') + '"';
}
function configIdentifier(value) {
if (/[;\r\n]|--|\/\*|\*\//.test(value))
throw new Error('Tabela/schema devem ser nomes isolados, não fragmentos SQL.');
return identifier(value);
}
function decimalKey(raw) {
const match = raw.match(/^([+-]?)(\d+)(?:\.(\d*))?(?:[eE]([+-]?\d+))?$/);
if (!match)
throw new Error('Formato numérico não suportado; use dígitos antes do ponto e valores seguros ou strings.');
let digits = (match[2] + (match[3] ?? '')).replace(/^0+/, '');
let power = Number(match[4] ?? 0) - (match[3]?.length ?? 0);
if (!digits)
return match[1] === '-' ? '-0' : '0';
while (digits.endsWith('0')) {
digits = digits.slice(0, -1);
power++;
}
return `${match[1] === '-' ? '-' : ''}${digits}e${power}`;
}
function safeNumber(raw) {
const value = Number(raw);
if (!Number.isFinite(value) || Object.is(value, -0) || (Number.isInteger(value) && !Number.isSafeInteger(value)) || decimalKey(raw) !== decimalKey(String(value)))
throw new Error('Número não preservável como JSON/JavaScript: inteiro inseguro, precisão decimal excessiva, underflow, infinito ou zero negativo. Use uma string para preservar os dígitos.');
return value;
}
function literal(value) {
if (value === null)
return 'NULL';
if (typeof value === 'boolean')
return value ? 'TRUE' : 'FALSE';
if (typeof value === 'number') {
const text = String(value);
if (!/[eE]/.test(text))
return text;
const [coefficient, exponent] = text.split('e');
const negative = coefficient.startsWith('-');
const parts = coefficient.replace('-', '').split('.');
const digits = parts.join('');
const point = parts[0].length + Number(exponent);
return (negative ? '-' : '') + (point <= 0 ? '0.' + '0'.repeat(-point) + digits : point >= digits.length ? digits + '0'.repeat(point - digits.length) : digits.slice(0, point) + '.' + digits.slice(point));
}
if (typeof value !== 'string')
throw new Error('Objetos e listas aninhados não são suportados.');
textCheck(value);
return "'" + value.replace(/'/g, "''") + "'";
}
function jsonToSql(input, table, schema = '') {
if (input.length > 100000)
throw new Error('Limite de entrada: 100 mil caracteres.');
const doc = parseDocument(input, { schema: 'json', intAsBigInt: true });
visit(doc, (_, node) => {
if (isScalar(node) && (typeof node.value === 'number' || typeof node.value === 'bigint'))
safeNumber(node.source ?? '');
});
const order = new WeakMap();
const data = parseJsonCompatible(input, 'JSON', (object, keys) => order.set(object, keys));
if (!Array.isArray(data) || !data.length || data.length > 1000 || data.some(row => !row || typeof row !== 'object' || Array.isArray(row)))
throw new Error('Use uma lista não vazia de até 1.000 objetos simples.');
const columns = [...new Set(data.flatMap(row => order.get(row) ?? []))];
if (!columns.length || columns.length > 100)
throw new Error('Use de 1 a 100 colunas.');
const target = (schema ? configIdentifier(schema) + '.' : '') + configIdentifier(table);
const rows = data.map(row => '(' + columns.map(key => literal(Object.hasOwn(row, key) ? row[key] : null)).join(', ') + ')');
return `INSERT INTO ${target} (${columns.map(identifier).join(', ')}) VALUES\n${rows.join(',\n')};`;
}
return jsonToSql(input, table, schema);
}
import json
import math
import re
from decimal import Decimal
def executar(input='[{"codigo":"00123"}]', table="dados", schema=""):
def read(text):
if not text.strip() or len(text.encode("utf-16-le", errors="surrogatepass")) // 2 > 1000000:
raise ValueError("Informe JSON com até 1 milhão de caracteres.")
def pairs(items):
result = {}
for key, value in items:
if key in result: raise ValueError("Chave duplicada: " + key)
result[key] = value
return result
def number(token):
value = float(token) if "." in token or "e" in token.lower() else int(token)
if not math.isfinite(value) or (value == 0 and (token.startswith("-") or any(c in "123456789" for c in token.lower().split("e")[0]))) or (value % 1 == 0 and abs(value) > 9007199254740991):
raise ValueError("Número não preservável; use uma string para preservar os dígitos.")
return value
def reject(token): raise ValueError("Constante JSON inválida: " + token)
value = json.loads(text, object_pairs_hook=pairs, parse_int=number, parse_float=number, parse_constant=reject)
count = 0
def walk(item, depth=0):
nonlocal count
count += 1
if count > 100000 or depth > 100: raise ValueError("Limite de 100 níveis ou 100 mil nós.")
if isinstance(item, dict):
for child in item.values(): walk(child, depth + 1)
elif isinstance(item, list):
for child in item: walk(child, depth + 1)
walk(value)
return value
def scalar(value):
if value is None: return "null"
if value is True: return "true"
if value is False: return "false"
if isinstance(value, float):
if value == int(value): return str(int(value))
text = repr(value)
if "e" in text:
coefficient, power = text.split("e")
exponent = int(power)
if -6 <= exponent < 21:
negative = coefficient.startswith("-")
coefficient = coefficient.lstrip("-")
digits = coefficient.replace(".", "")
point = coefficient.find(".") if "." in coefficient else len(coefficient)
point += exponent
return ("-" if negative else "") + ("0." + "0" * -point + digits if point <= 0 else digits + "0" * (point - len(digits)) if point >= len(digits) else digits[:point] + "." + digits[point:])
return coefficient + "e" + ("+" if exponent >= 0 else "-") + str(abs(exponent))
return text
return str(value)
def text_check(value):
if "\0" in value or any(0xD800 <= ord(c) <= 0xDFFF for c in value):
raise ValueError("NUL e surrogates isolados não são suportados em PostgreSQL UTF-8.")
def identifier(value, config=False):
text_check(value)
if not value or len(value.encode("utf-8")) > 63: raise ValueError("Identificador deve ter de 1 a 63 bytes UTF-8.")
if config and any(item in value for item in (";","\r","\n","--","/*","*/")): raise ValueError("Tabela/schema devem ser nomes isolados, não fragmentos SQL.")
return '"' + value.replace('"','""') + '"'
def safe_number(raw, sql=False):
if sql and not re.fullmatch(r"[+-]?[0-9]+(?:\.[0-9]+)?",raw): raise ValueError("Números SQL devem ser literais sem expoentes.")
decimal = Decimal(raw)
value = float(raw)
if not math.isfinite(value) or (value == 0 and (decimal.is_signed() or decimal != 0)) or (value.is_integer() and abs(value)>9007199254740991) or Decimal(str(value)) != decimal:
raise ValueError("Número não preservável como JSON/JavaScript; use uma string.")
return int(value) if value.is_integer() else value
if len(input.encode("utf-16-le",errors="surrogatepass"))//2>100000: raise ValueError("Limite de 100 mil caracteres.")
# Validate original number tokens before the JSON parser can round them.
json.loads(input,parse_int=safe_number,parse_float=safe_number)
data=read(input)
if not isinstance(data,list) or not 1<=len(data)<=1000 or any(not isinstance(row,dict) for row in data): raise ValueError("Use uma lista não vazia de até 1.000 objetos simples.")
columns=list(dict.fromkeys(key for row in data for key in row))
if not 1<=len(columns)<=100: raise ValueError("Use de 1 a 100 colunas.")
target=(identifier(schema,True)+"." if schema else "")+identifier(table,True)
def literal(value):
if value is None: return "NULL"
if value is True: return "TRUE"
if value is False: return "FALSE"
if isinstance(value,(int,float)): return format(Decimal(scalar(value)),"f")
if not isinstance(value,str): raise ValueError("Objetos e listas aninhados não são suportados.")
text_check(value)
return "'" + value.replace("'","''") + "'"
rows=["("+", ".join(literal(row.get(key)) for key in columns)+")" for row in data]
return "INSERT INTO "+target+" ("+", ".join(identifier(key) for key in columns)+") VALUES\n"+",\n".join(rows)+";"
<?php
use Brick\Math\BigDecimal;
require_once 'vendor/autoload.php';
function executar($input = '[{"codigo":"00123"}]', $table = 'dados', $schema = '') {
$read = function ($text) {
if (trim($text) === '' || !mb_check_encoding($text, 'UTF-8') || strlen(mb_convert_encoding($text, 'UTF-16LE', 'UTF-8')) / 2 > 1000000) throw new InvalidArgumentException('Informe JSON válido com até 1 milhão de caracteres.');
json_decode($text, false, 512, JSON_THROW_ON_ERROR | JSON_BIGINT_AS_STRING);
$stack = [];
for ($i = 0; $i < strlen($text); $i++) {
$ch = $text[$i];
if ($ch === '{' || $ch === '[') { $stack[] = ['keys'=>[]]; if (count($stack) > 101) throw new InvalidArgumentException('Limite de profundidade.'); }
elseif ($ch === '}' || $ch === ']') array_pop($stack);
elseif ($ch === '"') {
$start = $i;
while (++$i < strlen($text)) { if ($text[$i] === '\\') $i++; elseif ($text[$i] === '"') break; }
$look = $i + 1;
while ($look < strlen($text) && str_contains(" \r\n\t", $text[$look])) $look++;
if (($text[$look] ?? '') === ':') {
$key = json_decode(substr($text, $start, $i - $start + 1), false, 512, JSON_THROW_ON_ERROR);
$index = count($stack) - 1;
if (array_key_exists($key, $stack[$index]['keys'])) throw new InvalidArgumentException('Chave duplicada: '.$key);
$stack[$index]['keys'][$key] = true;
}
} elseif ($ch === '-' || ctype_digit($ch)) {
preg_match('/\G-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/', $text, $match, 0, $i);
$token = $match[0]; $value = (float)$token;
if (!is_finite($value) || ($value == 0 && (str_starts_with($token, '-') || preg_match('/[1-9]/', explode('e', strtolower($token))[0]))) || (floor($value) === $value && abs($value) > 9007199254740991)) throw new InvalidArgumentException('Número não preservável; use uma string.');
$i += strlen($token) - 1;
}
}
$value = json_decode($text, false, 512, JSON_THROW_ON_ERROR);
$count = 0;
$walk = function ($node, $depth = 0) use (&$walk, &$count) {
if (++$count > 100000 || $depth > 100) throw new InvalidArgumentException('Limite de 100 níveis ou 100 mil nós.');
if (is_object($node) || is_array($node)) foreach ($node as $child) $walk($child, $depth + 1);
};
$walk($value);
return $value;
};
$dump = fn($value) => preg_replace_callback('/^( +)/m', fn($match) => str_repeat(' ', strlen($match[1]) / 2), json_encode($value, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR));
$scalar = fn($value) => is_string($value) ? $value : json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
$textCheck = function ($value) {
if (str_contains($value,"\0") || !mb_check_encoding($value,'UTF-8')) throw new InvalidArgumentException('NUL e UTF-8 inválido não são suportados.');
};
$identifier = function ($value,$config = false) use ($textCheck) {
$textCheck($value);
if ($value==='' || strlen($value)>63) throw new InvalidArgumentException('Identificador deve ter de 1 a 63 bytes UTF-8.');
if ($config && preg_match('/[;\r\n]|--|\/\*|\*\//',$value)) throw new InvalidArgumentException('Tabela/schema devem ser nomes isolados.');
return '"'.str_replace('"','""',$value).'"';
};
$safeNumber = function ($raw,$sql = false) {
if ($sql && !preg_match('/^[+-]?[0-9]+(?:\.[0-9]+)?$/D',$raw)) throw new InvalidArgumentException('Números SQL devem ser literais sem expoentes.');
$value=(float)$raw; $exact=BigDecimal::of(ltrim($raw,'+'));
if (!is_finite($value) || ($value==0 && (str_starts_with($raw,'-') || !$exact->isZero())) || (floor($value)===$value && abs($value)>9007199254740991) || $exact->compareTo(BigDecimal::of(json_encode($value,JSON_THROW_ON_ERROR)))!==0) throw new InvalidArgumentException('Número não preservável; use uma string.');
return floor($value)===$value ? (int)$value : $value;
};
if (strlen(mb_convert_encoding($input,'UTF-16LE','UTF-8'))/2>100000) throw new InvalidArgumentException('Limite de 100 mil caracteres.');
$data=$read($input);
// Revisit raw numeric tokens, skipping quoted strings.
preg_match_all('/"(?:[^"\\\\]|\\\\.)*"|-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/s',$input,$tokens);
foreach ($tokens[0] as $raw) if ($raw[0]!=='"') $safeNumber($raw);
if (!is_array($data) || count($data)<1 || count($data)>1000) throw new InvalidArgumentException('Use de 1 a 1.000 objetos simples.');
$columns=[];
foreach ($data as $row) {
if (!$row instanceof stdClass) throw new InvalidArgumentException('Registros devem ser objetos simples.');
foreach ($row as $key=>$value) if (!in_array((string)$key,$columns,true)) $columns[]=(string)$key;
}
if (!$columns || count($columns)>100) throw new InvalidArgumentException('Use de 1 a 100 colunas.');
$target=($schema!=='' ? $identifier($schema,true).'.' : '').$identifier($table,true);
$literal=function ($value) use ($textCheck) {
if ($value===null) return 'NULL';
if (is_bool($value)) return $value ? 'TRUE' : 'FALSE';
if (is_int($value) || is_float($value)) return (string)BigDecimal::of(json_encode($value,JSON_THROW_ON_ERROR));
if (!is_string($value)) throw new InvalidArgumentException('Objetos/listas aninhados não são suportados.');
$textCheck($value);
return "'".str_replace("'","''",$value)."'";
};
$rows=[];
foreach ($data as $row) $rows[]='('.implode(', ',array_map(fn($key)=>$literal($row->{$key} ?? null),$columns)).')';
return 'INSERT INTO '.$target.' ('.implode(', ',array_map($identifier,$columns)).") VALUES\n".implode(",\n",$rows).';';
}