合格最低点
一般前期
2024 | 2023 | 2022 | |
---|---|---|---|
一次合格最低点 | 229/400点 (57.3%) | 245/400点 (61.3%) | 245/400点 (61.3%) |
一般後期
2024 | 2023 | 2022 | |
---|---|---|---|
一次合格最低点 | 278/400点 (69.5%) | 251/400点 (62.3%) | 243/400点 (60.8%) |
2024 | 2023 | 2022 | |
---|---|---|---|
一次合格最低点 | 229/400点 (57.3%) | 245/400点 (61.3%) | 245/400点 (61.3%) |
2024 | 2023 | 2022 | |
---|---|---|---|
一次合格最低点 | 278/400点 (69.5%) | 251/400点 (62.3%) | 243/400点 (60.8%) |
の記事の続編。
F#はVB.net同様、手動でのパス通しをする羽目になった。
open Autodesk.AutoCAD.Runtime
open Autodesk.AutoCAD.ApplicationServices
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Geometry
type MyCommands() =
interface IExtensionApplication with
member this.Initialize() =
Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\nMyCommands initialized")
member this.Terminate() =
Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\nMyCommands terminated")
[<CommandMethod("bot")>]
member this.ProcessUserInput() =
let doc = Application.DocumentManager.MdiActiveDocument
let ed = doc.Editor
ed.WriteMessage("\nProcessUserInput called")
let userInput = this.GetStringFromUserInput("CAD", "何をしましょうか?")
if userInput.Contains("直線") then
this.CreateLine()
elif userInput.Contains("円") then
this.CreateCircle()
else
ed.WriteMessage("\nそのような操作はできません。")
member private this.CreateLine() =
let doc = Application.DocumentManager.MdiActiveDocument
let ed = doc.Editor
let start_x = this.GetDoubleFromUserInput("始点のX座標を入力してください。")
let start_y = this.GetDoubleFromUserInput("始点のY座標を入力してください。")
let end_x = this.GetDoubleFromUserInput("終点のX座標を入力してください。")
let end_y = this.GetDoubleFromUserInput("終点のY座標を入力してください。")
this.DrawLine(start_x, start_y, end_x, end_y)
member private this.CreateCircle() =
let doc = Application.DocumentManager.MdiActiveDocument
let ed = doc.Editor
let center_x = this.GetDoubleFromUserInput("中心のX座標を入力してください。")
let center_y = this.GetDoubleFromUserInput("中心のY座標を入力してください。")
let radius = this.GetDoubleFromUserInput("半径を入力してください。")
this.DrawCircle(center_x, center_y, radius)
member private this.GetDoubleFromUserInput(prompt: string) : double =
let ed = Application.DocumentManager.MdiActiveDocument.Editor
let mutable result = ed.GetDouble(prompt)
while result.Status <> PromptStatus.OK do
ed.WriteMessage("\n数値を入力してください。")
result <- ed.GetDouble(prompt)
result.Value
member private this.GetStringFromUserInput(title: string, prompt: string) : string =
let ed = Application.DocumentManager.MdiActiveDocument.Editor
(ed.GetString(prompt)).StringResult
member private this.DrawLine(startX: double, startY: double, endX: double, endY: double) =
let doc = Application.DocumentManager.MdiActiveDocument
let db = doc.Database
use tr = db.TransactionManager.StartTransaction()
let bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) :?> BlockTable
let btr = tr.GetObject(bt.[BlockTableRecord.ModelSpace], OpenMode.ForWrite) :?> BlockTableRecord
let startPoint = Point3d(startX, startY, 0.0)
let endPoint = Point3d(endX, endY, 0.0)
let line = new Line(startPoint, endPoint)
btr.AppendEntity(line) |> ignore
tr.AddNewlyCreatedDBObject(line, true) |> ignore
tr.Commit()
member private this.DrawCircle(centerX: double, centerY: double, radius: double) =
let doc = Application.DocumentManager.MdiActiveDocument
let db = doc.Database
use tr = db.TransactionManager.StartTransaction()
let bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) :?> BlockTable
let btr = tr.GetObject(bt.[BlockTableRecord.ModelSpace], OpenMode.ForWrite) :?> BlockTableRecord
let centerPoint = Point3d(centerX, centerY, 0.0)
let circle = new Circle(centerPoint, Vector3d.ZAxis, radius)
btr.AppendEntity(circle) |> ignore
tr.AddNewlyCreatedDBObject(circle, true) |> ignore
tr.Commit()
ACETUCS-BUTTON
というコマンドが勝手に呼び出され、ロード中・・・と表示されたままフリーズ・
誰もACETUCS-BUTTONなんていうコマンドを入力した覚えがないんだけど。
F#は使えない言語ということでソッコー没!
次はC++でためしてみることになった。
どうなるかわからんが、とりあえずChatGPTの吐いたソースコードをここに投げておこう。
#include "acutads.h"
#include "acedads.h"
#include "acdocman.h"
#include "dbents.h"
#include "dbmain.h"
#include "dbsymtb.h"
#include "dbapserv.h"
#include "geassign.h"
#include "acarray.h"
class MyCommands
{
public:
static void ProcessUserInput()
{
AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase();
AcDbBlockTable* pBlockTable;
AcDbBlockTableRecord* pBlockTableRecord;
acdbHostApplicationServices()->workingDatabase()->getBlockTable(pBlockTable, AcDb::kForRead);
pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord, AcDb::kForWrite);
pBlockTable->close();
ACHAR szPrompt[512];
acutPrintf(_T("\nCAD、何をしましょうか?: "));
acedGetString(0, szPrompt);
CString userInput = szPrompt;
if (userInput.Find(_T("直線")) != -1)
{
CreateLine(pBlockTableRecord);
}
else if (userInput.Find(_T("円")) != -1)
{
CreateCircle(pBlockTableRecord);
}
else
{
acutPrintf(_T("\nそのような操作はできません。"));
}
pBlockTableRecord->close();
}
private:
static void CreateLine(AcDbBlockTableRecord* pBlockTableRecord)
{
double start_x = GetDoubleFromUserInput(_T("始点のX座標を入力してください。"));
double start_y = GetDoubleFromUserInput(_T("始点のY座標を入力してください。"));
double end_x = GetDoubleFromUserInput(_T("終点のX座標を入力してください。"));
double end_y = GetDoubleFromUserInput(_T("終点のY座標を入力してください。"));
AcDbLine* pLine = new AcDbLine(AcGePoint3d(start_x, start_y, 0), AcGePoint3d(end_x, end_y, 0));
pBlockTableRecord->appendAcDbEntity(pLine);
pLine->close();
}
static void CreateCircle(AcDbBlockTableRecord* pBlockTableRecord)
{
double center_x = GetDoubleFromUserInput(_T("中心のX座標を入力してください。"));
double center_y = GetDoubleFromUserInput(_T("中心のY座標を入力してください。"));
double radius = GetDoubleFromUserInput(_T("半径を入力してください。"));
AcDbCircle* pCircle = new AcDbCircle(AcGePoint3d(center_x, center_y, 0), AcGeVector3d::kZAxis, radius);
pBlockTableRecord->appendAcDbEntity(pCircle);
pCircle->close();
}
static double GetDoubleFromUserInput(const ACHAR* prompt)
{
double value;
ACHAR szPrompt[512];
acutPrintf(prompt);
acedInitGet(0, _T("Cancel"));
if (RTNORM != acedGetReal(szPrompt, &value))
{
acutPrintf(_T("\n数値を入力してください。"));
acutPrintf(_T("\n操作をキャンセルしました。"));
acedGetPoint(nullptr, _T("\n続行するにはリターン キーを押してください。"));
acutPrintf(_T("\n"));
return -1.0;
}
return value;
}
};
extern "C" AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt)
{
switch (msg)
{
case AcRx::kInitAppMsg:
acrxDynamicLinker->unlockApplication(pkt);
acrxRegisterAppMDIAware(pkt);
break;
case AcRx::kUnloadAppMsg:
// Do nothing
break;
}
return AcRx::kRetOK;
}
extern "C" void
ProcessUserInput()
{
MyCommands::ProcessUserInput();
}
PostgreSQL からの移行 (cockroachlabs.com)
から引用したものを和訳してみた。
PostgreSQL からの移行
このページでは、PostgreSQLからCockroachDBにデータを移行するための基本的な考慮事項と基本的な例を示します。このページの情報は、データベースを CockroachDB に移行するための大まかなフェーズと考慮事項について説明している「移行の概要」を読んでいることを前提としています。
このページの PostgreSQL 移行の例では、MOLT ツールを使用して PostgreSQL スキーマを更新し、データの初期読み込みを実行し、データを検証する方法を示します。これらの手順は、完全な移行の準備をするときに不可欠です。
先端:
CockroachDBへの移行についてサポートが必要な場合は、営業チームにお問い合わせください。
構文の違い
CockroachDBはPostgreSQLのワイヤプロトコルをサポートしており、PostgreSQLの構文とほぼ互換性があります。
構文の違いについては、PostgreSQLと異なる機能を参照してください。
サポートされていない機能
以下のPostgreSQL機能は、CockroachDBにはまだ存在しません。
トリガー。これらは、アプリケーション ロジックに実装する必要があります。
イベント。
主キーを削除します。
手記:
各テーブルには、主キーが関連付けられている必要があります。主キー制約は、1 つのトランザクション内で削除および追加できます。
XML 関数。
列レベルの権限。
XA 構文。
テンプレートからデータベースを作成する。
テーブルから 1 つのパーティションを削除する。
外部データラッパー。
アドバイザリ ロック関数 (ただし、一部の関数は no-op 実装で定義されています)。
PostgreSQL データの読み込み
次のいずれかの方法を使用して、PostgreSQL データを CockroachDB に移行できます。
IMPORT INTO を使用して、ユーザーファイルまたはクラウドストレージを介して保存された CSV、TSV、または Avro データを CockroachDB 上の既存のテーブルに移行します。このオプションでは、最高のスループットが得られますが、インポート速度を達成するにはテーブルをオフラインにする必要があります。
先端:
CockroachDB でのインポートパフォーマンスを最適化するためのベストプラクティスについては、「インポートパフォーマンスのベストプラクティス」を参照してください。
サードパーティのデータ移行ツール(AWS DMS、Qlik、Striimなど)を使用してデータをロードします。
PostgreSQL から移行する場合、COPY FROM を使用して、CSV またはタブ区切りのデータを CockroachDB テーブルにコピーできます。このオプションを使用すると、テーブルをオンラインのままにしてアクセス可能にすることができます。ただし、IMPORT INTOを使用するよりも遅くなります。
次の例では、を使用して初期データ・ロードを実行します。IMPORT INTO
例: CockroachDB への移行frenchtowns
次の手順では、移行中のスキーマの変換、データの初期読み込みの実行、およびデータの整合性の検証を示します。
完全移行のコンテキストでは、これらの手順により、PostgreSQL データを CockroachDB に適切に移行し、クラスターに対してアプリケーション クエリをテストできます。詳細については、「移行の概要」を参照してください。
始める前に
この例では、PostgreSQL データセットの変更バージョンを使用し、スキーマとデータをサーバーレスクラスターに移行する方法を示します。次の手順に従うには、次の手順を実行します。french-towns-communes-francais
データセットをダウンロードします。frenchtowns
curl -O https://cockroachdb-migration-examples.s3.us-east-1.amazonaws.com/postgresql/frenchtowns/frenchtowns.sql
PostgreSQL インスタンスにデータベースを作成します。frenchtowns
createdb frenchtowns
ダウンロードしたファイルのパスを指定して、データをPostgreSQLにロードします。frenchtowns
psql frenchtowns -a -f frenchtowns.sql
スキーマ変換ツールへのアクセスとサーバーレスクラスターの作成に使用する無料のクラウドアカウントを作成します。
先端:
CockroachDB セルフホストデータベースに移行する場合は、変換されたスキーマをスキーマ変換ツールからエクスポートし、Cockroach SQL でステートメントを実行するか、Alembic、Flyway、Liquibase などのサードパーティのスキーマ移行ツールを使用できます。
ステップ1。PostgreSQL スキーマの変換
スキーマ変換ツールを使用して、CockroachDB との互換性のためにスキーマを変換します。スキーマには、frenchtownsregionsdepartmentstowns
次の pg_dump コマンドで PostgreSQL スキーマをダンプします。frenchtowns
pg_dump --schema-only frenchtowns > frenchtowns_schema.sql
Cloud Console でスキーマ変換ツールを開き、新しい PostgreSQL スキーマを追加します。
変換が完了したら、結果を確認します。要約レポートには、「必要な修正」の下にエラーがあることが示されます。スキーマを CockroachDB に移行するには、これらを解決する必要があります。
先端:
また、PostgreSQL データベースの資格情報を追加して、スキーマ変換ツールが PostgreSQL データベースから直接スキーマを取得するようにすることもできます。
Missing user: postgreserrors は、SQL ユーザーが CockroachDB に存在しないことを示します。「ユーザーの追加」をクリックして、ユーザーを作成します。postgres
Miscellaneous Errorsには、安全に削除できるステートメントが含まれています。「削除」をクリックして、スキーマからステートメントを削除します。SELECT pg_catalog.set_config('search_path', '', false)
[提案] の下に一覧表示されているステートメントを確認します。Cockroach Labs では、シーケンスを使用して主キー列を定義することはお勧めしません。詳細については、「一意の ID のベスト プラクティス」を参照してください。CREATE SEQUENCE
この例では、これ以上変更を加えずに提案を承認します。実際には、CockroachDB への完全な移行を実行した後、一意の非連続主キーを使用するように CockroachDB スキーマを変更します。
[移行の再試行] をクリックします。概要レポートに、エラーがないことが表示されます。これは、スキーマを CockroachDB に移行する準備ができていることを意味します。
この例では、サーバーレスクラスターに直接移行します。 CockroachDB セルフホストデータベースに移行する場合は、変換されたスキーマをスキーマ変換ツールからエクスポートし、Cockroach SQL でステートメントを実行するか、Alembic、Flyway、Liquibase などのサードパーティのスキーマ移行ツールを使用できます。
[Migrate Schema] をクリックして、変換されたスキーマで新しいサーバーレスクラスターを作成します。データベースに という名前を付けます。frenchtowns
このデータベースは、Cloud Console の [データベース] ページで確認できます。
ステップ2。PostgreSQL データの読み込み
CSV形式のデータでIMPORT INTOを使用して、データをCockroachDBにロードします。IMPORT INTO では、次の属性を持つテーブルごとに 1 つのファイルをエクスポートする必要があります。frenchtowns
ファイルは、有効な CSV (カンマ区切り値) または TSV (タブ区切り値) 形式である必要があります。
区切り文字は 1 文字でなければなりません。区切り文字オプションを使用して、コンマ以外の文字 (TSV 形式のタブなど) を設定します。
ファイルは UTF-8 でエンコードする必要があります。
フィールドに次の文字のいずれかが含まれている場合は、フィールドを二重引用符で囲む必要があります。
区切り文字 (デフォルト)。,
二重引用符 () です。フィールドは二重引用符で囲まれるため、フィールド内の二重引用符の前に別の二重引用符を付けてエスケープします。例えば:。""aaa","b""bb","ccc"
改行 () です。\n
キャリッジリターン()。\r
カラムがバイト型の場合、有効な UTF-8 文字列、または で始まる 16 進数エンコードされたバイト リテラルのいずれかになります。たとえば、値がバイト であるフィールドは、 と記述されます。\x12\x0102
手記:
デフォルトでは、IMPORT INTO はターゲット表のすべての外部キー制約を無効にします。
PostgreSQLデータベースの各テーブルをCSV形式のファイルにダンプします。frenchtowns
psql frenchtowns -c "COPY regions TO stdout DELIMITER ',' CSV;" > regions.csv
psql frenchtowns -c "COPY departments TO stdout DELIMITER ',' CSV;" > departments.csv
psql frenchtowns -c "COPY towns TO stdout DELIMITER ',' CSV;" > towns.csv
CockroachDB クラスターがアクセスできる場所でファイルをホストします。
CockroachDB クラスター内の各ノードは、インポートされるファイルにアクセスできる必要があります。クラスターがデータにアクセスする方法はいくつかあります。IMPORT INTO がプルできるストレージのタイプの詳細については、以下を参照してください。
クラウドストレージを使用する
ローカル・ファイル・サーバーの使用
Amazon S3 や Google Cloud などのクラウドストレージは、インポートするデータファイルをホストすることを強くお勧めします。
前のステップで生成されたダンプファイルは、この例用に作成されたパブリック S3 バケットですでにホストされています。
CockroachDB クラスターへの SQL シェルを開きます。コマンドを見つけるには、Cloud Console で [接続] ダイアログを開き、データベースと [CockroachDB クライアント] オプションを選択します。次のようになります。frenchtownsfrenchtowns
cockroach sql --url "postgresql://{username}@{hostname}:{port}/frenchtowns?sslmode=verify-full"
IMPORT INTO を使用して、各 PostgreSQL ダンプ ファイルをデータベース内の対応するテーブルにインポートします。frenchtowns
次のコマンドは、この例でデータダンプファイルがホストされているパブリック S3 バケットを指しています。frenchtowns
先端:
インポートする行数を指定するオプションを追加できます。たとえば、テーブルの最初の 10 行をインポートします。このオプションは、時間とリソースを消費するインポートを実行する前に、エラーをすばやく検出するのに役立ちます。row_limitrow_limit = '10'
IMPORT INTO regions
CSV DATA (
'https://cockroachdb-migration-examples.s3.us-east-1.amazonaws.com/postgresql/frenchtowns/regions.csv'
);
job_id | status | fraction_completed | rows | index_entries | bytes
---------------------+-----------+--------------------+------+---------------+--------
893753132185026561 | succeeded | 1 | 26 | 52 | 2338
IMPORT INTO departments
CSV DATA (
'https://cockroachdb-migration-examples.s3.us-east-1.amazonaws.com/postgresql/frenchtowns/departments.csv'
);
job_id | status | fraction_completed | rows | index_entries | bytes
---------------------+-----------+--------------------+------+---------------+--------
893753147892465665 | succeeded | 1 | 100 | 300 | 11166
IMPORT INTO towns
CSV DATA (
'https://cockroachdb-migration-examples.s3.us-east-1.amazonaws.com/postgresql/frenchtowns/towns.csv'
);
job_id | status | fraction_completed | rows | index_entries | bytes
---------------------+-----------+--------------------+-------+---------------+----------
893753162225680385 | succeeded | 1 | 36684 | 36684 | 2485007
ターゲット表のすべての外部キー制約が無効になることを思い出してください。と に定義されている制約を表示します。IMPORT INTOdepartmentstowns
SHOW CONSTRAINTS FROM departments;
table_name | constraint_name | constraint_type | details | validated
--------------+-------------------------+-----------------+---------------------------------------------------------+------------
departments | departments_capital_key | UNIQUE | UNIQUE (capital ASC) | t
departments | departments_code_key | UNIQUE | UNIQUE (code ASC) | t
departments | departments_name_key | UNIQUE | UNIQUE (name ASC) | t
departments | departments_pkey | PRIMARY KEY | PRIMARY KEY (id ASC) | t
departments | departments_region_fkey | FOREIGN KEY | FOREIGN KEY (region) REFERENCES regions(code) NOT VALID | f
SHOW CONSTRAINTS FROM towns;
table_name | constraint_name | constraint_type | details | validated
-------------+---------------------------+-----------------+-----------------------------------------------------------------+------------
towns | towns_code_department_key | UNIQUE | UNIQUE (code ASC, department ASC) | t
towns | towns_department_fkey | FOREIGN KEY | FOREIGN KEY (department) REFERENCES departments(code) NOT VALID | f
towns | towns_pkey | PRIMARY KEY | PRIMARY KEY (id ASC) | t
外部キーを検証するには、ALTER TABLE ...VALIDATE CONSTRAINT ステートメントを使用します。
ALTER TABLE departments VALIDATE CONSTRAINT departments_region_fkey;
ALTER TABLE towns VALIDATE CONSTRAINT towns_department_fkey;
ステップ3。移行されたデータを検証する
MOLT Verifyを使用して、PostgreSQLとCockroachDBのデータが一致していることを確認します。
MOLT Verifyをインストールします。
MOLT Verifyをインストールしたディレクトリで、次のコマンドを使用して2つのデータベースを比較し、PostgreSQL接続文字列を に、CockroachDB接続文字列を に指定します。--source--target
先端:
CockroachDB 接続文字列を見つけるには、Cloud Console で [接続] ダイアログを開き、データベースと [全般] 接続文字列オプションを選択します。frenchtowns
./molt verify --source 'postgresql://{username}:{password}@{host}:{port}/frenchtowns' --target 'postgresql://{user}:{password}@{host}:{port}/frenchtowns?sslmode=verify-full'
初期出力が表示されます。
<nil> INF verification in progress
次の出力は、MOLT Verify が検証を完了したことを示しています。
<nil> INF finished row verification on public.regions (shard 1/1): truth rows seen: 26, success: 26, missing: 0, mismatch: 0, extraneous: 0, live_retry: 0
<nil> INF finished row verification on public.departments (shard 1/1): truth rows seen: 100, success: 100, missing: 0, mismatch: 0, extraneous: 0, live_retry: 0
<nil> INF progress on public.towns (shard 1/1): truth rows seen: 10000, success: 10000, missing: 0, mismatch: 0, extraneous: 0, live_retry: 0
<nil> INF progress on public.towns (shard 1/1): truth rows seen: 20000, success: 20000, missing: 0, mismatch: 0, extraneous: 0, live_retry: 0
<nil> INF progress on public.towns (shard 1/1): truth rows seen: 30000, success: 30000, missing: 0, mismatch: 0, extraneous: 0, live_retry: 0
<nil> INF finished row verification on public.towns (shard 1/1): truth rows seen: 36684, success: 36684, missing: 0, mismatch: 0, extraneous: 0, live_retry: 0
<nil> INF verification complete
スキーマを移行し、初期データ読み込みを検証したら、実際の移行の次の手順は、完全な移行を実行する前に、必要なアプリケーションの変更を行ったことを確認し、アプリケーション クエリを検証し、ドライ ランを実行することです。
詳細については、「移行の概要」を参照してください。
MySQLだけじゃなくてPostgreSQLもCockroachDBへの移行ツールが無いらしいようだ。
もしかしたらOracleDBもCockroachDBへの移行ツールがないかもしれん。
Migrate from MySQL (cockroachlabs.com)
の和訳を以下に示す。
MySQLからの移行
このページでは、基本的な考慮事項について説明し、MySQL から CockroachDB にデータを移行する基本的な例を示します。このページの情報は、データベースを CockroachDB に移行するための大まかなフェーズと考慮事項について説明している「移行の概要」を読んでいることを前提としています。
このページのMySQL移行例は、MOLTツールを使用してMySQLスキーマを更新し、データの初期ロードを実行し、データを検証する方法を示しています。これらの手順は、完全な移行の準備をするときに不可欠です。
先端:
CockroachDBへの移行についてサポートが必要な場合は、営業チームにお問い合わせください。
構文の違い
MySQLとCockroachDBの構文の違いにより、アプリケーションの変更が必要になる可能性があります。移行の概要の一般的な考慮事項に加えて、移行計画を作成する際には、次の MySQL 固有の情報も考慮してください。
スキーマ変換ツールを使用すると、自動変換できないMySQL構文がサマリーレポートに表示されます。これらには、次のものが含まれる場合があります。
文字列の大文字と小文字の区別
文字列は、MySQLでは大文字と小文字が区別されず、CockroachDBでは大文字と小文字が区別されます。CockroachDBから期待する結果を得るには、MySQLデータを編集する必要があるかもしれません。たとえば、MySQLで文字列比較を行っていた場合、CockroachDBで動作するように変更する必要があります。
MySQL での文字列の大文字と小文字の区別の詳細については、MySQL ドキュメントの「文字列検索での大文字と小文字の区別」を参照してください。CockroachDB 文字列の詳細については、「STRING」を参照してください。
識別子の大文字と小文字の区別
識別子は、MySQLでは大文字と小文字が区別され、CockroachDBでは大文字と小文字が区別されません。スキーマ変換ツールを使用する場合は、識別子を二重引用符で囲んで大文字と小文字を区別するか、小文字に変換して識別子を大文字と小文字を区別しないようにすることができます。
AUTO_INCREMENT属性
連続したカラム値を作成する MySQL AUTO_INCREMENT 属性は、CockroachDB ではサポートされていません。スキーマ変換ツールを使用する場合、 は シーケンス、 gen_random_uuid() は値、 unique_rowid() は一意の値を使用するように変換できます。Cockroach Labs では、シーケンスを使用して主キー列を定義することはお勧めしません。詳細については、「一意の ID のベスト プラクティス」を参照してください。AUTO_INCREMENTUUIDINT8
手記:
スキーマ変換中にカラムタイプを変更すると、MOLT Verifyはデータ検証中にタイプの不一致を識別します。これは正常な動作です。
ENUM種類
MySQLの型は、テーブルの列で定義されます。CockroachDBでは、ENUMはスタンドアロン型です。スキーマ変換ツールを使用する場合は、定義の重複を排除するか、列ごとに個別の型を作成できます。ENUMENUM
TINYINT種類
TINYINTデータ型は CockroachDB ではサポートされていません。スキーマ変換ツールは、列を自動的に INT2 () に変換します。TINYINTSMALLINT
地理空間タイプ
MySQL ジオメトリ タイプは、スキーマ変換ツールによって CockroachDB 地理空間タイプに変換されません。これらは、CockroachDBの対応する型に手動で変換する必要があります。
FIELD機能
MYSQL 関数は CockroachDB ではサポートされていません。代わりに、配列内で最初に出現する要素のインデックスを返す array_position 関数を使用できます。FIELD
使用例:
SELECT array_position(ARRAY[4,1,3,2],1);
array_position
------------------
2
(1 row)
要素が見つからない場合、MySQL は 0 を返しますが、CockroachDB は .したがって、関数を含むステートメントで句を使用している場合、要素が見つからない場合でも並べ替えが適用されることに注意してください。回避策として、COALESCE 演算子を使用できます。NULLORDER BYarray_position
SELECT * FROM table_a ORDER BY COALESCE(array_position(ARRAY[4,1,3,2],5),999);
MySQLデータの読み込み
次のいずれかの方法を使用して、MySQL データを CockroachDB に移行できます。
IMPORT INTO を使用して、ユーザーファイルまたはクラウドストレージを介して保存された CSV、TSV、または Avro データを CockroachDB 上の既存のテーブルに移行します。このオプションでは、最高のスループットが得られますが、インポート速度を達成するにはテーブルをオフラインにする必要があります。
先端:
CockroachDB でのインポートパフォーマンスを最適化するためのベストプラクティスについては、「インポートパフォーマンスのベストプラクティス」を参照してください。
サードパーティのデータ移行ツール(AWS DMS、Qlik、Striimなど)を使用してデータをロードします。
次の例では、を使用して初期データ・ロードを実行します。IMPORT INTO
例: CockroachDB への移行world
次の手順では、移行中のスキーマの変換、データの初期読み込みの実行、およびデータの整合性の検証を示します。
完全移行のコンテキストでは、これらの手順により、MySQLデータをCockroachDBに適切に移行し、アプリケーションクエリをクラスタに対してテストできます。詳細については、「移行の概要」を参照してください。
始める前に
この例では、MySQL ワールドデータセットを使用し、スキーマとデータをサーバーレスクラスターに移行する方法を示します。次の手順に従うには、次の手順を実行します。
ワールド データ セットをダウンロードします。
MySQLインスタンスにデータベースを作成し、ダウンロードしたファイルのパスを指定します。world
mysqlsh -uroot --sql --file {path}/world-db/world.sql
スキーマ変換ツールへのアクセスとサーバーレスクラスターの作成に使用する無料のクラウドアカウントを作成します。
先端:
CockroachDB セルフホストデータベースに移行する場合は、変換されたスキーマをスキーマ変換ツールからエクスポートし、Cockroach SQL でステートメントを実行するか、Alembic、Flyway、Liquibase などのサードパーティのスキーマ移行ツールを使用できます。
ステップ1。MySQLスキーマの変換
スキーマ変換ツールを使用して、CockroachDB との互換性のためにスキーマを変換します。スキーマには、worldcitycountrycountrylanguage
次の mysqldump コマンドを使用して MySQL スキーマをダンプします。world
mysqldump -uroot --no-data world > world_schema.sql
Cloud Console でスキーマ変換ツールを開き、新しい MySQL スキーマを追加します。
AUTO_INCREMENT変換オプション」で、「unique_rowid()」オプションを選択します。これにより、MySQL 型と を持つテーブル内の列が、unique_rowid() によって生成されたデフォルト値を持つ CockroachDB INT8 型に変換されます。このオプションのコンテキストについては、AUTO_INCREMENT 属性を参照してください。IDcityintAUTO_INCREMENT
と オプションは、それぞれ異なるユースケースで推奨されます。この例では、このオプションを選択すると、ソース列とターゲット列の両方が整数型になるため、後の手順でデータをロードするのがより簡単になります。UUIDunique_rowid()unique_rowid()
スキーマ変換ツールにworld_schema.sqlをアップロードします。
変換が完了したら、結果を確認します。概要レポートには、エラーがないことが示されます。これは、スキーマを CockroachDB に移行する準備ができていることを意味します。
先端:
また、MySQLデータベースの認証情報を追加して、スキーマ変換ツールがMySQLデータベースから直接スキーマを取得するようにすることもできます。
この例では、サーバーレスクラスターに直接移行します。 CockroachDB セルフホストデータベースに移行する場合は、変換されたスキーマをスキーマ変換ツールからエクスポートし、Cockroach SQL でステートメントを実行するか、Alembic、Flyway、Liquibase などのサードパーティのスキーマ移行ツールを使用できます。
変換されたスキーマを移行する前に、「ステートメント」タブをクリックして「ステートメント」リストを表示します。ステートメントまで下にスクロールし、ステートメントを編集して、列に照合順序 () を追加します。CREATE TABLE countrylanguageCOLLATE en_USlanguage
CREATE TABLE countrylanguage (
countrycode VARCHAR(3) DEFAULT '' NOT NULL,
language VARCHAR(30) COLLATE en_US DEFAULT '' NOT NULL,
isofficial countrylanguage_isofficial_enum
DEFAULT 'F'
NOT NULL,
percentage DECIMAL(4,1) DEFAULT '0.0' NOT NULL,
PRIMARY KEY (countrycode, language),
INDEX countrycode (countrycode),
CONSTRAINT countrylanguage_ibfk_1
FOREIGN KEY (countrycode) REFERENCES country (code)
)
「保存」をクリックします。
これは、照合順序の不一致によるデータ検証の失敗を防ぐための回避策です。詳細については、MOLT Verify のドキュメントを参照してください。
[Migrate Schema] をクリックして、変換されたスキーマで新しいサーバーレスクラスターを作成します。データベースに という名前を付けます。world
このデータベースは、Cloud Console の [データベース] ページで確認できます。
CockroachDB クラスターへの SQL シェルを開きます。コマンドを見つけるには、Cloud Console で [接続] ダイアログを開き、データベースと [CockroachDB クライアント] オプションを選択します。次のようになります。worldworld
cockroach sql --url "postgresql://{username}@{hostname}:{port}/world?sslmode=verify-full"
大規模なインポートの場合、Cockroach Labs では、データを読み込む前にインデックスを削除し、後で再作成することをお勧めします。これにより、インポートの進行状況の可視性が向上し、各ステップを個別に再試行できるようになります。
データベースのインデックスを表示します。world
SHOW INDEXES FROM DATABASE world;
とテーブルの外部キーインデックスは、今のところ削除できます。countrycodecitycountrylanguage
table_name | index_name | index_schema | non_unique | seq_in_index | column_name | definition | direction | storing | implicit | visible
---------------------------------+-------------------------------------------------+--------------+------------+--------------+-----------------+-----------------+-----------+---------+----------+----------
...
city | countrycode | public | t | 2 | id | id | ASC | f | t | t
city | countrycode | public | t | 1 | countrycode | countrycode | ASC | f | f | t
...
countrylanguage | countrycode | public | t | 1 | countrycode | countrycode | ASC | f | f | t
countrylanguage | countrycode | public | t | 2 | language | language | ASC | f | t | t
...
インデックスを削除します。countrycode
DROP INDEX city@countrycode;
DROP INDEX countrylanguage@countrycode;
データを読み込んだ後にインデックスを再作成します。
ステップ2。MySQLデータをロードする
CSV形式のデータでIMPORT INTOを使用して、データをCockroachDBにロードします。IMPORT INTO では、次の属性を持つテーブルごとに 1 つのファイルをエクスポートする必要があります。world
ファイルは、有効な CSV (カンマ区切り値) または TSV (タブ区切り値) 形式である必要があります。
区切り文字は 1 文字でなければなりません。区切り文字オプションを使用して、コンマ以外の文字 (TSV 形式のタブなど) を設定します。
ファイルは UTF-8 でエンコードする必要があります。
フィールドに次の文字のいずれかが含まれている場合は、フィールドを二重引用符で囲む必要があります。
区切り文字 (デフォルト)。,
二重引用符 () です。フィールドは二重引用符で囲まれるため、フィールド内の二重引用符の前に別の二重引用符を付けてエスケープします。例えば:。""aaa","b""bb","ccc"
改行 () です。\n
キャリッジリターン()。\r
カラムがバイト型の場合、有効な UTF-8 文字列、または で始まる 16 進数エンコードされたバイト リテラルのいずれかになります。たとえば、値がバイト であるフィールドは、 と記述されます。\x12\x0102
手記:
MySQL がデータをダンプするとき、テーブルは外部キー制約によって順序付けられず、外部キーは正しい依存関係の順序に配置されません。CockroachDBにデータをロードするときは外部キーチェックを無効にし、データがロードされた後に各テーブルで外部キーを再検証することをお勧めします。
デフォルトでは、IMPORT INTO はターゲット表のすべての外部キー制約を無効にします。
次のmysqldumpコマンドを使用してMySQLデータをダンプします。world
mysqldump -uroot -T /{path}/world-data --fields-terminated-by ',' --fields-enclosed-by '"' --fields-escaped-by '\' --no-create-info world
これにより、データベース内の各テーブルが CSV 形式のファイルとしてパスにダンプされます。/{path}/world-data.txt
--fields-terminated-by値をタブではなくコンマで区切ることを指定します。
--fields-enclosed-byをクリックし、列の値を囲む文字とエスケープする文字をそれぞれ指定します。--fields-escaped-by
--no-create-infoデータ操作言語 (DML) のみをダンプします。
CockroachDB クラスターがアクセスできる場所でファイルをホストします。
CockroachDB クラスター内の各ノードは、インポートされるファイルにアクセスできる必要があります。クラスターがデータにアクセスする方法はいくつかあります。IMPORT INTO がプルできるストレージのタイプの詳細については、以下を参照してください。
クラウドストレージを使用する
ローカル・ファイル・サーバーの使用
Amazon S3 や Google Cloud などのクラウドストレージは、インポートするデータファイルをホストすることを強くお勧めします。
前のステップで生成されたダンプファイルは、この例用に作成されたパブリック S3 バケットですでにホストされています。
以前と同じコマンドを使用して、CockroachDB クラスターへの SQL シェルを開きます。world
cockroach sql --url "postgresql://{username}@{hostname}:{port}/world?sslmode=verify-full"
IMPORT INTO を使用して、各 MySQL ダンプファイルをデータベース内の対応するテーブルにインポートします。world
次のコマンドは、この例でデータダンプファイルがホストされているパブリック S3 バケットを指しています。この句は、コマンドによって生成される値を NULL として読み取る必要があることを指定します。worldnullif='\N'\Nmysqldump
先端:
インポートする行数を指定するオプションを追加できます。たとえば、テーブルの最初の 10 行をインポートします。このオプションは、時間とリソースを消費するインポートを実行する前に、エラーをすばやく検出するのに役立ちます。row_limitrow_limit = '10'
IMPORT INTO countrylanguage
CSV DATA (
'https://cockroachdb-migration-examples.s3.us-east-1.amazonaws.com/mysql/world/countrylanguage.txt'
)
WITH
nullif='\N';
job_id | status | fraction_completed | rows | index_entries | bytes
---------------------+-----------+--------------------+------+---------------+---------
887782070812344321 | succeeded | 1 | 984 | 984 | 171555
IMPORT INTO country
CSV DATA (
'https://cockroachdb-migration-examples.s3.us-east-1.amazonaws.com/mysql/world/country.txt'
)
WITH
nullif='\N';
job_id | status | fraction_completed | rows | index_entries | bytes
---------------------+-----------+--------------------+------+---------------+--------
887782114360819713 | succeeded | 1 | 239 | 0 | 33173
IMPORT INTO city
CSV DATA (
'https://cockroachdb-migration-examples.s3.us-east-1.amazonaws.com/mysql/world/city.txt'
)
WITH
nullif='\N';
job_id | status | fraction_completed | rows | index_entries | bytes
---------------------+-----------+--------------------+------+---------------+---------
887782154421567489 | succeeded | 1 | 4079 | 4079 | 288140
手記:
CockroachDB で動作するようにスキーマを変換した後、 のカラムは unique_rowid() によって生成されたデフォルト値を持つ INT8 になります。ただし、値が生成されるのは、値なしで新しい行が挿入された場合のみです。MySQLデータダンプには、MySQL AUTO_INCREMENT属性によって生成された連続した値が含まれており、これらはコマンドでインポートされます。idcityunique_rowid()ididIMPORT INTO
実際の移行では、主キーを複数列のキーに更新するか、一意の ID を生成する新しい主キー列を追加できます。
データをインポートする前に削除したインデックスを再作成します。
CREATE INDEX countrycode ON city (countrycode, id);
CREATE INDEX countrycode ON countrylanguage (countrycode, language);
ターゲット表のすべての外部キー制約が無効になることを思い出してください。と に定義されている制約を表示します。IMPORT INTOcitycountrylanguage
SHOW CONSTRAINTS FROM city;
table_name | constraint_name | constraint_type | details | validated
-------------+-----------------+-----------------+--------------------------------------------------------------+------------
city | city_ibfk_1 | FOREIGN KEY | FOREIGN KEY (countrycode) REFERENCES country(code) NOT VALID | f
city | city_pkey | PRIMARY KEY | PRIMARY KEY (id ASC) | t
SHOW CONSTRAINTS FROM countrylanguage;
table_name | constraint_name | constraint_type | details | validated
------------------+------------------------+-----------------+--------------------------------------------------------------+------------
countrylanguage | countrylanguage_ibfk_1 | FOREIGN KEY | FOREIGN KEY (countrycode) REFERENCES country(code) NOT VALID | f
countrylanguage | countrylanguage_pkey | PRIMARY KEY | PRIMARY KEY (countrycode ASC, language ASC) | t
外部キーを検証するには、ALTER TABLE ...VALIDATE CONSTRAINT ステートメントを使用します。
ALTER TABLE city VALIDATE CONSTRAINT city_ibfk_1;
ALTER TABLE countrylanguage VALIDATE CONSTRAINT countrylanguage_ibfk_1;
ステップ3。移行されたデータを検証する
MOLT Verifyを使用して、MySQLとCockroachDBのデータの整合性を確認します。
MOLT Verifyをインストールします。
MOLT Verifyをインストールしたディレクトリで、次のコマンドを使用して2つのデータベースを比較し、MySQLのJDBC接続文字列とCockroachDBのSQL接続文字列を次のように指定します。--source--target
先端:
CockroachDB 接続文字列を見つけるには、Cloud Console で [接続] ダイアログを開き、データベースと [全般] 接続文字列オプションを選択します。world
./molt verify --source 'jdbc:mysql://{user}:{password}@tcp({host}:{port})/world' --target 'postgresql://{user}:{password}@{host}:{port}/world?sslmode=verify-full'
初期出力が表示されます。
<nil> INF verification in progress
次の警告は、MySQL カラムと CockroachDB カラムの型が異なることを示しています。これは、スキーマを変換したときに一部の列が ENUM 型に変更されたため、予期される結果です。
<nil> WRN mismatching table definition mismatch_info="column type mismatch on continent: text vs country_continent_enum" table_name=country table_schema=public
<nil> WRN mismatching table definition mismatch_info="column type mismatch on isofficial: text vs countrylanguage_isofficial_enum" table_name=countrylanguage table_schema=public
次の出力は、MOLT Verify が検証を完了したことを示しています。
<nil> INF finished row verification on public.country (shard 1/1): truth rows seen: 239, success: 239, missing: 0, mismatch: 0, extraneous: 0, live_retry: 0
<nil> INF finished row verification on public.countrylanguage (shard 1/1): truth rows seen: 984, success: 984, missing: 0, mismatch: 0, extraneous: 0, live_retry: 0
<nil> INF finished row verification on public.city (shard 1/1): truth rows seen: 4079, success: 4079, missing: 0, mismatch: 0, extraneous: 0, live_retry: 0
<nil> INF verification complete
スキーマを移行し、初期データ読み込みを検証したら、実際の移行の次の手順は、完全な移行を実行する前に、必要なアプリケーションの変更を行ったことを確認し、アプリケーション クエリを検証し、ドライ ランを実行することです。
詳細については、「移行の概要」を参照してください。
・・・要するにMySQLからCockroachDBへの移行ツールは開発されていないということでいいんだな?
;; TetrisSquareクラスの定義
(defun TetrisSquare (x y color)
(list x y color))
(defun TetrisSquareGetX (square)
(nth 0 square))
(defun TetrisSquareGetY (square)
(nth 1 square))
(defun TetrisSquareGetColor (square)
(nth 2 square))
;; TetrisFieldクラスの定義
(defun TetrisField (/ width height squares)
(setq width 10
height 20
squares (make-array (list height width))))
(defun TetrisFieldGetWidth ()
width)
(defun TetrisFieldGetHeight ()
height)
(defun TetrisFieldGetSquare (x y)
(aref squares y x))
(defun TetrisFieldJudgeGameOver (block)
(setq noEmptyCord (list)
blockCord (list))
(repeat height
(repeat width
(if (/= "gray" (TetrisSquareGetColor (TetrisFieldGetSquare x y)))
(setq noEmptyCord (cons (cons x y) noEmptyCord)))
(setq x (+ x 1))
)
(setq x 0
y (+ y 1))
)
(foreach square (TetrisBlockGetSquares block)
(setq cord (TetrisSquareGetCord square))
(setq blockCord (cons (cons (car cord) (cadr cord)) blockCord))
)
(setq blockCord (vl-remove-if-not '(lambda (x) (member x noEmptyCord)) blockCord))
(> (length blockCord) 0)
)
(defun TetrisFieldJudgeCanMove (block direction)
(setq noEmptyCord (list))
(repeat height
(repeat width
(if (/= "gray" (TetrisSquareGetColor (TetrisFieldGetSquare x y)))
(setq noEmptyCord (cons (cons x y) noEmptyCord)))
(setq x (+ x 1))
)
(setq x 0
y (+ y 1))
)
(setq moveBlockCord (list))
(foreach square (TetrisBlockGetSquares block)
(setq cord (TetrisSquareGetMovedCord square direction))
(setq moveBlockCord (cons (cons (car cord) (cadr cord)) moveBlockCord))
(if (or (< (car cord) 0)
(>= (car cord) width)
(< (cadr cord) 0)
(>= (cadr cord) height))
(return nil)
)
)
(setq moveBlockCord (vl-remove-if-not '(lambda (x) (member x noEmptyCord)) moveBlockCord))
(= (length moveBlockCord) 0)
)
(defun TetrisFieldFixBlock (block)
(foreach square (TetrisBlockGetSquares block)
(setq x (car (TetrisSquareGetCord square))
y (cadr (TetrisSquareGetCord square))
color (TetrisSquareGetColor square))
(setq (nth y (nth x squares)) (TetrisSquare x y color))
)
)
(defun TetrisFieldDeleteLine ()
(setq y (- height 1))
(while (>= y 0)
(setq isFull T)
(setq x 0)
(while (< x width)
(if (= "gray" (TetrisSquareGetColor (TetrisFieldGetSquare x y)))
(setq isFull nil))
(setq x (+ x 1))
)
(if isFull
(progn
(setq yy y)
(while (> yy 0)
(setq x 0)
(while (< x width)
(setq (nth yy (nth x squares)) (TetrisSquareGetX (nth (- yy 1) (nth x squares)))
(TetrisSquareGetY (nth (- yy 1) (nth x squares)))
(TetrisSquareGetColor (nth (- yy 1) (nth x squares)))))
(setq x (+ x 1))
)
(setq yy (- yy 1))
)
(setq x 0)
(while (< x width)
(setq (nth 0 (nth x squares)) (TetrisSquare x 0 "gray"))
(setq x (+ x 1))
)
(setq y (+ y 1))
)
)
(setq y (- y 1))
)
)
;; TetrisBlockクラスの定義
(defun TetrisBlock (/ squares)
(setq squares (list))
(setq blockType (random 4))
(cond
((= blockType 0)
(setq color "red"
cords (list (list (/ 10 2) 0)
(list (/ 10 2) 1)
(list (/ 10 2) 2)
(list (/ 10 2) 3))))
((= blockType 1)
(setq color "blue"
cords (list (list (/ 10 2) 0)
(list (/ 10 2) 1)
(list (- (/ 10 2) 1) 0)
(list (- (/ 10 2) 1) 1))))
((= blockType 2)
(setq color "green"
cords (list (list (- (/ 10 2) 1) 0)
(list (/ 10 2) 0)
(list (/ 10 2) 1)
(list (/ 10 2) 2))))
((= blockType 3)
(setq color "orange"
cords (list (list (/ 10 2) 0)
(list (- (/ 10 2) 1) 0)
(list (- (/ 10 2) 1) 1)
(list (- (/ 10 2) 1) 2))))
(T
(setq color "gray"
cords nil))
)
(foreach cord cords
(setq squares (cons (TetrisSquare (car cord) (cadr cord) color) squares))
)
squares
)
(defun TetrisBlockGetSquares (block)
squares)
(defun TetrisBlockMove (block direction)
(setq newSquares (list))
(foreach square squares
(setq movedCord (TetrisSquareGetMovedCord square direction)
x (car movedCord)
y (cadr movedCord))
(setq newSquares (cons (TetrisSquare x y (TetrisSquareGetColor square)) newSquares))
)
(setq squares newSquares)
)
;; TetrisGameクラスの定義
(defun TetrisGame (/ field block canvas)
(setq field (TetrisField)
block nil
canvas nil))
(defun TetrisGameStart ()
(setq field (TetrisField)
block nil
canvas (TetrisCanvas field))
)
(defun TetrisGameNewBlock ()
(setq block (TetrisBlock))
(if (TetrisFieldJudgeGameOver block)
(progn
(princ "GAMEOVER")
(terpri))
)
)
(defun TetrisGameMoveBlock (direction)
(if (TetrisFieldJudgeCanMove block direction)
(progn
(TetrisBlockMove block direction)
(TetrisCanvasUpdate canvas field block))
(if (= direction 2)
(progn
(TetrisFieldFixBlock block)
(TetrisFieldDeleteLine)
(TetrisGameNewBlock)
(TetrisCanvasUpdate canvas field block))
)
)
)
;; TetrisCanvasクラスの定義
(defun TetrisCanvas (field)
(setq beforeField field
field field))
(defun TetrisCanvasUpdate (field block)
(setq beforeField field)
;; キャンバスを更新する処理
)
;; TetrisCommandsクラスの定義
(defun c:TETRIS ()
(setq field (TetrisField)
block nil
canvas (TetrisCanvas field)
game (TetrisGame))
(TetrisGameStart)
(while T
;; ユーザー入力を取得し、適切な方向で game.MoveBlock(direction) を呼び出す
)
)
さてどうなるか?
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.Threading;
namespace TetrisPlugin
{
public class TetrisSquare
{
public int X { get; set; }
public int Y { get; set; }
public string Color { get; set; }
public TetrisSquare(int x = 0, int y = 0, string color = "gray")
{
X = x;
Y = y;
Color = color;
}
public Point2d GetCord()
{
return new Point2d(X, Y);
}
public void SetColor(string color)
{
Color = color;
}
public string GetColor()
{
return Color;
}
public Point2d GetMovedCord(int direction)
{
int x = X;
int y = Y;
switch (direction)
{
case TetrisGame.MOVE_LEFT:
x--;
break;
case TetrisGame.MOVE_RIGHT:
x++;
break;
case TetrisGame.MOVE_DOWN:
y++;
break;
}
return new Point2d(x, y);
}
}
public class TetrisField
{
private readonly int width = 10; // Fix width and height
private readonly int height = 20;
private TetrisSquare[,] squares;
public TetrisField()
{
squares = new TetrisSquare[height, width];
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
squares[y, x] = new TetrisSquare(x, y, "gray");
}
}
}
public int GetWidth()
{
return width;
}
public int GetHeight()
{
return height;
}
public TetrisSquare GetSquare(int x, int y)
{
return squares[y, x];
}
public bool JudgeGameOver(TetrisBlock block)
{
HashSet<Point2d> noEmptyCord = new HashSet<Point2d>();
HashSet<Point2d> blockCord = new HashSet<Point2d>();
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (squares[y, x].GetColor() != "gray")
noEmptyCord.Add(new Point2d(x, y));
}
}
foreach (TetrisSquare square in block.GetSquares())
{
Point2d cord = square.GetCord();
blockCord.Add(cord);
}
blockCord.IntersectWith(noEmptyCord);
return blockCord.Count > 0;
}
public bool JudgeCanMove(TetrisBlock block, int direction)
{
HashSet<Point2d> noEmptyCord = new HashSet<Point2d>();
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (squares[y, x].GetColor() != "gray")
noEmptyCord.Add(new Point2d(x, y));
}
}
HashSet<Point2d> moveBlockCord = new HashSet<Point2d>();
foreach (TetrisSquare square in block.GetSquares())
{
Point2d cord = square.GetMovedCord(direction);
moveBlockCord.Add(cord);
if (cord.X < 0 || cord.X >= width || cord.Y < 0 || cord.Y >= height)
return false;
}
moveBlockCord.IntersectWith(noEmptyCord);
return moveBlockCord.Count == 0;
}
public void FixBlock(TetrisBlock block)
{
foreach (TetrisSquare square in block.GetSquares())
{
int x = (int)square.GetCord().X;
int y = (int)square.GetCord().Y;
string color = square.GetColor();
squares[y, x].SetColor(color);
}
}
public void DeleteLine()
{
for (int y = height - 1; y >= 0; y--)
{
bool isFull = true;
for (int x = 0; x < width; x++)
{
if (squares[y, x].GetColor() == "gray")
{
isFull = false;
break;
}
}
if (isFull)
{
for (int yy = y; yy > 0; yy--)
{
for (int x = 0; x < width; x++)
{
squares[yy, x].SetColor(squares[yy - 1, x].GetColor());
}
}
for (int x = 0; x < width; x++)
{
squares[0, x].SetColor("gray");
}
y++;
}
}
}
}
public class TetrisBlock
{
private List<TetrisSquare> squares = new List<TetrisSquare>();
public TetrisBlock()
{
int blockType = new Random().Next(1, 5);
string color;
List<Point2d> cords = new List<Point2d>();
switch (blockType)
{
case 1:
color = "red";
cords.Add(new Point2d(10 / 2, 0));
cords.Add(new Point2d(10 / 2, 1));
cords.Add(new Point2d(10 / 2, 2));
cords.Add(new Point2d(10 / 2, 3));
break;
case 2:
color = "blue";
cords.Add(new Point2d(10 / 2, 0));
cords.Add(new Point2d(10 / 2, 1));
cords.Add(new Point2d(10 / 2 - 1, 0));
cords.Add(new Point2d(10 / 2 - 1, 1));
break;
case 3:
color = "green";
cords.Add(new Point2d(10 / 2 - 1, 0));
cords.Add(new Point2d(10 / 2, 0));
cords.Add(new Point2d(10 / 2, 1));
cords.Add(new Point2d(10 / 2, 2));
break;
case 4:
color = "orange";
cords.Add(new Point2d(10 / 2, 0));
cords.Add(new Point2d(10 / 2 - 1, 0));
cords.Add(new Point2d(10 / 2 - 1, 1));
cords.Add(new Point2d(10 / 2 - 1, 2));
break;
default:
color = "gray";
break;
}
foreach (Point2d cord in cords)
{
squares.Add(new TetrisSquare((int)cord.X, (int)cord.Y, color));
}
}
public List<TetrisSquare> GetSquares()
{
return squares;
}
public void Move(int direction)
{
foreach (TetrisSquare square in squares)
{
Point2d movedCord = square.GetMovedCord(direction);
square.X = (int)movedCord.X;
square.Y = (int)movedCord.Y;
}
}
}
public class TetrisGame
{
private TetrisField field;
private TetrisBlock block;
private TetrisCanvas canvas;
public const int MOVE_LEFT = 0;
public const int MOVE_RIGHT = 1;
public const int MOVE_DOWN = 2;
public TetrisGame(TetrisCanvas canvas, TetrisField field, TetrisBlock block)
{
this.canvas = canvas;
this.field = field;
this.block = block;
}
public void Start(Action endFunc)
{
field = new TetrisField();
block = null;
canvas.Update(field, block);
}
public void NewBlock()
{
block = new TetrisBlock();
if (field.JudgeGameOver(block))
{
Console.WriteLine("GAMEOVER");
}
canvas.Update(field, block);
}
public void MoveBlock(int direction)
{
if (field.JudgeCanMove(block, direction))
{
block.Move(direction);
canvas.Update(field, block);
}
else
{
if (direction == MOVE_DOWN)
{
field.FixBlock(block);
field.DeleteLine();
NewBlock();
}
}
}
}
public class TetrisCanvas
{
private TetrisField beforeField;
private TetrisField field;
private readonly int BLOCK_SIZE = 25;
private readonly int FIELD_WIDTH = 10;
private readonly int FIELD_HEIGHT = 20;
public TetrisCanvas(TetrisField field)
{
this.field = field;
beforeField = field;
}
public void Update(TetrisField field, TetrisBlock block)
{
beforeField = field;
// Update canvas with new field and block
}
}
public class TetrisCommands
{
[CommandMethod("TETRIS")]
public void TetrisGame()
{
TetrisField field = new TetrisField();
TetrisBlock block = null;
TetrisCanvas canvas = new TetrisCanvas(field);
TetrisGame game = new TetrisGame(canvas, field, block);
game.Start(null); // You can pass a function to handle end game scenario
while (true)
{
// Get user input, for example through AutoCAD commands or UI buttons
// Depending on input, call game.MoveBlock(direction) with appropriate direction
}
}
}
}
プログラムを実行してみたが、エラーは出なかった。しかしAutoCADでTETRISとコマンドを入れたらそれっきりウンともスンとも言わなくなってしまった。
前回はVisualBasic.netで成功させたから、今度はChatGPTにC#に変換してもらって試してみた。
※コマンド名に注目www
直線を書いてみた。
ソースコードの一部。
いわゆるパスを通すという作業の様子。
ここが躓いた原因。VB.NETの時はXMLタグを編集したがC#ではプロパティで開いて入力ボックスにacad.exeのディレクトリをフルパスで入力した。
いわゆる参照という作業の様子。
これはVB.NETの時と一緒。
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
public class MyCommands
{
[CommandMethod("両足チョンパの崔バカ雄")]
public void ProcessUserInput()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
string userInput = GetStringFromUserInput("CAD", "何をしましょうか?");
if (userInput.Contains("直線"))
{
CreateLine();
}
else if (userInput.Contains("円"))
{
CreateCircle();
}
else
{
ed.WriteMessage("そのような操作はできません。");
}
}
private void CreateLine()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
double start_x = GetDoubleFromUserInput("始点のX座標を入力してください。");
double start_y = GetDoubleFromUserInput("始点のY座標を入力してください。");
double end_x = GetDoubleFromUserInput("終点のX座標を入力してください。");
double end_y = GetDoubleFromUserInput("終点のY座標を入力してください。");
DrawLine(start_x, start_y, end_x, end_y);
}
private void CreateCircle()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
double center_x = GetDoubleFromUserInput("中心のX座標を入力してください。");
double center_y = GetDoubleFromUserInput("中心のY座標を入力してください。");
double radius = GetDoubleFromUserInput("半径を入力してください。");
DrawCircle(center_x, center_y, radius);
}
private double GetDoubleFromUserInput(string prompt)
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
while (true)
{
PromptDoubleResult result = ed.GetDouble(prompt);
if (result.Status == PromptStatus.OK)
{
return result.Value;
}
else
{
ed.WriteMessage("数値を入力してください。");
}
}
}
private string GetStringFromUserInput(string title, string prompt)
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
return ed.GetString(prompt).StringResult;
}
private void DrawLine(double startX, double startY, double endX, double endY)
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
Point3d startPoint = new Point3d(startX, startY, 0);
Point3d endPoint = new Point3d(endX, endY, 0);
Line line = new Line(startPoint, endPoint);
btr.AppendEntity(line);
tr.AddNewlyCreatedDBObject(line, true);
tr.Commit();
}
}
private void DrawCircle(double centerX, double centerY, double radius)
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
Point3d centerPoint = new Point3d(centerX, centerY, 0);
Circle circle = new Circle(centerPoint, Vector3d.ZAxis, radius);
btr.AppendEntity(circle);
tr.AddNewlyCreatedDBObject(circle, true);
tr.Commit();
}
}
}
AutoCAD VB.NETマクロサンプル大全集に書かれてある通りにC#でもやればいいのではないかと思ったが、失敗してしまった。
以前購入したAmazon kindleの英語で書かれたe-bookを見ながらやってみたら、三度目の正直で成功!
VB.NETでは押出くり抜きとかもっと高度なことをやろうとしてChatGPTにコーディングしてもらったが、如何せんエラーが直らず断念。
C#ではもっと高度なことができると期待している。とりあえずVB.NETはこれにて終了。
https://ken-it.world/it/2014/09/k-engine.html
より引用。
LIXILグループのK-engine(本社:東京都新宿区)は、これまで約1週間(約1万分)かかっていた見積もり作業をわずか5分に短縮する画期的なクラウドシステム「K-engineサービス」をこのほどスタートさせました。
Jw_cadの図面データをクラウドにアップロードし、簡単な設定を行えば、わずか2分間で施主への見積書や実行予算などを正確に計算してデータを戻してくれるというシステムなのです。
Jw_cadの図面から住宅の壁や部屋などの寸法や、システムキッチンなどの建材設備などを拾い出し、それらに単価をかけて集計するのは、BIM(ビルディング・インフォメーション・モデリング)ソフトも顔負けです。
なぜ、こんなことができるかというと、Jw_cadの図面データにある「レイヤー」をBIMの属性情報代わりに使用し、クラウドが部材の種類などを区別できるようにしているからです。
図面上のデータは「3D部品」として分解され、住宅全体を3Dモデルとして作成します。これらの機能を実現するエンジンは、福井コンピュータアーキテクトの3D住宅設計システム「Architrend-Z」のものが採用されているとのことです。そのため、Jw_cadの図面のほかArchitrend-Zの図面データでも見積もりなどが可能です。
その他・・・
施主用の見積書や実行予算書を作成
工程表まで自動作成
これはすごいと思った。しかし、Revit等のBIMの牙城をとこまで攻め崩せるかが見ものだ。
建築VRのUnityやUnrealEngineもあることだし。
https://www.kumagaigumi.co.jp/news/2024/pr_20240422_1.html
より引用。
今回開発した「CABTrans」は大きく2つのモジュールに分かれています。
ひとつは、燈社が開発した、CADデータから情報を取得し構造化されたCSVデータを出力するモジュール「D-CSV」、もうひとつは熊谷組が担当したCSVを読み込み、CSVからRhino-Grasshopper※1を経由してArchicad※2上にBIMモデルを生成するモジュールです。
「D-CSV」はブラウザ上で動作し、図面から範囲・レイヤー等を指定することでAIによって柱・梁・基礎・杭の位置情報及び断面情報を取得し、CSV形式で出力します。さらに、生成したCSVファイルをGrasshopperで構築したアルゴリズムにより処理することで鉄骨及びRC構造フレーム部分をArchicad上に生成することが可能です。現状は、構造図CADデータからの構造部分BIMデータの変換にのみ対応しています。
CABTransのサイトを見た俺の感想。
JWCADで3Dが可能になったのかと一瞬思ってしまった。
現状ではやはりJWCADで2.5Dまでが精いっぱいだ。かと言っていきなりBIMでモデリングするのもまだまだ敷居が高い。
IDENTIFICATION DIVISION.
PROGRAM-ID. SAMPLE.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 SQL-STATEMENT PIC X(100).
01 SQL-RESULT PIC S9(4) COMP.
PROCEDURE DIVISION.
MAIN-PROCEDURE.
MOVE "SELECT * FROM EMPLOYEES WHERE DEPARTMENT = 'SALES'" TO SQL-STATEMENT.
EXEC SQL
PREPARE SQL-STATEMENT
END-EXEC.
EXEC SQL
OPEN EMPLOYEE-CURSOR
END-EXEC.
EXEC SQL
FETCH NEXT FROM EMPLOYEE-CURSOR INTO :EMPLOYEE-ID, :EMPLOYEE-NAME
END-EXEC.
PERFORM UNTIL SQL-RESULT = 100
DISPLAY "EMPLOYEE ID: " EMPLOYEE-ID " EMPLOYEE NAME: " EMPLOYEE-NAME
EXEC SQL
FETCH NEXT FROM EMPLOYEE-CURSOR INTO :EMPLOYEE-ID, :EMPLOYEE-NAME
END-EXEC.
END-PERFORM.
EXEC SQL
CLOSE EMPLOYEE-CURSOR
END-EXEC.
STOP RUN.
このプログラムは、部署が "SALES" の従業員を表示する単純な例です。SQL文は文字列変数SQL-STATEMENT
に格納され、EXEC SQL
ステートメントによって実行されます。このコードは、実際のデータベース接続や設定には関係なく、SQL文の埋め込み方法を示しています。
実際には、プログラム内で使用するデータベースにアクセスするためには、データベース接続情報などの追加の設定が必要です。また、プリプロセッサを使用してCOBOLプログラムを生成するための手順もありますが、この手順はCOBOLの特定のコンパイラに依存します。
とのこと。
https://amzn.asia/d/8BeCip1
という本のレビュー覧で「COBOL埋め込みSQL」という文言が出てきたので、気になっていた。
レビューではさんざんなことが書かれていたが、このレビューをきっかけにPython埋め込みVisualBasic.netとかいろいろ閃いた。
さらにこんな情報も・・・
https://itpfdoc.hitachi.co.jp/manuals/3020/30203D6240/USR20403.HTM
https://software.fujitsu.com/jp/manual/manualfiles/M080271/J2X02268/06Z201/aplsq03/aplsq062.html
https://software.fujitsu.com/jp/manual/manualfiles/m140016/j2ul1756/03z200/j2ul-1756-03z0.pdf
Googleで「cobol 埋め込みsql」と入力して検索すべし。
【追伸】
Androidでコンパイルしてみたらエラーとなった。
main.cob: 20: warning: line not terminated by a newline
main.cob: 1: error: PROGRAM-ID header missing
main.cob: 1: error: ENVIRONMENT DIVISION header missing
main.cob: 1: error: CONFIGURATION SECTION header missing
main.cob: 1: error: SPECIAL-NAMES header missing
main.cob: 1: error: invalid system-name 'WHERE'
main.cob: 1: error: syntax error, unexpected =