Compare commits

..

9 Commits

Author SHA1 Message Date
root
900dbe3b6c new version 2025-06-08 11:54:19 +01:00
FredericoFalcao
28f6467bb7
Merge pull request #5 from FredericoFalcao/experimental
Experimental
2025-06-07 17:09:47 +03:00
FredericoFalcao
56a17dfb84
Update handleTriggerExecutionResult.inc.php 2025-06-07 16:52:20 +03:00
FredericoFalcao
ac7f2e9f08
Update index.php 2025-06-07 15:12:23 +03:00
FredericoFalcao
69575693d4
Merge pull request #4 from FredericoFalcao/codex/suggest-project-improvements
Add initialization script for PyPi table
2025-06-07 15:10:57 +03:00
FredericoFalcao
18812a2b17
Merge pull request #3 from FredericoFalcao/quju18-codex/suggest-project-improvements
Add SQL hydration and Python trigger utilities
2025-06-07 15:06:23 +03:00
FredericoFalcao
d3b267ab02 Add sql_read_and_hydrate utility 2025-06-07 15:05:11 +03:00
FredericoFalcao
f7008d3d0f
Handle better PHP Trigger Code 2025-06-07 15:02:10 +03:00
FredericoFalcao
659e10d5c2 Add initialization script for PyPi table 2025-06-07 14:24:48 +03:00
10 changed files with 132 additions and 7 deletions

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
vendor/ vendor/
composer.json
composer.lock composer.lock
composer.sync composer.sync
@ -8,3 +9,5 @@ composer.sync
test_code.php test_code.php
modules/ modules/
requirements.txt

View File

@ -3,7 +3,9 @@ cd "$(dirname ${BASH_SOURCE[0]})"
while [[ 1 ]] while [[ 1 ]]
do do
killall DbContinuousIntegrationWrapper.sh killall DbContinuousIntegrationWrapper.sh
/usr/bin/php DbContinuousIntegration.php /usr/bin/php composer.json.php > composer.json
touch -t $(/usr/bin/mysql -se "SELECT DATE_FORMAT(LastUpdated, '%Y%m%d%H%i.%s') FROM SYS_PRD_BND.Composer ORDER BY LastUpdated DESC LIMIT 1") composer.json
make make
/usr/bin/php DbContinuousIntegration.php
sleep 10 sleep 10
done done

View File

@ -1,8 +1,10 @@
#!/bin/bash #!/bin/bash
composer.sync: composer.json composer.sync: composer.json
COMPOSER_ALLOW_SUPERUSER=1 composer update 2>&1 > $@ COMPOSER_ALLOW_SUPERUSER=1 composer update > $@ 2>&1
requirements.sync: requirements.txt
pip install -r requirements.txt $@
install: install:
echo "Add this line to crontab -e" echo "Add this line to crontab -e"
echo '@reboot /bin/bash /root/DbContinuousIntegration/DbContinuousIntegrationWrapper.sh 2> /dev/null > /dev/null &' echo '@reboot /bin/bash /root/DbContinuousIntegration/DbContinuousIntegrationWrapper.sh 2> /dev/null > /dev/null &'

View File

@ -1,5 +1,6 @@
{ {
"require": { "require": {
"denpa\/php-bitcoinrpc": "^2.2" "psr/log": "*",
"symfony/console": "*"
} }
} }

44
composer.json.php Normal file
View File

