{"id":19440322,"url":"https://github.com/jehy/oracletogit","last_synced_at":"2025-04-24T22:33:34.044Z","repository":{"id":11000139,"uuid":"13322913","full_name":"jehy/OracleToGit","owner":"jehy","description":"Real time export oracle database structure DDL to Git repositary","archived":false,"fork":false,"pushed_at":"2017-08-04T07:56:11.000Z","size":1943,"stargazers_count":7,"open_issues_count":0,"forks_count":6,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-04-14T11:05:28.758Z","etag":null,"topics":["ddl","oracle","php"],"latest_commit_sha":null,"homepage":"http://oracletogit.ru/","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jehy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-10-04T11:45:19.000Z","updated_at":"2023-03-30T13:00:38.000Z","dependencies_parsed_at":"2022-09-16T23:10:40.275Z","dependency_job_id":null,"html_url":"https://github.com/jehy/OracleToGit","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jehy%2FOracleToGit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jehy%2FOracleToGit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jehy%2FOracleToGit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jehy%2FOracleToGit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jehy","download_url":"https://codeload.github.com/jehy/OracleToGit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223971457,"owners_count":17234059,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ddl","oracle","php"],"created_at":"2024-11-10T15:28:48.726Z","updated_at":"2024-11-10T15:28:49.335Z","avatar_url":"https://github.com/jehy.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"OracleToGit\n===========\n\nWhat is it?\n-----------\nOracleToGit is a simple tool for making realtime comprehensible\n version controlled backups of your database in form of DDL queries.\n\nTo make the long story short, it is a daemon script which exports\n your database DDL scripts in realtime to git and allows you to track changes\n  in code of your triggers, tables, packages, fuctions, views, etc.\n\nYou will be able to see, who changed your code, when he did it\n and what exactly he has done. For example, that’s how it looks\n  on bitbucket:\n![how it looks](screenshots/wtf.png)\n\nInstallation\n------------\n### Requirements.\n\nYou need the following software:\n\n* Linux server with Apache, PHP 5 and git installed. PHP has to be able to connect to your Oracle database (set up oci library for php).\n* Oracle Database server\n\nAlso, you need\n* Basic knowledge of Linux, PHP and Git\n* DBA priviledges on database in question\n\n### 1. Schema\n\nFirst, you will have to run some administrative queries manually.\nThose are dangerous and can kill kittens - so it is better to be\ncareful and examine all the queries output.\nThat is why everything doesn't happen in one click.\n\nFirstly, we will need a separate schema with DBA role\n(yup, we could grant smth like \"select any table\"...\nBut it isn't really much different from DBA).\n\nSo, let's run\n\n```sql\n-- Create the user\nCREATE USER MAGIC identified BY \"YOUR_PASSWORD\"\nDEFAULT tablespace APP_TABLESPACE --your tablespace name\ntemporary tablespace TEMP_TABLESPACE --your temporary tablespace name\nprofile DEFAULT;\n-- Grant/Revoke role privileges\ngrant CONNECT TO MAGIC;\ngrant resource TO MAGIC;\ngrant dba TO MAGIC;\n-- Grant/Revoke system privileges\ngrant CREATE session TO MAGIC;\ngrant unlimited tablespace TO MAGIC;\n```\n\n### 2. Log table\n\nWe will use table to store data about changes,\nhappening to your database.\n\nThat's how it looks:\n```sql\n-- Create table\nCREATE TABLE MAGIC.DDLLOG\n(\nddl_timestamp   DATE,\nsysevent        VARCHAR2(100),\nlogin_user      VARCHAR2(50),\ninstance_num    NUMBER,\ndatabase_name   VARCHAR2(50),\ndict_obj_name   VARCHAR2(100),\ndict_obj_type   VARCHAR2(100),\ndict_obj_owner  VARCHAR2(50),\nhost            VARCHAR2(100),\nip              VARCHAR2(15),\nos_user         VARCHAR2(50),\nobj_current_ddl CLOB,\nevent_id        NUMBER\n)\n--tablespace APP_TABLESPACE\nPCTFREE 10\ninitrans 1\nmaxtrans 255\nstorage\n(\ninitial 64K\nnext 1M\nminextents 1\nmaxextents unlimited\n);\n-- Create/Recreate indexes\nCREATE INDEX MAGIC.DDLLOG_ID ON MAGIC.DDLLOG (EVENT_ID)\n--tablespace APP_TABLESPACE\nPCTFREE 10\ninitrans 2\nmaxtrans 255\nstorage\n(\ninitial 64K\nnext 1M\nminextents 1\nmaxextents unlimited\n);\n \n \n-- Create sequence\nCREATE sequence MAGIC.EVENT_IDS\nminvalue 1\nmaxvalue 1000000000000\nSTART WITH 1\nincrement BY 1\ncache 20;\n \n \nCREATE OR REPLACE TRIGGER magic.tgr_id\nbefore INSERT OR UPDATE ON magic.ddllog\nFOR each ROW\nDECLARE\nBEGIN\nIF (inserting AND :NEW.event_id IS NULL OR :NEW.event_id \u003c= 0) THEN\nSELECT magic.event_IDS.NEXTVAL INTO :NEW.event_id FROM dual ;\nEND IF ;\nEND ;\n```\n \n### 3. DDL trigger\n\nNow we're gonna do really dangerous staff - add trigger for all DDL\noperations in database. If this trigger fucks up, your ddl\noperations will too. If you feel that something's off -\ndisable the trigger!\n```sql\nCREATE OR REPLACE TYPE magic.after_ddl_queue_type AS object\n    (\n     ddl_timestamp DATE,\n     sysevent VARCHAR2(100),\n     ora_login_user VARCHAR2(50),\n     ora_instance_num NUMBER,\n     ora_database_name VARCHAR2(50),\n     ora_dict_obj_name VARCHAR2(100),\n     ora_dict_obj_type VARCHAR2(100),\n     ora_dict_obj_owner VARCHAR2(50),\n     host VARCHAR2(100),\n     ip VARCHAR2(15),\n     os_user VARCHAR2(50),\n     ddl_text clob\n    );\n \nCREATE OR REPLACE TRIGGER magic.after_ddl after ddl ON database\nDECLARE\n ddl_text_var dbms_standard.ora_name_list_t;       --This is the type ora_name_list_t, is table of varchar2(64)\n full_ddl_text clob;                               --There will be stored the full DDL text\n message after_ddl_queue_type;\nBEGIN\n  IF(ora_sysevent IN ('TRUNCATE','ANALYZE'))\n  THEN\n    NULL;--smth may be here in future\n  ELSE\n FOR i IN 1..ora_sql_txt(ddl_text_var) LOOP        --This portion of code calculates the full DDL text, because ddl_text_var\n   full_ddl_text:=full_ddl_text||ddl_text_var(i);  --is just a table of 64 byte pieces of DDL, we need to subtract them\n END LOOP;                                 --to get full DDL.\n message:=after_ddl_queue_type(SYSDATE,\n                               ora_sysevent,\n                               ora_login_user,\n                               ora_instance_num,\n                               ora_database_name,\n                               ora_dict_obj_name,\n                               ora_dict_obj_type,\n                               ora_dict_obj_owner,\n                               SYS_CONTEXT('userenv','HOST'),\n                               SYS_CONTEXT('userenv','IP_ADDRESS'),\n                               SYS_CONTEXT('userenv','OS_USER'),\n                               full_ddl_text);\n INSERT INTO magic.ddllog VALUES(message.ddl_timestamp,message.sysevent,message.ora_login_user,message.ora_instance_num\n ,message.ora_database_name,message.ora_dict_obj_name,message.ora_dict_obj_type,message.ora_dict_obj_owner,message.host,\n message.ip,message.os_user,message.ddl_text,NULL);\n                 END IF;\nEND;\n```\n \n### 4. Test!\n\nSeems like you're ready to go! Try making random DDL query, and see how\nit is reflected in `magic.ddllog` table.\n\n### 5. Configure script\n\nNow we need to set up connection settings for PHP script.\nYou need to download project code from github repository\n(\"Download ZIP\" button in right lower corner).\n\nIn this example, all PHP code is extracted to application\ndirectory `/web/oracle2git`. Copy the following code to\nnew file \"settings/default.php\" and change default connect\nsettings to the ones for your database with the newly\ncreated `magic` schema.\n```php\n\u003c?\n##########  DEFINITIONS\nset_time_limit(0);\n$CURR_LOG='';\n$CURR_SESSION='DEFAULT';\n$CONNECT_POOL=array();\n$normal_errors=array(24344,955,1917,942);#errors to ignore\n$normal_errors[]=20102;\n$CONNECTS=array('DEFAULT'=\u003earray('scheme'=\u003e'magic','pass'=\u003e'YOUR_PASSWORD','connect'=\u003e'//host:1521/sid','enc'=\u003e'AL32UTF8','mode'=\u003eOCI_DEFAULT),);#your oracle connection settings\ndefine('VERBOSE',0);\ndefine('DEBUG',1);\n$bkp_dir = '/repo/default.git/';#define a directory to store your git repo\n#$LOGS_CONVERSION=array('from'=\u003e\"Windows-1251\",'to'=\u003e\"utf-8\"); #convert GIT logs to utf if you need it.k\n?\u003e\n```\n### 6. Set up Git repo for your database\n\nNow you need to associate your backup directory with the git repository.\nInit repository, make first clean commit and push it to remote server.\nPlease, use remote repository (github, bitbucket or any other)\nwith \"master\" branch. Remote repo should be called \"backup\".\nAlso, add there `.gitignore` file with the following lines:\n\n* last_time.txt\n* working*.txt\n\nAlso, make sure that your push can be done without entering\nlogin and password. To accomplish it, you can store login\nand password locally, or use SSH keys (that's the best).\n\n### 7. Set up permissions\n\nAllow PHP to write to \"logs\" directory and to backup directory (which you chose in settings.php file).\n\n### 8. Primary export\n\nYup, at last we're ready to export your database source code!\n\nOpen your server console and launch backup.php script. It may take long for your first export.\n```bash\nphp \"/web/oracle2git/backup.php\" \"default\"\n```\n\n### 9. Secondary export\n\nSecondary export should be quick but you need to check if it works okay.\n\nJust repeat the same command you used for primary export.\n\n### 10. Push your repo to remote repositary\n```bash\nphp \"/web/oracle2git/push.php\" \"default\"\n```\nIt should work okay if you correctly completed step 6.\n\n### 11. Set up regular export\n\nNow you just need to set up a crontab script to regularly\nlaunch secondary export script and push script.\nThose are represented as two different scripts because\nobviously you don't need to sync as often as you update\nyour local repo. It would just make unneccessary traffic.\nI'd recommend to set it backup to every five minutes and\npush to every hour. You need to make two bash scripts\nwith backup and push commands, for example,\n\n**/root/backup_default.sh**\n```bash\n#!/bin/bash\nphp /web/oracle2git/backup.php default\n```\n\nand\n\n**/root/push_default.sh**\n```bash\n#!/bin/bash\nphp /web/oracle2git/push.php default\n```\nMake sure that your bash and php files have right permissions for\nexecution. And, the last thing - make it a cron job:\n```\n*/5 * * * * php /root/backup_default.sh\n00 * * * * php /root/push_default.sh\n```\n\nNow you are ready to go!\n\nFAQ\n---\n\nQ: Why PHP?!   \nA: Why not? It’s quick to write, easy to update and customize. And either way PHP won’t slow down backup process – there surely will be bottlenecks on Oracle server.\n\nQ: Why Git?!   \nA: I like Git. It is quick and comfortable to work with. SVN was such a bitch.\n\nQ: What services can I use to host my database repositaries?   \nA: We tried using github and bitbucket. Both worked wonderful for us.\n\nQ: Can my commit history be wrong?   \nA: Yup, sometimes it can be not accurate – if someone worked changed object too many times between two backups.\n\nQ: Why isn’t there web interface for installation or performing backup?   \nA: Installation should be accomplished very carefully. You can really fuck up your database. And for performing backups – it’s a long process and it can hang in browser for many hours – that’s not cool.\n\nQ: Can I backup some of my schemas, not the whole database?   \nA: Yes, of cause! You can change database trigger or backup script appropriately.\n\nQ: I found an error \\ bottleneck in code or made a new feature!   \nA: Cool! Please, make a fork on github and notify me – we’ll merge as much exciting features as possible.\n\nQ: Is it possible to make a complete structure backup and restore it with OracleToGit?   \nA: Right now, there is no tool for installing export from OracleToGit. However, it is pretty much possible and I can publish it on request.\n\nQ: Can I backup data in my tables using OracleToGit?   \nA: Nope. And you don’t want it. Really.\n\n\nScreenshots\n-----------\nSome examples on how Oracle to Git can work:\n\nLoading updates from database:\n![how it looks](screenshots/1.png)\n\nRepository on github:\n![how it looks](screenshots/2.png)\n\nRepositary on bitbucket:\n![how it looks](screenshots/3.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjehy%2Foracletogit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjehy%2Foracletogit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjehy%2Foracletogit/lists"}