@ -0,0 +1,44 @@
<?php
// Setup PDO
$dsn = "mysql:unix_socket=/var/run/mysqld/mysqld.sock;dbname=SYS_PRD_BND;charset=utf8mb4";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
];
try {
$pdo = new PDO($dsn, "root", "", $options);
// Fetch dependencies
$stmt = $pdo->query("SELECT VendorName, PackageName, VersionOrBranch FROM Composer ORDER BY VendorName, PackageName");
$require = [];
foreach ($stmt as $row) {
$require["{$row['VendorName']}/{$row['PackageName']}"] = $row['VersionOrBranch'];
}
// Fetch repositories
$stmt = $pdo->query("SELECT RepositoryType, RepositoryUrl FROM Composer WHERE RepositoryUrl IS NOT NULL ORDER BY VendorName, PackageName");
$repositories = [];
foreach ($stmt as $row) {
$repositories[] = [
'type' => $row['RepositoryType'],
'url' => $row['RepositoryUrl'],
];
}
// Build composer.json content
$composerJson = [
'require' => $require,
];
if (!empty($repositories)) {
$composerJson['repositories'] = $repositories;
}
// Write to file
file_put_contents('php://stdout', json_encode($composerJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
file_put_contents("php://stderr", "✅ composer.json generated successfully.\n");
} catch (PDOException $e) {
file_put_contents("php://stderr","❌ Database error: " . $e->getMessage() . "\n");
}

View File

@ -9,6 +9,9 @@
* @return string The complete PHP code ready for sandbox execution. * @return string The complete PHP code ready for sandbox execution.
*/ */
function generatePHPTriggerCode($functionName, $onUpdate_phpCode, $row) { function generatePHPTriggerCode($functionName, $onUpdate_phpCode, $row) {
// Fix code if redundant opening PHP tag
if (substr($onUpdate_phpCode,0,5) == "<"."?"."php") $onUpdate_phpCode = substr($onUpdate_phpCode,5);
// Prepare the constants definition from the database // Prepare the constants definition from the database
$constants = getConstantsDefinition(); $constants = getConstantsDefinition();

View File

@ -18,6 +18,9 @@ function handleTriggerExecutionResult($result, $stdout, $stderr, $originalRow, $
// Decode the output from JSON to array // Decode the output from JSON to array
$newRowValue = json_decode($stdout, true); $newRowValue = json_decode($stdout, true);
// Ignore the hydrate columns
$newRowValue = array_filter($newRowValue, fn($k) => !str_ends_with($k, '_ref'), ARRAY_FILTER_USE_KEY);
if ($newRowValue === null) { if ($newRowValue === null) {
updateTriggerError($tableName, 'Invalid JSON output from sandboxed execution.'); updateTriggerError($tableName, 'Invalid JSON output from sandboxed execution.');
return; return;

View File

@ -85,7 +85,7 @@ function processActiveTable($activeTable) {
ensureLastUpdatedColumnExists($Name); ensureLastUpdatedColumnExists($Name);
$rowsToProcess = sql("SELECT * FROM $Name WHERE LastUpdated > '$LastUpdated'"); $rowsToProcess = sql_read_and_hydrate("SELECT * FROM $Name WHERE LastUpdated > '$LastUpdated'");
foreach ($rowsToProcess as $unprocessedRow) { foreach ($rowsToProcess as $unprocessedRow) {
processTableRow($activeTable, $unprocessedRow); processTableRow($activeTable, $unprocessedRow);
@ -166,7 +166,7 @@ function updateDatabaseRow($tableName, $originalRow, $newRowValue) {
$setStatements = []; $setStatements = [];
foreach ($newRowValue as $k => $v) { foreach ($newRowValue as $k => $v) {
$value = is_numeric($v) ? $v : "'" . str_replace("'", "''", $v) . "'"; $value = is_numeric($v) ? $v : "'" . str_replace("'", "''", is_string($v)?$v:json_encode($v)) . "'";
$setStatements[] = "$k = $value"; $setStatements[] = "$k = $value";
} }

View File

@ -11,6 +11,7 @@
function runSandboxedPython($code, &$stdout = null, &$stderr = null) { function runSandboxedPython($code, &$stdout = null, &$stderr = null) {
// Create a temporary file to hold the Python code // Create a temporary file to hold the Python code
$tempFile = tempnam(sys_get_temp_dir(), 'sandboxed_') . '.py'; $tempFile = tempnam(sys_get_temp_dir(), 'sandboxed_') . '.py';
echo "Creating ".redText("python temp code file")." for sandboxed execution at: $tempFile \n";
// Write the generated Python code to the temporary file // Write the generated Python code to the temporary file
file_put_contents($tempFile, $code); file_put_contents($tempFile, $code);

66
sys.php
View File

@ -66,3 +66,69 @@ function getTblPrimaryKeyColName($tblName) {
return $cols; return $cols;
} }
/**
* Executes a SELECT query and hydrates any foreign key columns with the
* referenced row data.
*
* The query should target a single table (e.g., "SELECT * FROM db.table WHERE …").
* For each foreign key in that table, an additional key named
* `<column>_ref` is added to each returned row containing the referenced row
* from the foreign table.
*
* @param string $query SQL SELECT statement for a single table.
* @return array Result set with hydrated foreign key data.
*/
function sql_read_and_hydrate($query) {
$rows = sql_read($query);
if (empty($rows)) {
return $rows;
}
if (!preg_match('/FROM\s+([`\w\.]+)/i', $query, $m)) {
return $rows; // Unable to determine table
}
$table = str_replace('`', '', $m[1]);
if (strpos($table, '.') !== false) {
list($dbName, $tblName) = explode('.', $table, 2);
} else {
$dbName = DB_NAME;
$tblName = $table;
}
$fks = sql_read(
"SELECT COLUMN_NAME, REFERENCED_TABLE_SCHEMA, REFERENCED_TABLE_NAME, " .
"REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE " .
"WHERE TABLE_SCHEMA = '$dbName' AND TABLE_NAME = '$tblName' " .
"AND REFERENCED_TABLE_NAME IS NOT NULL"
);
if (empty($fks)) {
return $rows; // no foreign keys
}
foreach ($rows as &$row) {
foreach ($fks as $fk) {
$col = $fk['COLUMN_NAME'];
if (!isset($row[$col])) continue;
$val = $row[$col];
if ($val === null) {
$row[$col . '_ref'] = null;
continue;
}
$refTable = $fk['REFERENCED_TABLE_SCHEMA'] . '.' . $fk['REFERENCED_TABLE_NAME'];
$refCol = $fk['REFERENCED_COLUMN_NAME'];
$condition = is_numeric($val)
? "$refCol = $val"
: "$refCol = '" . str_replace("'", "''", $val) . "'";
$refRow = sql_read("SELECT * FROM $refTable WHERE $condition LIMIT 1");
$row[$col . '_ref'] = $refRow[0] ?? null;
}
}
unset($row);
return $rows;
}